/* -*- mode: C; c-basic-offset: 2; indent-tabs-mode: nil; -*- */ #include #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; }