diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index 50477c13f5..585bc28e70 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -5,6 +5,7 @@ main.ui + main-listitem.ui application.c diff --git a/demos/gtk-demo/geninclude.py b/demos/gtk-demo/geninclude.py index af48187294..bae6e57f47 100755 --- a/demos/gtk-demo/geninclude.py +++ b/demos/gtk-demo/geninclude.py @@ -13,17 +13,16 @@ in_files = sys.argv[2:] file_output = """ typedef GtkWidget *(*GDoDemoFunc) (GtkWidget *do_widget); -typedef struct _Demo Demo; +typedef struct _DemoData DemoData; -struct _Demo +struct _DemoData { const char *name; const char *title; const char *filename; GDoDemoFunc func; - Demo *children; + DemoData *children; }; - """ # Demo = namedtuple('Demo', ['name', 'title', 'file', 'func']) @@ -67,7 +66,7 @@ for demo in demos: i = 0 for parent in parents: id = parent_ids[i] - file_output += "\nDemo child" + str(id) + "[] = {\n" + file_output += "\nDemoData child" + str(id) + "[] = {\n" # iterate over all demos and check if the name starts with the given parent name for child in demos: if child[1].startswith(parent + "/"): @@ -82,7 +81,7 @@ for parent in parents: # Sort demos by title demos = sorted(demos, key=lambda x: x[1]) -file_output += "\nDemo gtk_demos[] = {\n" +file_output += "\nDemoData gtk_demos[] = {\n" for demo in demos: # Do not generate one of these for demos with a parent demo if "/" not in demo[1]: diff --git a/demos/gtk-demo/main-listitem.ui b/demos/gtk-demo/main-listitem.ui new file mode 100644 index 0000000000..a8d9c47430 --- /dev/null +++ b/demos/gtk-demo/main-listitem.ui @@ -0,0 +1,22 @@ + + + + diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c index a54e791844..8052f2f96b 100644 --- a/demos/gtk-demo/main.c +++ b/demos/gtk-demo/main.c @@ -17,18 +17,96 @@ static GtkWidget *source_view; static gchar *current_file = NULL; static GtkWidget *notebook; -static GtkWidget *treeview; +static GtkSingleSelection *selection; static GtkWidget *toplevel; -enum { - NAME_COLUMN, - TITLE_COLUMN, - FILENAME_COLUMN, - FUNC_COLUMN, - STYLE_COLUMN, - NUM_COLUMNS +typedef struct _GtkDemo GtkDemo; +struct _GtkDemo +{ + GObject parent_instance; + + const char *name; + const char *title; + const char *filename; + GDoDemoFunc func; + GListModel *children_model; }; +enum { + PROP_0, + PROP_FILENAME, + PROP_NAME, + PROP_TITLE, + + N_PROPS +}; + +# define GTK_TYPE_DEMO (gtk_demo_get_type ()) +G_DECLARE_FINAL_TYPE (GtkDemo, gtk_demo, GTK, DEMO, GObject); + +G_DEFINE_TYPE (GtkDemo, gtk_demo, G_TYPE_OBJECT); +static GParamSpec *properties[N_PROPS] = { NULL, }; + +static void +gtk_demo_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GtkDemo *self = GTK_DEMO (object); + + switch (property_id) + { + case PROP_FILENAME: + g_value_set_string (value, self->filename); + break; + + case PROP_NAME: + g_value_set_string (value, self->name); + break; + + case PROP_TITLE: + g_value_set_string (value, self->title); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void gtk_demo_class_init (GtkDemoClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->get_property = gtk_demo_get_property; + + properties[PROP_FILENAME] = + g_param_spec_string ("filename", + "filename", + "filename", + NULL, + G_PARAM_READABLE); + properties[PROP_NAME] = + g_param_spec_string ("name", + "name", + "name", + NULL, + G_PARAM_READABLE); + properties[PROP_TITLE] = + g_param_spec_string ("title", + "title", + "title", + NULL, + G_PARAM_READABLE); + + g_object_class_install_properties (gobject_class, N_PROPS, properties); +} + +static void gtk_demo_init (GtkDemo *self) +{ +} + typedef struct _CallbackData CallbackData; struct _CallbackData { @@ -36,6 +114,27 @@ struct _CallbackData GtkTreePath *path; }; +static gboolean +gtk_demo_run (GtkDemo *self, + GtkWidget *window) +{ + GtkWidget *result; + + if (!self->func) + return FALSE; + + result = self->func (window); + if (result == NULL) + return FALSE; + + if (GTK_IS_WINDOW (result)) + { + gtk_window_set_transient_for (GTK_WINDOW (result), GTK_WINDOW (window)); + gtk_window_set_modal (GTK_WINDOW (result), TRUE); + } + return TRUE; +} + static void activate_about (GSimpleAction *action, GVariant *parameter, @@ -117,82 +216,15 @@ activate_inspector (GSimpleAction *action, award ("demo-inspector"); } -static void -window_closed_cb (GtkWidget *window, gpointer data) -{ - CallbackData *cbdata = data; - GtkTreeIter iter; - PangoStyle style; - - gtk_tree_model_get_iter (cbdata->model, &iter, cbdata->path); - gtk_tree_model_get (GTK_TREE_MODEL (cbdata->model), &iter, - STYLE_COLUMN, &style, - -1); - if (style == PANGO_STYLE_ITALIC) - gtk_tree_store_set (GTK_TREE_STORE (cbdata->model), &iter, - STYLE_COLUMN, PANGO_STYLE_NORMAL, - -1); - - gtk_tree_path_free (cbdata->path); - g_free (cbdata); -} - -static void -run_example_for_row (GtkWidget *window, - GtkTreeModel *model, - GtkTreeIter *iter) -{ - PangoStyle style; - GDoDemoFunc func; - GtkWidget *demo; - - gtk_tree_model_get (GTK_TREE_MODEL (model), - iter, - FUNC_COLUMN, &func, - STYLE_COLUMN, &style, - -1); - - if (func) - { - gtk_tree_store_set (GTK_TREE_STORE (model), - iter, - STYLE_COLUMN, (style == PANGO_STYLE_ITALIC ? PANGO_STYLE_NORMAL : PANGO_STYLE_ITALIC), - -1); - demo = (func) (window); - - if (demo != NULL) - { - CallbackData *cbdata; - - cbdata = g_new (CallbackData, 1); - cbdata->model = model; - cbdata->path = gtk_tree_model_get_path (model, iter); - - if (GTK_IS_WINDOW (demo)) - { - gtk_window_set_transient_for (GTK_WINDOW (demo), GTK_WINDOW (window)); - gtk_window_set_modal (GTK_WINDOW (demo), TRUE); - } - - g_signal_connect (demo, "destroy", - G_CALLBACK (window_closed_cb), cbdata); - } - } -} - static void activate_run (GSimpleAction *action, GVariant *parameter, - gpointer user_data) + gpointer window) { - GtkWidget *window = user_data; - GtkTreeSelection *selection; - GtkTreeModel *model; - GtkTreeIter iter; + GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection); + GtkDemo *demo = gtk_tree_list_row_get_item (row); - selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (treeview)); - if (gtk_tree_selection_get_selected (selection, &model, &iter)) - run_example_for_row (window, model, &iter); + gtk_demo_run (demo, window); } /* Stupid syntax highlighting. @@ -897,107 +929,93 @@ load_file (const gchar *demoname, } static void -selection_cb (GtkTreeSelection *selection, - GtkTreeModel *model) +activate_cb (GtkWidget *widget, + guint position, + gpointer window) { - GtkTreeIter iter; - char *name; - char *filename; - char *title; + GtkTreeListRow *row = g_list_model_get_item (gtk_list_view_get_model (GTK_LIST_VIEW (widget)), position); + GtkDemo *demo = gtk_tree_list_row_get_item (row); - if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) - return; + gtk_demo_run (demo, window); - gtk_tree_model_get (model, &iter, - NAME_COLUMN, &name, - TITLE_COLUMN, &title, - FILENAME_COLUMN, &filename, - -1); - - if (filename) - load_file (name, filename); - - gtk_window_set_title (GTK_WINDOW (toplevel), title); - - g_free (name); - g_free (title); - g_free (filename); + g_object_unref (row); } static void -populate_model (GtkTreeModel *model) +selection_cb (GtkSingleSelection *sel, + GParamSpec *pspec, + gpointer user_data) { - Demo *d = gtk_demos; + GtkTreeListRow *row = gtk_single_selection_get_selected_item (sel); + GtkDemo *demo = gtk_tree_list_row_get_item (row); - /* this code only supports 1 level of children. If we - * want more we probably have to use a recursing function. - */ - while (d->title) + if (demo->filename) + load_file (demo->name, demo->filename); + + gtk_window_set_title (GTK_WINDOW (toplevel), demo->title); +} + +static GListModel * +create_demo_model (void) +{ + GListStore *store = g_list_store_new (GTK_TYPE_DEMO); + DemoData *demo = gtk_demos; + + while (demo->title) { - Demo *children = d->children; - GtkTreeIter iter; + GtkDemo *d = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL)); + DemoData *children = demo->children; - gtk_tree_store_append (GTK_TREE_STORE (model), &iter, NULL); + d->name = demo->name; + d->title = demo->title; + d->filename = demo->filename; + d->func = demo->func; - gtk_tree_store_set (GTK_TREE_STORE (model), - &iter, - NAME_COLUMN, d->name, - TITLE_COLUMN, d->title, - FILENAME_COLUMN, d->filename, - FUNC_COLUMN, d->func, - STYLE_COLUMN, PANGO_STYLE_NORMAL, - -1); + g_list_store_append (store, d); - d++; - - if (!children) - continue; - - while (children->title) + if (children) { - GtkTreeIter child_iter; + d->children_model = G_LIST_MODEL (g_list_store_new (GTK_TYPE_DEMO)); - gtk_tree_store_append (GTK_TREE_STORE (model), &child_iter, &iter); + while (children->title) + { + GtkDemo *child = GTK_DEMO (g_object_new (GTK_TYPE_DEMO, NULL)); - gtk_tree_store_set (GTK_TREE_STORE (model), - &child_iter, - NAME_COLUMN, children->name, - TITLE_COLUMN, children->title, - FILENAME_COLUMN, children->filename, - FUNC_COLUMN, children->func, - STYLE_COLUMN, PANGO_STYLE_NORMAL, - -1); + child->name = children->name; + child->title = children->title; + child->filename = children->filename; + child->func = children->func; - children++; + g_list_store_append (G_LIST_STORE (d->children_model), child); + children++; + } } + + demo++; } + return G_LIST_MODEL (store); } -static void -row_activated_cb (GtkWidget *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column) +static GListModel * +get_child_model (gpointer item, + gpointer user_data) { - GtkTreeIter iter; - GtkWidget *window; - GtkTreeModel *model; + GtkDemo *demo = item; - window = GTK_WIDGET (gtk_widget_get_root (tree_view)); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (tree_view)); - gtk_tree_model_get_iter (model, &iter, path); + if (demo->children_model) + return g_object_ref (G_LIST_MODEL (demo->children_model)); - run_example_for_row (window, model, &iter); + return NULL; } static void activate (GApplication *app) { GtkBuilder *builder; - GtkWindow *window; - GtkWidget *widget; - GtkTreeModel *model; - GtkTreeIter iter; + GListModel *listmodel; + GtkTreeListModel *treemodel; + GtkWidget *window, *listview; static GActionEntry win_entries[] = { { "run", activate_run, NULL, NULL, NULL } @@ -1005,33 +1023,33 @@ activate (GApplication *app) builder = gtk_builder_new_from_resource ("/ui/main.ui"); - window = (GtkWindow *)gtk_builder_get_object (builder, "window"); - gtk_application_add_window (GTK_APPLICATION (app), window); + window = (GtkWidget *)gtk_builder_get_object (builder, "window"); + gtk_application_add_window (GTK_APPLICATION (app), GTK_WINDOW (window)); g_action_map_add_action_entries (G_ACTION_MAP (window), win_entries, G_N_ELEMENTS (win_entries), window); - notebook = (GtkWidget *)gtk_builder_get_object (builder, "notebook"); + notebook = GTK_WIDGET (gtk_builder_get_object (builder, "notebook")); - info_view = (GtkWidget *)gtk_builder_get_object (builder, "info-textview"); - source_view = (GtkWidget *)gtk_builder_get_object (builder, "source-textview"); - treeview = (GtkWidget *)gtk_builder_get_object (builder, "treeview"); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); + info_view = GTK_WIDGET (gtk_builder_get_object (builder, "info-textview")); + source_view = GTK_WIDGET (gtk_builder_get_object (builder, "source-textview")); toplevel = GTK_WIDGET (window); + listview = GTK_WIDGET (gtk_builder_get_object (builder, "listview")); + g_signal_connect (listview, "activate", G_CALLBACK (activate_cb), window); load_file (gtk_demos[0].name, gtk_demos[0].filename); - populate_model (model); - - g_signal_connect (treeview, "row-activated", G_CALLBACK (row_activated_cb), model); - - widget = (GtkWidget *)gtk_builder_get_object (builder, "treeview-selection"); - g_signal_connect (widget, "changed", G_CALLBACK (selection_cb), model); - - gtk_tree_model_get_iter_first (gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)), &iter); - gtk_tree_selection_select_iter (GTK_TREE_SELECTION (widget), &iter); - - gtk_tree_view_collapse_all (GTK_TREE_VIEW (treeview)); + listmodel = create_demo_model (); + treemodel = gtk_tree_list_model_new (FALSE, + G_LIST_MODEL (listmodel), + FALSE, + get_child_model, + NULL, + NULL); + selection = gtk_single_selection_new (G_LIST_MODEL (treemodel)); + g_signal_connect (selection, "notify::selected-item", G_CALLBACK (selection_cb), NULL); + gtk_list_view_set_model (GTK_LIST_VIEW (listview), + G_LIST_MODEL (selection)); award ("demo-start"); @@ -1050,7 +1068,7 @@ auto_quit (gpointer data) static void list_demos (void) { - Demo *d, *c; + DemoData *d, *c; d = gtk_demos; @@ -1077,7 +1095,7 @@ command_line (GApplication *app, const gchar *name = NULL; gboolean autoquit = FALSE; gboolean list = FALSE; - Demo *d, *c; + DemoData *d, *c; GDoDemoFunc func = 0; GtkWidget *window, *demo; diff --git a/demos/gtk-demo/main.ui b/demos/gtk-demo/main.ui index cc652598ba..beea6b3117 100644 --- a/demos/gtk-demo/main.ui +++ b/demos/gtk-demo/main.ui @@ -65,30 +65,12 @@ never 150 - - treestore - 0 - - - browse + + + + /ui/main-listitem.ui - - - - - - - 4 - 1 - - - - - - - - - +