[gtk/constraint-editor-fun: 2/3] constraint editor: Allow editing children



commit bc1f2ded846d8396670ab9249a470a460ead9f85
Author: Matthias Clasen <mclasen redhat com>
Date:   Tue Jul 2 22:21:07 2019 +0000

    constraint editor: Allow editing children
    
    Just name and size, for now.

 demos/constraint-editor/child-editor.c             | 262 +++++++++++++++++++++
 demos/constraint-editor/child-editor.h             |  32 +++
 demos/constraint-editor/child-editor.ui            |  84 +++++++
 demos/constraint-editor/constraint-editor-window.c |  60 +++--
 .../constraint-editor.gresource.xml                |   1 +
 demos/constraint-editor/constraint-view.c          |   6 +-
 demos/constraint-editor/meson.build                |   1 +
 7 files changed, 426 insertions(+), 20 deletions(-)
---
diff --git a/demos/constraint-editor/child-editor.c b/demos/constraint-editor/child-editor.c
new file mode 100644
index 0000000000..be22e391ef
--- /dev/null
+++ b/demos/constraint-editor/child-editor.c
@@ -0,0 +1,262 @@
+/*
+ * Copyright © 2019 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen
+ */
+
+#include "config.h"
+
+#include "child-editor.h"
+
+struct _ChildEditor
+{
+  GtkWidget parent_instance;
+
+  GtkWidget *grid;
+  GtkWidget *name;
+  GtkWidget *min_width;
+  GtkWidget *min_height;
+  GtkWidget *button;
+
+  GtkWidget *child;
+
+  gboolean constructed;
+};
+
+enum {
+  PROP_CHILD = 1,
+  LAST_PROP
+};
+
+static GParamSpec *pspecs[LAST_PROP];
+
+enum {
+  DONE,
+  LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+G_DEFINE_TYPE(ChildEditor, child_editor, GTK_TYPE_WIDGET);
+
+void
+child_editor_serialize_child (GString   *str,
+                              int        indent,
+                              GtkWidget *child)
+{
+  int min_width, min_height;
+  const char *name;
+
+  name = gtk_widget_get_name (child);
+  if (!name)
+    name = "";
+
+  gtk_widget_get_size_request (child, &min_width, &min_height);
+
+  g_string_append_printf (str, "%*s<child>\n", indent, "");
+  g_string_append_printf (str, "%*s  <object class=\"GtkLabel\" id=\"%s\">\n", indent, "", name);
+  g_string_append_printf (str, "%*s    <property name=\"label\">%s</property>\n", indent, "", name);
+  if (min_width != -1)
+    g_string_append_printf (str, "%*s    <property name=\"width-request\">%d</property>\n", indent, "", 
min_width);
+  if (min_height != -1)
+    g_string_append_printf (str, "%*s    <property name=\"height-request\">%d</property>\n", indent, "", 
min_height);
+  g_string_append_printf (str, "%*s  </object>\n", indent, "");
+  g_string_append_printf (str, "%*s</child>\n", indent, "");
+}
+
+static void
+apply (GtkButton   *button,
+       ChildEditor *editor)
+{
+  const char *name;
+  int w, h;
+
+  name = gtk_editable_get_text (GTK_EDITABLE (editor->name));
+  w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_width));
+  h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->min_height));
+
+  gtk_widget_set_size_request (editor->child, w, h);
+  gtk_widget_set_name (editor->child, name);
+
+  g_signal_emit (editor, signals[DONE], 0, editor->child);
+}
+
+static void
+child_editor_init (ChildEditor *editor)
+{
+  gtk_widget_init_template (GTK_WIDGET (editor));
+}
+
+static int
+min_input (GtkSpinButton *spin_button,
+           double        *new_val)
+{
+  if (strcmp (gtk_editable_get_text (GTK_EDITABLE (spin_button)), "") == 0)
+    {
+      *new_val = 0.0;
+      return TRUE;
+    }
+
+  return FALSE;
+}
+
+static gboolean
+min_output (GtkSpinButton *spin_button)
+{
+  GtkAdjustment *adjustment;
+  double value;
+  GtkWidget *box, *text;
+
+  adjustment = gtk_spin_button_get_adjustment (spin_button);
+  value = gtk_adjustment_get_value (adjustment);
+
+  box = gtk_widget_get_first_child (GTK_WIDGET (spin_button));
+  text = gtk_widget_get_first_child (box);
+
+  if (value <= 0.0)
+    {
+      gtk_editable_set_text (GTK_EDITABLE (spin_button), "");
+      gtk_text_set_placeholder_text (GTK_TEXT (text), "unset");
+      return TRUE;
+    }
+  else
+    {
+      gtk_text_set_placeholder_text (GTK_TEXT (text), "");
+      return FALSE;
+    }
+}
+
+static void
+child_editor_constructed (GObject *object)
+{
+  ChildEditor *editor = CHILD_EDITOR (object);
+  const char *nick;
+  int w, h;
+
+  g_signal_connect (editor->min_width, "input", G_CALLBACK (min_input), NULL);
+  g_signal_connect (editor->min_width, "output", G_CALLBACK (min_output), NULL);
+
+  g_signal_connect (editor->min_height, "input", G_CALLBACK (min_input), NULL);
+  g_signal_connect (editor->min_height, "output", G_CALLBACK (min_output), NULL);
+
+  nick = gtk_widget_get_name (editor->child);
+  if (nick)
+    gtk_editable_set_text (GTK_EDITABLE (editor->name), nick);
+
+  gtk_widget_get_size_request (editor->child, &w, &h);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w);
+  gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h);
+
+  editor->constructed = TRUE;
+}
+
+static void
+child_editor_set_property (GObject      *object,
+                           guint         property_id,
+                           const GValue *value,
+                           GParamSpec   *pspec)
+{
+  ChildEditor *self = CHILD_EDITOR (object);
+
+  switch (property_id)
+    {
+    case PROP_CHILD:
+      self->child = g_value_dup_object (value);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+child_editor_get_property (GObject    *object,
+                           guint       property_id,
+                           GValue     *value,
+                           GParamSpec *pspec)
+{
+  ChildEditor *self = CHILD_EDITOR (object);
+
+  switch (property_id)
+    {
+    case PROP_CHILD:
+      g_value_set_object (value, self->child);
+      break;
+
+    default:
+      G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
+    }
+}
+
+static void
+child_editor_dispose (GObject *object)
+{
+  ChildEditor *self = (ChildEditor *)object;
+
+  g_clear_pointer (&self->grid, gtk_widget_unparent);
+  g_clear_object (&self->child);
+
+  G_OBJECT_CLASS (child_editor_parent_class)->dispose (object);
+}
+
+static void
+child_editor_class_init (ChildEditorClass *class)
+{
+  GObjectClass *object_class = G_OBJECT_CLASS (class);
+  GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class);
+
+  object_class->constructed = child_editor_constructed;
+  object_class->dispose = child_editor_dispose;
+  object_class->set_property = child_editor_set_property;
+  object_class->get_property = child_editor_get_property;
+
+  pspecs[PROP_CHILD] =
+    g_param_spec_object ("child", "child", "child",
+                         GTK_TYPE_WIDGET,
+                         G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY);
+
+  g_object_class_install_properties (object_class, LAST_PROP, pspecs);
+
+  signals[DONE] =
+    g_signal_new ("done",
+                  G_TYPE_FROM_CLASS (object_class),
+                  G_SIGNAL_RUN_LAST,
+                  0,
+                  NULL, NULL,
+                  NULL,
+                  G_TYPE_NONE, 1, GTK_TYPE_WIDGET);
+
+  gtk_widget_class_set_layout_manager_type (widget_class, GTK_TYPE_BIN_LAYOUT);
+
+  gtk_widget_class_set_template_from_resource (widget_class,
+                                               "/org/gtk/gtk4/constraint-editor/child-editor.ui");
+
+  gtk_widget_class_bind_template_child (widget_class, ChildEditor, grid);
+  gtk_widget_class_bind_template_child (widget_class, ChildEditor, name);
+  gtk_widget_class_bind_template_child (widget_class, ChildEditor, min_width);
+  gtk_widget_class_bind_template_child (widget_class, ChildEditor, min_height);
+  gtk_widget_class_bind_template_child (widget_class, ChildEditor, button);
+
+  gtk_widget_class_bind_template_callback (widget_class, apply);
+}
+
+ChildEditor *
+child_editor_new (GtkWidget *child)
+{
+  return g_object_new (CHILD_EDITOR_TYPE,
+                       "child", child,
+                       NULL);
+}
diff --git a/demos/constraint-editor/child-editor.h b/demos/constraint-editor/child-editor.h
new file mode 100644
index 0000000000..71bd90e034
--- /dev/null
+++ b/demos/constraint-editor/child-editor.h
@@ -0,0 +1,32 @@
+/*
+ * Copyright © 2019 Red Hat, Inc
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library. If not, see <http://www.gnu.org/licenses/>.
+ *
+ * Authors: Matthias Clasen
+ */
+
+#pragma once
+
+#include <gtk/gtk.h>
+
+#define CHILD_EDITOR_TYPE (child_editor_get_type ())
+
+G_DECLARE_FINAL_TYPE (ChildEditor, child_editor, CHILD, EDITOR, GtkWidget)
+
+ChildEditor * child_editor_new (GtkWidget *child);
+
+void child_editor_serialize_child (GString   *str,
+                                   int        indent,
+                                   GtkWidget *child);
diff --git a/demos/constraint-editor/child-editor.ui b/demos/constraint-editor/child-editor.ui
new file mode 100644
index 0000000000..f66f375982
--- /dev/null
+++ b/demos/constraint-editor/child-editor.ui
@@ -0,0 +1,84 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+  <object class="GtkAdjustment" id="min_width_adj">
+    <property name="lower">0</property>
+    <property name="upper">2147483647</property>
+    <property name="step-increment">1</property>
+    <property name="page-increment">10</property>
+    <property name="page-size">0</property>
+  </object>
+  <object class="GtkAdjustment" id="min_height_adj">
+    <property name="lower">0</property>
+    <property name="upper">2147483647</property>
+    <property name="step-increment">1</property>
+    <property name="page-increment">10</property>
+    <property name="page-size">0</property>
+  </object>
+  <template class="ChildEditor" parent="GtkWidget">
+    <child>
+      <object class="GtkGrid" id="grid">
+        <property name="margin">20</property>
+        <property name="row-spacing">10</property>
+        <property name="column-spacing">10</property>
+        <child>
+          <object class="GtkLabel">
+            <property name="label">Name</property>
+            <layout>
+              <property name="left-attach">0</property>
+              <property name="top-attach">0</property>
+            </layout>
+          </object>
+        </child>
+        <child>
+          <object class="GtkEntry" id="name">
+            <property name="max-width-chars">20</property>
+            <layout>
+              <property name="left-attach">1</property>
+              <property name="top-attach">0</property>
+              <property name="column-span">2</property>
+            </layout>
+          </object>
+        </child>
+        <child>
+          <object class="GtkLabel">
+            <property name="label">Min Size</property>
+            <layout>
+              <property name="left-attach">0</property>
+              <property name="top-attach">1</property>
+            </layout>
+          </object>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="min_width">
+            <property name="adjustment">min_width_adj</property>
+            <property name="max-width-chars">5</property>
+            <layout>
+              <property name="left-attach">1</property>
+              <property name="top-attach">1</property>
+            </layout>
+          </object>
+        </child>
+        <child>
+          <object class="GtkSpinButton" id="min_height">
+            <property name="adjustment">min_height_adj</property>
+            <property name="max-width-chars">5</property>
+            <layout>
+              <property name="left-attach">2</property>
+              <property name="top-attach">1</property>
+            </layout>
+          </object>
+        </child>
+        <child>
+          <object class="GtkButton" id="button">
+            <property name="label">Apply</property>
+            <signal name="clicked" handler="apply"/>
+            <layout>
+              <property name="left-attach">2</property>
+              <property name="top-attach">5</property>
+            </layout>
+          </object>
+        </child>
+      </object>
+    </child>
+  </template>
+</interface>
diff --git a/demos/constraint-editor/constraint-editor-window.c 
b/demos/constraint-editor/constraint-editor-window.c
index 2b5654b98a..152547f245 100644
--- a/demos/constraint-editor/constraint-editor-window.c
+++ b/demos/constraint-editor/constraint-editor-window.c
@@ -23,6 +23,7 @@
 #include "constraint-view.h"
 #include "constraint-editor.h"
 #include "guide-editor.h"
+#include "child-editor.h"
 
 struct _ConstraintEditorWindow
 {
@@ -453,6 +454,33 @@ edit_guide (ConstraintEditorWindow *win,
   gtk_widget_show (window);
 }
 
+static void
+child_editor_done (ChildEditor            *editor,
+                   GtkWidget              *child,
+                   ConstraintEditorWindow *win)
+{
+  gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW));
+}
+
+static void
+edit_child (ConstraintEditorWindow *win,
+            GtkWidget              *child)
+{
+  GtkWidget *window;
+  ChildEditor *editor;
+
+  window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+  gtk_window_set_resizable (GTK_WINDOW (window), FALSE);
+  gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win));
+  gtk_window_set_title (GTK_WINDOW (window), "Edit Child");
+
+  editor = child_editor_new (child);
+  gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor));
+
+  g_signal_connect (editor, "done", G_CALLBACK (child_editor_done), win);
+  gtk_widget_show (window);
+}
+
 static void
 row_activated (GtkListBox *list,
                GtkListBoxRow *row,
@@ -466,6 +494,8 @@ row_activated (GtkListBox *list,
     edit_constraint (win, GTK_CONSTRAINT (item));
   else if (GTK_IS_CONSTRAINT_GUIDE (item))
     edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
+  else if (GTK_IS_WIDGET (item))
+    edit_child (win, GTK_WIDGET (item));
 }
 
 static void
@@ -506,6 +536,8 @@ row_edit (GtkButton *button,
     edit_constraint (win, GTK_CONSTRAINT (item));
   else if (GTK_IS_CONSTRAINT_GUIDE (item))
     edit_guide (win, GTK_CONSTRAINT_GUIDE (item));
+  else if (GTK_IS_WIDGET (item))
+    edit_child (win, GTK_WIDGET (item));
 }
 
 static void
@@ -594,25 +626,15 @@ create_widget_func (gpointer item,
   gtk_container_add (GTK_CONTAINER (row), box);
   gtk_container_add (GTK_CONTAINER (box), label);
 
-  if (GTK_IS_CONSTRAINT (item) || GTK_IS_CONSTRAINT_GUIDE (item))
-    {
-      button = gtk_button_new_from_icon_name ("document-edit-symbolic");
-      gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
-      g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
-      g_object_set_data (G_OBJECT (row), "edit", button);
-      gtk_container_add (GTK_CONTAINER (box), button);
-      button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
-      gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
-      g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
-      gtk_container_add (GTK_CONTAINER (box), button);
-    }
-  else if (GTK_IS_WIDGET (item))
-    {
-      button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
-      gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
-      g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
-      gtk_container_add (GTK_CONTAINER (box), button);
-    }
+  button = gtk_button_new_from_icon_name ("document-edit-symbolic");
+  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+  g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win);
+  g_object_set_data (G_OBJECT (row), "edit", button);
+  gtk_container_add (GTK_CONTAINER (box), button);
+  button = gtk_button_new_from_icon_name ("edit-delete-symbolic");
+  gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
+  g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win);
+  gtk_container_add (GTK_CONTAINER (box), button);
 
   g_free (freeme);
 
diff --git a/demos/constraint-editor/constraint-editor.gresource.xml 
b/demos/constraint-editor/constraint-editor.gresource.xml
index e57964b1a7..a6393b34e0 100644
--- a/demos/constraint-editor/constraint-editor.gresource.xml
+++ b/demos/constraint-editor/constraint-editor.gresource.xml
@@ -4,6 +4,7 @@
     <file preprocess="xml-stripblanks">constraint-editor-window.ui</file>
     <file preprocess="xml-stripblanks">constraint-editor.ui</file>
     <file preprocess="xml-stripblanks">guide-editor.ui</file>
+    <file preprocess="xml-stripblanks">child-editor.ui</file>
     <file>constraint-editor.css</file>
   </gresource>
 </gresources>
diff --git a/demos/constraint-editor/constraint-view.c b/demos/constraint-editor/constraint-view.c
index 063e445f91..fb0b7e45d7 100644
--- a/demos/constraint-editor/constraint-view.c
+++ b/demos/constraint-editor/constraint-view.c
@@ -216,11 +216,15 @@ constraint_view_add_child (ConstraintView *view,
   GtkWidget *frame;
   GtkWidget *label;
 
-  label = gtk_label_new (name);
   frame = gtk_frame_new (NULL);
   gtk_style_context_add_class (gtk_widget_get_style_context (frame), "child");
   gtk_widget_set_name (frame, name);
+  label = gtk_label_new (name);
   gtk_container_add (GTK_CONTAINER (frame), label);
+  g_object_bind_property (frame, "name",
+                          label, "label",
+                          G_BINDING_DEFAULT);
+
   gtk_widget_set_parent (frame, GTK_WIDGET (view));
 
   update_weak_position (view, frame, 100, 100);
diff --git a/demos/constraint-editor/meson.build b/demos/constraint-editor/meson.build
index 9c01a7b50b..f5abd13445 100644
--- a/demos/constraint-editor/meson.build
+++ b/demos/constraint-editor/meson.build
@@ -5,6 +5,7 @@ constraint_editor_sources = [
   'constraint-view.c',
   'constraint-editor.c',
   'guide-editor.c',
+  'child-editor.c',
   'guide-placeholder.c',
 ]
 


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