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