[gtk/wip/otte/listview: 10/19] demo: Use a listview as sidebar
- From: Benjamin Otte <otte src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk/wip/otte/listview: 10/19] demo: Use a listview as sidebar
- Date: Sun, 20 Oct 2019 06:16:18 +0000 (UTC)
commit faf2143ae7a886175284a90189a04a09338ee127
Author: Timm Bäder <mail baedert org>
Date: Tue Oct 15 15:39:59 2019 +0200
demo: Use a listview as sidebar
demos/gtk-demo/demo.gresource.xml | 1 +
demos/gtk-demo/geninclude.py | 17 +-
demos/gtk-demo/main-listitem.ui | 16 ++
demos/gtk-demo/main.c | 361 ++++++++++++++++++++------------------
demos/gtk-demo/main.ui | 32 +---
5 files changed, 222 insertions(+), 205 deletions(-)
---
diff --git a/demos/gtk-demo/demo.gresource.xml b/demos/gtk-demo/demo.gresource.xml
index 8bd44e7783..7d94e0462b 100644
--- a/demos/gtk-demo/demo.gresource.xml
+++ b/demos/gtk-demo/demo.gresource.xml
@@ -5,6 +5,7 @@
</gresource>
<gresource prefix="/ui">
<file preprocess="xml-stripblanks">main.ui</file>
+ <file preprocess="xml-stripblanks">main-listitem.ui</file>
<file preprocess="xml-stripblanks">appmenu.ui</file>
</gresource>
<gresource prefix="/application_demo">
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..6f70835802
--- /dev/null
+++ b/demos/gtk-demo/main-listitem.ui
@@ -0,0 +1,16 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <template class="GtkListItem">
+ <child>
+ <object class="GtkTreeExpander" id="expander">
+ <binding name="list-row">GtkListItem.item</binding>
+ <property name="child">
+ <object class="GtkLabel">
+ <property name="halign">start</property>
+ <binding name="label">expander.item:GtkDemo.title</binding>
+ </object>
+ </property>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/demos/gtk-demo/main.c b/demos/gtk-demo/main.c
index e8af585472..9062178db1 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;
+typedef struct _GtkDemo GtkDemo;
+struct _GtkDemo
+{
+ GObject parent_instance;
+
+ const char *name;
+ const char *title;
+ const char *filename;
+ GDoDemoFunc func;
+ GListModel *children_model;
+};
+
enum {
- NAME_COLUMN,
- TITLE_COLUMN,
- FILENAME_COLUMN,
- FUNC_COLUMN,
- STYLE_COLUMN,
- NUM_COLUMNS
+ 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.
@@ -890,81 +924,72 @@ load_file (const gchar *demoname,
}
static void
-selection_cb (GtkTreeSelection *selection,
- GtkTreeModel *model)
-{
- GtkTreeIter iter;
- char *name;
- char *filename;
- char *title;
-
- if (! gtk_tree_selection_get_selected (selection, NULL, &iter))
- return;
-
- gtk_tree_model_get (model, &iter,
- NAME_COLUMN, &name,
- TITLE_COLUMN, &title,
- FILENAME_COLUMN, &filename,
- -1);
- if (filename)
- load_file (name, filename);
+selection_cb (GtkSingleSelection *selection,
+ GParamSpec *pspec,
+ gpointer user_data)
+{
+ GtkTreeListRow *row = gtk_single_selection_get_selected_item (selection);
+ GtkDemo *demo = gtk_tree_list_row_get_item (row);
- gtk_header_bar_set_title (GTK_HEADER_BAR (headerbar), title);
+ if (demo->filename)
+ load_file (demo->name, demo->filename);
- 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
@@ -984,22 +1009,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)
{
@@ -1026,34 +1035,45 @@ scrollbar_popup (GtkWidget *scrollbar, GtkWidget *menu)
return TRUE;
}
+static void
+listview_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;
GError *error = NULL;
GtkWidget *sw;
GtkWidget *scrollbar;
GtkWidget *menu;
GtkWidget *item;
+ GListModel *listmodel;
+ GtkTreeListModel *treemodel;
static GActionEntry win_entries[] = {
{ "run", activate_run, NULL, NULL, NULL }
};
builder = gtk_builder_new ();
+ gtk_builder_add_callback_symbol (builder, "listview_activate_cb", G_CALLBACK (listview_activate_cb));
gtk_builder_add_from_resource (builder, "/ui/main.ui", &error);
if (error != NULL)
{
g_critical ("%s", error->message);
exit (1);
}
+ gtk_builder_connect_signals (builder, NULL);
- 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);
@@ -1063,8 +1083,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));
@@ -1083,17 +1102,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");
@@ -1112,7 +1131,7 @@ auto_quit (gpointer data)
static void
list_demos (void)
{
- Demo *d, *c;
+ DemoData *d, *c;
d = gtk_demos;
@@ -1139,7 +1158,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..3fc5c1559e 100644
--- a/demos/gtk-demo/main.ui
+++ b/demos/gtk-demo/main.ui
@@ -28,7 +28,6 @@
<property name="default-width">800</property>
<property name="default-height">600</property>
<property name="title">GTK Demo</property>
- <signal name="destroy" handler="gtk_main_quit" swapped="no"/>
<child type="titlebar">
<object class="GtkHeaderBar" id="headerbar">
<property name="show-title-buttons">1</property>
@@ -66,32 +65,15 @@
<property name="can-focus">1</property>
<property name="hscrollbar-policy">never</property>
<property name="min-content-width">150</property>
+
<child>
- <object class="GtkTreeView" id="treeview">
- <property name="can-focus">1</property>
- <property name="model">treestore</property>
- <property name="headers-visible">0</property>
- <child internal-child="selection">
- <object class="GtkTreeSelection" id="treeview-selection">
- <property name="mode">browse</property>
+ <object class="GtkListView" id="listview">
+ <signal name="activate" handler="listview_activate_cb" swapped="no" />
+ <property name="factory">
+ <object class="GtkBuilderListItemFactory">
+ <property name="resource">/ui/main-listitem.ui</property>
</object>
- </child>
- <child>
- <object class="GtkTreeViewColumn">
- <child>
- <object class="GtkCellRendererText"/>
- <attributes>
- <attribute name="style">4</attribute>
- <attribute name="text">1</attribute>
- </attributes>
- </child>
- <child>
- <object class="GtkCellRendererText">
- <property name="text"> </property>
- </object>
- </child>
- </object>
- </child>
+ </property>
</object>
</child>
</object>
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]