Skip to main content

ferroui_base/input/
data_transfer_extensions.rs

1use super::{DataFormat, DataFormatOf, DataTransferItemExtensions, IDataTransfer, IDataTransferItem};
2use crate::media::imaging::Bitmap;
3use crate::platform::storage::IStorageItem;
4use std::rc::Rc;
5
6/// The items of a data transfer that support a format, in order.
7pub struct DataTransferItems {
8    items: Rc<[Rc<dyn IDataTransferItem>]>,
9    format: DataFormat,
10    index: usize,
11}
12
13impl Iterator for DataTransferItems {
14    type Item = Rc<dyn IDataTransferItem>;
15
16    fn next(&mut self) -> Option<Self::Item> {
17        while let Some(item) = self.items.get(self.index) {
18            self.index += 1;
19            if item.contains(&self.format) {
20                return Some(item.clone());
21            }
22        }
23        None
24    }
25}
26
27// Keep the `try_get_xxx` methods in sync with the `try_get_xxx_async` ones
28// of `AsyncDataTransferExtensions`.
29
30/// Contains extension methods for [`IDataTransfer`].
31pub trait DataTransferExtensions: IDataTransfer {
32    /// Gets whether the data transfer supports a specific format.
33    fn contains(&self, format: &DataFormat) -> bool {
34        self.formats().iter().any(|candidate| candidate == format)
35    }
36
37    /// Gets the list of [`IDataTransferItem`] contained in the data
38    /// transfer, filtered by a given format.
39    ///
40    /// Some platforms (such as Windows and X11) may only support a single
41    /// data item for all formats except files.
42    fn get_items(&self, format: &DataFormat) -> DataTransferItems {
43        DataTransferItems { items: self.items(), format: format.clone(), index: 0 }
44    }
45
46    /// Tries to get a value for a given format from the data transfer.
47    /// Returns `None` if the format is not supported.
48    ///
49    /// If the data transfer contains several items supporting the format,
50    /// the first matching one will be returned.
51    fn try_get_value<T: Clone + 'static>(&self, format: &DataFormatOf<T>) -> Option<T> {
52        self.get_items(format).next().and_then(|item| item.try_get_value(format))
53    }
54
55    /// Tries to get multiple values for a given format from the data
56    /// transfer. Returns `None` if the format is not supported.
57    fn try_get_values<T: Clone + 'static>(&self, format: &DataFormatOf<T>) -> Option<Vec<T>> {
58        let mut results: Option<Vec<T>> = None;
59
60        for item in self.get_items(format) {
61            let Some(result) = item.try_get_value(format) else { continue };
62            results.get_or_insert_with(Vec::new).push(result);
63        }
64
65        results
66    }
67
68    /// Returns a text, if available, from the data transfer.
69    ///
70    /// If the data transfer contains several items supporting
71    /// [`DataFormat::text`], the first matching one will be returned.
72    fn try_get_text(&self) -> Option<String> {
73        self.try_get_value(&DataFormat::text())
74    }
75
76    /// Returns a bitmap, if available, from the data transfer.
77    ///
78    /// If the data transfer contains several items supporting
79    /// [`DataFormat::bitmap`], the first matching one will be returned.
80    fn try_get_bitmap(&self) -> Option<Rc<Bitmap>> {
81        self.try_get_value(&DataFormat::bitmap())
82    }
83
84    /// Returns a file (or folder), if available, from the data transfer.
85    ///
86    /// See [`DataFormat::file`].
87    fn try_get_file(&self) -> Option<Rc<dyn IStorageItem>> {
88        self.try_get_value(&DataFormat::file())
89    }
90
91    /// Returns the files (or folders), if available, from the data
92    /// transfer.
93    ///
94    /// See [`DataFormat::file`].
95    fn try_get_files(&self) -> Option<Vec<Rc<dyn IStorageItem>>> {
96        self.try_get_values(&DataFormat::file())
97    }
98}
99
100impl<I: IDataTransfer + ?Sized> DataTransferExtensions for I {}