1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::action::{Action, Props, StatefulAction, INFINITE, VISUAL};
use crate::comm::QWriter;
use crate::resource::{Color, IoManager, ResourceAddr, ResourceManager, ResourceValue};
use crate::server::{AsyncSignal, Config, State, SyncSignal};
use eframe::egui;
use eframe::egui::{CentralPanel, Color32, CursorIcon, Frame, TextureId, Vec2};
use eyre::{eyre, Result};
use serde::{Deserialize, Serialize};
use std::path::PathBuf;
#[derive(Debug, Deserialize, Serialize)]
#[serde(deny_unknown_fields)]
pub struct Image {
src: PathBuf,
#[serde(default)]
width: Option<f32>,
#[serde(default)]
background: Color,
}
stateful!(Image {
handle: TextureId,
size: Vec2,
width: Option<f32>,
background: Color32,
});
impl Image {
#[inline(always)]
pub fn new(src: PathBuf, width: Option<f32>, background: Color) -> Self {
Self {
src,
width,
background,
}
}
}
impl Action for Image {
#[inline(always)]
fn resources(&self, _config: &Config) -> Vec<ResourceAddr> {
vec![ResourceAddr::Image(self.src.to_owned())]
}
fn stateful(
&self,
_io: &IoManager,
res: &ResourceManager,
_config: &Config,
_sync_writer: &QWriter<SyncSignal>,
_async_writer: &QWriter<AsyncSignal>,
) -> Result<Box<dyn StatefulAction>> {
let src = ResourceAddr::Image(self.src.clone());
let (texture, size) = {
if let ResourceValue::Image(texture, size) = res.fetch(&src)? {
(texture, size)
} else {
return Err(eyre!("Resource value and address types don't match."));
}
};
Ok(Box::new(StatefulImage {
done: false,
handle: texture,
size,
width: self.width,
background: self.background.into(),
}))
}
}
impl StatefulAction for StatefulImage {
impl_stateful!();
#[inline]
fn props(&self) -> Props {
(INFINITE | VISUAL).into()
}
fn show(
&mut self,
ui: &mut egui::Ui,
_sync_writer: &mut QWriter<SyncSignal>,
_async_writer: &mut QWriter<AsyncSignal>,
_state: &State,
) -> Result<()> {
ui.output().cursor_icon = CursorIcon::None;
CentralPanel::default()
.frame(Frame::default().fill(self.background))
.show_inside(ui, |ui| {
ui.centered_and_justified(|ui| {
if let Some(width) = self.width {
let scale = width / self.size.x;
ui.image(self.handle, self.size * scale);
} else {
ui.image(self.handle, self.size);
}
});
});
Ok(())
}
fn debug(&self) -> Vec<(&str, String)> {
<dyn StatefulAction>::debug(self)
.into_iter()
.chain([
("texture_id", format!("{:?}", self.handle)),
("size", format!("{:?}", self.size)),
])
.collect()
}
}