[gtk/wip/otte/listview: 20/80] demo: Use a listview as sidebar



commit 3a5f47c3b85091dd53ac435489df1c1e05003a37
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   |  22 +++
 demos/gtk-demo/main.c             | 359 ++++++++++++++++++++------------------
 demos/gtk-demo/main.ui            |  32 +---
 5 files changed, 226 insertions(+), 205 deletions(-)
---
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 @@
   </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..a8d9c47430
--- /dev/null
+++ b/demos/gtk-demo/main-listitem.ui
@@ -0,0 +1,22 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <template class="GtkListItem">
+    <property name="child">
+      <object class="GtkTreeExpander" id="expander">
+        <binding name="list-row">
+          <lookup name="item">GtkListItem</lookup>
+        </binding>
+        <property name="child">
+          <object class="GtkLabel">
+            <property name="halign">start</property>
+            <binding name="label">
+              <lookup name="title" type="GtkDemo">
+                <lookup name="item">expander</lookup>
+              </lookup>
+            </binding>
+          </object>
+        </property>
+      </object>
+    </property>
+  </template>
+</interface>
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;
 
+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.
@@ -895,81 +929,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
@@ -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 @@
     <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="main_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]