mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
editor: implement tracks editor parts list
This commit is contained in:
parent
642d9340e5
commit
53680df13d
15 changed files with 311 additions and 32 deletions
35
data/ui/tracks_editor_parts_popover.blp
Normal file
35
data/ui/tracks_editor_parts_popover.blp
Normal file
|
|
@ -0,0 +1,35 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template $MusicusTracksEditorPartsPopover: Gtk.Popover {
|
||||||
|
styles [
|
||||||
|
"selector"
|
||||||
|
]
|
||||||
|
|
||||||
|
Adw.ToolbarView {
|
||||||
|
[top]
|
||||||
|
Gtk.SearchEntry search_entry {
|
||||||
|
placeholder-text: _("Search parts…");
|
||||||
|
margin-start: 8;
|
||||||
|
margin-end: 8;
|
||||||
|
margin-top: 8;
|
||||||
|
margin-bottom: 6;
|
||||||
|
search-changed => $search_changed() swapped;
|
||||||
|
activate => $activate() swapped;
|
||||||
|
stop-search => $stop_search() swapped;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.ScrolledWindow scrolled_window {
|
||||||
|
height-request: 200;
|
||||||
|
|
||||||
|
Gtk.ListBox list_box {
|
||||||
|
styles [
|
||||||
|
"selector-list"
|
||||||
|
]
|
||||||
|
|
||||||
|
selection-mode: none;
|
||||||
|
activate-on-single-click: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -13,8 +13,21 @@ template $MusicusTracksEditorTrackRow: Adw.ActionRow {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Gtk.Button reset_button {
|
||||||
|
icon-name: "edit-clear-symbolic";
|
||||||
|
tooltip-text: _("Clear selected work parts");
|
||||||
|
visible: false;
|
||||||
|
valign: center;
|
||||||
|
clicked => $reset() swapped;
|
||||||
|
|
||||||
|
styles [
|
||||||
|
"flat"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
|
||||||
Gtk.Button {
|
Gtk.Button {
|
||||||
icon-name: "user-trash-symbolic";
|
icon-name: "user-trash-symbolic";
|
||||||
|
tooltip-text: _("Remove this track");
|
||||||
valign: center;
|
valign: center;
|
||||||
clicked => $remove() swapped;
|
clicked => $remove() swapped;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -149,14 +149,20 @@ impl Work {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn composers_string(&self) -> String {
|
pub fn composers_string(&self) -> Option<String> {
|
||||||
// TODO: Include roles except default composer.
|
// TODO: Include roles except default composer.
|
||||||
// TODO: Think about works without composers.
|
let composers_string = self
|
||||||
self.persons
|
.persons
|
||||||
.iter()
|
.iter()
|
||||||
.map(|p| p.person.name.get().to_string())
|
.map(|p| p.person.name.get().to_string())
|
||||||
.collect::<Vec<String>>()
|
.collect::<Vec<String>>()
|
||||||
.join(", ")
|
.join(", ");
|
||||||
|
|
||||||
|
if composers_string.is_empty() {
|
||||||
|
None
|
||||||
|
} else {
|
||||||
|
Some(composers_string)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -169,8 +175,11 @@ impl PartialEq for Work {
|
||||||
|
|
||||||
impl Display for Work {
|
impl Display for Work {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
// TODO: Handle works without composers.
|
if let Some(composers) = self.composers_string() {
|
||||||
write!(f, "{}: {}", self.composers_string(), self.name)
|
write!(f, "{}: {}", composers, self.name)
|
||||||
|
} else {
|
||||||
|
write!(f, "{}", self.name)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,7 +79,10 @@ impl MusicusEnsembleEditor {
|
||||||
|
|
||||||
if let Some(ensemble) = ensemble {
|
if let Some(ensemble) = ensemble {
|
||||||
obj.imp().save_row.set_title(&gettext("Save changes"));
|
obj.imp().save_row.set_title(&gettext("Save changes"));
|
||||||
obj.imp().ensemble_id.set(ensemble.ensemble_id.clone()).unwrap();
|
obj.imp()
|
||||||
|
.ensemble_id
|
||||||
|
.set(ensemble.ensemble_id.clone())
|
||||||
|
.unwrap();
|
||||||
obj.imp().name_editor.set_translation(&ensemble.name);
|
obj.imp().name_editor.set_translation(&ensemble.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -79,14 +79,20 @@ impl MusicusInstrumentEditor {
|
||||||
|
|
||||||
if let Some(instrument) = instrument {
|
if let Some(instrument) = instrument {
|
||||||
obj.imp().save_row.set_title(&gettext("Save changes"));
|
obj.imp().save_row.set_title(&gettext("Save changes"));
|
||||||
obj.imp().instrument_id.set(instrument.instrument_id.clone()).unwrap();
|
obj.imp()
|
||||||
|
.instrument_id
|
||||||
|
.set(instrument.instrument_id.clone())
|
||||||
|
.unwrap();
|
||||||
obj.imp().name_editor.set_translation(&instrument.name);
|
obj.imp().name_editor.set_translation(&instrument.name);
|
||||||
}
|
}
|
||||||
|
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn connect_created<F: Fn(&Self, Instrument) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
pub fn connect_created<F: Fn(&Self, Instrument) + 'static>(
|
||||||
|
&self,
|
||||||
|
f: F,
|
||||||
|
) -> glib::SignalHandlerId {
|
||||||
self.connect_local("created", true, move |values| {
|
self.connect_local("created", true, move |values| {
|
||||||
let obj = values[0].get::<Self>().unwrap();
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
let instrument = values[1].get::<Instrument>().unwrap();
|
let instrument = values[1].get::<Instrument>().unwrap();
|
||||||
|
|
|
||||||
|
|
@ -13,6 +13,7 @@ pub mod recording_selector_popover;
|
||||||
pub mod role_editor;
|
pub mod role_editor;
|
||||||
pub mod role_selector_popover;
|
pub mod role_selector_popover;
|
||||||
pub mod tracks_editor;
|
pub mod tracks_editor;
|
||||||
|
pub mod tracks_editor_parts_popover;
|
||||||
pub mod tracks_editor_track_row;
|
pub mod tracks_editor_track_row;
|
||||||
pub mod translation_editor;
|
pub mod translation_editor;
|
||||||
pub mod translation_entry;
|
pub mod translation_entry;
|
||||||
|
|
|
||||||
|
|
@ -248,7 +248,11 @@ impl MusicusRecordingEditor {
|
||||||
|
|
||||||
fn set_work(&self, work: Work) {
|
fn set_work(&self, work: Work) {
|
||||||
self.imp().work_row.set_title(&work.name.get());
|
self.imp().work_row.set_title(&work.name.get());
|
||||||
self.imp().work_row.set_subtitle(&work.composers_string());
|
self.imp().work_row.set_subtitle(
|
||||||
|
&work
|
||||||
|
.composers_string()
|
||||||
|
.unwrap_or_else(|| gettext("No composers")),
|
||||||
|
);
|
||||||
self.imp().work.replace(Some(work));
|
self.imp().work.replace(Some(work));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -181,12 +181,9 @@ impl TracksEditor {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_recording(&self, recording: Recording) {
|
fn set_recording(&self, recording: Recording) {
|
||||||
self.imp().recording_row.set_title(&format!(
|
self.imp()
|
||||||
"{}: {}",
|
.recording_row
|
||||||
recording.work.composers_string(),
|
.set_title(&recording.work.to_string());
|
||||||
recording.work.name.get(),
|
|
||||||
));
|
|
||||||
|
|
||||||
self.imp()
|
self.imp()
|
||||||
.recording_row
|
.recording_row
|
||||||
.set_subtitle(&recording.performers_string());
|
.set_subtitle(&recording.performers_string());
|
||||||
|
|
|
||||||
171
src/editor/tracks_editor_parts_popover.rs
Normal file
171
src/editor/tracks_editor_parts_popover.rs
Normal file
|
|
@ -0,0 +1,171 @@
|
||||||
|
use super::activatable_row::MusicusActivatableRow;
|
||||||
|
use crate::db::models::Work;
|
||||||
|
|
||||||
|
use gtk::{
|
||||||
|
glib::{self, subclass::Signal},
|
||||||
|
prelude::*,
|
||||||
|
subclass::prelude::*,
|
||||||
|
};
|
||||||
|
use once_cell::sync::Lazy;
|
||||||
|
|
||||||
|
use std::cell::{OnceCell, RefCell};
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||||
|
#[template(file = "data/ui/tracks_editor_parts_popover.blp")]
|
||||||
|
pub struct TracksEditorPartsPopover {
|
||||||
|
pub parts: OnceCell<Vec<Work>>,
|
||||||
|
pub parts_filtered: RefCell<Vec<Work>>,
|
||||||
|
|
||||||
|
#[template_child]
|
||||||
|
pub search_entry: TemplateChild<gtk::SearchEntry>,
|
||||||
|
#[template_child]
|
||||||
|
pub scrolled_window: TemplateChild<gtk::ScrolledWindow>,
|
||||||
|
#[template_child]
|
||||||
|
pub list_box: TemplateChild<gtk::ListBox>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for TracksEditorPartsPopover {
|
||||||
|
const NAME: &'static str = "MusicusTracksEditorPartsPopover";
|
||||||
|
type Type = super::TracksEditorPartsPopover;
|
||||||
|
type ParentType = gtk::Popover;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
klass.bind_template_instance_callbacks();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for TracksEditorPartsPopover {
|
||||||
|
fn constructed(&self) {
|
||||||
|
self.parent_constructed();
|
||||||
|
|
||||||
|
self.obj()
|
||||||
|
.connect_visible_notify(|obj: &super::TracksEditorPartsPopover| {
|
||||||
|
if obj.is_visible() {
|
||||||
|
obj.imp().search_entry.set_text("");
|
||||||
|
obj.imp().search_entry.grab_focus();
|
||||||
|
obj.imp().scrolled_window.vadjustment().set_value(0.0);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
fn signals() -> &'static [Signal] {
|
||||||
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
||||||
|
vec![
|
||||||
|
Signal::builder("part-selected")
|
||||||
|
.param_types([Work::static_type()])
|
||||||
|
.build(),
|
||||||
|
Signal::builder("create").build(),
|
||||||
|
]
|
||||||
|
});
|
||||||
|
|
||||||
|
SIGNALS.as_ref()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl WidgetImpl for TracksEditorPartsPopover {
|
||||||
|
// TODO: Fix focus.
|
||||||
|
fn focus(&self, direction_type: gtk::DirectionType) -> bool {
|
||||||
|
if direction_type == gtk::DirectionType::Down {
|
||||||
|
self.list_box.child_focus(direction_type)
|
||||||
|
} else {
|
||||||
|
self.parent_focus(direction_type)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PopoverImpl for TracksEditorPartsPopover {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct TracksEditorPartsPopover(ObjectSubclass<imp::TracksEditorPartsPopover>)
|
||||||
|
@extends gtk::Widget, gtk::Popover;
|
||||||
|
}
|
||||||
|
|
||||||
|
#[gtk::template_callbacks]
|
||||||
|
impl TracksEditorPartsPopover {
|
||||||
|
pub fn new(parts: Vec<Work>) -> Self {
|
||||||
|
let obj: Self = glib::Object::new();
|
||||||
|
obj.imp().parts.set(parts).unwrap();
|
||||||
|
obj.search("");
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn connect_part_selected<F: Fn(&Self, Work) + 'static>(
|
||||||
|
&self,
|
||||||
|
f: F,
|
||||||
|
) -> glib::SignalHandlerId {
|
||||||
|
self.connect_local("part-selected", true, move |values| {
|
||||||
|
let obj = values[0].get::<Self>().unwrap();
|
||||||
|
let role = values[1].get::<Work>().unwrap();
|
||||||
|
f(&obj, role);
|
||||||
|
None
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn search_changed(&self, entry: >k::SearchEntry) {
|
||||||
|
self.search(&entry.text());
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn activate(&self, _: >k::SearchEntry) {
|
||||||
|
if let Some(work) = self.imp().parts_filtered.borrow().first() {
|
||||||
|
self.select(work.clone());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn stop_search(&self, _: >k::SearchEntry) {
|
||||||
|
self.popdown();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn search(&self, search: &str) {
|
||||||
|
let imp = self.imp();
|
||||||
|
|
||||||
|
let parts_filtered = imp
|
||||||
|
.parts
|
||||||
|
.get()
|
||||||
|
.unwrap()
|
||||||
|
.iter()
|
||||||
|
.filter(|p| p.name.get().to_lowercase().contains(&search.to_lowercase()))
|
||||||
|
.cloned()
|
||||||
|
.collect::<Vec<Work>>();
|
||||||
|
|
||||||
|
imp.list_box.remove_all();
|
||||||
|
|
||||||
|
for part in &parts_filtered {
|
||||||
|
let row = MusicusActivatableRow::new(
|
||||||
|
>k::Label::builder()
|
||||||
|
.label(part.to_string())
|
||||||
|
.halign(gtk::Align::Start)
|
||||||
|
.build(),
|
||||||
|
);
|
||||||
|
|
||||||
|
row.set_tooltip_text(Some(&part.to_string()));
|
||||||
|
|
||||||
|
let part = part.clone();
|
||||||
|
let obj = self.clone();
|
||||||
|
row.connect_activated(move |_: &MusicusActivatableRow| {
|
||||||
|
obj.select(part.clone());
|
||||||
|
});
|
||||||
|
|
||||||
|
imp.list_box.append(&row);
|
||||||
|
}
|
||||||
|
|
||||||
|
imp.parts_filtered.replace(parts_filtered);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn select(&self, part: Work) {
|
||||||
|
self.emit_by_name::<()>("part-selected", &[&part]);
|
||||||
|
self.popdown();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,5 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
db::models::{Recording, Work},
|
db::models::{Recording, Work},
|
||||||
|
editor::tracks_editor_parts_popover::TracksEditorPartsPopover,
|
||||||
library::MusicusLibrary,
|
library::MusicusLibrary,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -29,8 +30,12 @@ mod imp {
|
||||||
pub recording: OnceCell<Recording>,
|
pub recording: OnceCell<Recording>,
|
||||||
pub track_data: RefCell<TracksEditorTrackData>,
|
pub track_data: RefCell<TracksEditorTrackData>,
|
||||||
|
|
||||||
|
pub parts_popover: OnceCell<TracksEditorPartsPopover>,
|
||||||
|
|
||||||
#[template_child]
|
#[template_child]
|
||||||
pub select_parts_box: TemplateChild<gtk::Box>,
|
pub select_parts_box: TemplateChild<gtk::Box>,
|
||||||
|
#[template_child]
|
||||||
|
pub reset_button: TemplateChild<gtk::Button>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[glib::object_subclass]
|
#[glib::object_subclass]
|
||||||
|
|
@ -101,9 +106,23 @@ impl TracksEditorTrackRow {
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let parts_popover = TracksEditorPartsPopover::new(recording.work.parts.clone());
|
||||||
|
|
||||||
|
parts_popover.connect_part_selected(clone!(
|
||||||
|
#[weak]
|
||||||
|
obj,
|
||||||
|
move |_, part| {
|
||||||
|
obj.imp().track_data.borrow_mut().parts.push(part);
|
||||||
|
obj.parts_updated();
|
||||||
|
}
|
||||||
|
));
|
||||||
|
|
||||||
|
obj.imp().select_parts_box.append(&parts_popover);
|
||||||
|
obj.imp().parts_popover.set(parts_popover).unwrap();
|
||||||
|
|
||||||
obj.imp().recording.set(recording).unwrap();
|
obj.imp().recording.set(recording).unwrap();
|
||||||
obj.imp().track_data.replace(track_data);
|
obj.imp().track_data.replace(track_data);
|
||||||
obj.update_title();
|
obj.parts_updated();
|
||||||
|
|
||||||
obj
|
obj
|
||||||
}
|
}
|
||||||
|
|
@ -122,7 +141,13 @@ impl TracksEditorTrackRow {
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
fn select_parts(&self) {
|
fn select_parts(&self) {
|
||||||
// self.imp().parts_popover.get().unwrap().popup();
|
self.imp().parts_popover.get().unwrap().popup();
|
||||||
|
}
|
||||||
|
|
||||||
|
#[template_callback]
|
||||||
|
fn reset(&self) {
|
||||||
|
self.imp().track_data.borrow_mut().parts.clear();
|
||||||
|
self.parts_updated();
|
||||||
}
|
}
|
||||||
|
|
||||||
#[template_callback]
|
#[template_callback]
|
||||||
|
|
@ -130,9 +155,11 @@ impl TracksEditorTrackRow {
|
||||||
self.emit_by_name::<()>("remove", &[]);
|
self.emit_by_name::<()>("remove", &[]);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn update_title(&self) {
|
fn parts_updated(&self) {
|
||||||
let parts = &self.imp().track_data.borrow().parts;
|
let parts = &self.imp().track_data.borrow().parts;
|
||||||
|
|
||||||
|
self.imp().reset_button.set_visible(!parts.is_empty());
|
||||||
|
|
||||||
self.set_title(&if parts.is_empty() {
|
self.set_title(&if parts.is_empty() {
|
||||||
if self.imp().recording.get().unwrap().work.parts.is_empty() {
|
if self.imp().recording.get().unwrap().work.parts.is_empty() {
|
||||||
gettext("Whole work")
|
gettext("Whole work")
|
||||||
|
|
|
||||||
|
|
@ -301,8 +301,12 @@ impl MusicusHomePage {
|
||||||
}
|
}
|
||||||
Tag::Work(work) => {
|
Tag::Work(work) => {
|
||||||
imp.title_label.set_text(&work.name.get());
|
imp.title_label.set_text(&work.name.get());
|
||||||
imp.subtitle_label.set_text(&work.composers_string());
|
if let Some(composers) = work.composers_string() {
|
||||||
imp.subtitle_label.set_visible(true);
|
imp.subtitle_label.set_text(&composers);
|
||||||
|
imp.subtitle_label.set_visible(true);
|
||||||
|
} else {
|
||||||
|
imp.subtitle_label.set_visible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -222,7 +222,7 @@ impl MusicusPlayer {
|
||||||
if tracks.len() == 1 {
|
if tracks.len() == 1 {
|
||||||
items.push(PlaylistItem::new(
|
items.push(PlaylistItem::new(
|
||||||
true,
|
true,
|
||||||
Some(&recording.work.composers_string()),
|
recording.work.composers_string(),
|
||||||
&recording.work.name.get(),
|
&recording.work.name.get(),
|
||||||
Some(&performances),
|
Some(&performances),
|
||||||
None,
|
None,
|
||||||
|
|
@ -250,7 +250,7 @@ impl MusicusPlayer {
|
||||||
|
|
||||||
items.push(PlaylistItem::new(
|
items.push(PlaylistItem::new(
|
||||||
true,
|
true,
|
||||||
Some(&recording.work.composers_string()),
|
recording.work.composers_string(),
|
||||||
&recording.work.name.get(),
|
&recording.work.name.get(),
|
||||||
Some(&performances),
|
Some(&performances),
|
||||||
Some(&track_title(&first_track, 1)),
|
Some(&track_title(&first_track, 1)),
|
||||||
|
|
@ -261,7 +261,7 @@ impl MusicusPlayer {
|
||||||
for (index, track) in tracks.enumerate() {
|
for (index, track) in tracks.enumerate() {
|
||||||
items.push(PlaylistItem::new(
|
items.push(PlaylistItem::new(
|
||||||
false,
|
false,
|
||||||
Some(&recording.work.composers_string()),
|
recording.work.composers_string(),
|
||||||
&recording.work.name.get(),
|
&recording.work.name.get(),
|
||||||
Some(&performances),
|
Some(&performances),
|
||||||
// track number = track index + 1 (first track) + 1 (zero based)
|
// track number = track index + 1 (first track) + 1 (zero based)
|
||||||
|
|
|
||||||
|
|
@ -52,7 +52,7 @@ glib::wrapper! {
|
||||||
impl PlaylistItem {
|
impl PlaylistItem {
|
||||||
pub fn new(
|
pub fn new(
|
||||||
is_title: bool,
|
is_title: bool,
|
||||||
composers: Option<&str>,
|
composers: Option<String>,
|
||||||
work: &str,
|
work: &str,
|
||||||
performers: Option<&str>,
|
performers: Option<&str>,
|
||||||
part_title: Option<&str>,
|
part_title: Option<&str>,
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,12 @@
|
||||||
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
|
|
||||||
use std::cell::OnceCell;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
db::models::Recording, editor::recording_editor::MusicusRecordingEditor,
|
db::models::Recording, editor::recording_editor::MusicusRecordingEditor,
|
||||||
library::MusicusLibrary,
|
library::MusicusLibrary,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
use gettextrs::gettext;
|
||||||
|
use gtk::{gio, glib, prelude::*, subclass::prelude::*};
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
mod imp {
|
mod imp {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
|
|
@ -83,8 +84,12 @@ impl MusicusRecordingTile {
|
||||||
let imp = obj.imp();
|
let imp = obj.imp();
|
||||||
|
|
||||||
imp.work_label.set_label(&recording.work.name.get());
|
imp.work_label.set_label(&recording.work.name.get());
|
||||||
imp.composer_label
|
imp.composer_label.set_label(
|
||||||
.set_label(&recording.work.composers_string());
|
&recording
|
||||||
|
.work
|
||||||
|
.composers_string()
|
||||||
|
.unwrap_or_else(|| gettext("No composers")),
|
||||||
|
);
|
||||||
imp.performances_label
|
imp.performances_label
|
||||||
.set_label(&recording.performers_string());
|
.set_label(&recording.performers_string());
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -55,8 +55,12 @@ impl MusicusTagTile {
|
||||||
}
|
}
|
||||||
Tag::Work(work) => {
|
Tag::Work(work) => {
|
||||||
imp.title_label.set_label(work.name.get());
|
imp.title_label.set_label(work.name.get());
|
||||||
imp.subtitle_label.set_label(&work.composers_string());
|
if let Some(composers) = work.composers_string() {
|
||||||
imp.subtitle_label.set_visible(true);
|
imp.subtitle_label.set_label(&composers);
|
||||||
|
imp.subtitle_label.set_visible(true);
|
||||||
|
} else {
|
||||||
|
imp.subtitle_label.set_visible(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue