diff --git a/res/resources.xml b/res/resources.xml index 369155e..cc45cd4 100644 --- a/res/resources.xml +++ b/res/resources.xml @@ -9,6 +9,7 @@ ui/performance_editor.ui ui/person_editor.ui ui/person_selector.ui + ui/recording_editor.ui ui/section_editor.ui ui/window.ui ui/work_editor.ui diff --git a/res/ui/recording_editor.ui b/res/ui/recording_editor.ui new file mode 100644 index 0000000..63f7d03 --- /dev/null +++ b/res/ui/recording_editor.ui @@ -0,0 +1,231 @@ + + + + + + False + True + 500 + 450 + True + dialog + + + True + True + + + + True + False + 18 + 12 + 6 + + + True + False + end + Comment + + + 0 + 1 + + + + + True + True + True + True + + + True + False + start + Select … + + + + + 1 + 0 + + + + + True + True + + + 1 + 1 + + + + + True + False + end + Work + + + 0 + 0 + + + + + + + True + False + Overview + + + False + + + + + True + False + 18 + 6 + + + True + True + in + + + True + False + + + True + False + True + True + + + True + False + No performers added. + + + + + + + + + True + True + 0 + + + + + True + False + 0 + vertical + 6 + + + True + True + True + + + True + False + list-add-symbolic + + + + + False + True + 0 + + + + + True + True + True + + + True + False + list-remove-symbolic + + + + + False + True + 1 + + + + + False + True + 1 + + + + + 1 + + + + + True + False + Performers + + + 1 + False + + + + + + + True + False + Recording + + + Cancel + True + True + True + + + + + Save + True + False + True + True + + + + end + 1 + + + + + + diff --git a/src/dialogs/mod.rs b/src/dialogs/mod.rs index 8aa65b5..f862abb 100644 --- a/src/dialogs/mod.rs +++ b/src/dialogs/mod.rs @@ -22,6 +22,9 @@ pub use person_editor::*; pub mod person_selector; pub use person_selector::*; +pub mod recording_editor; +pub use recording_editor::*; + pub mod section_editor; pub use section_editor::*; diff --git a/src/dialogs/recording_editor.rs b/src/dialogs/recording_editor.rs new file mode 100644 index 0000000..5f0d045 --- /dev/null +++ b/src/dialogs/recording_editor.rs @@ -0,0 +1,142 @@ +use super::*; +use crate::backend::Backend; +use crate::database::*; +use glib::clone; +use gtk::prelude::*; +use gtk_macros::get_widget; +use std::cell::RefCell; +use std::rc::Rc; +use std::convert::TryInto; + +pub struct RecordingEditor +where + F: Fn(RecordingDescription) -> () + 'static, +{ + backend: Rc, + window: gtk::Window, + callback: F, + id: i64, + save_button: gtk::Button, + work_label: gtk::Label, + work: RefCell>, + performers: RefCell>, + performer_list: gtk::ListBox, +} + +impl RecordingEditor +where + F: Fn(RecordingDescription) -> () + 'static, +{ + pub fn new>( + backend: Rc, + parent: &P, + recording: Option, + callback: F, + ) -> Rc { + let builder = + gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/recording_editor.ui"); + + get_widget!(builder, gtk::Window, window); + get_widget!(builder, gtk::Button, cancel_button); + get_widget!(builder, gtk::Button, save_button); + get_widget!(builder, gtk::Button, work_button); + get_widget!(builder, gtk::Label, work_label); + get_widget!(builder, gtk::ListBox, performer_list); + get_widget!(builder, gtk::Button, add_performer_button); + get_widget!(builder, gtk::Button, remove_performer_button); + + let (id, work, performers) = match recording { + Some(recording) => { + save_button.set_sensitive(true); + (recording.id, Some(recording.work), recording.performances) + } + None => (rand::random::().into(), None, Vec::new()), + }; + + let result = Rc::new(RecordingEditor { + backend: backend, + window: window, + callback: callback, + id: id, + save_button: save_button, + work_label: work_label, + work: RefCell::new(work), + performers: RefCell::new(performers), + performer_list: performer_list, + }); + + cancel_button.connect_clicked(clone!(@strong result => move |_| { + result.window.close(); + })); + + result + .save_button + .connect_clicked(clone!(@strong result => move |_| { + result.window.close(); + })); + + work_button.connect_clicked(clone!(@strong result => move |_| { + WorkSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |work| { + result.work.replace(Some(work.clone())); + result.work_label.set_text(&format!("{}: {}", work.composer.name_fl(), work.title)); + result.save_button.set_sensitive(true); + })).show(); + })); + + add_performer_button.connect_clicked(clone!(@strong result => move |_| { + PerformanceEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |performance| { + { + let mut performers = result.performers.borrow_mut(); + performers.push(performance); + } + + result.show_performers(); + })).show(); + })); + + remove_performer_button.connect_clicked(clone!(@strong result => move |_| { + let row = result.get_selected_performer_row(); + match row { + Some(row) => { + let index = row.get_index(); + let index: usize = index.try_into().unwrap(); + result.performers.borrow_mut().remove(index); + result.show_performers(); + } + None => (), + } + })); + + result.window.set_transient_for(Some(parent)); + + result + } + + pub fn show(&self) { + self.window.show(); + } + + fn show_performers(&self) { + for child in self.performer_list.get_children() { + self.performer_list.remove(&child); + } + + for (index, performer) in self.performers.borrow().iter().enumerate() { + let label = gtk::Label::new(Some(&performer.get_title())); + label.set_halign(gtk::Align::Start); + let row = SelectorRow::new(index.try_into().unwrap(), &label); + row.show_all(); + self.performer_list.insert(&row, -1); + } + } + + fn get_selected_performer_row(&self) -> Option { + match self.performer_list.get_selected_rows().first() { + Some(row) => match row.get_child() { + Some(child) => Some(child.downcast().unwrap()), + None => None, + }, + None => None, + } + } +} diff --git a/src/window.rs b/src/window.rs index 0bd40bb..7848e50 100644 --- a/src/window.rs +++ b/src/window.rs @@ -124,9 +124,15 @@ impl Window { }) ); - action!(result.window, "add-recording", |_, _| { - println!("TODO: Add recording."); - }); + action!( + result.window, + "add-recording", + clone!(@strong result => move |_, _| { + RecordingEditor::new(result.backend.clone(), &result.window, None, clone!(@strong result => move |_| { + result.clone().set_state(Loading); + })).show(); + }) + ); action!( result.window,