constraint editor: Allow editing children

Just name and size, for now.
This commit is contained in:
Matthias Clasen
2019-07-02 22:21:07 +00:00
parent a5a6e90105
commit bc1f2ded84
7 changed files with 426 additions and 20 deletions

View File

@@ -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);
}

View File

@@ -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);

View File

@@ -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>

View File

@@ -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);

View File

@@ -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>

View File

@@ -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);

View File

@@ -5,6 +5,7 @@ constraint_editor_sources = [
'constraint-view.c',
'constraint-editor.c',
'guide-editor.c',
'child-editor.c',
'guide-placeholder.c',
]