mirror of
https://github.com/storytold/figcraft.git
synced 2026-10-26 03:16:53 -06:00
UI: Route text clipboard writes through egui (#1239)
Co-Authored-By: GPT-6 Luna <noreply@openai.com>
This commit is contained in:
committed by
SusieeTheFemboy
co-authored by
GPT-6 Luna
parent
8167f13a6a
commit
c6dd115e78
@@ -244,14 +244,15 @@ fn main() -> eframe::Result {
|
||||
let result = eframe::run_native(
|
||||
"FigCraft",
|
||||
options,
|
||||
Box::new(move |_cc| {
|
||||
Box::new(move |cc| {
|
||||
with_app(|fig| fig.services.set_egui_context(&cc.egui_ctx));
|
||||
Ok(Box::new(App {
|
||||
queue,
|
||||
ctx_slot,
|
||||
title: String::new(),
|
||||
recovery,
|
||||
#[cfg(target_os = "macos")]
|
||||
apple_events: apple_events.connect(&_cc.egui_ctx),
|
||||
apple_events: apple_events.connect(&cc.egui_ctx),
|
||||
}))
|
||||
}),
|
||||
);
|
||||
|
||||
@@ -11,6 +11,7 @@ use serde_json::{Value, json};
|
||||
|
||||
pub struct Desktop {
|
||||
clipboard: Option<arboard::Clipboard>,
|
||||
egui_ctx: Option<egui::Context>,
|
||||
/// Where the preferences live ([`config_dir`]).
|
||||
dir: Option<PathBuf>,
|
||||
pub prefs: Option<Prefs>,
|
||||
@@ -54,7 +55,7 @@ impl Desktop {
|
||||
let reduce_motion = Arc::new(AtomicBool::new(false));
|
||||
let flag = reduce_motion.clone();
|
||||
std::thread::spawn(move || flag.store(system_reduce_motion(), Ordering::Relaxed));
|
||||
Self { clipboard: arboard::Clipboard::new().ok(), dir, prefs, reduce_motion, language: system_language(), recovery }
|
||||
Self { clipboard: arboard::Clipboard::new().ok(), egui_ctx: None, dir, prefs, reduce_motion, language: system_language(), recovery }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -277,10 +278,13 @@ impl Services for Desktop {
|
||||
picked(dialog(title).pick_folder())
|
||||
}
|
||||
fn clipboard_set_text(&mut self, s: &str) {
|
||||
if let Some(c) = self.clipboard.as_mut() {
|
||||
let _ = c.set_text(s.to_string());
|
||||
if let Some(ctx) = &self.egui_ctx {
|
||||
ctx.copy_text(s.to_string());
|
||||
}
|
||||
}
|
||||
fn set_egui_context(&mut self, ctx: &egui::Context) {
|
||||
self.egui_ctx = Some(ctx.clone());
|
||||
}
|
||||
fn clipboard_get_text(&mut self) -> Option<String> {
|
||||
read_clipboard(self.clipboard.as_mut()?, |c| c.get_text().ok())
|
||||
}
|
||||
|
||||
@@ -272,6 +272,8 @@ pub trait Services {
|
||||
Box::pin(std::future::ready(None))
|
||||
}
|
||||
fn clipboard_set_text(&mut self, _s: &str) {}
|
||||
/// Give native services access to the window context for platform clipboard output.
|
||||
fn set_egui_context(&mut self, _ctx: &egui::Context) {}
|
||||
fn clipboard_get_text(&mut self) -> Option<String> {
|
||||
None
|
||||
}
|
||||
@@ -387,9 +389,8 @@ impl Wake for RepaintWaker {
|
||||
pub struct NoServices;
|
||||
impl Services for NoServices {}
|
||||
|
||||
/// Put `text` on the system clipboard through egui's output, which the browser shell writes while
|
||||
/// it handles the copy event (the only time a page may write it). For shells without a clipboard
|
||||
/// of their own.
|
||||
/// Put `text` on the system clipboard through egui's platform output. Native integrations handle
|
||||
/// it directly; the browser shell writes it while handling the copy event.
|
||||
pub fn egui_copy_text(ctx: &egui::Context, text: &str) {
|
||||
ctx.copy_text(text.to_string());
|
||||
}
|
||||
|
||||
@@ -59,6 +59,30 @@ fn enter_edits_a_selected_text_with_all_of_it_selected_and_escape_keeps_the_laye
|
||||
assert!(u.app.session.selection().is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn copying_and_cutting_selected_text_use_clipboard_service() {
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
struct Clipboard(Rc<RefCell<Vec<String>>>);
|
||||
impl crate::Services for Clipboard {
|
||||
fn clipboard_set_text(&mut self, text: &str) {
|
||||
self.0.borrow_mut().push(text.to_string());
|
||||
}
|
||||
}
|
||||
|
||||
let mut s = Session::new();
|
||||
let t = NodeId(s.execute("text.create", &json!({"text": "Hello world", "x": 20, "y": 20})).unwrap()["id"].as_u64().unwrap());
|
||||
s.execute("select.set", &json!({"ids": [t]})).unwrap();
|
||||
let mut u = Ui::new(s);
|
||||
let copied = Rc::new(RefCell::new(Vec::new()));
|
||||
u.app.services = Box::new(Clipboard(copied.clone()));
|
||||
press(&mut u, Key::Enter);
|
||||
u.frame_output(vec![Event::Copy]);
|
||||
u.frame_output(vec![Event::Cut]);
|
||||
assert_eq!(&*copied.borrow(), &["Hello world", "Hello world"]);
|
||||
assert_eq!(u.app.session.doc().unwrap().node(t).unwrap().kind.text().unwrap().characters, "");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn a_new_file_takes_the_page_colour_of_the_theme_and_keeps_it() {
|
||||
let mut s = Session::new();
|
||||
|
||||
Reference in New Issue
Block a user