1use glam::Vec2;
2use ori_graphics::{ImageHandle, ImageSource, Mesh};
3use ori_macro::Build;
4
5use crate::{
6 BoxConstraints, Context, DrawContext, Event, EventContext, LayoutContext, Style, View,
7};
8
9#[derive(Clone, Default, Debug, Build)]
10pub struct Image {
11 #[prop]
12 src: ImageSource,
13}
14
15impl Image {
16 pub fn new() -> Self {
17 Self::default()
18 }
19}
20
21#[derive(Clone, Debug, Default)]
22pub struct ImageState {
23 src: ImageSource,
24 handle: Option<ImageHandle>,
25}
26
27impl ImageState {
28 pub fn update(&mut self, context: &mut impl Context, src: &ImageSource) -> &ImageHandle {
29 if self.src != *src || self.handle.is_none() {
30 self.src = src.clone();
31 self.handle = Some(context.load_image(src));
32 }
33
34 self.handle.as_ref().unwrap()
35 }
36}
37
38impl View for Image {
39 type State = ImageState;
40
41 fn build(&self) -> Self::State {
42 Default::default()
43 }
44
45 fn style(&self) -> Style {
46 Style::new("image")
47 }
48
49 fn event(&self, _state: &mut Self::State, _cx: &mut EventContext, _event: &Event) {}
50
51 fn layout(&self, state: &mut Self::State, cx: &mut LayoutContext, bc: BoxConstraints) -> Vec2 {
52 let min_width = cx.style_range_group("min-width", "width", bc.width());
53 let max_width = cx.style_range_group("max-width", "width", bc.width());
54
55 let min_height = cx.style_range_group("min-width", "height", bc.height());
56 let max_height = cx.style_range_group("min-height", "height", bc.height());
57
58 let min_size = bc.constrain(Vec2::new(min_width, min_height));
59 let max_size = bc.constrain(Vec2::new(max_width, max_height));
60
61 let handle = state.update(cx, &self.src);
62
63 let mut size = handle.size();
66 let aspect = size.x / size.y;
67
68 if size.x > max_size.x {
69 size.x = max_size.x;
70 size.y = size.x / aspect;
71 }
72
73 if size.y > max_size.y {
74 size.y = max_size.y;
75 size.x = size.y * aspect;
76 }
77
78 if size.x < min_size.x {
79 size.x = min_size.x;
80 size.y = size.x / aspect;
81 }
82
83 if size.y < min_size.y {
84 size.y = min_size.y;
85 size.x = size.y * aspect;
86 }
87
88 size
89 }
90
91 fn draw(&self, state: &mut Self::State, cx: &mut DrawContext) {
92 let handle = state.update(cx, &self.src);
93 let mesh = Mesh::image(cx.rect(), handle.clone());
94 cx.draw(mesh);
95 }
96}