M inc/gui/widgets/dialogs/project_assistant.h => inc/gui/widgets/dialogs/project_assistant.h +4 -20
@@ 1,21 1,5 @@
-/*
- * Copyright (C) 2018-2019, 2022 Alexandros Theodotou <alex at zrythm dot org>
- *
- * This file is part of Zrythm
- *
- * Zrythm is free software: you can redistribute it and/or modify
- * it under the terms of the GNU Affero General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * Zrythm 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 Affero General Public License for more details.
- *
- * You should have received a copy of the GNU Affero General Public License
- * along with Zrythm. If not, see <https://www.gnu.org/licenses/>.
- */
+// SPDX-FileCopyrightText: © 2018-2019, 2022-2023 Alexandros Theodotou <alex@zrythm.org>
+// SPDX-License-Identifier: LicenseRef-ZrythmLicense
/**
* \file
@@ 48,7 32,7 @@ G_DECLARE_FINAL_TYPE (
project_assistant_widget,
Z,
PROJECT_ASSISTANT_WIDGET,
- GtkDialog)
+ AdwWindow)
/**
* Project file information.
@@ 68,7 52,7 @@ typedef struct ProjectInfo
*/
typedef struct _ProjectAssistantWidget
{
- GtkDialog parent_instance;
+ AdwWindow parent_instance;
AdwViewStack * stack;
M inc/utils/gtk.h => inc/utils/gtk.h +3 -0
@@ 779,6 779,9 @@ z_gtk_get_first_focusable_child (GtkWidget * parent);
bool
z_gtk_descendant_has_focus (GtkWidget * parent);
+void
+z_gtk_window_make_escapable (GtkWindow * self);
+
/**
* @}
*/
M meson.build => meson.build +1 -2
@@ 520,7 520,6 @@ test_cflags = [
'-DG_LOG_USE_STRUCTURED=1',
'-DG_LOG_DOMAIN="' + prog_name_lowercase + '"',
'-DREALTIME=' + (is_clang ? '__attribute__((annotate("realtime")))' : ''),
- #'-DDEPRECATED_MSG(x)=__attribute__((deprecated(x)))',
'-DOPTIMIZE(x)=' + (is_gcc ? '__attribute__((optimize(#x)))' : ''),
'-DOPTIMIZE_O0=OPTIMIZE(O0)',
'-DOPTIMIZE_O1=OPTIMIZE(O1)',
@@ 899,7 898,7 @@ gtk_dep = dependency (
static: all_static)
libadwaita_dep = dependency (
- 'libadwaita-1', version: '>=1.2',
+ 'libadwaita-1', version: '>=1.4',
fallback: ['libadwaita', 'libadwaita_dep'],
default_options: [
'vapi=false', 'tests=false',
M resources/ui/export_dialog.ui => resources/ui/export_dialog.ui +1 -1
@@ 1,6 1,6 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
- <requires lib="Adw" version="4.0"/>
+ <requires lib="Adw" version="1.0"/>
<requires lib="gtk" version="4.0"/>
<template class="ExportDialogWidget" parent="GtkDialog">
<property name="title" translatable="yes">Export As...</property>
M resources/ui/project_assistant.ui => resources/ui/project_assistant.ui +83 -82
@@ 1,19 1,18 @@
<?xml version="1.0" encoding="UTF-8"?>
<interface>
<requires lib="gtk" version="4.0"/>
- <template class="ProjectAssistantWidget" parent="GtkDialog">
+ <requires lib="Adw" version="1.0"/>
+ <template class="ProjectAssistantWidget" parent="AdwWindow">
<property name="title" translatable="yes">Select a Project</property>
<property name="resizable">1</property>
<property name="icon_name">zrythm</property>
<property name="decorated">0</property>
<property name="modal">True</property>
- <property name="use-header-bar">True</property>
- <property name="height-request">280</property>
+ <property name="height-request">256</property>
<property name="width-request">680</property>
- <child internal-child="content_area">
- <object class="GtkBox">
- <property name="orientation">vertical</property>
- <child>
+ <property name="content">
+ <object class="AdwToolbarView">
+ <child type="top">
<object class="AdwHeaderBar">
<property name="centering-policy">strict</property>
<child type="title">
@@ 23,93 22,95 @@
</child>
</object>
</child>
- <child>
- <object class="AdwViewStack" id="stack">
- <property name="vexpand">1</property>
+ <property name="content">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
<child>
- <object class="AdwViewStackPage">
- <property name="name">open-recent</property>
- <property name="title" translatable="yes">Open Project</property>
- <property name="icon-name">folder-recent</property>
- <property name="child">
- <object class="GtkBox">
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkScrolledWindow">
- <property name="hscrollbar-policy">never</property>
- <property name="vexpand">1</property>
- <property name="child">
- <object class="GtkColumnView" id="recent_projects_column_view">
- <style>
- <class name="data-table"/>
- </style>
+ <object class="AdwViewStack" id="stack">
+ <property name="vexpand">1</property>
+ <child>
+ <object class="AdwViewStackPage">
+ <property name="name">open-recent</property>
+ <property name="title" translatable="yes">Open Project</property>
+ <property name="icon-name">folder-recent</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">never</property>
+ <property name="vexpand">1</property>
+ <property name="child">
+ <object class="GtkColumnView" id="recent_projects_column_view">
+ <property name="tab-behavior">GTK_LIST_TAB_ITEM</property>
+ <style>
+ <class name="data-table"/>
+ </style>
+ </object>
+ </property>
</object>
- </property>
+ </child>
</object>
- </child>
+ </property>
</object>
- </property>
- </object>
- </child>
- <child>
- <object class="AdwViewStackPage">
- <property name="name">create-new</property>
- <property name="title" translatable="yes">Create New</property>
- <property name="icon-name">document-new</property>
- <property name="child">
- <object class="GtkBox">
- <property name="orientation">vertical</property>
- <child>
- <object class="GtkScrolledWindow">
- <property name="hscrollbar-policy">never</property>
- <property name="vexpand">1</property>
- <property name="child">
- <object class="GtkColumnView" id="templates_column_view">
- <style>
- <class name="data-table"/>
- </style>
+ </child>
+ <child>
+ <object class="AdwViewStackPage">
+ <property name="name">create-new</property>
+ <property name="title" translatable="yes">Create New</property>
+ <property name="icon-name">document-new</property>
+ <property name="child">
+ <object class="GtkBox">
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkScrolledWindow">
+ <property name="hscrollbar-policy">never</property>
+ <property name="vexpand">1</property>
+ <property name="child">
+ <object class="GtkColumnView" id="templates_column_view">
+ <style>
+ <class name="data-table"/>
+ </style>
+ </object>
+ </property>
</object>
- </property>
+ </child>
</object>
- </child>
+ </property>
</object>
- </property>
+ </child>
+ </object>
+ </child>
+ <child>
+ <object class="AdwViewSwitcherBar">
+ <property name="stack">stack</property>
+ <binding name="reveal">
+ <lookup name="title-visible">title</lookup>
+ </binding>
</object>
</child>
</object>
- </child>
- <child>
- <object class="AdwViewSwitcherBar">
- <property name="stack">stack</property>
- <binding name="reveal">
- <lookup name="title-visible">title</lookup>
- </binding>
+ </property>
+ <child type="bottom">
+ <object class="GtkActionBar">
+ <child type="end">
+ <object class="GtkButton" id="ok_btn">
+ <style>
+ <class name="suggested-action"/>
+ </style>
+ <property name="label" translatable="yes">_Open Selected</property>
+ <property name="use-underline">1</property>
+ </object>
+ </child>
+ <child type="end">
+ <object class="GtkButton" id="open_from_path_btn">
+ <property name="label" translatable="yes">Open from _Path</property>
+ <property name="use-underline">1</property>
+ </object>
+ </child>
</object>
</child>
</object>
- </child>
- <child type="action">
- <object class="GtkButton" id="cancel_btn">
- <property name="label" translatable="yes">_Cancel</property>
- <property name="use-underline">1</property>
- </object>
- </child>
- <child type="action">
- <object class="GtkButton" id="open_from_path_btn">
- <property name="label" translatable="yes">Open from _Path</property>
- <property name="use-underline">1</property>
- </object>
- </child>
- <child type="action">
- <object class="GtkButton" id="ok_btn">
- <property name="label" translatable="yes">_Open Selected</property>
- <property name="use-underline">1</property>
- </object>
- </child>
- <action-widgets>
- <action-widget response="cancel">cancel_btn</action-widget>
- <action-widget response="256">open_from_path_btn</action-widget>
- <action-widget response="ok" default="true">ok_btn</action-widget>
- </action-widgets>
+ </property>
</template>
</interface>
M src/gui/widgets/dialogs/midi_function_dialog.c => src/gui/widgets/dialogs/midi_function_dialog.c +2 -12
@@ 5,6 5,7 @@
#include "project.h"
#include "settings/settings.h"
#include "utils/error.h"
+#include "utils/gtk.h"
#include "utils/io.h"
#include "utils/objects.h"
#include "utils/resources.h"
@@ 421,16 422,5 @@ midi_function_dialog_widget_init (
gtk_box_append (self->vbox, GTK_WIDGET (self->page));
/* close on escape */
- GtkShortcutTrigger * trigger =
- gtk_shortcut_trigger_parse_string ("Escape|<Control>w");
- GtkShortcutAction * action =
- gtk_named_action_new ("window.close");
- GtkShortcut * esc_shortcut =
- gtk_shortcut_new (trigger, action);
- GtkShortcutController * sc =
- GTK_SHORTCUT_CONTROLLER (gtk_shortcut_controller_new ());
- gtk_shortcut_controller_add_shortcut (sc, esc_shortcut);
- gtk_widget_add_controller (
- GTK_WIDGET (self), GTK_EVENT_CONTROLLER (sc));
- /* note: can also use gtk_widget_class_add_binding_action (widget_class, GDK_KEY_Escape, 0, "window.close", NULL); */
+ z_gtk_window_make_escapable (GTK_WINDOW (self));
}
M src/gui/widgets/dialogs/project_assistant.c => src/gui/widgets/dialogs/project_assistant.c +149 -128
@@ 26,7 26,7 @@
G_DEFINE_TYPE (
ProjectAssistantWidget,
project_assistant_widget,
- GTK_TYPE_DIALOG)
+ ADW_TYPE_WINDOW)
static ProjectInfo *
project_info_new (const char * name, const char * filename)
@@ 315,27 315,6 @@ on_key_release (
}
}
-static void
-on_project_activate (
- GtkColumnView * column_view,
- guint position,
- gpointer user_data)
-{
- ProjectAssistantWidget * self =
- (ProjectAssistantWidget *) user_data;
-
- GListStore * list_store =
- z_gtk_column_view_get_list_store (column_view);
- WrappedObjectWithChangeSignal * wrapped_obj =
- Z_WRAPPED_OBJECT_WITH_CHANGE_SIGNAL (g_list_model_get_item (
- G_LIST_MODEL (list_store), position));
- ProjectInfo * nfo = (ProjectInfo *) wrapped_obj->obj;
-
- g_debug ("activated %s", nfo->filename);
-
- gtk_dialog_response (GTK_DIALOG (self), GTK_RESPONSE_OK);
-}
-
/**
* Runs the project assistant.
*
@@ 389,36 368,45 @@ project_assistant_widget_present (
}
static void
-on_file_chooser_response (
- GtkNativeDialog * native,
- int response,
+run_create_project_dialog (
+ ProjectAssistantWidget * self,
+ GtkWindow * transient_parent)
+{
+ CreateProjectDialogWidget * create_prj_dialog =
+ create_project_dialog_widget_new ();
+ g_signal_connect (
+ G_OBJECT (create_prj_dialog), "response",
+ G_CALLBACK (create_project_dialog_response_cb),
+ GINT_TO_POINTER (self->zrythm_already_running));
+
+ gtk_window_set_transient_for (
+ GTK_WINDOW (create_prj_dialog),
+ GTK_WINDOW (transient_parent));
+
+ gtk_window_present (GTK_WINDOW (create_prj_dialog));
+}
+
+static bool
+on_close_request (
+ GtkWindow * window,
ProjectAssistantWidget * self)
{
- if (response == GTK_RESPONSE_ACCEPT)
- {
- GtkFileChooser * chooser = GTK_FILE_CHOOSER (native);
- GFile * file = gtk_file_chooser_get_file (chooser);
- char * path = g_file_get_path (file);
- g_return_if_fail (path);
- g_object_unref (file);
+ g_debug ("close request");
- ZRYTHM->open_filename = path;
- g_message ("Loading project: %s", ZRYTHM->open_filename);
+ ZRYTHM->creating_project = true;
+ ZRYTHM->open_filename = NULL;
- post_finish (self, self->zrythm_already_running, false);
- }
+ /* window already destroyed, set transient to splash screen
+ * instead */
+ run_create_project_dialog (self, GTK_WINDOW (self->parent));
- g_object_unref (native);
+ /* close normally */
+ return false;
}
static void
-on_response (
- GtkDialog * dialog,
- gint response_id,
- ProjectAssistantWidget * self)
+on_ok_clicked (GtkButton * btn, ProjectAssistantWidget * self)
{
- g_debug ("response %d", response_id);
-
ZRYTHM->creating_project = true;
const char * child_name =
@@ 428,106 416,124 @@ on_response (
ProjectInfo * selected_template =
get_selected_template (self);
- switch (response_id)
+ if (string_is_equal (child_name, "create-new"))
{
- case GTK_RESPONSE_DELETE_EVENT:
- case GTK_RESPONSE_CLOSE:
- case GTK_RESPONSE_CANCEL:
- ZRYTHM->open_filename = NULL;
- break;
- case GTK_RESPONSE_OK:
- if (string_is_equal (child_name, "create-new"))
- {
- g_return_if_fail (selected_template);
+ g_return_if_fail (selected_template);
- /* if we are loading a blank template */
- if (selected_template->filename[0] == '-')
- {
- ZRYTHM->open_filename = NULL;
- g_message ("Creating blank project");
- }
- else
- {
- ZRYTHM->open_filename =
- selected_template->filename;
- g_message (
- "Creating project from template: %s",
- ZRYTHM->open_filename);
- ZRYTHM->opening_template = true;
- }
+ /* if we are loading a blank template */
+ if (selected_template->filename[0] == '-')
+ {
+ ZRYTHM->open_filename = NULL;
+ g_message ("Creating blank project");
}
- /* else if we are loading a project */
- else if (string_is_equal (child_name, "open-recent"))
+ else
{
- if (!selected_project)
- {
- ui_show_error_message (
- false, _ ("No project selected"));
- return;
- }
- ZRYTHM->open_filename = selected_project->filename;
- g_return_if_fail (ZRYTHM->open_filename);
+ ZRYTHM->open_filename = selected_template->filename;
g_message (
- "Loading project: %s", ZRYTHM->open_filename);
- ZRYTHM->creating_project = false;
+ "Creating project from template: %s",
+ ZRYTHM->open_filename);
+ ZRYTHM->opening_template = true;
}
- break;
- /* open from path */
- case 256:
- {
- GtkFileChooserNative * native =
- gtk_file_chooser_native_new (
- _ ("Select Project File"), GTK_WINDOW (self),
- GTK_FILE_CHOOSER_ACTION_OPEN, _ ("_Open"),
- _ ("_Cancel"));
- GtkFileFilter * filter = gtk_file_filter_new ();
- gtk_file_filter_add_mime_type (
- filter, "application/x-zrythm-project");
- gtk_file_filter_add_suffix (filter, "zpj");
- gtk_file_chooser_add_filter (
- GTK_FILE_CHOOSER (native), filter);
- g_signal_connect (
- native, "response",
- G_CALLBACK (on_file_chooser_response), self);
- gtk_native_dialog_show (GTK_NATIVE_DIALOG (native));
- return;
- }
- break;
+ }
+ /* else if we are loading a project */
+ else if (string_is_equal (child_name, "open-recent"))
+ {
+ if (!selected_project)
+ {
+ ui_show_error_message (
+ false, _ ("No project selected"));
+ return;
+ }
+ ZRYTHM->open_filename = selected_project->filename;
+ g_return_if_fail (ZRYTHM->open_filename);
+ g_message ("Loading project: %s", ZRYTHM->open_filename);
+ ZRYTHM->creating_project = false;
}
- /* if not loading a project, show dialog to
- * select directory and name */
+ /* if not loading a project, show dialog to select directory
+ * and name */
if (ZRYTHM->creating_project)
{
- CreateProjectDialogWidget * create_prj_dialog =
- create_project_dialog_widget_new ();
- g_signal_connect (
- G_OBJECT (create_prj_dialog), "response",
- G_CALLBACK (create_project_dialog_response_cb),
- GINT_TO_POINTER (self->zrythm_already_running));
+ run_create_project_dialog (self, GTK_WINDOW (self));
+ }
+ else
+ {
+ post_finish (self, self->zrythm_already_running, false);
+ }
+}
- /* if window already destroyed, set transient
- * to splash screen instead */
- if (
- response_id == GTK_RESPONSE_DELETE_EVENT
- || response_id == GTK_RESPONSE_CLOSE)
- {
- gtk_window_set_transient_for (
- GTK_WINDOW (create_prj_dialog),
- GTK_WINDOW (self->parent));
- }
- else
- {
- gtk_window_set_transient_for (
- GTK_WINDOW (create_prj_dialog), GTK_WINDOW (self));
- }
- gtk_window_present (GTK_WINDOW (create_prj_dialog));
+static void
+open_ready_cb (
+ GtkFileDialog * dialog,
+ GAsyncResult * res,
+ ProjectAssistantWidget * self)
+{
+ GError * err = NULL;
+ GFile * file =
+ gtk_file_dialog_open_finish (dialog, res, &err);
+ if (!file)
+ {
+ g_message ("no project selected: %s", err->message);
+ g_error_free (err);
return;
}
+ char * path = g_file_get_path (file);
+ g_return_if_fail (path);
+ g_object_unref (file);
+
+ ZRYTHM->open_filename = path;
+ g_message ("Loading project: %s", ZRYTHM->open_filename);
+
post_finish (self, self->zrythm_already_running, false);
}
+static void
+on_open_from_path_clicked (
+ GtkButton * btn,
+ ProjectAssistantWidget * self)
+{
+ ZRYTHM->creating_project = true;
+
+ GtkFileDialog * dialog = gtk_file_dialog_new ();
+ gtk_file_dialog_set_title (dialog, _ ("Select Project"));
+ gtk_file_dialog_set_modal (dialog, true);
+ GtkFileFilter * filter = gtk_file_filter_new ();
+ gtk_file_filter_add_mime_type (
+ filter, "application/x-zrythm-project");
+ gtk_file_filter_add_suffix (filter, "zpj");
+ GListStore * list_store =
+ g_list_store_new (GTK_TYPE_FILE_FILTER);
+ g_list_store_append (list_store, filter);
+ gtk_file_dialog_set_filters (
+ dialog, G_LIST_MODEL (list_store));
+ g_object_unref (list_store);
+ gtk_file_dialog_open (
+ dialog, GTK_WINDOW (self), NULL,
+ (GAsyncReadyCallback) open_ready_cb, self);
+}
+
+static void
+on_project_activate (
+ GtkColumnView * column_view,
+ guint position,
+ gpointer user_data)
+{
+ ProjectAssistantWidget * self =
+ (ProjectAssistantWidget *) user_data;
+
+ GListStore * list_store =
+ z_gtk_column_view_get_list_store (column_view);
+ WrappedObjectWithChangeSignal * wrapped_obj =
+ Z_WRAPPED_OBJECT_WITH_CHANGE_SIGNAL (g_list_model_get_item (
+ G_LIST_MODEL (list_store), position));
+ ProjectInfo * nfo = (ProjectInfo *) wrapped_obj->obj;
+
+ g_debug ("activated %s", nfo->filename);
+
+ on_ok_clicked (self->ok_btn, self);
+}
+
static char *
get_prj_name (void * data)
{
@@ 646,7 652,7 @@ project_assistant_widget_class_init (
BIND_CHILD (templates_column_view);
BIND_CHILD (ok_btn);
BIND_CHILD (open_from_path_btn);
- BIND_CHILD (cancel_btn);
+ /*BIND_CHILD (cancel_btn);*/
#undef BIND_CHILD
@@ 658,6 664,8 @@ project_assistant_widget_class_init (
static void
project_assistant_widget_init (ProjectAssistantWidget * self)
{
+ g_type_ensure (ADW_TYPE_TOOLBAR_VIEW);
+
gtk_widget_init_template (GTK_WIDGET (self));
gtk_widget_set_size_request (GTK_WIDGET (self), 380, 180);
@@ 756,9 764,22 @@ project_assistant_widget_init (ProjectAssistantWidget * self)
G_CALLBACK (on_visible_child_name_changed), self);
g_signal_connect (
- self, "response", G_CALLBACK (on_response), self);
+ self->ok_btn, "clicked", G_CALLBACK (on_ok_clicked), self);
+ g_signal_connect (
+ self->open_from_path_btn, "clicked",
+ G_CALLBACK (on_open_from_path_clicked), self);
+ g_signal_connect (
+ self, "close-request", G_CALLBACK (on_close_request),
+ self);
gtk_window_set_focus (
GTK_WINDOW (self),
GTK_WIDGET (self->recent_projects_column_view));
+
+ /* close on escape */
+ z_gtk_window_make_escapable (GTK_WINDOW (self));
+
+ gtk_accessible_update_property (
+ GTK_ACCESSIBLE (self->recent_projects_column_view),
+ GTK_ACCESSIBLE_PROPERTY_LABEL, "Recent projects", -1);
}
M src/utils/gtk.c => src/utils/gtk.c +26 -0
@@ 2296,3 2296,29 @@ z_gtk_descendant_has_focus (GtkWidget * parent)
return get_first_focused_or_focusable_child (parent, true)
!= NULL;
}
+
+void
+z_gtk_window_make_escapable (GtkWindow * self)
+{
+ /* close on escape */
+#if 0
+ /* for reference */
+ GtkShortcutTrigger * trigger =
+ gtk_shortcut_trigger_parse_string ("Escape|<Control>w");
+ GtkShortcutAction * action =
+ gtk_named_action_new ("window.close");
+ GtkShortcut * esc_shortcut =
+ gtk_shortcut_new (trigger, action);
+ GtkShortcutController * sc =
+ GTK_SHORTCUT_CONTROLLER (gtk_shortcut_controller_new ());
+ gtk_shortcut_controller_add_shortcut (sc, esc_shortcut);
+ gtk_widget_add_controller (
+ GTK_WIDGET (self), GTK_EVENT_CONTROLLER (sc));
+#endif
+ GtkWidgetClass * wklass =
+ GTK_WIDGET_CLASS (G_OBJECT_GET_CLASS (self));
+ gtk_widget_class_add_binding_action (
+ wklass, GDK_KEY_Escape, 0, "window.close", NULL);
+ gtk_widget_class_add_binding_action (
+ wklass, GDK_KEY_w, GDK_CONTROL_MASK, "window.close", NULL);
+}
M subprojects/libadwaita.wrap => subprojects/libadwaita.wrap +2 -2
@@ 1,6 1,6 @@
[wrap-git]
directory=libadwaita
url=https://gitlab.gnome.org/GNOME/libadwaita
-# 1.3.2
-revision=dfaf404704a6e4a15d9881fc39ec8a607cd47701
+# 1.4.beta
+revision=dbe9da35ed611b907efb4a671f6ab57342946581
depth=1