Add recording editor

This commit is contained in:
Elias Projahn 2020-10-09 23:02:50 +02:00
parent c3e7663be9
commit bd3a61c4bf
5 changed files with 386 additions and 3 deletions

View file

@ -9,6 +9,7 @@
<file preprocess="xml-stripblanks">ui/performance_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/recording_editor.ui</file>
<file preprocess="xml-stripblanks">ui/section_editor.ui</file> <file preprocess="xml-stripblanks">ui/section_editor.ui</file>
<file preprocess="xml-stripblanks">ui/window.ui</file> <file preprocess="xml-stripblanks">ui/window.ui</file>
<file preprocess="xml-stripblanks">ui/work_editor.ui</file> <file preprocess="xml-stripblanks">ui/work_editor.ui</file>

231
res/ui/recording_editor.ui Normal file
View file

@ -0,0 +1,231 @@
<?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="default-width">500</property>
<property name="default-height">450</property>
<property name="destroy-with-parent">True</property>
<property name="type-hint">dialog</property>
<child>
<object class="GtkNotebook">
<property name="visible">True</property>
<property name="can-focus">True</property>
<child>
<!-- n-columns=2 n-rows=2 -->
<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">Comment</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">1</property>
</packing>
</child>
<child>
<object class="GtkButton" id="work_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="work_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>
</packing>
</child>
<child>
<object class="GtkEntry" id="comment_button">
<property name="visible">True</property>
<property name="can-focus">True</property>
</object>
<packing>
<property name="left-attach">1</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">Work</property>
</object>
<packing>
<property name="left-attach">0</property>
<property name="top-attach">0</property>
</packing>
</child>
</object>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Overview</property>
</object>
<packing>
<property name="tab-fill">False</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">18</property>
<property name="spacing">6</property>
<child>
<object class="GtkScrolledWindow">
<property name="visible">True</property>
<property name="can-focus">True</property>
<property name="shadow-type">in</property>
<child>
<object class="GtkViewport">
<property name="visible">True</property>
<property name="can-focus">False</property>
<child>
<object class="GtkListBox" id="performer_list">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="hexpand">True</property>
<property name="vexpand">True</property>
<child type="placeholder">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">No performers added.</property>
</object>
</child>
</object>
</child>
</object>
</child>
</object>
<packing>
<property name="expand">True</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkBox">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="border-width">0</property>
<property name="orientation">vertical</property>
<property name="spacing">6</property>
<child>
<object class="GtkButton" id="add_performer_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">list-add-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">0</property>
</packing>
</child>
<child>
<object class="GtkButton" id="remove_performer_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">list-remove-symbolic</property>
</object>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="expand">False</property>
<property name="fill">True</property>
<property name="position">1</property>
</packing>
</child>
</object>
<packing>
<property name="position">1</property>
</packing>
</child>
<child type="tab">
<object class="GtkLabel">
<property name="visible">True</property>
<property name="can-focus">False</property>
<property name="label" translatable="yes">Performers</property>
</object>
<packing>
<property name="position">1</property>
<property name="tab-fill">False</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">Recording</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

@ -22,6 +22,9 @@ pub use person_editor::*;
pub mod person_selector; pub mod person_selector;
pub use person_selector::*; pub use person_selector::*;
pub mod recording_editor;
pub use recording_editor::*;
pub mod section_editor; pub mod section_editor;
pub use section_editor::*; pub use section_editor::*;

View file

@ -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<F>
where
F: Fn(RecordingDescription) -> () + 'static,
{
backend: Rc<Backend>,
window: gtk::Window,
callback: F,
id: i64,
save_button: gtk::Button,
work_label: gtk::Label,
work: RefCell<Option<WorkDescription>>,
performers: RefCell<Vec<PerformanceDescription>>,
performer_list: gtk::ListBox,
}
impl<F> RecordingEditor<F>
where
F: Fn(RecordingDescription) -> () + 'static,
{
pub fn new<P: IsA<gtk::Window>>(
backend: Rc<Backend>,
parent: &P,
recording: Option<RecordingDescription>,
callback: F,
) -> Rc<Self> {
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::<u32>().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<SelectorRow> {
match self.performer_list.get_selected_rows().first() {
Some(row) => match row.get_child() {
Some(child) => Some(child.downcast().unwrap()),
None => None,
},
None => None,
}
}
}

View file

@ -124,9 +124,15 @@ impl Window {
}) })
); );
action!(result.window, "add-recording", |_, _| { action!(
println!("TODO: Add recording."); 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!( action!(
result.window, result.window,