mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-27 04:07:25 +01:00
Remove work sections
This commit is contained in:
parent
3350c6be95
commit
ee8399e93d
10 changed files with 24 additions and 332 deletions
|
|
@ -21,6 +21,5 @@
|
|||
<file preprocess="xml-stripblanks">ui/track_set_editor.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/work_editor.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/work_part_editor.ui</file>
|
||||
<file preprocess="xml-stripblanks">ui/work_section_editor.ui</file>
|
||||
</gresource>
|
||||
</gresources>
|
||||
|
|
|
|||
|
|
@ -146,12 +146,6 @@
|
|||
</attributes>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_section_button">
|
||||
<property name="has-frame">false</property>
|
||||
<property name="icon-name">folder-new-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkButton" id="add_part_button">
|
||||
<property name="has-frame">false</property>
|
||||
|
|
|
|||
|
|
@ -1,78 +0,0 @@
|
|||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<interface>
|
||||
<requires lib="gtk" version="4.0"/>
|
||||
<requires lib="libadwaita" version="1.0"/>
|
||||
<object class="GtkBox" id="widget">
|
||||
<property name="orientation">vertical</property>
|
||||
<child>
|
||||
<object class="AdwHeaderBar">
|
||||
<property name="show-start-title-buttons">false</property>
|
||||
<property name="show-end-title-buttons">false</property>
|
||||
<property name="title-widget">
|
||||
<object class="GtkLabel">
|
||||
<property name="label" translatable="yes">Work section</property>
|
||||
<style>
|
||||
<class name="title"/>
|
||||
</style>
|
||||
</object>
|
||||
</property>
|
||||
<child>
|
||||
<object class="GtkButton" id="back_button">
|
||||
<property name="icon-name">go-previous-symbolic</property>
|
||||
</object>
|
||||
</child>
|
||||
<child type="end">
|
||||
<object class="GtkButton" id="save_button">
|
||||
<property name="icon-name">object-select-symbolic</property>
|
||||
<style>
|
||||
<class name="suggested-action"/>
|
||||
</style>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkInfoBar" id="info_bar">
|
||||
<property name="revealed">False</property>
|
||||
</object>
|
||||
</child>
|
||||
<child>
|
||||
<object class="GtkScrolledWindow">
|
||||
<property name="vexpand">true</property>
|
||||
<child>
|
||||
<object class="AdwClamp">
|
||||
<property name="margin-start">12</property>
|
||||
<property name="margin-end">12</property>
|
||||
<property name="margin-top">18</property>
|
||||
<property name="margin-bottom">12</property>
|
||||
<property name="maximum-size">500</property>
|
||||
<property name="tightening-threshold">300</property>
|
||||
<child>
|
||||
<object class="GtkFrame">
|
||||
<property name="valign">start</property>
|
||||
<child>
|
||||
<object class="GtkListBox">
|
||||
<property name="selection-mode">none</property>
|
||||
<child>
|
||||
<object class="AdwActionRow">
|
||||
<property name="focusable">False</property>
|
||||
<property name="title" translatable="yes">Title</property>
|
||||
<property name="activatable-widget">title_entry</property>
|
||||
<child>
|
||||
<object class="GtkEntry" id="title_entry">
|
||||
<property name="valign">center</property>
|
||||
<property name="hexpand">True</property>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</child>
|
||||
</object>
|
||||
</interface>
|
||||
|
|
@ -15,4 +15,3 @@ pub use work::*;
|
|||
|
||||
mod performance;
|
||||
mod work_part;
|
||||
mod work_section;
|
||||
|
|
|
|||
|
|
@ -1,5 +1,4 @@
|
|||
use super::work_part::WorkPartEditor;
|
||||
use super::work_section::WorkSectionEditor;
|
||||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::selectors::{InstrumentSelector, PersonSelector};
|
||||
use crate::widgets::{List, Widget};
|
||||
|
|
@ -8,26 +7,10 @@ use anyhow::Result;
|
|||
use gettextrs::gettext;
|
||||
use glib::clone;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::db::{generate_id, Instrument, Person, Work, WorkPart, WorkSection};
|
||||
use musicus_backend::db::{generate_id, Instrument, Person, Work, WorkPart};
|
||||
use std::cell::RefCell;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// Either a work part or a work section.
|
||||
#[derive(Clone)]
|
||||
enum PartOrSection {
|
||||
Part(WorkPart),
|
||||
Section(WorkSection),
|
||||
}
|
||||
|
||||
impl PartOrSection {
|
||||
pub fn get_title(&self) -> String {
|
||||
match self {
|
||||
PartOrSection::Part(part) => part.title.clone(),
|
||||
PartOrSection::Section(section) => section.title.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// A widget for editing and creating works.
|
||||
pub struct WorkEditor {
|
||||
handle: NavigationHandle<Work>,
|
||||
|
|
@ -41,7 +24,7 @@ pub struct WorkEditor {
|
|||
id: String,
|
||||
composer: RefCell<Option<Person>>,
|
||||
instruments: RefCell<Vec<Instrument>>,
|
||||
structure: RefCell<Vec<PartOrSection>>,
|
||||
parts: RefCell<Vec<WorkPart>>,
|
||||
}
|
||||
|
||||
impl Screen<Option<Work>, Work> for WorkEditor {
|
||||
|
|
@ -62,7 +45,6 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
get_widget!(builder, gtk::Button, add_instrument_button);
|
||||
get_widget!(builder, gtk::Frame, structure_frame);
|
||||
get_widget!(builder, gtk::Button, add_part_button);
|
||||
get_widget!(builder, gtk::Button, add_section_button);
|
||||
|
||||
let instrument_list = List::new();
|
||||
instrument_frame.set_child(Some(&instrument_list.widget));
|
||||
|
|
@ -74,18 +56,7 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
let (id, composer, instruments, structure) = match work {
|
||||
Some(work) => {
|
||||
title_entry.set_text(&work.title);
|
||||
|
||||
let mut structure = Vec::new();
|
||||
|
||||
for part in work.parts {
|
||||
structure.push(PartOrSection::Part(part));
|
||||
}
|
||||
|
||||
for section in work.sections {
|
||||
structure.insert(section.before_index, PartOrSection::Section(section));
|
||||
}
|
||||
|
||||
(work.id, Some(work.composer), work.instruments, structure)
|
||||
(work.id, Some(work.composer), work.instruments, work.parts)
|
||||
}
|
||||
None => (generate_id(), None, Vec::new(), Vec::new()),
|
||||
};
|
||||
|
|
@ -102,7 +73,7 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
part_list,
|
||||
composer: RefCell::new(composer),
|
||||
instruments: RefCell::new(instruments),
|
||||
structure: RefCell::new(structure),
|
||||
parts: RefCell::new(structure),
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
|
@ -178,14 +149,14 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
}));
|
||||
|
||||
this.part_list.set_make_widget_cb(clone!(@weak this => @default-panic, move |index| {
|
||||
let pos = &this.structure.borrow()[index];
|
||||
let part = &this.parts.borrow()[index];
|
||||
|
||||
let delete_button = gtk::Button::from_icon_name(Some("user-trash-symbolic"));
|
||||
delete_button.set_valign(gtk::Align::Center);
|
||||
|
||||
delete_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
let length = {
|
||||
let mut structure = this.structure.borrow_mut();
|
||||
let mut structure = this.parts.borrow_mut();
|
||||
structure.remove(index);
|
||||
structure.len()
|
||||
};
|
||||
|
|
@ -198,57 +169,37 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
|
||||
edit_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
spawn!(@clone this, async move {
|
||||
let part_or_section = this.structure.borrow()[index].clone();
|
||||
match part_or_section {
|
||||
PartOrSection::Part(part) => {
|
||||
if let Some(part) = push!(this.handle, WorkPartEditor, Some(part)).await {
|
||||
let length = {
|
||||
let mut structure = this.structure.borrow_mut();
|
||||
structure[index] = PartOrSection::Part(part);
|
||||
structure.len()
|
||||
};
|
||||
let part = this.parts.borrow()[index].clone();
|
||||
if let Some(part) = push!(this.handle, WorkPartEditor, Some(part)).await {
|
||||
let length = {
|
||||
let mut structure = this.parts.borrow_mut();
|
||||
structure[index] = part;
|
||||
structure.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
}
|
||||
}
|
||||
PartOrSection::Section(section) => {
|
||||
if let Some(section) = push!(this.handle, WorkSectionEditor, Some(section)).await {
|
||||
let length = {
|
||||
let mut structure = this.structure.borrow_mut();
|
||||
structure[index] = PartOrSection::Section(section);
|
||||
structure.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
}
|
||||
}
|
||||
this.part_list.update(length);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
let row = adw::ActionRowBuilder::new()
|
||||
.focusable(false)
|
||||
.title(&pos.get_title())
|
||||
.title(&part.title)
|
||||
.activatable_widget(&edit_button)
|
||||
.build();
|
||||
|
||||
row.add_suffix(&delete_button);
|
||||
row.add_suffix(&edit_button);
|
||||
|
||||
if let PartOrSection::Part(_) = pos {
|
||||
// TODO: Replace with better solution to differentiate parts and sections.
|
||||
row.set_margin_start(12);
|
||||
}
|
||||
|
||||
row.upcast()
|
||||
}));
|
||||
|
||||
this.part_list
|
||||
.set_move_cb(clone!(@weak this => move |old_index, new_index| {
|
||||
let length = {
|
||||
let mut structure = this.structure.borrow_mut();
|
||||
structure.swap(old_index, new_index);
|
||||
structure.len()
|
||||
let mut parts = this.parts.borrow_mut();
|
||||
parts.swap(old_index, new_index);
|
||||
parts.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
|
|
@ -258,23 +209,9 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
spawn!(@clone this, async move {
|
||||
if let Some(part) = push!(this.handle, WorkPartEditor, None).await {
|
||||
let length = {
|
||||
let mut structure = this.structure.borrow_mut();
|
||||
structure.push(PartOrSection::Part(part));
|
||||
structure.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
}
|
||||
});
|
||||
}));
|
||||
|
||||
add_section_button.connect_clicked(clone!(@strong this => move |_| {
|
||||
spawn!(@clone this, async move {
|
||||
if let Some(section) = push!(this.handle, WorkSectionEditor, None).await {
|
||||
let length = {
|
||||
let mut structure = this.structure.borrow_mut();
|
||||
structure.push(PartOrSection::Section(section));
|
||||
structure.len()
|
||||
let mut parts = this.parts.borrow_mut();
|
||||
parts.push(part);
|
||||
parts.len()
|
||||
};
|
||||
|
||||
this.part_list.update(length);
|
||||
|
|
@ -289,7 +226,7 @@ impl Screen<Option<Work>, Work> for WorkEditor {
|
|||
}
|
||||
|
||||
this.instrument_list.update(this.instruments.borrow().len());
|
||||
this.part_list.update(this.structure.borrow().len());
|
||||
this.part_list.update(this.parts.borrow().len());
|
||||
|
||||
this
|
||||
}
|
||||
|
|
@ -311,22 +248,6 @@ impl WorkEditor {
|
|||
|
||||
/// Save the work.
|
||||
fn save(self: &Rc<Self>) -> Result<Work> {
|
||||
let mut section_count: usize = 0;
|
||||
let mut parts = Vec::new();
|
||||
let mut sections = Vec::new();
|
||||
|
||||
for (index, pos) in self.structure.borrow().iter().enumerate() {
|
||||
match pos {
|
||||
PartOrSection::Part(part) => parts.push(part.clone()),
|
||||
PartOrSection::Section(section) => {
|
||||
let mut section = section.clone();
|
||||
section.before_index = index - section_count;
|
||||
sections.push(section);
|
||||
section_count += 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let work = Work {
|
||||
id: self.id.clone(),
|
||||
title: self.title_entry.text().to_string(),
|
||||
|
|
@ -336,8 +257,7 @@ impl WorkEditor {
|
|||
.clone()
|
||||
.expect("Tried to create work without composer!"),
|
||||
instruments: self.instruments.borrow().clone(),
|
||||
parts,
|
||||
sections,
|
||||
parts: self.parts.borrow().clone(),
|
||||
};
|
||||
|
||||
self.handle.backend.db().update_work(work.clone())?;
|
||||
|
|
|
|||
|
|
@ -1,77 +0,0 @@
|
|||
use crate::navigator::{NavigationHandle, Screen};
|
||||
use crate::widgets::Widget;
|
||||
use glib::clone;
|
||||
use gtk::prelude::*;
|
||||
use gtk_macros::get_widget;
|
||||
use musicus_backend::db::WorkSection;
|
||||
use std::rc::Rc;
|
||||
|
||||
/// A dialog for creating or editing a work section.
|
||||
pub struct WorkSectionEditor {
|
||||
handle: NavigationHandle<WorkSection>,
|
||||
widget: gtk::Box,
|
||||
save_button: gtk::Button,
|
||||
title_entry: gtk::Entry,
|
||||
}
|
||||
|
||||
impl Screen<Option<WorkSection>, WorkSection> for WorkSectionEditor {
|
||||
/// Create a new section editor and optionally initialize it.
|
||||
fn new(section: Option<WorkSection>, handle: NavigationHandle<WorkSection>) -> Rc<Self> {
|
||||
// Create UI
|
||||
|
||||
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/work_section_editor.ui");
|
||||
|
||||
get_widget!(builder, gtk::Box, widget);
|
||||
get_widget!(builder, gtk::Button, back_button);
|
||||
get_widget!(builder, gtk::Button, save_button);
|
||||
get_widget!(builder, gtk::Entry, title_entry);
|
||||
|
||||
if let Some(section) = section {
|
||||
title_entry.set_text(§ion.title);
|
||||
}
|
||||
|
||||
let this = Rc::new(Self {
|
||||
handle,
|
||||
widget,
|
||||
save_button,
|
||||
title_entry,
|
||||
});
|
||||
|
||||
// Connect signals and callbacks
|
||||
|
||||
back_button.connect_clicked(clone!(@weak this => move |_| {
|
||||
this.handle.pop(None);
|
||||
}));
|
||||
|
||||
this.save_button
|
||||
.connect_clicked(clone!(@weak this => move |_| {
|
||||
let section = WorkSection {
|
||||
before_index: 0,
|
||||
title: this.title_entry.text().to_string(),
|
||||
};
|
||||
|
||||
this.handle.pop(Some(section));
|
||||
}));
|
||||
|
||||
this.title_entry
|
||||
.connect_changed(clone!(@weak this => move |_| this.validate()));
|
||||
|
||||
this.validate();
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
impl WorkSectionEditor {
|
||||
/// Validate inputs and enable/disable saving.
|
||||
fn validate(&self) {
|
||||
self.save_button
|
||||
.set_sensitive(!self.title_entry.text().is_empty());
|
||||
}
|
||||
}
|
||||
|
||||
impl Widget for WorkSectionEditor {
|
||||
fn get_widget(&self) -> gtk::Widget {
|
||||
self.widget.clone().upcast()
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue