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::{Element, 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
21pub 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 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 pub fn width(mut self, width: impl Into<Length>) -> Self {
45 self.width = width.into();
46 self
47 }
48
49 pub fn height(mut self, height: impl Into<Length>) -> Self {
51 self.height = height.into();
52 self
53 }
54}
55
56impl<P, Message, Theme, Renderer> Widget<Message, Theme, Renderer> for Shader<Message, P>
57where
58 P: Program<Message>,
59 Renderer: primitive::Renderer,
60{
61 fn tag(&self) -> tree::Tag {
62 struct Tag<T>(T);
63 tree::Tag::of::<Tag<P::State>>()
64 }
65
66 fn state(&self) -> tree::State {
67 tree::State::new(P::State::default())
68 }
69
70 fn size(&self) -> Size<Length> {
71 Size {
72 width: self.width,
73 height: self.height,
74 }
75 }
76
77 fn layout(
78 &mut self,
79 _tree: &mut Tree,
80 _renderer: &Renderer,
81 limits: &layout::Limits,
82 ) -> layout::Node {
83 layout::atomic(limits, self.width, self.height)
84 }
85
86 fn update(
87 &mut self,
88 tree: &mut Tree,
89 event: &Event,
90 layout: Layout<'_>,
91 cursor: mouse::Cursor,
92 _renderer: &Renderer,
93 shell: &mut Shell<'_, Message>,
94 _viewport: &Rectangle,
95 ) {
96 let bounds = layout.bounds();
97
98 let state = tree.state.downcast_mut::<P::State>();
99
100 if let Some(action) = self.program.update(state, event, bounds, cursor) {
101 let (message, redraw_request, event_status) = action.into_inner();
102
103 shell.request_redraw_at(redraw_request);
104
105 if let Some(message) = message {
106 shell.publish(message);
107 }
108
109 if event_status == event::Status::Captured {
110 shell.capture_event();
111 }
112 }
113 }
114
115 fn mouse_interaction(
116 &self,
117 tree: &Tree,
118 layout: Layout<'_>,
119 cursor: mouse::Cursor,
120 _viewport: &Rectangle,
121 _renderer: &Renderer,
122 ) -> mouse::Interaction {
123 let bounds = layout.bounds();
124 let state = tree.state.downcast_ref::<P::State>();
125
126 self.program.mouse_interaction(state, bounds, cursor)
127 }
128
129 fn draw(
130 &self,
131 tree: &widget::Tree,
132 renderer: &mut Renderer,
133 _theme: &Theme,
134 _style: &renderer::Style,
135 layout: Layout<'_>,
136 cursor_position: mouse::Cursor,
137 _viewport: &Rectangle,
138 ) {
139 let bounds = layout.bounds();
140 let state = tree.state.downcast_ref::<P::State>();
141
142 renderer.draw_primitive(bounds, self.program.draw(state, cursor_position, bounds));
143 }
144}
145
146impl<'a, Message, Theme, Renderer, P> From<Shader<Message, P>>
147 for Element<'a, Message, Theme, Renderer>
148where
149 Message: 'a,
150 Renderer: primitive::Renderer,
151 P: Program<Message> + 'a,
152{
153 fn from(custom: Shader<Message, P>) -> Element<'a, Message, Theme, Renderer> {
154 Element::new(custom)
155 }
156}
157
158impl<Message, T> Program<Message> for &T
159where
160 T: Program<Message>,
161{
162 type State = T::State;
163 type Primitive = T::Primitive;
164
165 fn update(
166 &self,
167 state: &mut Self::State,
168 event: &Event,
169 bounds: Rectangle,
170 cursor: mouse::Cursor,
171 ) -> Option<Action<Message>> {
172 T::update(self, state, event, bounds, cursor)
173 }
174
175 fn draw(
176 &self,
177 state: &Self::State,
178 cursor: mouse::Cursor,
179 bounds: Rectangle,
180 ) -> Self::Primitive {
181 T::draw(self, state, cursor, bounds)
182 }
183
184 fn mouse_interaction(
185 &self,
186 state: &Self::State,
187 bounds: Rectangle,
188 cursor: mouse::Cursor,
189 ) -> mouse::Interaction {
190 T::mouse_interaction(self, state, bounds, cursor)
191 }
192}