From bc1f2ded846d8396670ab9249a470a460ead9f85 Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Tue, 2 Jul 2019 22:21:07 +0000 Subject: [PATCH] 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 ++++++ .../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(-) create mode 100644 demos/constraint-editor/child-editor.c create mode 100644 demos/constraint-editor/child-editor.h create mode 100644 demos/constraint-editor/child-editor.ui 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 . + * + * 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\n", indent, ""); + g_string_append_printf (str, "%*s \n", indent, "", name); + g_string_append_printf (str, "%*s %s\n", indent, "", name); + if (min_width != -1) + g_string_append_printf (str, "%*s %d\n", indent, "", min_width); + if (min_height != -1) + g_string_append_printf (str, "%*s %d\n", indent, "", min_height); + g_string_append_printf (str, "%*s \n", indent, ""); + g_string_append_printf (str, "%*s\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 . + * + * Authors: Matthias Clasen + */ + +#pragma once + +#include + +#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 @@ + + + + 0 + 2147483647 + 1 + 10 + 0 + + + 0 + 2147483647 + 1 + 10 + 0 + + + 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 @@ constraint-editor-window.ui constraint-editor.ui guide-editor.ui + child-editor.ui constraint-editor.css 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', ]