Initial port to GTK4

This commit is contained in:
Elias Projahn 2021-01-25 14:00:57 +01:00
parent 1a9e58d627
commit 801a130ef8
76 changed files with 3098 additions and 6625 deletions

View file

@ -11,19 +11,37 @@ discid = "0.4.4"
fragile = "1.0.0" fragile = "1.0.0"
futures = "0.3.6" futures = "0.3.6"
futures-channel = "0.3.5" futures-channel = "0.3.5"
gdk = "0.13.2"
gettext-rs = "0.5.0" gettext-rs = "0.5.0"
gio = "0.9.1"
glib = "0.10.2"
gtk = { version = "0.9.2", features = ["v3_24"] }
gtk-macros = "0.2.0" gtk-macros = "0.2.0"
gstreamer = "0.16.4" gstreamer = "0.16.4"
gstreamer-player = "0.16.3" gstreamer-player = "0.16.3"
isahc = "0.9.12" isahc = "0.9.12"
libhandy = "0.7.0"
pango = "0.9.1"
rand = "0.7.3" rand = "0.7.3"
secret-service = "1.1.1" secret-service = "1.1.1"
serde = { version = "1.0.117", features = ["derive"] } serde = { version = "1.0.117", features = ["derive"] }
serde_json = "1.0.59" serde_json = "1.0.59"
uuid = { version = "0.8", features = ["v4"] } uuid = { version = "0.8", features = ["v4"] }
[dependencies.gdk]
git = "https://github.com/gtk-rs/gtk4-rs/"
package = "gdk4"
[dependencies.gio]
git = "https://github.com/gtk-rs/gtk-rs/"
features = ["v2_64"]
[dependencies.glib]
git = "https://github.com/gtk-rs/gtk-rs/"
features = ["v2_64"]
[dependencies.gtk]
git = "https://github.com/gtk-rs/gtk4-rs"
package = "gtk4"
[dependencies.libhandy]
git = "https://gitlab.gnome.org/bilelmoussaoui/libhandy4-rs"
package = "libhandy4"
[dependencies.pango]
git = "https://github.com/gtk-rs/gtk-rs/"
features = ["v1_44"]

View file

@ -92,6 +92,28 @@
} }
] ]
}, },
{
"name" : "libhandy",
"buildsystem" : "meson",
"config-opts" : [
"-Dintrospection=enabled",
"-Dtests=false",
"-Dexamples=false",
"-Dvapi=false",
"-Dglade_catalog=disabled"
],
"cleanup" : [
"/include",
"/lib/pkgconfig"
],
"sources" : [
{
"type" : "git",
"url" : "https://gitlab.gnome.org/exalm/libhandy",
"branch" : "gtk4"
}
]
},
{ {
"name" : "musicus", "name" : "musicus",
"builddir" : true, "builddir" : true,

View file

@ -3,24 +3,18 @@
<gresource prefix="/de/johrpan/musicus"> <gresource prefix="/de/johrpan/musicus">
<file preprocess="xml-stripblanks">ui/ensemble_editor.ui</file> <file preprocess="xml-stripblanks">ui/ensemble_editor.ui</file>
<file preprocess="xml-stripblanks">ui/ensemble_screen.ui</file> <file preprocess="xml-stripblanks">ui/ensemble_screen.ui</file>
<file preprocess="xml-stripblanks">ui/ensemble_selector.ui</file>
<file preprocess="xml-stripblanks">ui/instrument_editor.ui</file> <file preprocess="xml-stripblanks">ui/instrument_editor.ui</file>
<file preprocess="xml-stripblanks">ui/instrument_selector.ui</file>
<file preprocess="xml-stripblanks">ui/login_dialog.ui</file> <file preprocess="xml-stripblanks">ui/login_dialog.ui</file>
<file preprocess="xml-stripblanks">ui/medium_editor.ui</file> <file preprocess="xml-stripblanks">ui/medium_editor.ui</file>
<file preprocess="xml-stripblanks">ui/performance_editor.ui</file> <file preprocess="xml-stripblanks">ui/performance_editor.ui</file>
<file preprocess="xml-stripblanks">ui/person_editor.ui</file> <file preprocess="xml-stripblanks">ui/person_editor.ui</file>
<file preprocess="xml-stripblanks">ui/person_list.ui</file>
<file preprocess="xml-stripblanks">ui/person_screen.ui</file> <file preprocess="xml-stripblanks">ui/person_screen.ui</file>
<file preprocess="xml-stripblanks">ui/person_selector.ui</file>
<file preprocess="xml-stripblanks">ui/player_bar.ui</file> <file preprocess="xml-stripblanks">ui/player_bar.ui</file>
<file preprocess="xml-stripblanks">ui/player_screen.ui</file> <file preprocess="xml-stripblanks">ui/player_screen.ui</file>
<file preprocess="xml-stripblanks">ui/poe_list.ui</file> <file preprocess="xml-stripblanks">ui/poe_list.ui</file>
<file preprocess="xml-stripblanks">ui/preferences.ui</file> <file preprocess="xml-stripblanks">ui/preferences.ui</file>
<file preprocess="xml-stripblanks">ui/recording_editor.ui</file> <file preprocess="xml-stripblanks">ui/recording_editor.ui</file>
<file preprocess="xml-stripblanks">ui/recording_screen.ui</file> <file preprocess="xml-stripblanks">ui/recording_screen.ui</file>
<file preprocess="xml-stripblanks">ui/recording_selector.ui</file>
<file preprocess="xml-stripblanks">ui/recording_selector_screen.ui</file>
<file preprocess="xml-stripblanks">ui/selector.ui</file> <file preprocess="xml-stripblanks">ui/selector.ui</file>
<file preprocess="xml-stripblanks">ui/server_dialog.ui</file> <file preprocess="xml-stripblanks">ui/server_dialog.ui</file>
<file preprocess="xml-stripblanks">ui/source_selector.ui</file> <file preprocess="xml-stripblanks">ui/source_selector.ui</file>
@ -32,7 +26,5 @@
<file preprocess="xml-stripblanks">ui/work_part_editor.ui</file> <file preprocess="xml-stripblanks">ui/work_part_editor.ui</file>
<file preprocess="xml-stripblanks">ui/work_screen.ui</file> <file preprocess="xml-stripblanks">ui/work_screen.ui</file>
<file preprocess="xml-stripblanks">ui/work_section_editor.ui</file> <file preprocess="xml-stripblanks">ui/work_section_editor.ui</file>
<file preprocess="xml-stripblanks">ui/work_selector.ui</file>
<file preprocess="xml-stripblanks">ui/work_selector_screen.ui</file>
</gresource> </gresource>
</gresources> </gresources>

View file

@ -1,189 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkStack" id="widget"> <object class="GtkStack" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Ensemble</property> <object class="GtkLabel">
<property name="label" translatable="yes">Ensemble</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="revealed">False</property> <property name="revealed">False</property>
<child>
<placeholder/>
</child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<child> <child>
<!-- n-columns=2 n-rows=2 --> <object class="GtkFrame">
<object class="GtkGrid"> <property name="valign">start</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkListBox">
<property name="visible">True</property> <property name="selection-mode">none</property>
<property name="can-focus">False</property> <child>
<property name="halign">end</property> <object class="HdyActionRow">
<property name="label" translatable="yes">Name</property> <property name="activatable">True</property>
</object> <property name="title" translatable="yes">Name</property>
<packing> <property name="activatable-widget">name_entry</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="name_entry"> <object class="GtkEntry" id="name_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
<packing> </child>
<property name="left-attach">1</property> </object>
<property name="top-attach">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Publish to the server</property>
<property name="halign">end</property> <property name="activatable-widget">upload_switch</property>
<property name="label" translatable="yes">Publish</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child> <child>
<object class="GtkSwitch" id="upload_switch"> <object class="GtkSwitch" id="upload_switch">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="active">True</property> <property name="active">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing> </child>
<property name="name">content</property> </object>
</packing> </child>
</object>
</child>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Ensemble</property> <object class="GtkLabel">
<property name="label" translatable="yes">Ensemble</property>
<style>
<class name="title"/>
</style>
</object>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="spinning">true</property>
<property name="can-focus">False</property> <property name="hexpand">true</property>
<property name="vexpand">True</property> <property name="vexpand">true</property>
<property name="active">True</property> <property name="halign">center</property>
<property name="valign">center</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">loading</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,132 +1,73 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar" id="header"> <object class="HdyHeaderBar" id="header">
<property name="visible">True</property> <property name="title-widget">
<property name="can-focus">False</property> <object class="GtkLabel" id="title_label">
<property name="show-close-button">True</property> <property name="label" translatable="yes">Ensemble</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkMenuButton"> <object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="menu-model">menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">view-more-symbolic</property> <property name="icon-name">view-more-symbolic</property>
<property name="menu-model">menu</property>
</object> </object>
</child> </child>
</object> <child type="end">
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_button"> <object class="GtkToggleButton" id="search_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-find-symbolic</property> <property name="icon-name">edit-find-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="HdySearchBar"> <object class="GtkSearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create">False</property> <property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create">False</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">400</property> <property name="maximum-size">400</property>
<property name="hexpand">true</property>
<child> <child>
<object class="GtkSearchEntry" id="search_entry"> <object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search recordings …</property> <property name="placeholder-text" translatable="yes">Search recordings …</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkSpinner"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
</packing> <property name="child">
<object class="GtkSpinner">
<property name="spinning">True</property>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">12</property> <property name="margin-start">12</property>
<property name="margin-end">12</property> <property name="margin-end">12</property>
<property name="margin-top">18</property> <property name="margin-top">18</property>
@ -134,42 +75,19 @@
<property name="maximum-size">800</property> <property name="maximum-size">800</property>
<child> <child>
<object class="GtkBox" id="recording_box"> <object class="GtkBox" id="recording_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Recordings</property> <property name="label" translatable="yes">Recordings</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkFrame" id="recording_frame"> <object class="GtkFrame" id="recording_frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object> </object>
</child> </child>
</object> </object>
@ -177,28 +95,20 @@
</object> </object>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">content</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">nothing</property>
<property name="child">
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">No recordings found.</property> <property name="label" translatable="yes">No recordings found.</property>
</object> </object>
<packing> </property>
<property name="name">nothing</property> </object>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<menu id="menu"> <menu id="menu">

View file

@ -1,210 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="0.0"/>
<object class="HdyWindow" id="window">
<property name="can-focus">False</property>
<property name="modal">True</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Select ensemble</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkButton" id="add_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search ensembles …</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="server_check_button">
<property name="label" translatable="yes">Show ensembles from the Musicus server</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">An error occured!</property>
<attributes>
<attribute name="size" value="16384"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="max-width-chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">error</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View file

@ -1,189 +1,132 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkStack" id="widget"> <object class="GtkStack" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Instrument</property> <object class="GtkLabel">
<property name="label" translatable="yes">Instrument</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="revealed">False</property> <property name="revealed">False</property>
<child>
<placeholder/>
</child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<child> <child>
<!-- n-columns=2 n-rows=2 --> <object class="GtkFrame">
<object class="GtkGrid"> <property name="valign">start</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkListBox">
<property name="visible">True</property> <property name="selection-mode">none</property>
<property name="can-focus">False</property> <child>
<property name="halign">end</property> <object class="HdyActionRow">
<property name="label" translatable="yes">Name</property> <property name="activatable">True</property>
</object> <property name="title" translatable="yes">Name</property>
<packing> <property name="activatable-widget">name_entry</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="name_entry"> <object class="GtkEntry" id="name_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
<packing> </child>
<property name="left-attach">1</property> </object>
<property name="top-attach">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Publish to the server</property>
<property name="halign">end</property> <property name="activatable-widget">upload_switch</property>
<property name="label" translatable="yes">Publish</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child> <child>
<object class="GtkSwitch" id="upload_switch"> <object class="GtkSwitch" id="upload_switch">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="active">True</property> <property name="active">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing> </child>
<property name="name">content</property> </object>
</packing> </child>
</object>
</child>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Instrument</property> <object class="GtkLabel">
<property name="label" translatable="yes">Instrument</property>
<style>
<class name="title"/>
</style>
</object>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="spinning">true</property>
<property name="can-focus">False</property> <property name="hexpand">true</property>
<property name="vexpand">True</property> <property name="vexpand">true</property>
<property name="active">True</property> <property name="halign">center</property>
<property name="valign">center</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">loading</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,210 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="0.0"/>
<object class="HdyWindow" id="window">
<property name="can-focus">False</property>
<property name="modal">True</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Select instrument</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkButton" id="add_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search instruments …</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="server_check_button">
<property name="label" translatable="yes">Show instruments from the Musicus server</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">An error occured!</property>
<attributes>
<attribute name="size" value="16384"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="max-width-chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">error</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View file

@ -1,219 +1,134 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="0.0"/> <requires lib="libhandy" version="1.0"/>
<object class="HdyWindow" id="window"> <object class="HdyWindow" id="window">
<property name="can-focus">False</property>
<property name="modal">True</property> <property name="modal">True</property>
<property name="default-width">350</property> <property name="default-width">350</property>
<property name="type-hint">dialog</property>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Login</property> <object class="GtkLabel">
<property name="label" translatable="yes">Login</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="cancel_button"> <object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">Cancel</property> <property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
</object> </object>
</child> </child>
<child> <child type="end">
<object class="GtkButton" id="login_button"> <object class="GtkButton" id="login_button">
<property name="label" translatable="yes">Login</property> <property name="label" translatable="yes">Login</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="has-default">True</property> <property name="has-default">True</property>
<property name="receives-default">False</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="message-type">error</property> <property name="message-type">error</property>
<property name="revealed">False</property> <property name="revealed">False</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can-focus">False</property>
<property name="spacing">6</property>
<property name="layout-style">end</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can-focus">False</property>
<property name="spacing">16</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">The login credentials were wrong!</property> <property name="label" translatable="yes">The login credentials were wrong!</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<!-- n-columns=2 n-rows=2 --> <object class="GtkListBox">
<object class="GtkGrid"> <property name="selection-mode">none</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Username</property>
<property name="halign">end</property> <property name="activatable-widget">username_entry</property>
<property name="label" translatable="yes">Username</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Password</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="username_entry"> <object class="GtkEntry" id="username_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
<packing> </child>
<property name="left-attach">1</property> </object>
<property name="top-attach">0</property>
</packing>
</child> </child>
<child>
<object class="HdyActionRow">
<property name="activatable">True</property>
<property name="title" translatable="yes">Password</property>
<property name="activatable-widget">password_entry</property>
<child> <child>
<object class="GtkEntry" id="password_entry"> <object class="GtkEntry" id="password_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property> <property name="hexpand">True</property>
<property name="visibility">False</property> <property name="visibility">False</property>
<property name="activates-default">True</property> <property name="activates-default">True</property>
<property name="input-purpose">password</property> <property name="input-purpose">password</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing> </child>
<property name="name">content</property> </object>
</packing> </property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Login</property> <object class="GtkLabel">
<property name="label" translatable="yes">Login</property>
<style>
<class name="title"/>
</style>
</object>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="spinning">True</property>
<property name="can-focus">False</property> <property name="hexpand">true</property>
<property name="active">True</property> <property name="vexpand">true</property>
<property name="halign">center</property>
<property name="valign">center</property>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">loading</property> </object>
<property name="position">1</property>
</packing>
</child>
<child>
<placeholder/>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<object class="GtkSizeGroup">
<widgets>
<widget name="username_entry"/>
<widget name="password_entry"/>
</widgets>
</object>
</interface> </interface>

View file

@ -1,48 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkStack" id="widget"> <object class="GtkStack" id="widget">
<property name="visible">True</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="title" translatable="yes">Import music</property> <property name="title-widget">
<object class="GtkLabel">
<property name="label" translatable="yes">Import music</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="done_button"> <object class="GtkButton" id="done_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<child> <child>
<object class="GtkStack" id="done_stack"> <object class="GtkStack" id="done_stack">
<property name="visible">True</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkSpinner" id="spinner"> <object class="GtkSpinner" id="spinner">
<property name="visible">True</property> <property name="spinning">True</property>
<property name="active">True</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkImage" id="done"> <object class="GtkImage" id="done">
<property name="visible">True</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object> </object>
</child> </child>
@ -52,37 +48,27 @@
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="revealed">False</property> <property name="revealed">False</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="vexpand">True</property> <property name="vexpand">True</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="margin-start">6</property> <property name="margin-start">6</property>
<property name="margin-end">6</property> <property name="margin-end">6</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="margin-top">12</property> <property name="margin-top">12</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
@ -94,23 +80,16 @@
</child> </child>
<child> <child>
<object class="GtkFrame"> <object class="GtkFrame">
<property name="visible">True</property>
<property name="shadow-type">in</property>
<child> <child>
<object class="GtkListBox"> <object class="GtkListBox">
<property name="visible">True</property>
<property name="selection-mode">none</property> <property name="selection-mode">none</property>
<child> <child>
<object class="HdyActionRow" id="name_row"> <object class="HdyActionRow" id="name_row">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="activatable">True</property> <property name="activatable">True</property>
<property name="title" translatable="yes">Name of the medium</property> <property name="title" translatable="yes">Name of the medium</property>
<property name="activatable-widget">name_entry</property> <property name="activatable-widget">name_entry</property>
<child> <child>
<object class="GtkEntry" id="name_entry"> <object class="GtkEntry" id="name_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
@ -119,15 +98,11 @@
</child> </child>
<child> <child>
<object class="HdyActionRow"> <object class="HdyActionRow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="activatable">True</property> <property name="activatable">True</property>
<property name="title" translatable="yes">Publish to the server</property> <property name="title" translatable="yes">Publish to the server</property>
<property name="activatable-widget">publish_switch</property> <property name="activatable-widget">publish_switch</property>
<child> <child>
<object class="GtkSwitch" id="publish_switch"> <object class="GtkSwitch" id="publish_switch">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="active">True</property> <property name="active">True</property>
</object> </object>
@ -140,13 +115,11 @@
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">horizontal</property> <property name="orientation">horizontal</property>
<property name="margin-top">12</property> <property name="margin-top">12</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="valign">end</property> <property name="valign">end</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
@ -158,44 +131,38 @@
</child> </child>
<child> <child>
<object class="GtkButton" id="add_button"> <object class="GtkButton" id="add_button">
<property name="visible">True</property> <property name="has-frame">false</property>
<property name="can-focus">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">list-add-symbolic</property> <property name="icon-name">list-add-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
<child>
<object class="GtkFrame" id="frame"/>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</property>
</object> </object>
</child> </child>
<child> <child>
<object class="GtkFrame" id="frame"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="shadow-type">in</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="name">content</property>
</packing>
</child>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
</packing> <property name="child">
<object class="GtkSpinner">
<property name="spinning">true</property>
<property name="hexpand">true</property>
<property name="vexpand">true</property>
<property name="halign">center</property>
<property name="valign">center</property>
</object>
</property>
</object>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,281 +1,106 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Performance</property> <object class="GtkLabel">
<property name="label" translatable="yes">Performance</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<child> <child>
<!-- n-columns=2 n-rows=3 --> <object class="GtkFrame">
<object class="GtkGrid"> <property name="valign">start</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel" id="label4"> <object class="GtkListBox">
<property name="visible">True</property> <property name="selection-mode">none</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Role</property>
<property name="xalign">1</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child> <child>
<object class="GtkBox"> <object class="HdyActionRow" id="person_row">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Select a person</property>
<property name="hexpand">True</property> <property name="activatable-widget">person_button</property>
<child>
<object class="GtkButton" id="role_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkLabel" id="role_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Select …</property>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="reset_role_button">
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">user-trash-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="label1">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Type</property>
<property name="justify">right</property>
<property name="xalign">1</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">6</property>
<child>
<object class="GtkLabel" id="label2">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Person</property>
<property name="xalign">1</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child> <child>
<object class="GtkButton" id="person_button"> <object class="GtkButton" id="person_button">
<property name="visible">True</property> <property name="label" translatable="yes">Select</property>
<property name="can-focus">True</property> <property name="valign">center</property>
<property name="receives-default">True</property>
<child>
<object class="GtkLabel" id="person_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Select …</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">person</property>
<property name="title" translatable="yes">Person</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="HdyActionRow" id="ensemble_row">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Select an ensemble</property>
<property name="spacing">6</property> <property name="activatable-widget">ensemble_button</property>
<child>
<object class="GtkLabel" id="label3">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Ensemble</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child> <child>
<object class="GtkButton" id="ensemble_button"> <object class="GtkButton" id="ensemble_button">
<property name="visible">True</property> <property name="label" translatable="yes">Select</property>
<property name="can-focus">True</property> <property name="valign">center</property>
<property name="receives-default">True</property> </object>
</child>
</object>
</child>
<child> <child>
<object class="GtkLabel" id="ensemble_label"> <object class="HdyActionRow" id="role_row">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Select a role</property>
<property name="halign">start</property> <property name="activatable-widget">role_button</property>
<property name="label" translatable="yes">Select …</property> <child>
<object class="GtkButton" id="reset_role_button">
<property name="visible">false</property>
<property name="icon-name">user-trash-symbolic</property>
<property name="valign">center</property>
</object> </object>
</child> </child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="name">ensemble</property>
<property name="title" translatable="yes">Ensemble</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child> <child>
<object class="GtkStackSwitcher"> <object class="GtkButton" id="role_button">
<property name="visible">True</property> <property name="label" translatable="yes">Select</property>
<property name="can-focus">False</property> <property name="valign">center</property>
<property name="hexpand">True</property> </object>
<property name="homogeneous">True</property> </child>
<property name="stack">stack</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<object class="GtkSizeGroup"> </child>
<widgets> </object>
<widget name="label1"/> </child>
<widget name="label2"/>
<widget name="label3"/>
<widget name="label4"/>
</widgets>
</object> </object>
</interface> </interface>

View file

@ -1,212 +1,145 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkStack" id="widget"> <object class="GtkStack" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Person</property> <object class="GtkLabel">
<property name="label" translatable="yes">Person</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="revealed">False</property> <property name="revealed">False</property>
<child>
<placeholder/>
</child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<child> <child>
<!-- n-columns=2 n-rows=3 --> <object class="GtkFrame">
<object class="GtkGrid"> <property name="valign">start</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkListBox">
<property name="visible">True</property> <property name="selection-mode">none</property>
<property name="can-focus">False</property> <child>
<property name="halign">end</property> <object class="HdyActionRow">
<property name="label" translatable="yes">First name</property> <property name="activatable">True</property>
</object> <property name="title" translatable="yes">First name</property>
<packing> <property name="activatable-widget">first_name_entry</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="first_name_entry"> <object class="GtkEntry" id="first_name_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
<packing> </child>
<property name="left-attach">1</property> </object>
<property name="top-attach">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Last name</property>
<property name="halign">end</property> <property name="activatable-widget">last_name_entry</property>
<property name="label" translatable="yes">Last name</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="last_name_entry"> <object class="GtkEntry" id="last_name_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
<packing> </child>
<property name="left-attach">1</property> </object>
<property name="top-attach">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Publish to the server</property>
<property name="halign">end</property> <property name="activatable-widget">upload_switch</property>
<property name="label" translatable="yes">Publish</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child> <child>
<object class="GtkSwitch" id="upload_switch"> <object class="GtkSwitch" id="upload_switch">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="active">True</property> <property name="active">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing> </child>
<property name="name">content</property> </object>
</packing> </child>
</object>
</child>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Person</property> <object class="GtkLabel">
<property name="label" translatable="yes">Person</property>
<style>
<class name="title"/>
</style>
</object>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="spinning">true</property>
<property name="can-focus">False</property> <property name="hexpand">true</property>
<property name="vexpand">True</property> <property name="vexpand">true</property>
<property name="active">True</property> <property name="halign">center</property>
<property name="valign">center</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">loading</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,75 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property>
<child>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">400</property>
<property name="tightening-threshold">300</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search persons …</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scrolled_window">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>

View file

@ -1,132 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar" id="header"> <object class="HdyHeaderBar" id="header">
<property name="visible">True</property> <property name="title-widget">
<property name="can-focus">False</property> <object class="GtkLabel" id="title_label">
<property name="show-close-button">True</property> <property name="label" translatable="yes">Person</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkMenuButton"> <object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="menu-model">menu</property> <property name="menu-model">menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">view-more-symbolic</property> <property name="icon-name">view-more-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_button"> <object class="GtkToggleButton" id="search_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-find-symbolic</property> <property name="icon-name">edit-find-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="HdySearchBar"> <object class="GtkSearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create">False</property> <property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create">False</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">400</property> <property name="maximum-size">400</property>
<property name="hexpand">true</property>
<child> <child>
<object class="GtkSearchEntry" id="search_entry"> <object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search works and recordings …</property> <property name="placeholder-text" translatable="yes">Search works and recordings …</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkSpinner"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
</packing> <property name="child">
<object class="GtkSpinner">
<property name="hexpand">true</property>
<property name="vexpand">true</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="spinning">true</property>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">12</property> <property name="margin-start">12</property>
<property name="margin-end">12</property> <property name="margin-end">12</property>
<property name="margin-top">18</property> <property name="margin-top">18</property>
@ -134,99 +79,43 @@
<property name="maximum-size">800</property> <property name="maximum-size">800</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">18</property> <property name="spacing">18</property>
<child> <child>
<object class="GtkBox" id="work_box"> <object class="GtkBox" id="work_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Works</property> <property name="label" translatable="yes">Works</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkFrame" id="work_frame"> <object class="GtkFrame" id="work_frame">
<property name="visible">True</property> </object>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox" id="recording_box"> <object class="GtkBox" id="recording_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Recordings</property> <property name="label" translatable="yes">Recordings</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkFrame" id="recording_frame"> <object class="GtkFrame" id="recording_frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
@ -235,28 +124,20 @@
</object> </object>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">content</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">nothing</property>
<property name="child">
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">No works or recordings found.</property> <property name="label" translatable="yes">No works or recordings found.</property>
</object> </object>
<packing> </property>
<property name="name">nothing</property> </object>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<menu id="menu"> <menu id="menu">

View file

@ -1,210 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="0.0"/>
<object class="HdyWindow" id="window">
<property name="can-focus">False</property>
<property name="modal">True</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Select person</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkButton" id="add_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search persons …</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="server_check_button">
<property name="label" translatable="yes">Show persons from the Musicus server</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">An error occured!</property>
<attributes>
<attribute name="size" value="16384"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="max-width-chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">error</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View file

@ -1,119 +1,66 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<object class="GtkImage" id="play_image"> <object class="GtkImage" id="play_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-playback-start-symbolic</property> <property name="icon-name">media-playback-start-symbolic</property>
</object> </object>
<object class="GtkRevealer" id="widget"> <object class="GtkRevealer" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">slide-up</property> <property name="transition-type">slide-up</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkSeparator"> <object class="GtkSeparator"/>
<property name="visible">True</property>
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property> <property name="margin-top">6</property>
<property name="can-focus">False</property> <property name="margin-bottom">6</property>
<property name="border-width">6</property> <property name="margin-start">6</property>
<property name="margin-end">6</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="spacing">6</property> <property name="spacing">6</property>
<child> <child>
<object class="GtkButton" id="previous_button"> <object class="GtkButton" id="previous_button">
<property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-skip-backward-symbolic</property> <property name="icon-name">media-skip-backward-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="play_button"> <object class="GtkButton" id="play_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child> <child>
<object class="GtkImage" id="pause_image"> <object class="GtkImage" id="pause_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-playback-pause-symbolic</property> <property name="icon-name">media-playback-pause-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="next_button"> <object class="GtkButton" id="next_button">
<property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-skip-forward-symbolic</property> <property name="icon-name">media-skip-forward-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="hexpand">True</property>
<child> <child>
<object class="GtkLabel" id="title_label"> <object class="GtkLabel" id="title_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Title</property> <property name="label" translatable="yes">Title</property>
<property name="ellipsize">end</property> <property name="ellipsize">end</property>
@ -121,108 +68,47 @@
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel" id="subtitle_label"> <object class="GtkLabel" id="subtitle_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Subtitle</property> <property name="label" translatable="yes">Subtitle</property>
<property name="ellipsize">end</property> <property name="ellipsize">end</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </child>
<property name="expand">True</property> <child>
<property name="fill">True</property> <object class="GtkBox">
<property name="position">1</property> <property name="spacing">2</property>
</packing> <child>
<object class="GtkLabel" id="position_label">
<property name="label" translatable="yes">0:00</property>
</object>
</child>
<child>
<object class="GtkLabel">
<property name="label" translatable="yes">/</property>
</object>
</child>
<child>
<object class="GtkLabel" id="duration_label">
<property name="label" translatable="yes">0:00</property>
</object>
</child>
</object>
</child> </child>
<child> <child>
<object class="GtkButton" id="playlist_button"> <object class="GtkButton" id="playlist_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="valign">center</property> <property name="valign">center</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">view-list-bullet-symbolic</property> <property name="icon-name">view-list-bullet-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">2</property>
<child>
<object class="GtkLabel" id="position_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">0:00</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">/</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="duration_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">0:00</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</child> </child>

View file

@ -1,11 +1,8 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkImage" id="play_image"> <object class="GtkImage" id="play_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-playback-start-symbolic</property> <property name="icon-name">media-playback-start-symbolic</property>
</object> </object>
<object class="GtkAdjustment" id="position"> <object class="GtkAdjustment" id="position">
@ -14,51 +11,34 @@
<property name="page-increment">0.05</property> <property name="page-increment">0.05</property>
</object> </object>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="title-widget">
<property name="can-focus">False</property> <object class="GtkLabel">
<property name="title" translatable="yes">Player</property> <property name="label" translatable="yes">Player</property>
<property name="show-close-button">True</property> <style>
<class name="title"/>
</style>
</object>
</property>
<property name="show-title-buttons">True</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-left">12</property>
<property name="margin-right">12</property>
<property name="margin-start">12</property> <property name="margin-start">12</property>
<property name="margin-end">12</property> <property name="margin-end">12</property>
<property name="margin-top">18</property> <property name="margin-top">18</property>
@ -66,96 +46,55 @@
<property name="maximum-size">800</property> <property name="maximum-size">800</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="spacing">6</property> <property name="spacing">6</property>
<child> <child>
<object class="GtkButton" id="previous_button"> <object class="GtkButton" id="previous_button">
<property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
<property name="receives-default">True</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-skip-backward-symbolic</property> <property name="icon-name">media-skip-backward-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="play_button"> <object class="GtkButton" id="play_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<child> <child>
<object class="GtkImage" id="pause_image"> <object class="GtkImage" id="pause_image">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-playback-pause-symbolic</property> <property name="icon-name">media-playback-pause-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="next_button"> <object class="GtkButton" id="next_button">
<property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-skip-forward-symbolic</property> <property name="icon-name">media-skip-forward-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="hexpand">True</property>
<child> <child>
<object class="GtkLabel" id="title_label"> <object class="GtkLabel" id="title_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Title</property> <property name="label" translatable="yes">Title</property>
<property name="ellipsize">end</property> <property name="ellipsize">end</property>
@ -163,131 +102,52 @@
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel" id="subtitle_label"> <object class="GtkLabel" id="subtitle_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Subtitle</property> <property name="label" translatable="yes">Subtitle</property>
<property name="ellipsize">end</property> <property name="ellipsize">end</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="stop_button"> <object class="GtkButton" id="stop_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="valign">center</property> <property name="valign">center</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">media-playback-stop-symbolic</property> <property name="icon-name">media-playback-stop-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="spacing">6</property> <property name="spacing">6</property>
<child> <child>
<object class="GtkLabel" id="position_label"> <object class="GtkLabel" id="position_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">0:00</property> <property name="label" translatable="yes">0:00</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkScale" id="position_scale"> <object class="GtkScale" id="position_scale">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="events">GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK</property>
<property name="adjustment">position</property> <property name="adjustment">position</property>
<property name="upper-stepper-sensitivity">off</property> <property name="hexpand">True</property>
<property name="round-digits">1</property>
<property name="draw-value">False</property>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel" id="duration_label"> <object class="GtkLabel" id="duration_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">0:00</property> <property name="label" translatable="yes">0:00</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkFrame" id="frame"> <object class="GtkFrame" id="frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
<child type="label_item">
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object> </object>
</child> </child>
</object> </object>
@ -295,11 +155,6 @@
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,57 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdySearchBar"> <object class="GtkSearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property> <property name="search-mode-enabled">True</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">400</property> <property name="maximum-size">400</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<property name="hexpand">true</property>
<child> <child>
<object class="GtkSearchEntry" id="search_entry"> <object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search persons and ensembles …</property> <property name="placeholder-text" translatable="yes">Search persons and ensembles …</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property> <property name="hexpand">True</property>
<property name="can-focus">False</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkSpinner"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
</packing> <property name="child">
<object class="GtkSpinner">
<property name="spinning">True</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkScrolledWindow" id="scrolled_window"> <object class="GtkScrolledWindow" id="scrolled_window">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">True</property> <property name="can-focus">True</property>
@ -59,17 +50,10 @@
<placeholder/> <placeholder/>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">content</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,37 +1,25 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="0.0"/> <requires lib="libhandy" version="1.0"/>
<object class="HdyPreferencesWindow" id="window"> <object class="HdyPreferencesWindow" id="window">
<property name="can-focus">False</property>
<property name="modal">True</property> <property name="modal">True</property>
<property name="default-width">400</property> <property name="default-width">400</property>
<property name="default-height">400</property> <property name="default-height">400</property>
<property name="type-hint">dialog</property>
<child> <child>
<object class="HdyPreferencesPage"> <object class="HdyPreferencesPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">General</property> <property name="title" translatable="yes">General</property>
<child> <child>
<object class="HdyPreferencesGroup"> <object class="HdyPreferencesGroup">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Music library</property> <property name="title" translatable="yes">Music library</property>
<child> <child>
<object class="HdyActionRow" id="music_library_path_row"> <object class="HdyActionRow" id="music_library_path_row">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="selectable">False</property>
<property name="title" translatable="yes">Music library folder</property> <property name="title" translatable="yes">Music library folder</property>
<property name="activatable-widget">select_music_library_path_button</property> <property name="activatable-widget">select_music_library_path_button</property>
<property name="subtitle" translatable="yes">None selected</property> <property name="subtitle" translatable="yes">None selected</property>
<child> <child>
<object class="GtkButton" id="select_music_library_path_button"> <object class="GtkButton" id="select_music_library_path_button">
<property name="label" translatable="yes">Select</property> <property name="label" translatable="yes">Select</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="valign">center</property> <property name="valign">center</property>
</object> </object>
@ -42,22 +30,15 @@
</child> </child>
<child> <child>
<object class="HdyPreferencesGroup"> <object class="HdyPreferencesGroup">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Server connection</property> <property name="title" translatable="yes">Server connection</property>
<child> <child>
<object class="HdyActionRow" id="url_row"> <object class="HdyActionRow" id="url_row">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="selectable">False</property>
<property name="title" translatable="yes">Server URL</property> <property name="title" translatable="yes">Server URL</property>
<property name="activatable-widget">url_button</property> <property name="activatable-widget">url_button</property>
<property name="subtitle" translatable="yes">Not set</property> <property name="subtitle" translatable="yes">Not set</property>
<child> <child>
<object class="GtkButton" id="url_button"> <object class="GtkButton" id="url_button">
<property name="label" translatable="yes">Change</property> <property name="label" translatable="yes">Change</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="valign">center</property> <property name="valign">center</property>
</object> </object>
@ -66,17 +47,12 @@
</child> </child>
<child> <child>
<object class="HdyActionRow" id="login_row"> <object class="HdyActionRow" id="login_row">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="selectable">False</property>
<property name="title" translatable="yes">Login credentials</property> <property name="title" translatable="yes">Login credentials</property>
<property name="activatable-widget">login_button</property> <property name="activatable-widget">login_button</property>
<property name="subtitle" translatable="yes">Not logged in</property> <property name="subtitle" translatable="yes">Not logged in</property>
<child> <child>
<object class="GtkButton" id="login_button"> <object class="GtkButton" id="login_button">
<property name="label" translatable="yes">Change</property> <property name="label" translatable="yes">Change</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="valign">center</property> <property name="valign">center</property>
</object> </object>

View file

@ -1,373 +1,188 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkStack" id="widget"> <object class="GtkStack" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Recording</property> <object class="GtkLabel">
<property name="label" translatable="yes">Recording</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="revealed">False</property> <property name="revealed">False</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can-focus">False</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<placeholder/> <object class="GtkScrolledWindow">
</child> <property name="vexpand">true</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkNotebook">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="show-border">False</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="maximum-size">500</property> <property name="margin-top">18</property>
<property name="tightening-threshold">300</property> <property name="margin-bottom">12</property>
<child> <child>
<!-- n-columns=2 n-rows=3 --> <object class="GtkBox">
<object class="GtkGrid"> <property name="margin-start">6</property>
<property name="visible">True</property> <property name="margin-end">6</property>
<property name="can-focus">False</property> <property name="margin-bottom">6</property>
<property name="border-width">18</property> <property name="orientation">vertical</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="halign">start</property>
<property name="can-focus">False</property> <property name="margin-top">12</property>
<property name="halign">end</property> <property name="margin-bottom">6</property>
<property name="label" translatable="yes">Comment</property> <property name="label" translatable="yes">Overview</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object> </object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child> </child>
<child>
<object class="GtkFrame">
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<child>
<object class="HdyActionRow" id="work_row">
<property name="activatable">True</property>
<property name="title" translatable="yes">Select a work</property>
<property name="activatable-widget">work_button</property>
<child> <child>
<object class="GtkButton" id="work_button"> <object class="GtkButton" id="work_button">
<property name="visible">True</property> <property name="label" translatable="yes">Select</property>
<property name="can-focus">True</property> <property name="valign">center</property>
<property name="receives-default">True</property> </object>
<property name="hexpand">True</property> </child>
</object>
</child>
<child> <child>
<object class="GtkLabel" id="work_label"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Comment</property>
<property name="halign">start</property> <property name="activatable-widget">comment_entry</property>
<property name="label" translatable="yes">Select …</property>
<property name="ellipsize">end</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="comment_entry"> <object class="GtkEntry" id="comment_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property> <property name="hexpand">True</property>
</object>
</child>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Publish to the server</property>
<property name="halign">end</property> <property name="activatable-widget">upload_switch</property>
<property name="label" translatable="yes">Work</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Publish</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child> <child>
<object class="GtkSwitch" id="upload_switch"> <object class="GtkSwitch" id="upload_switch">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="active">True</property> <property name="active">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
<child type="tab"> </object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="margin-top">12</property>
<property name="margin-bottom">6</property>
<child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="halign">start</property>
<property name="can-focus">False</property> <property name="valign">end</property>
<property name="label" translatable="yes">Overview</property> <property name="hexpand">True</property>
<property name="label" translatable="yes">Performers</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object> </object>
<packing>
<property name="tab-fill">False</property>
</packing>
</child> </child>
<child>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="tightening-threshold">300</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">0</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child> <child>
<object class="GtkButton" id="add_performer_button"> <object class="GtkButton" id="add_performer_button">
<property name="visible">True</property> <property name="has-frame">false</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property> <property name="icon-name">list-add-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="edit_performer_button"> <object class="GtkFrame" id="performance_frame"/>
<property name="visible">True</property> </child>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing> </child>
<property name="expand">False</property> </object>
<property name="fill">True</property> </child>
<property name="position">1</property> </object>
</packing> </property>
</child> </object>
<child>
<object class="GtkButton" id="remove_performer_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-remove-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Performers</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab-fill">False</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">content</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Recording</property> <object class="GtkLabel">
<property name="label" translatable="yes">Recording</property>
<style>
<class name="title"/>
</style>
</object>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="hexpand">true</property>
<property name="can-focus">False</property> <property name="vexpand">true</property>
<property name="vexpand">True</property> <property name="halign">center</property>
<property name="active">True</property> <property name="valign">center</property>
<property name="spinning">true</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">loading</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,85 +1,65 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar" id="header"> <object class="HdyHeaderBar" id="header">
<property name="visible">True</property> <property name="title-widget">
<property name="can-focus">False</property> <object class="GtkBox">
<property name="show-close-button">True</property> <property name="orientation">vertical</property>
<property name="valign">center</property>
<child>
<object class="GtkLabel" id="title_label">
<property name="label" translatable="yes">Recording</property>
<style>
<class name="title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="subtitle_label">
<style>
<class name="subtitle"/>
</style>
</object>
</child>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkMenuButton"> <object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="menu-model">menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">view-more-symbolic</property> <property name="icon-name">view-more-symbolic</property>
<property name="menu-model">menu</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkSpinner"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
</packing> <property name="child">
<object class="GtkSpinner">
<property name="spinning">True</property>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">12</property> <property name="margin-start">12</property>
<property name="margin-end">12</property> <property name="margin-end">12</property>
<property name="margin-top">18</property> <property name="margin-top">18</property>
@ -87,77 +67,39 @@
<property name="maximum-size">800</property> <property name="maximum-size">800</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Tracks</property> <property name="label" translatable="yes">Tracks</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkFrame" id="frame"> <object class="GtkFrame" id="frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="add_to_playlist_button"> <object class="GtkButton" id="add_to_playlist_button">
<property name="label" translatable="yes">Add to playlist</property> <property name="label" translatable="yes">Add to playlist</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">end</property> <property name="halign">end</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
</property>
</object>
</child> </child>
</object> </object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<menu id="menu"> <menu id="menu">

View file

@ -1,258 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="empty_screen">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="show-close-button">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Select a composer on the left.</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<object class="HdyLeaflet" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="visible-child">sidebar_box</property>
<child>
<object class="GtkBox" id="sidebar_box">
<property name="width-request">250</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Select a recording</property>
<property name="show-close-button" bind-source="widget" bind-property="folded" bind-flags="sync-create">False</property>
<child>
<object class="GtkButton" id="add_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search composers …</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="server_check_button">
<property name="label" translatable="yes">Show recordings from the server</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hhomogeneous">False</property>
<property name="transition-type">crossfade</property>
<property name="interpolate-size">True</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">An error occured!</property>
<attributes>
<attribute name="size" value="16384"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="max-width-chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">error</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">sidebar</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<style>
<class name="sidebar"/>
</style>
</object>
<packing>
<property name="navigatable">False</property>
</packing>
</child>
</object>
</interface>

View file

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<requires lib="libhandy" version="0.0"/>
<object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar" id="header">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hhomogeneous">False</property>
<property name="transition-type">crossfade</property>
<property name="interpolate-size">True</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">An error occured!</property>
<attributes>
<attribute name="size" value="16384"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="max-width-chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">error</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>

View file

@ -1,264 +1,174 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="width-request">250</property> <property name="width-request">250</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">False</property> <property name="hexpand">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar" id="header"> <object class="HdyHeaderBar" id="header">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<object class="GtkBox">
<property name="orientation">vertical</property>
<property name="valign">center</property>
<child>
<object class="GtkLabel" id="title_label">
<style>
<class name="title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="subtitle_label">
<property name="visible">false</property>
<style>
<class name="subtitle"/>
</style>
</object>
</child>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="add_button"> <object class="GtkButton" id="add_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property> <property name="icon-name">list-add-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="HdySearchBar"> <object class="GtkSearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property> <property name="search-mode-enabled">True</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<property name="hexpand">true</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">6</property> <property name="spacing">6</property>
<child> <child>
<object class="GtkSearchEntry" id="search_entry"> <object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search …</property> <property name="placeholder-text" translatable="yes">Search …</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkCheckButton" id="server_check_button"> <object class="GtkCheckButton" id="server_check_button">
<property name="label" translatable="yes">Use the Musicus server</property> <property name="label" translatable="yes">Use the Musicus server</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="active">True</property> <property name="active">True</property>
<property name="draw-indicator">True</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hhomogeneous">False</property> <property name="hhomogeneous">False</property>
<property name="vhomogeneous">False</property> <property name="vhomogeneous">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<property name="interpolate-size">True</property> <property name="interpolate-size">True</property>
<child> <child>
<object class="GtkSpinner"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-top">12</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
</packing> <property name="child">
<object class="GtkSpinner">
<property name="margin-top">12</property>
<property name="halign">center</property>
<property name="valign">start</property>
<property name="spinning">True</property>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="height-request">200</property> <property name="height-request">200</property>
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<child> <child>
<object class="GtkFrame" id="frame"> <object class="GtkFrame" id="frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="valign">start</property> <property name="valign">start</property>
<property name="margin-start">6</property> <property name="margin-start">6</property>
<property name="margin-end">6</property> <property name="margin-end">6</property>
<property name="margin-top">12</property> <property name="margin-top">12</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
<child type="label_item">
<placeholder/>
</child>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
</child> </property>
</object> </object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">error</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="border-width">18</property> <property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">18</property> <property name="spacing">18</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="pixel-size">80</property> <property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property> <property name="icon-name">network-error-symbolic</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="label" translatable="yes">An error occured!</property> <property name="label" translatable="yes">An error occured!</property>
<attributes> <attributes>
<attribute name="size" value="16384"/> <attribute name="size" value="16384"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property> <property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property> <property name="justify">center</property>
<property name="wrap">True</property> <property name="wrap">True</property>
<property name="max-width-chars">40</property> <property name="max-width-chars">40</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="try_again_button"> <object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property> <property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property> <property name="halign">center</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">error</property> </object>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,94 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="0.0"/> <requires lib="libhandy" version="1.0"/>
<object class="HdyWindow" id="window"> <object class="HdyWindow" id="window">
<property name="can-focus">False</property>
<property name="modal">True</property> <property name="modal">True</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Server</property> <object class="GtkLabel">
<property name="label" translatable="yes">Server</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="cancel_button"> <object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">Cancel</property> <property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
</object> </object>
</child> </child>
<child> <child type="end">
<object class="GtkButton" id="set_button"> <object class="GtkButton" id="set_button">
<property name="label" translatable="yes">Set</property> <property name="label" translatable="yes">Set</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="can-default">True</property>
<property name="has-default">True</property> <property name="has-default">True</property>
<property name="receives-default">True</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<!-- n-columns=2 n-rows=1 --> <object class="GtkListBox">
<object class="GtkGrid"> <property name="selection-mode">none</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">URL</property>
<property name="halign">end</property> <property name="activatable-widget">url_entry</property>
<property name="label" translatable="yes">URL</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="url_entry"> <object class="GtkEntry" id="url_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="has-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
<property name="activates-default">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child> </child>
</object> </object>
<packing> </child>
<property name="expand">False</property> </object>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</child> </child>

View file

@ -1,25 +1,24 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Import music</property> <object class="GtkLabel">
<property name="label" translatable="yes">Import music</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
@ -29,131 +28,90 @@
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">start</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="message-type">error</property> <property name="message-type">error</property>
<property name="revealed">False</property> <property name="revealed">False</property>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can-focus">False</property>
<property name="spacing">16</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Failed to load the CD. Make sure you have inserted it into your drive.</property> <property name="label" translatable="yes">Failed to load the CD. Make sure you have inserted it into your drive.</property>
<property name="wrap">True</property> <property name="wrap">True</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object>
</child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="vexpand">True</property> <property name="vexpand">True</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="border-width">18</property> <property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">18</property> <property name="spacing">18</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property> <property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property> <property name="pixel-size">80</property>
<property name="icon-name">media-optical-cd-audio-symbolic</property> <property name="icon-name">media-optical-cd-audio-symbolic</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property> <property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">Import from audio CD</property> <property name="label" translatable="yes">Import from audio CD</property>
<attributes> <attributes>
<attribute name="size" value="16384"/> <attribute name="size" value="16384"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property> <property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">Insert an audio compact disc into your drive and click the button below. The disc will be copied in the background while you set up the metadata.</property> <property name="label" translatable="yes">Insert an audio compact disc into your drive and click the button below. The disc will be copied in the background while you set up the metadata.</property>
<property name="justify">center</property> <property name="justify">center</property>
<property name="wrap">True</property> <property name="wrap">True</property>
<property name="max-width-chars">40</property> <property name="max-width-chars">40</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="import_button"> <object class="GtkButton" id="import_button">
<property name="label" translatable="yes">Import</property> <property name="label" translatable="yes">Import</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="halign">center</property> <property name="halign">center</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">start</property> </object>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
<property name="position">1</property> <property name="child">
</packing> <object class="GtkSpinner">
<property name="spinning">True</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="hexpand">true</property>
<property name="vexpand">true</property>
</object>
</property>
</object>
</child> </child>
</object> </object>
</child> </child>

View file

@ -1,69 +1,47 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="title" translatable="yes">Track</property> <property name="title-widget">
<object class="GtkLabel">
<property name="label" translatable="yes">Track</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="select_button"> <object class="GtkButton" id="select_button">
<property name="visible">True</property> <property name="icon-name">object-select-symbolic</property>
<property name="can-focus">True</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">object-select-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="vexpand">True</property> <property name="vexpand">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<child> <child>
<object class="GtkFrame" id="parts_frame"> <object class="GtkFrame" id="parts_frame">
<property name="visible">True</property>
<property name="valign">start</property> <property name="valign">start</property>
<property name="margin-top">12</property> <property name="margin-top">12</property>
<property name="margin-start">6</property> <property name="margin-start">6</property>
<property name="margin-end">6</property> <property name="margin-end">6</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
<property name="shadow-type">in</property>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>

View file

@ -1,70 +1,48 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="title" translatable="yes">Select tracks</property> <property name="title-widget">
<object class="GtkLabel">
<property name="label" translatable="yes">Select tracks</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="select_button"> <object class="GtkButton" id="select_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="icon-name">object-select-symbolic</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">object-select-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="vexpand">True</property> <property name="vexpand">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<child> <child>
<object class="GtkFrame" id="tracks_frame"> <object class="GtkFrame" id="tracks_frame">
<property name="visible">True</property>
<property name="valign">start</property> <property name="valign">start</property>
<property name="margin-top">12</property> <property name="margin-top">12</property>
<property name="margin-start">6</property> <property name="margin-start">6</property>
<property name="margin-end">6</property> <property name="margin-end">6</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
<property name="shadow-type">in</property>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>

View file

@ -1,69 +1,49 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="title" translatable="yes">Tracks</property> <property name="title-widget">
<object class="GtkLabel">
<property name="label" translatable="yes">Import music</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property> <property name="icon-name">object-select-symbolic</property>
<property name="can-focus">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">object-select-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
</packing>
</child>
</object>
</child> </child>
<child> <child>
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="vexpand">True</property> <property name="vexpand">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="margin-start">6</property> <property name="margin-start">6</property>
<property name="margin-end">6</property> <property name="margin-end">6</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="margin-top">12</property> <property name="margin-top">12</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
@ -75,24 +55,17 @@
</child> </child>
<child> <child>
<object class="GtkFrame"> <object class="GtkFrame">
<property name="visible">True</property>
<property name="shadow-type">in</property>
<child> <child>
<object class="GtkListBox"> <object class="GtkListBox">
<property name="visible">True</property>
<property name="selection-mode">none</property> <property name="selection-mode">none</property>
<child> <child>
<object class="HdyActionRow" id="recording_row"> <object class="HdyActionRow" id="recording_row">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="activatable">True</property> <property name="activatable">True</property>
<property name="title" translatable="yes">Select a recording</property> <property name="title" translatable="yes">Select a recording</property>
<property name="activatable-widget">select_recording_button</property> <property name="activatable-widget">select_recording_button</property>
<child> <child>
<object class="GtkButton" id="select_recording_button"> <object class="GtkButton" id="select_recording_button">
<property name="label" translatable="yes">Select</property> <property name="label" translatable="yes">Select</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="valign">center</property> <property name="valign">center</property>
</object> </object>
</child> </child>
@ -104,13 +77,11 @@
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="orientation">horizontal</property> <property name="orientation">horizontal</property>
<property name="margin-top">12</property> <property name="margin-top">12</property>
<property name="margin-bottom">6</property> <property name="margin-bottom">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="valign">end</property> <property name="valign">end</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
@ -122,26 +93,14 @@
</child> </child>
<child> <child>
<object class="GtkButton" id="edit_tracks_button"> <object class="GtkButton" id="edit_tracks_button">
<property name="visible">True</property> <property name="has-frame">false</property>
<property name="can-focus">True</property>
<property name="relief">none</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="icon-name">document-edit-symbolic</property> <property name="icon-name">document-edit-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object>
</child>
<child> <child>
<object class="GtkFrame" id="tracks_frame"> <object class="GtkFrame" id="tracks_frame"/>
<property name="visible">True</property>
<property name="shadow-type">in</property>
</object>
</child>
</object>
</child> </child>
</object> </object>
</child> </child>

View file

@ -1,326 +1,224 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22" /> <requires lib="gtk" version="4.0" />
<requires lib="libhandy" version="1.0" /> <requires lib="libhandy" version="1.0" />
<object class="GtkBox" id="empty_screen"> <object class="GtkBox" id="empty_screen">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
<property name="show-close-button">True</property> <property name="show-title-buttons">True</property>
<property name="title-widget">
<object class="GtkLabel"/>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property> <property name="vexpand">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="border-width">18</property> <property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">18</property> <property name="spacing">18</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="pixel-size">80</property> <property name="pixel-size">80</property>
<property name="icon-name">folder-music-symbolic</property> <property name="icon-name">folder-music-symbolic</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="label" translatable="yes">Welcome to Musicus!</property> <property name="label" translatable="yes">Welcome to Musicus!</property>
<attributes> <attributes>
<attribute name="size" value="16384" /> <attribute name="size" value="16384" />
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5</property> <property name="opacity">0.5</property>
<property name="label" translatable="yes">Get startet by selecting something from the sidebar or adding new things to your library using the button in the top left corner.</property> <property name="label" translatable="yes">Get startet by selecting something from the sidebar or adding new things to your library using the button in the top left corner.</property>
<property name="justify">center</property> <property name="justify">center</property>
<property name="wrap">True</property> <property name="wrap">True</property>
<property name="max-width-chars">40</property> <property name="max-width-chars">40</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<object class="HdyApplicationWindow" id="window"> <object class="HdyApplicationWindow" id="window">
<property name="can-focus">False</property>
<property name="default-width">800</property> <property name="default-width">800</property>
<property name="default-height">566</property> <property name="default-height">566</property>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="transition-type">crossfade</property> <property name="transition-type">crossfade</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">empty</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="title-widget">
<property name="can-focus">False</property> <object class="GtkLabel">
<property name="title" translatable="yes">Musicus</property> <property name="label">Musicus</property>
<property name="show-close-button">True</property> <style>
<class name="title"/>
</style>
</object>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property> <property name="vexpand">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property> <property name="halign">center</property>
<property name="valign">center</property> <property name="valign">center</property>
<property name="border-width">18</property> <property name="margin-top">18</property>
<property name="margin-bottom">18</property>
<property name="margin-start">18</property>
<property name="margin-end">18</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">18</property> <property name="spacing">18</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property> <property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property> <property name="pixel-size">80</property>
<property name="icon-name">folder-music-symbolic</property> <property name="icon-name">folder-music-symbolic</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property> <property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">Welcome to Musicus!</property> <property name="label" translatable="yes">Welcome to Musicus!</property>
<attributes> <attributes>
<attribute name="size" value="16384" /> <attribute name="size" value="16384" />
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property> <property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">Get startet by selecting the folder containing your music files! Musicus will create a new database there or open one that already exists.</property> <property name="label" translatable="yes">Get startet by selecting the folder containing your music files! Musicus will create a new database there or open one that already exists.</property>
<property name="justify">center</property> <property name="justify">center</property>
<property name="wrap">True</property> <property name="wrap">True</property>
<property name="max-width-chars">40</property> <property name="max-width-chars">40</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="select_music_library_path_button"> <object class="GtkButton" id="select_music_library_path_button">
<property name="label" translatable="yes">Select folder</property> <property name="label" translatable="yes">Select folder</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="halign">center</property> <property name="halign">center</property>
<style> <style>
<class name="suggested-action" /> <class name="suggested-action" />
</style> </style>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">empty</property> </object>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="show-close-button">True</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="spinning">True</property>
<property name="can-focus">False</property> <property name="vexpand">True</property>
<property name="active">True</property> <property name="hexpand">True</property>
<property name="valign">center</property>
<property name="halign">center</property>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">loading</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox" id="content_box"> <object class="GtkBox" id="content_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyLeaflet" id="leaflet"> <object class="HdyLeaflet" id="leaflet">
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">False</property>
<child> <child>
<object class="HdyLeafletPage">
<property name="child">
<object class="GtkBox" id="sidebar_box"> <object class="GtkBox" id="sidebar_box">
<property name="width-request">250</property> <property name="width-request">250</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">False</property> <property name="hexpand">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">False</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Musicus</property> <object class="GtkLabel">
<property name="label">Musicus</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="add_button"> <object class="GtkButton" id="add_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<child> <child>
<object class="GtkImage"> <object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property> <property name="icon-name">list-add-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
<child> <child type="end">
<object class="GtkMenuButton"> <object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property> <property name="receives-default">True</property>
<property name="menu-model">menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">open-menu-symbolic</property> <property name="icon-name">open-menu-symbolic</property>
<property name="menu-model">menu</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
</object> </object>
<packing>
<property name="name">sidebar</property>
</packing>
</child> </child>
<child> <child>
<object class="HdyLeafletPage">
<property name="navigatable">False</property>
<property name="child">
<object class="GtkSeparator"> <object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<style> <style>
<class name="sidebar" /> <class name="sidebar" />
</style> </style>
</object> </object>
<packing> </property>
<property name="navigatable">False</property> </object>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">content</property> </object>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
</child> </child>

View file

@ -1,529 +1,223 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkStack" id="widget"> <object class="GtkStack" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property> <property name="visible">True</property>
<property name="can-focus">False</property> <property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Work</property> <object class="GtkLabel">
<property name="label" translatable="yes">Work</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="sensitive">False</property> <property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkInfoBar" id="info_bar"> <object class="GtkInfoBar" id="info_bar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="revealed">False</property> <property name="revealed">False</property>
<child internal-child="action_area">
<object class="GtkButtonBox">
<property name="can-focus">False</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child>
<child internal-child="content_area">
<object class="GtkBox">
<property name="can-focus">False</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">False</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<placeholder/> <object class="GtkScrolledWindow">
</child> <property name="vexpand">true</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkNotebook">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="show-border">False</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="maximum-size">500</property> <property name="margin-top">18</property>
<property name="tightening-threshold">300</property> <property name="margin-bottom">12</property>
<child> <child>
<!-- n-columns=2 n-rows=3 --> <object class="GtkBox">
<object class="GtkGrid"> <property name="margin-start">6</property>
<property name="visible">True</property> <property name="margin-end">6</property>
<property name="can-focus">False</property> <property name="margin-bottom">6</property>
<property name="border-width">18</property> <property name="orientation">vertical</property>
<property name="row-spacing">12</property> <child>
<property name="column-spacing">6</property> <object class="GtkLabel">
<property name="halign">start</property>
<property name="margin-top">12</property>
<property name="margin-bottom">6</property>
<property name="label" translatable="yes">Overview</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object>
</child>
<child>
<object class="GtkFrame">
<child>
<object class="GtkListBox">
<property name="selection-mode">none</property>
<child>
<object class="HdyActionRow" id="composer_row">
<property name="activatable">True</property>
<property name="title" translatable="yes">Select a composer</property>
<property name="activatable-widget">composer_button</property>
<child> <child>
<object class="GtkButton" id="composer_button"> <object class="GtkButton" id="composer_button">
<property name="visible">True</property> <property name="label" translatable="yes">Select</property>
<property name="can-focus">True</property> <property name="valign">center</property>
<property name="receives-default">True</property>
<property name="hexpand">True</property>
<child>
<object class="GtkLabel" id="composer_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Select …</property>
<property name="ellipsize">end</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Title</property>
<property name="halign">end</property> <property name="activatable-widget">title_entry</property>
<property name="label" translatable="yes">Composer</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="title_entry"> <object class="GtkEntry" id="title_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property> <property name="hexpand">True</property>
</object>
</child>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkLabel" id="composer_labe"> <object class="HdyActionRow">
<property name="visible">True</property> <property name="activatable">True</property>
<property name="can-focus">False</property> <property name="title" translatable="yes">Publish to the server</property>
<property name="halign">end</property> <property name="activatable-widget">upload_switch</property>
<property name="label" translatable="yes">Title</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Publish</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child> <child>
<object class="GtkSwitch" id="upload_switch"> <object class="GtkSwitch" id="upload_switch">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="halign">start</property>
<property name="active">True</property> <property name="active">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
<child type="tab"> </object>
</child>
<child>
<object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="margin-top">12</property>
<property name="margin-bottom">6</property>
<child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="halign">start</property>
<property name="can-focus">False</property> <property name="valign">end</property>
<property name="label" translatable="yes">Overview</property> <property name="hexpand">True</property>
<property name="label" translatable="yes">Instruments</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object> </object>
<packing>
<property name="tab-fill">False</property>
</packing>
</child> </child>
<child>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">800</property>
<property name="tightening-threshold">300</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow" id="instruments_scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">0</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child> <child>
<object class="GtkButton" id="add_instrument_button"> <object class="GtkButton" id="add_instrument_button">
<property name="visible">True</property> <property name="has-frame">false</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property> <property name="icon-name">list-add-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="remove_instrument_button"> <object class="GtkFrame" id="instrument_frame"/>
<property name="visible">True</property> </child>
<property name="can-focus">True</property> <child>
<property name="receives-default">True</property> <object class="GtkBox">
<property name="orientation">horizontal</property>
<property name="margin-top">12</property>
<property name="margin-bottom">6</property>
<child> <child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-remove-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property> <property name="halign">start</property>
<property name="can-focus">False</property> <property name="valign">end</property>
<property name="label" translatable="yes">Instruments</property> <property name="hexpand">True</property>
<property name="label" translatable="yes">Structure</property>
<attributes>
<attribute name="weight" value="bold"/>
</attributes>
</object> </object>
<packing>
<property name="position">1</property>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">800</property>
<property name="tightening-threshold">300</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow" id="structure_scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="add_part_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="add_section_button"> <object class="GtkButton" id="add_section_button">
<property name="visible">True</property> <property name="has-frame">false</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">folder-new-symbolic</property> <property name="icon-name">folder-new-symbolic</property>
</object> </object>
</child> </child>
<child>
<object class="GtkButton" id="add_part_button">
<property name="has-frame">false</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkButton" id="edit_part_button"> <object class="GtkFrame" id="structure_frame"/>
<property name="visible">True</property> </child>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing> </child>
<property name="expand">False</property> </object>
<property name="fill">True</property> </child>
<property name="position">2</property> </object>
</packing> </property>
</child> </object>
<child>
<object class="GtkButton" id="remove_part_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-remove-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
<child>
<object class="GtkButton" id="move_part_down_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-down-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">4</property>
</packing>
</child>
<child>
<object class="GtkButton" id="move_part_up_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-up-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="pack-type">end</property>
<property name="position">5</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="position">2</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Structure</property>
</object>
<packing>
<property name="position">2</property>
<property name="tab-fill">False</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">content</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">loading</property>
<property name="child">
<object class="GtkBox"> <object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Work</property> <object class="GtkLabel">
<property name="label" translatable="yes">Work</property>
<style>
<class name="title"/>
</style>
</object>
</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkSpinner"> <object class="GtkSpinner">
<property name="visible">True</property> <property name="hexpand">true</property>
<property name="can-focus">False</property> <property name="vexpand">true</property>
<property name="vexpand">True</property> <property name="halign">center</property>
<property name="active">True</property> <property name="valign">center</property>
<property name="spinning">True</property>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">loading</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,169 +1,97 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Work part</property> <object class="GtkLabel">
<property name="label" translatable="yes">Work part</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="revealed">False</property>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<child> <child>
<!-- n-columns=2 n-rows=2 --> <object class="GtkFrame">
<object class="GtkGrid"> <property name="valign">start</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkListBox">
<property name="visible">True</property> <property name="selection-mode">none</property>
<property name="can-focus">False</property> <child>
<property name="halign">end</property> <object class="HdyActionRow">
<property name="label" translatable="yes">Composer</property> <property name="activatable">True</property>
</object> <property name="title" translatable="yes">Title</property>
<packing> <property name="activatable-widget">title_entry</property>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="title_entry"> <object class="GtkEntry" id="title_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel" id="composer_labe">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Title</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<child>
<object class="GtkButton" id="composer_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="hexpand">True</property>
<child>
<object class="GtkLabel" id="composer_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Select …</property>
</object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child>
<object class="HdyActionRow" id="composer_row">
<property name="activatable">True</property>
<property name="title" translatable="yes">Select a composer</property>
<property name="activatable-widget">composer_button</property>
<child> <child>
<object class="GtkButton" id="reset_composer_button"> <object class="GtkButton" id="reset_composer_button">
<property name="can-focus">True</property> <property name="visible">false</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">user-trash-symbolic</property> <property name="icon-name">user-trash-symbolic</property>
<property name="valign">center</property>
</object>
</child>
<child>
<object class="GtkButton" id="composer_button">
<property name="label" translatable="yes">Select</property>
<property name="valign">center</property>
</object>
</child>
</object>
</child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<style>
<class name="linked"/>
</style>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,132 +1,86 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.24"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar" id="header"> <object class="HdyHeaderBar" id="header">
<property name="visible">True</property> <property name="title-widget">
<property name="can-focus">False</property> <object class="GtkBox">
<property name="show-close-button">True</property> <property name="orientation">vertical</property>
<property name="valign">center</property>
<child>
<object class="GtkLabel" id="title_label">
<property name="label" translatable="yes">Work</property>
<style>
<class name="title"/>
</style>
</object>
</child>
<child>
<object class="GtkLabel" id="subtitle_label">
<style>
<class name="subtitle"/>
</style>
</object>
</child>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkMenuButton"> <object class="GtkMenuButton">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="focus-on-click">False</property>
<property name="receives-default">True</property>
<property name="menu-model">menu</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">view-more-symbolic</property> <property name="icon-name">view-more-symbolic</property>
<property name="menu-model">menu</property>
</object> </object>
</child> </child>
</object> <child type="end">
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkToggleButton" id="search_button"> <object class="GtkToggleButton" id="search_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-find-symbolic</property> <property name="icon-name">edit-find-symbolic</property>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="HdySearchBar"> <object class="GtkSearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create">False</property> <property name="search-mode-enabled" bind-source="search_button" bind-property="active" bind-flags="bidirectional|sync-create">False</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="maximum-size">400</property> <property name="maximum-size">400</property>
<property name="hexpand">true</property>
<child> <child>
<object class="GtkSearchEntry" id="search_entry"> <object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search recordings …</property> <property name="placeholder-text" translatable="yes">Search recordings …</property>
</object> </object>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStack" id="stack"> <object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child> <child>
<object class="GtkSpinner"> <object class="GtkStackPage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property> <property name="name">loading</property>
</packing> <property name="child">
<object class="GtkSpinner">
<property name="spinning">True</property>
</object>
</property>
</object>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">content</property>
<property name="child">
<object class="GtkScrolledWindow"> <object class="GtkScrolledWindow">
<property name="visible">True</property> <property name="vexpand">true</property>
<property name="can-focus">True</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="shadow-type">none</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="margin-start">12</property> <property name="margin-start">12</property>
<property name="margin-end">12</property> <property name="margin-end">12</property>
<property name="margin-top">18</property> <property name="margin-top">18</property>
@ -134,42 +88,19 @@
<property name="maximum-size">800</property> <property name="maximum-size">800</property>
<child> <child>
<object class="GtkBox" id="recording_box"> <object class="GtkBox" id="recording_box">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<property name="spacing">12</property> <property name="spacing">12</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property> <property name="halign">start</property>
<property name="label" translatable="yes">Recordings</property> <property name="label" translatable="yes">Recordings</property>
<attributes> <attributes>
<attribute name="weight" value="bold"/> <attribute name="weight" value="bold"/>
</attributes> </attributes>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkFrame" id="recording_frame"> <object class="GtkFrame" id="recording_frame">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label-xalign">0</property>
<property name="shadow-type">in</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object> </object>
</child> </child>
</object> </object>
@ -177,28 +108,20 @@
</object> </object>
</child> </child>
</object> </object>
<packing> </property>
<property name="name">content</property> </object>
<property name="position">1</property>
</packing>
</child> </child>
<child> <child>
<object class="GtkStackPage">
<property name="name">nothing</property>
<property name="child">
<object class="GtkLabel"> <object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">No recordings found.</property> <property name="label" translatable="yes">No recordings found.</property>
</object> </object>
<packing> </property>
<property name="name">nothing</property> </object>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child> </child>
</object> </object>
<menu id="menu"> <menu id="menu">

View file

@ -1,104 +1,77 @@
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface> <interface>
<requires lib="gtk+" version="3.22"/> <requires lib="gtk" version="4.0"/>
<requires lib="libhandy" version="1.0"/> <requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="widget"> <object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property> <property name="orientation">vertical</property>
<child> <child>
<object class="HdyHeaderBar"> <object class="HdyHeaderBar">
<property name="visible">True</property> <property name="show-title-buttons">false</property>
<property name="can-focus">False</property> <property name="title-widget">
<property name="title" translatable="yes">Work section</property> <object class="GtkLabel">
<property name="label" translatable="yes">Work section</property>
<style>
<class name="title"/>
</style>
</object>
</property>
<child> <child>
<object class="GtkButton" id="back_button"> <object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property> <property name="icon-name">go-previous-symbolic</property>
</object> </object>
</child> </child>
</object> <child type="end">
</child>
<child>
<object class="GtkButton" id="save_button"> <object class="GtkButton" id="save_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">object-select-symbolic</property> <property name="icon-name">object-select-symbolic</property>
</object>
</child>
<style> <style>
<class name="suggested-action"/> <class name="suggested-action"/>
</style> </style>
</object> </object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child> </child>
</object> </object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child> </child>
<child>
<object class="GtkInfoBar" id="info_bar">
<property name="revealed">False</property>
</object>
</child>
<child>
<object class="GtkScrolledWindow">
<property name="vexpand">true</property>
<child> <child>
<object class="HdyClamp"> <object class="HdyClamp">
<property name="visible">True</property> <property name="margin-start">12</property>
<property name="can-focus">False</property> <property name="margin-end">12</property>
<property name="margin-top">18</property>
<property name="margin-bottom">12</property>
<property name="maximum-size">500</property> <property name="maximum-size">500</property>
<property name="tightening-threshold">300</property> <property name="tightening-threshold">300</property>
<child> <child>
<!-- n-columns=2 n-rows=1 --> <object class="GtkFrame">
<object class="GtkGrid"> <property name="valign">start</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child> <child>
<object class="GtkLabel"> <object class="GtkListBox">
<property name="visible">True</property> <property name="selection-mode">none</property>
<property name="can-focus">False</property> <child>
<property name="halign">end</property> <object class="HdyActionRow">
<property name="label" translatable="yes">Title</property> <property name="activatable">True</property>
</object> <property name="title" translatable="yes">Title</property>
<packing> <property name="activatable-widget">title_entry</property>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child> <child>
<object class="GtkEntry" id="title_entry"> <object class="GtkEntry" id="title_entry">
<property name="visible">True</property> <property name="valign">center</property>
<property name="can-focus">True</property>
<property name="hexpand">True</property> <property name="hexpand">True</property>
</object> </object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
</packing>
</child> </child>
</object> </object>
</child> </child>
</object> </object>
<packing> </child>
<property name="expand">False</property> </object>
<property name="fill">True</property> </child>
<property name="position">1</property> </object>
</packing> </child>
</object>
</child> </child>
</object> </object>
</interface> </interface>

View file

@ -1,275 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<requires lib="libhandy" version="1.0"/>
<object class="GtkBox" id="empty_screen">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="show-close-button">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Select a composer on the left.</property>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<object class="HdyLeaflet" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="visible-child">sidebar_box</property>
<child>
<object class="GtkBox" id="sidebar_box">
<property name="width-request">250</property>
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Select a work</property>
<child>
<object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
<child>
<object class="GtkButton" id="add_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">list-add-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="HdySearchBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="search-mode-enabled">True</property>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkSearchEntry" id="search_entry">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="primary-icon-name">edit-find-symbolic</property>
<property name="primary-icon-activatable">False</property>
<property name="primary-icon-sensitive">False</property>
<property name="placeholder-text" translatable="yes">Search composers …</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkCheckButton" id="server_check_button">
<property name="label" translatable="yes">Show works from the server</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">False</property>
<property name="active">True</property>
<property name="draw-indicator">True</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hhomogeneous">False</property>
<property name="transition-type">crossfade</property>
<property name="interpolate-size">True</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">An error occured!</property>
<attributes>
<attribute name="size" value="16384"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="max-width-chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">error</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="name">sidebar</property>
</packing>
</child>
<child>
<object class="GtkSeparator">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<style>
<class name="sidebar"/>
</style>
</object>
<packing>
<property name="navigatable">False</property>
</packing>
</child>
</object>
</interface>

View file

@ -1,153 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.24"/>
<requires lib="libhandy" version="0.0"/>
<object class="GtkBox" id="widget">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="orientation">vertical</property>
<child>
<object class="HdyHeaderBar" id="header">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="show-close-button">True</property>
<child>
<object class="GtkButton" id="back_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">go-previous-symbolic</property>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkStack" id="stack">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hhomogeneous">False</property>
<property name="transition-type">crossfade</property>
<property name="interpolate-size">True</property>
<child>
<object class="GtkSpinner">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="active">True</property>
</object>
<packing>
<property name="name">loading</property>
</packing>
</child>
<child>
<object class="GtkScrolledWindow" id="scroll">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<placeholder/>
</child>
</object>
<packing>
<property name="name">content</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">center</property>
<property name="valign">center</property>
<property name="border-width">18</property>
<property name="orientation">vertical</property>
<property name="spacing">18</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="pixel-size">80</property>
<property name="icon-name">network-error-symbolic</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">An error occured!</property>
<attributes>
<attribute name="size" value="16384"/>
</attributes>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="opacity">0.5019607843137255</property>
<property name="label" translatable="yes">The server was not reachable or responded with an error. Please check your internet connection.</property>
<property name="justify">center</property>
<property name="wrap">True</property>
<property name="max-width-chars">40</property>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="try_again_button">
<property name="label" translatable="yes">Try again</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="halign">center</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">3</property>
</packing>
</child>
</object>
<packing>
<property name="name">error</property>
<property name="position">2</property>
</packing>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
</interface>

View file

@ -17,6 +17,5 @@ pub fn show_about_dialog<W: IsA<gtk::Window>>(parent: &W) {
.authors(vec![String::from("Elias Projahn <johrpan@gmail.com>")]) .authors(vec![String::from("Elias Projahn <johrpan@gmail.com>")])
.build(); .build();
dialog.connect_response(|dialog, _| dialog.close());
dialog.show(); dialog.show();
} }

View file

@ -52,8 +52,8 @@ impl LoginDialog {
this.stack.set_visible_child_name("loading"); this.stack.set_visible_child_name("loading");
let data = LoginData { let data = LoginData {
username: this.username_entry.get_text().to_string(), username: this.username_entry.get_text().unwrap().to_string(),
password: this.password_entry.get_text().to_string(), password: this.password_entry.get_text().unwrap().to_string(),
}; };
let c = glib::MainContext::default(); let c = glib::MainContext::default();

View file

@ -43,12 +43,19 @@ impl Preferences {
// Connect signals and callbacks // Connect signals and callbacks
select_music_library_path_button.connect_clicked(clone!(@strong this => move |_| { select_music_library_path_button.connect_clicked(clone!(@strong this => move |_| {
let dialog = gtk::FileChooserNative::new( let dialog = gtk::FileChooserDialog::new(
Some(&gettext("Select music library folder")), Some(&gettext("Select music library folder")),
Some(&this.window), gtk::FileChooserAction::SelectFolder,None, None); Some(&this.window),
gtk::FileChooserAction::SelectFolder,
&[
(&gettext("Cancel"), gtk::ResponseType::Cancel),
(&gettext("Select"), gtk::ResponseType::Accept),
]);
if let gtk::ResponseType::Accept = dialog.run() { dialog.connect_response(clone!(@strong this => move |dialog, response| {
if let Some(path) = dialog.get_filename() { if let gtk::ResponseType::Accept = response {
if let Some(file) = dialog.get_file() {
if let Some(path) = file.get_path() {
this.music_library_path_row.set_subtitle(Some(path.to_str().unwrap())); this.music_library_path_row.set_subtitle(Some(path.to_str().unwrap()));
let context = glib::MainContext::default(); let context = glib::MainContext::default();
@ -58,6 +65,10 @@ impl Preferences {
}); });
} }
} }
}
}));
dialog.show();
})); }));
url_button.connect_clicked(clone!(@strong this => move |_| { url_button.connect_clicked(clone!(@strong this => move |_| {

View file

@ -40,7 +40,7 @@ impl ServerDialog {
})); }));
set_button.connect_clicked(clone!(@strong this => move |_| { set_button.connect_clicked(clone!(@strong this => move |_| {
let url = this.url_entry.get_text().to_string(); let url = this.url_entry.get_text().unwrap().to_string();
this.backend.set_server_url(&url).unwrap(); this.backend.set_server_url(&url).unwrap();
if let Some(cb) = &*this.selected_cb.borrow() { if let Some(cb) = &*this.selected_cb.borrow() {

View file

@ -94,7 +94,7 @@ impl EnsembleEditor {
/// Save the ensemble and possibly upload it to the server. /// Save the ensemble and possibly upload it to the server.
async fn save(self: Rc<Self>) -> Result<()> { async fn save(self: Rc<Self>) -> Result<()> {
let name = self.name_entry.get_text().to_string(); let name = self.name_entry.get_text().unwrap().to_string();
let ensemble = Ensemble { let ensemble = Ensemble {
id: self.id.clone(), id: self.id.clone(),

View file

@ -94,7 +94,7 @@ impl InstrumentEditor {
/// Save the instrument and possibly upload it to the server. /// Save the instrument and possibly upload it to the server.
async fn save(self: Rc<Self>) -> Result<()> { async fn save(self: Rc<Self>) -> Result<()> {
let name = self.name_entry.get_text().to_string(); let name = self.name_entry.get_text().unwrap().to_string();
let instrument = Instrument { let instrument = Instrument {
id: self.id.clone(), id: self.id.clone(),

View file

@ -6,6 +6,7 @@ use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -14,9 +15,9 @@ pub struct PerformanceEditor {
backend: Rc<Backend>, backend: Rc<Backend>,
widget: gtk::Box, widget: gtk::Box,
save_button: gtk::Button, save_button: gtk::Button,
person_label: gtk::Label, person_row: libhandy::ActionRow,
ensemble_label: gtk::Label, ensemble_row: libhandy::ActionRow,
role_label: gtk::Label, role_row: libhandy::ActionRow,
reset_role_button: gtk::Button, reset_role_button: gtk::Button,
person: RefCell<Option<Person>>, person: RefCell<Option<Person>>,
ensemble: RefCell<Option<Ensemble>>, ensemble: RefCell<Option<Ensemble>>,
@ -39,17 +40,17 @@ impl PerformanceEditor {
get_widget!(builder, gtk::Button, ensemble_button); get_widget!(builder, gtk::Button, ensemble_button);
get_widget!(builder, gtk::Button, role_button); get_widget!(builder, gtk::Button, role_button);
get_widget!(builder, gtk::Button, reset_role_button); get_widget!(builder, gtk::Button, reset_role_button);
get_widget!(builder, gtk::Label, person_label); get_widget!(builder, libhandy::ActionRow, person_row);
get_widget!(builder, gtk::Label, ensemble_label); get_widget!(builder, libhandy::ActionRow, ensemble_row);
get_widget!(builder, gtk::Label, role_label); get_widget!(builder, libhandy::ActionRow, role_row);
let this = Rc::new(PerformanceEditor { let this = Rc::new(PerformanceEditor {
backend, backend,
widget, widget,
save_button, save_button,
person_label, person_row,
ensemble_label, ensemble_row,
role_label, role_row,
reset_role_button, reset_role_button,
person: RefCell::new(None), person: RefCell::new(None),
ensemble: RefCell::new(None), ensemble: RefCell::new(None),
@ -166,30 +167,36 @@ impl PerformanceEditor {
/// Update the UI according to person. /// Update the UI according to person.
fn show_person(&self, person: Option<&Person>) { fn show_person(&self, person: Option<&Person>) {
if let Some(person) = person { if let Some(person) = person {
self.person_label.set_text(&person.name_fl()); self.person_row.set_title(Some(&gettext("Person")));
self.person_row.set_subtitle(Some(&person.name_fl()));
self.save_button.set_sensitive(true); self.save_button.set_sensitive(true);
} else { } else {
self.person_label.set_text(&gettext("Select …")); self.person_row.set_title(Some(&gettext("Select a person")));
self.person_row.set_subtitle(None);
} }
} }
/// Update the UI according to ensemble. /// Update the UI according to ensemble.
fn show_ensemble(&self, ensemble: Option<&Ensemble>) { fn show_ensemble(&self, ensemble: Option<&Ensemble>) {
if let Some(ensemble) = ensemble { if let Some(ensemble) = ensemble {
self.ensemble_label.set_text(&ensemble.name); self.ensemble_row.set_title(Some(&gettext("Ensemble")));
self.ensemble_row.set_subtitle(Some(&ensemble.name));
self.save_button.set_sensitive(true); self.save_button.set_sensitive(true);
} else { } else {
self.ensemble_label.set_text(&gettext("Select …")); self.ensemble_row.set_title(Some(&gettext("Select an ensemble")));
self.ensemble_row.set_subtitle(None);
} }
} }
/// Update the UI according to role. /// Update the UI according to role.
fn show_role(&self, role: Option<&Instrument>) { fn show_role(&self, role: Option<&Instrument>) {
if let Some(role) = role { if let Some(role) = role {
self.role_label.set_text(&role.name); self.role_row.set_title(Some(&gettext("Role")));
self.role_row.set_subtitle(Some(&role.name));
self.reset_role_button.show(); self.reset_role_button.show();
} else { } else {
self.role_label.set_text(&gettext("Select …")); self.role_row.set_title(Some(&gettext("Select a role")));
self.role_row.set_subtitle(None);
self.reset_role_button.hide(); self.reset_role_button.hide();
} }
} }

View file

@ -98,8 +98,8 @@ impl PersonEditor {
/// Save the person and possibly upload it to the server. /// Save the person and possibly upload it to the server.
async fn save(self: Rc<Self>) -> Result<()> { async fn save(self: Rc<Self>) -> Result<()> {
let first_name = self.first_name_entry.get_text().to_string(); let first_name = self.first_name_entry.get_text().unwrap().to_string();
let last_name = self.last_name_entry.get_text().to_string(); let last_name = self.last_name_entry.get_text().unwrap().to_string();
let person = Person { let person = Person {
id: self.id.clone(), id: self.id.clone(),

View file

@ -8,20 +8,20 @@ use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
/// A widget for creating or editing a recording. /// A widget for creating or editing a recording.
// TODO: Disable buttons if no performance is selected.
pub struct RecordingEditor { pub struct RecordingEditor {
pub widget: gtk::Stack, pub widget: gtk::Stack,
backend: Rc<Backend>, backend: Rc<Backend>,
save_button: gtk::Button, save_button: gtk::Button,
info_bar: gtk::InfoBar, info_bar: gtk::InfoBar,
work_label: gtk::Label, work_row: libhandy::ActionRow,
comment_entry: gtk::Entry, comment_entry: gtk::Entry,
upload_switch: gtk::Switch, upload_switch: gtk::Switch,
performance_list: Rc<List<Performance>>, performance_list: Rc<List>,
id: String, id: String,
work: RefCell<Option<Work>>, work: RefCell<Option<Work>>,
performances: RefCell<Vec<Performance>>, performances: RefCell<Vec<Performance>>,
@ -40,17 +40,15 @@ impl RecordingEditor {
get_widget!(builder, gtk::Button, back_button); get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::Button, save_button); get_widget!(builder, gtk::Button, save_button);
get_widget!(builder, gtk::InfoBar, info_bar); get_widget!(builder, gtk::InfoBar, info_bar);
get_widget!(builder, libhandy::ActionRow, work_row);
get_widget!(builder, gtk::Button, work_button); get_widget!(builder, gtk::Button, work_button);
get_widget!(builder, gtk::Label, work_label);
get_widget!(builder, gtk::Entry, comment_entry); get_widget!(builder, gtk::Entry, comment_entry);
get_widget!(builder, gtk::Switch, upload_switch); get_widget!(builder, gtk::Switch, upload_switch);
get_widget!(builder, gtk::ScrolledWindow, scroll); get_widget!(builder, gtk::Frame, performance_frame);
get_widget!(builder, gtk::Button, add_performer_button); get_widget!(builder, gtk::Button, add_performer_button);
get_widget!(builder, gtk::Button, edit_performer_button);
get_widget!(builder, gtk::Button, remove_performer_button);
let performance_list = List::new(&gettext("No performers added.")); let performance_list = List::new();
scroll.add(&performance_list.widget); performance_frame.set_child(Some(&performance_list.widget));
let (id, work, performances) = match recording { let (id, work, performances) = match recording {
Some(recording) => { Some(recording) => {
@ -65,7 +63,7 @@ impl RecordingEditor {
backend, backend,
save_button, save_button,
info_bar, info_bar,
work_label, work_row,
comment_entry, comment_entry,
upload_switch, upload_switch,
performance_list, performance_list,
@ -130,45 +128,28 @@ impl RecordingEditor {
} }
})); }));
this.performance_list.set_make_widget(|performance| { this.performance_list.set_make_widget_cb(clone!(@strong this => move |index| {
let label = gtk::Label::new(Some(&performance.get_title())); let performance = &this.performances.borrow()[index];
label.set_ellipsize(pango::EllipsizeMode::End);
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
label.upcast()
});
add_performer_button.connect_clicked(clone!(@strong this => move |_| { let delete_button = gtk::Button::from_icon_name(Some("user-trash-symbolic"));
let navigator = this.navigator.borrow().clone(); delete_button.set_valign(gtk::Align::Center);
if let Some(navigator) = navigator {
let editor = PerformanceEditor::new(this.backend.clone(), None);
editor.set_selected_cb(clone!(@strong this, @strong navigator => move |performance| { delete_button.connect_clicked(clone!(@strong this => move |_| {
let length = {
let mut performances = this.performances.borrow_mut(); let mut performances = this.performances.borrow_mut();
performances.remove(index);
let index = match this.performance_list.get_selected_index() { performances.len()
Some(index) => index + 1,
None => performances.len(),
}; };
performances.insert(index, performance); this.performance_list.update(length);
this.performance_list.show_items(performances.clone());
this.performance_list.select_index(index);
navigator.clone().pop();
})); }));
navigator.push(editor); let edit_button = gtk::Button::from_icon_name(Some("document-edit-symbolic"));
} edit_button.set_valign(gtk::Align::Center);
}));
edit_performer_button.connect_clicked(clone!(@strong this => move |_| { edit_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone(); let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
if let Some(index) = this.performance_list.get_selected_index() {
let performance = &this.performances.borrow()[index]; let performance = &this.performances.borrow()[index];
let editor = PerformanceEditor::new( let editor = PerformanceEditor::new(
@ -177,24 +158,49 @@ impl RecordingEditor {
); );
editor.set_selected_cb(clone!(@strong this, @strong navigator => move |performance| { editor.set_selected_cb(clone!(@strong this, @strong navigator => move |performance| {
let length = {
let mut performances = this.performances.borrow_mut(); let mut performances = this.performances.borrow_mut();
performances[index] = performance; performances[index] = performance;
this.performance_list.show_items(performances.clone()); performances.len()
this.performance_list.select_index(index); };
this.performance_list.update(length);
navigator.clone().pop(); navigator.clone().pop();
})); }));
navigator.push(editor); navigator.push(editor);
} }
}
})); }));
remove_performer_button.connect_clicked(clone!(@strong this => move |_| { let row = libhandy::ActionRow::new();
if let Some(index) = this.performance_list.get_selected_index() { row.set_activatable(true);
row.set_title(Some(&performance.get_title()));
row.add_suffix(&delete_button);
row.add_suffix(&edit_button);
row.set_activatable_widget(Some(&edit_button));
row.upcast()
}));
add_performer_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator {
let editor = PerformanceEditor::new(this.backend.clone(), None);
editor.set_selected_cb(clone!(@strong this, @strong navigator => move |performance| {
let length = {
let mut performances = this.performances.borrow_mut(); let mut performances = this.performances.borrow_mut();
performances.remove(index); performances.push(performance);
this.performance_list.show_items(performances.clone()); performances.len()
this.performance_list.select_index(index); };
this.performance_list.update(length);
navigator.clone().pop();
}));
navigator.push(editor);
} }
})); }));
@ -204,8 +210,8 @@ impl RecordingEditor {
this.work_selected(work); this.work_selected(work);
} }
this.performance_list let length = this.performances.borrow().len();
.show_items(this.performances.borrow().clone()); this.performance_list.update(length);
this this
} }
@ -217,8 +223,8 @@ impl RecordingEditor {
/// Update the UI according to work. /// Update the UI according to work.
fn work_selected(&self, work: &Work) { fn work_selected(&self, work: &Work) {
self.work_label self.work_row.set_title(Some(&gettext("Work")));
.set_text(&format!("{}: {}", work.composer.name_fl(), work.title)); self.work_row.set_subtitle(Some(&work.get_title()));
self.save_button.set_sensitive(true); self.save_button.set_sensitive(true);
} }
@ -231,7 +237,7 @@ impl RecordingEditor {
.borrow() .borrow()
.clone() .clone()
.expect("Tried to create recording without work!"), .expect("Tried to create recording without work!"),
comment: self.comment_entry.get_text().to_string(), comment: self.comment_entry.get_text().unwrap().to_string(),
performances: self.performances.borrow().clone(), performances: self.performances.borrow().clone(),
}; };

View file

@ -9,6 +9,7 @@ use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::convert::TryInto; use std::convert::TryInto;
use std::rc::Rc; use std::rc::Rc;
@ -20,6 +21,15 @@ enum PartOrSection {
Section(WorkSection), Section(WorkSection),
} }
impl PartOrSection {
pub fn get_title(&self) -> String {
match self {
PartOrSection::Part(part) => part.title.clone(),
PartOrSection::Section(section) => section.title.clone(),
}
}
}
/// A widget for editing and creating works. /// A widget for editing and creating works.
pub struct WorkEditor { pub struct WorkEditor {
widget: gtk::Stack, widget: gtk::Stack,
@ -27,10 +37,10 @@ pub struct WorkEditor {
save_button: gtk::Button, save_button: gtk::Button,
title_entry: gtk::Entry, title_entry: gtk::Entry,
info_bar: gtk::InfoBar, info_bar: gtk::InfoBar,
composer_label: gtk::Label, composer_row: libhandy::ActionRow,
upload_switch: gtk::Switch, upload_switch: gtk::Switch,
instrument_list: Rc<List<Instrument>>, instrument_list: Rc<List>,
part_list: Rc<List<PartOrSection>>, part_list: Rc<List>,
id: String, id: String,
composer: RefCell<Option<Person>>, composer: RefCell<Option<Person>>,
instruments: RefCell<Vec<Instrument>>, instruments: RefCell<Vec<Instrument>>,
@ -52,24 +62,19 @@ impl WorkEditor {
get_widget!(builder, gtk::InfoBar, info_bar); get_widget!(builder, gtk::InfoBar, info_bar);
get_widget!(builder, gtk::Entry, title_entry); get_widget!(builder, gtk::Entry, title_entry);
get_widget!(builder, gtk::Button, composer_button); get_widget!(builder, gtk::Button, composer_button);
get_widget!(builder, gtk::Label, composer_label); get_widget!(builder, libhandy::ActionRow, composer_row);
get_widget!(builder, gtk::Switch, upload_switch); get_widget!(builder, gtk::Switch, upload_switch);
get_widget!(builder, gtk::ScrolledWindow, instruments_scroll); get_widget!(builder, gtk::Frame, instrument_frame);
get_widget!(builder, gtk::Button, add_instrument_button); get_widget!(builder, gtk::Button, add_instrument_button);
get_widget!(builder, gtk::Button, remove_instrument_button); get_widget!(builder, gtk::Frame, structure_frame);
get_widget!(builder, gtk::ScrolledWindow, structure_scroll);
get_widget!(builder, gtk::Button, add_part_button); get_widget!(builder, gtk::Button, add_part_button);
get_widget!(builder, gtk::Button, remove_part_button);
get_widget!(builder, gtk::Button, add_section_button); get_widget!(builder, gtk::Button, add_section_button);
get_widget!(builder, gtk::Button, edit_part_button);
get_widget!(builder, gtk::Button, move_part_up_button);
get_widget!(builder, gtk::Button, move_part_down_button);
let instrument_list = List::new(&gettext("No instruments added.")); let instrument_list = List::new();
instruments_scroll.add(&instrument_list.widget); instrument_frame.set_child(Some(&instrument_list.widget));
let part_list = List::new(&gettext("No work parts added.")); let part_list = List::new();
structure_scroll.add(&part_list.widget); structure_frame.set_child(Some(&part_list.widget));
let (id, composer, instruments, structure) = match work { let (id, composer, instruments, structure) = match work {
Some(work) => { Some(work) => {
@ -100,7 +105,7 @@ impl WorkEditor {
id, id,
info_bar, info_bar,
title_entry, title_entry,
composer_label, composer_row,
upload_switch, upload_switch,
instrument_list, instrument_list,
part_list, part_list,
@ -157,16 +162,28 @@ impl WorkEditor {
} }
})); }));
this.instrument_list.set_make_widget(|instrument| { this.instrument_list.set_make_widget_cb(clone!(@strong this => move |index| {
let label = gtk::Label::new(Some(&instrument.name)); let instrument = &this.instruments.borrow()[index];
label.set_ellipsize(pango::EllipsizeMode::End);
label.set_halign(gtk::Align::Start); let delete_button = gtk::Button::from_icon_name(Some("user-trash-symbolic"));
label.set_margin_start(6); delete_button.set_valign(gtk::Align::Center);
label.set_margin_end(6);
label.set_margin_top(6); delete_button.connect_clicked(clone!(@strong this => move |_| {
label.set_margin_bottom(6); let length = {
label.upcast() let mut instruments = this.instruments.borrow_mut();
}); instruments.remove(index);
instruments.len()
};
this.instrument_list.update(length);
}));
let row = libhandy::ActionRow::new();
row.set_title(Some(&instrument.name));
row.add_suffix(&delete_button);
row.upcast()
}));
add_instrument_button.connect_clicked(clone!(@strong this => move |_| { add_instrument_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone(); let navigator = this.navigator.borrow().clone();
@ -174,17 +191,13 @@ impl WorkEditor {
let selector = InstrumentSelector::new(this.backend.clone()); let selector = InstrumentSelector::new(this.backend.clone());
selector.set_selected_cb(clone!(@strong this, @strong navigator => move |instrument| { selector.set_selected_cb(clone!(@strong this, @strong navigator => move |instrument| {
let length = {
let mut instruments = this.instruments.borrow_mut(); let mut instruments = this.instruments.borrow_mut();
instruments.push(instrument.clone());
let index = match this.instrument_list.get_selected_index() { instruments.len()
Some(index) => index + 1,
None => instruments.len(),
}; };
instruments.insert(index, instrument.clone()); this.instrument_list.update(length);
this.instrument_list.show_items(instruments.clone());
this.instrument_list.select_index(index);
navigator.clone().pop(); navigator.clone().pop();
})); }));
@ -192,39 +205,93 @@ impl WorkEditor {
} }
})); }));
remove_instrument_button.connect_clicked(clone!(@strong this => move |_| { this.part_list.set_make_widget_cb(clone!(@strong this => move |index| {
if let Some(index) = this.instrument_list.get_selected_index() { let pos = &this.structure.borrow()[index];
let mut instruments = this.instruments.borrow_mut();
instruments.remove(index); let drag_source = gtk::DragSource::new();
this.instrument_list.show_items(instruments.clone()); drag_source.set_content(Some(&gdk::ContentProvider::new_for_value(&(index as u32).to_value())));
this.instrument_list.select_index(index);
let drop_target = gtk::DropTarget::new(glib::Type::U32, gdk::DragAction::MOVE);
drop_target.connect_property_value_notify(clone!(@strong this => move |drop_target| {
println!("{:?} -> {:?}", drop_target.get_value(), index);
}));
let handle = gtk::Image::from_icon_name(Some("open-menu-symbolic"));
handle.add_controller(&drag_source);
let delete_button = gtk::Button::from_icon_name(Some("user-trash-symbolic"));
delete_button.set_valign(gtk::Align::Center);
delete_button.connect_clicked(clone!(@strong this => move |_| {
let length = {
let mut structure = this.structure.borrow_mut();
structure.remove(index);
structure.len()
};
this.part_list.update(length);
}));
let edit_button = gtk::Button::from_icon_name(Some("document-edit-symbolic"));
edit_button.set_valign(gtk::Align::Center);
edit_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator {
match this.structure.borrow()[index].clone() {
PartOrSection::Part(part) => {
let editor = WorkPartEditor::new(this.backend.clone(), Some(part));
editor.set_ready_cb(clone!(@strong this, @strong navigator => move |part| {
let length = {
let mut structure = this.structure.borrow_mut();
structure[index] = PartOrSection::Part(part);
structure.len()
};
this.part_list.update(length);
navigator.clone().pop();
}));
navigator.push(editor);
}
PartOrSection::Section(section) => {
let editor = WorkSectionEditor::new(Some(section));
editor.set_ready_cb(clone!(@strong this, @strong navigator => move |section| {
let length = {
let mut structure = this.structure.borrow_mut();
structure[index] = PartOrSection::Section(section);
structure.len()
};
this.part_list.update(length);
navigator.clone().pop();
}));
navigator.push(editor);
}
}
} }
})); }));
this.part_list.set_make_widget(|pos| { let row = libhandy::ActionRow::new();
let label = gtk::Label::new(None); row.set_activatable(true);
label.set_ellipsize(pango::EllipsizeMode::End); row.set_title(Some(&pos.get_title()));
label.set_halign(gtk::Align::Start); row.add_prefix(&handle);
label.set_margin_end(6); row.add_suffix(&delete_button);
label.set_margin_top(6); row.add_suffix(&edit_button);
label.set_margin_bottom(6); row.set_activatable_widget(Some(&edit_button));
row.add_controller(&drop_target);
match pos { if let PartOrSection::Part(_) = pos {
PartOrSection::Part(part) => { // TODO: Replace with better solution to differentiate parts and sections.
label.set_text(&part.title); row.set_margin_start(12);
label.set_margin_start(12);
}
PartOrSection::Section(section) => {
let attrs = pango::AttrList::new();
attrs.insert(pango::Attribute::new_weight(pango::Weight::Bold).unwrap());
label.set_attributes(Some(&attrs));
label.set_text(&section.title);
label.set_margin_start(6);
}
} }
label.upcast() row.upcast()
}); }));
add_part_button.connect_clicked(clone!(@strong this => move |_| { add_part_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone(); let navigator = this.navigator.borrow().clone();
@ -232,17 +299,13 @@ impl WorkEditor {
let editor = WorkPartEditor::new(this.backend.clone(), None); let editor = WorkPartEditor::new(this.backend.clone(), None);
editor.set_ready_cb(clone!(@strong this, @strong navigator => move |part| { editor.set_ready_cb(clone!(@strong this, @strong navigator => move |part| {
let length = {
let mut structure = this.structure.borrow_mut(); let mut structure = this.structure.borrow_mut();
structure.push(PartOrSection::Part(part));
let index = match this.part_list.get_selected_index() { structure.len()
Some(index) => index + 1,
None => structure.len(),
}; };
structure.insert(index, PartOrSection::Part(part)); this.part_list.update(length);
this.part_list.show_items(structure.clone());
this.part_list.select_index(index);
navigator.clone().pop(); navigator.clone().pop();
})); }));
@ -256,17 +319,13 @@ impl WorkEditor {
let editor = WorkSectionEditor::new(None); let editor = WorkSectionEditor::new(None);
editor.set_ready_cb(clone!(@strong this, @strong navigator => move |section| { editor.set_ready_cb(clone!(@strong this, @strong navigator => move |section| {
let length = {
let mut structure = this.structure.borrow_mut(); let mut structure = this.structure.borrow_mut();
structure.push(PartOrSection::Section(section));
let index = match this.part_list.get_selected_index() { structure.len()
Some(index) => index + 1,
None => structure.len(),
}; };
structure.insert(index, PartOrSection::Section(section)); this.part_list.update(length);
this.part_list.show_items(structure.clone());
this.part_list.select_index(index);
navigator.clone().pop(); navigator.clone().pop();
})); }));
@ -274,82 +333,14 @@ impl WorkEditor {
} }
})); }));
edit_part_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator {
if let Some(index) = this.part_list.get_selected_index() {
match this.structure.borrow()[index].clone() {
PartOrSection::Part(part) => {
let editor = WorkPartEditor::new(this.backend.clone(), Some(part));
editor.set_ready_cb(clone!(@strong this, @strong navigator => move |part| {
let mut structure = this.structure.borrow_mut();
structure[index] = PartOrSection::Part(part);
this.part_list.show_items(structure.clone());
this.part_list.select_index(index);
navigator.clone().pop();
}));
navigator.push(editor);
}
PartOrSection::Section(section) => {
let editor = WorkSectionEditor::new(Some(section));
editor.set_ready_cb(clone!(@strong this, @strong navigator => move |section| {
let mut structure = this.structure.borrow_mut();
structure[index] = PartOrSection::Section(section);
this.part_list.show_items(structure.clone());
this.part_list.select_index(index);
navigator.clone().pop();
}));
navigator.push(editor);
}
}
}
}
}));
remove_part_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(index) = this.part_list.get_selected_index() {
let mut structure = this.structure.borrow_mut();
structure.remove(index);
this.part_list.show_items(structure.clone());
this.part_list.select_index(index);
}
}));
move_part_up_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(index) = this.part_list.get_selected_index() {
if index > 0 {
let mut structure = this.structure.borrow_mut();
structure.swap(index - 1, index);
this.part_list.show_items(structure.clone());
this.part_list.select_index(index - 1);
}
}
}));
move_part_down_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(index) = this.part_list.get_selected_index() {
let mut structure = this.structure.borrow_mut();
if index < structure.len() - 1 {
structure.swap(index, index + 1);
this.part_list.show_items(structure.clone());
this.part_list.select_index(index + 1);
}
}
}));
// Initialization // Initialization
if let Some(composer) = &*this.composer.borrow() { if let Some(composer) = &*this.composer.borrow() {
this.show_composer(composer); this.show_composer(composer);
} }
this.instrument_list this.instrument_list.update(this.instruments.borrow().len());
.show_items(this.instruments.borrow().clone()); this.part_list.update(this.structure.borrow().len());
this.part_list.show_items(this.structure.borrow().clone());
this this
} }
@ -361,7 +352,8 @@ impl WorkEditor {
/// Update the UI according to person. /// Update the UI according to person.
fn show_composer(&self, person: &Person) { fn show_composer(&self, person: &Person) {
self.composer_label.set_text(&person.name_fl()); self.composer_row.set_title(Some(&gettext("Composer")));
self.composer_row.set_subtitle(Some(&person.name_fl()));
self.save_button.set_sensitive(true); self.save_button.set_sensitive(true);
} }
@ -385,7 +377,7 @@ impl WorkEditor {
let work = Work { let work = Work {
id: self.id.clone(), id: self.id.clone(),
title: self.title_entry.get_text().to_string(), title: self.title_entry.get_text().unwrap().to_string(),
composer: self composer: self
.composer .composer
.borrow() .borrow()

View file

@ -6,6 +6,7 @@ use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -14,7 +15,7 @@ pub struct WorkPartEditor {
backend: Rc<Backend>, backend: Rc<Backend>,
widget: gtk::Box, widget: gtk::Box,
title_entry: gtk::Entry, title_entry: gtk::Entry,
composer_label: gtk::Label, composer_row: libhandy::ActionRow,
reset_composer_button: gtk::Button, reset_composer_button: gtk::Button,
composer: RefCell<Option<Person>>, composer: RefCell<Option<Person>>,
ready_cb: RefCell<Option<Box<dyn Fn(WorkPart) -> ()>>>, ready_cb: RefCell<Option<Box<dyn Fn(WorkPart) -> ()>>>,
@ -33,7 +34,7 @@ impl WorkPartEditor {
get_widget!(builder, gtk::Button, save_button); get_widget!(builder, gtk::Button, save_button);
get_widget!(builder, gtk::Entry, title_entry); get_widget!(builder, gtk::Entry, title_entry);
get_widget!(builder, gtk::Button, composer_button); get_widget!(builder, gtk::Button, composer_button);
get_widget!(builder, gtk::Label, composer_label); get_widget!(builder, libhandy::ActionRow, composer_row);
get_widget!(builder, gtk::Button, reset_composer_button); get_widget!(builder, gtk::Button, reset_composer_button);
let composer = match part { let composer = match part {
@ -48,7 +49,7 @@ impl WorkPartEditor {
backend, backend,
widget, widget,
title_entry, title_entry,
composer_label, composer_row,
reset_composer_button, reset_composer_button,
composer: RefCell::new(composer), composer: RefCell::new(composer),
ready_cb: RefCell::new(None), ready_cb: RefCell::new(None),
@ -67,7 +68,7 @@ impl WorkPartEditor {
save_button.connect_clicked(clone!(@strong this => move |_| { save_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(cb) = &*this.ready_cb.borrow() { if let Some(cb) = &*this.ready_cb.borrow() {
cb(WorkPart { cb(WorkPart {
title: this.title_entry.get_text().to_string(), title: this.title_entry.get_text().unwrap().to_string(),
composer: this.composer.borrow().clone(), composer: this.composer.borrow().clone(),
}); });
} }
@ -117,10 +118,12 @@ impl WorkPartEditor {
/// Update the UI according to person. /// Update the UI according to person.
fn show_composer(&self, person: Option<&Person>) { fn show_composer(&self, person: Option<&Person>) {
if let Some(person) = person { if let Some(person) = person {
self.composer_label.set_text(&person.name_fl()); self.composer_row.set_title(Some(&gettext("Composer")));
self.composer_row.set_subtitle(Some(&person.name_fl()));
self.reset_composer_button.show(); self.reset_composer_button.show();
} else { } else {
self.composer_label.set_text(&gettext("Select …")); self.composer_row.set_title(Some(&gettext("Select a composer")));
self.composer_row.set_subtitle(None);
self.reset_composer_button.hide(); self.reset_composer_button.hide();
} }
} }

View file

@ -50,7 +50,7 @@ impl WorkSectionEditor {
if let Some(cb) = &*this.ready_cb.borrow() { if let Some(cb) = &*this.ready_cb.borrow() {
cb(WorkSection { cb(WorkSection {
before_index: 0, before_index: 0,
title: this.title_entry.get_text().to_string(), title: this.title_entry.get_text().unwrap().to_string(),
}); });
} }

View file

@ -3,7 +3,6 @@ use discid::DiscId;
use futures_channel::oneshot; use futures_channel::oneshot;
use gstreamer::prelude::*; use gstreamer::prelude::*;
use gstreamer::{Element, ElementFactory, Pipeline}; use gstreamer::{Element, ElementFactory, Pipeline};
use std::cell::RefCell;
use std::path::{Path, PathBuf}; use std::path::{Path, PathBuf};
use std::thread; use std::thread;

View file

@ -2,8 +2,7 @@ use super::disc_source::DiscSource;
use super::track_set_editor::{TrackSetData, TrackSetEditor}; use super::track_set_editor::{TrackSetData, TrackSetEditor};
use crate::database::{generate_id, Medium, Track, TrackSet}; use crate::database::{generate_id, Medium, Track, TrackSet};
use crate::backend::Backend; use crate::backend::Backend;
use crate::widgets::{Navigator, NavigatorScreen}; use crate::widgets::{List, Navigator, NavigatorScreen};
use crate::widgets::new_list::List;
use anyhow::Result; use anyhow::Result;
use glib::clone; use glib::clone;
use glib::prelude::*; use glib::prelude::*;
@ -23,7 +22,7 @@ pub struct MediumEditor {
done: gtk::Image, done: gtk::Image,
name_entry: gtk::Entry, name_entry: gtk::Entry,
publish_switch: gtk::Switch, publish_switch: gtk::Switch,
track_set_list: List, track_set_list: Rc<List>,
track_sets: RefCell<Vec<TrackSetData>>, track_sets: RefCell<Vec<TrackSetData>>,
navigator: RefCell<Option<Rc<Navigator>>>, navigator: RefCell<Option<Rc<Navigator>>>,
} }
@ -45,8 +44,8 @@ impl MediumEditor {
get_widget!(builder, gtk::Button, add_button); get_widget!(builder, gtk::Button, add_button);
get_widget!(builder, gtk::Frame, frame); get_widget!(builder, gtk::Frame, frame);
let list = List::new("No recordings added."); let list = List::new();
frame.add(&list.widget); frame.set_child(Some(&list.widget));
let this = Rc::new(Self { let this = Rc::new(Self {
backend, backend,
@ -106,25 +105,24 @@ impl MediumEditor {
} }
})); }));
this.track_set_list.set_make_widget(clone!(@strong this => move |index| { this.track_set_list.set_make_widget_cb(clone!(@strong this => move |index| {
let track_set = &this.track_sets.borrow()[index]; let track_set = &this.track_sets.borrow()[index];
let title = track_set.recording.work.get_title(); let title = track_set.recording.work.get_title();
let subtitle = track_set.recording.get_performers(); let subtitle = track_set.recording.get_performers();
let edit_image = gtk::Image::from_icon_name(Some("document-edit-symbolic"), gtk::IconSize::Button); let edit_image = gtk::Image::from_icon_name(Some("document-edit-symbolic"));
let edit_button = gtk::Button::new(); let edit_button = gtk::Button::new();
edit_button.set_relief(gtk::ReliefStyle::None); edit_button.set_has_frame(false);
edit_button.set_valign(gtk::Align::Center); edit_button.set_valign(gtk::Align::Center);
edit_button.add(&edit_image); edit_button.set_child(Some(&edit_image));
let row = libhandy::ActionRow::new(); let row = libhandy::ActionRow::new();
row.set_activatable(true); row.set_activatable(true);
row.set_title(Some(&title)); row.set_title(Some(&title));
row.set_subtitle(Some(&subtitle)); row.set_subtitle(Some(&subtitle));
row.add(&edit_button); row.add_suffix(&edit_button);
row.set_activatable_widget(Some(&edit_button)); row.set_activatable_widget(Some(&edit_button));
row.show_all();
edit_button.connect_clicked(clone!(@strong this => move |_| { edit_button.connect_clicked(clone!(@strong this => move |_| {
@ -154,7 +152,7 @@ impl MediumEditor {
/// Save the medium and possibly upload it to the server. /// Save the medium and possibly upload it to the server.
async fn save(self: Rc<Self>) -> Result<()> { async fn save(self: Rc<Self>) -> Result<()> {
let name = self.name_entry.get_text().to_string(); let name = self.name_entry.get_text().unwrap().to_string();
// Create a new directory in the music library path for the imported medium. // Create a new directory in the music library path for the imported medium.
@ -200,7 +198,7 @@ impl MediumEditor {
let medium = Medium { let medium = Medium {
id: generate_id(), id: generate_id(),
name: self.name_entry.get_text().to_string(), name: self.name_entry.get_text().unwrap().to_string(),
discid: Some(self.source.discid.clone()), discid: Some(self.source.discid.clone()),
tracks: track_sets, tracks: track_sets,
}; };

View file

@ -2,7 +2,6 @@ use super::medium_editor::MediumEditor;
use super::disc_source::DiscSource; use super::disc_source::DiscSource;
use crate::backend::Backend; use crate::backend::Backend;
use crate::widgets::{Navigator, NavigatorScreen}; use crate::widgets::{Navigator, NavigatorScreen};
use anyhow::Result;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;

View file

@ -1,6 +1,5 @@
use crate::database::Recording; use crate::database::Recording;
use crate::widgets::{Navigator, NavigatorScreen}; use crate::widgets::{Navigator, NavigatorScreen};
use crate::widgets::new_list::List;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
@ -32,7 +31,7 @@ impl TrackEditor {
parts_list.set_selection_mode(gtk::SelectionMode::None); parts_list.set_selection_mode(gtk::SelectionMode::None);
parts_list.set_vexpand(false); parts_list.set_vexpand(false);
parts_list.show(); parts_list.show();
parts_frame.add(&parts_list); parts_frame.set_child(Some(&parts_list));
let this = Rc::new(Self { let this = Rc::new(Self {
widget, widget,
@ -81,9 +80,8 @@ impl TrackEditor {
row.add_prefix(&check); row.add_prefix(&check);
row.set_activatable_widget(Some(&check)); row.set_activatable_widget(Some(&check));
row.set_title(Some(&part.title)); row.set_title(Some(&part.title));
row.show_all();
parts_list.add(&row); parts_list.append(&row);
} }
this this

View file

@ -33,7 +33,7 @@ impl TrackSelector {
track_list.set_selection_mode(gtk::SelectionMode::None); track_list.set_selection_mode(gtk::SelectionMode::None);
track_list.set_vexpand(false); track_list.set_vexpand(false);
track_list.show(); track_list.show();
tracks_frame.add(&track_list); tracks_frame.set_child(Some(&track_list));
let this = Rc::new(Self { let this = Rc::new(Self {
source, source,
@ -90,10 +90,10 @@ impl TrackSelector {
let row = libhandy::ActionRow::new(); let row = libhandy::ActionRow::new();
row.add_prefix(&check); row.add_prefix(&check);
row.set_activatable_widget(Some(&check)); row.set_activatable_widget(Some(&check));
row.set_activatable(true);
row.set_title(Some(&title)); row.set_title(Some(&title));
row.show_all();
track_list.add(&row); track_list.append(&row);
} }
this this

View file

@ -2,17 +2,15 @@ use super::disc_source::DiscSource;
use super::track_editor::TrackEditor; use super::track_editor::TrackEditor;
use super::track_selector::TrackSelector; use super::track_selector::TrackSelector;
use crate::backend::Backend; use crate::backend::Backend;
use crate::database::{Recording, Track, TrackSet}; use crate::database::Recording;
use crate::selectors::{PersonSelector, RecordingSelector, WorkSelector}; use crate::selectors::{PersonSelector, RecordingSelector, WorkSelector};
use crate::widgets::{Navigator, NavigatorScreen}; use crate::widgets::{List, Navigator, NavigatorScreen};
use crate::widgets::new_list::List;
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::prelude::*; use libhandy::prelude::*;
use std::cell::{Cell, RefCell}; use std::cell::RefCell;
use std::collections::HashSet;
use std::rc::Rc; use std::rc::Rc;
/// A track set before being imported. /// A track set before being imported.
@ -39,7 +37,7 @@ pub struct TrackSetEditor {
widget: gtk::Box, widget: gtk::Box,
save_button: gtk::Button, save_button: gtk::Button,
recording_row: libhandy::ActionRow, recording_row: libhandy::ActionRow,
track_list: List, track_list: Rc<List>,
recording: RefCell<Option<Recording>>, recording: RefCell<Option<Recording>>,
tracks: RefCell<Vec<TrackData>>, tracks: RefCell<Vec<TrackData>>,
done_cb: RefCell<Option<Box<dyn Fn(TrackSetData)>>>, done_cb: RefCell<Option<Box<dyn Fn(TrackSetData)>>>,
@ -61,8 +59,8 @@ impl TrackSetEditor {
get_widget!(builder, gtk::Button, edit_tracks_button); get_widget!(builder, gtk::Button, edit_tracks_button);
get_widget!(builder, gtk::Frame, tracks_frame); get_widget!(builder, gtk::Frame, tracks_frame);
let track_list = List::new(&gettext!("No tracks added")); let track_list = List::new();
tracks_frame.add(&track_list.widget); tracks_frame.set_child(Some(&track_list.widget));
let this = Rc::new(Self { let this = Rc::new(Self {
backend, backend,
@ -159,7 +157,7 @@ impl TrackSetEditor {
} }
})); }));
this.track_list.set_make_widget(clone!(@strong this => move |index| { this.track_list.set_make_widget_cb(clone!(@strong this => move |index| {
let track = &this.tracks.borrow()[index]; let track = &this.tracks.borrow()[index];
let mut title_parts = Vec::<String>::new(); let mut title_parts = Vec::<String>::new();
@ -179,19 +177,18 @@ impl TrackSetEditor {
let number = this.source.tracks[track.track_source].number; let number = this.source.tracks[track.track_source].number;
let subtitle = format!("Track {}", number); let subtitle = format!("Track {}", number);
let edit_image = gtk::Image::from_icon_name(Some("document-edit-symbolic"), gtk::IconSize::Button); let edit_image = gtk::Image::from_icon_name(Some("document-edit-symbolic"));
let edit_button = gtk::Button::new(); let edit_button = gtk::Button::new();
edit_button.set_relief(gtk::ReliefStyle::None); edit_button.set_has_frame(false);
edit_button.set_valign(gtk::Align::Center); edit_button.set_valign(gtk::Align::Center);
edit_button.add(&edit_image); edit_button.set_child(Some(&edit_image));
let row = libhandy::ActionRow::new(); let row = libhandy::ActionRow::new();
row.set_activatable(true); row.set_activatable(true);
row.set_title(Some(&title)); row.set_title(Some(&title));
row.set_subtitle(Some(&subtitle)); row.set_subtitle(Some(&subtitle));
row.add(&edit_button); row.add_suffix(&edit_button);
row.set_activatable_widget(Some(&edit_button)); row.set_activatable_widget(Some(&edit_button));
row.show_all();
edit_button.connect_clicked(clone!(@strong this => move |_| { edit_button.connect_clicked(clone!(@strong this => move |_| {
let recording = this.recording.borrow().clone(); let recording = this.recording.borrow().clone();

View file

@ -65,6 +65,13 @@ sources = files(
'editors/work.rs', 'editors/work.rs',
'editors/work_part.rs', 'editors/work_part.rs',
'editors/work_section.rs', 'editors/work_section.rs',
'import/disc_source.rs',
'import/medium_editor.rs',
'import/mod.rs',
'import/source_selector.rs',
'import/track_editor.rs',
'import/track_selector.rs',
'import/track_set_editor.rs',
'screens/ensemble_screen.rs', 'screens/ensemble_screen.rs',
'screens/mod.rs', 'screens/mod.rs',
'screens/person_screen.rs', 'screens/person_screen.rs',
@ -78,13 +85,13 @@ sources = files(
'selectors/recording.rs', 'selectors/recording.rs',
'selectors/selector.rs', 'selectors/selector.rs',
'selectors/work.rs', 'selectors/work.rs',
'widgets/indexed_list_model.rs',
'widgets/list.rs', 'widgets/list.rs',
'widgets/mod.rs', 'widgets/mod.rs',
'widgets/navigator.rs', 'widgets/navigator.rs',
'widgets/navigator_window.rs', 'widgets/navigator_window.rs',
'widgets/player_bar.rs', 'widgets/player_bar.rs',
'widgets/poe_list.rs', 'widgets/poe_list.rs',
'widgets/selector_row.rs',
'config.rs', 'config.rs',
'config.rs.in', 'config.rs.in',
'main.rs', 'main.rs',

View file

@ -3,12 +3,11 @@ use crate::backend::*;
use crate::database::*; use crate::database::*;
use crate::editors::EnsembleEditor; use crate::editors::EnsembleEditor;
use crate::widgets::{List, Navigator, NavigatorScreen, NavigatorWindow}; use crate::widgets::{List, Navigator, NavigatorScreen, NavigatorWindow};
use gettextrs::gettext;
use gio::prelude::*; use gio::prelude::*;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::HeaderBarExt; use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -16,8 +15,10 @@ pub struct EnsembleScreen {
backend: Rc<Backend>, backend: Rc<Backend>,
ensemble: Ensemble, ensemble: Ensemble,
widget: gtk::Box, widget: gtk::Box,
search_entry: gtk::SearchEntry,
stack: gtk::Stack, stack: gtk::Stack,
recording_list: Rc<List<Recording>>, recording_list: Rc<List>,
recordings: RefCell<Vec<Recording>>,
navigator: RefCell<Option<Rc<Navigator>>>, navigator: RefCell<Option<Rc<Navigator>>>,
} }
@ -26,13 +27,13 @@ impl EnsembleScreen {
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/ensemble_screen.ui"); let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/ensemble_screen.ui");
get_widget!(builder, gtk::Box, widget); get_widget!(builder, gtk::Box, widget);
get_widget!(builder, libhandy::HeaderBar, header); get_widget!(builder, gtk::Label, title_label);
get_widget!(builder, gtk::Button, back_button); get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::SearchEntry, search_entry); get_widget!(builder, gtk::SearchEntry, search_entry);
get_widget!(builder, gtk::Stack, stack); get_widget!(builder, gtk::Stack, stack);
get_widget!(builder, gtk::Frame, recording_frame); get_widget!(builder, gtk::Frame, recording_frame);
header.set_title(Some(&ensemble.name)); title_label.set_label(&ensemble.name);
let edit_action = gio::SimpleAction::new("edit", None); let edit_action = gio::SimpleAction::new("edit", None);
let delete_action = gio::SimpleAction::new("delete", None); let delete_action = gio::SimpleAction::new("delete", None);
@ -43,75 +44,66 @@ impl EnsembleScreen {
widget.insert_action_group("widget", Some(&actions)); widget.insert_action_group("widget", Some(&actions));
let recording_list = List::new(&gettext("No recordings found.")); let recording_list = List::new();
recording_frame.set_child(Some(&recording_list.widget));
recording_list.set_make_widget(|recording: &Recording| { let this = Rc::new(Self {
let work_label = gtk::Label::new(Some(&recording.work.get_title()));
work_label.set_ellipsize(pango::EllipsizeMode::End);
work_label.set_halign(gtk::Align::Start);
let performers_label = gtk::Label::new(Some(&recording.get_performers()));
performers_label.set_ellipsize(pango::EllipsizeMode::End);
performers_label.set_opacity(0.5);
performers_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&work_label);
vbox.add(&performers_label);
vbox.upcast()
});
recording_list.set_filter(
clone!(@strong search_entry => move |recording: &Recording| {
let search = search_entry.get_text().to_string().to_lowercase();
let text = recording.work.get_title() + &recording.get_performers();
search.is_empty() || text.contains(&search)
}),
);
recording_frame.add(&recording_list.widget.clone());
let result = Rc::new(Self {
backend, backend,
ensemble, ensemble,
widget, widget,
search_entry,
stack, stack,
recording_list, recording_list,
recordings: RefCell::new(Vec::new()),
navigator: RefCell::new(None), navigator: RefCell::new(None),
}); });
search_entry.connect_search_changed(clone!(@strong result => move |_| { this.search_entry.connect_search_changed(clone!(@strong this => move |_| {
result.recording_list.invalidate_filter(); this.recording_list.invalidate_filter();
})); }));
back_button.connect_clicked(clone!(@strong result => move |_| { back_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = result.navigator.borrow().clone(); let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.pop(); navigator.pop();
} }
})); }));
result this.recording_list.set_make_widget_cb(clone!(@strong this => move |index| {
.recording_list let recording = &this.recordings.borrow()[index];
.set_selected(clone!(@strong result => move |recording| {
let navigator = result.navigator.borrow().clone(); let row = libhandy::ActionRow::new();
row.set_activatable(true);
row.set_title(Some(&recording.work.get_title()));
row.set_subtitle(Some(&recording.get_performers()));
let recording = recording.to_owned();
row.connect_activated(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.push(RecordingScreen::new(result.backend.clone(), recording.clone())); navigator.push(RecordingScreen::new(this.backend.clone(), recording.clone()));
} }
})); }));
edit_action.connect_activate(clone!(@strong result => move |_, _| { row.upcast()
let editor = EnsembleEditor::new(result.backend.clone(), Some(result.ensemble.clone())); }));
this.recording_list.set_filter_cb(clone!(@strong this => move |index| {
let recording = &this.recordings.borrow()[index];
let search = this.search_entry.get_text().unwrap().to_string().to_lowercase();
let text = recording.work.get_title() + &recording.get_performers();
search.is_empty() || text.to_lowercase().contains(&search)
}));
edit_action.connect_activate(clone!(@strong this => move |_, _| {
let editor = EnsembleEditor::new(this.backend.clone(), Some(this.ensemble.clone()));
let window = NavigatorWindow::new(editor); let window = NavigatorWindow::new(editor);
window.show(); window.show();
})); }));
delete_action.connect_activate(clone!(@strong result => move |_, _| { delete_action.connect_activate(clone!(@strong this => move |_, _| {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
clone.backend.db().delete_ensemble(&clone.ensemble.id).await.unwrap(); clone.backend.db().delete_ensemble(&clone.ensemble.id).await.unwrap();
clone.backend.library_changed(); clone.backend.library_changed();
@ -119,7 +111,7 @@ impl EnsembleScreen {
})); }));
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
let recordings = clone let recordings = clone
.backend .backend
@ -131,12 +123,14 @@ impl EnsembleScreen {
if recordings.is_empty() { if recordings.is_empty() {
clone.stack.set_visible_child_name("nothing"); clone.stack.set_visible_child_name("nothing");
} else { } else {
clone.recording_list.show_items(recordings); let length = recordings.len();
clone.recordings.replace(recordings);
clone.recording_list.update(length);
clone.stack.set_visible_child_name("content"); clone.stack.set_visible_child_name("content");
} }
}); });
result this
} }
} }

View file

@ -3,12 +3,11 @@ use crate::backend::*;
use crate::database::*; use crate::database::*;
use crate::editors::PersonEditor; use crate::editors::PersonEditor;
use crate::widgets::{List, Navigator, NavigatorScreen, NavigatorWindow}; use crate::widgets::{List, Navigator, NavigatorScreen, NavigatorWindow};
use gettextrs::gettext;
use gio::prelude::*; use gio::prelude::*;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::HeaderBarExt; use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -17,8 +16,13 @@ pub struct PersonScreen {
person: Person, person: Person,
widget: gtk::Box, widget: gtk::Box,
stack: gtk::Stack, stack: gtk::Stack,
work_list: Rc<List<Work>>, search_entry: gtk::SearchEntry,
recording_list: Rc<List<Recording>>, work_box: gtk::Box,
work_list: Rc<List>,
recording_box: gtk::Box,
recording_list: Rc<List>,
works: RefCell<Vec<Work>>,
recordings: RefCell<Vec<Recording>>,
navigator: RefCell<Option<Rc<Navigator>>>, navigator: RefCell<Option<Rc<Navigator>>>,
} }
@ -27,7 +31,7 @@ impl PersonScreen {
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/person_screen.ui"); let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/person_screen.ui");
get_widget!(builder, gtk::Box, widget); get_widget!(builder, gtk::Box, widget);
get_widget!(builder, libhandy::HeaderBar, header); get_widget!(builder, gtk::Label, title_label);
get_widget!(builder, gtk::Button, back_button); get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::SearchEntry, search_entry); get_widget!(builder, gtk::SearchEntry, search_entry);
get_widget!(builder, gtk::Stack, stack); get_widget!(builder, gtk::Stack, stack);
@ -36,7 +40,7 @@ impl PersonScreen {
get_widget!(builder, gtk::Box, recording_box); get_widget!(builder, gtk::Box, recording_box);
get_widget!(builder, gtk::Frame, recording_frame); get_widget!(builder, gtk::Frame, recording_frame);
header.set_title(Some(&person.name_fl())); title_label.set_label(&person.name_fl());
let edit_action = gio::SimpleAction::new("edit", None); let edit_action = gio::SimpleAction::new("edit", None);
let delete_action = gio::SimpleAction::new("delete", None); let delete_action = gio::SimpleAction::new("delete", None);
@ -47,107 +51,98 @@ impl PersonScreen {
widget.insert_action_group("widget", Some(&actions)); widget.insert_action_group("widget", Some(&actions));
let work_list = List::new(&gettext("No works found.")); let work_list = List::new();
let recording_list = List::new();
work_frame.set_child(Some(&work_list.widget));
recording_frame.set_child(Some(&recording_list.widget));
work_list.set_make_widget(|work: &Work| { let this = Rc::new(Self {
let label = gtk::Label::new(Some(&work.title));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
label.upcast()
});
work_list.set_filter(clone!(@strong search_entry => move |work: &Work| {
let search = search_entry.get_text().to_string().to_lowercase();
let title = work.title.to_lowercase();
search.is_empty() || title.contains(&search)
}));
let recording_list = List::new(&gettext("No recordings found."));
recording_list.set_make_widget(|recording: &Recording| {
let work_label = gtk::Label::new(Some(&recording.work.get_title()));
work_label.set_ellipsize(pango::EllipsizeMode::End);
work_label.set_halign(gtk::Align::Start);
let performers_label = gtk::Label::new(Some(&recording.get_performers()));
performers_label.set_ellipsize(pango::EllipsizeMode::End);
performers_label.set_opacity(0.5);
performers_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&work_label);
vbox.add(&performers_label);
vbox.upcast()
});
recording_list.set_filter(
clone!(@strong search_entry => move |recording: &Recording| {
let search = search_entry.get_text().to_string().to_lowercase();
let text = recording.work.get_title() + &recording.get_performers();
search.is_empty() || text.contains(&search)
}),
);
work_frame.add(&work_list.widget);
recording_frame.add(&recording_list.widget);
let result = Rc::new(Self {
backend, backend,
person, person,
widget, widget,
stack, stack,
search_entry,
work_box,
work_list, work_list,
recording_box,
recording_list, recording_list,
works: RefCell::new(Vec::new()),
recordings: RefCell::new(Vec::new()),
navigator: RefCell::new(None), navigator: RefCell::new(None),
}); });
search_entry.connect_search_changed(clone!(@strong result => move |_| { this.search_entry.connect_search_changed(clone!(@strong this => move |_| {
result.work_list.invalidate_filter(); this.work_list.invalidate_filter();
result.recording_list.invalidate_filter(); this.recording_list.invalidate_filter();
})); }));
back_button.connect_clicked(clone!(@strong result => move |_| { back_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = result.navigator.borrow().clone(); let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.clone().pop(); navigator.clone().pop();
} }
})); }));
result this.work_list.set_make_widget_cb(clone!(@strong this => move |index| {
.work_list let work = &this.works.borrow()[index];
.set_selected(clone!(@strong result => move |work| {
result.recording_list.clear_selection(); let row = libhandy::ActionRow::new();
let navigator = result.navigator.borrow().clone(); row.set_activatable(true);
row.set_title(Some(&work.title));
let work = work.to_owned();
row.connect_activated(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.push(WorkScreen::new(result.backend.clone(), work.clone())); navigator.push(WorkScreen::new(this.backend.clone(), work.clone()));
} }
})); }));
result row.upcast()
.recording_list }));
.set_selected(clone!(@strong result => move |recording| {
result.work_list.clear_selection(); this.work_list.set_filter_cb(clone!(@strong this => move |index| {
let navigator = result.navigator.borrow().clone(); let work = &this.works.borrow()[index];
let search = this.search_entry.get_text().unwrap().to_string().to_lowercase();
let title = work.title.to_lowercase();
search.is_empty() || title.contains(&search)
}));
this.recording_list.set_make_widget_cb(clone!(@strong this => move |index| {
let recording = &this.recordings.borrow()[index];
let row = libhandy::ActionRow::new();
row.set_activatable(true);
row.set_title(Some(&recording.work.get_title()));
row.set_subtitle(Some(&recording.get_performers()));
let recording = recording.to_owned();
row.connect_activated(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.push(RecordingScreen::new(result.backend.clone(), recording.clone())); navigator.push(RecordingScreen::new(this.backend.clone(), recording.clone()));
} }
})); }));
edit_action.connect_activate(clone!(@strong result => move |_, _| { row.upcast()
let editor = PersonEditor::new(result.backend.clone(), Some(result.person.clone())); }));
this.recording_list.set_filter_cb(clone!(@strong this => move |index| {
let recording = &this.recordings.borrow()[index];
let search = this.search_entry.get_text().unwrap().to_string().to_lowercase();
let text = recording.work.get_title() + &recording.get_performers();
search.is_empty() || text.contains(&search)
}));
edit_action.connect_activate(clone!(@strong this => move |_, _| {
let editor = PersonEditor::new(this.backend.clone(), Some(this.person.clone()));
let window = NavigatorWindow::new(editor); let window = NavigatorWindow::new(editor);
window.show(); window.show();
})); }));
delete_action.connect_activate(clone!(@strong result => move |_, _| { delete_action.connect_activate(clone!(@strong this => move |_, _| {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
clone.backend.db().delete_person(&clone.person.id).await.unwrap(); clone.backend.db().delete_person(&clone.person.id).await.unwrap();
clone.backend.library_changed(); clone.backend.library_changed();
@ -155,7 +150,7 @@ impl PersonScreen {
})); }));
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
let works = clone let works = clone
.backend .backend
@ -163,6 +158,7 @@ impl PersonScreen {
.get_works(&clone.person.id) .get_works(&clone.person.id)
.await .await
.unwrap(); .unwrap();
let recordings = clone let recordings = clone
.backend .backend
.db() .db()
@ -174,22 +170,26 @@ impl PersonScreen {
clone.stack.set_visible_child_name("nothing"); clone.stack.set_visible_child_name("nothing");
} else { } else {
if works.is_empty() { if works.is_empty() {
work_box.hide(); clone.work_box.hide();
} else { } else {
clone.work_list.show_items(works); let length = works.len();
clone.works.replace(works);
clone.work_list.update(length);
} }
if recordings.is_empty() { if recordings.is_empty() {
recording_box.hide(); clone.recording_box.hide();
} else { } else {
clone.recording_list.show_items(recordings); let length = recordings.len();
clone.recordings.replace(recordings);
clone.recording_list.update(length);
} }
clone.stack.set_visible_child_name("content"); clone.stack.set_visible_child_name("content");
} }
}); });
result this
} }
} }

View file

@ -4,15 +4,22 @@ use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::prelude::*;
use std::cell::{Cell, RefCell}; use std::cell::{Cell, RefCell};
use std::rc::Rc; use std::rc::Rc;
struct PlaylistElement { /// Elements for visually representing the playlist.
pub item: usize, enum ListItem {
pub track: usize, /// A header shown on top of a track set. This contains an index
pub title: String, /// referencing the playlist item containing this track set.
pub subtitle: Option<String>, Header(usize),
pub playable: bool,
/// A playable track. This contains an index to the playlist item, an
/// index to the track and whether it is the currently played one.
Track(usize, usize, bool),
/// A separator shown between track sets.
Separator,
} }
pub struct PlayerScreen { pub struct PlayerScreen {
@ -27,16 +34,18 @@ pub struct PlayerScreen {
duration_label: gtk::Label, duration_label: gtk::Label,
play_image: gtk::Image, play_image: gtk::Image,
pause_image: gtk::Image, pause_image: gtk::Image,
list: Rc<List<PlaylistElement>>, list: Rc<List>,
player: Rc<RefCell<Option<Rc<Player>>>>, playlist: RefCell<Vec<PlaylistItem>>,
seeking: Rc<Cell<bool>>, items: RefCell<Vec<ListItem>>,
current_item: Rc<Cell<usize>>, player: RefCell<Option<Rc<Player>>>,
current_track: Rc<Cell<usize>>, seeking: Cell<bool>,
back_cb: Rc<RefCell<Option<Box<dyn Fn() -> ()>>>>, current_item: Cell<usize>,
current_track: Cell<usize>,
back_cb: RefCell<Option<Box<dyn Fn()>>>,
} }
impl PlayerScreen { impl PlayerScreen {
pub fn new() -> Self { pub fn new() -> Rc<Self> {
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/player_screen.ui"); let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/player_screen.ui");
get_widget!(builder, gtk::Box, widget); get_widget!(builder, gtk::Box, widget);
@ -55,124 +64,10 @@ impl PlayerScreen {
get_widget!(builder, gtk::Image, pause_image); get_widget!(builder, gtk::Image, pause_image);
get_widget!(builder, gtk::Frame, frame); get_widget!(builder, gtk::Frame, frame);
let back_cb = Rc::new(RefCell::new(None::<Box<dyn Fn() -> ()>>)); let list = List::new();
frame.set_child(Some(&list.widget));
back_button.connect_clicked(clone!(@strong back_cb => move |_| { let this = Rc::new(Self {
if let Some(cb) = &*back_cb.borrow() {
cb();
}
}));
let player = Rc::new(RefCell::new(None::<Rc<Player>>));
let seeking = Rc::new(Cell::new(false));
previous_button.connect_clicked(clone!(@strong player => move |_| {
if let Some(player) = &*player.borrow() {
player.previous().unwrap();
}
}));
play_button.connect_clicked(clone!(@strong player => move |_| {
if let Some(player) = &*player.borrow() {
player.play_pause();
}
}));
next_button.connect_clicked(clone!(@strong player => move |_| {
if let Some(player) = &*player.borrow() {
player.next().unwrap();
}
}));
stop_button.connect_clicked(clone!(@strong player, @strong back_cb => move |_| {
if let Some(player) = &*player.borrow() {
if let Some(cb) = &*back_cb.borrow() {
cb();
}
player.clear();
}
}));
position_scale.connect_button_press_event(clone!(@strong seeking => move |_, _| {
seeking.replace(true);
Inhibit(false)
}));
position_scale.connect_button_release_event(
clone!(@strong seeking, @strong position, @strong player => move |_, _| {
if let Some(player) = &*player.borrow() {
player.seek(position.get_value() as u64);
}
seeking.replace(false);
Inhibit(false)
}),
);
position_scale.connect_value_changed(
clone!(@strong seeking, @strong position, @strong position_label => move |_| {
if seeking.get() {
let ms = position.get_value() as u64;
let min = ms / 60000;
let sec = (ms % 60000) / 1000;
position_label.set_text(&format!("{}:{:02}", min, sec));
}
}),
);
let current_item = Rc::new(Cell::<usize>::new(0));
let current_track = Rc::new(Cell::<usize>::new(0));
let list = List::new("");
list.set_make_widget(clone!(
@strong current_item,
@strong current_track
=> move |element: &PlaylistElement| {
let title_label = gtk::Label::new(Some(&element.title));
title_label.set_ellipsize(pango::EllipsizeMode::End);
title_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.add(&title_label);
if let Some(subtitle) = &element.subtitle {
let subtitle_label = gtk::Label::new(Some(&subtitle));
subtitle_label.set_ellipsize(pango::EllipsizeMode::End);
subtitle_label.set_halign(gtk::Align::Start);
subtitle_label.set_opacity(0.5);
vbox.add(&subtitle_label);
}
let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 6);
hbox.set_border_width(6);
if element.playable {
let image = gtk::Image::new();
if element.item == current_item.get() && element.track == current_track.get() {
image.set_from_icon_name(
Some("media-playback-start-symbolic"),
gtk::IconSize::Button,
);
}
hbox.add(&image);
} else if element.item > 0 {
hbox.set_margin_top(18);
}
hbox.add(&vbox);
hbox.upcast()
}
));
list.set_selected(clone!(@strong player => move |element| {
if let Some(player) = &*player.borrow() {
player.set_track(element.item, element.track).unwrap();
}
}));
frame.add(&list.widget);
Self {
widget, widget,
title_label, title_label,
subtitle_label, subtitle_label,
@ -185,47 +80,97 @@ impl PlayerScreen {
play_image, play_image,
pause_image, pause_image,
list, list,
player, items: RefCell::new(Vec::new()),
seeking, playlist: RefCell::new(Vec::new()),
current_item, player: RefCell::new(None),
current_track, seeking: Cell::new(false),
back_cb, current_item: Cell::new(0),
} current_track: Cell::new(0),
} back_cb: RefCell::new(None),
pub fn set_player(&self, player: Option<Rc<Player>>) {
self.player.replace(player.clone());
if let Some(player) = player {
let playlist = Rc::new(RefCell::new(Vec::<PlaylistItem>::new()));
player.add_playlist_cb(clone!(
@strong player,
@strong self.previous_button as previous_button,
@strong self.next_button as next_button,
@strong self.list as list,
@strong playlist
=> move |new_playlist| {
playlist.replace(new_playlist);
previous_button.set_sensitive(player.has_previous());
next_button.set_sensitive(player.has_next());
let mut elements = Vec::new();
for (item_index, item) in playlist.borrow().iter().enumerate() {
elements.push(PlaylistElement {
item: item_index,
track: 0,
title: item.track_set.recording.work.get_title(),
subtitle: Some(item.track_set.recording.get_performers()),
playable: false,
}); });
for track_index in &item.indices { back_button.connect_clicked(clone!(@strong this => move |_| {
let track = &item.track_set.tracks[*track_index]; if let Some(cb) = &*this.back_cb.borrow() {
cb();
}
}));
this.previous_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(player) = &*this.player.borrow() {
player.previous().unwrap();
}
}));
this.play_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(player) = &*this.player.borrow() {
player.play_pause();
}
}));
this.next_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(player) = &*this.player.borrow() {
player.next().unwrap();
}
}));
stop_button.connect_clicked(clone!(@strong this => move |_| {
if let Some(player) = &*this.player.borrow() {
if let Some(cb) = &*this.back_cb.borrow() {
cb();
}
player.clear();
}
}));
// position_scale.connect_button_press_event(clone!(@strong seeking => move |_, _| {
// seeking.replace(true);
// Inhibit(false)
// }));
// position_scale.connect_button_release_event(
// clone!(@strong seeking, @strong position, @strong player => move |_, _| {
// if let Some(player) = &*player.borrow() {
// player.seek(position.get_value() as u64);
// }
// seeking.replace(false);
// Inhibit(false)
// }),
// );
position_scale.connect_value_changed(clone!(@strong this => move |_| {
if this.seeking.get() {
let ms = this.position.get_value() as u64;
let min = ms / 60000;
let sec = (ms % 60000) / 1000;
this.position_label.set_text(&format!("{}:{:02}", min, sec));
}
}));
this.list.set_make_widget_cb(clone!(@strong this => move |index| {
match this.items.borrow()[index] {
ListItem::Header(item_index) => {
let playlist_item = &this.playlist.borrow()[item_index];
let recording = &playlist_item.track_set.recording;
let row = libhandy::ActionRow::new();
row.set_activatable(false);
row.set_selectable(false);
row.set_title(Some(&recording.work.get_title()));
row.set_subtitle(Some(&recording.get_performers()));
row.upcast()
}
ListItem::Track(item_index, track_index, playing) => {
let playlist_item = &this.playlist.borrow()[item_index];
let index = playlist_item.indices[track_index];
let track = &playlist_item.track_set.tracks[index];
let mut parts = Vec::<String>::new(); let mut parts = Vec::<String>::new();
for part in &track.work_parts { for part in &track.work_parts {
parts.push(item.track_set.recording.work.parts[*part].title.clone()); parts.push(playlist_item.track_set.recording.work.parts[*part].title.clone());
} }
let title = if parts.is_empty() { let title = if parts.is_empty() {
@ -234,36 +179,102 @@ impl PlayerScreen {
parts.join(", ") parts.join(", ")
}; };
elements.push(PlaylistElement { let row = libhandy::ActionRow::new();
item: item_index, row.set_selectable(false);
track: *track_index, row.set_activatable(true);
title: title, row.set_title(Some(&title));
subtitle: None,
playable: true, row.connect_activated(clone!(@strong this => move |_| {
}); if let Some(player) = &*this.player.borrow() {
player.set_track(item_index, track_index).unwrap();
}
}));
let icon = if playing {
Some("media-playback-start-symbolic")
} else {
None
};
let image = gtk::Image::from_icon_name(icon);
row.add_prefix(&image);
row.upcast()
}
ListItem::Separator => {
let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
separator.upcast()
} }
} }
}));
list.show_items(elements); // list.set_make_widget(clone!(
// @strong current_item,
// @strong current_track
// => move |element: &PlaylistElement| {
// let title_label = gtk::Label::new(Some(&element.title));
// title_label.set_ellipsize(pango::EllipsizeMode::End);
// title_label.set_halign(gtk::Align::Start);
// let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
// vbox.append(&title_label);
// if let Some(subtitle) = &element.subtitle {
// let subtitle_label = gtk::Label::new(Some(&subtitle));
// subtitle_label.set_ellipsize(pango::EllipsizeMode::End);
// subtitle_label.set_halign(gtk::Align::Start);
// subtitle_label.set_opacity(0.5);
// vbox.append(&subtitle_label);
// }
// let hbox = gtk::Box::new(gtk::Orientation::Horizontal, 6);
// hbox.set_margin_top(6);
// hbox.set_margin_bottom(6);
// hbox.set_margin_start(6);
// hbox.set_margin_end(6);
// if element.playable {
// let image = gtk::Image::new();
// if element.item == current_item.get() && element.track == current_track.get() {
// image.set_from_icon_name(
// Some("media-playback-start-symbolic"),
// gtk::IconSize::Button,
// );
// }
// hbox.append(&image);
// } else if element.item > 0 {
// hbox.set_margin_top(18);
// }
// hbox.append(&vbox);
// hbox.upcast()
// }
// ));
// list.set_selected(clone!(@strong player => move |element| {
// if let Some(player) = &*player.borrow() {
// player.set_track(element.item, element.track).unwrap();
// }
// }));
this
} }
));
player.add_track_cb(clone!( pub fn set_player(self: Rc<Self>, player: Option<Rc<Player>>) {
@strong player, self.player.replace(player.clone());
@strong playlist,
@strong self.previous_button as previous_button,
@strong self.next_button as next_button,
@strong self.title_label as title_label,
@strong self.subtitle_label as subtitle_label,
@strong self.position_label as position_label,
@strong self.current_item as self_item,
@strong self.current_track as self_track,
@strong self.list as list
=> move |current_item, current_track| {
previous_button.set_sensitive(player.has_previous());
next_button.set_sensitive(player.has_next());
let item = &playlist.borrow()[current_item]; if let Some(player) = player {
player.add_playlist_cb(clone!(@strong self as this => move |playlist| {
this.playlist.replace(playlist);
this.show_playlist();
}));
player.add_track_cb(clone!(@strong self as this, @strong player => move |current_item, current_track| {
this.previous_button.set_sensitive(player.has_previous());
this.next_button.set_sensitive(player.has_next());
let item = &this.playlist.borrow()[current_item];
let track = &item.track_set.tracks[current_track]; let track = &item.track_set.tracks[current_track];
let mut parts = Vec::<String>::new(); let mut parts = Vec::<String>::new();
@ -276,15 +287,15 @@ impl PlayerScreen {
title = format!("{}: {}", title, parts.join(", ")); title = format!("{}: {}", title, parts.join(", "));
} }
title_label.set_text(&title); this.title_label.set_text(&title);
subtitle_label.set_text(&item.track_set.recording.get_performers()); this.subtitle_label.set_text(&item.track_set.recording.get_performers());
position_label.set_text("0:00"); this.position_label.set_text("0:00");
self_item.replace(current_item); this.current_item.set(current_item);
self_track.replace(current_track); this.current_track.set(current_track);
list.update();
} this.show_playlist();
)); }));
player.add_duration_cb(clone!( player.add_duration_cb(clone!(
@strong self.duration_label as duration_label, @strong self.duration_label as duration_label,
@ -302,15 +313,11 @@ impl PlayerScreen {
@strong self.play_image as play_image, @strong self.play_image as play_image,
@strong self.pause_image as pause_image @strong self.pause_image as pause_image
=> move |playing| { => move |playing| {
if let Some(child) = play_button.get_child() { play_button.set_child(Some(if playing {
play_button.remove( &child);
}
play_button.add(if playing {
&pause_image &pause_image
} else { } else {
&play_image &play_image
}); }));
} }
)); ));
@ -333,4 +340,33 @@ impl PlayerScreen {
pub fn set_back_cb<F: Fn() -> () + 'static>(&self, cb: F) { pub fn set_back_cb<F: Fn() -> () + 'static>(&self, cb: F) {
self.back_cb.replace(Some(Box::new(cb))); self.back_cb.replace(Some(Box::new(cb)));
} }
/// Update the user interface according to the playlist.
fn show_playlist(&self) {
let playlist = self.playlist.borrow();
let current_item = self.current_item.get();
let current_track = self.current_track.get();
let mut first = true;
let mut items = Vec::new();
for (item_index, playlist_item) in playlist.iter().enumerate() {
if !first {
items.push(ListItem::Separator);
} else {
first = false;
}
items.push(ListItem::Header(item_index));
for (index, _) in playlist_item.indices.iter().enumerate() {
let playing = current_item == item_index && current_track == index;
items.push(ListItem::Track(item_index, index, playing));
}
}
let length = items.len();
self.items.replace(items);
self.list.update(length);
}
} }

View file

@ -8,16 +8,28 @@ use gio::prelude::*;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::HeaderBarExt; use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
/// Representation of one entry within the track list.
enum ListItem {
/// A track row. This hold an index to the track set and an index to the
/// track within the track set.
Track(usize, usize),
/// A separator intended for use between track sets.
Separator,
}
pub struct RecordingScreen { pub struct RecordingScreen {
backend: Rc<Backend>, backend: Rc<Backend>,
recording: Recording, recording: Recording,
widget: gtk::Box, widget: gtk::Box,
stack: gtk::Stack, stack: gtk::Stack,
list: Rc<List>,
track_sets: RefCell<Vec<TrackSet>>, track_sets: RefCell<Vec<TrackSet>>,
items: RefCell<Vec<ListItem>>,
navigator: RefCell<Option<Rc<Navigator>>>, navigator: RefCell<Option<Rc<Navigator>>>,
} }
@ -26,14 +38,15 @@ impl RecordingScreen {
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/recording_screen.ui"); let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/recording_screen.ui");
get_widget!(builder, gtk::Box, widget); get_widget!(builder, gtk::Box, widget);
get_widget!(builder, libhandy::HeaderBar, header); get_widget!(builder, gtk::Label, title_label);
get_widget!(builder, gtk::Label, subtitle_label);
get_widget!(builder, gtk::Button, back_button); get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::Stack, stack); get_widget!(builder, gtk::Stack, stack);
get_widget!(builder, gtk::Frame, frame); get_widget!(builder, gtk::Frame, frame);
get_widget!(builder, gtk::Button, add_to_playlist_button); get_widget!(builder, gtk::Button, add_to_playlist_button);
header.set_title(Some(&recording.work.get_title())); title_label.set_label(&recording.work.get_title());
header.set_subtitle(Some(&recording.get_performers())); subtitle_label.set_label(&recording.get_performers());
let edit_action = gio::SimpleAction::new("edit", None); let edit_action = gio::SimpleAction::new("edit", None);
let delete_action = gio::SimpleAction::new("delete", None); let delete_action = gio::SimpleAction::new("delete", None);
@ -48,29 +61,29 @@ impl RecordingScreen {
widget.insert_action_group("widget", Some(&actions)); widget.insert_action_group("widget", Some(&actions));
let list = List::new(&gettext("No tracks found.")); let list = List::new();
frame.add(&list.widget); frame.set_child(Some(&list.widget));
let result = Rc::new(Self { let this = Rc::new(Self {
backend, backend,
recording, recording,
widget, widget,
stack, stack,
list,
track_sets: RefCell::new(Vec::new()), track_sets: RefCell::new(Vec::new()),
items: RefCell::new(Vec::new()),
navigator: RefCell::new(None), navigator: RefCell::new(None),
}); });
list.set_make_widget(clone!(@strong result => move |track_set: &TrackSet| { this.list.set_make_widget_cb(clone!(@strong this => move |index| {
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0); match this.items.borrow()[index] {
vbox.set_border_width(6); ListItem::Track(track_set_index, track_index) => {
vbox.set_spacing(6); let track_set = &this.track_sets.borrow()[track_set_index];
let track = &track_set.tracks[track_index];
for track in &track_set.tracks {
let track_box = gtk::Box::new(gtk::Orientation::Vertical, 0);
let mut title_parts = Vec::<String>::new(); let mut title_parts = Vec::<String>::new();
for part in &track.work_parts { for part in &track.work_parts {
title_parts.push(result.recording.work.parts[*part].title.clone()); title_parts.push(this.recording.work.parts[*part].title.clone());
} }
let title = if title_parts.is_empty() { let title = if title_parts.is_empty() {
@ -79,64 +92,65 @@ impl RecordingScreen {
title_parts.join(", ") title_parts.join(", ")
}; };
let title_label = gtk::Label::new(Some(&title)); let row = libhandy::ActionRow::new();
title_label.set_ellipsize(pango::EllipsizeMode::End); row.set_title(Some(&title));
title_label.set_halign(gtk::Align::Start);
let file_name_label = gtk::Label::new(Some(&track.path)); row.upcast()
file_name_label.set_ellipsize(pango::EllipsizeMode::End); }
file_name_label.set_opacity(0.5); ListItem::Separator => {
file_name_label.set_halign(gtk::Align::Start); let separator = gtk::Separator::new(gtk::Orientation::Horizontal);
separator.upcast()
track_box.add(&title_label); }
track_box.add(&file_name_label);
vbox.add(&track_box);
} }
vbox.upcast()
})); }));
back_button.connect_clicked(clone!(@strong result => move |_| { back_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = result.navigator.borrow().clone(); let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.clone().pop(); navigator.clone().pop();
} }
})); }));
add_to_playlist_button.connect_clicked(clone!(@strong result => move |_| { // TODO: Decide whether to handle multiple track sets.
// if let Some(player) = result.backend.get_player() { add_to_playlist_button.connect_clicked(clone!(@strong this => move |_| {
// player.add_item(PlaylistItem { if let Some(player) = this.backend.get_player() {
// track_set: result.track_sets.get(0).unwrap().clone(), if let Some(track_set) = this.track_sets.borrow().get(0).cloned() {
// indices: result.tracks.borrow().clone(), let indices = (0..track_set.tracks.len()).collect();
// }).unwrap();
// } let playlist_item = PlaylistItem {
track_set,
indices,
};
player.add_item(playlist_item).unwrap();
}
}
})); }));
edit_action.connect_activate(clone!(@strong result => move |_, _| { edit_action.connect_activate(clone!(@strong this => move |_, _| {
let editor = RecordingEditor::new(result.backend.clone(), Some(result.recording.clone())); let editor = RecordingEditor::new(this.backend.clone(), Some(this.recording.clone()));
let window = NavigatorWindow::new(editor); let window = NavigatorWindow::new(editor);
window.show(); window.show();
})); }));
delete_action.connect_activate(clone!(@strong result => move |_, _| { delete_action.connect_activate(clone!(@strong this => move |_, _| {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
clone.backend.db().delete_recording(&clone.recording.id).await.unwrap(); clone.backend.db().delete_recording(&clone.recording.id).await.unwrap();
clone.backend.library_changed(); clone.backend.library_changed();
}); });
})); }));
edit_tracks_action.connect_activate(clone!(@strong result => move |_, _| { edit_tracks_action.connect_activate(clone!(@strong this => move |_, _| {
// let editor = TracksEditor::new(result.backend.clone(), Some(result.recording.clone()), result.tracks.borrow().clone()); // let editor = TracksEditor::new(this.backend.clone(), Some(this.recording.clone()), this.tracks.borrow().clone());
// let window = NavigatorWindow::new(editor); // let window = NavigatorWindow::new(editor);
// window.show(); // window.show();
})); }));
delete_tracks_action.connect_activate(clone!(@strong result => move |_, _| { delete_tracks_action.connect_activate(clone!(@strong this => move |_, _| {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
// clone.backend.db().delete_tracks(&clone.recording.id).await.unwrap(); // clone.backend.db().delete_tracks(&clone.recording.id).await.unwrap();
// clone.backend.library_changed(); // clone.backend.library_changed();
@ -144,7 +158,7 @@ impl RecordingScreen {
})); }));
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
let track_sets = clone let track_sets = clone
.backend .backend
@ -153,12 +167,34 @@ impl RecordingScreen {
.await .await
.unwrap(); .unwrap();
list.show_items(track_sets.clone()); clone.show_track_sets(track_sets);
clone.stack.set_visible_child_name("content"); clone.stack.set_visible_child_name("content");
clone.track_sets.replace(track_sets);
}); });
result this
}
/// Update the track sets variable as well as the user interface.
fn show_track_sets(&self, track_sets: Vec<TrackSet>) {
let mut first = true;
let mut items = Vec::new();
for (track_set_index, track_set) in track_sets.iter().enumerate() {
if !first {
items.push(ListItem::Separator);
} else {
first = false;
}
for (track_index, _) in track_set.tracks.iter().enumerate() {
items.push(ListItem::Track(track_set_index, track_index));
}
}
let length = items.len();
self.items.replace(items);
self.track_sets.replace(track_sets);
self.list.update(length);
} }
} }

View file

@ -3,12 +3,11 @@ use crate::backend::*;
use crate::database::*; use crate::database::*;
use crate::editors::WorkEditor; use crate::editors::WorkEditor;
use crate::widgets::{List, Navigator, NavigatorScreen, NavigatorWindow}; use crate::widgets::{List, Navigator, NavigatorScreen, NavigatorWindow};
use gettextrs::gettext;
use gio::prelude::*; use gio::prelude::*;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::HeaderBarExt; use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -17,7 +16,9 @@ pub struct WorkScreen {
work: Work, work: Work,
widget: gtk::Box, widget: gtk::Box,
stack: gtk::Stack, stack: gtk::Stack,
recording_list: Rc<List<Recording>>, search_entry: gtk::SearchEntry,
recording_list: Rc<List>,
recordings: RefCell<Vec<Recording>>,
navigator: RefCell<Option<Rc<Navigator>>>, navigator: RefCell<Option<Rc<Navigator>>>,
} }
@ -26,14 +27,15 @@ impl WorkScreen {
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/work_screen.ui"); let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/work_screen.ui");
get_widget!(builder, gtk::Box, widget); get_widget!(builder, gtk::Box, widget);
get_widget!(builder, libhandy::HeaderBar, header); get_widget!(builder, gtk::Label, title_label);
get_widget!(builder, gtk::Label, subtitle_label);
get_widget!(builder, gtk::Button, back_button); get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::SearchEntry, search_entry); get_widget!(builder, gtk::SearchEntry, search_entry);
get_widget!(builder, gtk::Stack, stack); get_widget!(builder, gtk::Stack, stack);
get_widget!(builder, gtk::Frame, recording_frame); get_widget!(builder, gtk::Frame, recording_frame);
header.set_title(Some(&work.title)); title_label.set_label(&work.composer.name_fl());
header.set_subtitle(Some(&work.composer.name_fl())); subtitle_label.set_label(&work.title);
let edit_action = gio::SimpleAction::new("edit", None); let edit_action = gio::SimpleAction::new("edit", None);
let delete_action = gio::SimpleAction::new("delete", None); let delete_action = gio::SimpleAction::new("delete", None);
@ -44,73 +46,66 @@ impl WorkScreen {
widget.insert_action_group("widget", Some(&actions)); widget.insert_action_group("widget", Some(&actions));
let recording_list = List::new(&gettext("No recordings found.")); let recording_list = List::new();
recording_frame.set_child(Some(&recording_list.widget));
recording_list.set_make_widget(|recording: &Recording| { let this = Rc::new(Self {
let work_label = gtk::Label::new(Some(&recording.work.get_title()));
work_label.set_ellipsize(pango::EllipsizeMode::End);
work_label.set_halign(gtk::Align::Start);
let performers_label = gtk::Label::new(Some(&recording.get_performers()));
performers_label.set_ellipsize(pango::EllipsizeMode::End);
performers_label.set_opacity(0.5);
performers_label.set_halign(gtk::Align::Start);
let vbox = gtk::Box::new(gtk::Orientation::Vertical, 0);
vbox.set_border_width(6);
vbox.add(&work_label);
vbox.add(&performers_label);
vbox.upcast()
});
recording_list.set_filter(clone!(@strong search_entry => move |recording: &Recording| {
let search = search_entry.get_text().to_string().to_lowercase();
let text = recording.work.get_title().to_lowercase() + &recording.get_performers().to_lowercase();
search.is_empty() || text.contains(&search)
}),);
recording_frame.add(&recording_list.widget);
let result = Rc::new(Self {
backend, backend,
work, work,
widget, widget,
stack, stack,
search_entry,
recording_list, recording_list,
recordings: RefCell::new(Vec::new()),
navigator: RefCell::new(None), navigator: RefCell::new(None),
}); });
search_entry.connect_search_changed(clone!(@strong result => move |_| { this.search_entry.connect_search_changed(clone!(@strong this => move |_| {
result.recording_list.invalidate_filter(); this.recording_list.invalidate_filter();
})); }));
back_button.connect_clicked(clone!(@strong result => move |_| { back_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = result.navigator.borrow().clone(); let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.clone().pop(); navigator.clone().pop();
} }
})); }));
result this.recording_list.set_make_widget_cb(clone!(@strong this => move |index| {
.recording_list let recording = &this.recordings.borrow()[index];
.set_selected(clone!(@strong result => move |recording| {
let navigator = result.navigator.borrow().clone(); let row = libhandy::ActionRow::new();
row.set_activatable(true);
row.set_title(Some(&recording.work.get_title()));
row.set_subtitle(Some(&recording.get_performers()));
let recording = recording.to_owned();
row.connect_activated(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator { if let Some(navigator) = navigator {
navigator.push(RecordingScreen::new(result.backend.clone(), recording.clone())); navigator.push(RecordingScreen::new(this.backend.clone(), recording.clone()));
} }
})); }));
edit_action.connect_activate(clone!(@strong result => move |_, _| { row.upcast()
let editor = WorkEditor::new(result.backend.clone(), Some(result.work.clone())); }));
this.recording_list.set_filter_cb(clone!(@strong this => move |index| {
let recording = &this.recordings.borrow()[index];
let search = this.search_entry.get_text().unwrap().to_string().to_lowercase();
let text = recording.work.get_title() + &recording.get_performers();
search.is_empty() || text.to_lowercase().contains(&search)
}));
edit_action.connect_activate(clone!(@strong this => move |_, _| {
let editor = WorkEditor::new(this.backend.clone(), Some(this.work.clone()));
let window = NavigatorWindow::new(editor); let window = NavigatorWindow::new(editor);
window.show(); window.show();
})); }));
delete_action.connect_activate(clone!(@strong result => move |_, _| { delete_action.connect_activate(clone!(@strong this => move |_, _| {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
clone.backend.db().delete_work(&clone.work.id).await.unwrap(); clone.backend.db().delete_work(&clone.work.id).await.unwrap();
clone.backend.library_changed(); clone.backend.library_changed();
@ -118,7 +113,7 @@ impl WorkScreen {
})); }));
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = result.clone(); let clone = this.clone();
context.spawn_local(async move { context.spawn_local(async move {
let recordings = clone let recordings = clone
.backend .backend
@ -130,12 +125,14 @@ impl WorkScreen {
if recordings.is_empty() { if recordings.is_empty() {
clone.stack.set_visible_child_name("nothing"); clone.stack.set_visible_child_name("nothing");
} else { } else {
clone.recording_list.show_items(recordings); let length = recordings.len();
clone.recordings.replace(recordings);
clone.recording_list.update(length);
clone.stack.set_visible_child_name("content"); clone.stack.set_visible_child_name("content");
} }
}); });
result this
} }
} }

View file

@ -6,6 +6,7 @@ use crate::widgets::{Navigator, NavigatorScreen};
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -63,22 +64,22 @@ impl EnsembleSelector {
async move { clone.backend.db().get_ensembles().await.unwrap() } async move { clone.backend.db().get_ensembles().await.unwrap() }
})); }));
this.selector.set_make_widget(|ensemble| { this.selector.set_make_widget(clone!(@strong this => move |ensemble| {
let label = gtk::Label::new(Some(&ensemble.name)); let row = libhandy::ActionRow::new();
label.set_halign(gtk::Align::Start); row.set_activatable(true);
label.set_margin_start(6); row.set_title(Some(&ensemble.name));
label.set_margin_end(6);
label.set_margin_top(6); let ensemble = ensemble.to_owned();
label.set_margin_bottom(6); row.connect_activated(clone!(@strong this => move |_| {
label.upcast() this.select(&ensemble);
}); }));
row.upcast()
}));
this.selector this.selector
.set_filter(|search, ensemble| ensemble.name.to_lowercase().contains(search)); .set_filter(|search, ensemble| ensemble.name.to_lowercase().contains(search));
this.selector
.set_selected_cb(clone!(@strong this => move |ensemble| this.select(ensemble)));
this this
} }
@ -87,7 +88,7 @@ impl EnsembleSelector {
self.selected_cb.replace(Some(Box::new(cb))); self.selected_cb.replace(Some(Box::new(cb)));
} }
/// Select a ensemble. /// Select an ensemble.
fn select(&self, ensemble: &Ensemble) { fn select(&self, ensemble: &Ensemble) {
if let Some(cb) = &*self.selected_cb.borrow() { if let Some(cb) = &*self.selected_cb.borrow() {
cb(&ensemble); cb(&ensemble);

View file

@ -6,6 +6,7 @@ use crate::widgets::{Navigator, NavigatorScreen};
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -63,22 +64,22 @@ impl InstrumentSelector {
async move { clone.backend.db().get_instruments().await.unwrap() } async move { clone.backend.db().get_instruments().await.unwrap() }
})); }));
this.selector.set_make_widget(|instrument| { this.selector.set_make_widget(clone!(@strong this => move |instrument| {
let label = gtk::Label::new(Some(&instrument.name)); let row = libhandy::ActionRow::new();
label.set_halign(gtk::Align::Start); row.set_activatable(true);
label.set_margin_start(6); row.set_title(Some(&instrument.name));
label.set_margin_end(6);
label.set_margin_top(6); let instrument = instrument.to_owned();
label.set_margin_bottom(6); row.connect_activated(clone!(@strong this => move |_| {
label.upcast() this.select(&instrument);
}); }));
row.upcast()
}));
this.selector this.selector
.set_filter(|search, instrument| instrument.name.to_lowercase().contains(search)); .set_filter(|search, instrument| instrument.name.to_lowercase().contains(search));
this.selector
.set_selected_cb(clone!(@strong this => move |instrument| this.select(instrument)));
this this
} }
@ -87,7 +88,7 @@ impl InstrumentSelector {
self.selected_cb.replace(Some(Box::new(cb))); self.selected_cb.replace(Some(Box::new(cb)));
} }
/// Select a instrument. /// Select an instrument.
fn select(&self, instrument: &Instrument) { fn select(&self, instrument: &Instrument) {
if let Some(cb) = &*self.selected_cb.borrow() { if let Some(cb) = &*self.selected_cb.borrow() {
cb(&instrument); cb(&instrument);

View file

@ -6,6 +6,7 @@ use crate::widgets::{Navigator, NavigatorScreen};
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -63,22 +64,22 @@ impl PersonSelector {
async move { clone.backend.db().get_persons().await.unwrap() } async move { clone.backend.db().get_persons().await.unwrap() }
})); }));
this.selector.set_make_widget(|person| { this.selector.set_make_widget(clone!(@strong this => move |person| {
let label = gtk::Label::new(Some(&person.name_lf())); let row = libhandy::ActionRow::new();
label.set_halign(gtk::Align::Start); row.set_activatable(true);
label.set_margin_start(6); row.set_title(Some(&person.name_lf()));
label.set_margin_end(6);
label.set_margin_top(6); let person = person.to_owned();
label.set_margin_bottom(6); row.connect_activated(clone!(@strong this => move |_| {
label.upcast() this.select(&person);
}); }));
row.upcast()
}));
this.selector this.selector
.set_filter(|search, person| person.name_fl().to_lowercase().contains(search)); .set_filter(|search, person| person.name_fl().to_lowercase().contains(search));
this.selector
.set_selected_cb(clone!(@strong this => move |person| this.select(person)));
this this
} }

View file

@ -6,6 +6,7 @@ use crate::widgets::{Navigator, NavigatorScreen};
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -73,23 +74,23 @@ impl RecordingSelector {
async move { clone.backend.db().get_recordings_for_work(&clone.work.id).await.unwrap() } async move { clone.backend.db().get_recordings_for_work(&clone.work.id).await.unwrap() }
})); }));
this.selector.set_make_widget(|recording| { this.selector.set_make_widget(clone!(@strong this => move |recording| {
let label = gtk::Label::new(Some(&recording.get_performers())); let row = libhandy::ActionRow::new();
label.set_halign(gtk::Align::Start); row.set_activatable(true);
label.set_margin_start(6); row.set_title(Some(&recording.get_performers()));
label.set_margin_end(6);
label.set_margin_top(6); let recording = recording.to_owned();
label.set_margin_bottom(6); row.connect_activated(clone!(@strong this => move |_| {
label.upcast() this.select(&recording);
}); }));
row.upcast()
}));
this.selector.set_filter(|search, recording| { this.selector.set_filter(|search, recording| {
recording.get_performers().to_lowercase().contains(search) recording.get_performers().to_lowercase().contains(search)
}); });
this.selector
.set_selected_cb(clone!(@strong this => move |recording| this.select(recording)));
this this
} }

View file

@ -1,10 +1,8 @@
use crate::widgets::List; use crate::widgets::List;
use anyhow::Result; use anyhow::Result;
use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::HeaderBarExt;
use std::cell::RefCell; use std::cell::RefCell;
use std::future::Future; use std::future::Future;
use std::pin::Pin; use std::pin::Pin;
@ -14,12 +12,16 @@ use std::rc::Rc;
/// database and to search within the list. /// database and to search within the list.
pub struct Selector<T: 'static> { pub struct Selector<T: 'static> {
pub widget: gtk::Box, pub widget: gtk::Box,
header: libhandy::HeaderBar, title_label: gtk::Label,
subtitle_label: gtk::Label,
search_entry: gtk::SearchEntry,
server_check_button: gtk::CheckButton, server_check_button: gtk::CheckButton,
stack: gtk::Stack, stack: gtk::Stack,
list: Rc<List<T>>, list: Rc<List>,
items: RefCell<Vec<T>>,
back_cb: RefCell<Option<Box<dyn Fn() -> ()>>>, back_cb: RefCell<Option<Box<dyn Fn() -> ()>>>,
add_cb: RefCell<Option<Box<dyn Fn() -> ()>>>, add_cb: RefCell<Option<Box<dyn Fn() -> ()>>>,
make_widget: RefCell<Option<Box<dyn Fn(&T) -> gtk::Widget>>>,
load_online: RefCell<Option<Box<dyn Fn() -> Box<dyn Future<Output = Result<Vec<T>>>>>>>, load_online: RefCell<Option<Box<dyn Fn() -> Box<dyn Future<Output = Result<Vec<T>>>>>>>,
load_local: RefCell<Option<Box<dyn Fn() -> Box<dyn Future<Output = Vec<T>>>>>>, load_local: RefCell<Option<Box<dyn Fn() -> Box<dyn Future<Output = Vec<T>>>>>>,
filter: RefCell<Option<Box<dyn Fn(&str, &T) -> bool>>>, filter: RefCell<Option<Box<dyn Fn(&str, &T) -> bool>>>,
@ -33,7 +35,8 @@ impl<T> Selector<T> {
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/selector.ui"); let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/selector.ui");
get_widget!(builder, gtk::Box, widget); get_widget!(builder, gtk::Box, widget);
get_widget!(builder, libhandy::HeaderBar, header); get_widget!(builder, gtk::Label, title_label);
get_widget!(builder, gtk::Label, subtitle_label);
get_widget!(builder, gtk::Button, back_button); get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::Button, add_button); get_widget!(builder, gtk::Button, add_button);
get_widget!(builder, gtk::SearchEntry, search_entry); get_widget!(builder, gtk::SearchEntry, search_entry);
@ -42,17 +45,21 @@ impl<T> Selector<T> {
get_widget!(builder, gtk::Frame, frame); get_widget!(builder, gtk::Frame, frame);
get_widget!(builder, gtk::Button, try_again_button); get_widget!(builder, gtk::Button, try_again_button);
let list = List::<T>::new(&gettext("Nothing found.")); let list = List::new();
frame.add(&list.widget); frame.set_child(Some(&list.widget));
let this = Rc::new(Self { let this = Rc::new(Self {
widget, widget,
header, title_label,
subtitle_label,
search_entry,
server_check_button, server_check_button,
stack, stack,
list, list,
items: RefCell::new(Vec::new()),
back_cb: RefCell::new(None), back_cb: RefCell::new(None),
add_cb: RefCell::new(None), add_cb: RefCell::new(None),
make_widget: RefCell::new(None),
load_online: RefCell::new(None), load_online: RefCell::new(None),
load_local: RefCell::new(None), load_local: RefCell::new(None),
filter: RefCell::new(None), filter: RefCell::new(None),
@ -72,7 +79,7 @@ impl<T> Selector<T> {
} }
})); }));
search_entry.connect_search_changed(clone!(@strong this => move |_| { this.search_entry.connect_search_changed(clone!(@strong this => move |_| {
this.list.invalidate_filter(); this.list.invalidate_filter();
})); }));
@ -85,17 +92,25 @@ impl<T> Selector<T> {
} }
})); }));
this.list.set_filter( this.list.set_make_widget_cb(clone!(@strong this => move |index| {
clone!(@strong this, @strong search_entry => move |item: &T| { if let Some(cb) = &*this.make_widget.borrow() {
let item = &this.items.borrow()[index];
cb(item)
} else {
gtk::Label::new(None).upcast()
}
}));
this.list.set_filter_cb(clone!(@strong this => move |index| {
match &*this.filter.borrow() { match &*this.filter.borrow() {
Some(filter) => { Some(filter) => {
let search = search_entry.get_text().to_string().to_lowercase(); let item = &this.items.borrow()[index];
let search = this.search_entry.get_text().unwrap().to_string().to_lowercase();
search.is_empty() || filter(&search, item) search.is_empty() || filter(&search, item)
} }
None => true, None => true,
} }
}), }));
);
try_again_button.connect_clicked(clone!(@strong this => move |_| { try_again_button.connect_clicked(clone!(@strong this => move |_| {
this.clone().load_online(); this.clone().load_online();
@ -109,12 +124,13 @@ impl<T> Selector<T> {
/// Set the title to be shown in the header. /// Set the title to be shown in the header.
pub fn set_title(&self, title: &str) { pub fn set_title(&self, title: &str) {
self.header.set_title(Some(title)); self.title_label.set_label(&title);
} }
/// Set the subtitle to be shown in the header. /// Set the subtitle to be shown in the header.
pub fn set_subtitle(&self, subtitle: &str) { pub fn set_subtitle(&self, subtitle: &str) {
self.header.set_subtitle(Some(subtitle)); self.subtitle_label.set_label(&subtitle);
self.subtitle_label.show();
} }
/// Set the closure to be called when the user wants to go back. /// Set the closure to be called when the user wants to go back.
@ -150,7 +166,7 @@ impl<T> Selector<T> {
/// Set the closure to be called for creating a new list row. /// Set the closure to be called for creating a new list row.
pub fn set_make_widget<F: Fn(&T) -> gtk::Widget + 'static>(&self, make_widget: F) { pub fn set_make_widget<F: Fn(&T) -> gtk::Widget + 'static>(&self, make_widget: F) {
self.list.set_make_widget(make_widget); self.make_widget.replace(Some(Box::new(make_widget)));
} }
/// Set a closure to call when deciding whether to show an item based on a search string. The /// Set a closure to call when deciding whether to show an item based on a search string. The
@ -159,11 +175,6 @@ impl<T> Selector<T> {
self.filter.replace(Some(Box::new(filter))); self.filter.replace(Some(Box::new(filter)));
} }
/// Set the closure to be called when an item is selected.
pub fn set_selected_cb<F: Fn(&T) -> () + 'static>(&self, cb: F) {
self.list.set_selected(cb);
}
fn load_online(self: Rc<Self>) { fn load_online(self: Rc<Self>) {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let clone = self.clone(); let clone = self.clone();
@ -173,11 +184,10 @@ impl<T> Selector<T> {
match Pin::from(cb()).await { match Pin::from(cb()).await {
Ok(items) => { Ok(items) => {
clone.list.show_items(items); clone.show_items(items);
clone.stack.set_visible_child_name("content");
} }
Err(_) => { Err(_) => {
clone.list.show_items(Vec::new()); clone.show_items(Vec::new());
clone.stack.set_visible_child_name("error"); clone.stack.set_visible_child_name("error");
} }
} }
@ -193,9 +203,15 @@ impl<T> Selector<T> {
self.stack.set_visible_child_name("loading"); self.stack.set_visible_child_name("loading");
let items = Pin::from(cb()).await; let items = Pin::from(cb()).await;
clone.list.show_items(items); clone.show_items(items);
clone.stack.set_visible_child_name("content");
} }
}); });
} }
fn show_items(&self, items: Vec<T>) {
let length = items.len();
self.items.replace(items);
self.list.update(length);
self.stack.set_visible_child_name("content");
}
} }

View file

@ -6,6 +6,7 @@ use crate::widgets::{Navigator, NavigatorScreen};
use gettextrs::gettext; use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use libhandy::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
@ -73,22 +74,22 @@ impl WorkSelector {
async move { clone.backend.db().get_works(&clone.person.id).await.unwrap() } async move { clone.backend.db().get_works(&clone.person.id).await.unwrap() }
})); }));
this.selector.set_make_widget(|work| { this.selector.set_make_widget(clone!(@strong this => move |work| {
let label = gtk::Label::new(Some(&work.title)); let row = libhandy::ActionRow::new();
label.set_halign(gtk::Align::Start); row.set_activatable(true);
label.set_margin_start(6); row.set_title(Some(&work.title));
label.set_margin_end(6);
label.set_margin_top(6); let work = work.to_owned();
label.set_margin_bottom(6); row.connect_activated(clone!(@strong this => move |_| {
label.upcast() this.select(&work);
}); }));
row.upcast()
}));
this.selector this.selector
.set_filter(|search, work| work.title.to_lowercase().contains(search)); .set_filter(|search, work| work.title.to_lowercase().contains(search));
this.selector
.set_selected_cb(clone!(@strong this => move |work| this.select(work)));
this this
} }

View file

@ -0,0 +1,189 @@
use glib::prelude::*;
use glib::subclass;
use glib::subclass::prelude::*;
use gio::prelude::*;
use gio::subclass::prelude::*;
use std::cell::Cell;
glib::wrapper! {
pub struct IndexedListModel(ObjectSubclass<indexed_list_model::IndexedListModel>)
@implements gio::ListModel;
}
impl IndexedListModel {
/// Create a new indexed list model, which will be empty initially.
pub fn new() -> Self {
glib::Object::new(&[]).unwrap()
}
/// Set the length of the list model.
pub fn set_length(&self, length: u32) {
let old_length = self.get_property("length").unwrap().get_some::<u32>().unwrap();
self.set_property("length", &length).unwrap();
self.items_changed(0, old_length, length);
}
}
mod indexed_list_model {
use super::*;
#[derive(Debug)]
pub struct IndexedListModel {
length: Cell<u32>,
}
static PROPERTIES: [subclass::Property; 1] = [
subclass::Property("length", |length| {
glib::ParamSpec::uint(
length,
"Length",
"Length",
0,
std::u32::MAX,
0,
glib::ParamFlags::READWRITE,
)
}),
];
impl ObjectSubclass for IndexedListModel {
const NAME: &'static str = "IndexedListModel";
type Type = super::IndexedListModel;
type ParentType = glib::Object;
type Instance = subclass::simple::InstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
fn type_init(type_: &mut subclass::InitializingType<Self>) {
type_.add_interface::<gio::ListModel>();
}
fn class_init(klass: &mut Self::Class) {
klass.install_properties(&PROPERTIES);
}
fn new() -> Self {
Self { length: Cell::new(0) }
}
}
impl ObjectImpl for IndexedListModel {
fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
let prop = &PROPERTIES[id];
match *prop {
subclass::Property("length", ..) => {
let length = value.get().unwrap().unwrap();
self.length.set(length);
}
_ => unimplemented!(),
}
}
fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
let prop = &PROPERTIES[id];
match *prop {
subclass::Property("length", ..) => self.length.get().to_value(),
_ => unimplemented!(),
}
}
}
impl ListModelImpl for IndexedListModel {
fn get_item_type(&self, _: &Self::Type) -> glib::Type {
ItemIndex::static_type()
}
fn get_n_items(&self, _: &Self::Type) -> u32 {
self.length.get()
}
fn get_item(&self, _: &Self::Type, position: u32) -> Option<glib::Object> {
Some(ItemIndex::new(position).upcast())
}
}
}
glib::wrapper! {
pub struct ItemIndex(ObjectSubclass<item_index::ItemIndex>);
}
impl ItemIndex {
/// Create a new item index.
pub fn new(value: u32) -> Self {
glib::Object::new(&[("value", &value)]).unwrap()
}
/// Get the value of the item index..
pub fn get(&self) -> u32 {
self.get_property("value").unwrap().get_some::<u32>().unwrap()
}
}
mod item_index {
use super::*;
#[derive(Debug)]
pub struct ItemIndex {
value: Cell<u32>,
}
static PROPERTIES: [subclass::Property; 1] = [
subclass::Property("value", |value| {
glib::ParamSpec::uint(
value,
"Value",
"Value",
0,
std::u32::MAX,
0,
glib::ParamFlags::READWRITE,
)
}),
];
impl ObjectSubclass for ItemIndex {
const NAME: &'static str = "ItemIndex";
type Type = super::ItemIndex;
type ParentType = glib::Object;
type Instance = subclass::simple::InstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib::object_subclass!();
fn class_init(klass: &mut Self::Class) {
klass.install_properties(&PROPERTIES);
}
fn new() -> Self {
Self { value: Cell::new(0) }
}
}
impl ObjectImpl for ItemIndex {
fn set_property(&self, _obj: &Self::Type, id: usize, value: &glib::Value) {
let prop = &PROPERTIES[id];
match *prop {
subclass::Property("value", ..) => {
let value = value.get().unwrap().unwrap();
self.value.set(value);
}
_ => unimplemented!(),
}
}
fn get_property(&self, _obj: &Self::Type, id: usize) -> glib::Value {
let prop = &PROPERTIES[id];
match *prop {
subclass::Property("value", ..) => self.value.get().to_value(),
_ => unimplemented!(),
}
}
}
}

View file

@ -1,139 +1,88 @@
use super::*; use super::indexed_list_model::{IndexedListModel, ItemIndex};
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use std::cell::RefCell; use std::cell::RefCell;
use std::convert::TryInto;
use std::rc::Rc; use std::rc::Rc;
pub struct List<T> /// A simple list of widgets.
where pub struct List {
T: 'static,
{
pub widget: gtk::ListBox, pub widget: gtk::ListBox,
items: RefCell<Vec<T>>, model: IndexedListModel,
make_widget: RefCell<Option<Box<dyn Fn(&T) -> gtk::Widget>>>, filter: gtk::CustomFilter,
filter: RefCell<Option<Box<dyn Fn(&T) -> bool>>>, make_widget_cb: RefCell<Option<Box<dyn Fn(usize) -> gtk::Widget>>>,
selected: RefCell<Option<Box<dyn Fn(&T) -> ()>>>, filter_cb: RefCell<Option<Box<dyn Fn(usize) -> bool>>>,
} }
impl<T> List<T> impl List {
where /// Create a new list. The list will be empty initially.
T: 'static, pub fn new() -> Rc<Self> {
{ let model = IndexedListModel::new();
pub fn new(placeholder_text: &str) -> Rc<Self> { let filter = gtk::CustomFilter::new(|_| true);
let placeholder_label = gtk::Label::new(Some(placeholder_text)); let filter_model = gtk::FilterListModel::new(Some(&model), Some(&filter));
placeholder_label.set_margin_top(6);
placeholder_label.set_margin_bottom(6); // TODO: Switch to gtk::ListView.
placeholder_label.set_margin_start(6); // let selection = gtk::NoSelection::new(Some(&model));
placeholder_label.set_margin_end(6); // let factory = gtk::SignalListItemFactory::new();
placeholder_label.show(); // let widget = gtk::ListView::new(Some(&selection), Some(&factory));
let widget = gtk::ListBox::new(); let widget = gtk::ListBox::new();
widget.set_placeholder(Some(&placeholder_label));
widget.show();
let this = Rc::new(Self { let this = Rc::new(Self {
widget, widget,
items: RefCell::new(Vec::new()), model,
make_widget: RefCell::new(None), filter,
filter: RefCell::new(None), make_widget_cb: RefCell::new(None),
selected: RefCell::new(None), filter_cb: RefCell::new(None),
}); });
this.widget this.filter.set_filter_func(clone!(@strong this => move |index| {
.connect_row_activated(clone!(@strong this => move |_, row| { if let Some(cb) = &*this.filter_cb.borrow() {
if let Some(selected) = &*this.selected.borrow() { let index = index.downcast_ref::<ItemIndex>().unwrap().get() as usize;
let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap(); cb(index)
let index: usize = row.get_index().try_into().unwrap();
selected(&this.items.borrow()[index]);
}
}));
this.widget
.set_filter_func(Some(Box::new(clone!(@strong this => move |row| {
if let Some(filter) = &*this.filter.borrow() {
let row = row.get_child().unwrap().downcast::<SelectorRow>().unwrap();
let index: usize = row.get_index().try_into().unwrap();
filter(&this.items.borrow()[index])
} else { } else {
true true
} }
})))); }));
this.widget.bind_model(Some(&filter_model), clone!(@strong this => move |index| {
let index = index.downcast_ref::<ItemIndex>().unwrap().get() as usize;
if let Some(cb) = &*this.make_widget_cb.borrow() {
cb(index)
} else {
gtk::Label::new(None).upcast()
}
}));
this this
} }
pub fn set_selectable(&self, selectable: bool) { /// Set the closure to be called to construct widgets for the items.
let mode = if selectable { pub fn set_make_widget_cb<F: Fn(usize) -> gtk::Widget + 'static>(&self, cb: F) {
gtk::SelectionMode::Single self.make_widget_cb.replace(Some(Box::new(cb)));
} else {
gtk::SelectionMode::None
};
self.widget.set_selection_mode(mode);
} }
pub fn set_make_widget<F: Fn(&T) -> gtk::Widget + 'static>(&self, make_widget: F) { /// Set the closure to be called to filter the items. If this returns
self.make_widget.replace(Some(Box::new(make_widget))); /// false, the item will not be shown.
pub fn set_filter_cb<F: Fn(usize) -> bool + 'static>(&self, cb: F) {
self.filter_cb.replace(Some(Box::new(cb)));
} }
pub fn set_filter<F: Fn(&T) -> bool + 'static>(&self, filter: F) { /// Select an item by its index. If the index is out of range, nothing will happen.
self.filter.replace(Some(Box::new(filter))); pub fn select(&self, index: usize) {
} let row = self.widget.get_row_at_index(index as i32);
if let Some(row) = row {
pub fn set_selected<S: Fn(&T) -> () + 'static>(&self, selected: S) { self.widget.select_row(Some(&row));
self.selected.replace(Some(Box::new(selected)));
}
pub fn get_selected_index(&self) -> Option<usize> {
match self.widget.get_selected_rows().first() {
Some(row) => match row.get_child() {
Some(child) => Some(
child
.downcast::<SelectorRow>()
.unwrap()
.get_index()
.try_into()
.unwrap(),
),
None => None,
},
None => None,
} }
} }
pub fn select_index(&self, index: usize) { /// Refilter the list based on the filter callback.
self.widget.select_row(
self.widget
.get_row_at_index(index.try_into().unwrap())
.as_ref(),
);
}
pub fn show_items(&self, items: Vec<T>) {
self.items.replace(items);
self.update();
}
pub fn invalidate_filter(&self) { pub fn invalidate_filter(&self) {
self.widget.invalidate_filter(); self.filter.changed(gtk::FilterChange::Different);
} }
pub fn update(&self) { /// Call the make_widget function for each item. This will automatically
for child in self.widget.get_children() { /// show all children by indices 0..length.
self.widget.remove(&child); pub fn update(&self, length: usize) {
} self.model.set_length(length as u32);
if let Some(make_widget) = &*self.make_widget.borrow() {
for (index, item) in self.items.borrow().iter().enumerate() {
let row = SelectorRow::new(index.try_into().unwrap(), &make_widget(item));
row.show_all();
self.widget.insert(&row, -1);
}
}
}
pub fn clear_selection(&self) {
self.widget.unselect_all();
} }
} }

View file

@ -7,13 +7,10 @@ pub use navigator::*;
pub mod navigator_window; pub mod navigator_window;
pub use navigator_window::*; pub use navigator_window::*;
pub mod new_list;
pub mod player_bar; pub mod player_bar;
pub use player_bar::*; pub use player_bar::*;
pub mod poe_list; pub mod poe_list;
pub use poe_list::*; pub use poe_list::*;
pub mod selector_row; mod indexed_list_model;
pub use selector_row::*;

View file

@ -29,7 +29,7 @@ impl Navigator {
widget.set_interpolate_size(true); widget.set_interpolate_size(true);
widget.set_transition_type(gtk::StackTransitionType::Crossfade); widget.set_transition_type(gtk::StackTransitionType::Crossfade);
widget.set_hexpand(true); widget.set_hexpand(true);
widget.add_named(empty_screen, "empty_screen"); widget.add_named(empty_screen, Some("empty_screen"));
widget.show(); widget.show();
let result = Rc::new(Self { let result = Rc::new(Self {
@ -70,7 +70,7 @@ impl Navigator {
} }
let widget = screen.get_widget(); let widget = screen.get_widget();
self.widget.add(&widget); self.widget.add_child(&widget);
self.widget.set_visible_child(&widget); self.widget.set_visible_child(&widget);
screen.attach_navigator(self.clone()); screen.attach_navigator(self.clone());
@ -116,7 +116,7 @@ impl Navigator {
} }
let widget = screen.get_widget(); let widget = screen.get_widget();
self.widget.add(&widget); self.widget.add_child(&widget);
self.widget.set_visible_child(&widget); self.widget.set_visible_child(&widget);
screen.attach_navigator(self.clone()); screen.attach_navigator(self.clone());

View file

@ -18,7 +18,7 @@ impl NavigatorWindow {
window.set_default_size(600, 424); window.set_default_size(600, 424);
let placeholder = gtk::Label::new(None); let placeholder = gtk::Label::new(None);
let navigator = Navigator::new(&window, &placeholder); let navigator = Navigator::new(&window, &placeholder);
window.add(&navigator.widget); libhandy::WindowExt::set_child(&window, Some(&navigator.widget));
let this = Rc::new(Self { window, navigator }); let this = Rc::new(Self { window, navigator });

View file

@ -1,50 +0,0 @@
use gtk::prelude::*;
use std::cell::RefCell;
/// A simple list of widgets.
pub struct List {
pub widget: gtk::ListBox,
make_widget: RefCell<Option<Box<dyn Fn(usize) -> gtk::Widget>>>,
}
impl List {
/// Create a new list. The list will be empty.
pub fn new(placeholder_text: &str) -> Self {
let placeholder_label = gtk::Label::new(Some(placeholder_text));
placeholder_label.set_margin_top(6);
placeholder_label.set_margin_bottom(6);
placeholder_label.set_margin_start(6);
placeholder_label.set_margin_end(6);
placeholder_label.show();
let widget = gtk::ListBox::new();
widget.set_selection_mode(gtk::SelectionMode::None);
widget.set_placeholder(Some(&placeholder_label));
widget.show();
Self {
widget,
make_widget: RefCell::new(None),
}
}
/// Set the closure to be called to construct widgets for the items.
pub fn set_make_widget<F: Fn(usize) -> gtk::Widget + 'static>(&self, make_widget: F) {
self.make_widget.replace(Some(Box::new(make_widget)));
}
/// Call the make_widget function for each item. This will automatically
/// show all children by indices 0..length.
pub fn update(&self, length: usize) {
for child in self.widget.get_children() {
self.widget.remove(&child);
}
if let Some(make_widget) = &*self.make_widget.borrow() {
for index in 0..length {
let row = make_widget(index);
self.widget.insert(&row, -1);
}
}
}
}

View file

@ -144,15 +144,11 @@ impl PlayerBar {
@strong self.play_image as play_image, @strong self.play_image as play_image,
@strong self.pause_image as pause_image @strong self.pause_image as pause_image
=> move |playing| { => move |playing| {
if let Some(child) = play_button.get_child() { play_button.set_child(Some(if playing {
play_button.remove( &child);
}
play_button.add(if playing {
&pause_image &pause_image
} else { } else {
&play_image &play_image
}); }));
} }
)); ));

View file

@ -1,10 +1,11 @@
use super::*; use super::*;
use crate::backend::Backend; use crate::backend::Backend;
use crate::database::*; use crate::database::*;
use gettextrs::gettext;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::get_widget; use gtk_macros::get_widget;
use libhandy::prelude::*;
use std::cell::RefCell;
use std::rc::Rc; use std::rc::Rc;
#[derive(Clone)] #[derive(Clone)]
@ -24,9 +25,12 @@ impl PersonOrEnsemble {
pub struct PoeList { pub struct PoeList {
pub widget: gtk::Box, pub widget: gtk::Box,
list: Rc<List<PersonOrEnsemble>>,
backend: Rc<Backend>, backend: Rc<Backend>,
stack: gtk::Stack, stack: gtk::Stack,
search_entry: gtk::SearchEntry,
list: Rc<List>,
data: RefCell<Vec<PersonOrEnsemble>>,
selected_cb: RefCell<Option<Box<dyn Fn(&PersonOrEnsemble)>>>,
} }
impl PoeList { impl PoeList {
@ -38,47 +42,54 @@ impl PoeList {
get_widget!(builder, gtk::Stack, stack); get_widget!(builder, gtk::Stack, stack);
get_widget!(builder, gtk::ScrolledWindow, scrolled_window); get_widget!(builder, gtk::ScrolledWindow, scrolled_window);
let list = List::new(&gettext("No persons or ensembles found.")); let list = List::new();
list.widget.add_css_class("navigation-sidebar");
list.set_make_widget(|poe: &PersonOrEnsemble| { scrolled_window.set_child(Some(&list.widget));
let label = gtk::Label::new(Some(&poe.get_title()));
label.set_halign(gtk::Align::Start);
label.set_margin_start(6);
label.set_margin_end(6);
label.set_margin_top(6);
label.set_margin_bottom(6);
label.upcast()
});
list.set_filter( let this = Rc::new(Self {
clone!(@strong search_entry => move |poe: &PersonOrEnsemble| {
let search = search_entry.get_text().to_string().to_lowercase();
let title = poe.get_title().to_lowercase();
search.is_empty() || title.contains(&search)
}),
);
scrolled_window.add(&list.widget);
let result = Rc::new(Self {
widget, widget,
list,
backend, backend,
stack, stack,
search_entry,
list,
data: RefCell::new(Vec::new()),
selected_cb: RefCell::new(None),
}); });
search_entry.connect_search_changed(clone!(@strong result => move |_| { this.search_entry.connect_search_changed(clone!(@strong this => move |_| {
result.list.invalidate_filter(); this.list.invalidate_filter();
})); }));
result this.list.set_make_widget_cb(clone!(@strong this => move |index| {
let poe = &this.data.borrow()[index];
let row = libhandy::ActionRow::new();
row.set_activatable(true);
row.set_title(Some(&poe.get_title()));
let poe = poe.to_owned();
row.connect_activated(clone!(@strong this => move |_| {
if let Some(cb) = &*this.selected_cb.borrow() {
cb(&poe);
}
}));
row.upcast()
}));
this.list.set_filter_cb(clone!(@strong this => move |index| {
let poe = &this.data.borrow()[index];
let search = this.search_entry.get_text().unwrap().to_string().to_lowercase();
let title = poe.get_title().to_lowercase();
search.is_empty() || title.contains(&search)
}));
this
} }
pub fn set_selected<S>(&self, selected: S) pub fn set_selected_cb<F: Fn(&PersonOrEnsemble) + 'static>(&self, cb: F) {
where self.selected_cb.replace(Some(Box::new(cb)));
S: Fn(&PersonOrEnsemble) -> () + 'static,
{
self.list.set_selected(selected);
} }
pub fn reload(self: Rc<Self>) { pub fn reload(self: Rc<Self>) {
@ -86,7 +97,6 @@ impl PoeList {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let backend = self.backend.clone(); let backend = self.backend.clone();
let list = self.list.clone();
context.spawn_local(async move { context.spawn_local(async move {
let persons = backend.db().get_persons().await.unwrap(); let persons = backend.db().get_persons().await.unwrap();
@ -101,7 +111,9 @@ impl PoeList {
poes.push(PersonOrEnsemble::Ensemble(ensemble)); poes.push(PersonOrEnsemble::Ensemble(ensemble));
} }
list.show_items(poes); let length = poes.len();
self.data.replace(poes);
self.list.update(length);
self.stack.set_visible_child_name("content"); self.stack.set_visible_child_name("content");
}); });

View file

@ -1,149 +0,0 @@
use glib::prelude::*;
use glib::subclass;
use glib::subclass::prelude::*;
use glib::translate::*;
use glib::{glib_object_impl, glib_object_subclass, glib_wrapper};
use gtk::prelude::*;
use gtk::subclass::prelude::*;
use std::cell::{Cell, RefCell};
glib_wrapper! {
pub struct SelectorRow(
Object<subclass::simple::InstanceStruct<SelectorRowPriv>,
subclass::simple::ClassStruct<SelectorRowPriv>,
SelectorRowClass>
) @extends gtk::Bin, gtk::Container, gtk::Widget;
match fn {
get_type => || SelectorRowPriv::get_type().to_glib(),
}
}
impl SelectorRow {
pub fn new<T: IsA<gtk::Widget>>(index: u64, child: &T) -> Self {
glib::Object::new(
Self::static_type(),
&[("index", &index), ("child", child.upcast_ref())],
)
.expect("Failed to create SelectorRow GObject!")
.downcast()
.expect("SelectorRow GObject is of the wrong type!")
}
pub fn get_index(&self) -> u64 {
self.get_property("index").unwrap().get().unwrap().unwrap()
}
}
pub struct SelectorRowPriv {
index: Cell<u64>,
child: RefCell<Option<gtk::Widget>>,
}
static PROPERTIES: [subclass::Property; 2] = [
subclass::Property("index", |name| {
glib::ParamSpec::uint64(
name,
"Index",
"Index",
0,
u64::MAX,
0,
glib::ParamFlags::READWRITE,
)
}),
subclass::Property("child", |name| {
glib::ParamSpec::object(
name,
"Child",
"Child",
gtk::Widget::static_type(),
glib::ParamFlags::READWRITE,
)
}),
];
impl ObjectSubclass for SelectorRowPriv {
const NAME: &'static str = "SelectorRow";
type ParentType = gtk::Bin;
type Instance = subclass::simple::InstanceStruct<Self>;
type Class = subclass::simple::ClassStruct<Self>;
glib_object_subclass!();
fn class_init(klass: &mut Self::Class) {
klass.install_properties(&PROPERTIES);
}
fn new() -> Self {
Self {
index: Cell::new(0),
child: RefCell::new(None),
}
}
}
impl ObjectImpl for SelectorRowPriv {
glib_object_impl!();
fn constructed(&self, object: &glib::Object) {
self.parent_constructed(object);
let row = object.downcast_ref::<SelectorRow>().unwrap();
let child = self.child.borrow();
match child.as_ref() {
Some(child) => row.add(child),
None => (),
}
}
fn set_property(&self, object: &glib::Object, id: usize, value: &glib::Value) {
let prop = &PROPERTIES[id];
match *prop {
subclass::Property("index", ..) => {
let index = value
.get_some()
.expect("Wrong type for SelectorRow GObject index property!");
self.index.set(index);
}
subclass::Property("child", ..) => {
let child = value
.get()
.expect("Wrong type for SelectorRow GObject child property!");
let row = object.downcast_ref::<SelectorRow>().unwrap();
{
let old = self.child.borrow();
match old.as_ref() {
Some(old) => row.remove(old),
None => (),
}
}
self.child.replace(child.clone());
match child {
Some(child) => row.add(&child),
None => (),
}
}
_ => unimplemented!(),
}
}
fn get_property(&self, _obj: &glib::Object, id: usize) -> Result<glib::Value, ()> {
let prop = &PROPERTIES[id];
match *prop {
subclass::Property("index", ..) => Ok(self.index.get().to_value()),
subclass::Property("child", ..) => Ok(self.child.borrow().to_value()),
_ => unimplemented!(),
}
}
}
impl WidgetImpl for SelectorRowPriv {}
impl ContainerImpl for SelectorRowPriv {}
impl BinImpl for SelectorRowPriv {}

View file

@ -9,7 +9,6 @@ use gio::prelude::*;
use glib::clone; use glib::clone;
use gtk::prelude::*; use gtk::prelude::*;
use gtk_macros::{action, get_widget}; use gtk_macros::{action, get_widget};
use libhandy::prelude::*;
use std::rc::Rc; use std::rc::Rc;
pub struct Window { pub struct Window {
@ -21,7 +20,7 @@ pub struct Window {
poe_list: Rc<PoeList>, poe_list: Rc<PoeList>,
navigator: Rc<Navigator>, navigator: Rc<Navigator>,
player_bar: PlayerBar, player_bar: PlayerBar,
player_screen: PlayerScreen, player_screen: Rc<PlayerScreen>,
} }
impl Window { impl Window {
@ -40,7 +39,7 @@ impl Window {
let backend = Rc::new(Backend::new()); let backend = Rc::new(Backend::new());
let player_screen = PlayerScreen::new(); let player_screen = PlayerScreen::new();
stack.add_named(&player_screen.widget, "player_screen"); stack.add_named(&player_screen.widget, Some("player_screen"));
let poe_list = PoeList::new(backend.clone()); let poe_list = PoeList::new(backend.clone());
let navigator = Navigator::new(&window, &empty_screen); let navigator = Navigator::new(&window, &empty_screen);
@ -49,7 +48,7 @@ impl Window {
})); }));
let player_bar = PlayerBar::new(); let player_bar = PlayerBar::new();
content_box.add(&player_bar.widget); content_box.append(&player_bar.widget);
let result = Rc::new(Self { let result = Rc::new(Self {
backend, backend,
@ -73,8 +72,10 @@ impl Window {
None, None,
None); None);
if let gtk::ResponseType::Accept = dialog.run() { dialog.connect_response(clone!(@strong result => move |dialog, response| {
if let Some(path) = dialog.get_filename() { if response == gtk::ResponseType::Accept {
if let Some(file) = dialog.get_file() {
if let Some(path) = file.get_path() {
let context = glib::MainContext::default(); let context = glib::MainContext::default();
let backend = result.backend.clone(); let backend = result.backend.clone();
context.spawn_local(async move { context.spawn_local(async move {
@ -82,6 +83,10 @@ impl Window {
}); });
} }
} }
}
}));
dialog.show();
})); }));
add_button.connect_clicked(clone!(@strong result => move |_| { add_button.connect_clicked(clone!(@strong result => move |_| {
@ -156,7 +161,7 @@ impl Window {
let player = clone.backend.get_player().unwrap(); let player = clone.backend.get_player().unwrap();
clone.player_bar.set_player(Some(player.clone())); clone.player_bar.set_player(Some(player.clone()));
clone.player_screen.set_player(Some(player)); clone.player_screen.clone().set_player(Some(player));
} }
} }
} }
@ -169,11 +174,11 @@ impl Window {
clone.backend.clone().init().await.unwrap(); clone.backend.clone().init().await.unwrap();
}); });
result.leaflet.add(&result.navigator.widget); result.leaflet.append(&result.navigator.widget);
result result
.poe_list .poe_list
.set_selected(clone!(@strong result => move |poe| { .set_selected_cb(clone!(@strong result => move |poe| {
result.leaflet.set_visible_child(&result.navigator.widget); result.leaflet.set_visible_child(&result.navigator.widget);
match poe { match poe {
PersonOrEnsemble::Person(person) => { PersonOrEnsemble::Person(person) => {
@ -187,7 +192,7 @@ impl Window {
result result
.sidebar_box .sidebar_box
.pack_start(&result.poe_list.widget, true, true, 0); .append(&result.poe_list.widget);
result result
} }