use std::cell::RefCell; use adw::subclass::prelude::*; use adw::{prelude::*, ActionRow, ComboRow}; use glib::{subclass::InitializingObject, Binding}; use gtk::glib::clone; use gtk::glib::subclass::Signal; use gtk::{glib, Button, CompositeTemplate, Entry, Switch}; use std::sync::OnceLock; #[derive(CompositeTemplate, Default)] #[template(resource = "/de/feschber/LanMouse/client_row.ui")] pub struct ClientRow { #[template_child] pub enable_switch: TemplateChild, #[template_child] pub dns_button: TemplateChild, #[template_child] pub hostname: TemplateChild, #[template_child] pub port: TemplateChild, #[template_child] pub position: TemplateChild, #[template_child] pub delete_row: TemplateChild, #[template_child] pub delete_button: TemplateChild, #[template_child] pub dns_loading_indicator: TemplateChild, pub bindings: RefCell>, } #[glib::object_subclass] impl ObjectSubclass for ClientRow { // `NAME` needs to match `class` attribute of template const NAME: &'static str = "ClientRow"; const ABSTRACT: bool = false; type Type = super::ClientRow; type ParentType = adw::ExpanderRow; fn class_init(klass: &mut Self::Class) { klass.bind_template(); klass.bind_template_callbacks(); } fn instance_init(obj: &InitializingObject) { obj.init_template(); } } impl ObjectImpl for ClientRow { fn constructed(&self) { self.parent_constructed(); self.delete_button.connect_clicked(clone!( #[weak(rename_to = row)] self, move |button| { row.handle_client_delete(button); } )); self.hostname.connect_changed(clone!( #[weak(rename_to = row)] self, move |entry| { row.handle_hostname_changed(entry); } )); } fn signals() -> &'static [glib::subclass::Signal] { static SIGNALS: OnceLock> = OnceLock::new(); SIGNALS.get_or_init(|| { vec![ Signal::builder("request-activate") .param_types([bool::static_type()]) .build(), Signal::builder("request-delete").build(), Signal::builder("request-dns").build(), Signal::builder("request-hostname-change") .param_types([String::static_type()]) .build(), Signal::builder("request-port-change") .param_types([u32::static_type()]) .build(), Signal::builder("request-position-change") .param_types([u32::static_type()]) .build(), ] }) } } #[gtk::template_callbacks] impl ClientRow { #[template_callback] fn handle_activate_switch(&self, state: bool, _switch: &Switch) -> bool { self.obj().emit_by_name::<()>("request-activate", &[&state]); true // dont run default handler } #[template_callback] fn handle_request_dns(&self, _: &Button) { self.obj().emit_by_name::<()>("request-dns", &[]); } #[template_callback] fn handle_client_delete(&self, _button: &Button) { self.obj().emit_by_name::<()>("request-delete", &[]); } #[template_callback] fn handle_port_changed(&self) { if let Ok(port) = self.port.text().parse::() { self.obj() .emit_by_name::<()>("request-port-change", &[&(port as u32)]); } } // #[template_callback] fn handle_hostname_changed(&self, entry: &Entry) { self.obj() .emit_by_name::<()>("request-hostname-change", &[&entry.text()]); } #[template_callback] fn handle_position_changed(&self) { self.obj() .emit_by_name("request-position-change", &[&self.position.selected()]) } } impl WidgetImpl for ClientRow {} impl BoxImpl for ClientRow {} impl ListBoxRowImpl for ClientRow {} impl PreferencesRowImpl for ClientRow {} impl ExpanderRowImpl for ClientRow {}