| /* |
| * 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); |
| |
| static GtkConstraintTarget * |
| find_target (GListModel *model, |
| GtkConstraintTarget *orig) |
| { |
| const char *name; |
| const char *model_name; |
| gpointer item; |
| int i; |
| |
| if (orig == NULL) |
| return NULL; |
| |
| if (GTK_IS_LABEL (orig)) |
| name = gtk_label_get_label (GTK_LABEL (orig)); |
| else if (GTK_IS_CONSTRAINT_GUIDE (orig)) |
| name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (orig)); |
| else |
| { |
| g_warning ("Don't know how to handle %s targets", G_OBJECT_TYPE_NAME (orig)); |
| return NULL; |
| } |
| for (i = 0; i < g_list_model_get_n_items (model); i++) |
| { |
| item = g_list_model_get_item (model, i); |
| g_object_unref (item); |
| if (GTK_IS_WIDGET (item)) |
| model_name = gtk_widget_get_name (GTK_WIDGET (item)); |
| else |
| model_name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item)); |
| |
| if (strcmp (name, model_name) == 0) |
| return GTK_CONSTRAINT_TARGET (item); |
| } |
| g_warning ("Failed to find target '%s'", name); |
| |
| return NULL; |
| } |
| |
| gboolean |
| constraint_editor_window_load (ConstraintEditorWindow *self, |
| GFile *file) |
| { |
| char *path; |
| GtkBuilder *builder; |
| GError *error = NULL; |
| GtkWidget *view; |
| GtkLayoutManager *layout; |
| GtkWidget *child; |
| const char *name; |
| gpointer item; |
| int i; |
| GListModel *list; |
| |
| path = g_file_get_path (file); |
| |
| builder = gtk_builder_new (); |
| if (!gtk_builder_add_from_file (builder, path, &error)) |
| { |
| g_print ("Could not load %s: %s", path, error->message); |
| g_error_free (error); |
| g_free (path); |
| g_object_unref (builder); |
| return FALSE; |
| } |
| |
| view = GTK_WIDGET (gtk_builder_get_object (builder, "view")); |
| if (!GTK_IS_BOX (view)) |
| { |
| g_print ("Could not load %s: No GtkBox named 'view'", path); |
| g_free (path); |
| g_object_unref (builder); |
| return FALSE; |
| } |
| layout = gtk_widget_get_layout_manager (view); |
| if (!GTK_IS_CONSTRAINT_LAYOUT (layout)) |
| { |
| g_print ("Could not load %s: Widget 'view' does not use GtkConstraintLayout", path); |
| g_free (path); |
| g_object_unref (builder); |
| return FALSE; |
| } |
| |
| for (child = gtk_widget_get_first_child (view); |
| child; |
| child = gtk_widget_get_next_sibling (child)) |
| { |
| if (!GTK_IS_LABEL (child)) |
| { |
| g_print ("Skipping non-GtkLabel child\n"); |
| continue; |
| } |
| |
| name = gtk_label_get_label (GTK_LABEL (child)); |
| constraint_view_add_child (CONSTRAINT_VIEW (self->view), name); |
| } |
| |
| list = gtk_constraint_layout_observe_guides (GTK_CONSTRAINT_LAYOUT (layout)); |
| for (i = 0; i < g_list_model_get_n_items (list); i++) |
| { |
| GtkConstraintGuide *guide, *clone; |
| int w, h; |
| |
| item = g_list_model_get_item (list, i); |
| guide = GTK_CONSTRAINT_GUIDE (item); |
| |
| /* need to clone here, to attach to the right targets */ |
| clone = gtk_constraint_guide_new (); |
| gtk_constraint_guide_set_name (clone, gtk_constraint_guide_get_name (guide)); |
| gtk_constraint_guide_set_strength (clone, gtk_constraint_guide_get_strength (guide)); |
| gtk_constraint_guide_get_min_size (guide, &w, &h); |
| gtk_constraint_guide_set_min_size (clone, w, h); |
| gtk_constraint_guide_get_nat_size (guide, &w, &h); |
| gtk_constraint_guide_set_nat_size (clone, w, h); |
| gtk_constraint_guide_get_max_size (guide, &w, &h); |
| gtk_constraint_guide_set_max_size (clone, w, h); |
| constraint_view_add_guide (CONSTRAINT_VIEW (self->view), clone); |
| g_object_unref (guide); |
| g_object_unref (clone); |
| } |
| g_object_unref (list); |
| |
| list = gtk_constraint_layout_observe_constraints (GTK_CONSTRAINT_LAYOUT (layout)); |
| for (i = 0; i < g_list_model_get_n_items (list); i++) |
| { |
| GtkConstraint *constraint; |
| GtkConstraint *clone; |
| GtkConstraintTarget *target; |
| GtkConstraintTarget *source; |
| GtkConstraintAttribute source_attr; |
| |
| item = g_list_model_get_item (list, i); |
| constraint = GTK_CONSTRAINT (item); |
| |
| target = gtk_constraint_get_target (constraint); |
| source = gtk_constraint_get_source (constraint); |
| source_attr = gtk_constraint_get_source_attribute (constraint); |
| |
| if (source == NULL && source_attr == GTK_CONSTRAINT_ATTRIBUTE_NONE) |
| clone = gtk_constraint_new_constant (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target), |
| gtk_constraint_get_target_attribute (constraint), |
| gtk_constraint_get_relation (constraint), |
| gtk_constraint_get_constant (constraint), |
| gtk_constraint_get_strength (constraint)); |
| else |
| clone = gtk_constraint_new (find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), target), |
| gtk_constraint_get_target_attribute (constraint), |
| gtk_constraint_get_relation (constraint), |
| find_target (constraint_view_get_model (CONSTRAINT_VIEW (self->view)), source), |
| source_attr, |
| gtk_constraint_get_multiplier (constraint), |
| gtk_constraint_get_constant (constraint), |
| gtk_constraint_get_strength (constraint)); |
| |
| constraint_view_add_constraint (CONSTRAINT_VIEW (self->view), clone); |
| |
| g_object_unref (constraint); |
| g_object_unref (clone); |
| } |
| g_object_unref (list); |
| |
| g_free (path); |
| g_object_unref (builder); |
| |
| return TRUE; |
| } |
| |
| static void |
| open_response_cb (GtkNativeDialog *dialog, |
| int 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); |
| |
| GFile *cwd = g_file_new_for_path ("."); |
| gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL); |
| g_object_unref (cwd); |
| |
| 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<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); |
| g_string_append_printf (str, "%*s </object>\n", indent, ""); |
| g_string_append_printf (str, "%*s</child>\n", indent, ""); |
| } |
| |
| static char * |
| serialize_model (GListModel *list) |
| { |
| GString *str = g_string_new (""); |
| int i; |
| |
| g_string_append (str, "<interface>\n"); |
| g_string_append (str, " <object class=\"GtkBox\" id=\"view\">\n"); |
| g_string_append (str, " <property name=\"layout-manager\">\n"); |
| g_string_append (str, " <object class=\"GtkConstraintLayout\">\n"); |
| g_string_append (str, " <constraints>\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, " </constraints>\n"); |
| g_string_append (str, " </object>\n"); |
| g_string_append (str, " </property>\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, " </object>\n"); |
| g_string_append (str, "</interface>\n"); |
| |
| return g_string_free (str, FALSE); |
| } |
| |
| |
| static void |
| save_response_cb (GtkNativeDialog *dialog, |
| int response, |
| ConstraintEditorWindow *self) |
| { |
| gtk_native_dialog_hide (dialog); |
| |
| if (response == GTK_RESPONSE_ACCEPT) |
| { |
| GListModel *model; |
| GFile *file; |
| char *text; |
| GError *error = NULL; |
| |
| model = constraint_view_get_model (CONSTRAINT_VIEW (self->view)); |
| text = serialize_model (model); |
| file = gtk_file_chooser_get_file (GTK_FILE_CHOOSER (dialog)); |
| g_file_replace_contents (file, text, strlen (text), |
| NULL, FALSE, |
| G_FILE_CREATE_NONE, |
| NULL, |
| NULL, |
| &error); |
| if (error != NULL) |
| { |
| GtkWidget *message_dialog; |
| |
| message_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 (message_dialog), |
| "%s", error->message); |
| g_signal_connect (message_dialog, "response", G_CALLBACK (gtk_window_destroy), NULL); |
| gtk_widget_show (message_dialog); |
| g_error_free (error); |
| } |
| |
| g_free (text); |
| g_object_unref (file); |
| } |
| |
| 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); |
| |
| GFile *cwd = g_file_new_for_path ("."); |
| gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), cwd, NULL); |
| g_object_unref (cwd); |
| |
| 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) |
| { |
| //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 = gtk_constraint_guide_new (); |
| gtk_constraint_guide_set_name (guide, name); |
| g_free (name); |
| |
| 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_window_destroy (GTK_WINDOW (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_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_window_set_child (GTK_WINDOW (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) |
| { |
| gtk_window_destroy (GTK_WINDOW (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_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_window_set_child (GTK_WINDOW (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); |
| |
| 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, 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); |
| 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; |
| char *freeme = NULL; |
| GtkWidget *row, *box, *label, *button; |
| |
| if (GTK_IS_WIDGET (item)) |
| name = gtk_widget_get_name (GTK_WIDGET (item)); |
| else if (GTK_IS_CONSTRAINT_GUIDE (item)) |
| name = gtk_constraint_guide_get_name (GTK_CONSTRAINT_GUIDE (item)); |
| else if (GTK_IS_CONSTRAINT (item)) |
| name = freeme = constraint_editor_constraint_to_string (GTK_CONSTRAINT (item)); |
| else |
| name = ""; |
| |
| row = gtk_list_box_row_new (); |
| g_object_set_data_full (G_OBJECT (row), "item", g_object_ref (item), g_object_unref); |
| box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); |
| label = gtk_label_new (name); |
| if (GTK_IS_WIDGET (item) || GTK_IS_CONSTRAINT_GUIDE (item)) |
| g_object_bind_property (item, "name", |
| label, "label", |
| G_BINDING_DEFAULT); |
| gtk_widget_set_margin_start (label, 10); |
| gtk_widget_set_margin_end (label, 10); |
| gtk_widget_set_margin_top (label, 10); |
| gtk_widget_set_margin_bottom (label, 10); |
| gtk_label_set_xalign (GTK_LABEL (label), 0.0); |
| gtk_widget_set_hexpand (label, TRUE); |
| gtk_list_box_row_set_child (GTK_LIST_BOX_ROW (row), box); |
| gtk_box_append (GTK_BOX (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_has_frame (GTK_BUTTON (button), FALSE); |
| g_signal_connect (button, "clicked", G_CALLBACK (row_edit), win); |
| g_object_set_data (G_OBJECT (row), "edit", button); |
| gtk_box_append (GTK_BOX (box), button); |
| button = gtk_button_new_from_icon_name ("edit-delete-symbolic"); |
| gtk_button_set_has_frame (GTK_BUTTON (button), FALSE); |
| g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win); |
| gtk_box_append (GTK_BOX (box), button); |
| } |
| else if (GTK_IS_WIDGET (item)) |
| { |
| button = gtk_button_new_from_icon_name ("edit-delete-symbolic"); |
| gtk_button_set_has_frame (GTK_BUTTON (button), FALSE); |
| g_signal_connect (button, "clicked", G_CALLBACK (row_delete), win); |
| gtk_box_append (GTK_BOX (box), button); |
| } |
| |
| g_free (freeme); |
| |
| 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); |
| } |