diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml index acd6ed7543..f73721e027 100644 --- a/demos/gtk-demo/demo.gresource.xml +++ b/demos/gtk-demo/demo.gresource.xml @@ -5,6 +5,7 @@ main.ui + main-listitem.ui appmenu.ui diff --git a/demos/gtk-demo/geninclude.py b/demos/gtk-demo/geninclude.py index cd0af14e0d..878308648e 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 { - gchar *name; - gchar *title; - gchar *filename; + char *name; + char *title; + 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 53f0dfc605..20c2c06733 100644 --- a/demos/gtk-demo/main.c +++ b/demos/gtk-demo/main.c @@ -16,19 +16,99 @@ static GtkWidget *source_view; static gchar *current_file = NULL; +static GtkWidget *window; static GtkWidget *notebook; -static GtkWidget *treeview; +static GtkWidget *listview; +static GtkSingleSelection *selection; static GtkWidget *headerbar; -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 +116,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, @@ -115,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) { - 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. @@ -895,81 +929,72 @@ load_file (const gchar *demoname, } static void -selection_cb (GtkTreeSelection *selection, - GtkTreeModel *model) + +selection_cb (GtkSingleSelection *selection, + GParamSpec *pspec, + gpointer user_data) { - GtkTreeIter iter; - char *name; - char *filename; - char *title; + GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection); + GtkDemo *demo = gtk_tree_list_row_get_item (row); - if (! gtk_tree_selection_get_selected (selection, NULL, &iter)) - return; + if (demo->filename) + load_file (demo->name, demo->filename); - gtk_tree_model_get (model, &iter, - NAME_COLUMN, &name, - TITLE_COLUMN, &title, - FILENAME_COLUMN, &filename, - -1); - - if (filename) - load_file (name, filename); - - gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), title); - - g_free (name); - g_free (title); - g_free (filename); + gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), demo->title); } -static void -populate_model (GtkTreeModel *model) +static GListModel * +create_demo_model (void) { - Demo *d = gtk_demos; + GListStore *store = g_list_store_new (GTK_TYPE_DEMO); + DemoData *demo = gtk_demos; - /* this code only supports 1 level of children. If we - * want more we probably have to use a recursing function. - */ - while (d->title) + 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 GListModel * +get_child_model (gpointer item, + gpointer user_data) +{ + GtkDemo *demo = item; + + if (demo->children_model) + return g_object_ref (G_LIST_MODEL (demo->children_model)); + + return NULL; } static void @@ -989,22 +1014,6 @@ startup (GApplication *app) g_object_unref (builder); } -static void -row_activated_cb (GtkWidget *tree_view, - GtkTreePath *path, - GtkTreeViewColumn *column) -{ - GtkTreeIter iter; - GtkWidget *window; - GtkTreeModel *model; - - 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); - - run_example_for_row (window, model, &iter); -} - static void start_cb (GtkMenuItem *item, GtkWidget *scrollbar) { @@ -1031,18 +1040,27 @@ scrollbar_popup (GtkWidget *scrollbar, GtkWidget *menu) return TRUE; } +void +main_activate_cb (GtkListView *listview, + guint position, + gpointer user_data) +{ + GtkTreeListRow *row = g_list_model_get_item (gtk_list_view_get_model (listview), position); + GtkDemo *demo = gtk_tree_list_row_get_item (row); + + gtk_demo_run (demo, window); +} + static void activate (GApplication *app) { GtkBuilder *builder; - GtkWindow *window; - GtkWidget *widget; - GtkTreeModel *model; - GtkTreeIter iter; GtkWidget *sw; GtkWidget *scrollbar; GtkWidget *menu; GtkWidget *item; + GListModel *listmodel; + GtkTreeListModel *treemodel; static GActionEntry win_entries[] = { { "run", activate_run, NULL, NULL, NULL } @@ -1050,8 +1068,8 @@ 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); @@ -1061,8 +1079,7 @@ activate (GApplication *app) info_view = (GtkWidget *)gtk_builder_get_object (builder, "info-textview"); source_view = (GtkWidget *)gtk_builder_get_object (builder, "source-textview"); headerbar = (GtkWidget *)gtk_builder_get_object (builder, "headerbar"); - treeview = (GtkWidget *)gtk_builder_get_object (builder, "treeview"); - model = gtk_tree_view_get_model (GTK_TREE_VIEW (treeview)); + listview = (GtkWidget *)gtk_builder_get_object (builder, "listview"); sw = (GtkWidget *)gtk_builder_get_object (builder, "source-scrolledwindow"); scrollbar = gtk_scrolled_window_get_vscrollbar (GTK_SCROLLED_WINDOW (sw)); @@ -1081,17 +1098,17 @@ activate (GApplication *app) 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"); @@ -1110,7 +1127,7 @@ auto_quit (gpointer data) static void list_demos (void) { - Demo *d, *c; + DemoData *d, *c; d = gtk_demos; @@ -1137,7 +1154,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 bf70a37be6..b6b04f7326 100644 --- a/demos/gtk-demo/main.ui +++ b/demos/gtk-demo/main.ui @@ -28,7 +28,6 @@ 800 600 GTK Demo - 1 @@ -66,32 +65,15 @@ 1 never 150 + - - 1 - treestore - 0 - - - browse + + + + + /ui/main-listitem.ui - - - - - - - 4 - 1 - - - - - - - - - +