fractal/session/view/content/room_details/members_page/members_list_view/
item_row.rs

1use adw::{prelude::*, subclass::prelude::*};
2use gtk::glib;
3
4use super::MembershipSubpageRow;
5use crate::{
6    prelude::*,
7    session::{
8        model::Member,
9        view::content::room_details::{MemberRow, MembershipSubpageItem},
10    },
11};
12
13mod imp {
14    use std::cell::{Cell, RefCell};
15
16    use super::*;
17
18    #[derive(Debug, Default, glib::Properties)]
19    #[properties(wrapper_type = super::ItemRow)]
20    pub struct ItemRow {
21        /// The item represented by this row.
22        ///
23        /// It can be a `Member` or a `MemberSubpageItem`.
24        #[property(get, set = Self::set_item, explicit_notify, nullable)]
25        item: RefCell<Option<glib::Object>>,
26        /// Whether this row can be activated.
27        #[property(get)]
28        activatable: Cell<bool>,
29    }
30
31    #[glib::object_subclass]
32    impl ObjectSubclass for ItemRow {
33        const NAME: &'static str = "ContentMemberItemRow";
34        type Type = super::ItemRow;
35        type ParentType = adw::Bin;
36    }
37
38    #[glib::derived_properties]
39    impl ObjectImpl for ItemRow {}
40
41    impl WidgetImpl for ItemRow {}
42    impl BinImpl for ItemRow {}
43
44    impl ItemRow {
45        /// Set the item represented by this row.
46        ///
47        /// It must be a `Member` or a `MemberSubpageItem`.
48        fn set_item(&self, item: Option<glib::Object>) {
49            if *self.item.borrow() == item {
50                return;
51            }
52            let obj = self.obj();
53
54            if let Some(item) = &item {
55                if let Some(member) = item.downcast_ref::<Member>() {
56                    let child = obj.child_or_else::<MemberRow>(|| MemberRow::new(true));
57                    child.set_member(Some(member.clone()));
58                    self.set_activatable(true);
59                } else if let Some(item) = item.downcast_ref::<MembershipSubpageItem>() {
60                    let child = obj.child_or_else::<MembershipSubpageRow>(|| {
61                        let child = MembershipSubpageRow::new();
62                        child.set_activatable(false);
63                        child
64                    });
65
66                    child.set_item(Some(item.clone()));
67                    self.set_activatable(true);
68                } else if let Some(child) = item.downcast_ref::<gtk::Widget>() {
69                    obj.set_child(Some(child));
70                    self.set_activatable(false);
71                } else {
72                    unimplemented!("The object {item:?} doesn't have a widget implementation");
73                }
74            }
75
76            self.item.replace(item);
77            obj.notify_item();
78        }
79
80        /// Set whether this row can be activated.
81        fn set_activatable(&self, activatable: bool) {
82            if self.activatable.get() == activatable {
83                return;
84            }
85
86            self.activatable.set(activatable);
87            self.obj().notify_activatable();
88        }
89    }
90}
91
92glib::wrapper! {
93    /// A row presenting an item in the list of room members.
94    pub struct ItemRow(ObjectSubclass<imp::ItemRow>)
95        @extends gtk::Widget, adw::Bin, @implements gtk::Accessible;
96}
97
98impl ItemRow {
99    pub fn new() -> Self {
100        glib::Object::new()
101    }
102}
103
104impl IsABin for ItemRow {}