1use ferroui_base::media::imaging::{BitmapEncoderOptions, PngBitmapEncoderOptions};
2use ferroui_base::platform::SharedBitmapImpl;
3use ferroui_controls::platform::{
4 IPlatformIconLoader, ITopLevelImpl, ITrayIconImpl, IWindowIconImpl, IWindowImpl, IWindowingPlatform,
5};
6use std::fs::File;
7use std::io;
8use std::rc::Rc;
9use std::sync::Arc;
10
11#[derive(Default)]
14pub struct WindowingPlatformStub;
15
16impl IWindowingPlatform for WindowingPlatformStub {
17 fn create_window(&self) -> Rc<dyn IWindowImpl> {
18 panic!("Specified method is not supported.");
19 }
20
21 fn create_embeddable_top_level(&self) -> Rc<dyn ITopLevelImpl> {
22 self.create_embeddable_window()
23 }
24
25 fn create_embeddable_window(&self) -> Rc<dyn IWindowImpl> {
26 panic!("Specified method is not supported.");
27 }
28
29 fn create_tray_icon(&self) -> Option<Rc<dyn ITrayIconImpl>> {
30 None
31 }
32
33 fn get_windows_z_order(&self, _windows: &[Rc<dyn IWindowImpl>], _z_order: &mut [i64]) {
34 panic!("Specified method is not supported.");
35 }
36}
37
38#[derive(Default)]
41pub struct PlatformIconLoaderStub;
42
43impl IPlatformIconLoader for PlatformIconLoaderStub {
44 fn load_icon_from_file(&self, file_name: &str) -> io::Result<Rc<dyn IWindowIconImpl>> {
45 let mut file = File::open(file_name)?;
46 self.load_icon_from_stream(&mut file)
47 }
48
49 fn load_icon_from_stream(&self, stream: &mut dyn io::Read) -> io::Result<Rc<dyn IWindowIconImpl>> {
50 let mut ms = Vec::new();
51 stream.read_to_end(&mut ms)?;
52 Ok(Rc::new(IconStub::new(ms)))
53 }
54
55 fn load_icon_from_bitmap(&self, bitmap: Arc<SharedBitmapImpl>) -> Rc<dyn IWindowIconImpl> {
56 let mut stream = Vec::new();
57 if bitmap.save(&mut stream, &BitmapEncoderOptions::Png(PngBitmapEncoderOptions::DEFAULT)).is_err() {
60 stream.clear();
61 }
62 Rc::new(IconStub::new(stream))
63 }
64}
65
66pub(crate) struct IconStub {
67 ms: Vec<u8>,
68}
69
70impl IconStub {
71 pub(crate) fn new(stream: Vec<u8>) -> Self {
72 Self { ms: stream }
73 }
74}
75
76impl IWindowIconImpl for IconStub {
77 fn save(&self, output_stream: &mut dyn io::Write) -> io::Result<()> {
78 output_stream.write_all(&self.ms)
79 }
80}
81
82#[cfg(test)]
83mod tests {
84 use super::*;
86
87 #[test]
88 fn there_is_no_tray_icon() {
89 assert!(WindowingPlatformStub.create_tray_icon().is_none());
90 }
91
92 #[test]
93 #[should_panic(expected = "Specified method is not supported")]
94 fn windows_cannot_be_created() {
95 WindowingPlatformStub.create_window();
96 }
97
98 #[test]
99 #[should_panic(expected = "Specified method is not supported")]
100 fn embeddable_top_levels_cannot_be_created() {
101 WindowingPlatformStub.create_embeddable_top_level();
102 }
103
104 #[test]
105 #[should_panic(expected = "Specified method is not supported")]
106 fn the_z_order_of_windows_is_not_available() {
107 WindowingPlatformStub.get_windows_z_order(&[], &mut []);
108 }
109
110 #[test]
111 fn an_icon_of_a_stream_saves_the_bytes_of_the_stream() {
112 let loader = PlatformIconLoaderStub;
113 let icon = loader.load_icon_from_stream(&mut io::Cursor::new(vec![1, 2, 3])).unwrap();
114 let mut output = Vec::new();
115
116 icon.save(&mut output).unwrap();
117 icon.save(&mut output).unwrap();
118
119 assert_eq!(output, [1, 2, 3, 1, 2, 3]);
120 }
121
122 #[test]
123 fn a_missing_file_is_an_error() {
124 assert!(PlatformIconLoaderStub.load_icon_from_file("/nonexistent/icon.png").is_err());
125 }
126}