rg3d_ui/
image.rs

1use crate::{
2    brush::Brush,
3    core::{algebra::Vector2, color::Color, pool::Handle},
4    define_constructor,
5    draw::{CommandTexture, Draw, DrawingContext, SharedTexture},
6    message::{MessageDirection, UiMessage},
7    widget::{Widget, WidgetBuilder},
8    BuildContext, Control, UiNode, UserInterface,
9};
10use std::{
11    any::{Any, TypeId},
12    ops::{Deref, DerefMut},
13};
14
15#[derive(Debug, Clone, PartialEq)]
16pub enum ImageMessage {
17    Texture(Option<SharedTexture>),
18    Flip(bool),
19}
20
21impl ImageMessage {
22    define_constructor!(ImageMessage:Texture => fn texture(Option<SharedTexture>), layout: false);
23    define_constructor!(ImageMessage:Flip => fn flip(bool), layout: false);
24}
25
26#[derive(Clone)]
27pub struct Image {
28    widget: Widget,
29    texture: Option<SharedTexture>,
30    flip: bool,
31}
32
33crate::define_widget_deref!(Image);
34
35impl Image {
36    pub fn new(widget: Widget) -> Self {
37        Self {
38            widget,
39            texture: None,
40            flip: false,
41        }
42    }
43
44    pub fn set_texture(&mut self, texture: SharedTexture) {
45        self.texture = Some(texture);
46    }
47
48    pub fn texture(&self) -> Option<SharedTexture> {
49        self.texture.clone()
50    }
51}
52
53impl Control for Image {
54    fn query_component(&self, type_id: TypeId) -> Option<&dyn Any> {
55        if type_id == TypeId::of::<Self>() {
56            Some(self)
57        } else {
58            None
59        }
60    }
61
62    fn draw(&self, drawing_context: &mut DrawingContext) {
63        let bounds = self.widget.screen_bounds();
64        let tex_coords = if self.flip {
65            Some([
66                Vector2::new(0.0, 0.0),
67                Vector2::new(1.0, 0.0),
68                Vector2::new(1.0, -1.0),
69                Vector2::new(0.0, -1.0),
70            ])
71        } else {
72            None
73        };
74        drawing_context.push_rect_filled(&bounds, tex_coords.as_ref());
75        let texture = self
76            .texture
77            .as_ref()
78            .map_or(CommandTexture::None, |t| CommandTexture::Texture(t.clone()));
79        drawing_context.commit(self.clip_bounds(), self.widget.background(), texture, None);
80    }
81
82    fn handle_routed_message(&mut self, ui: &mut UserInterface, message: &mut UiMessage) {
83        self.widget.handle_routed_message(ui, message);
84
85        if let Some(msg) = message.data::<ImageMessage>() {
86            if message.destination() == self.handle {
87                match msg {
88                    ImageMessage::Texture(tex) => {
89                        self.texture = tex.clone();
90                    }
91                    &ImageMessage::Flip(flip) => {
92                        self.flip = flip;
93                    }
94                }
95            }
96        }
97    }
98}
99
100pub struct ImageBuilder {
101    widget_builder: WidgetBuilder,
102    texture: Option<SharedTexture>,
103    flip: bool,
104}
105
106impl ImageBuilder {
107    pub fn new(widget_builder: WidgetBuilder) -> Self {
108        Self {
109            widget_builder,
110            texture: None,
111            flip: false,
112        }
113    }
114
115    pub fn with_flip(mut self, flip: bool) -> Self {
116        self.flip = flip;
117        self
118    }
119
120    pub fn with_texture(mut self, texture: SharedTexture) -> Self {
121        self.texture = Some(texture);
122        self
123    }
124
125    pub fn with_opt_texture(mut self, texture: Option<SharedTexture>) -> Self {
126        self.texture = texture;
127        self
128    }
129
130    pub fn build_node(mut self) -> UiNode {
131        if self.widget_builder.background.is_none() {
132            self.widget_builder.background = Some(Brush::Solid(Color::WHITE))
133        }
134
135        let image = Image {
136            widget: self.widget_builder.build(),
137            texture: self.texture,
138            flip: self.flip,
139        };
140        UiNode::new(image)
141    }
142
143    pub fn build(self, ctx: &mut BuildContext) -> Handle<UiNode> {
144        ctx.add_node(self.build_node())
145    }
146}