2025-03-01 09:57:01 +01:00
|
|
|
mod composer_row;
|
2025-03-01 15:52:59 +01:00
|
|
|
mod instrument_row;
|
2025-03-01 09:57:01 +01:00
|
|
|
mod part_row;
|
|
|
|
|
|
|
|
|
|
use std::cell::{Cell, OnceCell, RefCell};
|
|
|
|
|
|
|
|
|
|
use adw::{prelude::*, subclass::prelude::*};
|
|
|
|
|
use composer_row::WorkEditorComposerRow;
|
|
|
|
|
use gettextrs::gettext;
|
|
|
|
|
use gtk::glib::{self, clone, subclass::Signal, Properties};
|
|
|
|
|
use once_cell::sync::Lazy;
|
|
|
|
|
use part_row::WorkEditorPartRow;
|
|
|
|
|
|
2024-05-31 13:39:27 +02:00
|
|
|
use crate::{
|
2024-06-01 13:49:13 +02:00
|
|
|
db::{
|
|
|
|
|
self,
|
2025-01-17 17:54:16 +01:00
|
|
|
models::{Composer, Instrument, Person, Work},
|
2024-06-01 13:49:13 +02:00
|
|
|
},
|
2025-03-01 09:57:01 +01:00
|
|
|
editor::{instrument::InstrumentEditor, person::PersonEditor, translation::TranslationEditor},
|
|
|
|
|
library::Library,
|
|
|
|
|
selector::{instrument::InstrumentSelectorPopover, person::PersonSelectorPopover},
|
2024-05-31 13:39:27 +02:00
|
|
|
};
|
2025-03-01 15:52:59 +01:00
|
|
|
use instrument_row::InstrumentRow;
|
2024-05-31 13:39:27 +02:00
|
|
|
|
|
|
|
|
mod imp {
|
|
|
|
|
use super::*;
|
|
|
|
|
|
|
|
|
|
#[derive(Debug, Default, gtk::CompositeTemplate, Properties)]
|
2025-03-01 09:57:01 +01:00
|
|
|
#[properties(wrapper_type = super::WorkEditor)]
|
|
|
|
|
#[template(file = "data/ui/editor/work.blp")]
|
|
|
|
|
pub struct WorkEditor {
|
2024-06-05 19:03:04 +02:00
|
|
|
#[property(get, construct_only)]
|
|
|
|
|
pub navigation: OnceCell<adw::NavigationView>,
|
|
|
|
|
|
2024-05-31 13:39:27 +02:00
|
|
|
#[property(get, construct_only)]
|
2025-03-01 09:57:01 +01:00
|
|
|
pub library: OnceCell<Library>,
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2025-01-15 11:23:04 +01:00
|
|
|
pub work_id: OnceCell<String>,
|
2025-01-17 17:54:16 +01:00
|
|
|
pub is_part_editor: Cell<bool>,
|
2025-01-15 11:23:04 +01:00
|
|
|
|
2024-05-31 13:39:27 +02:00
|
|
|
// Holding a reference to each composer row is the simplest way to enumerate all
|
|
|
|
|
// results when finishing the process of editing the work. The composer rows
|
|
|
|
|
// handle all state related to the composer.
|
2025-03-01 09:57:01 +01:00
|
|
|
pub composer_rows: RefCell<Vec<WorkEditorComposerRow>>,
|
|
|
|
|
pub part_rows: RefCell<Vec<WorkEditorPartRow>>,
|
2025-03-01 15:52:59 +01:00
|
|
|
pub instrument_rows: RefCell<Vec<InstrumentRow>>,
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2025-03-01 09:57:01 +01:00
|
|
|
pub persons_popover: OnceCell<PersonSelectorPopover>,
|
|
|
|
|
pub instruments_popover: OnceCell<InstrumentSelectorPopover>,
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2024-06-05 19:03:04 +02:00
|
|
|
#[template_child]
|
2025-03-01 09:57:01 +01:00
|
|
|
pub name_editor: TemplateChild<TranslationEditor>,
|
2024-05-31 13:39:27 +02:00
|
|
|
#[template_child]
|
2025-03-01 11:13:29 +01:00
|
|
|
pub composers_box: TemplateChild<gtk::Box>,
|
2024-05-31 13:39:27 +02:00
|
|
|
#[template_child]
|
2025-03-01 11:13:29 +01:00
|
|
|
pub composer_list: TemplateChild<gtk::ListBox>,
|
2024-05-31 13:39:27 +02:00
|
|
|
#[template_child]
|
2024-06-01 13:49:13 +02:00
|
|
|
pub part_list: TemplateChild<gtk::ListBox>,
|
|
|
|
|
#[template_child]
|
2025-03-01 11:13:29 +01:00
|
|
|
pub instruments_box: TemplateChild<gtk::Box>,
|
2024-05-31 13:39:27 +02:00
|
|
|
#[template_child]
|
2025-03-01 11:13:29 +01:00
|
|
|
pub instrument_list: TemplateChild<gtk::ListBox>,
|
2025-01-15 11:23:04 +01:00
|
|
|
#[template_child]
|
2025-01-17 18:33:31 +01:00
|
|
|
pub save_row: TemplateChild<adw::ButtonRow>,
|
2024-05-31 13:39:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[glib::object_subclass]
|
2025-03-01 09:57:01 +01:00
|
|
|
impl ObjectSubclass for WorkEditor {
|
2024-05-31 13:39:27 +02:00
|
|
|
const NAME: &'static str = "MusicusWorkEditor";
|
2025-03-01 09:57:01 +01:00
|
|
|
type Type = super::WorkEditor;
|
2024-05-31 13:39:27 +02:00
|
|
|
type ParentType = adw::NavigationPage;
|
|
|
|
|
|
|
|
|
|
fn class_init(klass: &mut Self::Class) {
|
2025-03-01 09:57:01 +01:00
|
|
|
TranslationEditor::static_type();
|
2024-05-31 13:39:27 +02:00
|
|
|
klass.bind_template();
|
|
|
|
|
klass.bind_template_instance_callbacks();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
|
|
|
|
obj.init_template();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[glib::derived_properties]
|
2025-03-01 09:57:01 +01:00
|
|
|
impl ObjectImpl for WorkEditor {
|
2025-01-15 11:23:04 +01:00
|
|
|
fn signals() -> &'static [Signal] {
|
|
|
|
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
|
|
|
|
vec![Signal::builder("created")
|
|
|
|
|
.param_types([Work::static_type()])
|
|
|
|
|
.build()]
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
SIGNALS.as_ref()
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-31 13:39:27 +02:00
|
|
|
fn constructed(&self) {
|
|
|
|
|
self.parent_constructed();
|
|
|
|
|
|
2025-03-01 09:57:01 +01:00
|
|
|
let persons_popover = PersonSelectorPopover::new(self.library.get().unwrap());
|
2024-05-31 13:39:27 +02:00
|
|
|
|
|
|
|
|
let obj = self.obj().clone();
|
2024-06-06 15:17:56 +02:00
|
|
|
persons_popover.connect_person_selected(move |_, person| {
|
|
|
|
|
obj.add_composer(person);
|
|
|
|
|
});
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2024-06-06 15:17:56 +02:00
|
|
|
let obj = self.obj().clone();
|
|
|
|
|
persons_popover.connect_create(move |_| {
|
2025-03-01 09:57:01 +01:00
|
|
|
let editor = PersonEditor::new(&obj.navigation(), &obj.library(), None);
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2024-07-18 15:01:30 +02:00
|
|
|
editor.connect_created(clone!(
|
|
|
|
|
#[weak]
|
|
|
|
|
obj,
|
|
|
|
|
move |_, person| {
|
|
|
|
|
obj.add_composer(person);
|
|
|
|
|
}
|
|
|
|
|
));
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2024-06-06 15:17:56 +02:00
|
|
|
obj.navigation().push(&editor);
|
|
|
|
|
});
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2025-03-01 11:13:29 +01:00
|
|
|
self.composers_box.append(&persons_popover);
|
2024-05-31 13:39:27 +02:00
|
|
|
self.persons_popover.set(persons_popover).unwrap();
|
|
|
|
|
|
2025-03-01 09:57:01 +01:00
|
|
|
let instruments_popover = InstrumentSelectorPopover::new(self.library.get().unwrap());
|
2024-05-31 13:39:27 +02:00
|
|
|
|
|
|
|
|
let obj = self.obj().clone();
|
2025-01-15 11:23:04 +01:00
|
|
|
instruments_popover.connect_instrument_selected(move |_, instrument| {
|
|
|
|
|
obj.add_instrument_row(instrument);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
let obj = self.obj().clone();
|
|
|
|
|
instruments_popover.connect_create(move |_| {
|
2025-03-01 09:57:01 +01:00
|
|
|
let editor = InstrumentEditor::new(&obj.navigation(), &obj.library(), None);
|
2025-01-15 11:23:04 +01:00
|
|
|
|
|
|
|
|
editor.connect_created(clone!(
|
|
|
|
|
#[weak]
|
|
|
|
|
obj,
|
|
|
|
|
move |_, instrument| {
|
|
|
|
|
obj.add_instrument_row(instrument);
|
|
|
|
|
}
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
obj.navigation().push(&editor);
|
|
|
|
|
});
|
2024-05-31 13:39:27 +02:00
|
|
|
|
2025-03-01 11:13:29 +01:00
|
|
|
self.instruments_box.append(&instruments_popover);
|
2024-05-31 13:39:27 +02:00
|
|
|
self.instruments_popover.set(instruments_popover).unwrap();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
2025-03-01 09:57:01 +01:00
|
|
|
impl WidgetImpl for WorkEditor {}
|
|
|
|
|
impl NavigationPageImpl for WorkEditor {}
|
2024-05-31 13:39:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
glib::wrapper! {
|
2025-03-01 09:57:01 +01:00
|
|
|
pub struct WorkEditor(ObjectSubclass<imp::WorkEditor>)
|
2024-05-31 13:39:27 +02:00
|
|
|
@extends gtk::Widget, adw::NavigationPage;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[gtk::template_callbacks]
|
2025-03-01 09:57:01 +01:00
|
|
|
impl WorkEditor {
|
2024-06-05 19:03:04 +02:00
|
|
|
pub fn new(
|
|
|
|
|
navigation: &adw::NavigationView,
|
2025-03-01 09:57:01 +01:00
|
|
|
library: &Library,
|
2024-06-05 19:03:04 +02:00
|
|
|
work: Option<&Work>,
|
2025-01-17 17:54:16 +01:00
|
|
|
is_part_editor: bool,
|
2024-06-05 19:03:04 +02:00
|
|
|
) -> Self {
|
|
|
|
|
let obj: Self = glib::Object::builder()
|
|
|
|
|
.property("navigation", navigation)
|
|
|
|
|
.property("library", library)
|
|
|
|
|
.build();
|
|
|
|
|
|
2025-01-17 17:54:16 +01:00
|
|
|
if is_part_editor {
|
|
|
|
|
obj.set_title(&gettext("Work part"));
|
2025-03-01 15:54:13 +01:00
|
|
|
obj.imp().save_row.set_title(&gettext("Add _work part"));
|
2025-01-17 17:54:16 +01:00
|
|
|
obj.imp().is_part_editor.set(true);
|
|
|
|
|
}
|
|
|
|
|
|
2025-01-15 11:23:04 +01:00
|
|
|
if let Some(work) = work {
|
2025-03-01 08:34:53 +01:00
|
|
|
obj.imp().save_row.set_title(&gettext("_Save changes"));
|
2025-01-15 11:23:04 +01:00
|
|
|
obj.imp().work_id.set(work.work_id.clone()).unwrap();
|
2025-01-17 17:54:16 +01:00
|
|
|
|
|
|
|
|
obj.imp().name_editor.set_translation(&work.name);
|
|
|
|
|
|
|
|
|
|
for part in &work.parts {
|
|
|
|
|
obj.add_part_row(part.clone());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for composer in &work.persons {
|
|
|
|
|
obj.add_composer_row(composer.clone());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
for instrument in &work.instruments {
|
|
|
|
|
obj.add_instrument_row(instrument.clone());
|
|
|
|
|
}
|
2024-06-05 19:03:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
obj
|
2024-05-31 13:39:27 +02:00
|
|
|
}
|
|
|
|
|
|
2025-01-15 11:23:04 +01:00
|
|
|
pub fn connect_created<F: Fn(&Self, Work) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
|
|
|
|
self.connect_local("created", true, move |values| {
|
|
|
|
|
let obj = values[0].get::<Self>().unwrap();
|
|
|
|
|
let work = values[1].get::<Work>().unwrap();
|
|
|
|
|
f(&obj, work);
|
|
|
|
|
None
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
2024-05-31 13:39:27 +02:00
|
|
|
#[template_callback]
|
2025-03-01 08:55:04 +01:00
|
|
|
fn add_person(&self) {
|
2024-05-31 13:39:27 +02:00
|
|
|
self.imp().persons_popover.get().unwrap().popup();
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[template_callback]
|
2025-03-01 08:55:04 +01:00
|
|
|
fn add_part(&self) {
|
2025-03-01 09:57:01 +01:00
|
|
|
let editor = WorkEditor::new(&self.navigation(), &self.library(), None, true);
|
2024-06-01 13:49:13 +02:00
|
|
|
|
2025-01-17 17:54:16 +01:00
|
|
|
editor.connect_created(clone!(
|
2024-07-18 15:01:30 +02:00
|
|
|
#[weak(rename_to = this)]
|
|
|
|
|
self,
|
2025-01-17 17:54:16 +01:00
|
|
|
move |_, part| {
|
|
|
|
|
this.add_part_row(part);
|
2024-07-18 15:01:30 +02:00
|
|
|
}
|
|
|
|
|
));
|
2024-06-01 13:49:13 +02:00
|
|
|
|
2025-01-17 17:54:16 +01:00
|
|
|
self.navigation().push(&editor);
|
2024-05-31 13:39:27 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[template_callback]
|
2025-03-01 08:55:04 +01:00
|
|
|
fn add_instrument(&self) {
|
2024-05-31 13:39:27 +02:00
|
|
|
self.imp().instruments_popover.get().unwrap().popup();
|
|
|
|
|
}
|
2024-06-06 15:17:56 +02:00
|
|
|
|
|
|
|
|
fn add_composer(&self, person: Person) {
|
2025-03-29 17:29:29 +01:00
|
|
|
let composer = Composer { person, role: None };
|
2025-01-17 17:54:16 +01:00
|
|
|
self.add_composer_row(composer);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add_part_row(&self, part: Work) {
|
2025-03-01 09:57:01 +01:00
|
|
|
let row = WorkEditorPartRow::new(&self.navigation(), &self.library(), part);
|
2025-01-17 17:54:16 +01:00
|
|
|
|
2025-03-01 15:52:59 +01:00
|
|
|
row.connect_move(clone!(
|
|
|
|
|
#[weak(rename_to = this)]
|
|
|
|
|
self,
|
|
|
|
|
move |target, source| {
|
|
|
|
|
let mut part_rows = this.imp().part_rows.borrow_mut();
|
|
|
|
|
if let Some(index) = part_rows.iter().position(|p| p == target) {
|
|
|
|
|
this.imp().part_list.remove(&source);
|
|
|
|
|
part_rows.retain(|p| p != &source);
|
|
|
|
|
this.imp().part_list.insert(&source, index as i32);
|
|
|
|
|
part_rows.insert(index, source);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
));
|
|
|
|
|
|
2025-01-17 17:54:16 +01:00
|
|
|
row.connect_remove(clone!(
|
|
|
|
|
#[weak(rename_to = this)]
|
|
|
|
|
self,
|
|
|
|
|
move |row| {
|
|
|
|
|
this.imp().part_list.remove(row);
|
|
|
|
|
this.imp().part_rows.borrow_mut().retain(|p| p != row);
|
|
|
|
|
}
|
|
|
|
|
));
|
|
|
|
|
|
|
|
|
|
self.imp()
|
|
|
|
|
.part_list
|
|
|
|
|
.insert(&row, self.imp().part_rows.borrow().len() as i32);
|
|
|
|
|
|
|
|
|
|
self.imp().part_rows.borrow_mut().push(row);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn add_composer_row(&self, composer: Composer) {
|
2025-03-01 09:57:01 +01:00
|
|
|
let row = WorkEditorComposerRow::new(&self.navigation(), &self.library(), composer);
|
2024-07-18 15:01:30 +02:00
|
|
|
|
2025-03-01 15:52:59 +01:00
|
|
|
row.connect_move(clone!(
|
|
|
|
|
#[weak(rename_to = this)]
|
|
|
|
|
self,
|
|
|
|
|
move |target, source| {
|
|
|
|
|
let mut composer_rows = this.imp().composer_rows.borrow_mut();
|
|
|
|
|
if let Some(index) = composer_rows.iter().position(|p| p == target) {
|
|
|
|
|
this.imp().composer_list.remove(&source);
|
|
|
|
|
composer_rows.retain(|p| p != &source);
|
|
|
|
|
this.imp().composer_list.insert(&source, index as i32);
|
|
|
|
|
composer_rows.insert(index, source);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
));
|
|
|
|
|
|
2024-07-18 15:01:30 +02:00
|
|
|
row.connect_remove(clone!(
|
|
|
|
|
#[weak(rename_to = this)]
|
|
|
|
|
self,
|
|
|
|
|
move |row| {
|
|
|
|
|
this.imp().composer_list.remove(row);
|
|
|
|
|
this.imp().composer_rows.borrow_mut().retain(|c| c != row);
|
|
|
|
|
}
|
|
|
|
|
));
|
2024-06-06 15:17:56 +02:00
|
|
|
|
|
|
|
|
self.imp()
|
|
|
|
|
.composer_list
|
|
|
|
|
.insert(&row, self.imp().composer_rows.borrow().len() as i32);
|
|
|
|
|
|
|
|
|
|
self.imp().composer_rows.borrow_mut().push(row);
|
|
|
|
|
}
|
2025-01-15 11:23:04 +01:00
|
|
|
|
|
|
|
|
fn add_instrument_row(&self, instrument: Instrument) {
|
2025-03-01 15:52:59 +01:00
|
|
|
let row = InstrumentRow::new(instrument);
|
2025-01-15 11:23:04 +01:00
|
|
|
|
2025-03-01 15:52:59 +01:00
|
|
|
row.connect_move(clone!(
|
2025-01-15 11:23:04 +01:00
|
|
|
#[weak(rename_to = this)]
|
|
|
|
|
self,
|
2025-03-01 15:52:59 +01:00
|
|
|
move |target, source| {
|
|
|
|
|
let mut instrument_rows = this.imp().instrument_rows.borrow_mut();
|
|
|
|
|
if let Some(index) = instrument_rows.iter().position(|p| p == target) {
|
|
|
|
|
this.imp().instrument_list.remove(&source);
|
|
|
|
|
instrument_rows.retain(|p| p != &source);
|
|
|
|
|
this.imp().instrument_list.insert(&source, index as i32);
|
|
|
|
|
instrument_rows.insert(index, source);
|
|
|
|
|
}
|
2025-01-15 11:23:04 +01:00
|
|
|
}
|
|
|
|
|
));
|
|
|
|
|
|
2025-03-01 15:52:59 +01:00
|
|
|
row.connect_remove(clone!(
|
|
|
|
|
#[weak(rename_to = this)]
|
|
|
|
|
self,
|
|
|
|
|
move |row| {
|
|
|
|
|
this.imp().instrument_list.remove(row);
|
|
|
|
|
this.imp().instrument_rows.borrow_mut().retain(|p| p != row);
|
|
|
|
|
}
|
|
|
|
|
));
|
2025-01-15 11:23:04 +01:00
|
|
|
|
|
|
|
|
self.imp()
|
|
|
|
|
.instrument_list
|
2025-03-01 15:52:59 +01:00
|
|
|
.insert(&row, self.imp().instrument_rows.borrow().len() as i32);
|
2025-01-15 11:23:04 +01:00
|
|
|
|
2025-03-01 15:52:59 +01:00
|
|
|
self.imp().instrument_rows.borrow_mut().push(row);
|
2025-01-15 11:23:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
#[template_callback]
|
2025-02-16 16:30:24 +01:00
|
|
|
fn save(&self) {
|
2025-01-15 11:23:04 +01:00
|
|
|
let library = self.imp().library.get().unwrap();
|
|
|
|
|
|
|
|
|
|
let name = self.imp().name_editor.translation();
|
2025-01-17 17:54:16 +01:00
|
|
|
|
|
|
|
|
let parts = self
|
|
|
|
|
.imp()
|
|
|
|
|
.part_rows
|
|
|
|
|
.borrow()
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|p| p.part())
|
|
|
|
|
.collect::<Vec<Work>>();
|
|
|
|
|
|
2025-01-15 11:23:04 +01:00
|
|
|
let composers = self
|
|
|
|
|
.imp()
|
|
|
|
|
.composer_rows
|
|
|
|
|
.borrow()
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|c| c.composer())
|
|
|
|
|
.collect::<Vec<Composer>>();
|
2025-03-01 15:52:59 +01:00
|
|
|
|
|
|
|
|
let instruments = self
|
|
|
|
|
.imp()
|
|
|
|
|
.instrument_rows
|
|
|
|
|
.borrow()
|
|
|
|
|
.iter()
|
|
|
|
|
.map(|r| r.instrument())
|
|
|
|
|
.collect::<Vec<Instrument>>();
|
2025-01-15 11:23:04 +01:00
|
|
|
|
2025-01-17 17:54:16 +01:00
|
|
|
if self.imp().is_part_editor.get() {
|
|
|
|
|
let work_id = self
|
|
|
|
|
.imp()
|
|
|
|
|
.work_id
|
|
|
|
|
.get()
|
|
|
|
|
.map(|w| w.to_string())
|
|
|
|
|
.unwrap_or_else(db::generate_id);
|
|
|
|
|
|
|
|
|
|
let part = Work {
|
|
|
|
|
work_id,
|
|
|
|
|
name,
|
|
|
|
|
parts,
|
|
|
|
|
persons: composers,
|
|
|
|
|
instruments,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
self.emit_by_name::<()>("created", &[&part]);
|
2025-01-15 11:23:04 +01:00
|
|
|
} else {
|
2025-01-17 17:54:16 +01:00
|
|
|
if let Some(work_id) = self.imp().work_id.get() {
|
|
|
|
|
library
|
|
|
|
|
.update_work(work_id, name, parts, composers, instruments)
|
|
|
|
|
.unwrap();
|
|
|
|
|
} else {
|
|
|
|
|
let work = library
|
|
|
|
|
.create_work(name, parts, composers, instruments)
|
|
|
|
|
.unwrap();
|
|
|
|
|
self.emit_by_name::<()>("created", &[&work]);
|
|
|
|
|
}
|
2025-01-15 11:23:04 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
self.imp().navigation.get().unwrap().pop();
|
|
|
|
|
}
|
2024-05-31 13:39:27 +02:00
|
|
|
}
|