musicus/src/util/activatable_row.rs

110 lines
3.4 KiB
Rust
Raw Normal View History

2025-03-01 09:57:01 +01:00
use std::cell::RefCell;
2024-05-27 12:39:29 +02:00
use gtk::{
glib::{self, clone, subclass::Signal},
prelude::*,
subclass::prelude::*,
};
use once_cell::sync::Lazy;
mod imp {
use super::*;
#[derive(Default)]
2025-03-01 09:57:01 +01:00
pub struct ActivatableRow {
2024-05-27 12:39:29 +02:00
pub previous_parent: RefCell<Option<gtk::ListBox>>,
pub previous_signal_handler_id: RefCell<Option<glib::SignalHandlerId>>,
}
#[glib::object_subclass]
2025-03-01 09:57:01 +01:00
impl ObjectSubclass for ActivatableRow {
2024-05-27 12:39:29 +02:00
const NAME: &'static str = "MusicusActivatableRow";
2025-03-01 09:57:01 +01:00
type Type = super::ActivatableRow;
2024-05-27 12:39:29 +02:00
type ParentType = gtk::ListBoxRow;
}
2025-03-01 09:57:01 +01:00
impl ObjectImpl for ActivatableRow {
2024-05-27 12:39:29 +02:00
fn constructed(&self) {
self.parent_constructed();
let obj = self.obj();
obj.connect_parent_notify(clone!(
#[weak]
obj,
2025-03-01 09:57:01 +01:00
move |_: &super::ActivatableRow| {
let previous_parent = obj.imp().previous_parent.borrow_mut().take();
let previous_signal_handler_id =
obj.imp().previous_signal_handler_id.borrow_mut().take();
if let (Some(previous_parent), Some(previous_signal_handler_id)) =
(previous_parent, previous_signal_handler_id)
{
previous_parent.disconnect(previous_signal_handler_id);
}
2024-05-27 12:39:29 +02:00
if let Some(parent) = obj.parent().and_downcast::<gtk::ListBox>() {
let signal_handler_id = parent.connect_row_activated(clone!(
#[weak]
obj,
move |_: &gtk::ListBox, row: &gtk::ListBoxRow| {
if *row == obj {
obj.activate();
}
}
));
2024-05-27 12:39:29 +02:00
obj.imp().previous_parent.replace(Some(parent));
obj.imp()
.previous_signal_handler_id
.replace(Some(signal_handler_id));
}
2024-05-27 12:39:29 +02:00
}
));
2024-05-27 12:39:29 +02:00
}
fn signals() -> &'static [Signal] {
static SIGNALS: Lazy<Vec<Signal>> =
Lazy::new(|| vec![Signal::builder("activated").build()]);
SIGNALS.as_ref()
}
}
2025-03-01 09:57:01 +01:00
impl WidgetImpl for ActivatableRow {}
2024-05-27 12:39:29 +02:00
2025-03-01 09:57:01 +01:00
impl ListBoxRowImpl for ActivatableRow {
2024-05-27 12:39:29 +02:00
fn activate(&self) {
self.obj().emit_by_name::<()>("activated", &[]);
}
}
}
glib::wrapper! {
/// A simple helper widget for connecting a signal handler to a single [`gtk::ListBoxRow`] for
/// handling activation.
2025-03-01 09:57:01 +01:00
pub struct ActivatableRow(ObjectSubclass<imp::ActivatableRow>)
2024-05-27 12:39:29 +02:00
@extends gtk::Widget, gtk::ListBoxRow;
}
2025-03-01 09:57:01 +01:00
impl ActivatableRow {
2024-05-27 12:39:29 +02:00
pub fn new<W>(child: &W) -> Self
where
W: IsA<gtk::Widget>,
{
let obj: Self = glib::Object::builder()
.property("activatable", true)
.property("selectable", false)
.build();
obj.set_child(Some(child));
obj
}
pub fn connect_activated<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
self.connect_local("activated", true, move |values| {
let obj = values[0].get::<Self>().unwrap();
f(&obj);
None
})
}
}