fractal/components/rows/
loading_button_row.rs1use adw::{prelude::*, subclass::prelude::*};
2use gtk::{
3 glib,
4 glib::{clone, closure_local},
5};
6
7use crate::components::LoadingBin;
8
9mod imp {
10 use std::{marker::PhantomData, sync::LazyLock};
11
12 use glib::subclass::{InitializingObject, Signal};
13
14 use super::*;
15
16 #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
17 #[template(resource = "/org/gnome/Fractal/ui/components/rows/loading_button_row.ui")]
18 #[properties(wrapper_type = super::LoadingButtonRow)]
19 pub struct LoadingButtonRow {
20 #[template_child]
21 loading_bin: TemplateChild<LoadingBin>,
22 #[property(get = Self::is_loading, set = Self::set_is_loading)]
24 is_loading: PhantomData<bool>,
25 }
26
27 #[glib::object_subclass]
28 impl ObjectSubclass for LoadingButtonRow {
29 const NAME: &'static str = "LoadingButtonRow";
30 type Type = super::LoadingButtonRow;
31 type ParentType = adw::PreferencesRow;
32
33 fn class_init(klass: &mut Self::Class) {
34 Self::bind_template(klass);
35
36 klass.set_css_name("row");
37 }
38
39 fn instance_init(obj: &InitializingObject<Self>) {
40 obj.init_template();
41 }
42 }
43
44 #[glib::derived_properties]
45 impl ObjectImpl for LoadingButtonRow {
46 fn signals() -> &'static [Signal] {
47 static SIGNALS: LazyLock<Vec<Signal>> =
48 LazyLock::new(|| vec![Signal::builder("activated").build()]);
49 SIGNALS.as_ref()
50 }
51
52 fn constructed(&self) {
53 self.parent_constructed();
54
55 self.obj().connect_parent_notify(|obj| {
56 if let Some(listbox) = obj.parent().and_downcast_ref::<gtk::ListBox>() {
57 listbox.connect_row_activated(clone!(
58 #[weak]
59 obj,
60 move |_, row| {
61 if *row == obj {
62 obj.emit_by_name::<()>("activated", &[]);
63 }
64 }
65 ));
66 }
67 });
68 }
69 }
70
71 impl WidgetImpl for LoadingButtonRow {}
72 impl ListBoxRowImpl for LoadingButtonRow {}
73 impl PreferencesRowImpl for LoadingButtonRow {}
74
75 impl LoadingButtonRow {
76 fn is_loading(&self) -> bool {
78 self.loading_bin.is_loading()
79 }
80
81 fn set_is_loading(&self, loading: bool) {
83 if self.is_loading() == loading {
84 return;
85 }
86
87 self.loading_bin.set_is_loading(loading);
88
89 let obj = self.obj();
90 obj.set_activatable(!loading);
91 obj.notify_is_loading();
92 }
93 }
94}
95
96glib::wrapper! {
97 pub struct LoadingButtonRow(ObjectSubclass<imp::LoadingButtonRow>)
99 @extends gtk::Widget, gtk::ListBoxRow, adw::PreferencesRow,
100 @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Actionable;
101}
102
103impl LoadingButtonRow {
104 pub fn new() -> Self {
105 glib::Object::new()
106 }
107
108 pub fn connect_activated<F: Fn(&Self) + 'static>(&self, f: F) -> glib::SignalHandlerId {
110 self.connect_closure(
111 "activated",
112 true,
113 closure_local!(move |obj: Self| {
114 f(&obj);
115 }),
116 )
117 }
118}