From c5e1b00994d09f60a4985b9fb5d15e071d28229c Mon Sep 17 00:00:00 2001 From: Matthias Clasen Date: Mon, 1 Jul 2019 18:39:36 +0000 Subject: [PATCH] constraint editor: Implement saving Save to a ui file. --- .../constraint-editor-application.c | 21 +++ .../constraint-editor-window.c | 147 ++++++++++++++++++ .../constraint-editor-window.ui | 14 ++ demos/constraint-editor/constraint-editor.c | 34 ++++ demos/constraint-editor/constraint-editor.h | 4 + demos/constraint-editor/guide-editor.c | 23 +++ demos/constraint-editor/guide-editor.h | 4 + 7 files changed, 247 insertions(+) diff --git a/demos/constraint-editor/constraint-editor-application.c b/demos/constraint-editor/constraint-editor-application.c index 09b5d64270..aa130d9c13 100644 --- a/demos/constraint-editor/constraint-editor-application.c +++ b/demos/constraint-editor/constraint-editor-application.c @@ -51,6 +51,7 @@ static void constraint_editor_application_startup (GApplication *app) { const char *quit_accels[2] = { "Q", NULL }; + const char *open_accels[2] = { "O", NULL }; GtkCssProvider *provider; G_APPLICATION_CLASS (constraint_editor_application_parent_class)->startup (app); @@ -59,6 +60,7 @@ constraint_editor_application_startup (GApplication *app) app_entries, G_N_ELEMENTS (app_entries), app); gtk_application_set_accels_for_action (GTK_APPLICATION (app), "app.quit", quit_accels); + gtk_application_set_accels_for_action (GTK_APPLICATION (app), "win.open", open_accels); provider = gtk_css_provider_new (); gtk_css_provider_load_from_resource (provider, "/org/gtk/gtk4/constraint-editor/constraint-editor.css"); @@ -76,6 +78,23 @@ constraint_editor_application_activate (GApplication *app) gtk_window_present (GTK_WINDOW (win)); } +static void +constraint_editor_application_open (GApplication *app, + GFile **files, + gint n_files, + const gchar *hint) +{ + ConstraintEditorWindow *win; + gint i; + + for (i = 0; i < n_files; i++) + { + win = constraint_editor_window_new (CONSTRAINT_EDITOR_APPLICATION (app)); + constraint_editor_window_load (win, files[i]); + gtk_window_present (GTK_WINDOW (win)); + } +} + static void constraint_editor_application_class_init (ConstraintEditorApplicationClass *class) { @@ -83,6 +102,7 @@ constraint_editor_application_class_init (ConstraintEditorApplicationClass *clas application_class->startup = constraint_editor_application_startup; application_class->activate = constraint_editor_application_activate; + application_class->open = constraint_editor_application_open; } ConstraintEditorApplication * @@ -90,5 +110,6 @@ constraint_editor_application_new (void) { return g_object_new (CONSTRAINT_EDITOR_APPLICATION_TYPE, "application-id", "org.gtk.gtk4.ConstraintEditor", + "flags", G_APPLICATION_HANDLES_OPEN, NULL); } diff --git a/demos/constraint-editor/constraint-editor-window.c b/demos/constraint-editor/constraint-editor-window.c index bd9fd3e171..971450e5fa 100644 --- a/demos/constraint-editor/constraint-editor-window.c +++ b/demos/constraint-editor/constraint-editor-window.c @@ -65,6 +65,151 @@ constraint_editor_window_load (ConstraintEditorWindow *self, return TRUE; } +static void +open_response_cb (GtkNativeDialog *dialog, + gint response, + ConstraintEditorWindow *self) +{ + gtk_native_dialog_hide (dialog); + + if (response == GTK_RESPONSE_ACCEPT) + { + GFile *file; + + file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); + constraint_editor_window_load (self, file); + g_object_unref (file); + } + + gtk_native_dialog_destroy (dialog); +} + +static void +open_cb (GtkWidget *button, + ConstraintEditorWindow *self) +{ + GtkFileChooserNative *dialog; + + dialog = gtk_file_chooser_native_new ("Open file", + GTK_WINDOW (self), + GTK_FILE_CHOOSER_ACTION_OPEN, + "_Load", + "_Cancel"); + + gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), "."); + g_signal_connect (dialog, "response", G_CALLBACK (open_response_cb), self); + gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog)); +} + +static void +serialize_child (GString *str, + int indent, + GtkWidget *child) +{ + const char *name; + + name = gtk_widget_get_name (child); + g_string_append_printf (str, "%*s\n", indent, ""); + g_string_append_printf (str, "%*s \n", indent, "", name); + g_string_append_printf (str, "%*s %s\n", indent, "", name); + g_string_append_printf (str, "%*s \n", indent, ""); + g_string_append_printf (str, "%*s\n", indent, ""); +} + +static char * +serialize_model (GListModel *list) +{ + GString *str = g_string_new (""); + int i; + + g_string_append (str, "\n"); + g_string_append (str, " \n"); + g_string_append (str, " \n"); + g_string_append (str, " \n"); + g_string_append (str, " \n"); + for (i = 0; i < g_list_model_get_n_items (list); i++) + { + gpointer item = g_list_model_get_item (list, i); + g_object_unref (item); + if (GTK_IS_CONSTRAINT (item)) + constraint_editor_serialize_constraint (str, 10, GTK_CONSTRAINT (item)); + else if (GTK_IS_CONSTRAINT_GUIDE (item)) + guide_editor_serialize_guide (str, 10, GTK_CONSTRAINT_GUIDE (item)); + } + g_string_append (str, " \n"); + g_string_append (str, " \n"); + g_string_append (str, " \n"); + for (i = 0; i < g_list_model_get_n_items (list); i++) + { + gpointer item = g_list_model_get_item (list, i); + g_object_unref (item); + if (GTK_IS_WIDGET (item)) + serialize_child (str, 4, GTK_WIDGET (item)); + } + g_string_append (str, " \n"); + g_string_append (str, "\n"); + + return g_string_free (str, FALSE); +} + + +static void +save_response_cb (GtkNativeDialog *dialog, + gint response, + ConstraintEditorWindow *self) +{ + gtk_native_dialog_hide (dialog); + + if (response == GTK_RESPONSE_ACCEPT) + { + GListModel *model; + char *text, *filename; + GError *error = NULL; + + model = constraint_view_get_model (CONSTRAINT_VIEW (self->view)); + text = serialize_model (model); + + filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (dialog)); + if (!g_file_set_contents (filename, text, -1, &error)) + { + GtkWidget *dialog; + + dialog = gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (self))), + GTK_DIALOG_MODAL|GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_INFO, + GTK_BUTTONS_OK, + "Saving failed"); + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); + gtk_widget_show (dialog); + g_error_free (error); + } + g_free (filename); + } + + gtk_native_dialog_destroy (dialog); +} + +static void +save_cb (GtkWidget *button, + ConstraintEditorWindow *self) +{ + GtkFileChooserNative *dialog; + + dialog = gtk_file_chooser_native_new ("Save constraints", + GTK_WINDOW (gtk_widget_get_root (GTK_WIDGET (button))), + GTK_FILE_CHOOSER_ACTION_SAVE, + "_Save", + "_Cancel"); + + gtk_native_dialog_set_modal (GTK_NATIVE_DIALOG (dialog), TRUE); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), "."); + g_signal_connect (dialog, "response", G_CALLBACK (save_response_cb), self); + gtk_native_dialog_show (GTK_NATIVE_DIALOG (dialog)); +} + static void constraint_editor_window_finalize (GObject *object) { @@ -213,6 +358,8 @@ constraint_editor_window_class_init (ConstraintEditorWindowClass *class) 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, open_cb); + gtk_widget_class_bind_template_callback (widget_class, save_cb); 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); diff --git a/demos/constraint-editor/constraint-editor-window.ui b/demos/constraint-editor/constraint-editor-window.ui index c2c9a009ec..0d2e72fcea 100644 --- a/demos/constraint-editor/constraint-editor-window.ui +++ b/demos/constraint-editor/constraint-editor-window.ui @@ -11,6 +11,20 @@ GTK Constraint Editor 1 + + + document-open-symbolic + Open ui file + + + + + + document-save-symbolic + Save to ui file + + + diff --git a/demos/constraint-editor/constraint-editor.c b/demos/constraint-editor/constraint-editor.c index e871b6a6c8..8346be7d42 100644 --- a/demos/constraint-editor/constraint-editor.c +++ b/demos/constraint-editor/constraint-editor.c @@ -236,6 +236,40 @@ get_strength_nick (GtkConstraintStrength strength) return nick; } +void +constraint_editor_serialize_constraint (GString *str, + int indent, + GtkConstraint *constraint) +{ + const char *target; + const char *target_attr; + const char *relation; + const char *source; + const char *source_attr; + double multiplier; + double constant; + const char *strength; + + target = get_target_name (gtk_constraint_get_target (constraint)); + target_attr = get_attr_nick (gtk_constraint_get_target_attribute (constraint)); + relation = get_relation_nick (gtk_constraint_get_relation (constraint)); + source = get_target_name (gtk_constraint_get_source (constraint)); + source_attr = get_attr_nick (gtk_constraint_get_source_attribute (constraint)); + multiplier = gtk_constraint_get_multiplier (constraint); + constant = gtk_constraint_get_constant (constraint); + strength = get_strength_nick (gtk_constraint_get_strength (constraint)); + + g_string_append_printf (str, "%*s\n", indent, "", strength); +} + static void create_constraint (GtkButton *button, ConstraintEditor *editor) diff --git a/demos/constraint-editor/constraint-editor.h b/demos/constraint-editor/constraint-editor.h index c5940e254b..b2b5613856 100644 --- a/demos/constraint-editor/constraint-editor.h +++ b/demos/constraint-editor/constraint-editor.h @@ -27,3 +27,7 @@ G_DECLARE_FINAL_TYPE (ConstraintEditor, constraint_editor, CONSTRAINT, EDITOR, G ConstraintEditor * constraint_editor_new (GListModel *model, GtkConstraint *constraint); + +void constraint_editor_serialize_constraint (GString *str, + int indent, + GtkConstraint *constraint); diff --git a/demos/constraint-editor/guide-editor.c b/demos/constraint-editor/guide-editor.c index 663697337c..a7ea6b5da0 100644 --- a/demos/constraint-editor/guide-editor.c +++ b/demos/constraint-editor/guide-editor.c @@ -89,6 +89,29 @@ get_strength_nick (GtkConstraintStrength strength) return nick; } +void +guide_editor_serialize_guide (GString *str, + int indent, + GtkConstraintGuide *guide) +{ + int min_width, min_height; + int nat_width, nat_height; + int max_width, max_height; + const char *name; + const char *strength; + + gtk_constraint_guide_get_min_size (guide, &min_width, &min_height); + gtk_constraint_guide_get_nat_size (guide, &nat_width, &nat_height); + gtk_constraint_guide_get_max_size (guide, &max_width, &max_height); + name = gtk_constraint_guide_get_name (guide); + strength = get_strength_nick (gtk_constraint_guide_get_strength (guide)); + + g_string_append_printf (str, "%*s\n", indent, "", name, strength); +} + static void create_guide (GtkButton *button, GuideEditor *editor) diff --git a/demos/constraint-editor/guide-editor.h b/demos/constraint-editor/guide-editor.h index d11cb4f3db..56ccbfd5d3 100644 --- a/demos/constraint-editor/guide-editor.h +++ b/demos/constraint-editor/guide-editor.h @@ -26,3 +26,7 @@ G_DECLARE_FINAL_TYPE (GuideEditor, guide_editor, GUIDE, EDITOR, GtkWidget) GuideEditor * guide_editor_new (GtkConstraintGuide *guide); + +void guide_editor_serialize_guide (GString *str, + int indent, + GtkConstraintGuide *guide);