gtk/tests/testdatatable.c
Benjamin Otte 00cb4c66cf testdatatable: Add a --pages option
That way, local scrolling is available and the scrolling isn't random.

Recycling should now involve reordering the recycled widgets instead of
just keeping their order because all of them got recycled.
2023-04-01 20:49:40 +02:00

324 lines
8.0 KiB
C

/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */
#include <gtk/gtk.h>
#include "frame-stats.h"
static gboolean no_auto_scroll = FALSE;
static gint n_columns = 20;
static double scroll_pages = 0;
/* This is our dummy item for the model. */
#define DATA_TABLE_TYPE_ITEM (data_table_item_get_type ())
G_DECLARE_FINAL_TYPE (DataTableItem, data_table_item, DATA_TABLE, ITEM, GObject)
struct _DataTableItem
{
GObject parent_instance;
int data;
};
struct _DataTableItemClass
{
GObjectClass parent_class;
};
G_DEFINE_TYPE (DataTableItem, data_table_item, G_TYPE_OBJECT)
static void data_table_item_init (DataTableItem *item) {}
static void data_table_item_class_init (DataTableItemClass *class) {}
static DataTableItem *
data_table_item_new (int data)
{
DataTableItem *item = g_object_new (DATA_TABLE_TYPE_ITEM, NULL);
item->data = data;
return item;
}
static void
set_adjustment_to_fraction (GtkAdjustment *adjustment,
double fraction)
{
double upper = gtk_adjustment_get_upper (adjustment);
double lower = gtk_adjustment_get_lower (adjustment);
double page_size = gtk_adjustment_get_page_size (adjustment);
gtk_adjustment_set_value (adjustment,
(1 - fraction) * lower +
fraction * (upper - page_size));
}
static void
move_adjustment_by_pages (GtkAdjustment *adjustment,
double n_pages)
{
double page_size = gtk_adjustment_get_page_size (adjustment);
double value = gtk_adjustment_get_value (adjustment);
value += page_size * n_pages;
/* the adjustment will clamp properly */
gtk_adjustment_set_value (adjustment, value);
}
static gboolean
scroll_column_view (GtkWidget *column_view,
GdkFrameClock *frame_clock,
gpointer user_data)
{
GtkAdjustment *vadjustment;
vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (column_view));
if (scroll_pages == 0.0)
set_adjustment_to_fraction (vadjustment, g_random_double ());
else
move_adjustment_by_pages (vadjustment, (g_random_double () * 2 - 1) * scroll_pages);
return TRUE;
}
enum WidgetType
{
WIDGET_TYPE_NONE,
WIDGET_TYPE_LABEL,
WIDGET_TYPE_TEXT,
WIDGET_TYPE_INSCRIPTION,
};
static enum WidgetType widget_type = WIDGET_TYPE_INSCRIPTION;
static void
setup (GtkSignalListItemFactory *factory,
GObject *listitem)
{
GtkWidget *widget;
switch (widget_type)
{
case WIDGET_TYPE_NONE:
/* It's actually a box, just to request size similar to labels. */
widget = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
gtk_widget_set_size_request (widget, 50, 18);
break;
case WIDGET_TYPE_LABEL:
widget = gtk_label_new ("");
break;
case WIDGET_TYPE_TEXT:
widget = gtk_text_new ();
break;
case WIDGET_TYPE_INSCRIPTION:
widget = gtk_inscription_new ("");
gtk_inscription_set_min_chars (GTK_INSCRIPTION (widget), 6);
break;
default:
g_assert_not_reached ();
}
gtk_list_item_set_child (GTK_LIST_ITEM (listitem), widget);
}
static void
bind (GtkSignalListItemFactory *factory,
GObject *listitem,
gpointer name)
{
GtkWidget *widget;
GObject *item;
widget = gtk_list_item_get_child (GTK_LIST_ITEM (listitem));
item = gtk_list_item_get_item (GTK_LIST_ITEM (listitem));
char buffer[16] = { 0, };
g_snprintf (buffer,
sizeof (buffer),
"%c%d",
GPOINTER_TO_INT (name),
DATA_TABLE_ITEM (item)->data);
switch (widget_type)
{
case WIDGET_TYPE_NONE:
break;
case WIDGET_TYPE_LABEL:
gtk_label_set_label (GTK_LABEL (widget), buffer);
break;
case WIDGET_TYPE_TEXT:
gtk_editable_set_text (GTK_EDITABLE (widget), buffer);
break;
case WIDGET_TYPE_INSCRIPTION:
gtk_inscription_set_text (GTK_INSCRIPTION (widget), buffer);
break;
default:
g_assert_not_reached ();
}
}
static gboolean
parse_widget_arg (const gchar* option_name,
const gchar* value,
gpointer data,
GError** error)
{
if (!g_strcmp0 (value, "none"))
{
widget_type = WIDGET_TYPE_NONE;
return TRUE;
}
else if (!g_strcmp0 (value, "label"))
{
widget_type = WIDGET_TYPE_LABEL;
return TRUE;
}
else if (!g_strcmp0 (value, "text"))
{
widget_type = WIDGET_TYPE_TEXT;
return TRUE;
}
else if (!g_strcmp0 (value, "inscription"))
{
widget_type = WIDGET_TYPE_INSCRIPTION;
return TRUE;
}
else
{
g_set_error_literal (error, G_IO_ERROR, G_IO_ERROR_INVALID_DATA,
"Invalid option value");
return FALSE;
}
}
static GOptionEntry options[] = {
{
"widget",
'w',
G_OPTION_FLAG_NONE,
G_OPTION_ARG_CALLBACK,
parse_widget_arg,
"Cell item widget to use, can be one of: none, label, text, inscription",
"WIDGET"
},
{
"no-auto-scroll",
'n',
G_OPTION_FLAG_NONE,
G_OPTION_ARG_NONE,
&no_auto_scroll,
"Disable automatic scrolling",
NULL
},
{
"columns",
'c',
G_OPTION_FLAG_NONE,
G_OPTION_ARG_INT,
&n_columns,
"Column count",
"COUNT"
},
{
"pages",
'p',
G_OPTION_FLAG_NONE,
G_OPTION_ARG_DOUBLE,
&scroll_pages,
"Maximum number of pages to scroll (or 0 for random)",
"COUNT"
},
{ NULL }
};
static void
quit_cb (GtkWidget *widget,
gpointer data)
{
gboolean *done = data;
*done = TRUE;
g_main_context_wakeup (NULL);
}
int
main (int argc, char **argv)
{
GtkWidget *window;
GtkWidget *scrolled_window;
GListStore *store;
int i;
GtkMultiSelection *multi_selection;
GtkWidget *column_view;
GError *error = NULL;
gboolean done = FALSE;
GOptionContext *context = g_option_context_new (NULL);
g_option_context_add_main_entries (context, options, NULL);
frame_stats_add_options (g_option_context_get_main_group (context));
if (!g_option_context_parse (context, &argc, &argv, &error))
{
g_printerr ("Option parsing failed: %s\n", error->message);
return 1;
}
gtk_init ();
window = gtk_window_new ();
frame_stats_ensure (GTK_WINDOW (window));
gtk_window_set_default_size (GTK_WINDOW (window), 1700, 900);
scrolled_window = gtk_scrolled_window_new ();
gtk_window_set_child (GTK_WINDOW (window), scrolled_window);
store = g_list_store_new (DATA_TABLE_TYPE_ITEM);
for (i = 0; i < 10000; ++i)
{
DataTableItem *item = data_table_item_new (i);
g_list_store_append (store, item);
g_object_unref (item);
}
multi_selection = gtk_multi_selection_new (G_LIST_MODEL (store));
column_view = gtk_column_view_new (GTK_SELECTION_MODEL (multi_selection));
gtk_column_view_set_show_column_separators (GTK_COLUMN_VIEW (column_view), TRUE);
gtk_column_view_set_show_row_separators (GTK_COLUMN_VIEW (column_view), TRUE);
gtk_widget_add_css_class (column_view, "data-table");
for (i = 0; i < MIN (n_columns, 127 - 65); ++i)
{
const char name[] = { 'A' + i, '\0' };
GtkListItemFactory *factory = gtk_signal_list_item_factory_new ();
g_signal_connect (factory, "setup", G_CALLBACK (setup), NULL);
g_signal_connect (factory, "bind", G_CALLBACK (bind), GINT_TO_POINTER (name[0]));
gtk_column_view_append_column (GTK_COLUMN_VIEW (column_view),
gtk_column_view_column_new (name, factory));
}
gtk_scrolled_window_set_child (GTK_SCROLLED_WINDOW (scrolled_window),
column_view);
if (!no_auto_scroll)
{
gtk_widget_add_tick_callback (column_view,
scroll_column_view,
NULL,
NULL);
}
gtk_window_present (GTK_WINDOW (window));
g_signal_connect (window, "destroy",
G_CALLBACK (quit_cb), &done);
while (!done)
g_main_context_iteration (NULL, TRUE);
return 0;
}