2020-12-02 15:41:19 +01:00
|
|
|
use crate::backend::Backend;
|
2020-11-08 12:11:54 +01:00
|
|
|
use crate::database::*;
|
2020-12-02 15:41:19 +01:00
|
|
|
use crate::selectors::{EnsembleSelector, InstrumentSelector, PersonSelector};
|
|
|
|
|
use crate::widgets::{Navigator, NavigatorScreen};
|
2020-11-08 12:11:54 +01:00
|
|
|
use gettextrs::gettext;
|
|
|
|
|
use glib::clone;
|
|
|
|
|
use gtk::prelude::*;
|
|
|
|
|
use gtk_macros::get_widget;
|
2021-01-25 14:00:57 +01:00
|
|
|
use libhandy::prelude::*;
|
2020-11-08 12:11:54 +01:00
|
|
|
use std::cell::RefCell;
|
|
|
|
|
use std::rc::Rc;
|
|
|
|
|
|
|
|
|
|
/// A dialog for editing a performance within a recording.
|
|
|
|
|
pub struct PerformanceEditor {
|
|
|
|
|
backend: Rc<Backend>,
|
2020-12-02 15:41:19 +01:00
|
|
|
widget: gtk::Box,
|
2020-11-08 12:11:54 +01:00
|
|
|
save_button: gtk::Button,
|
2021-01-25 14:00:57 +01:00
|
|
|
person_row: libhandy::ActionRow,
|
|
|
|
|
ensemble_row: libhandy::ActionRow,
|
|
|
|
|
role_row: libhandy::ActionRow,
|
2020-11-08 12:11:54 +01:00
|
|
|
reset_role_button: gtk::Button,
|
|
|
|
|
person: RefCell<Option<Person>>,
|
|
|
|
|
ensemble: RefCell<Option<Ensemble>>,
|
|
|
|
|
role: RefCell<Option<Instrument>>,
|
2020-11-17 15:52:47 +01:00
|
|
|
selected_cb: RefCell<Option<Box<dyn Fn(Performance) -> ()>>>,
|
2020-12-02 15:41:19 +01:00
|
|
|
navigator: RefCell<Option<Rc<Navigator>>>,
|
2020-11-08 12:11:54 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
impl PerformanceEditor {
|
|
|
|
|
/// Create a new performance editor.
|
2020-12-02 15:41:19 +01:00
|
|
|
pub fn new(backend: Rc<Backend>, performance: Option<Performance>) -> Rc<Self> {
|
2020-11-08 12:11:54 +01:00
|
|
|
// Create UI
|
|
|
|
|
|
|
|
|
|
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/performance_editor.ui");
|
|
|
|
|
|
2020-12-02 15:41:19 +01:00
|
|
|
get_widget!(builder, gtk::Box, widget);
|
|
|
|
|
get_widget!(builder, gtk::Button, back_button);
|
2020-11-08 12:11:54 +01:00
|
|
|
get_widget!(builder, gtk::Button, save_button);
|
|
|
|
|
get_widget!(builder, gtk::Button, person_button);
|
|
|
|
|
get_widget!(builder, gtk::Button, ensemble_button);
|
|
|
|
|
get_widget!(builder, gtk::Button, role_button);
|
|
|
|
|
get_widget!(builder, gtk::Button, reset_role_button);
|
2021-01-25 14:00:57 +01:00
|
|
|
get_widget!(builder, libhandy::ActionRow, person_row);
|
|
|
|
|
get_widget!(builder, libhandy::ActionRow, ensemble_row);
|
|
|
|
|
get_widget!(builder, libhandy::ActionRow, role_row);
|
2020-11-08 12:11:54 +01:00
|
|
|
|
|
|
|
|
let this = Rc::new(PerformanceEditor {
|
|
|
|
|
backend,
|
2020-12-02 15:41:19 +01:00
|
|
|
widget,
|
2020-11-08 12:11:54 +01:00
|
|
|
save_button,
|
2021-01-25 14:00:57 +01:00
|
|
|
person_row,
|
|
|
|
|
ensemble_row,
|
|
|
|
|
role_row,
|
2020-11-08 12:11:54 +01:00
|
|
|
reset_role_button,
|
|
|
|
|
person: RefCell::new(None),
|
|
|
|
|
ensemble: RefCell::new(None),
|
|
|
|
|
role: RefCell::new(None),
|
|
|
|
|
selected_cb: RefCell::new(None),
|
2020-12-02 15:41:19 +01:00
|
|
|
navigator: RefCell::new(None),
|
2020-11-08 12:11:54 +01:00
|
|
|
});
|
|
|
|
|
|
|
|
|
|
// Connect signals and callbacks
|
|
|
|
|
|
2020-12-02 15:41:19 +01:00
|
|
|
back_button.connect_clicked(clone!(@strong this => move |_| {
|
|
|
|
|
let navigator = this.navigator.borrow().clone();
|
|
|
|
|
if let Some(navigator) = navigator {
|
|
|
|
|
navigator.pop();
|
|
|
|
|
}
|
2020-11-08 12:11:54 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
this.save_button
|
|
|
|
|
.connect_clicked(clone!(@strong this => move |_| {
|
|
|
|
|
if let Some(cb) = &*this.selected_cb.borrow() {
|
2020-11-17 15:52:47 +01:00
|
|
|
cb(Performance {
|
2020-11-08 12:11:54 +01:00
|
|
|
person: this.person.borrow().clone(),
|
|
|
|
|
ensemble: this.ensemble.borrow().clone(),
|
|
|
|
|
role: this.role.borrow().clone(),
|
|
|
|
|
});
|
2020-12-02 15:41:19 +01:00
|
|
|
}
|
2020-11-08 12:11:54 +01:00
|
|
|
|
2020-12-02 15:41:19 +01:00
|
|
|
let navigator = this.navigator.borrow().clone();
|
|
|
|
|
if let Some(navigator) = navigator {
|
|
|
|
|
navigator.pop();
|
2020-11-08 12:11:54 +01:00
|
|
|
}
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
person_button.connect_clicked(clone!(@strong this => move |_| {
|
2020-12-02 15:41:19 +01:00
|
|
|
let navigator = this.navigator.borrow().clone();
|
|
|
|
|
if let Some(navigator) = navigator {
|
|
|
|
|
let selector = PersonSelector::new(this.backend.clone());
|
|
|
|
|
|
|
|
|
|
selector.set_selected_cb(clone!(@strong this, @strong navigator => move |person| {
|
|
|
|
|
this.show_person(Some(&person));
|
|
|
|
|
this.person.replace(Some(person.clone()));
|
|
|
|
|
this.show_ensemble(None);
|
|
|
|
|
this.ensemble.replace(None);
|
|
|
|
|
navigator.clone().pop();
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
navigator.push(selector);
|
|
|
|
|
}
|
2020-11-08 12:11:54 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
ensemble_button.connect_clicked(clone!(@strong this => move |_| {
|
2020-12-02 15:41:19 +01:00
|
|
|
let navigator = this.navigator.borrow().clone();
|
|
|
|
|
if let Some(navigator) = navigator {
|
|
|
|
|
let selector = EnsembleSelector::new(this.backend.clone());
|
|
|
|
|
|
|
|
|
|
selector.set_selected_cb(clone!(@strong this, @strong navigator => move |ensemble| {
|
|
|
|
|
this.show_person(None);
|
|
|
|
|
this.person.replace(None);
|
|
|
|
|
this.show_ensemble(Some(&ensemble));
|
|
|
|
|
this.ensemble.replace(Some(ensemble.clone()));
|
|
|
|
|
navigator.clone().pop();
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
navigator.push(selector);
|
|
|
|
|
}
|
2020-11-08 12:11:54 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
role_button.connect_clicked(clone!(@strong this => move |_| {
|
2020-12-02 15:41:19 +01:00
|
|
|
let navigator = this.navigator.borrow().clone();
|
|
|
|
|
if let Some(navigator) = navigator {
|
|
|
|
|
let selector = InstrumentSelector::new(this.backend.clone());
|
2020-11-28 23:07:31 +01:00
|
|
|
|
2020-12-02 15:41:19 +01:00
|
|
|
selector.set_selected_cb(clone!(@strong this, @strong navigator => move |role| {
|
|
|
|
|
this.show_role(Some(&role));
|
|
|
|
|
this.role.replace(Some(role.clone()));
|
|
|
|
|
navigator.clone().pop();
|
|
|
|
|
}));
|
2020-11-28 23:07:31 +01:00
|
|
|
|
2020-12-02 15:41:19 +01:00
|
|
|
navigator.push(selector);
|
|
|
|
|
}
|
2020-11-08 12:11:54 +01:00
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
this.reset_role_button
|
|
|
|
|
.connect_clicked(clone!(@strong this => move |_| {
|
|
|
|
|
this.show_role(None);
|
|
|
|
|
this.role.replace(None);
|
|
|
|
|
}));
|
|
|
|
|
|
|
|
|
|
// Initialize
|
|
|
|
|
|
|
|
|
|
if let Some(performance) = performance {
|
|
|
|
|
if let Some(person) = performance.person {
|
|
|
|
|
this.show_person(Some(&person));
|
|
|
|
|
this.person.replace(Some(person));
|
|
|
|
|
} else if let Some(ensemble) = performance.ensemble {
|
|
|
|
|
this.show_ensemble(Some(&ensemble));
|
|
|
|
|
this.ensemble.replace(Some(ensemble));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if let Some(role) = performance.role {
|
|
|
|
|
this.show_role(Some(&role));
|
|
|
|
|
this.role.replace(Some(role));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
this
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Set a closure to be called when the user has chosen to save the performance.
|
2020-11-17 15:52:47 +01:00
|
|
|
pub fn set_selected_cb<F: Fn(Performance) -> () + 'static>(&self, cb: F) {
|
2020-11-08 12:11:54 +01:00
|
|
|
self.selected_cb.replace(Some(Box::new(cb)));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Update the UI according to person.
|
|
|
|
|
fn show_person(&self, person: Option<&Person>) {
|
|
|
|
|
if let Some(person) = person {
|
2021-01-25 14:00:57 +01:00
|
|
|
self.person_row.set_title(Some(&gettext("Person")));
|
|
|
|
|
self.person_row.set_subtitle(Some(&person.name_fl()));
|
2020-11-08 12:11:54 +01:00
|
|
|
self.save_button.set_sensitive(true);
|
|
|
|
|
} else {
|
2021-01-25 14:00:57 +01:00
|
|
|
self.person_row.set_title(Some(&gettext("Select a person")));
|
|
|
|
|
self.person_row.set_subtitle(None);
|
2020-11-08 12:11:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Update the UI according to ensemble.
|
|
|
|
|
fn show_ensemble(&self, ensemble: Option<&Ensemble>) {
|
|
|
|
|
if let Some(ensemble) = ensemble {
|
2021-01-25 14:00:57 +01:00
|
|
|
self.ensemble_row.set_title(Some(&gettext("Ensemble")));
|
|
|
|
|
self.ensemble_row.set_subtitle(Some(&ensemble.name));
|
2020-11-08 12:11:54 +01:00
|
|
|
self.save_button.set_sensitive(true);
|
|
|
|
|
} else {
|
2021-01-25 14:00:57 +01:00
|
|
|
self.ensemble_row.set_title(Some(&gettext("Select an ensemble")));
|
|
|
|
|
self.ensemble_row.set_subtitle(None);
|
2020-11-08 12:11:54 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/// Update the UI according to role.
|
|
|
|
|
fn show_role(&self, role: Option<&Instrument>) {
|
|
|
|
|
if let Some(role) = role {
|
2021-01-25 14:00:57 +01:00
|
|
|
self.role_row.set_title(Some(&gettext("Role")));
|
|
|
|
|
self.role_row.set_subtitle(Some(&role.name));
|
2020-11-08 12:11:54 +01:00
|
|
|
self.reset_role_button.show();
|
|
|
|
|
} else {
|
2021-01-25 14:00:57 +01:00
|
|
|
self.role_row.set_title(Some(&gettext("Select a role")));
|
|
|
|
|
self.role_row.set_subtitle(None);
|
2020-11-08 12:11:54 +01:00
|
|
|
self.reset_role_button.hide();
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2020-12-02 15:41:19 +01:00
|
|
|
|
|
|
|
|
impl NavigatorScreen for PerformanceEditor {
|
|
|
|
|
fn attach_navigator(&self, navigator: Rc<Navigator>) {
|
|
|
|
|
self.navigator.replace(Some(navigator));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn get_widget(&self) -> gtk::Widget {
|
|
|
|
|
self.widget.clone().upcast()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
fn detach_navigator(&self) {
|
|
|
|
|
self.navigator.replace(None);
|
|
|
|
|
}
|
|
|
|
|
}
|