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::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 _clipboard: &mut dyn Clipboard,
94 shell: &mut Shell<'_, Message>,
95 _viewport: &Rectangle,
96 ) {
97 let bounds = layout.bounds();
98
99 let state = tree.state.downcast_mut::<P::State>();
100
101 if let Some(action) = self.program.update(state, event, bounds, cursor) {
102 let (message, redraw_request, event_status) = action.into_inner();
103
104 shell.request_redraw_at(redraw_request);
105
106 if let Some(message) = message {
107 shell.publish(message);
108 }
109
110 if event_status == event::Status::Captured {
111 shell.capture_event();
112 }
113 }
114 }
115
116 fn mouse_interaction(
117 &self,
118 tree: &Tree,
119 layout: Layout<'_>,
120 cursor: mouse::Cursor,
121 _viewport: &Rectangle,
122 _renderer: &Renderer,
123 ) -> mouse::Interaction {
124 let bounds = layout.bounds();
125 let state = tree.state.downcast_ref::<P::State>();
126
127 self.program.mouse_interaction(state, bounds, cursor)
128 }
129
130 fn draw(
131 &self,
132 tree: &widget::Tree,
133 renderer: &mut Renderer,
134 _theme: &Theme,
135 _style: &renderer::Style,
136 layout: Layout<'_>,
137 cursor_position: mouse::Cursor,
138 _viewport: &Rectangle,
139 ) {
140 let bounds = layout.bounds();
141 let state = tree.state.downcast_ref::<P::State>();
142
143 renderer.draw_primitive(bounds, self.program.draw(state, cursor_position, bounds));
144 }
145}
146
147impl<'a, Message, Theme, Renderer, P> From<Shader<Message, P>>
148 for Element<'a, Message, Theme, Renderer>
149where
150 Message: 'a,
151 Renderer: primitive::Renderer,
152 P: Program<Message> + 'a,
153{
154 fn from(custom: Shader<Message, P>) -> Element<'a, Message, Theme, Renderer> {
155 Element::new(custom)
156 }
157}
158
159impl<Message, T> Program<Message> for &T
160where
161 T: Program<Message>,
162{
163 type State = T::State;
164 type Primitive = T::Primitive;
165
166 fn update(
167 &self,
168 state: &mut Self::State,
169 event: &Event,
170 bounds: Rectangle,
171 cursor: mouse::Cursor,
172 ) -> Option<Action<Message>> {
173 T::update(self, state, event, bounds, cursor)
174 }
175
176 fn draw(
177 &self,
178 state: &Self::State,
179 cursor: mouse::Cursor,
180 bounds: Rectangle,
181 ) -> Self::Primitive {
182 T::draw(self, state, cursor, bounds)
183 }
184
185 fn mouse_interaction(
186 &self,
187 state: &Self::State,
188 bounds: Rectangle,
189 cursor: mouse::Cursor,
190 ) -> mouse::Interaction {
191 T::mouse_interaction(self, state, bounds, cursor)
192 }
193}