1mod 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::{Clipboard, Element, Event, Length, Rectangle, Shell, Size};
13use crate::renderer::wgpu::primitive;
14
15use std::marker::PhantomData;
16
17pub use crate::graphics::Viewport;
18pub use crate::Action;
19pub use primitive::{Primitive, Storage};
20
21#[allow(missing_debug_implementations)]
26pub struct Shader<Message, P: Program<Message>> {
27 width: Length,
28 height: Length,
29 program: P,
30 _message: PhantomData<Message>,
31}
32
33impl<Message, P: Program<Message>> Shader<Message, P> {
34 pub fn new(program: P) -> Self {
36 Self {
37 width: Length::Fixed(100.0),
38 height: Length::Fixed(100.0),
39 program,
40 _message: PhantomData,
41 }
42 }
43
44 pub fn width(mut self, width: impl Into<Length>) -> Self {
46 self.width = width.into();
47 self
48 }
49
50 pub fn height(mut self, height: impl Into<Length>) -> Self {
52 self.height = height.into();
53 self
54 }
55}
56
57impl<P, Message, Theme, Renderer> Widget<Message, Theme, Renderer>
58 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(
80 &self,
81 _tree: &mut Tree,
82 _renderer: &Renderer,
83 limits: &layout::Limits,
84 ) -> layout::Node {
85 layout::atomic(limits, self.width, self.height)
86 }
87
88 fn update(
89 &mut self,
90 tree: &mut Tree,
91 event: &Event,
92 layout: Layout<'_>,
93 cursor: mouse::Cursor,
94 _renderer: &Renderer,
95 _clipboard: &mut dyn Clipboard,
96 shell: &mut Shell<'_, Message>,
97 _viewport: &Rectangle,
98 ) {
99 let bounds = layout.bounds();
100
101 let state = tree.state.downcast_mut::<P::State>();
102
103 if let Some(action) = self.program.update(state, event, bounds, cursor)
104 {
105 let (message, redraw_request, event_status) = action.into_inner();
106
107 shell.request_redraw_at(redraw_request);
108
109 if let Some(message) = message {
110 shell.publish(message);
111 }
112
113 if event_status == event::Status::Captured {
114 shell.capture_event();
115 }
116 }
117 }
118
119 fn mouse_interaction(
120 &self,
121 tree: &Tree,
122 layout: Layout<'_>,
123 cursor: mouse::Cursor,
124 _viewport: &Rectangle,
125 _renderer: &Renderer,
126 ) -> mouse::Interaction {
127 let bounds = layout.bounds();
128 let state = tree.state.downcast_ref::<P::State>();
129
130 self.program.mouse_interaction(state, bounds, cursor)
131 }
132
133 fn draw(
134 &self,
135 tree: &widget::Tree,
136 renderer: &mut Renderer,
137 _theme: &Theme,
138 _style: &renderer::Style,
139 layout: Layout<'_>,
140 cursor_position: mouse::Cursor,
141 _viewport: &Rectangle,
142 ) {
143 let bounds = layout.bounds();
144 let state = tree.state.downcast_ref::<P::State>();
145
146 renderer.draw_primitive(
147 bounds,
148 self.program.draw(state, cursor_position, bounds),
149 );
150 }
151}
152
153impl<'a, Message, Theme, Renderer, P> From<Shader<Message, P>>
154 for Element<'a, Message, Theme, Renderer>
155where
156 Message: 'a,
157 Renderer: primitive::Renderer,
158 P: Program<Message> + 'a,
159{
160 fn from(
161 custom: Shader<Message, P>,
162 ) -> Element<'a, Message, Theme, Renderer> {
163 Element::new(custom)
164 }
165}
166
167impl<Message, T> Program<Message> for &T
168where
169 T: Program<Message>,
170{
171 type State = T::State;
172 type Primitive = T::Primitive;
173
174 fn update(
175 &self,
176 state: &mut Self::State,
177 event: &Event,
178 bounds: Rectangle,
179 cursor: mouse::Cursor,
180 ) -> Option<Action<Message>> {
181 T::update(self, state, event, bounds, cursor)
182 }
183
184 fn draw(
185 &self,
186 state: &Self::State,
187 cursor: mouse::Cursor,
188 bounds: Rectangle,
189 ) -> Self::Primitive {
190 T::draw(self, state, cursor, bounds)
191 }
192
193 fn mouse_interaction(
194 &self,
195 state: &Self::State,
196 bounds: Rectangle,
197 cursor: mouse::Cursor,
198 ) -> mouse::Interaction {
199 T::mouse_interaction(self, state, bounds, cursor)
200 }
201}