1use super::CursorStyle;
2use crate::{AnyAction, ClipboardItem};
3use parking_lot::Mutex;
4use pathfinder_geometry::vector::Vector2F;
5use std::{
6 any::Any,
7 cell::RefCell,
8 path::{Path, PathBuf},
9 rc::Rc,
10 sync::Arc,
11};
12use time::UtcOffset;
13
14pub struct Platform {
15 dispatcher: Arc<dyn super::Dispatcher>,
16 fonts: Arc<dyn super::FontSystem>,
17 current_clipboard_item: Mutex<Option<ClipboardItem>>,
18 cursor: Mutex<CursorStyle>,
19}
20
21#[derive(Default)]
22pub struct ForegroundPlatform {
23 last_prompt_for_new_path_args: RefCell<Option<(PathBuf, Box<dyn FnOnce(Option<PathBuf>)>)>>,
24}
25
26struct Dispatcher;
27
28pub struct Window {
29 size: Vector2F,
30 scale_factor: f32,
31 current_scene: Option<crate::Scene>,
32 event_handlers: Vec<Box<dyn FnMut(super::Event)>>,
33 resize_handlers: Vec<Box<dyn FnMut()>>,
34 close_handlers: Vec<Box<dyn FnOnce()>>,
35 pub(crate) last_prompt: RefCell<Option<Box<dyn FnOnce(usize)>>>,
36}
37
38impl ForegroundPlatform {
39 pub(crate) fn simulate_new_path_selection(
40 &self,
41 result: impl FnOnce(PathBuf) -> Option<PathBuf>,
42 ) {
43 let (dir_path, callback) = self
44 .last_prompt_for_new_path_args
45 .take()
46 .expect("prompt_for_new_path was not called");
47 callback(result(dir_path));
48 }
49
50 pub(crate) fn did_prompt_for_new_path(&self) -> bool {
51 self.last_prompt_for_new_path_args.borrow().is_some()
52 }
53}
54
55impl super::ForegroundPlatform for ForegroundPlatform {
56 fn on_become_active(&self, _: Box<dyn FnMut()>) {}
57
58 fn on_resign_active(&self, _: Box<dyn FnMut()>) {}
59
60 fn on_event(&self, _: Box<dyn FnMut(crate::Event) -> bool>) {}
61
62 fn on_open_files(&self, _: Box<dyn FnMut(Vec<std::path::PathBuf>)>) {}
63
64 fn run(&self, _on_finish_launching: Box<dyn FnOnce() -> ()>) {
65 unimplemented!()
66 }
67
68 fn on_menu_command(&self, _: Box<dyn FnMut(&dyn AnyAction)>) {}
69
70 fn set_menus(&self, _: Vec<crate::Menu>) {}
71
72 fn prompt_for_paths(
73 &self,
74 _: super::PathPromptOptions,
75 _: Box<dyn FnOnce(Option<Vec<std::path::PathBuf>>)>,
76 ) {
77 }
78
79 fn prompt_for_new_path(&self, path: &Path, f: Box<dyn FnOnce(Option<std::path::PathBuf>)>) {
80 *self.last_prompt_for_new_path_args.borrow_mut() = Some((path.to_path_buf(), f));
81 }
82}
83
84impl Platform {
85 fn new() -> Self {
86 Self {
87 dispatcher: Arc::new(Dispatcher),
88 fonts: Arc::new(super::current::FontSystem::new()),
89 current_clipboard_item: Default::default(),
90 cursor: Mutex::new(CursorStyle::Arrow),
91 }
92 }
93}
94
95impl super::Platform for Platform {
96 fn dispatcher(&self) -> Arc<dyn super::Dispatcher> {
97 self.dispatcher.clone()
98 }
99
100 fn fonts(&self) -> std::sync::Arc<dyn super::FontSystem> {
101 self.fonts.clone()
102 }
103
104 fn activate(&self, _ignoring_other_apps: bool) {}
105
106 fn open_window(
107 &self,
108 _: usize,
109 options: super::WindowOptions,
110 _executor: Rc<super::executor::Foreground>,
111 ) -> Box<dyn super::Window> {
112 Box::new(Window::new(options.bounds.size()))
113 }
114
115 fn key_window_id(&self) -> Option<usize> {
116 None
117 }
118
119 fn quit(&self) {}
120
121 fn write_to_clipboard(&self, item: ClipboardItem) {
122 *self.current_clipboard_item.lock() = Some(item);
123 }
124
125 fn read_from_clipboard(&self) -> Option<ClipboardItem> {
126 self.current_clipboard_item.lock().clone()
127 }
128
129 fn open_url(&self, _: &str) {}
130
131 fn write_credentials(&self, _: &str, _: &str, _: &[u8]) {}
132
133 fn read_credentials(&self, _: &str) -> Option<(String, Vec<u8>)> {
134 None
135 }
136
137 fn set_cursor_style(&self, style: CursorStyle) {
138 *self.cursor.lock() = style;
139 }
140
141 fn local_timezone(&self) -> UtcOffset {
142 UtcOffset::UTC
143 }
144}
145
146impl Window {
147 fn new(size: Vector2F) -> Self {
148 Self {
149 size,
150 event_handlers: Vec::new(),
151 resize_handlers: Vec::new(),
152 close_handlers: Vec::new(),
153 scale_factor: 1.0,
154 current_scene: None,
155 last_prompt: RefCell::new(None),
156 }
157 }
158}
159
160impl super::Dispatcher for Dispatcher {
161 fn is_main_thread(&self) -> bool {
162 true
163 }
164
165 fn run_on_main_thread(&self, task: async_task::Runnable) {
166 task.run();
167 }
168}
169
170impl super::WindowContext for Window {
171 fn size(&self) -> Vector2F {
172 self.size
173 }
174
175 fn scale_factor(&self) -> f32 {
176 self.scale_factor
177 }
178
179 fn titlebar_height(&self) -> f32 {
180 24.
181 }
182
183 fn present_scene(&mut self, scene: crate::Scene) {
184 self.current_scene = Some(scene);
185 }
186}
187
188impl super::Window for Window {
189 fn as_any_mut(&mut self) -> &mut dyn Any {
190 self
191 }
192
193 fn on_event(&mut self, callback: Box<dyn FnMut(crate::Event)>) {
194 self.event_handlers.push(callback);
195 }
196
197 fn on_resize(&mut self, callback: Box<dyn FnMut()>) {
198 self.resize_handlers.push(callback);
199 }
200
201 fn on_close(&mut self, callback: Box<dyn FnOnce()>) {
202 self.close_handlers.push(callback);
203 }
204
205 fn prompt(&self, _: crate::PromptLevel, _: &str, _: &[&str], f: Box<dyn FnOnce(usize)>) {
206 self.last_prompt.replace(Some(f));
207 }
208}
209
210pub fn platform() -> Platform {
211 Platform::new()
212}
213
214pub fn foreground_platform() -> ForegroundPlatform {
215 ForegroundPlatform::default()
216}