mirror of
https://github.com/johrpan/musicus.git
synced 2025-10-26 11:47:25 +01:00
181 lines
6 KiB
Rust
181 lines
6 KiB
Rust
use std::{cell::OnceCell, str::FromStr};
|
|
|
|
use adw::{prelude::*, subclass::prelude::*};
|
|
use gtk::{
|
|
gio,
|
|
glib::{self, subclass::Signal},
|
|
};
|
|
use once_cell::sync::Lazy;
|
|
|
|
use crate::{
|
|
program::{Program, ProgramDesign},
|
|
slider_row::SliderRow,
|
|
};
|
|
|
|
mod imp {
|
|
use super::*;
|
|
|
|
#[derive(Debug, Default, gtk::CompositeTemplate)]
|
|
#[template(file = "data/ui/editor/program.blp")]
|
|
pub struct ProgramEditor {
|
|
pub navigation: OnceCell<adw::NavigationView>,
|
|
pub action_group: OnceCell<gio::SimpleActionGroup>,
|
|
|
|
#[template_child]
|
|
pub title_row: TemplateChild<adw::EntryRow>,
|
|
#[template_child]
|
|
pub description_row: TemplateChild<adw::EntryRow>,
|
|
#[template_child]
|
|
pub prefer_least_recently_played_adjustment: TemplateChild<gtk::Adjustment>,
|
|
#[template_child]
|
|
pub prefer_recently_added_adjustment: TemplateChild<gtk::Adjustment>,
|
|
#[template_child]
|
|
pub avoid_repeated_composers_adjustment: TemplateChild<gtk::Adjustment>,
|
|
#[template_child]
|
|
pub avoid_repeated_instruments_adjustment: TemplateChild<gtk::Adjustment>,
|
|
#[template_child]
|
|
pub play_full_recordings_row: TemplateChild<adw::SwitchRow>,
|
|
}
|
|
|
|
#[glib::object_subclass]
|
|
impl ObjectSubclass for ProgramEditor {
|
|
const NAME: &'static str = "MusicusProgramEditor";
|
|
type Type = super::ProgramEditor;
|
|
type ParentType = adw::NavigationPage;
|
|
|
|
fn class_init(klass: &mut Self::Class) {
|
|
SliderRow::static_type();
|
|
klass.bind_template();
|
|
klass.bind_template_instance_callbacks();
|
|
}
|
|
|
|
fn instance_init(obj: &glib::subclass::InitializingObject<Self>) {
|
|
obj.init_template();
|
|
}
|
|
}
|
|
|
|
impl ObjectImpl for ProgramEditor {
|
|
fn signals() -> &'static [Signal] {
|
|
static SIGNALS: Lazy<Vec<Signal>> = Lazy::new(|| {
|
|
vec![Signal::builder("save")
|
|
.param_types([Program::static_type()])
|
|
.build()]
|
|
});
|
|
|
|
SIGNALS.as_ref()
|
|
}
|
|
|
|
fn constructed(&self) {
|
|
self.parent_constructed();
|
|
|
|
let set_design_action = gio::ActionEntry::builder("set-design")
|
|
.parameter_type(Some(glib::VariantTy::STRING))
|
|
.state(glib::Variant::from("program-1"))
|
|
.build();
|
|
|
|
let actions = gio::SimpleActionGroup::new();
|
|
actions.add_action_entries([set_design_action]);
|
|
self.obj().insert_action_group("program", Some(&actions));
|
|
self.action_group.set(actions).unwrap();
|
|
}
|
|
}
|
|
|
|
impl WidgetImpl for ProgramEditor {}
|
|
impl NavigationPageImpl for ProgramEditor {}
|
|
}
|
|
|
|
glib::wrapper! {
|
|
pub struct ProgramEditor(ObjectSubclass<imp::ProgramEditor>)
|
|
@extends gtk::Widget, adw::NavigationPage;
|
|
}
|
|
|
|
#[gtk::template_callbacks]
|
|
impl ProgramEditor {
|
|
pub fn new(navigation: &adw::NavigationView, program: Option<&Program>) -> Self {
|
|
let obj: Self = glib::Object::new();
|
|
|
|
if let Some(program) = program {
|
|
if let Some(title) = program.title() {
|
|
obj.imp().title_row.set_text(&title);
|
|
}
|
|
|
|
if let Some(description) = program.description() {
|
|
obj.imp().description_row.set_text(&description);
|
|
}
|
|
|
|
if let Err(err) = obj.activate_action(
|
|
"program.set-design",
|
|
Some(&glib::Variant::from(&program.design().to_string())),
|
|
) {
|
|
log::warn!("Failed to initialize program design buttons: {err:?}");
|
|
}
|
|
|
|
obj.imp()
|
|
.prefer_least_recently_played_adjustment
|
|
.set_value(program.prefer_least_recently_played() * 100.0);
|
|
|
|
obj.imp()
|
|
.prefer_recently_added_adjustment
|
|
.set_value(program.prefer_recently_added() * 100.0);
|
|
|
|
obj.imp()
|
|
.avoid_repeated_composers_adjustment
|
|
.set_value(program.avoid_repeated_composers() as f64);
|
|
|
|
obj.imp()
|
|
.avoid_repeated_instruments_adjustment
|
|
.set_value(program.avoid_repeated_instruments() as f64);
|
|
|
|
obj.imp()
|
|
.play_full_recordings_row
|
|
.set_active(program.play_full_recordings());
|
|
}
|
|
|
|
obj.imp().navigation.set(navigation.to_owned()).unwrap();
|
|
obj
|
|
}
|
|
|
|
pub fn connect_save<F: Fn(&Self, Program) + 'static>(&self, f: F) -> glib::SignalHandlerId {
|
|
self.connect_local("save", true, move |values| {
|
|
let obj = values[0].get::<Self>().unwrap();
|
|
let program = values[1].get::<Program>().unwrap();
|
|
f(&obj, program);
|
|
None
|
|
})
|
|
}
|
|
|
|
#[template_callback]
|
|
fn save(&self) {
|
|
let program = Program::new(
|
|
&self.imp().title_row.text(),
|
|
&self.imp().description_row.text(),
|
|
ProgramDesign::from_str(
|
|
&self
|
|
.imp()
|
|
.action_group
|
|
.get()
|
|
.unwrap()
|
|
.action_state("set-design")
|
|
.map(|v| v.get::<String>().unwrap_or_default())
|
|
.unwrap_or_default(),
|
|
)
|
|
.unwrap_or_default(),
|
|
);
|
|
|
|
program.set_prefer_least_recently_played(
|
|
self.imp().prefer_least_recently_played_adjustment.value() / 100.0,
|
|
);
|
|
program
|
|
.set_prefer_recently_added(self.imp().prefer_recently_added_adjustment.value() / 100.0);
|
|
program.set_avoid_repeated_composers(
|
|
self.imp().avoid_repeated_composers_adjustment.value() as i32,
|
|
);
|
|
program.set_avoid_repeated_instruments(
|
|
self.imp().avoid_repeated_instruments_adjustment.value() as i32,
|
|
);
|
|
program.set_play_full_recordings(self.imp().play_full_recordings_row.is_active());
|
|
|
|
self.emit_by_name::<()>("save", &[&program]);
|
|
self.imp().navigation.get().unwrap().pop();
|
|
}
|
|
}
|