fractal/utils/
single_item_list_model.rs1use gtk::{gio, glib, prelude::*, subclass::prelude::*};
2
3mod imp {
4 use std::cell::{Cell, RefCell};
5
6 use super::*;
7
8 #[derive(Debug, Default, glib::Properties)]
9 #[properties(wrapper_type = super::SingleItemListModel)]
10 pub struct SingleItemListModel {
11 #[property(get, set = Self::set_item, explicit_notify, nullable)]
13 item: RefCell<Option<glib::Object>>,
14 #[property(get, set = Self::set_is_hidden, explicit_notify)]
16 is_hidden: Cell<bool>,
17 }
18
19 #[glib::object_subclass]
20 impl ObjectSubclass for SingleItemListModel {
21 const NAME: &'static str = "SingleItemListModel";
22 type Type = super::SingleItemListModel;
23 type Interfaces = (gio::ListModel,);
24 }
25
26 #[glib::derived_properties]
27 impl ObjectImpl for SingleItemListModel {}
28
29 impl ListModelImpl for SingleItemListModel {
30 fn item_type(&self) -> glib::Type {
31 self.item
32 .borrow()
33 .as_ref()
34 .map_or_else(glib::Object::static_type, glib::Object::type_)
35 }
36
37 fn n_items(&self) -> u32 {
38 (!self.is_empty()).into()
39 }
40
41 fn item(&self, position: u32) -> Option<glib::Object> {
42 if self.is_hidden.get() || position != 0 {
43 return None;
44 }
45
46 self.item.borrow().clone().and_upcast()
47 }
48 }
49
50 impl SingleItemListModel {
51 fn set_item(&self, item: Option<glib::Object>) {
53 if *self.item.borrow() == item {
54 return;
55 }
56
57 let was_empty = self.is_empty();
58
59 self.item.replace(item);
60 self.obj().notify_item();
61
62 self.notify_items_changed(was_empty);
63 }
64
65 fn set_is_hidden(&self, hidden: bool) {
67 if self.is_hidden.get() == hidden {
68 return;
69 }
70
71 let was_empty = self.is_empty();
72
73 self.is_hidden.set(hidden);
74 self.obj().notify_is_hidden();
75
76 if was_empty != self.is_empty() {
77 self.notify_items_changed(was_empty);
78 }
79 }
80
81 fn is_empty(&self) -> bool {
83 self.is_hidden.get() || self.item.borrow().is_none()
84 }
85
86 fn notify_items_changed(&self, was_empty: bool) {
88 let is_empty = self.is_empty();
89
90 let removed = (!was_empty).into();
91 let added = (!is_empty).into();
92 self.obj().items_changed(0, removed, added);
93 }
94 }
95}
96
97glib::wrapper! {
98 pub struct SingleItemListModel(ObjectSubclass<imp::SingleItemListModel>)
100 @implements gio::ListModel;
101}
102
103impl SingleItemListModel {
104 pub fn new(item: Option<&impl IsA<glib::Object>>) -> Self {
106 glib::Object::builder().property("item", item).build()
107 }
108}
109
110impl Default for SingleItemListModel {
111 fn default() -> Self {
112 Self::new(None::<&glib::Object>)
113 }
114}