diff --git a/res/resources.xml b/res/resources.xml index d5e16e9..d866eb3 100644 --- a/res/resources.xml +++ b/res/resources.xml @@ -5,5 +5,6 @@ ui/instrument_editor.ui ui/person_editor.ui ui/window.ui + ui/work_editor.ui diff --git a/res/ui/work_editor.ui b/res/ui/work_editor.ui new file mode 100644 index 0000000..507f36a --- /dev/null +++ b/res/ui/work_editor.ui @@ -0,0 +1,388 @@ + + + + + + False + True + 500 + 450 + True + dialog + + + True + True + + + True + False + 18 + 12 + 6 + + + True + True + True + True + + + True + False + start + Select … + + + + + 1 + 1 + + + + + True + False + end + Composer + + + 0 + 1 + + + + + True + True + + + 1 + 0 + + + + + True + False + end + Title + + + 0 + 0 + + + + + + + True + False + Overview + + + False + + + + + True + False + 6 + 6 + + + True + False + True + True + + + True + False + No instruments added. + + + + + False + 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 + 6 + 6 + + + True + False + True + True + + + True + False + No work parts added. + + + + + False + True + 0 + + + + + True + False + vertical + 6 + + + True + True + True + + + True + False + list-add-symbolic + + + + + False + True + 0 + + + + + True + True + True + + + True + False + list-remove-symbolic + + + + + False + True + 1 + + + + + True + True + True + + + True + False + folder-new-symbolic + + + + + False + True + 2 + + + + + True + True + True + + + True + False + go-down-symbolic + + + + + False + True + end + 2 + + + + + True + True + True + + + True + False + go-up-symbolic + + + + + False + True + end + 3 + + + + + True + True + True + + + True + False + edit-symbolic + + + + + False + True + 5 + + + + + False + True + 1 + + + + + 2 + + + + + True + False + Structure + + + 2 + False + + + + + + + True + False + Work + + + Cancel + True + True + True + + + + + Save + True + False + True + True + + + + end + 1 + + + + + + diff --git a/src/dialogs/mod.rs b/src/dialogs/mod.rs index 3ab4e11..ca9e250 100644 --- a/src/dialogs/mod.rs +++ b/src/dialogs/mod.rs @@ -5,4 +5,7 @@ pub mod instrument_editor; pub use instrument_editor::*; pub mod person_editor; -pub use person_editor::*; \ No newline at end of file +pub use person_editor::*; + +pub mod work_editor; +pub use work_editor::*; \ No newline at end of file diff --git a/src/dialogs/work_editor.rs b/src/dialogs/work_editor.rs new file mode 100644 index 0000000..055aaf8 --- /dev/null +++ b/src/dialogs/work_editor.rs @@ -0,0 +1,176 @@ +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; + +struct PartOrSection { + part: Option, + section: Option, +} + +impl PartOrSection { + pub fn part(part: WorkPartDescription) -> Self { + PartOrSection { + part: Some(part), + section: None, + } + } + + pub fn section(section: WorkSectionDescription) -> Self { + PartOrSection { + part: None, + section: Some(section), + } + } + + pub fn is_part(&self) -> bool { + self.part.is_some() + } + + pub fn unwrap_part(&self) -> WorkPartDescription { + self.part.as_ref().unwrap().clone() + } + + pub fn unwrap_section(&self) -> WorkSectionDescription { + self.section.as_ref().unwrap().clone() + } +} + +pub struct WorkEditor { + window: gtk::Window, + save_button: gtk::Button, + id: i64, + title_entry: gtk::Entry, + composer: RefCell>, + instruments: RefCell>, + structure: RefCell>, +} + +impl WorkEditor { + pub fn new () + 'static, P: IsA>( + db: Rc, + parent: &P, + work: Option, + callback: F, + ) -> Rc { + let builder = gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/work_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::ListBox, instrument_list); + get_widget!(builder, gtk::Button, add_instrument_button); + get_widget!(builder, gtk::Button, remove_instrument_button); + get_widget!(builder, gtk::ListBox, part_list); + 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, edit_part_button); + get_widget!(builder, gtk::Button, move_part_up_button); + get_widget!(builder, gtk::Button, move_part_down_button); + + let id = match work.clone() { + Some(work) => { + title_entry.set_text(&work.title); + work.id + } + None => rand::random::().into(), + }; + + let composer = RefCell::new(match work.clone() { + Some(work) => { + save_button.set_sensitive(true); + Some(work.composer) + } + None => None, + }); + + let instruments = RefCell::new(match work.clone() { + Some(work) => work.instruments, + None => Vec::new(), + }); + + let structure = RefCell::new(match work.clone() { + Some(work) => { + let mut result = Vec::new(); + + for part in work.parts { + result.push(PartOrSection::part(part)); + } + + for section in work.sections { + result.insert( + section + .before_index + .try_into() + .expect("Section with unrealistic before_index!"), + PartOrSection::section(section), + ); + } + + result + } + None => Vec::new(), + }); + + let result = Rc::new(WorkEditor { + window: window, + save_button: save_button, + id: id, + title_entry: title_entry, + composer: composer, + instruments: instruments, + structure: structure, + }); + + cancel_button.connect_clicked(clone!(@strong result => move |_| { + result.window.close(); + })); + + result.save_button.connect_clicked(clone!(@strong result => move |_| { + result.window.close(); + + let mut section_count: i64 = 0; + let mut parts: Vec = Vec::new(); + let mut sections: Vec = Vec::new(); + + for (index, pos) in result.structure.borrow().iter().enumerate() { + if pos.is_part() { + parts.push(pos.unwrap_part()); + } else { + let mut section = pos.unwrap_section(); + let index: i64 = index.try_into().unwrap(); + section.before_index = index - section_count; + sections.push(section); + section_count += 1; + } + } + + let work = WorkDescription { + id: result.id, + title: result.title_entry.get_text().to_string(), + composer: result.composer.borrow().clone().expect("Tried to create work without composer!"), + instruments: result.instruments.borrow().to_vec(), + parts: parts, + sections: sections, + }; + + db.update_work(work.clone().into()); + callback(work); + })); + + result.window.set_transient_for(Some(parent)); + + result + } + + pub fn show(&self) { + self.window.show(); + } +} diff --git a/src/window.rs b/src/window.rs index a7aaf6f..d6ba19f 100644 --- a/src/window.rs +++ b/src/window.rs @@ -44,9 +44,15 @@ impl Window { }) ); - action!(result.window, "add-work", |_, _| { - println!("TODO: Add work."); - }); + action!( + result.window, + "add-work", + clone!(@strong result => move |_, _| { + WorkEditor::new(result.db.clone(), &result.window, None, |work| { + println!("{:?}", work); + }).show(); + }) + ); action!( result.window,