ferroui_diagnostics/diagnostics/screenshots/
file_picker_handler.rs1use super::BaseRenderToStreamHandler;
4use crate::diagnostics::views::MainWindow;
5use ferroui_base::input::LocalBoxFuture;
6use ferroui_base::platform::storage::{
7 FilePickerFileTypes, FilePickerSaveOptions, IStorageFolder, IStorageProvider, WellKnownFolder,
8};
9use ferroui_base::{Ref, Visual};
10use ferroui_controls::{Application, Control, TopLevel};
11use std::io::Write;
12use std::rc::Rc;
13
14pub struct FilePickerHandler {
16 title: String,
17 screenshot_root: Option<String>,
18}
19
20impl PartialEq for FilePickerHandler {
21 fn eq(&self, other: &Self) -> bool {
22 std::ptr::eq(self, other)
23 }
24}
25
26impl Default for FilePickerHandler {
27 fn default() -> Self {
28 Self::with_title(None, None)
29 }
30}
31
32impl FilePickerHandler {
33 pub fn new() -> Self {
35 Self::with_title(None, None)
36 }
37
38 pub fn with_title(title: Option<String>, screenshot_root: Option<String>) -> Self {
42 Self { title: title.unwrap_or_else(|| "Save Screenshot to ...".to_string()), screenshot_root }
43 }
44
45 fn get_top_level(control: &Ref<Control>) -> Option<Ref<TopLevel>> {
46 let dev_tools_top_level: Option<Ref<TopLevel>> = Application::current()
48 .and_then(|application| application.application_lifetime())
49 .and_then(|lifetime| {
50 lifetime.as_classic_desktop_style_application_lifetime().and_then(|desktop| {
51 desktop.windows().into_iter().find(|window| window.is::<MainWindow>()).map(|window| window.upcast())
52 })
53 });
54
55 let visual: &Visual = control;
56 dev_tools_top_level.or_else(|| TopLevel::get_top_level(Some(visual)))
57 }
58}
59
60impl BaseRenderToStreamHandler for FilePickerHandler {
61 fn get_stream(&self, control: &Ref<Control>) -> LocalBoxFuture<std::io::Result<Option<Box<dyn Write>>>> {
62 let Some(top_level) = Self::get_top_level(control) else {
63 return Box::pin(std::future::ready(Err::<Option<Box<dyn Write>>, _>(std::io::Error::other(
64 "No TopLevel is available.",
65 ))));
66 };
67 let storage_provider: Rc<dyn IStorageProvider> = top_level.storage_provider();
68 let title = self.title.clone();
69 let screenshot_root = self.screenshot_root.clone();
70
71 Box::pin(async move {
72 let mut default_folder: Option<Rc<dyn IStorageFolder>> = None;
73 if let Some(screenshot_root) = &screenshot_root {
74 default_folder = storage_provider.try_get_folder_from_path_str_async(screenshot_root).await;
75 }
76 if default_folder.is_none() {
77 default_folder = storage_provider.try_get_well_known_folder_async(WellKnownFolder::Pictures).await;
78 }
79
80 let mut options = FilePickerSaveOptions::new();
81 options.set_suggested_start_location(default_folder);
82 options.set_title(Some(title));
83 options.set_file_type_choices(Some(vec![FilePickerFileTypes::image_png()]));
84 options.set_default_extension(Some(".png".to_string()));
85
86 let result = storage_provider.save_file_picker_async(options).await?;
87 let Some(result) = result else {
88 return Ok(None);
89 };
90
91 Ok::<Option<Box<dyn Write>>, std::io::Error>(Some(result.open_write_async().await?))
92 })
93 }
94}