Skip to main content

fractal/components/power_level_selection/
combo_box.rs

1use adw::{prelude::*, subclass::prelude::*};
2use gtk::{gdk, glib};
3use ruma::{Int, events::room::power_levels::UserPowerLevel};
4
5use super::PowerLevelSelectionPopover;
6use crate::{components::RoleBadge, session::Permissions};
7
8mod imp {
9    use std::cell::{Cell, RefCell};
10
11    use glib::subclass::InitializingObject;
12
13    use super::*;
14
15    #[derive(Debug, Default, gtk::CompositeTemplate, glib::Properties)]
16    #[template(resource = "/org/gnome/Fractal/ui/components/power_level_selection/combo_box.ui")]
17    #[properties(wrapper_type = super::PowerLevelSelectionComboBox)]
18    pub struct PowerLevelSelectionComboBox {
19        #[template_child]
20        selected_level_label: TemplateChild<gtk::Label>,
21        #[template_child]
22        selected_role_badge: TemplateChild<RoleBadge>,
23        #[template_child]
24        popover: TemplateChild<PowerLevelSelectionPopover>,
25        /// The permissions to watch.
26        #[property(get, set = Self::set_permissions, explicit_notify, nullable)]
27        permissions: RefCell<Option<Permissions>>,
28        /// The selected power level.
29        #[property(get, set = Self::set_selected_power_level, explicit_notify)]
30        selected_power_level: Cell<i64>,
31    }
32
33    #[glib::object_subclass]
34    impl ObjectSubclass for PowerLevelSelectionComboBox {
35        const NAME: &'static str = "PowerLevelSelectionComboBox";
36        type Type = super::PowerLevelSelectionComboBox;
37        type ParentType = gtk::ToggleButton;
38
39        fn class_init(klass: &mut Self::Class) {
40            Self::bind_template(klass);
41            Self::bind_template_callbacks(klass);
42        }
43
44        fn instance_init(obj: &InitializingObject<Self>) {
45            obj.init_template();
46        }
47    }
48
49    #[glib::derived_properties]
50    impl ObjectImpl for PowerLevelSelectionComboBox {}
51
52    impl WidgetImpl for PowerLevelSelectionComboBox {}
53    impl ButtonImpl for PowerLevelSelectionComboBox {}
54    impl ToggleButtonImpl for PowerLevelSelectionComboBox {}
55
56    #[gtk::template_callbacks]
57    impl PowerLevelSelectionComboBox {
58        /// Set the permissions to watch.
59        fn set_permissions(&self, permissions: Option<Permissions>) {
60            if *self.permissions.borrow() == permissions {
61                return;
62            }
63
64            self.permissions.replace(permissions);
65            self.update_selected_label();
66            self.obj().notify_permissions();
67        }
68
69        /// Update the label of the selected power level.
70        fn update_selected_label(&self) {
71            let Some(permissions) = self.permissions.borrow().clone() else {
72                return;
73            };
74
75            let power_level = self.selected_power_level.get();
76            let role = permissions.role(UserPowerLevel::Int(Int::new_saturating(power_level)));
77
78            self.selected_role_badge.set_role(role);
79            self.selected_level_label
80                .set_label(&power_level.to_string());
81
82            let role_string = format!("{power_level} {role}");
83            self.obj()
84                .update_property(&[gtk::accessible::Property::Description(&role_string)]);
85        }
86
87        /// Set the selected power level.
88        fn set_selected_power_level(&self, power_level: i64) {
89            if self.selected_power_level.get() == power_level {
90                return;
91            }
92
93            self.selected_power_level.set(power_level);
94
95            self.update_selected_label();
96            self.obj().notify_selected_power_level();
97        }
98
99        /// The toggle button's changed.
100        #[template_callback]
101        fn active_changed(&self) {
102            let obj = self.obj();
103
104            if obj.is_active() {
105                self.popover
106                    .set_pointing_to(Some(&gdk::Rectangle::new(0, 0, 0, obj.height())));
107                self.popover.popup();
108            } else {
109                self.popover.popdown();
110            }
111        }
112    }
113}
114
115glib::wrapper! {
116    /// A combo box to select a room member's power level.
117    pub struct PowerLevelSelectionComboBox(ObjectSubclass<imp::PowerLevelSelectionComboBox>)
118        @extends gtk::Widget, gtk::Button, gtk::ToggleButton,
119        @implements gtk::Accessible, gtk::Buildable, gtk::ConstraintTarget, gtk::Actionable;
120}
121
122impl PowerLevelSelectionComboBox {
123    pub fn new() -> Self {
124        glib::Object::new()
125    }
126}