fractal/components/power_level_selection/
combo_box.rs1use 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 #[property(get, set = Self::set_permissions, explicit_notify, nullable)]
27 permissions: RefCell<Option<Permissions>>,
28 #[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 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 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 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 #[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 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}