Skip to main content

iced_widget/
shader.rs

1//! A custom shader widget for wgpu applications.
2mod program;
3
4pub use program::Program;
5
6use crate::core::event;
7use crate::core::layout::{self, Layout};
8use crate::core::mouse;
9use crate::core::renderer;
10use crate::core::widget::tree::{self, Tree};
11use crate::core::widget::{self, Widget};
12use crate::core::{Event, Length, Rectangle, Shell, Size};
13use crate::renderer::wgpu::primitive;
14
15use std::marker::PhantomData;
16
17pub use crate::Action;
18pub use crate::graphics::Viewport;
19pub use primitive::{Pipeline, Primitive, Storage};
20
21/// A widget which can render custom shaders with Iced's `wgpu` backend.
22///
23/// Must be initialized with a [`Program`], which describes the internal widget state & how
24/// its [`Program::Primitive`]s are drawn.
25pub struct Shader<Message, P: Program<Message>> {
26    width: Length,
27    height: Length,
28    program: P,
29    _message: PhantomData<Message>,
30}
31
32impl<Message, P: Program<Message>> Shader<Message, P> {
33    /// Create a new custom [`Shader`].
34    pub fn new(program: P) -> Self {
35        Self {
36            width: Length::Fixed(100.0),
37            height: Length::Fixed(100.0),
38            program,
39            _message: PhantomData,
40        }
41    }
42
43    /// Set the `width` of the custom [`Shader`].
44    pub fn width(mut self, width: impl Into<Length>) -> Self {
45        self.width = width.into();
46        self
47    }
48
49    /// Set the `height` of the custom [`Shader`].
50    pub fn height(mut self, height: impl Into<Length>) -> Self {
51        self.height = height.into();
52        self
53    }
54}
55
56impl<Message, P> widget::Meta for Shader<Message, P> where P: Program<Message> {}
57
58impl<P, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Shader<Message, P>
59where
60    P: Program<Message>,
61    Renderer: primitive::Renderer,
62{
63    fn tag(&self) -> tree::Tag {
64        struct Tag<T>(T);
65        tree::Tag::of::<Tag<P::State>>()
66    }
67
68    fn state(&self) -> tree::State {
69        tree::State::new(P::State::default())
70    }
71
72    fn size(&self) -> Size<Length> {
73        Size {
74            width: self.width,
75            height: self.height,
76        }
77    }
78
79    fn layout(&mut self, tree: &mut Tree, _renderer: &Renderer, limits: &layout::Limits) {
80        tree.size = layout::atomic(limits, self.width, self.height);
81    }
82
83    fn update(
84        &mut self,
85        tree: &mut Tree,
86        event: &Event,
87        layout: Layout,
88        cursor: mouse::Cursor,
89        _renderer: &Renderer,
90        shell: &mut Shell<'_, Message>,
91        _viewport: &Rectangle,
92    ) {
93        let bounds = layout.bounds();
94
95        let state = tree.state.downcast_mut::<P::State>();
96
97        if let Some(action) = self.program.update(state, event, bounds, cursor) {
98            let (message, redraw_request, event_status) = action.into_inner();
99
100            shell.request_redraw_at(redraw_request);
101
102            if let Some(message) = message {
103                shell.publish(message);
104            }
105
106            if event_status == event::Status::Captured {
107                shell.capture_event();
108            }
109        }
110    }
111
112    fn mouse_interaction(
113        &self,
114        tree: &Tree,
115        layout: Layout,
116        cursor: mouse::Cursor,
117        _viewport: &Rectangle,
118        _renderer: &Renderer,
119    ) -> mouse::Interaction {
120        let bounds = layout.bounds();
121        let state = tree.state.downcast_ref::<P::State>();
122
123        self.program.mouse_interaction(state, bounds, cursor)
124    }
125
126    fn draw(
127        &self,
128        tree: &widget::Tree,
129        renderer: &mut Renderer,
130        _theme: &Theme,
131        _style: &renderer::Style,
132        layout: Layout,
133        cursor_position: mouse::Cursor,
134        _viewport: &Rectangle,
135    ) {
136        let bounds = layout.bounds();
137        let state = tree.state.downcast_ref::<P::State>();
138
139        renderer.draw_primitive(bounds, self.program.draw(state, cursor_position, bounds));
140    }
141}
142
143impl<Message, T> Program<Message> for &T
144where
145    T: Program<Message>,
146{
147    type State = T::State;
148    type Primitive = T::Primitive;
149
150    fn update(
151        &self,
152        state: &mut Self::State,
153        event: &Event,
154        bounds: Rectangle,
155        cursor: mouse::Cursor,
156    ) -> Option<Action<Message>> {
157        T::update(self, state, event, bounds, cursor)
158    }
159
160    fn draw(
161        &self,
162        state: &Self::State,
163        cursor: mouse::Cursor,
164        bounds: Rectangle,
165    ) -> Self::Primitive {
166        T::draw(self, state, cursor, bounds)
167    }
168
169    fn mouse_interaction(
170        &self,
171        state: &Self::State,
172        bounds: Rectangle,
173        cursor: mouse::Cursor,
174    ) -> mouse::Interaction {
175        T::mouse_interaction(self, state, bounds, cursor)
176    }
177}