Add performance editor

This commit is contained in:
Elias Projahn 2020-10-09 23:02:43 +02:00
parent a7e7fe7b89
commit c3e7663be9
6 changed files with 345 additions and 3 deletions

View file

@ -6,6 +6,7 @@
<file preprocess="xml-stripblanks">ui/instrument_editor.ui</file> <file preprocess="xml-stripblanks">ui/instrument_editor.ui</file>
<file preprocess="xml-stripblanks">ui/instrument_selector.ui</file> <file preprocess="xml-stripblanks">ui/instrument_selector.ui</file>
<file preprocess="xml-stripblanks">ui/part_editor.ui</file> <file preprocess="xml-stripblanks">ui/part_editor.ui</file>
<file preprocess="xml-stripblanks">ui/performance_editor.ui</file>
<file preprocess="xml-stripblanks">ui/person_editor.ui</file> <file preprocess="xml-stripblanks">ui/person_editor.ui</file>
<file preprocess="xml-stripblanks">ui/person_selector.ui</file> <file preprocess="xml-stripblanks">ui/person_selector.ui</file>
<file preprocess="xml-stripblanks">ui/section_editor.ui</file> <file preprocess="xml-stripblanks">ui/section_editor.ui</file>

View file

@ -0,0 +1,168 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Generated with glade 3.38.1 -->
<interface>
<requires lib="gtk+" version="3.22"/>
<object class="GtkWindow" id="window">
<property name="can-focus">False</property>
<property name="modal">True</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<child>
<!-- n-columns=3 n-rows=3 -->
<object class="GtkGrid">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="row-spacing">12</property>
<property name="column-spacing">6</property>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Person</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Ensemble</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">end</property>
<property name="label" translatable="yes">Role</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="role_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="hexpand">True</property>
<child>
<object class="GtkLabel" id="role_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Select …</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="person_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="hexpand">True</property>
<child>
<object class="GtkLabel" id="person_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Select …</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">0</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="ensemble_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<property name="hexpand">True</property>
<child>
<object class="GtkLabel" id="ensemble_label">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="halign">start</property>
<property name="label" translatable="yes">Select …</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">1</property>
<property name="top-attach">1</property>
<property name="width">2</property>
</packing>
</child>
<child>
<object class="GtkButton" id="reset_role_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<child>
<object class="GtkImage">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="icon-name">edit-undo-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="left-attach">2</property>
<property name="top-attach">2</property>
</packing>
</child>
</object>
</child>
<child type="titlebar">
<object class="GtkHeaderBar">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="title" translatable="yes">Performance</property>
<child>
<object class="GtkButton" id="cancel_button">
<property name="label" translatable="yes">Cancel</property>
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
</object>
</child>
<child>
<object class="GtkButton" id="save_button">
<property name="label" translatable="yes">Save</property>
<property name="visible">True</property>
<property name="sensitive">False</property>
<property name="can-focus">True</property>
<property name="receives-default">True</property>
<style>
<class name="suggested-action"/>
</style>
</object>
<packing>
<property name="pack-type">end</property>
<property name="position">1</property>
</packing>
</child>
</object>
</child>
</object>
</interface>

View file

@ -291,7 +291,6 @@ impl Database {
.expect("Failed to load performances!") .expect("Failed to load performances!")
.iter() .iter()
.map(|performance| PerformanceDescription { .map(|performance| PerformanceDescription {
performance: performance.clone(),
person: performance.person.map(|id| { person: performance.person.map(|id| {
self.get_person(id) self.get_person(id)
.expect("Could not find person for performance!") .expect("Could not find person for performance!")

View file

@ -86,19 +86,44 @@ impl From<WorkDescription> for WorkInsertion {
#[derive(Debug, Clone)] #[derive(Debug, Clone)]
pub struct PerformanceDescription { pub struct PerformanceDescription {
pub performance: Performance,
pub person: Option<Person>, pub person: Option<Person>,
pub ensemble: Option<Ensemble>, pub ensemble: Option<Ensemble>,
pub role: Option<Instrument>, pub role: Option<Instrument>,
} }
impl PerformanceDescription { impl PerformanceDescription {
pub fn get_title(&self) -> String {
let mut text = String::from(if self.is_person() {
self.unwrap_person().name_fl()
} else {
self.unwrap_ensemble().name
});
if self.has_role() {
text = text + " (" + &self.unwrap_role().name + ")";
}
text
}
pub fn is_person(&self) -> bool { pub fn is_person(&self) -> bool {
self.person.is_some() self.person.is_some()
} }
pub fn unwrap_person(&self) -> Person {
self.person.clone().unwrap()
}
pub fn unwrap_ensemble(&self) -> Ensemble {
self.ensemble.clone().unwrap()
}
pub fn has_role(&self) -> bool { pub fn has_role(&self) -> bool {
self.role.is_some() self.role.clone().is_some()
}
pub fn unwrap_role(&self) -> Instrument {
self.role.clone().unwrap()
} }
} }

View file

@ -13,6 +13,9 @@ pub use instrument_selector::*;
pub mod part_editor; pub mod part_editor;
pub use part_editor::*; pub use part_editor::*;
pub mod performance_editor;
pub use performance_editor::*;
pub mod person_editor; pub mod person_editor;
pub use person_editor::*; pub use person_editor::*;

View file

@ -0,0 +1,146 @@
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;
pub struct PerformanceEditor<F>
where
F: Fn(PerformanceDescription) -> () + 'static,
{
backend: Rc<Backend>,
window: gtk::Window,
callback: F,
save_button: gtk::Button,
person_label: gtk::Label,
ensemble_label: gtk::Label,
role_label: gtk::Label,
person: RefCell<Option<Person>>,
ensemble: RefCell<Option<Ensemble>>,
role: RefCell<Option<Instrument>>,
}
impl<F> PerformanceEditor<F>
where
F: Fn(PerformanceDescription) -> () + 'static,
{
pub fn new<P: IsA<gtk::Window>>(
backend: Rc<Backend>,
parent: &P,
performance: Option<PerformanceDescription>,
callback: F,
) -> Rc<Self> {
let builder =
gtk::Builder::from_resource("/de/johrpan/musicus_editor/ui/performance_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, person_button);
get_widget!(builder, gtk::Button, ensemble_button);
get_widget!(builder, gtk::Button, role_button);
get_widget!(builder, gtk::Button, reset_role_button);
get_widget!(builder, gtk::Label, person_label);
get_widget!(builder, gtk::Label, ensemble_label);
get_widget!(builder, gtk::Label, role_label);
let (person, ensemble, role) = match performance {
Some(performance) => {
match performance.person.clone() {
Some(person) => {
person_label.set_text(&person.name_fl());
save_button.set_sensitive(true);
}
None => (),
}
match performance.ensemble.clone() {
Some(ensemble) => {
ensemble_label.set_text(&ensemble.name);
save_button.set_sensitive(true);
}
None => (),
}
match performance.role.clone() {
Some(role) => role_label.set_text(&role.name),
None => (),
}
(performance.person, performance.ensemble, performance.role)
}
None => (None, None, None),
};
let result = Rc::new(PerformanceEditor {
backend: backend,
window: window,
callback: callback,
save_button: save_button,
person_label: person_label,
ensemble_label: ensemble_label,
role_label: role_label,
person: RefCell::new(person),
ensemble: RefCell::new(ensemble),
role: RefCell::new(role),
});
cancel_button.connect_clicked(clone!(@strong result => move |_| {
result.window.close();
}));
result
.save_button
.connect_clicked(clone!(@strong result => move |_| {
(result.callback)(PerformanceDescription {
person: result.person.borrow().clone(),
ensemble: result.ensemble.borrow().clone(),
role: result.role.borrow().clone(),
});
result.window.close();
}));
person_button.connect_clicked(clone!(@strong result => move |_| {
PersonSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |person| {
result.person.replace(Some(person.clone()));
result.person_label.set_text(&person.name_fl());
result.ensemble.replace(None);
result.ensemble_label.set_text("Select …");
result.save_button.set_sensitive(true);
})).show();
}));
ensemble_button.connect_clicked(clone!(@strong result => move |_| {
EnsembleSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |ensemble| {
result.ensemble.replace(Some(ensemble.clone()));
result.ensemble_label.set_text(&ensemble.name);
result.person.replace(None);
result.person_label.set_text("Select …");
result.save_button.set_sensitive(true);
})).show();
}));
role_button.connect_clicked(clone!(@strong result => move |_| {
InstrumentSelector::new(result.backend.clone(), &result.window, clone!(@strong result => move |role| {
result.role.replace(Some(role.clone()));
result.role_label.set_text(&role.name);
})).show();
}));
reset_role_button.connect_clicked(clone!(@strong result => move |_| {
result.role.replace(None);
result.role_label.set_text("Select …");
}));
result.window.set_transient_for(Some(parent));
result
}
pub fn show(&self) {
self.window.show();
}
}