1use crate::{
2 makepad_derive_widget::*,
3 makepad_draw::*,
4 widget::*,
5};
6
7live_design!{
8 link widgets;
9 use link::theme::*;
10 use link::widgets::*;
11 use makepad_draw::shader::std::*;
12
13 pub SlidesViewBase = {{SlidesView}} {
14 }
15
16 pub SlidesView = <SlidesViewBase> {
17 anim_speed: 0.9
18 }
19
20 pub Slide = <RoundedView> {
21 width: Fill, height: Fill,
22 flow: Down, spacing: 10,
23 align: { x: 0.0, y: 0.5 }
24 padding: 50.
25 draw_bg: {
26 color: (THEME_COLOR_D_4),
27 border_radius: (THEME_CONTAINER_CORNER_RADIUS)
28 }
29 title = <H1> {
30 text: "SlideTitle",
31 draw_text: {
32 color: (THEME_COLOR_TEXT)
33 }
34 }
35 }
36
37 pub SlideChapter = <Slide> {
38 width: Fill, height: Fill,
39 flow: Down,
40 align: {x: 0.0, y: 0.5}
41 spacing: 10,
42 padding: 50,
43 draw_bg: {
44 color: (THEME_COLOR_MAKEPAD),
45 border_radius: (THEME_CONTAINER_CORNER_RADIUS)
46 }
47 title = <H1> {
48 text: "SlideTitle",
49 draw_text: {
50 color: (THEME_COLOR_TEXT)
51 }
52 }
53 }
54
55 pub SlideBody = <H2> {
56 text: "Body of the slide"
57 draw_text: {
58 color: (THEME_COLOR_TEXT)
59 }
60 }
61}
62
63#[derive(Live, LiveRegisterWidget, WidgetRef, WidgetSet)]
64pub struct SlidesView {
65 #[layout] layout: Layout,
66 #[rust] area: Area,
67 #[walk] walk: Walk,
68 #[rust] children: ComponentMap<LiveId, WidgetRef>,
69 #[rust] draw_order: Vec<LiveId>,
70 #[rust] next_frame: NextFrame,
71 #[rust] current_slide: f64,
72 #[rust] goal_slide: f64,
73 #[live] anim_speed: f64,
74 #[rust] draw_state: DrawStateWrap<DrawState>,
75}
76
77impl WidgetNode for SlidesView{
78 fn walk(&mut self, _cx:&mut Cx) -> Walk{
79 self.walk
80 }
81
82 fn area(&self)->Area{self.area}
83
84 fn redraw(&mut self, cx: &mut Cx){
85 self.area.redraw(cx)
86 }
87
88 fn find_widgets(&self, path: &[LiveId], cached: WidgetCache, results: &mut WidgetSet) {
89 for child in self.children.values() {
90 child.find_widgets(path, cached, results);
91 }
92 }
93
94 fn uid_to_widget(&self, uid:WidgetUid)->WidgetRef{
95 for child in self.children.values() {
96 let x = child.uid_to_widget(uid);
97 if !x.is_empty(){return x}
98 }
99 WidgetRef::empty()
100 }
101}
102
103
104
105#[derive(Clone)]
106enum DrawState {
107 DrawFirst,
108 DrawSecond,
109}
110
111impl LiveHook for SlidesView {
112 fn before_apply(&mut self, _cx: &mut Cx, apply: &mut Apply, _index: usize, _nodes: &[LiveNode]) {
113 if let ApplyFrom::UpdateFromDoc {..} = apply.from {
114 self.draw_order.clear();
116 }
117 }
118
119 fn apply_value_instance(&mut self, cx: &mut Cx, apply: &mut Apply, index: usize, nodes: &[LiveNode]) -> usize {
120 let id = nodes[index].id;
121 match apply.from {
122 ApplyFrom::Animate | ApplyFrom::Over => {
123 if let Some(component) = self.children.get_mut(&nodes[index].id) {
124 component.apply(cx, apply, index, nodes)
125 }
126 else {
127 nodes.skip_node(index)
128 }
129 }
130 ApplyFrom::NewFromDoc {..} | ApplyFrom::UpdateFromDoc {..} => {
131 if nodes[index].origin.has_prop_type(LivePropType::Instance) {
132 self.draw_order.push(id);
133 return self.children.get_or_insert(cx, id, | cx | {
134 WidgetRef::new(cx)
135 }).apply(cx, apply, index, nodes);
136 }
137 else {cx.apply_error_no_matching_field(live_error_origin!(), index, nodes);
138 nodes.skip_node(index)
139 }
140 }
141 _ => {
142 nodes.skip_node(index)
143 }
144 }
145 }
146
147 fn after_new_from_doc(&mut self, cx: &mut Cx){
148 self.next_frame(cx);
149 }
150
151}
152
153#[derive(Clone, Debug, DefaultNone)]
154pub enum SlidesViewAction {
155 Flipped(usize),
156 None,
157}
158
159impl Widget for SlidesView {
160 fn handle_event(&mut self, cx: &mut Cx, event: &Event, scope: &mut Scope) {
161 match event {
163 Event::NextFrame(ne) if ne.set.contains(&self.next_frame) => {
164 self.current_slide = self.current_slide * self.anim_speed + self.goal_slide * (1.0 - self.anim_speed);
165 if (self.current_slide - self.goal_slide).abs()>0.00001 {
166 self.next_frame(cx);
167 self.area.redraw(cx);
168 }
169 else {
170 self.current_slide = self.current_slide.round();
171 }
172
173 }
174 _ => ()
175 }
176
177 let current = self.current_slide.floor() as usize;
180 if let Some(current_id) = self.draw_order.get(current) {
181 if let Some(current) = self.children.get(¤t_id) {
182 scope.with_id(*current_id, |scope|{
183 current.handle_event(cx, event, scope);
184 })
185 }
186 }
187 if self.current_slide.fract() >0.0 {
188 let next = current + 1;
189 if let Some(next_id) = self.draw_order.get(next) {
190 if let Some(next) = self.children.get(&next_id) {
191 scope.with_id(*next_id, |scope|{
192 next.handle_event(cx, event, scope);
193 })
194 }
195 }
196 }
197 match event.hits(cx, self.area) {
198 Hit::KeyDown(KeyEvent {key_code: KeyCode::ArrowRight, ..}) => {
199 self.next_slide(cx);
200 let uid = self.widget_uid();
201 cx.widget_action(uid, &scope.path, SlidesViewAction::Flipped(self.goal_slide as usize));
202
203 }
204 Hit::KeyDown(KeyEvent {key_code: KeyCode::ArrowLeft, ..}) => {
205 self.prev_slide(cx);
206 let uid = self.widget_uid();
207 cx.widget_action(uid, &scope.path, SlidesViewAction::Flipped(self.goal_slide as usize));
208 }
209 Hit::FingerDown(_fe) => {
210 cx.set_key_focus(self.area);
211 },
212 _ => ()
213 }
214
215 }
216
217 fn draw_walk(&mut self, cx: &mut Cx2d, scope:&mut Scope, walk: Walk) -> DrawStep {
218 if self.draw_state.begin(cx, DrawState::DrawFirst) {
221 cx.begin_turtle(walk, Layout::flow_overlay());
222 let rect = cx.turtle().rect();
223 cx.begin_turtle(Walk {
224 abs_pos: None,
225 margin: Default::default(),
226 width: Size::Fill,
227 height: Size::Fill
228 }, Layout::flow_down().with_scroll(
229 dvec2(rect.size.x * self.current_slide.fract(), 0.0)
230 ));
231
232 }
233 if let Some(DrawState::DrawFirst) = self.draw_state.get() {
234 let first = self.current_slide.floor() as usize;
235 if let Some(first_id) = self.draw_order.get(first) {
236 if let Some(slide) = self.children.get(&first_id) {
237 let walk = slide.walk(cx);
238 scope.with_id(*first_id, |scope|{
239 slide.draw_walk(cx, scope, walk)
240 })?;
241 }
242 }
243 cx.end_turtle();
244 let rect = cx.turtle().rect();
245 cx.begin_turtle(Walk {
246 abs_pos: None,
247 margin: Default::default(),
248 width: Size::Fill,
249 height: Size::Fill
250 }, Layout::flow_down().with_scroll(
251 dvec2(-rect.size.x * (1.0-self.current_slide.fract()), 0.0)
252 ));
253 self.draw_state.set(DrawState::DrawSecond);
254 }
255 if let Some(DrawState::DrawSecond) = self.draw_state.get() {
256 if self.current_slide.fract() > 0.0 {
257 let second = self.current_slide.floor() as usize + 1;
258 if let Some(second_id) = self.draw_order.get(second) {
259 if let Some(slide) = self.children.get(&second_id) {
260 let walk = slide.walk(cx);
261 scope.with_id(*second_id, |scope|{
262 slide.draw_walk(cx, scope, walk)
263 })?;
264 }
265 }
266 }
267 }
268 cx.end_turtle();
269 cx.end_turtle_with_area(&mut self.area);
270 DrawStep::done()
271 }
272}
273
274impl SlidesView {
275 fn next_frame(&mut self, cx: &mut Cx) {
276 self.next_frame = cx.new_next_frame();
277 }
278
279 pub fn next_slide(&mut self, cx: &mut Cx) {
280 self.goal_slide += 1.0;
281 let max_goal_slide = (self.draw_order.len().max(1) - 1) as f64;
283 if self.goal_slide > max_goal_slide {
284 self.goal_slide = max_goal_slide
285 }
286 self.next_frame(cx);
287 }
288
289 pub fn prev_slide(&mut self, cx: &mut Cx) {
290 self.goal_slide -= 1.0;
291 if self.goal_slide < 0.0 {
292 self.goal_slide = 0.0;
293 }
294 self.next_frame(cx);
295 }
296
297 pub fn redraw(&mut self, cx: &mut Cx) {
298 self.area.redraw(cx);
299 }
300}
301
302impl SlidesViewRef {
303 pub fn flipped(&self, actions:&Actions)->Option<usize>{
304 if let SlidesViewAction::Flipped(m) = actions.find_widget_action(self.widget_uid()).cast_ref() {
305 Some(*m)
306 } else{
307 None
308 }
309 }
310
311
312 pub fn set_current_slide(&self, cx:&mut Cx, slide:usize){
313 if let Some(mut inner) = self.borrow_mut() {
314 inner.goal_slide = slide as f64;
315 inner.current_slide = slide as f64;
316 inner.redraw(cx);
317 }
318 }
319
320 pub fn set_goal_slide(&self, cx:&mut Cx, slide:usize){
321 if let Some(mut inner) = self.borrow_mut() {
322 inner.goal_slide = slide as f64;
323 inner.next_frame(cx);
324 }
325 }
326 pub fn get_slide(&self)->usize{
327 if let Some(inner) = self.borrow() {
328 return inner.current_slide as usize
329 }
330 0
331 }
332 pub fn next_slide(&self, cx: &mut Cx) {
333 if let Some(mut inner) = self.borrow_mut() {
334 inner.next_slide(cx);
335 }
336 }
337 pub fn prev_slide(&self, cx: &mut Cx) {
338 if let Some(mut inner) = self.borrow_mut() {
339 inner.prev_slide(cx);
340 }
341 }
342}
343
344impl SlidesViewSet {
345 pub fn next_slide(&self, cx: &mut Cx) {
346 for item in self.iter() {
347 item.next_slide(cx);
348 }
349 }
350 pub fn prev_slide(&self, cx: &mut Cx) {
351 for item in self.iter() {
352 item.prev_slide(cx);
353 }
354 }
355}