ferroui_base/input/
data_transfer_item.rs1use super::platform::ClipboardError;
2use super::{DataFormat, DataFormatOf, IAsyncDataTransferItem, IDataTransferItem, LocalBoxFuture};
3use crate::media::imaging::Bitmap;
4use crate::platform::storage::IStorageItem;
5use std::any::Any;
6use std::cell::RefCell;
7use std::rc::Rc;
8
9#[derive(Clone)]
10enum DataAccessor {
11 Value(Rc<dyn Any>),
12 Lazy(Rc<dyn Fn() -> Option<Rc<dyn Any>>>),
13}
14
15impl DataAccessor {
16 fn get_value(&self) -> Option<Rc<dyn Any>> {
17 match self {
18 DataAccessor::Value(value) => Some(value.clone()),
19 DataAccessor::Lazy(get_value) => get_value(),
20 }
21 }
22}
23
24pub struct DataTransferItem {
32 accessors: RefCell<Vec<(DataFormat, DataAccessor)>>,
35 formats: RefCell<Option<Rc<[DataFormat]>>>,
36}
37
38impl DataTransferItem {
39 pub fn new() -> Rc<DataTransferItem> {
41 Rc::new(DataTransferItem { accessors: RefCell::new(Vec::new()), formats: RefCell::new(None) })
42 }
43
44 pub fn formats(&self) -> Rc<[DataFormat]> {
46 if let Some(formats) = self.formats.borrow().as_ref() {
47 return formats.clone();
48 }
49
50 let formats: Rc<[DataFormat]> = self.accessors.borrow().iter().map(|(format, _)| format.clone()).collect();
51 *self.formats.borrow_mut() = Some(formats.clone());
52 formats
53 }
54
55 pub fn contains(&self, format: &DataFormat) -> bool {
57 self.accessors.borrow().iter().any(|(key, _)| key == format)
58 }
59
60 pub fn try_get_raw(&self, format: &DataFormat) -> Option<Rc<dyn Any>> {
63 let accessor = self.find_accessor(format)?;
65 accessor.get_value()
66 }
67
68 pub fn try_get_value<T: Clone + 'static>(&self, format: &DataFormatOf<T>) -> Option<T> {
70 self.try_get_raw(format).and_then(|value| value.downcast_ref::<T>().cloned())
71 }
72
73 fn find_accessor(&self, format: &DataFormat) -> Option<DataAccessor> {
74 self.accessors.borrow().iter().find(|(key, _)| key == format).map(|(_, accessor)| accessor.clone())
75 }
76
77 pub fn set<T: 'static>(&self, format: &DataFormatOf<T>, value: Option<T>) {
81 match value {
82 None => self.remove_core(format),
83 Some(value) => self.set_core(format, DataAccessor::Value(Rc::new(value))),
84 }
85 }
86
87 pub fn set_with<T: 'static>(&self, format: &DataFormatOf<T>, get_value: impl Fn() -> Option<T> + 'static) {
89 self.set_core(
90 format,
91 DataAccessor::Lazy(Rc::new(move || get_value().map(|value| Rc::new(value) as Rc<dyn Any>))),
92 );
93 }
94
95 fn set_core(&self, format: &DataFormat, accessor: DataAccessor) {
96 let old = {
97 let mut accessors = self.accessors.borrow_mut();
98 match accessors.iter_mut().find(|(key, _)| key == format) {
99 Some(entry) => Some(std::mem::replace(&mut entry.1, accessor)),
100 None => {
101 accessors.push((format.clone(), accessor));
102 None
103 }
104 }
105 };
106 drop(old);
108
109 *self.formats.borrow_mut() = None;
110 }
111
112 fn remove_core(&self, format: &DataFormat) {
113 let removed = {
114 let mut accessors = self.accessors.borrow_mut();
115 accessors.iter().position(|(key, _)| key == format).map(|index| accessors.remove(index))
116 };
117
118 if removed.is_some() {
119 *self.formats.borrow_mut() = None;
120 }
121 }
122
123 pub fn set_text(&self, value: Option<&str>) {
127 self.set(&DataFormat::text(), value.map(str::to_string))
128 }
129
130 pub fn set_file(&self, value: Option<Rc<dyn IStorageItem>>) {
134 self.set(&DataFormat::file(), value)
135 }
136
137 pub fn set_bitmap(&self, value: Option<Rc<Bitmap>>) {
141 self.set(&DataFormat::bitmap(), value)
142 }
143
144 pub fn create<T: 'static>(format: &DataFormatOf<T>, value: Option<T>) -> Rc<DataTransferItem> {
148 let item = DataTransferItem::new();
149 item.set(format, value);
150 item
151 }
152
153 pub fn create_with<T: 'static>(
156 format: &DataFormatOf<T>,
157 get_value: impl Fn() -> Option<T> + 'static,
158 ) -> Rc<DataTransferItem> {
159 let item = DataTransferItem::new();
160 item.set_with(format, get_value);
161 item
162 }
163
164 pub fn create_text(value: Option<&str>) -> Rc<DataTransferItem> {
168 Self::create(&DataFormat::text(), value.map(str::to_string))
169 }
170
171 pub fn create_file(value: Option<Rc<dyn IStorageItem>>) -> Rc<DataTransferItem> {
175 Self::create(&DataFormat::file(), value)
176 }
177}
178
179impl IDataTransferItem for DataTransferItem {
180 fn formats(&self) -> Rc<[DataFormat]> {
181 DataTransferItem::formats(self)
182 }
183
184 fn try_get_raw(&self, format: &DataFormat) -> Option<Rc<dyn Any>> {
185 DataTransferItem::try_get_raw(self, format)
186 }
187}
188
189impl IAsyncDataTransferItem for DataTransferItem {
190 fn formats(&self) -> Rc<[DataFormat]> {
191 DataTransferItem::formats(self)
192 }
193
194 fn try_get_raw_async(&self, format: &DataFormat) -> LocalBoxFuture<Result<Option<Rc<dyn Any>>, ClipboardError>> {
195 Box::pin(std::future::ready(Ok(DataTransferItem::try_get_raw(self, format))))
196 }
197}