diff options
author | Matthias Clasen <mclasen@redhat.com> | 2019-06-30 13:25:30 +0000 |
---|---|---|
committer | Emmanuele Bassi <ebassi@gnome.org> | 2019-07-01 00:10:11 +0100 |
commit | 514de0b91a34e90166a2f4a35ff29a0558590f1d (patch) | |
tree | 583b8430d0974308f8c91bf645a1b4e000f566a0 /demos/constraint-editor | |
parent | 9a463056d02226a3232dbdceda281a0f4c02a743 (diff) | |
download | gtk+-514de0b91a34e90166a2f4a35ff29a0558590f1d.tar.gz |
Add a constraint editor demo
This is an initial cut at providing a tool
for interactive exploration of constraints.
Diffstat (limited to 'demos/constraint-editor')
19 files changed, 2430 insertions, 0 deletions
diff --git a/demos/constraint-editor/constraint-editor-application.c b/demos/constraint-editor/constraint-editor-application.c new file mode 100644 index 0000000000..09b5d64270 --- /dev/null +++ b/demos/constraint-editor/constraint-editor-application.c @@ -0,0 +1,94 @@ +/* + * 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 "constraint-editor-application.h" +#include "constraint-editor-window.h" + +struct _ConstraintEditorApplication +{ + GtkApplication parent_instance; +}; + +G_DEFINE_TYPE(ConstraintEditorApplication, constraint_editor_application, GTK_TYPE_APPLICATION); + +static void +constraint_editor_application_init (ConstraintEditorApplication *app) +{ +} + +static void +quit_activated (GSimpleAction *action, + GVariant *parameter, + gpointer data) +{ + g_application_quit (G_APPLICATION (data)); +} + +static GActionEntry app_entries[] = +{ + { "quit", quit_activated, NULL, NULL, NULL } +}; + +static void +constraint_editor_application_startup (GApplication *app) +{ + const char *quit_accels[2] = { "<Ctrl>Q", NULL }; + GtkCssProvider *provider; + + G_APPLICATION_CLASS (constraint_editor_application_parent_class)->startup (app); + + g_action_map_add_action_entries (G_ACTION_MAP (app), + app_entries, G_N_ELEMENTS (app_entries), + app); + gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.quit", quit_accels); + + provider = gtk_css_provider_new (); + gtk_css_provider_load_from_resource (provider, "/org/gtk/gtk4/constraint-editor/constraint-editor.css"); + gtk_style_context_add_provider_for_display (gdk_display_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); +} + +static void +constraint_editor_application_activate (GApplication *app) +{ + ConstraintEditorWindow *win; + + win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app)); + gtk_window_present (GTK_WINDOW (win)); +} + +static void +constraint_editor_application_class_init (ConstraintEditorApplicationClass *class) +{ + GApplicationClass *application_class = G_APPLICATION_CLASS (class); + + application_class->startup = constraint_editor_application_startup; + application_class->activate = constraint_editor_application_activate; +} + +ConstraintEditorApplication * +constraint_editor_application_new (void) +{ + return g_object_new (CONSTRAINT_EDITOR_APPLICATION_TYPE, + "application-id", "org.gtk.gtk4.ConstraintEditor", + NULL); +} diff --git a/demos/constraint-editor/constraint-editor-application.h b/demos/constraint-editor/constraint-editor-application.h new file mode 100644 index 0000000000..c7d9fd3048 --- /dev/null +++ b/demos/constraint-editor/constraint-editor-application.h @@ -0,0 +1,28 @@ +/* + * 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 CONSTRAINT_EDITOR_APPLICATION_TYPE (constraint_editor_application_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintEditorApplication, constraint_editor_application, CONSTRAINT, EDITOR_APPLICATION, GtkApplication) + +ConstraintEditorApplication *constraint_editor_application_new (void); diff --git a/demos/constraint-editor/constraint-editor-window.c b/demos/constraint-editor/constraint-editor-window.c new file mode 100644 index 0000000000..a8fa33464d --- /dev/null +++ b/demos/constraint-editor/constraint-editor-window.c @@ -0,0 +1,354 @@ +/* + * 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 "constraint-editor-window.h" +#include "constraint-view.h" +#include "constraint-editor.h" +#include "guide-editor.h" + +struct _ConstraintEditorWindow +{ + GtkApplicationWindow parent_instance; + + GtkWidget *paned; + GtkWidget *view; + GtkWidget *list; +}; + +G_DEFINE_TYPE(ConstraintEditorWindow, constraint_editor_window, GTK_TYPE_APPLICATION_WINDOW); + +gboolean +constraint_editor_window_load (ConstraintEditorWindow *self, + GFile *file) +{ + GBytes *bytes; + + bytes = g_file_load_bytes (file, NULL, NULL, NULL); + if (bytes == NULL) + return FALSE; + + if (!g_utf8_validate (g_bytes_get_data (bytes, NULL), g_bytes_get_size (bytes), NULL)) + { + g_bytes_unref (bytes); + return FALSE; + } + +#if 0 + + gtk_text_buffer_get_end_iter (self->text_buffer, &end); + gtk_text_buffer_insert (self->text_buffer, + &end, + g_bytes_get_data (bytes, NULL), + g_bytes_get_size (bytes)); +#endif + + g_bytes_unref (bytes); + + return TRUE; +} + +static void +constraint_editor_window_finalize (GObject *object) +{ + //ConstraintEditorWindow *self = (ConstraintEditorWindow *)object; + + G_OBJECT_CLASS (constraint_editor_window_parent_class)->finalize (object); +} + +static int child_counter; +static int guide_counter; + +static void +add_child (ConstraintEditorWindow *win) +{ + char *name; + + child_counter++; + name = g_strdup_printf ("Child %d", child_counter); + constraint_view_add_child (CONSTRAINT_VIEW (win->view), name); + g_free (name); +} + +static void +add_guide (ConstraintEditorWindow *win) +{ + char *name; + GtkConstraintGuide *guide; + + guide_counter++; + name = g_strdup_printf ("Guide %d", guide_counter); + guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL); + g_object_set_data_full (G_OBJECT (guide), "name", name, g_free); + + constraint_view_add_guide (CONSTRAINT_VIEW (win->view), guide); +} + +static void +constraint_editor_done (ConstraintEditor *editor, + GtkConstraint *constraint, + ConstraintEditorWindow *win) +{ + GtkConstraint *old_constraint; + + g_object_get (editor, "constraint", &old_constraint, NULL); + + if (old_constraint) + constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view), old_constraint); + + constraint_view_add_constraint (CONSTRAINT_VIEW (win->view), constraint); + + g_clear_object (&old_constraint); + + gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)); +} + +static void +edit_constraint (ConstraintEditorWindow *win, + GtkConstraint *constraint) +{ + GtkWidget *window; + ConstraintEditor *editor; + GListModel *model; + + window = gtk_window_new (GTK_WINDOW_TOPLEVEL); + gtk_window_set_transient_for (GTK_WINDOW (window), GTK_WINDOW (win)); + gtk_window_set_resizable (GTK_WINDOW (window), FALSE); + if (constraint) + gtk_window_set_title (GTK_WINDOW (window), "Edit Constraint"); + else + gtk_window_set_title (GTK_WINDOW (window), "Create Constraint"); + + model = constraint_view_get_model (CONSTRAINT_VIEW (win->view)); + + editor = constraint_editor_new (model, constraint); + + gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor)); + + g_signal_connect (editor, "done", G_CALLBACK (constraint_editor_done), win); + + gtk_widget_show (window); +} + +static void +add_constraint (ConstraintEditorWindow *win) +{ + edit_constraint (win, NULL); +} + +static void +guide_editor_done (GuideEditor *editor, + GtkConstraintGuide *guide, + ConstraintEditorWindow *win) +{ + constraint_view_guide_changed (CONSTRAINT_VIEW (win->view), guide); + gtk_widget_destroy (gtk_widget_get_ancestor (GTK_WIDGET (editor), GTK_TYPE_WINDOW)); +} + +static void +edit_guide (ConstraintEditorWindow *win, + GtkConstraintGuide *guide) +{ + GtkWidget *window; + GuideEditor *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 Guide"); + + editor = guide_editor_new (guide); + gtk_container_add (GTK_CONTAINER (window), GTK_WIDGET (editor)); + + g_signal_connect (editor, "done", G_CALLBACK (guide_editor_done), win); + gtk_widget_show (window); +} + +static void +row_activated (GtkListBox *list, + GtkListBoxRow *row, + ConstraintEditorWindow *win) +{ + GObject *item; + + item = G_OBJECT (g_object_get_data (G_OBJECT (row), "item")); + + if (GTK_IS_CONSTRAINT (item)) + edit_constraint (win, GTK_CONSTRAINT (item)); + else if (GTK_IS_CONSTRAINT_GUIDE (item)) + edit_guide (win, GTK_CONSTRAINT_GUIDE (item)); +} + +static void +constraint_editor_window_class_init (ConstraintEditorWindowClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + g_type_ensure (CONSTRAINT_VIEW_TYPE); + + object_class->finalize = constraint_editor_window_finalize; + + gtk_widget_class_set_template_from_resource (widget_class, + "/org/gtk/gtk4/constraint-editor/constraint-editor-window.ui"); + + gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, paned); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, view); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditorWindow, list); + + gtk_widget_class_bind_template_callback (widget_class, add_child); + gtk_widget_class_bind_template_callback (widget_class, add_guide); + gtk_widget_class_bind_template_callback (widget_class, add_constraint); + gtk_widget_class_bind_template_callback (widget_class, row_activated); +} + +static void +row_edit (GtkButton *button, + ConstraintEditorWindow *win) +{ + GtkWidget *row; + GObject *item; + + row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW); + item = (GObject *)g_object_get_data (G_OBJECT (row), "item"); + if (GTK_IS_CONSTRAINT (item)) + edit_constraint (win, GTK_CONSTRAINT (item)); + else if (GTK_IS_CONSTRAINT_GUIDE (item)) + edit_guide (win, GTK_CONSTRAINT_GUIDE (item)); +} + +static void +mark_constraints_invalid (ConstraintEditorWindow *win, + gpointer removed) +{ + GtkWidget *child; + GObject *item; + + for (child = gtk_widget_get_first_child (win->list); + child; + child = gtk_widget_get_next_sibling (child)) + { + item = (GObject *)g_object_get_data (G_OBJECT (child), "item"); + if (GTK_IS_CONSTRAINT (item)) + { + GtkConstraint *constraint = GTK_CONSTRAINT (item); + + if (gtk_constraint_get_target (constraint) == (GtkConstraintTarget *)removed || + gtk_constraint_get_source (constraint) == (GtkConstraintTarget *)removed) + { + GtkWidget *button; + button = (GtkWidget *)g_object_get_data (G_OBJECT (child), "edit"); + gtk_button_set_icon_name (GTK_BUTTON (button), "dialog-warning-symbolic"); + gtk_widget_set_tooltip_text (button, "Constraint is invalid"); + } + } + } +} + +static void +row_delete (GtkButton *button, + ConstraintEditorWindow *win) +{ + GtkWidget *row; + GObject *item; + + row = gtk_widget_get_ancestor (GTK_WIDGET (button), GTK_TYPE_LIST_BOX_ROW); + item = (GObject *)g_object_get_data (G_OBJECT (row), "item"); + if (GTK_IS_CONSTRAINT (item)) + constraint_view_remove_constraint (CONSTRAINT_VIEW (win->view), + GTK_CONSTRAINT (item)); + else if (GTK_IS_CONSTRAINT_GUIDE (item)) + { + mark_constraints_invalid (win, item); + constraint_view_remove_guide (CONSTRAINT_VIEW (win->view), + GTK_CONSTRAINT_GUIDE (item)); + } + else if (GTK_IS_WIDGET (item)) + { + mark_constraints_invalid (win, item); + constraint_view_remove_child (CONSTRAINT_VIEW (win->view), + GTK_WIDGET (item)); + } +} + +static GtkWidget * +create_widget_func (gpointer item, + gpointer user_data) +{ + ConstraintEditorWindow *win = user_data; + const char *name; + GtkWidget *row, *box, *label, *button; + + name = (const char *)g_object_get_data (G_OBJECT (item), "name"); + + row = gtk_list_box_row_new (); + g_object_set_data (G_OBJECT (row), "item", item); + box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + label = gtk_label_new (name); + g_object_set (label, + "margin", 10, + NULL); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_widget_set_hexpand (label, TRUE); + 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); + } + + return row; +} + +static void +constraint_editor_window_init (ConstraintEditorWindow *self) +{ + gtk_widget_init_template (GTK_WIDGET (self)); + + gtk_list_box_bind_model (GTK_LIST_BOX (self->list), + constraint_view_get_model (CONSTRAINT_VIEW (self->view)), + create_widget_func, + self, + NULL); +} + +ConstraintEditorWindow * +constraint_editor_window_new (ConstraintEditorApplication *application) +{ + return g_object_new (CONSTRAINT_EDITOR_WINDOW_TYPE, + "application", application, + NULL); +} diff --git a/demos/constraint-editor/constraint-editor-window.h b/demos/constraint-editor/constraint-editor-window.h new file mode 100644 index 0000000000..9096c6e71d --- /dev/null +++ b/demos/constraint-editor/constraint-editor-window.h @@ -0,0 +1,34 @@ +/* + * 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> + +#include "constraint-editor-application.h" + + +#define CONSTRAINT_EDITOR_WINDOW_TYPE (constraint_editor_window_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintEditorWindow, constraint_editor_window, CONSTRAINT, EDITOR_WINDOW, GtkApplicationWindow) + +ConstraintEditorWindow * constraint_editor_window_new (ConstraintEditorApplication *application); + +gboolean constraint_editor_window_load (ConstraintEditorWindow *self, + GFile *file); diff --git a/demos/constraint-editor/constraint-editor-window.ui b/demos/constraint-editor/constraint-editor-window.ui new file mode 100644 index 0000000000..c2c9a009ec --- /dev/null +++ b/demos/constraint-editor/constraint-editor-window.ui @@ -0,0 +1,68 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <template class="ConstraintEditorWindow" parent="GtkApplicationWindow"> + <style> + <class name="devel"/> + </style> + <property name="title" translatable="yes">GTK Constraint Editor</property> + <property name="default-width">1024</property> + <property name="default-height">768</property> + <child type="titlebar"> + <object class="GtkHeaderBar" id="header"> + <property name="title" translatable="yes">GTK Constraint Editor</property> + <property name="show-title-buttons">1</property> + </object> + </child> + <child> + <object class="GtkPaned" id="paned"> + <property name="orientation">horizontal</property> + <child> + <object class="GtkBox"> + <property name="orientation">vertical</property> + <child> + <object class="GtkBox"> + <property name="orientation">horizontal</property> + <child> + <object class="GtkButton"> + <property name="label">Add Child</property> + <signal name="clicked" handler="add_child" swapped="yes"/> + </object> + </child> + <child> + <object class="GtkButton"> + <property name="label">Add Guide</property> + <signal name="clicked" handler="add_guide" swapped="yes"/> + </object> + </child> + <child> + <object class="GtkButton"> + <property name="label">Add Constraint</property> + <signal name="clicked" handler="add_constraint" swapped="yes"/> + </object> + </child> + </object> + </child> + <child> + <object class="GtkScrolledWindow"> + <property name="hscrollbar-policy">never</property> + <property name="vscrollbar-policy">automatic</property> + <property name="vexpand">1</property> + <child> + <object class="GtkListBox" id="list"> + <property name="show-separators">1</property> + <property name="selection-mode">none</property> + <signal name="row-activated" handler="row_activated"/> + </object> + </child> + </object> + </child> + </object> + </child> + <child> + <object class="ConstraintView" id="view"> + </object> + </child> + </object> + </child> + </template> +</interface> diff --git a/demos/constraint-editor/constraint-editor.c b/demos/constraint-editor/constraint-editor.c new file mode 100644 index 0000000000..5a85b35ecf --- /dev/null +++ b/demos/constraint-editor/constraint-editor.c @@ -0,0 +1,583 @@ +/* + * 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 "constraint-editor.h" + +struct _ConstraintEditor +{ + GtkWidget parent_instance; + + GtkWidget *grid; + GtkWidget *name; + GtkWidget *target; + GtkWidget *target_attr; + GtkWidget *relation; + GtkWidget *source; + GtkWidget *source_attr; + GtkWidget *multiplier; + GtkWidget *constant; + GtkWidget *strength; + GtkWidget *preview; + GtkWidget *button; + + GtkConstraint *constraint; + GListModel *model; + + gboolean constructed; +}; + +enum { + PROP_MODEL = 1, + PROP_CONSTRAINT, + LAST_PROP +}; + +static GParamSpec *pspecs[LAST_PROP]; + +enum { + DONE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE(ConstraintEditor, constraint_editor, GTK_TYPE_WIDGET); + +static const char * +get_target_name (GtkConstraintTarget *target) +{ + if (target == NULL) + return "super"; + else + return (const char *)g_object_get_data (G_OBJECT (target), "name"); +} + +static void +constraint_target_combo (GListModel *model, + GtkWidget *combo, + gboolean is_source) +{ + int i; + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "super", "Super"); + + if (model) + { + for (i = 0; i < g_list_model_get_n_items (model); i++) + { + GObject *item = g_list_model_get_object (model, i); + const char *name; + + if (GTK_IS_CONSTRAINT (item)) + continue; + + name = get_target_name (GTK_CONSTRAINT_TARGET (item)); + + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), name, name); + g_object_unref (item); + } + } +} + +static void +constraint_attribute_combo (GtkWidget *combo, + gboolean is_source) +{ + if (is_source) + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "none", "None"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "left", "Left"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "right", "Right"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "top", "Top"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "bottom", "Bottom"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "start", "Start"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "end", "End"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "width", "Width"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "height", "Height"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-x", "Center X"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "center-y", "Center Y"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "baseline", "Baseline"); +} + +static void +constraint_relation_combo (GtkWidget *combo) +{ + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "le", "≤"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "eq", "="); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "ge", "≥"); +} + +static void +constraint_strength_combo (GtkWidget *combo) +{ + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required"); +} + +static gpointer +get_target (GListModel *model, + const char *id) +{ + int i; + + if (strcmp ("super", id) == 0) + return NULL; + + for (i = 0; i < g_list_model_get_n_items (model); i++) + { + GObject *item = g_list_model_get_object (model, i); + const char *name; + if (GTK_IS_CONSTRAINT (item)) + continue; + name = (const char *)g_object_get_data (item, "name"); + g_object_unref (item); + if (strcmp (name, id) == 0) + return item; + } + + return NULL; +} + +static GtkConstraintAttribute +get_target_attr (const char *id) +{ + GtkConstraintAttribute attr; + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE); + GEnumValue *value = g_enum_get_value_by_nick (class, id); + attr = value->value; + g_type_class_unref (class); + + return attr; +} + +static const char * +get_attr_nick (GtkConstraintAttribute attr) +{ + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_ATTRIBUTE); + GEnumValue *value = g_enum_get_value (class, attr); + const char *nick = value->value_nick; + g_type_class_unref (class); + + return nick; +} + +static GtkConstraintRelation +get_relation (const char *id) +{ + GtkConstraintRelation relation; + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION); + GEnumValue *value = g_enum_get_value_by_nick (class, id); + relation = value->value; + g_type_class_unref (class); + + return relation; +} + +static const char * +get_relation_nick (GtkConstraintRelation relation) +{ + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_RELATION); + GEnumValue *value = g_enum_get_value (class, relation); + const char *nick = value->value_nick; + g_type_class_unref (class); + + return nick; +} + +static GtkConstraintStrength +get_strength (const char *id) +{ + GtkConstraintStrength strength; + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH); + GEnumValue *value = g_enum_get_value_by_nick (class, id); + strength = value->value; + g_type_class_unref (class); + + return strength; +} + +static const char * +get_strength_nick (GtkConstraintStrength strength) +{ + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH); + GEnumValue *value = g_enum_get_value (class, strength); + const char *nick = value->value_nick; + g_type_class_unref (class); + + return nick; +} + +static void +create_constraint (GtkButton *button, + ConstraintEditor *editor) +{ + const char *id; + gpointer target; + GtkConstraintAttribute target_attr; + gpointer source; + GtkConstraintAttribute source_attr; + GtkConstraintRelation relation; + double multiplier; + double constant; + int strength; + GtkConstraint *constraint; + const char *name; + + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)); + target = get_target (editor->model, id); + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr)); + target_attr = get_target_attr (id); + + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)); + source = get_target (editor->model, id); + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr)); + source_attr = get_target_attr (id); + + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->relation)); + relation = get_relation (id); + + multiplier = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)), NULL); + + constant = g_ascii_strtod (gtk_editable_get_text (GTK_EDITABLE (editor->constant)), NULL); + + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength)); + strength = get_strength (id); + + name = gtk_editable_get_text (GTK_EDITABLE (editor->name)); + + constraint = gtk_constraint_new (target, target_attr, + relation, + source, source_attr, + multiplier, + constant, + strength); + g_object_set_data_full (G_OBJECT (constraint), "name", g_strdup (name), g_free); + g_signal_emit (editor, signals[DONE], 0, constraint); + g_object_unref (constraint); +} + +static void +source_attr_changed (ConstraintEditor *editor) +{ + const char *id; + + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr)); + if (strcmp (id, "none") == 0) + { + gtk_combo_box_set_active (GTK_COMBO_BOX (editor->source), -1); + gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), ""); + gtk_widget_set_sensitive (editor->source, FALSE); + gtk_widget_set_sensitive (editor->multiplier, FALSE); + } + else + { + gtk_widget_set_sensitive (editor->source, TRUE); + gtk_widget_set_sensitive (editor->multiplier, TRUE); + } +} + +static void +update_preview (ConstraintEditor *editor) +{ + GString *str; + const char *name; + const char *attr; + char *relation; + const char *multiplier; + const char *constant; + double c, m; + + if (!editor->constructed) + return; + + str = g_string_new (""); + + name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)); + attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target_attr)); + relation = gtk_combo_box_text_get_active_text (GTK_COMBO_BOX_TEXT (editor->relation)); + + if (name == NULL) + name = "[ ]"; + + g_string_append_printf (str, "%s.%s %s ", name, attr, relation); + g_free (relation); + + constant = gtk_editable_get_text (GTK_EDITABLE (editor->constant)); + c = g_ascii_strtod (constant, NULL); + + attr = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source_attr)); + if (strcmp (attr, "none") != 0) + { + name = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)); + multiplier = gtk_editable_get_text (GTK_EDITABLE (editor->multiplier)); + m = g_ascii_strtod (multiplier, NULL); + + if (name == NULL) + name = "[ ]"; + + g_string_append_printf (str, "%s.%s", name, attr); + + if (m != 1.0) + g_string_append_printf (str, " × %g", m); + + if (c > 0.0) + g_string_append_printf (str, " + %g", c); + else if (c < 0.0) + g_string_append_printf (str, " - %g", -c); + } + else + g_string_append_printf (str, "%g", c); + + gtk_label_set_label (GTK_LABEL (editor->preview), str->str); + + g_string_free (str, TRUE); +} + +static void +update_button (ConstraintEditor *editor) +{ + if (gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->target)) != NULL && + gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->source)) != NULL) + gtk_widget_set_sensitive (editor->button, TRUE); + else + gtk_widget_set_sensitive (editor->button, FALSE); +} + +static void +constraint_editor_init (ConstraintEditor *editor) +{ + gtk_widget_init_template (GTK_WIDGET (editor)); +} + +static int constraint_counter; + +static void +constraint_editor_constructed (GObject *object) +{ + ConstraintEditor *editor = CONSTRAINT_EDITOR (object); + + constraint_target_combo (editor->model, editor->target, FALSE); + constraint_attribute_combo (editor->target_attr, FALSE); + constraint_relation_combo (editor->relation); + constraint_target_combo (editor->model, editor->source, TRUE); + constraint_attribute_combo (editor->source_attr, TRUE); + + constraint_strength_combo (editor->strength); + + if (editor->constraint) + { + GtkConstraintTarget *target; + GtkConstraintAttribute attr; + GtkConstraintRelation relation; + GtkConstraintStrength strength; + const char *nick; + char *val; + double multiplier; + double constant; + + nick = (char *)g_object_get_data (G_OBJECT (editor->constraint), "name"); + gtk_editable_set_text (GTK_EDITABLE (editor->name), nick); + + target = gtk_constraint_get_target (editor->constraint); + nick = get_target_name (target); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target), nick); + + attr = gtk_constraint_get_target_attribute (editor->constraint); + nick = get_attr_nick (attr); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), nick); + + target = gtk_constraint_get_source (editor->constraint); + nick = get_target_name (target); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source), nick); + + attr = gtk_constraint_get_source_attribute (editor->constraint); + nick = get_attr_nick (attr); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), nick); + + relation = gtk_constraint_get_relation (editor->constraint); + nick = get_relation_nick (relation); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), nick); + + multiplier = gtk_constraint_get_multiplier (editor->constraint); + val = g_strdup_printf ("%g", multiplier); + gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), val); + g_free (val); + + constant = gtk_constraint_get_constant (editor->constraint); + val = g_strdup_printf ("%g", constant); + gtk_editable_set_text (GTK_EDITABLE (editor->constant), val); + g_free (val); + + strength = gtk_constraint_get_strength (editor->constraint); + nick = get_strength_nick (strength); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick); + + gtk_button_set_label (GTK_BUTTON (editor->button), "Apply"); + } + else + { + char *name; + + constraint_counter++; + name = g_strdup_printf ("Constraint %d", constraint_counter); + gtk_editable_set_text (GTK_EDITABLE (editor->name), name); + g_free (name); + + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->target_attr), "left"); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->source_attr), "left"); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->relation), "eq"); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "required"); + + gtk_editable_set_text (GTK_EDITABLE (editor->multiplier), "1.0"); + gtk_editable_set_text (GTK_EDITABLE (editor->constant), "0.0"); + + gtk_button_set_label (GTK_BUTTON (editor->button), "Create"); + } + + editor->constructed = TRUE; + update_preview (editor); + update_button (editor); +} + +static void +constraint_editor_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + ConstraintEditor *self = CONSTRAINT_EDITOR (object); + + switch (property_id) + { + case PROP_MODEL: + self->model = g_value_dup_object (value); + break; + + case PROP_CONSTRAINT: + self->constraint = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +constraint_editor_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + ConstraintEditor *self = CONSTRAINT_EDITOR (object); + + switch (property_id) + { + case PROP_MODEL: + g_value_set_object (value, self->model); + break; + + case PROP_CONSTRAINT: + g_value_set_object (value, self->constraint); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +constraint_editor_dispose (GObject *object) +{ + ConstraintEditor *self = (ConstraintEditor *)object; + + g_clear_pointer (&self->grid, gtk_widget_unparent); + g_clear_object (&self->model); + g_clear_object (&self->constraint); + + G_OBJECT_CLASS (constraint_editor_parent_class)->dispose (object); +} + +static void +constraint_editor_class_init (ConstraintEditorClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + object_class->constructed = constraint_editor_constructed; + object_class->dispose = constraint_editor_dispose; + object_class->set_property = constraint_editor_set_property; + object_class->get_property = constraint_editor_get_property; + + pspecs[PROP_CONSTRAINT] = + g_param_spec_object ("constraint", "constraint", "constraint", + GTK_TYPE_CONSTRAINT, + G_PARAM_READWRITE|G_PARAM_CONSTRUCT_ONLY); + + pspecs[PROP_MODEL] = + g_param_spec_object ("model", "model", "model", + G_TYPE_LIST_MODEL, + 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_CONSTRAINT); + + 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/constraint-editor.ui"); + + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, grid); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, name); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, target_attr); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, relation); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, source_attr); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, multiplier); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, constant); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, strength); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, preview); + gtk_widget_class_bind_template_child (widget_class, ConstraintEditor, button); + + gtk_widget_class_bind_template_callback (widget_class, update_preview); + gtk_widget_class_bind_template_callback (widget_class, update_button); + gtk_widget_class_bind_template_callback (widget_class, create_constraint); + gtk_widget_class_bind_template_callback (widget_class, source_attr_changed); +} + +ConstraintEditor * +constraint_editor_new (GListModel *model, + GtkConstraint *constraint) +{ + return g_object_new (CONSTRAINT_EDITOR_TYPE, + "model", model, + "constraint", constraint, + NULL); +} diff --git a/demos/constraint-editor/constraint-editor.css b/demos/constraint-editor/constraint-editor.css new file mode 100644 index 0000000000..c9538bf268 --- /dev/null +++ b/demos/constraint-editor/constraint-editor.css @@ -0,0 +1,12 @@ +constraintview { + background: black; + color: white; +} + +constraintview .child { + background: red; +} + +constraintview .guide { + background: blue; +} diff --git a/demos/constraint-editor/constraint-editor.gresource.xml b/demos/constraint-editor/constraint-editor.gresource.xml new file mode 100644 index 0000000000..e57964b1a7 --- /dev/null +++ b/demos/constraint-editor/constraint-editor.gresource.xml @@ -0,0 +1,9 @@ +<?xml version="1.0" encoding="UTF-8"?> +<gresources> + <gresource prefix="/org/gtk/gtk4/constraint-editor"> + <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>constraint-editor.css</file> + </gresource> +</gresources> diff --git a/demos/constraint-editor/constraint-editor.h b/demos/constraint-editor/constraint-editor.h new file mode 100644 index 0000000000..c5940e254b --- /dev/null +++ b/demos/constraint-editor/constraint-editor.h @@ -0,0 +1,29 @@ +/* + * 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 CONSTRAINT_EDITOR_TYPE (constraint_editor_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintEditor, constraint_editor, CONSTRAINT, EDITOR, GtkWidget) + +ConstraintEditor * constraint_editor_new (GListModel *model, + GtkConstraint *constraint); diff --git a/demos/constraint-editor/constraint-editor.ui b/demos/constraint-editor/constraint-editor.ui new file mode 100644 index 0000000000..604757659a --- /dev/null +++ b/demos/constraint-editor/constraint-editor.ui @@ -0,0 +1,180 @@ +<?xml version="1.0" encoding="UTF-8"?> +<interface> + <template class="ConstraintEditor" 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"> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">0</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Target</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">1</property> + </layout> + </object> + </child> + <child> + <object class="GtkComboBoxText" id="target"> + <signal name="changed" handler="update_preview" swapped="yes"/> + <signal name="changed" handler="update_button" swapped="yes"/> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">1</property> + </layout> + </object> + </child> + <child> + <object class="GtkComboBoxText" id="target_attr"> + <signal name="changed" handler="update_preview" swapped="yes"/> + <layout> + <property name="left-attach">2</property> + <property name="top-attach">1</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Relation</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">2</property> + </layout> + </object> + </child> + <child> + <object class="GtkComboBoxText" id="relation"> + <signal name="changed" handler="update_preview" swapped="yes"/> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">2</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Source</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">3</property> + </layout> + </object> + </child> + <child> + <object class="GtkComboBoxText" id="source"> + <signal name="changed" handler="update_preview" swapped="yes"/> + <signal name="changed" handler="update_button" swapped="yes"/> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">3</property> + </layout> + </object> + </child> + <child> + <object class="GtkComboBoxText" id="source_attr"> + <signal name="changed" handler="update_preview" swapped="yes"/> + <signal name="changed" handler="source_attr_changed" swapped="yes"/> + <layout> + <property name="left-attach">2</property> + <property name="top-attach">3</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Multiplier</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">4</property> + </layout> + </object> + </child> + <child> + <object class="GtkEntry" id="multiplier"> + <signal name="changed" handler="update_preview" swapped="yes"/> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">4</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Constant</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">5</property> + </layout> + </object> + </child> + <child> + <object class="GtkEntry" id="constant"> + <signal name="changed" handler="update_preview" swapped="yes"/> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">5</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Strength</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">6</property> + </layout> + </object> + </child> + <child> + <object class="GtkComboBoxText" id="strength"> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">6</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel" id="preview"> + <property name="xalign">0</property> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">7</property> + <property name="column-span">2</property> + </layout> + <attributes> + <attribute name="scale" value="1.44"/> + </attributes> + </object> + </child> + <child> + <object class="GtkButton" id="button"> + <property name="label">Create</property> + <signal name="clicked" handler="create_constraint"/> + <layout> + <property name="left-attach">2</property> + <property name="top-attach">8</property> + </layout> + </object> + </child> + </object> + </child> + </template> +</interface> diff --git a/demos/constraint-editor/constraint-view-child.c b/demos/constraint-editor/constraint-view-child.c new file mode 100644 index 0000000000..272054a387 --- /dev/null +++ b/demos/constraint-editor/constraint-view-child.c @@ -0,0 +1,93 @@ +/* + * 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 "constraint-view-child.h" + +struct _ConstraintViewChild +{ + GObject parent_instance; + + char *name; +}; + +enum { + PROP_NAME = 1, + LAST_PROP +}; + +static GParamSpec props[LAST_PROP]; + +G_DEFINE_TYPE (ConstraintViewChild, constraint_view_child, G_TYPE_OBJECT) + +static void +constraint_view_child_init (ConstraintViewChild *child) +{ +} + +static void +constraint_view_child_finalize (GObject *object) +{ + ConstraintViewChild *child = CONSTRAINT_VIEW_CHILD (object); + + g_free (child->name); + + G_OBJECT_CLASS (constraint_view_child_parent_class)->finalize (object); +} + +static void +constraint_view_child_set_property (GObject *object, + +static void +constraint_view_child_class_init (ConstraintViewChildClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + + object_class->finalize = constraint_view_child_finalize; + object_class->get_property = constraint_view_child_get_property; + object_class->set_property = constraint_view_child_set_property; + + props[PROP_NAME] = + g_param_spec_string ("name", "name", "name", + NULL, + G_PARAM_READWRITE); + + g_object_class_install_properties (object_class, LAST_PROP, props); +} + +#define CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ()) + +G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject) + +#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild) + +ConstraintViewWidget * constraint_view_widget_new (void); + +#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild) + +ConstraintViewGuide * constraint_view_guide_new (void); + +#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild) + +ConstraintViewGuide * constraint_view_constraint_new (void); diff --git a/demos/constraint-editor/constraint-view-child.h b/demos/constraint-editor/constraint-view-child.h new file mode 100644 index 0000000000..6f2120ef0b --- /dev/null +++ b/demos/constraint-editor/constraint-view-child.h @@ -0,0 +1,44 @@ +/* + * 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 CONSTRAINT_VIEW_CHILD_TYPE (constraint_view_get_type ()) + +G_DECLARE_TYPE (ConstraintViewChild, constraint_view_child, CONSTRAINT, VIEW_CHILD, GObject) + +#define CONSTRAINT_VIEW_WIDGET_TYPE (constraint_view_widget_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintViewWidget, constraint_view_widget, CONSTRAINT, VIEW_WIDGET, ConstraintViewChild) + +ConstraintViewWidget * constraint_view_widget_new (void); + +#define CONSTRAINT_VIEW_GUIDE_TYPE (constraint_view_guide_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintViewGuide, constraint_view_guide, CONSTRAINT, VIEW_GUIDE, ConstraintViewChild) + +ConstraintViewGuide * constraint_view_guide_new (void); + +#define CONSTRAINT_VIEW_CONSTRAINT_TYPE (constraint_view_constraint_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintViewConstraint, constraint_view_constraint, CONSTRAINT, VIEW_CONSTRAINT, ConstraintViewChild) + +ConstraintViewGuide * constraint_view_constraint_new (void); diff --git a/demos/constraint-editor/constraint-view.c b/demos/constraint-editor/constraint-view.c new file mode 100644 index 0000000000..eb5852a94c --- /dev/null +++ b/demos/constraint-editor/constraint-view.c @@ -0,0 +1,277 @@ +/* Copyright (C) 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 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/>. + */ + +#include <gtk/gtk.h> +#include "constraint-view.h" + +struct _ConstraintView +{ + GtkWidget parent; + + GListStore *store; +}; + +G_DEFINE_TYPE (ConstraintView, constraint_view, GTK_TYPE_WIDGET); + +static void +constraint_view_dispose (GObject *object) +{ + ConstraintView *view = CONSTRAINT_VIEW (object); + GtkWidget *child; + + while ((child = gtk_widget_get_first_child (GTK_WIDGET (view))) != NULL) + gtk_widget_unparent (child); + + g_clear_object (&view->store); + + G_OBJECT_CLASS (constraint_view_parent_class)->dispose (object); +} + +static void +constraint_view_class_init (ConstraintViewClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = constraint_view_dispose; + + gtk_widget_class_set_css_name (widget_class, "constraintview"); +} + +static void +constraint_view_init (ConstraintView *self) +{ + gtk_widget_set_layout_manager (GTK_WIDGET (self), + gtk_constraint_layout_new ()); + + self->store = g_list_store_new (G_TYPE_OBJECT); +} + +ConstraintView * +constraint_view_new (void) +{ + return g_object_new (CONSTRAINT_VIEW_TYPE, NULL); +} + +void +constraint_view_add_child (ConstraintView *view, + const char *name) +{ + 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"); + g_object_set_data_full (G_OBJECT (frame), "name", g_strdup (name), g_free); + gtk_container_add (GTK_CONTAINER (frame), label); + gtk_widget_set_parent (frame, GTK_WIDGET (view)); + + g_list_store_append (view->store, frame); +} + +void +constraint_view_remove_child (ConstraintView *view, + GtkWidget *child) +{ + int i; + + gtk_widget_unparent (child); + + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++) + { + if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)child) + { + g_list_store_remove (view->store, i); + break; + } + } +} + +void +constraint_view_add_guide (ConstraintView *view, + GtkConstraintGuide *guide) +{ + GtkLayoutManager *manager; + GtkWidget *frame; + GtkWidget *label; + const char *name; + GtkConstraint *constraint; + + name = (const char *)g_object_get_data (G_OBJECT (guide), "name"); + + label = gtk_label_new (name); + frame = gtk_frame_new (NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (frame), "guide"); + g_object_set_data_full (G_OBJECT (frame), "name", g_strdup (name), g_free); + gtk_container_add (GTK_CONTAINER (frame), label); + gtk_widget_set_parent (frame, GTK_WIDGET (view)); + + g_object_set_data (G_OBJECT (guide), "frame", frame); + g_object_set_data (G_OBJECT (guide), "label", label); + + manager = gtk_widget_get_layout_manager (GTK_WIDGET (view)); + gtk_constraint_layout_add_guide (GTK_CONSTRAINT_LAYOUT (manager), + g_object_ref (guide)); + + constraint = gtk_constraint_new (frame, + GTK_CONSTRAINT_ATTRIBUTE_LEFT, + GTK_CONSTRAINT_RELATION_EQ, + guide, + GTK_CONSTRAINT_ATTRIBUTE_LEFT, + 1.0, 0.0, + GTK_CONSTRAINT_STRENGTH_REQUIRED); + gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + g_object_set_data (G_OBJECT (guide), "left-constraint", constraint); + + constraint = gtk_constraint_new (frame, + GTK_CONSTRAINT_ATTRIBUTE_TOP, + GTK_CONSTRAINT_RELATION_EQ, + guide, + GTK_CONSTRAINT_ATTRIBUTE_TOP, + 1.0, 0.0, + GTK_CONSTRAINT_STRENGTH_REQUIRED); + gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + g_object_set_data (G_OBJECT (guide), "top-constraint", constraint); + + constraint = gtk_constraint_new (frame, + GTK_CONSTRAINT_ATTRIBUTE_WIDTH, + GTK_CONSTRAINT_RELATION_EQ, + guide, + GTK_CONSTRAINT_ATTRIBUTE_WIDTH, + 1.0, 0.0, + GTK_CONSTRAINT_STRENGTH_REQUIRED); + gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + g_object_set_data (G_OBJECT (guide), "width-constraint", constraint); + + constraint = gtk_constraint_new (frame, + GTK_CONSTRAINT_ATTRIBUTE_HEIGHT, + GTK_CONSTRAINT_RELATION_EQ, + guide, + GTK_CONSTRAINT_ATTRIBUTE_HEIGHT, + 1.0, 0.0, + GTK_CONSTRAINT_STRENGTH_REQUIRED); + gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + + g_object_set_data (G_OBJECT (guide), "height-constraint", constraint); + + g_list_store_append (view->store, guide); +} + +void +constraint_view_guide_changed (ConstraintView *view, + GtkConstraintGuide *guide) +{ + GtkWidget *label; + const char *name; + int i; + + name = (const char *)g_object_get_data (G_OBJECT (guide), "name"); + label = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "label"); + gtk_label_set_label (GTK_LABEL (label), name); + + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++) + { + if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)guide) + { + g_list_model_items_changed (G_LIST_MODEL (view->store), i, 1, 1); + break; + } + } +} + +void +constraint_view_remove_guide (ConstraintView *view, + GtkConstraintGuide *guide) +{ + GtkLayoutManager *manager; + GtkWidget *frame; + GtkConstraint *constraint; + int i; + + manager = gtk_widget_get_layout_manager (GTK_WIDGET (view)); + + constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "left-constraint"); + gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "top-constraint"); + gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "width-constraint"); + gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + constraint = (GtkConstraint*)g_object_get_data (G_OBJECT (guide), "height-constraint"); + gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + + frame = (GtkWidget *)g_object_get_data (G_OBJECT (guide), "frame"); + gtk_widget_unparent (frame); + + gtk_constraint_layout_remove_guide (GTK_CONSTRAINT_LAYOUT (manager), + guide); + + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++) + { + if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)guide) + { + g_list_store_remove (view->store, i); + break; + } + } +} + +void +constraint_view_add_constraint (ConstraintView *view, + GtkConstraint *constraint) +{ + GtkLayoutManager *manager; + + manager = gtk_widget_get_layout_manager (GTK_WIDGET (view)); + gtk_constraint_layout_add_constraint (GTK_CONSTRAINT_LAYOUT (manager), + g_object_ref (constraint)); + + g_list_store_append (view->store, constraint); +} + +void +constraint_view_remove_constraint (ConstraintView *view, + GtkConstraint *constraint) +{ + GtkLayoutManager *manager; + int i; + + manager = gtk_widget_get_layout_manager (GTK_WIDGET (view)); + gtk_constraint_layout_remove_constraint (GTK_CONSTRAINT_LAYOUT (manager), + constraint); + for (i = 0; i < g_list_model_get_n_items (G_LIST_MODEL (view->store)); i++) + { + if (g_list_model_get_item (G_LIST_MODEL (view->store), i) == (GObject*)constraint) + { + g_list_store_remove (view->store, i); + break; + } + } +} + +GListModel * +constraint_view_get_model (ConstraintView *view) +{ + return G_LIST_MODEL (view->store); +} diff --git a/demos/constraint-editor/constraint-view.h b/demos/constraint-editor/constraint-view.h new file mode 100644 index 0000000000..40e80c8c43 --- /dev/null +++ b/demos/constraint-editor/constraint-view.h @@ -0,0 +1,44 @@ +/* + * 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 CONSTRAINT_VIEW_TYPE (constraint_view_get_type ()) + +G_DECLARE_FINAL_TYPE (ConstraintView, constraint_view, CONSTRAINT, VIEW, GtkWidget) + +ConstraintView * constraint_view_new (void); + +void constraint_view_add_child (ConstraintView *view, + const char *name); +void constraint_view_remove_child (ConstraintView *view, + GtkWidget *child); +void constraint_view_add_guide (ConstraintView *view, + GtkConstraintGuide *guide); +void constraint_view_remove_guide (ConstraintView *view, + GtkConstraintGuide *guide); +void constraint_view_guide_changed (ConstraintView *view, + GtkConstraintGuide *guide); +void constraint_view_add_constraint (ConstraintView *view, + GtkConstraint *constraint); +void constraint_view_remove_constraint (ConstraintView *view, + GtkConstraint *constraint); +GListModel * constraint_view_get_model (ConstraintView *view); diff --git a/demos/constraint-editor/guide-editor.c b/demos/constraint-editor/guide-editor.c new file mode 100644 index 0000000000..e4baf8ca32 --- /dev/null +++ b/demos/constraint-editor/guide-editor.c @@ -0,0 +1,318 @@ +/* + * 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 "guide-editor.h" + +struct _GuideEditor +{ + GtkWidget parent_instance; + + GtkWidget *grid; + GtkWidget *name; + GtkWidget *min_width; + GtkWidget *min_height; + GtkWidget *nat_width; + GtkWidget *nat_height; + GtkWidget *max_width; + GtkWidget *max_height; + GtkWidget *strength; + GtkWidget *button; + + GtkConstraintGuide *guide; + + gboolean constructed; +}; + +enum { + PROP_GUIDE = 1, + LAST_PROP +}; + +static GParamSpec *pspecs[LAST_PROP]; + +enum { + DONE, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE(GuideEditor, guide_editor, GTK_TYPE_WIDGET); + +static void +guide_strength_combo (GtkWidget *combo) +{ + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "weak", "Weak"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "medium", "Medium"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "strong", "Strong"); + gtk_combo_box_text_append (GTK_COMBO_BOX_TEXT (combo), "required", "Required"); +} + +#if 0 +static GtkConstraintStrength +get_strength (const char *id) +{ + GtkConstraintStrength strength; + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH); + GEnumValue *value = g_enum_get_value_by_nick (class, id); + strength = value->value; + g_type_class_unref (class); + + return strength; +} +#endif + +const char * +get_strength_nick (GtkConstraintStrength strength) +{ + GEnumClass *class = g_type_class_ref (GTK_TYPE_CONSTRAINT_STRENGTH); + GEnumValue *value = g_enum_get_value (class, strength); + const char *nick = value->value_nick; + g_type_class_unref (class); + + return nick; +} + +static void +create_guide (GtkButton *button, + GuideEditor *editor) +{ +#if 0 + const char *id; + int strength; +#endif + const char *name; + int w, h; + GtkConstraintGuide *guide; + + //guide = gtk_constraint_guide_new (); + if (editor->guide) + guide = g_object_ref (editor->guide); + else + guide = g_object_new (GTK_TYPE_CONSTRAINT_GUIDE, NULL); + + name = gtk_editable_get_text (GTK_EDITABLE (editor->name)); + g_object_set_data_full (G_OBJECT (guide), "name", g_strdup (name), g_free); + + 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_constraint_guide_set_min_size (guide, w, h); + g_object_set (guide, "min-width", w, "min-height", h, NULL); + + w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_width)); + h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->nat_height)); + //gtk_constraint_guide_set_nat_size (guide, w, h); + g_object_set (guide, "nat-width", w, "nat-height", h, NULL); + +#if 0 + w = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_width)); + h = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON (editor->max_height)); + gtk_constraint_guide_set_max_size (guide, w, h); + + id = gtk_combo_box_get_active_id (GTK_COMBO_BOX (editor->strength)); + strength = get_strength (id); + gtk_constraint_guide_set_strength (guide, strength); +#endif + + g_signal_emit (editor, signals[DONE], 0, guide); + g_object_unref (guide); +} + +static void +guide_editor_init (GuideEditor *editor) +{ + gtk_widget_init_template (GTK_WIDGET (editor)); +} + +static int guide_counter; + +static void +guide_editor_constructed (GObject *object) +{ + GuideEditor *editor = GUIDE_EDITOR (object); + + guide_strength_combo (editor->strength); + + gtk_widget_set_sensitive (editor->max_width, FALSE); + gtk_widget_set_sensitive (editor->max_height, FALSE); + gtk_widget_set_sensitive (editor->strength, FALSE); + + if (editor->guide) + { +#if 0 + GtkConstaintStrength strength; +#endif + const char *nick; + int w, h; + + nick = (char *)g_object_get_data (G_OBJECT (editor->guide), "name"); + gtk_editable_set_text (GTK_EDITABLE (editor->name), nick); + + //gtk_constaint_guide_get_min_size (editor->guide, &w, &h); + g_object_get (editor->guide, "min-width", &w, "min-height", &h, NULL); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), w); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), h); + + //gtk_constaint_guide_get_nat_size (editor->guide, &w, &h); + g_object_get (editor->guide, "nat-width", &w, "nat-height", &h, NULL); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), w); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), h); + +#if 0 + gtk_constaint_guide_get_max_size (editor->guide, &w, &h); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), w); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), h); + + strength = gtk_guide_get_strength (editor->guide); + nick = get_strength_nick (strength); + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), nick); +#endif + + gtk_button_set_label (GTK_BUTTON (editor->button), "Apply"); + } + else + { + char *name; + + guide_counter++; + name = g_strdup_printf ("Guide %d", guide_counter); + gtk_editable_set_text (GTK_EDITABLE (editor->name), name); + g_free (name); + + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_width), 0.0); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->min_height), 0.0); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_width), 0.0); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->nat_height), 0.0); +#if 0 + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_width), G_MAXINT); + gtk_spin_button_set_value (GTK_SPIN_BUTTON (editor->max_height), G_MAXINT); + + gtk_combo_box_set_active_id (GTK_COMBO_BOX (editor->strength), "medium"); +#endif + + gtk_button_set_label (GTK_BUTTON (editor->button), "Create"); + } + + editor->constructed = TRUE; +} + +static void +guide_editor_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GuideEditor *self = GUIDE_EDITOR (object); + + switch (property_id) + { + case PROP_GUIDE: + self->guide = g_value_dup_object (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +guide_editor_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GuideEditor *self = GUIDE_EDITOR (object); + + switch (property_id) + { + case PROP_GUIDE: + g_value_set_object (value, self->guide); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + } +} + +static void +guide_editor_dispose (GObject *object) +{ + GuideEditor *self = (GuideEditor *)object; + + g_clear_pointer (&self->grid, gtk_widget_unparent); + g_clear_object (&self->guide); + + G_OBJECT_CLASS (guide_editor_parent_class)->dispose (object); +} + +static void +guide_editor_class_init (GuideEditorClass *class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (class); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (class); + + object_class->constructed = guide_editor_constructed; + object_class->dispose = guide_editor_dispose; + object_class->set_property = guide_editor_set_property; + object_class->get_property = guide_editor_get_property; + + pspecs[PROP_GUIDE] = + g_param_spec_object ("guide", "guide", "guide", + GTK_TYPE_CONSTRAINT_GUIDE, + 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_CONSTRAINT_GUIDE); + + 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/guide-editor.ui"); + + gtk_widget_class_bind_template_child (widget_class, GuideEditor, grid); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, name); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_width); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, min_height); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_width); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, nat_height); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_width); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, max_height); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, strength); + gtk_widget_class_bind_template_child (widget_class, GuideEditor, button); + + gtk_widget_class_bind_template_callback (widget_class, create_guide); +} + +GuideEditor * +guide_editor_new (GtkConstraintGuide *guide) +{ + return g_object_new (GUIDE_EDITOR_TYPE, + "guide", guide, + NULL); +} diff --git a/demos/constraint-editor/guide-editor.h b/demos/constraint-editor/guide-editor.h new file mode 100644 index 0000000000..d11cb4f3db --- /dev/null +++ b/demos/constraint-editor/guide-editor.h @@ -0,0 +1,28 @@ +/* + * 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 GUIDE_EDITOR_TYPE (guide_editor_get_type ()) + +G_DECLARE_FINAL_TYPE (GuideEditor, guide_editor, GUIDE, EDITOR, GtkWidget) + +GuideEditor * guide_editor_new (GtkConstraintGuide *guide); diff --git a/demos/constraint-editor/guide-editor.ui b/demos/constraint-editor/guide-editor.ui new file mode 100644 index 0000000000..a788de10bf --- /dev/null +++ b/demos/constraint-editor/guide-editor.ui @@ -0,0 +1,188 @@ +<?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> + <object class="GtkAdjustment" id="nat_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="nat_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> + <object class="GtkAdjustment" id="max_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="max_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="GuideEditor" 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="GtkLabel"> + <property name="label">Nat Size</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">2</property> + </layout> + </object> + </child> + <child> + <object class="GtkSpinButton" id="nat_width"> + <property name="adjustment">nat_width_adj</property> + <property name="max-width-chars">5</property> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">2</property> + </layout> + </object> + </child> + <child> + <object class="GtkSpinButton" id="nat_height"> + <property name="adjustment">nat_height_adj</property> + <property name="max-width-chars">5</property> + <layout> + <property name="left-attach">2</property> + <property name="top-attach">2</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Max Size</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">3</property> + </layout> + </object> + </child> + <child> + <object class="GtkSpinButton" id="max_width"> + <property name="adjustment">max_width_adj</property> + <property name="max-width-chars">5</property> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">3</property> + </layout> + </object> + </child> + <child> + <object class="GtkSpinButton" id="max_height"> + <property name="adjustment">max_height_adj</property> + <property name="max-width-chars">5</property> + <layout> + <property name="left-attach">2</property> + <property name="top-attach">3</property> + </layout> + </object> + </child> + <child> + <object class="GtkLabel"> + <property name="label">Strength</property> + <layout> + <property name="left-attach">0</property> + <property name="top-attach">4</property> + </layout> + </object> + </child> + <child> + <object class="GtkComboBoxText" id="strength"> + <layout> + <property name="left-attach">1</property> + <property name="top-attach">4</property> + <property name="column-span">2</property> + </layout> + </object> + </child> + <child> + <object class="GtkButton" id="button"> + <property name="label">Create</property> + <signal name="clicked" handler="create_guide"/> + <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/main.c b/demos/constraint-editor/main.c new file mode 100644 index 0000000000..771774c08f --- /dev/null +++ b/demos/constraint-editor/main.c @@ -0,0 +1,28 @@ +/* + * 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 <mclasen@redhat.com> + */ + +#include "config.h" + +#include <constraint-editor-application.h> + +int +main (int argc, char *argv[]) +{ + return g_application_run (G_APPLICATION (constraint_editor_application_new ()), argc, argv); +} diff --git a/demos/constraint-editor/meson.build b/demos/constraint-editor/meson.build new file mode 100644 index 0000000000..af66846437 --- /dev/null +++ b/demos/constraint-editor/meson.build @@ -0,0 +1,19 @@ +constraint_editor_sources = [ + 'main.c', + 'constraint-editor-application.c', + 'constraint-editor-window.c', + 'constraint-view.c', + 'constraint-editor.c', + 'guide-editor.c', +] + +constraint_editor_resources = gnome.compile_resources('constraint_editor_resources', + 'constraint-editor.gresource.xml', + source_dir: '.') + +executable('gtk4-constraint-editor', + constraint_editor_sources, constraint_editor_resources, + dependencies: libgtk_dep, + include_directories: confinc, + gui_app: true, + install: false) |