diff --git a/res/resources.xml b/res/resources.xml index e0dcb06..64d125c 100644 --- a/res/resources.xml +++ b/res/resources.xml @@ -4,6 +4,7 @@ ui/ensemble_editor.ui ui/instrument_editor.ui ui/instrument_selector.ui + ui/part_editor.ui ui/person_editor.ui ui/person_selector.ui ui/window.ui diff --git a/res/ui/part_editor.ui b/res/ui/part_editor.ui new file mode 100644 index 0000000..3751470 --- /dev/null +++ b/res/ui/part_editor.ui @@ -0,0 +1,248 @@ + + + + + + False + True + 450 + 300 + True + dialog + + + True + True + + + True + False + 18 + 12 + 6 + + + True + True + True + True + + + True + False + start + Auswählen … + + + + + 1 + 1 + + + + + True + False + end + Composer + + + 0 + 1 + + + + + True + True + + + 1 + 0 + 2 + + + + + True + False + end + Title + + + 0 + 0 + + + + + True + True + True + + + True + False + edit-undo-symbolic + + + + + 2 + 1 + + + + + + + True + False + Overview + + + False + + + + + True + False + 18 + 6 + + + True + True + in + + + True + False + + + True + False + True + True + + + True + False + No instruments 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 + Instruments + + + 1 + False + + + + + + + True + False + Work part + + + Cancel + True + True + True + + + + + Save + True + True + True + + + + end + 1 + + + + + + diff --git a/src/dialogs/mod.rs b/src/dialogs/mod.rs index 66cb45a..d38a64d 100644 --- a/src/dialogs/mod.rs +++ b/src/dialogs/mod.rs @@ -7,6 +7,9 @@ pub use instrument_editor::*; pub mod instrument_selector; pub use instrument_selector::*; +pub mod part_editor; +pub use part_editor::*; + pub mod person_editor; pub use person_editor::*; diff --git a/src/dialogs/part_editor.rs b/src/dialogs/part_editor.rs new file mode 100644 index 0000000..a0b0c0a --- /dev/null +++ b/src/dialogs/part_editor.rs @@ -0,0 +1,156 @@ +use super::selector_row::SelectorRow; +use super::{InstrumentSelector, PersonSelector}; +use crate::database::*; +use glib::clone; +use gtk::prelude::*; +use gtk_macros::get_widget; +use std::cell::RefCell; +use std::convert::TryInto; +use std::rc::Rc; + +pub struct PartEditor { + db: Rc, + window: gtk::Window, + title_entry: gtk::Entry, + composer: RefCell>, + composer_label: gtk::Label, + instruments: RefCell>, + instrument_list: gtk::ListBox, +} + +impl PartEditor { + pub fn new () + 'static, P: IsA>( + db: Rc, + parent: &P, + part: Option, + callback: F, + ) -> Rc { + let builder = gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/part_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::Entry, title_entry); + get_widget!(builder, gtk::Button, composer_button); + get_widget!(builder, gtk::Label, composer_label); + get_widget!(builder, gtk::Button, reset_composer_button); + get_widget!(builder, gtk::ListBox, instrument_list); + get_widget!(builder, gtk::Button, add_instrument_button); + get_widget!(builder, gtk::Button, remove_instrument_button); + + match part.clone() { + Some(part) => { + title_entry.set_text(&part.title); + } + None => (), + }; + + let composer = RefCell::new(match part.clone() { + Some(work) => { + match work.composer.clone() { + Some(composer) => composer_label.set_text(&composer.name_fl()), + None => (), + } + + work.composer + }, + None => None, + }); + + let instruments = RefCell::new(match part.clone() { + Some(work) => work.instruments, + None => Vec::new(), + }); + + let result = Rc::new(PartEditor { + db: db, + window: window, + title_entry: title_entry, + composer: composer, + composer_label: composer_label, + instruments: instruments, + instrument_list: instrument_list, + }); + + cancel_button.connect_clicked(clone!(@strong result => move |_| { + result.window.close(); + })); + + save_button.connect_clicked(clone!(@strong result => move |_| { + result.window.close(); + callback(WorkPartDescription { + title: result.title_entry.get_text().to_string(), + composer: result.composer.borrow().clone(), + instruments: result.instruments.borrow().clone(), + }); + })); + + composer_button.connect_clicked(clone!(@strong result => move |_| { + PersonSelector::new(result.db.clone(), &result.window, clone!(@strong result => move |person| { + result.composer.replace(Some(person.clone())); + result.composer_label.set_text(&person.name_fl()); + })).show(); + })); + + reset_composer_button.connect_clicked(clone!(@strong result => move |_| { + result.composer.replace(None); + result.composer_label.set_text("Select …"); + })); + + add_instrument_button.connect_clicked(clone!(@strong result => move |_| { + InstrumentSelector::new(result.db.clone(), &result.window, clone!(@strong result => move |instrument| { + { + let mut instruments = result.instruments.borrow_mut(); + instruments.push(instrument); + } + + result.show_instruments(); + })).show(); + })); + + remove_instrument_button.connect_clicked(clone!(@strong result => move |_| { + let row = result.get_selected_instrument_row(); + match row { + Some(row) => { + let index = row.get_index(); + let index: usize = index.try_into().unwrap(); + result.instruments.borrow_mut().remove(index); + result.show_instruments(); + } + None => (), + } + })); + + result.window.set_transient_for(Some(parent)); + + result + } + + pub fn show(&self) { + self.window.show(); + } + + fn show_instruments(&self) { + for child in self.instrument_list.get_children() { + self.instrument_list.remove(&child); + } + + for (index, instrument) in self.instruments.borrow().iter().enumerate() { + let label = gtk::Label::new(Some(&instrument.name)); + label.set_halign(gtk::Align::Start); + let row = SelectorRow::new(index.try_into().unwrap(), &label); + row.show_all(); + self.instrument_list.insert(&row, -1); + } + } + + fn get_selected_instrument_row(&self) -> Option { + match self.instrument_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/dialogs/work_editor.rs b/src/dialogs/work_editor.rs index 29428fe..607c9fe 100644 --- a/src/dialogs/work_editor.rs +++ b/src/dialogs/work_editor.rs @@ -1,5 +1,5 @@ use super::selector_row::SelectorRow; -use super::{InstrumentSelector, PersonSelector}; +use super::{InstrumentSelector, PersonSelector, PartEditor}; use crate::database::*; use glib::clone; use gtk::prelude::*; @@ -39,6 +39,14 @@ impl PartOrSection { pub fn unwrap_section(&self) -> WorkSectionDescription { self.section.as_ref().unwrap().clone() } + + pub fn get_title(&self) -> String { + if self.is_part() { + self.unwrap_part().title + } else { + self.unwrap_section().title + } + } } pub struct WorkEditor { @@ -52,6 +60,7 @@ pub struct WorkEditor { instruments: RefCell>, instrument_list: gtk::ListBox, structure: RefCell>, + part_list: gtk::ListBox, } impl WorkEditor { @@ -135,6 +144,7 @@ impl WorkEditor { instruments: instruments, instrument_list: instrument_list, structure: structure, + part_list: part_list, }); cancel_button.connect_clicked(clone!(@strong result => move |_| { @@ -205,6 +215,80 @@ impl WorkEditor { } })); + add_part_button.connect_clicked(clone!(@strong result => move |_| { + PartEditor::new(result.db.clone(), &result.window, None, clone!(@strong result => move |part| { + { + let mut structure = result.structure.borrow_mut(); + structure.push(PartOrSection::part(part)); + } + + result.show_parts(); + })).show(); + })); + + remove_part_button.connect_clicked(clone!(@strong result => move |_| { + let row = result.get_selected_part_row(); + match row { + Some(row) => { + let index = row.get_index(); + let index: usize = index.try_into().unwrap(); + result.structure.borrow_mut().remove(index); + result.show_parts(); + } + None => (), + } + })); + + edit_part_button.connect_clicked(clone!(@strong result => move |_| { + let row = result.get_selected_part_row(); + match row { + Some(row) => { + let index = row.get_index(); + let index: usize = index.try_into().unwrap(); + let part = &result.structure.borrow()[index]; + + let editor = + PartEditor::new(result.db.clone(), &result.window, Some(part.unwrap_part()), clone!(@strong result => move |part| { + result.structure.borrow_mut()[index] = PartOrSection::part(part); + result.show_parts(); + })); + + editor.show(); + } + None => (), + } + })); + + move_part_up_button.connect_clicked(clone!(@strong result => move |_| { + let row = result.get_selected_part_row(); + match row { + Some(row) => { + let index = row.get_index(); + if index > 0 { + let index: usize = index.try_into().unwrap(); + result.structure.borrow_mut().swap(index - 1, index); + result.show_parts(); + } + } + None => (), + } + })); + + move_part_down_button.connect_clicked(clone!(@strong result => move |_| { + let row = result.get_selected_part_row(); + match row { + Some(row) => { + let index = row.get_index(); + let index: usize = index.try_into().unwrap(); + if index < result.structure.borrow().len() - 1 { + result.structure.borrow_mut().swap(index, index + 1); + result.show_parts(); + } + } + None => (), + } + })); + result.window.set_transient_for(Some(parent)); result @@ -237,4 +321,28 @@ impl WorkEditor { None => None, } } + + fn show_parts(&self) { + for child in self.part_list.get_children() { + self.part_list.remove(&child); + } + + for (index, part) in self.structure.borrow().iter().enumerate() { + let label = gtk::Label::new(Some(&part.get_title())); + label.set_halign(gtk::Align::Start); + let row = SelectorRow::new(index.try_into().unwrap(), &label); + row.show_all(); + self.part_list.insert(&row, -1); + } + } + + fn get_selected_part_row(&self) -> Option { + match self.part_list.get_selected_rows().first() { + Some(row) => match row.get_child() { + Some(child) => Some(child.downcast().unwrap()), + None => None, + }, + None => None, + } + } }