musicus/src/import/track_selector.rs

125 lines
3.9 KiB
Rust
Raw Normal View History

use super::source::Source;
2021-01-13 19:27:22 +01:00
use crate::widgets::{Navigator, NavigatorScreen};
use glib::clone;
use gtk::prelude::*;
use gtk_macros::get_widget;
2021-01-29 15:17:27 +01:00
use libadwaita::prelude::*;
2021-01-13 19:27:22 +01:00
use std::cell::RefCell;
use std::rc::Rc;
/// A screen for selecting tracks from a source.
2021-01-13 19:27:22 +01:00
pub struct TrackSelector {
source: Rc<Box<dyn Source>>,
2021-01-13 19:27:22 +01:00
widget: gtk::Box,
select_button: gtk::Button,
selection: RefCell<Vec<usize>>,
selected_cb: RefCell<Option<Box<dyn Fn(Vec<usize>)>>>,
navigator: RefCell<Option<Rc<Navigator>>>,
}
impl TrackSelector {
/// Create a new track selector.
pub fn new(source: Rc<Box<dyn Source>>) -> Rc<Self> {
2021-01-13 19:27:22 +01:00
// Create UI
let builder = gtk::Builder::from_resource("/de/johrpan/musicus/ui/track_selector.ui");
get_widget!(builder, gtk::Box, widget);
get_widget!(builder, gtk::Button, back_button);
get_widget!(builder, gtk::Button, select_button);
get_widget!(builder, gtk::Frame, tracks_frame);
let track_list = gtk::ListBox::new();
track_list.set_selection_mode(gtk::SelectionMode::None);
track_list.set_vexpand(false);
track_list.show();
2021-01-25 14:00:57 +01:00
tracks_frame.set_child(Some(&track_list));
2021-01-13 19:27:22 +01:00
let this = Rc::new(Self {
source,
widget,
select_button,
selection: RefCell::new(Vec::new()),
selected_cb: RefCell::new(None),
navigator: RefCell::new(None),
});
// Connect signals and callbacks
back_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator {
navigator.pop();
}
}));
this.select_button.connect_clicked(clone!(@strong this => move |_| {
let navigator = this.navigator.borrow().clone();
if let Some(navigator) = navigator {
navigator.pop();
}
if let Some(cb) = &*this.selected_cb.borrow() {
let selection = this.selection.borrow().clone();
cb(selection);
}
}));
let tracks = this.source.tracks().unwrap();
for (index, track) in tracks.iter().enumerate() {
2021-01-13 19:27:22 +01:00
let check = gtk::CheckButton::new();
check.connect_toggled(clone!(@strong this => move |check| {
let mut selection = this.selection.borrow_mut();
if check.get_active() {
selection.push(index);
} else {
if let Some(pos) = selection.iter().position(|part| *part == index) {
selection.remove(pos);
}
}
if selection.is_empty() {
this.select_button.set_sensitive(false);
} else {
this.select_button.set_sensitive(true);
}
}));
let title = format!("Track {}", track.number);
2021-01-29 15:17:27 +01:00
let row = libadwaita::ActionRow::new();
2021-01-13 19:27:22 +01:00
row.add_prefix(&check);
row.set_activatable_widget(Some(&check));
2021-01-25 14:00:57 +01:00
row.set_activatable(true);
2021-01-13 19:27:22 +01:00
row.set_title(Some(&title));
2021-01-25 14:00:57 +01:00
track_list.append(&row);
2021-01-13 19:27:22 +01:00
}
this
}
/// Set the closure to be called when the user has selected tracks. The
/// closure will be called with the indices of the selected tracks as its
/// argument.
pub fn set_selected_cb<F: Fn(Vec<usize>) + 'static>(&self, cb: F) {
self.selected_cb.replace(Some(Box::new(cb)));
}
}
impl NavigatorScreen for TrackSelector {
fn attach_navigator(&self, navigator: Rc<Navigator>) {
self.navigator.replace(Some(navigator));
}
fn get_widget(&self) -> gtk::Widget {
self.widget.clone().upcast()
}
fn detach_navigator(&self) {
self.navigator.replace(None);
}
}