[gtk+] inspector: Redo the CSS node page



commit 326f4739ca00c7a3b92990c9e747c71638935a85
Author: Matthias Clasen <mclasen redhat com>
Date:   Sun Dec 6 23:06:33 2015 -0500

    inspector: Redo the CSS node page
    
    Showing two lists in a paned was a bit awkward, and space was
    getting too limited. Go back to showing just the node list at
    first, and make the CSS properties available via a stack. At
    the same time, add a right-click context menu to the node list
    to make the name and class editing more easily available.

 gtk/inspector/css-node-tree.c  |  246 ++++++++++++++++++++++++++++++++++------
 gtk/inspector/css-node-tree.ui |  176 +++++++++++++++++++++--------
 2 files changed, 340 insertions(+), 82 deletions(-)
---
diff --git a/gtk/inspector/css-node-tree.c b/gtk/inspector/css-node-tree.c
index 5c6fc17..bd0ec29 100644
--- a/gtk/inspector/css-node-tree.c
+++ b/gtk/inspector/css-node-tree.c
@@ -41,6 +41,8 @@
 #include "gtktreeview.h"
 #include "gtktreeselection.h"
 #include "gtktypebuiltins.h"
+#include "gtkmodelbutton.h"
+#include "gtkstack.h"
 
 enum {
   COLUMN_NODE_NAME,
@@ -63,6 +65,10 @@ enum
 struct _GtkInspectorCssNodeTreePrivate
 {
   GtkWidget *node_tree;
+  GtkWidget *stack;
+  GtkWidget *node_list_button;
+  GtkWidget *prop_list_button;
+  GtkWidget *css_node_info;
   GtkTreeModel *node_model;
   GtkTreeViewColumn *node_name_column;
   GtkTreeViewColumn *node_id_column;
@@ -77,6 +83,35 @@ struct _GtkInspectorCssNodeTreePrivate
 
 G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorCssNodeTree, gtk_inspector_css_node_tree, GTK_TYPE_BOX)
 
+typedef struct {
+  GtkCssNode *node;
+  const gchar *prop_name;
+  GdkRectangle rect;
+  GtkInspectorCssNodeTree *cnt;
+} NodePropEditor;
+
+static void
+show_node_prop_editor (NodePropEditor *npe)
+{
+  GtkWidget *popover;
+  GtkWidget *editor;
+
+  popover = gtk_popover_new (GTK_WIDGET (npe->cnt->priv->node_tree));
+  gtk_popover_set_pointing_to (GTK_POPOVER (popover), &npe->rect);
+
+  editor = gtk_inspector_prop_editor_new (G_OBJECT (npe->node), npe->prop_name, FALSE);
+  gtk_widget_show (editor);
+
+  gtk_container_add (GTK_CONTAINER (popover), editor);
+
+  if (gtk_inspector_prop_editor_should_expand (GTK_INSPECTOR_PROP_EDITOR (editor)))
+    gtk_widget_set_vexpand (popover, TRUE);
+
+  gtk_widget_show (popover);
+
+  g_signal_connect (popover, "unmap", G_CALLBACK (gtk_widget_destroy), NULL);
+}
+
 static void
 row_activated (GtkTreeView             *tv,
                GtkTreePath             *path,
@@ -84,48 +119,162 @@ row_activated (GtkTreeView             *tv,
                GtkInspectorCssNodeTree *cnt)
 {
   GtkTreeIter iter;
-  GdkRectangle rect;
-  GtkWidget *editor;
-  GtkWidget *popover;
-  GtkCssNode *node;
-  const gchar *prop_name;
+  NodePropEditor npe;
+
+  npe.cnt = cnt;
 
   if (col == cnt->priv->node_name_column)
-    prop_name = "name";
+    npe.prop_name = "name";
   else if (col == cnt->priv->node_id_column)
-    prop_name = "id";
+    npe.prop_name = "id";
   else if (col == cnt->priv->node_classes_column)
-    prop_name = "classes";
+    npe.prop_name = "classes";
   else
     return;
 
   gtk_tree_model_get_iter (cnt->priv->node_model, &iter, path);
+  npe.node = gtk_tree_model_css_node_get_node_from_iter (GTK_TREE_MODEL_CSS_NODE (cnt->priv->node_model), 
&iter);
+  gtk_tree_view_get_cell_area (tv, path, col, &npe.rect);
+  gtk_tree_view_convert_bin_window_to_widget_coords (tv, npe.rect.x, npe.rect.y, &npe.rect.x, &npe.rect.y);
+
+  show_node_prop_editor (&npe);
+}
+
+static void
+switch_to_node_list (GtkInspectorCssNodeTree *cnt)
+{
+  gtk_stack_set_visible_child_name (GTK_STACK (cnt->priv->stack), "node-list");
+  gtk_widget_show (cnt->priv->prop_list_button);
+  gtk_widget_hide (cnt->priv->node_list_button);
+}
+
+static void
+switch_to_prop_list (GtkInspectorCssNodeTree *cnt)
+{
+  gtk_stack_set_visible_child_name (GTK_STACK (cnt->priv->stack), "prop-list");
+  gtk_widget_show (cnt->priv->node_list_button);
+  gtk_widget_hide (cnt->priv->prop_list_button);
+}
+
+static void
+show_node_popover (GtkInspectorCssNodeTree *cnt,
+                   gdouble                  x,
+                   gdouble                  y)
+{
+  GtkTreeSelection *selection;
+  GdkRectangle rect;
+  GtkWidget *popover;
+  GtkWidget *box;
+  GtkWidget *button;
+  GtkTreeIter iter;
+  GtkTreePath *path;
+  NodePropEditor *npe;
+  GtkCssNode *node;
+
+  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (cnt->priv->node_tree));
+  if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+    return;
+
+  path = gtk_tree_model_get_path (cnt->priv->node_model, &iter);
+  gtk_tree_view_get_cell_area (GTK_TREE_VIEW (cnt->priv->node_tree), path, NULL, &rect);
+  gtk_tree_view_convert_bin_window_to_widget_coords (GTK_TREE_VIEW (cnt->priv->node_tree),
+                                                     rect.x, rect.y, &rect.x, &rect.y);
+
+  rect.x = CLAMP (x - 20, 0, gtk_widget_get_allocated_width (cnt->priv->node_tree) - 40);
+  rect.width = 40;
+
   node = gtk_tree_model_css_node_get_node_from_iter (GTK_TREE_MODEL_CSS_NODE (cnt->priv->node_model), &iter);
-  gtk_tree_view_get_cell_area (tv, path, col, &rect);
-  gtk_tree_view_convert_bin_window_to_widget_coords (tv, rect.x, rect.y, &rect.x, &rect.y);
 
-  popover = gtk_popover_new (GTK_WIDGET (tv));
-  gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect);
+  npe = g_new0 (NodePropEditor, 1);
+  npe->node = node;
+  npe->prop_name = "name";
+  npe->rect = rect;
+  npe->cnt = cnt;
 
-  editor = gtk_inspector_prop_editor_new (G_OBJECT (node), prop_name, FALSE);
-  gtk_widget_show (editor);
+  popover = gtk_popover_new (GTK_WIDGET (cnt->priv->node_tree));
 
-  gtk_container_add (GTK_CONTAINER (popover), editor);
+  gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect);
+  box = g_object_new (GTK_TYPE_BOX,
+                      "orientation", GTK_ORIENTATION_VERTICAL,
+                      "visible", TRUE,
+                      "margin", 10,
+                      NULL);
+  gtk_container_add (GTK_CONTAINER (popover), box);
+  button = g_object_new (GTK_TYPE_MODEL_BUTTON,
+                         "visible", TRUE,
+                         "text", _("Change name"),
+                         NULL);
+  g_signal_connect_swapped (button, "clicked", G_CALLBACK (show_node_prop_editor), npe);
+  g_object_set_data_full (G_OBJECT (popover), "prop-name", npe, g_free);
+
+  gtk_container_add (GTK_CONTAINER (box), button);
+
+  npe = g_new0 (NodePropEditor, 1);
+  npe->node = node;
+  npe->prop_name = "classes";
+  npe->rect = rect;
+  npe->cnt = cnt;
+
+  button = g_object_new (GTK_TYPE_MODEL_BUTTON,
+                         "visible", TRUE,
+                         "text", _("Change classes"),
+                         NULL);
+  g_signal_connect_swapped (button, "clicked", G_CALLBACK (show_node_prop_editor), npe);
+  g_object_set_data_full (G_OBJECT (popover), "prop-classes", npe, g_free);
+
+  gtk_container_add (GTK_CONTAINER (box), button);
+
+  button = g_object_new (GTK_TYPE_MODEL_BUTTON,
+                         "visible", TRUE,
+                         "text", _("CSS properties"),
+                         NULL);
+  g_signal_connect_swapped (button, "clicked", G_CALLBACK (switch_to_prop_list), cnt);
+  gtk_container_add (GTK_CONTAINER (box), button);
 
-  if (gtk_inspector_prop_editor_should_expand (GTK_INSPECTOR_PROP_EDITOR (editor)))
-    gtk_widget_set_vexpand (popover, TRUE);
+  gtk_tree_path_free (path);
 
   gtk_widget_show (popover);
 
   g_signal_connect (popover, "unmap", G_CALLBACK (gtk_widget_destroy), NULL);
 }
 
-static void populate_properties (GtkInspectorCssNodeTree *cnt);
+static gboolean
+button_pressed (GtkWidget               *widget,
+                GdkEventButton          *event,
+                GtkInspectorCssNodeTree *cnt)
+{
+  static gboolean in_press = FALSE;
+
+  if (in_press)
+    return FALSE;
+
+  if (!gdk_event_triggers_context_menu ((GdkEvent *)event))
+    return FALSE;
+
+  in_press = TRUE;
+  gtk_widget_event (cnt->priv->node_tree, (GdkEvent *) event);
+  in_press = FALSE;
+
+ show_node_popover (cnt, event->x, event->y);
+
+  return TRUE;
+}
+
+static void
+gtk_inspector_css_node_tree_set_node (GtkInspectorCssNodeTree *cnt,
+                                      GtkCssNode              *node);
 
 static void
 selection_changed (GtkTreeSelection *selection, GtkInspectorCssNodeTree *cnt)
 {
-  populate_properties (cnt);
+  GtkTreeIter iter;
+  GtkCssNode *node;
+
+  if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+    return;
+
+  node = gtk_tree_model_css_node_get_node_from_iter (GTK_TREE_MODEL_CSS_NODE (cnt->priv->node_model), &iter);
+  gtk_inspector_css_node_tree_set_node (cnt, node);
 }
 
 static void
@@ -189,9 +338,16 @@ gtk_inspector_css_node_tree_class_init (GtkInspectorCssNodeTreeClass *klass)
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, prop_name_column);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, prop_model);
   gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, prop_name_column);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, stack);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, prop_list_button);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, node_list_button);
+  gtk_widget_class_bind_template_child_private (widget_class, GtkInspectorCssNodeTree, css_node_info);
 
   gtk_widget_class_bind_template_callback (widget_class, row_activated);
   gtk_widget_class_bind_template_callback (widget_class, selection_changed);
+  gtk_widget_class_bind_template_callback (widget_class, button_pressed);
+  gtk_widget_class_bind_template_callback (widget_class, switch_to_node_list);
+  gtk_widget_class_bind_template_callback (widget_class, switch_to_prop_list);
 }
 
 static int
@@ -351,10 +507,14 @@ gtk_inspector_css_node_tree_set_object (GtkInspectorCssNodeTree *cnt,
 
   if (!GTK_IS_WIDGET (object))
     {
-      gtk_tree_model_css_node_set_root_node (GTK_TREE_MODEL_CSS_NODE (priv->node_model), NULL);
+      gtk_widget_hide (GTK_WIDGET (cnt));
       return;
     }
 
+  gtk_widget_show (GTK_WIDGET (cnt));
+
+  switch_to_node_list (cnt);
+
   root = node = gtk_widget_get_css_node (GTK_WIDGET (object));
   while (gtk_css_node_get_parent (root))
     root = gtk_css_node_get_parent (root);
@@ -426,6 +586,11 @@ gtk_inspector_css_node_tree_set_node (GtkInspectorCssNodeTree *cnt,
                                       GtkCssNode              *node)
 {
   GtkInspectorCssNodeTreePrivate *priv = cnt->priv;
+  GString *s;
+  GType type;
+  const gchar *name;
+  gchar **strv;
+  gint i;
 
   if (priv->node == node)
     return;
@@ -443,22 +608,37 @@ gtk_inspector_css_node_tree_set_node (GtkInspectorCssNodeTree *cnt,
   priv->node = node;
 
   g_signal_connect (node, "style-changed", G_CALLBACK (gtk_inspector_css_node_tree_update_style), cnt);
-}
 
-static void
-populate_properties (GtkInspectorCssNodeTree *cnt)
-{
-  GtkInspectorCssNodeTreePrivate *priv = cnt->priv;
-  GtkTreeSelection *selection;
-  GtkTreeIter titer;
-  GtkCssNode *node;
+  s = g_string_new ("");
+  type = gtk_css_node_get_widget_type (node);
+  if (type != G_TYPE_NONE && type != G_TYPE_INVALID)
+    g_string_append (s, g_type_name (type));
 
-  selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (priv->node_tree));
-  if (!gtk_tree_selection_get_selected (selection, NULL, &titer))
-    return;
+  name = gtk_css_node_get_name (node);
+  if (name)
+    {
+      if (s->len > 0)
+        g_string_append (s, " — ");
+      g_string_append (s, name);
+    }
 
-  node = gtk_tree_model_css_node_get_node_from_iter (GTK_TREE_MODEL_CSS_NODE (priv->node_model), &titer);
-  gtk_inspector_css_node_tree_set_node (cnt, node);
+  strv = gtk_css_node_get_classes (node);
+  if (strv[0] != NULL)
+    {
+      strv_sort (strv);
+      if (s->len > 0)
+        g_string_append (s, " — ");
+      for (i = 0; strv[i]; i++)
+        {
+          if (i > 0)
+            g_string_append (s, " ");
+          g_string_append (s, strv[i]);
+        }
+      g_strfreev (strv);
+    }
+
+  gtk_label_set_label (GTK_LABEL (cnt->priv->css_node_info), s->str);
+  g_string_free (s, TRUE);
 }
 
 // vim: set et sw=2 ts=2:
diff --git a/gtk/inspector/css-node-tree.ui b/gtk/inspector/css-node-tree.ui
index 09b40aa..f34a3ac 100644
--- a/gtk/inspector/css-node-tree.ui
+++ b/gtk/inspector/css-node-tree.ui
@@ -12,17 +12,65 @@
   <template class="GtkInspectorCssNodeTree" parent="GtkBox">
     <property name="orientation">vertical</property>
     <child>
-      <object class="GtkLabel" id="object_title">
+      <object class="GtkBox">
         <property name="visible">1</property>
-        <property name="valign">center</property>
-        <property name="margin-top">12</property>
-        <property name="margin-bottom">12</property>
+        <property name="margin-start">6</property>
+        <property name="margin-end">6</property>
+        <child type="center">
+          <object class="GtkLabel" id="object_title">
+            <property name="visible">1</property>
+            <property name="valign">center</property>
+            <property name="margin">12</property>
+          </object>
+        </child>
+        <child>
+          <object class="GtkButton" id="node_list_button">
+            <property name="valign">center</property>
+            <property name="no-show-all">1</property>
+            <property name="relief">none</property>
+            <property name="tooltip-text" translatable="yes">Show all CSS nodes</property>
+            <signal name="clicked" handler="switch_to_node_list" swapped="1"/>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">1</property>
+                <property name="icon-name">pan-start-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
+            <style>
+              <class name="image-button"/>
+            </style>
+          </object>
+        </child>
+        <child>
+          <object class="GtkButton" id="prop_list_button">
+            <property name="visible">1</property>
+            <property name="valign">center</property>
+            <property name="no-show-all">1</property>
+            <property name="relief">none</property>
+            <property name="tooltip-text" translatable="yes">Show CSS properties</property>
+            <signal name="clicked" handler="switch_to_prop_list" swapped="1"/>
+            <child>
+              <object class="GtkImage">
+                <property name="visible">1</property>
+                <property name="icon-name">pan-end-symbolic</property>
+                <property name="icon-size">1</property>
+              </object>
+            </child>
+            <style>
+              <class name="image-button"/>
+            </style>
+          </object>
+          <packing>
+            <property name="pack-type">end</property>
+          </packing>
+        </child>
       </object>
     </child>
     <child>
-      <object class="GtkPaned">
+      <object class="GtkStack" id="stack">
         <property name="visible">1</property>
-        <property name="orientation">vertical</property>
+        <property name="transition-type">slide-left-right</property>
         <child>
           <object class="GtkScrolledWindow">
             <property name="visible">1</property>
@@ -34,9 +82,9 @@
                 <property name="search-column">0</property>
                 <property name="enable-search">0</property>
                 <signal name="row-activated" handler="row_activated"/>
+                <signal name="button-press-event" handler="button_pressed"/>
                 <child internal-child="selection">
                   <object class="GtkTreeSelection">
-                    <property name="mode">single</property>
                     <signal name="changed" handler="selection_changed"/>
                   </object>
                 </child>
@@ -108,68 +156,98 @@
               </object>
             </child>
           </object>
+          <packing>
+            <property name="name">node-list</property>
+          </packing>
         </child>
         <child>
-          <object class="GtkScrolledWindow">
+          <object class="GtkBox">
             <property name="visible">1</property>
-            <property name="expand">1</property>
-            <property name="min-content-height">100</property>
+            <property name="orientation">vertical</property>
             <child>
-              <object class="GtkTreeView" id="prop_tree">
+              <object class="GtkBox">
                 <property name="visible">1</property>
-                <property name="model">prop_model</property>
-                <property name="search-column">0</property>
-                <property name="enable-search">0</property>
+                <property name="orientation">horizontal</property>
+                <property name="margin">12</property>
                 <child>
-                  <object class="GtkTreeViewColumn" id="prop_name_column">
-                    <property name="title" translatable="yes">Property</property>
-                    <property name="resizable">1</property>
-                    <property name="sort-column-id">0</property>
-                    <child>
-                      <object class="GtkCellRendererText">
-                        <property name="scale">0.8</property>
-                      </object>
-                      <attributes>
-                        <attribute name="text">0</attribute>
-                      </attributes>
-                    </child>
+                  <object class="GtkLabel">
+                    <property name="visible">1</property>
+                    <property name="label" translatable="yes">Node:</property>
                   </object>
                 </child>
+                <child type="center">
+                  <object class="GtkLabel" id="css_node_info">
+                    <property name="visible">1</property>
+                  </object>
+                </child>
+              </object>
+            </child>
+            <child>
+              <object class="GtkScrolledWindow">
+                <property name="visible">1</property>
+                <property name="expand">1</property>
+                <property name="min-content-height">100</property>
                 <child>
-                  <object class="GtkTreeViewColumn">
-                    <property name="title" translatable="yes">Value</property>
-                    <property name="resizable">1</property>
+                  <object class="GtkTreeView" id="prop_tree">
+                    <property name="visible">1</property>
+                    <property name="model">prop_model</property>
+                    <property name="search-column">0</property>
+                    <property name="enable-search">0</property>
                     <child>
-                      <object class="GtkCellRendererText">
-                        <property name="scale">0.8</property>
-                        <property name="width-chars">20</property>
-                        <property name="ellipsize">end</property>
+                      <object class="GtkTreeViewColumn" id="prop_name_column">
+                        <property name="title" translatable="yes">CSS Property</property>
+                        <property name="resizable">1</property>
+                        <property name="sort-column-id">0</property>
+                        <child>
+                          <object class="GtkCellRendererText">
+                            <property name="scale">0.8</property>
+                          </object>
+                          <attributes>
+                            <attribute name="text">0</attribute>
+                          </attributes>
+                        </child>
                       </object>
-                      <attributes>
-                        <attribute name="text">1</attribute>
-                      </attributes>
                     </child>
-                  </object>
-                </child>
-                <child>
-                  <object class="GtkTreeViewColumn">
-                    <property name="title" translatable="yes">Location</property>
-                    <property name="resizable">1</property>
                     <child>
-                      <object class="GtkCellRendererText">
-                        <property name="scale">0.8</property>
-                        <property name="width-chars">20</property>
-                        <property name="ellipsize">end</property>
+                      <object class="GtkTreeViewColumn">
+                        <property name="title" translatable="yes">Value</property>
+                        <property name="resizable">1</property>
+                        <child>
+                          <object class="GtkCellRendererText">
+                            <property name="scale">0.8</property>
+                            <property name="width-chars">20</property>
+                            <property name="ellipsize">end</property>
+                          </object>
+                          <attributes>
+                            <attribute name="text">1</attribute>
+                          </attributes>
+                        </child>
+                      </object>
+                    </child>
+                    <child>
+                      <object class="GtkTreeViewColumn">
+                        <property name="title" translatable="yes">Location</property>
+                        <property name="resizable">1</property>
+                        <child>
+                          <object class="GtkCellRendererText">
+                            <property name="scale">0.8</property>
+                            <property name="width-chars">20</property>
+                            <property name="ellipsize">end</property>
+                          </object>
+                          <attributes>
+                            <attribute name="text">2</attribute>
+                          </attributes>
+                        </child>
                       </object>
-                      <attributes>
-                        <attribute name="text">2</attribute>
-                      </attributes>
                     </child>
                   </object>
                 </child>
               </object>
             </child>
           </object>
+          <packing>
+            <property name="name">prop-list</property>
+          </packing>
         </child>
       </object>
     </child>


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]