Skip to main content

ravenrs_widgets/
clipboard.rs

1//! The system clipboard, as a service the platform layer provides.
2
3use std::cell::RefCell;
4use std::fmt;
5use std::rc::Rc;
6
7/// Reads and writes the system clipboard. Platform layers install one with
8/// [`crate::Ui::set_clipboard`]; until then, an in-memory clipboard is used.
9pub trait ClipboardProvider {
10    /// The clipboard's text, or `None` when it is empty, not text, or cannot
11    /// be read synchronously (in the browser, pasting arrives as typed text).
12    fn read_text(&self) -> Option<String>;
13    /// Replaces the clipboard's content with `text`.
14    fn write_text(&self, text: &str);
15}
16
17/// A clipboard that lives only inside the app (tests, headless use).
18#[derive(Debug, Default)]
19#[cfg_attr(feature = "live", ravenrs_live::expose(part = "fields"))]
20pub struct MemoryClipboard(RefCell<Option<String>>);
21
22impl ClipboardProvider for MemoryClipboard {
23    fn read_text(&self) -> Option<String> {
24        self.0.borrow().clone()
25    }
26
27    fn write_text(&self, text: &str) {
28        *self.0.borrow_mut() = Some(text.to_owned());
29    }
30}
31
32/// A shared handle to the clipboard, from [`crate::BuildCx::clipboard`] or
33/// [`crate::Ui::clipboard`].
34///
35/// ```
36/// use ravenrs_widgets::{Clipboard, MemoryClipboard};
37///
38/// let clipboard = Clipboard::new(MemoryClipboard::default());
39/// clipboard.write("hello");
40/// assert_eq!(clipboard.read().as_deref(), Some("hello"));
41/// ```
42#[derive(Clone)]
43#[cfg_attr(feature = "live", ravenrs_live::expose(part = "fields"))]
44pub struct Clipboard(Rc<dyn ClipboardProvider>);
45
46#[cfg_attr(feature = "live", ravenrs_live::expose)]
47impl Clipboard {
48    /// Wraps a provider.
49    pub fn new(provider: impl ClipboardProvider + 'static) -> Self {
50        Self(Rc::new(provider))
51    }
52
53    /// The clipboard's text, if it can be read now.
54    pub fn read(&self) -> Option<String> {
55        self.0.read_text()
56    }
57
58    /// Replaces the clipboard's content with `text`.
59    pub fn write(&self, text: &str) {
60        self.0.write_text(text);
61    }
62}
63
64impl Default for Clipboard {
65    fn default() -> Self {
66        Self::new(MemoryClipboard::default())
67    }
68}
69
70impl fmt::Debug for Clipboard {
71    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
72        f.write_str("Clipboard")
73    }
74}