From 326f4739ca00c7a3b92990c9e747c71638935a85 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Sun, 6 Dec 2015 23:06:33 -0500 Subject: [PATCH] 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 | 264 +++++++++++++++++++++++++++------ gtk/inspector/css-node-tree.ui | 178 +++++++++++++++------- 2 files changed, 350 insertions(+), 92 deletions(-) diff --git a/gtk/inspector/css-node-tree.c b/gtk/inspector/css-node-tree.c index 5c6fc175e9..bd0ec29ca5 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,37 +83,23 @@ struct _GtkInspectorCssNodeTreePrivate G_DEFINE_TYPE_WITH_PRIVATE (GtkInspectorCssNodeTree, gtk_inspector_css_node_tree, GTK_TYPE_BOX) -static void -row_activated (GtkTreeView *tv, - GtkTreePath *path, - GtkTreeViewColumn *col, - GtkInspectorCssNodeTree *cnt) -{ - GtkTreeIter iter; - GdkRectangle rect; - GtkWidget *editor; - GtkWidget *popover; +typedef struct { GtkCssNode *node; const gchar *prop_name; + GdkRectangle rect; + GtkInspectorCssNodeTree *cnt; +} NodePropEditor; - if (col == cnt->priv->node_name_column) - prop_name = "name"; - else if (col == cnt->priv->node_id_column) - prop_name = "id"; - else if (col == cnt->priv->node_classes_column) - prop_name = "classes"; - else - return; +static void +show_node_prop_editor (NodePropEditor *npe) +{ + GtkWidget *popover; + GtkWidget *editor; - gtk_tree_model_get_iter (cnt->priv->node_model, &iter, path); - 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 (npe->cnt->priv->node_tree)); + gtk_popover_set_pointing_to (GTK_POPOVER (popover), &npe->rect); - popover = gtk_popover_new (GTK_WIDGET (tv)); - gtk_popover_set_pointing_to (GTK_POPOVER (popover), &rect); - - editor = gtk_inspector_prop_editor_new (G_OBJECT (node), prop_name, FALSE); + 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); @@ -120,12 +112,169 @@ row_activated (GtkTreeView *tv, g_signal_connect (popover, "unmap", G_CALLBACK (gtk_widget_destroy), NULL); } -static void populate_properties (GtkInspectorCssNodeTree *cnt); +static void +row_activated (GtkTreeView *tv, + GtkTreePath *path, + GtkTreeViewColumn *col, + GtkInspectorCssNodeTree *cnt) +{ + GtkTreeIter iter; + NodePropEditor npe; + + npe.cnt = cnt; + + if (col == cnt->priv->node_name_column) + npe.prop_name = "name"; + else if (col == cnt->priv->node_id_column) + npe.prop_name = "id"; + else if (col == cnt->priv->node_classes_column) + 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); + + npe = g_new0 (NodePropEditor, 1); + npe->node = node; + npe->prop_name = "name"; + npe->rect = rect; + npe->cnt = cnt; + + popover = gtk_popover_new (GTK_WIDGET (cnt->priv->node_tree)); + + 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); + + gtk_tree_path_free (path); + + gtk_widget_show (popover); + + g_signal_connect (popover, "unmap", G_CALLBACK (gtk_widget_destroy), NULL); +} + +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 09b40aacc6..f34a3acbd1 100644 --- a/gtk/inspector/css-node-tree.ui +++ b/gtk/inspector/css-node-tree.ui @@ -12,17 +12,65 @@