mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
Add separate recording tile
This commit is contained in:
parent
a790d913af
commit
2143d6333b
11 changed files with 319 additions and 125 deletions
|
|
@ -21,3 +21,17 @@
|
||||||
.tile .subtitle {
|
.tile .subtitle {
|
||||||
font-size: smaller;
|
font-size: smaller;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.tile .work {
|
||||||
|
margin-top: 3px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile .composer {
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
|
|
||||||
|
.tile .performances {
|
||||||
|
margin-top: 3px;
|
||||||
|
margin-bottom: 3px;
|
||||||
|
font-size: smaller;
|
||||||
|
}
|
||||||
39
data/ui/recording_tile.blp
Normal file
39
data/ui/recording_tile.blp
Normal file
|
|
@ -0,0 +1,39 @@
|
||||||
|
using Gtk 4.0;
|
||||||
|
using Adw 1;
|
||||||
|
|
||||||
|
template $MusicusRecordingTile : Gtk.FlowBoxChild {
|
||||||
|
styles ["card", "activatable", "tile"]
|
||||||
|
|
||||||
|
Gtk.Box {
|
||||||
|
spacing: 12;
|
||||||
|
|
||||||
|
Gtk.Image {
|
||||||
|
icon-name: "media-playback-start-symbolic";
|
||||||
|
valign: start;
|
||||||
|
margin-top: 12;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.Box {
|
||||||
|
orientation: vertical;
|
||||||
|
hexpand: true;
|
||||||
|
|
||||||
|
Gtk.Label work_label {
|
||||||
|
styles ["work"]
|
||||||
|
halign: start;
|
||||||
|
wrap: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.Label composer_label {
|
||||||
|
styles ["composer"]
|
||||||
|
halign: start;
|
||||||
|
wrap: true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Gtk.Label performances_label {
|
||||||
|
styles ["performances", "dim-label"]
|
||||||
|
halign: start;
|
||||||
|
wrap: true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,7 +1,7 @@
|
||||||
using Gtk 4.0;
|
using Gtk 4.0;
|
||||||
using Adw 1;
|
using Adw 1;
|
||||||
|
|
||||||
template $MusicusTile : Gtk.FlowBoxChild {
|
template $MusicusTagTile : Gtk.FlowBoxChild {
|
||||||
styles ["card", "activatable", "tile"]
|
styles ["card", "activatable", "tile"]
|
||||||
|
|
||||||
Gtk.Box {
|
Gtk.Box {
|
||||||
|
|
@ -11,26 +11,16 @@ template $MusicusTile : Gtk.FlowBoxChild {
|
||||||
Gtk.Label title_label {
|
Gtk.Label title_label {
|
||||||
styles ["title"]
|
styles ["title"]
|
||||||
halign: start;
|
halign: start;
|
||||||
label: _("Title");
|
lines: 1;
|
||||||
|
ellipsize: end;
|
||||||
}
|
}
|
||||||
|
|
||||||
Gtk.Label subtitle_label {
|
Gtk.Label subtitle_label {
|
||||||
visible: false;
|
visible: false;
|
||||||
styles ["subtitle", "dim-label"]
|
styles ["subtitle", "dim-label"]
|
||||||
halign: start;
|
halign: start;
|
||||||
label: _("Subtitle");
|
lines: 1;
|
||||||
|
ellipsize: end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
menu item_menu {
|
|
||||||
item {
|
|
||||||
label: _("_Play");
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
label: _("_Edit");
|
|
||||||
}
|
|
||||||
item {
|
|
||||||
label: _("_Delete");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
11
po/POTFILES
11
po/POTFILES
|
|
@ -1,10 +1,11 @@
|
||||||
data/res/home_page.blp
|
data/ui/home_page.blp
|
||||||
data/res/playlist_page.blp
|
data/ui/playlist_page.blp
|
||||||
|
data/ui/recording_tile.blp
|
||||||
data/ui/search_entry.blp
|
data/ui/search_entry.blp
|
||||||
data/ui/search_tag.blp
|
data/ui/search_tag.blp
|
||||||
data/res/tile.blp
|
data/ui/tag_tile.blp
|
||||||
data/res/welcome_page.blp
|
data/ui/welcome_page.blp
|
||||||
data/res/window.blp
|
data/ui/window.blp
|
||||||
data/de.johrpan.musicus.desktop.in
|
data/de.johrpan.musicus.desktop.in
|
||||||
data/de.johrpan.musicus.appdata.xml.in
|
data/de.johrpan.musicus.appdata.xml.in
|
||||||
data/de.johrpan.musicus.gschema.xml
|
data/de.johrpan.musicus.gschema.xml
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
library::{Ensemble, LibraryQuery, MusicusLibrary, Person, Recording, Work},
|
library::{Ensemble, LibraryQuery, MusicusLibrary, Person, Recording, Work},
|
||||||
player::MusicusPlayer,
|
player::MusicusPlayer,
|
||||||
|
recording_tile::MusicusRecordingTile,
|
||||||
search_entry::MusicusSearchEntry,
|
search_entry::MusicusSearchEntry,
|
||||||
search_tag::Tag,
|
search_tag::Tag,
|
||||||
tile::MusicusTile,
|
tag_tile::MusicusTagTile,
|
||||||
};
|
};
|
||||||
use adw::subclass::{navigation_page::NavigationPageImpl, prelude::*};
|
use adw::subclass::{navigation_page::NavigationPageImpl, prelude::*};
|
||||||
use gtk::{
|
use gtk::{
|
||||||
|
|
@ -170,31 +171,28 @@ impl MusicusHomePage {
|
||||||
|
|
||||||
for composer in &results.composers {
|
for composer in &results.composers {
|
||||||
imp.composers_flow_box
|
imp.composers_flow_box
|
||||||
.append(&MusicusTile::with_title(&composer.name_fl()));
|
.append(&MusicusTagTile::new(Tag::Composer(composer.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
for performer in &results.performers {
|
for performer in &results.performers {
|
||||||
imp.performers_flow_box
|
imp.performers_flow_box
|
||||||
.append(&MusicusTile::with_title(&performer.name_fl()));
|
.append(&MusicusTagTile::new(Tag::Performer(performer.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
for ensemble in &results.ensembles {
|
for ensemble in &results.ensembles {
|
||||||
imp.ensembles_flow_box
|
imp.ensembles_flow_box
|
||||||
.append(&MusicusTile::with_title(&ensemble.name));
|
.append(&MusicusTagTile::new(Tag::Ensemble(ensemble.clone())));
|
||||||
}
|
}
|
||||||
|
|
||||||
for work in &results.works {
|
for work in &results.works {
|
||||||
imp.works_flow_box.append(&MusicusTile::with_subtitle(
|
imp.works_flow_box
|
||||||
&work.title,
|
.append(&MusicusTagTile::new(Tag::Work(work.clone())));
|
||||||
&work.composer.name_fl(),
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
for recording in &results.recordings {
|
for recording in &results.recordings {
|
||||||
imp.recordings_flow_box.append(&MusicusTile::with_subtitle(
|
let performances = self.library().performances(recording);
|
||||||
&recording.work.title,
|
imp.recordings_flow_box
|
||||||
&recording.work.composer.name_fl(),
|
.append(&MusicusRecordingTile::new(recording, performances));
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
imp.composers.replace(results.composers);
|
imp.composers.replace(results.composers);
|
||||||
|
|
|
||||||
|
|
@ -167,7 +167,7 @@ impl MusicusLibrary {
|
||||||
recordings,
|
recordings,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
LibraryQuery {
|
LibraryQuery {
|
||||||
composer: None,
|
composer: None,
|
||||||
performer: Some(performer),
|
performer: Some(performer),
|
||||||
|
|
@ -196,7 +196,7 @@ impl MusicusLibrary {
|
||||||
recordings,
|
recordings,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
LibraryQuery {
|
LibraryQuery {
|
||||||
composer: Some(composer),
|
composer: Some(composer),
|
||||||
ensemble: Some(ensemble),
|
ensemble: Some(ensemble),
|
||||||
|
|
@ -216,7 +216,7 @@ impl MusicusLibrary {
|
||||||
recordings,
|
recordings,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
LibraryQuery {
|
LibraryQuery {
|
||||||
composer: Some(composer),
|
composer: Some(composer),
|
||||||
performer: Some(performer),
|
performer: Some(performer),
|
||||||
|
|
@ -236,10 +236,9 @@ impl MusicusLibrary {
|
||||||
recordings,
|
recordings,
|
||||||
..Default::default()
|
..Default::default()
|
||||||
}
|
}
|
||||||
},
|
}
|
||||||
LibraryQuery {
|
LibraryQuery {
|
||||||
work: Some(work),
|
work: Some(work), ..
|
||||||
..
|
|
||||||
} => {
|
} => {
|
||||||
let recordings = self
|
let recordings = self
|
||||||
.con()
|
.con()
|
||||||
|
|
@ -258,6 +257,28 @@ impl MusicusLibrary {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn performances(&self, recording: &Recording) -> Vec<Performance> {
|
||||||
|
let mut performances = self
|
||||||
|
.con()
|
||||||
|
.prepare("SELECT persons.id, persons.first_name, persons.last_name, instruments.id, instruments.name FROM performances INNER JOIN persons ON persons.id = performances.person LEFT JOIN instruments ON instruments.id = performances.role INNER JOIN recordings ON performances.recording = recordings.id WHERE recordings.id IS ?1")
|
||||||
|
.unwrap()
|
||||||
|
.query_map([&recording.id], Performance::from_person_row)
|
||||||
|
.unwrap()
|
||||||
|
.collect::<rusqlite::Result<Vec<Performance>>>()
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
performances.append(&mut self
|
||||||
|
.con()
|
||||||
|
.prepare("SELECT ensembles.id, ensembles.name, instruments.id, instruments.name FROM performances INNER JOIN ensembles ON ensembles.id = performances.ensemble LEFT JOIN instruments ON instruments.id = performances.role INNER JOIN recordings ON performances.recording = recordings.id WHERE recordings.id IS ?1")
|
||||||
|
.unwrap()
|
||||||
|
.query_map([&recording.id], Performance::from_ensemble_row)
|
||||||
|
.unwrap()
|
||||||
|
.collect::<rusqlite::Result<Vec<Performance>>>()
|
||||||
|
.unwrap());
|
||||||
|
|
||||||
|
performances
|
||||||
|
}
|
||||||
|
|
||||||
fn con(&self) -> &Connection {
|
fn con(&self) -> &Connection {
|
||||||
self.imp().connection.get().unwrap()
|
self.imp().connection.get().unwrap()
|
||||||
}
|
}
|
||||||
|
|
@ -394,3 +415,60 @@ impl Recording {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||||
|
pub enum Performance {
|
||||||
|
Person(Person, Option<Role>),
|
||||||
|
Ensemble(Ensemble, Option<Role>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Performance {
|
||||||
|
pub fn from_person_row(row: &Row) -> rusqlite::Result<Self> {
|
||||||
|
let person = Person {
|
||||||
|
id: row.get(0)?,
|
||||||
|
first_name: row.get(1)?,
|
||||||
|
last_name: row.get(2)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(match row.get::<_, Option<String>>(3)? {
|
||||||
|
None => Self::Person(person, None),
|
||||||
|
Some(role_id) => Self::Person(
|
||||||
|
person,
|
||||||
|
Some(Role {
|
||||||
|
id: role_id,
|
||||||
|
name: row.get(4)?,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn from_ensemble_row(row: &Row) -> rusqlite::Result<Self> {
|
||||||
|
let ensemble = Ensemble {
|
||||||
|
id: row.get(0)?,
|
||||||
|
name: row.get(1)?,
|
||||||
|
};
|
||||||
|
|
||||||
|
Ok(match row.get::<_, Option<String>>(2)? {
|
||||||
|
None => Self::Ensemble(ensemble, None),
|
||||||
|
Some(role_id) => Self::Ensemble(
|
||||||
|
ensemble,
|
||||||
|
Some(Role {
|
||||||
|
id: role_id,
|
||||||
|
name: row.get(3)?,
|
||||||
|
}),
|
||||||
|
),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Clone, Eq)]
|
||||||
|
pub struct Role {
|
||||||
|
pub id: String,
|
||||||
|
pub name: String,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PartialEq for Role {
|
||||||
|
fn eq(&self, other: &Self) -> bool {
|
||||||
|
self.id == other.id
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,9 +4,10 @@ mod home_page;
|
||||||
mod library;
|
mod library;
|
||||||
mod player;
|
mod player;
|
||||||
mod playlist_page;
|
mod playlist_page;
|
||||||
|
mod recording_tile;
|
||||||
mod search_entry;
|
mod search_entry;
|
||||||
mod search_tag;
|
mod search_tag;
|
||||||
mod tile;
|
mod tag_tile;
|
||||||
mod welcome_page;
|
mod welcome_page;
|
||||||
mod window;
|
mod window;
|
||||||
|
|
||||||
|
|
|
||||||
86
src/recording_tile.rs
Normal file
86
src/recording_tile.rs
Normal file
|
|
@ -0,0 +1,86 @@
|
||||||
|
use crate::library::{Performance, Recording};
|
||||||
|
use gtk::{glib, subclass::prelude::*};
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||||
|
#[template(file = "data/ui/recording_tile.blp")]
|
||||||
|
pub struct MusicusRecordingTile {
|
||||||
|
#[template_child]
|
||||||
|
pub composer_label: TemplateChild<gtk::Label>,
|
||||||
|
#[template_child]
|
||||||
|
pub work_label: TemplateChild<gtk::Label>,
|
||||||
|
#[template_child]
|
||||||
|
pub performances_label: TemplateChild<gtk::Label>,
|
||||||
|
|
||||||
|
pub recording: OnceCell<Recording>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for MusicusRecordingTile {
|
||||||
|
const NAME: &'static str = "MusicusRecordingTile";
|
||||||
|
type Type = super::MusicusRecordingTile;
|
||||||
|
type ParentType = gtk::FlowBoxChild;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for MusicusRecordingTile {}
|
||||||
|
impl WidgetImpl for MusicusRecordingTile {}
|
||||||
|
impl FlowBoxChildImpl for MusicusRecordingTile {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct MusicusRecordingTile(ObjectSubclass<imp::MusicusRecordingTile>)
|
||||||
|
@extends gtk::Widget, gtk::FlowBoxChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MusicusRecordingTile {
|
||||||
|
pub fn new(recording: &Recording, performances: Vec<Performance>) -> Self {
|
||||||
|
let obj: Self = glib::Object::new();
|
||||||
|
let imp = obj.imp();
|
||||||
|
|
||||||
|
imp.work_label.set_label(&recording.work.title);
|
||||||
|
imp.composer_label
|
||||||
|
.set_label(&recording.work.composer.name_fl());
|
||||||
|
|
||||||
|
imp.performances_label.set_label(
|
||||||
|
&performances
|
||||||
|
.into_iter()
|
||||||
|
.map(|performance| match performance {
|
||||||
|
Performance::Person(person, role) => {
|
||||||
|
let mut result = person.name_fl();
|
||||||
|
if let Some(role) = role {
|
||||||
|
result.push_str(&format!(" ({})", role.name));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
Performance::Ensemble(ensemble, role) => {
|
||||||
|
let mut result = ensemble.name;
|
||||||
|
if let Some(role) = role {
|
||||||
|
result.push_str(&format!(" ({})", role.name));
|
||||||
|
}
|
||||||
|
result
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect::<Vec<String>>()
|
||||||
|
.join(", "),
|
||||||
|
);
|
||||||
|
|
||||||
|
imp.recording.set(recording.clone()).unwrap();
|
||||||
|
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn recording(&self) -> &Recording {
|
||||||
|
self.imp().recording.get().unwrap()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -134,11 +134,12 @@ impl MusicusSearchEntry {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn reset(&self) {
|
pub fn reset(&self) {
|
||||||
|
{
|
||||||
let mut tags = self.imp().tags.borrow_mut();
|
let mut tags = self.imp().tags.borrow_mut();
|
||||||
|
|
||||||
while let Some(tag) = tags.pop() {
|
while let Some(tag) = tags.pop() {
|
||||||
self.imp().tags_box.remove(&tag);
|
self.imp().tags_box.remove(&tag);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
self.imp().text.set_text("");
|
self.imp().text.set_text("");
|
||||||
self.emit_by_name::<()>("query-changed", &[]);
|
self.emit_by_name::<()>("query-changed", &[]);
|
||||||
|
|
|
||||||
67
src/tag_tile.rs
Normal file
67
src/tag_tile.rs
Normal file
|
|
@ -0,0 +1,67 @@
|
||||||
|
use crate::search_tag::Tag;
|
||||||
|
use gtk::{glib, prelude::*, subclass::prelude::*};
|
||||||
|
use std::cell::OnceCell;
|
||||||
|
|
||||||
|
mod imp {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
||||||
|
#[template(file = "data/ui/tag_tile.blp")]
|
||||||
|
pub struct MusicusTagTile {
|
||||||
|
#[template_child]
|
||||||
|
pub title_label: TemplateChild<gtk::Label>,
|
||||||
|
#[template_child]
|
||||||
|
pub subtitle_label: TemplateChild<gtk::Label>,
|
||||||
|
|
||||||
|
pub tag: OnceCell<Tag>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[glib::object_subclass]
|
||||||
|
impl ObjectSubclass for MusicusTagTile {
|
||||||
|
const NAME: &'static str = "MusicusTagTile";
|
||||||
|
type Type = super::MusicusTagTile;
|
||||||
|
type ParentType = gtk::FlowBoxChild;
|
||||||
|
|
||||||
|
fn class_init(klass: &mut Self::Class) {
|
||||||
|
klass.bind_template();
|
||||||
|
}
|
||||||
|
|
||||||
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
||||||
|
obj.init_template();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ObjectImpl for MusicusTagTile {}
|
||||||
|
impl WidgetImpl for MusicusTagTile {}
|
||||||
|
impl FlowBoxChildImpl for MusicusTagTile {}
|
||||||
|
}
|
||||||
|
|
||||||
|
glib::wrapper! {
|
||||||
|
pub struct MusicusTagTile(ObjectSubclass<imp::MusicusTagTile>)
|
||||||
|
@extends gtk::Widget, gtk::FlowBoxChild;
|
||||||
|
}
|
||||||
|
|
||||||
|
impl MusicusTagTile {
|
||||||
|
pub fn new(tag: Tag) -> Self {
|
||||||
|
let obj: Self = glib::Object::new();
|
||||||
|
let imp = obj.imp();
|
||||||
|
|
||||||
|
match &tag {
|
||||||
|
Tag::Composer(person) | Tag::Performer(person) => {
|
||||||
|
imp.title_label.set_label(&person.name_fl());
|
||||||
|
}
|
||||||
|
Tag::Ensemble(ensemble) => {
|
||||||
|
imp.title_label.set_label(&ensemble.name);
|
||||||
|
}
|
||||||
|
Tag::Work(work) => {
|
||||||
|
imp.title_label.set_label(&work.title);
|
||||||
|
imp.subtitle_label.set_label(&work.composer.name_fl());
|
||||||
|
imp.subtitle_label.set_visible(true);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
imp.tag.set(tag).unwrap();
|
||||||
|
|
||||||
|
obj
|
||||||
|
}
|
||||||
|
}
|
||||||
81
src/tile.rs
81
src/tile.rs
|
|
@ -1,81 +0,0 @@
|
||||||
use gtk::{glib, glib::Properties, prelude::*, subclass::prelude::*};
|
|
||||||
use std::cell::RefCell;
|
|
||||||
|
|
||||||
mod imp {
|
|
||||||
use super::*;
|
|
||||||
|
|
||||||
#[derive(Properties, Debug, Default, gtk::CompositeTemplate)]
|
|
||||||
#[properties(wrapper_type = super::MusicusTile)]
|
|
||||||
#[template(file = "data/ui/tile.blp")]
|
|
||||||
pub struct MusicusTile {
|
|
||||||
#[property(get, set)]
|
|
||||||
pub title: RefCell<String>,
|
|
||||||
|
|
||||||
#[property(get, set)]
|
|
||||||
pub subtitle: RefCell<Option<String>>,
|
|
||||||
|
|
||||||
#[template_child]
|
|
||||||
pub title_label: TemplateChild<gtk::Label>,
|
|
||||||
#[template_child]
|
|
||||||
pub subtitle_label: TemplateChild<gtk::Label>,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[glib::object_subclass]
|
|
||||||
impl ObjectSubclass for MusicusTile {
|
|
||||||
const NAME: &'static str = "MusicusTile";
|
|
||||||
type Type = super::MusicusTile;
|
|
||||||
type ParentType = gtk::FlowBoxChild;
|
|
||||||
|
|
||||||
fn class_init(klass: &mut Self::Class) {
|
|
||||||
klass.bind_template();
|
|
||||||
}
|
|
||||||
|
|
||||||
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
|
||||||
obj.init_template();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[glib::derived_properties]
|
|
||||||
impl ObjectImpl for MusicusTile {
|
|
||||||
fn constructed(&self) {
|
|
||||||
self.parent_constructed();
|
|
||||||
|
|
||||||
self.obj()
|
|
||||||
.bind_property("title", &self.title_label.get(), "label")
|
|
||||||
.sync_create()
|
|
||||||
.build();
|
|
||||||
|
|
||||||
self.obj()
|
|
||||||
.bind_property("subtitle", &self.subtitle_label.get(), "visible")
|
|
||||||
.sync_create()
|
|
||||||
.transform_to(|_, s: Option<String>| Some(s.is_some()))
|
|
||||||
.build();
|
|
||||||
|
|
||||||
self.obj()
|
|
||||||
.bind_property("subtitle", &self.subtitle_label.get(), "label")
|
|
||||||
.sync_create()
|
|
||||||
.build();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl WidgetImpl for MusicusTile {}
|
|
||||||
impl FlowBoxChildImpl for MusicusTile {}
|
|
||||||
}
|
|
||||||
|
|
||||||
glib::wrapper! {
|
|
||||||
pub struct MusicusTile(ObjectSubclass<imp::MusicusTile>)
|
|
||||||
@extends gtk::Widget, gtk::FlowBoxChild;
|
|
||||||
}
|
|
||||||
|
|
||||||
impl MusicusTile {
|
|
||||||
pub fn with_title(title: &str) -> Self {
|
|
||||||
glib::Object::builder().property("title", title).build()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn with_subtitle(title: &str, subtitle: &str) -> Self {
|
|
||||||
glib::Object::builder()
|
|
||||||
.property("title", title)
|
|
||||||
.property("subtitle", subtitle)
|
|
||||||
.build()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue