tuix_widgets/
scroll_container.rs

1use tuix_core::layout::GeometryChanged;
2
3use crate::common::*;
4
5// #[derive(Debug, Copy, Clone, PartialEq)]
6// pub enum ScrollEvent {
7//     Scroll(f32, f32, f32),
8// }
9
10
11#[derive(Debug, Default, Clone, Copy, PartialEq)]
12pub struct Scroll {
13    pub scroll_pos: f32,
14    pub scroll_size: f32,
15    pub overflow: f32,
16}
17
18// #[derive(Debug, Default, Lens, Clone, Copy)]
19// pub struct ScrollData {
20//     scroll: Scroll,
21// }
22
23// impl Model for ScrollData {
24//     fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
25//         if let Some(scroll_event) = event.message.downcast() {
26//             match scroll_event {
27
28//                 ScrollEvent::Scroll(pos, size, overflow) => {
29//                     self.scroll.scroll_pos = *pos;
30//                     self.scroll.scroll_size = *size;
31//                     self.scroll.overflow = *overflow;
32//                     entity.emit(state, BindEvent::Update);
33//                     event.consume();
34//                 }
35//             }
36//         }
37//     }
38// }
39
40pub struct ScrollContainerH {
41    container: Entity,
42    horizontal_scroll: Entity,
43    //vertical_scroll: Entity,
44    //scrolly: f32,
45    //scrollh: f32,
46
47    pub scroll: Scroll,
48
49    pressedx: f32,
50    pressedy: f32,
51    moving: bool,
52    position: f32,
53
54    vertical_scroll_animation: Animation,
55    vertical_container_animation: Animation,
56
57    scrollbar: bool,
58    scroll_wheel: bool,
59
60    on_scroll: Option<Box<dyn Fn(&mut Self, &mut State, Entity)>>,
61}
62
63impl ScrollContainerH {
64    pub fn new() -> Self {
65        ScrollContainerH {
66            container: Entity::null(),
67            horizontal_scroll: Entity::null(),
68            //vertical_scroll: Entity::null(),
69            //scrolly: 0.0,
70            //scrollh: 0.0,
71
72            scroll: Scroll::default(),
73
74            pressedx: 0.0,
75            pressedy: 0.0,
76            moving: false,
77            position: 0.0,
78
79            vertical_scroll_animation: Animation::default(),
80            vertical_container_animation: Animation::default(),
81
82            scrollbar: true,
83            scroll_wheel: true,
84
85            on_scroll: None,
86        }
87    }
88
89    // TODO
90    pub fn disable_scrollbar(mut self) -> Self {
91        self.scrollbar = false;
92
93        self
94    }
95
96    pub fn disable_scroll_wheel(mut self) -> Self {
97        self.scroll_wheel = false;
98
99        self
100    }
101
102    pub fn on_scroll<F>(mut self, callback: F) -> Self 
103    where F: 'static + Fn(&mut Self, &mut State, Entity)
104    {
105        self.on_scroll = Some(Box::new(callback));
106
107        self
108    }
109}
110
111impl Widget for ScrollContainerH {
112    type Ret = Entity;
113    type Data = Scroll;
114    fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
115        entity
116            .set_layout_type(state, LayoutType::Column)
117            .set_min_width(state, Pixels(0.0));
118
119        self.container = Element::new().build(state, entity, |builder| {
120            builder
121                //.set_position_type(PositionType::SelfDirected)
122                .set_width(Auto)
123                .set_height(Stretch(1.0))
124                // .set_left(Units::Percentage(0.0))
125                // .set_align_self(AlignSelf::FlexStart)
126                //.set_background_color(Color::rgb(200, 70, 70))
127                .class("container")
128            //.set_hoverable(false)
129        });
130
131        state.style.clip_widget.insert(self.container, entity);
132
133        //if self.scrollbar {
134            self.horizontal_scroll = Element::new().build(state, entity, |builder| {
135                builder
136                    //.set_position_type(PositionType::SelfDirected)
137                    .set_min_width(Pixels(0.0))
138                    // .set_left(Units::Percentage(0.0))
139                    //.set_height(Units::Pixels(10.0))
140                    // .set_width(Units::Percentage(0.0))
141                    // .set_align_self(AlignSelf::FlexStart)
142                    //.set_background_color(Color::rgb(70, 70, 200))
143                    //.set_right(Units::Pixels(0.0))
144                    .class("scrollbar")
145
146                //
147            });
148        //}
149
150        entity.set_disabled(state, true);
151
152        entity.set_element(state, "scroll_containerh");
153
154        let vertical_scroll_animation = AnimationState::new()
155            .with_duration(std::time::Duration::from_millis(100))
156            .with_keyframe((0.0, Units::Percentage(0.0)))
157            .with_keyframe((1.0, Units::Percentage(20.0)));
158
159        self.vertical_scroll_animation =
160            state.style.left.insert_animation(vertical_scroll_animation);
161
162        let vertical_container_animation = AnimationState::new()
163            .with_duration(std::time::Duration::from_millis(100))
164            .with_keyframe((0.0, Units::Percentage(0.0)))
165            .with_keyframe((1.0, Units::Percentage(-20.0)));
166
167        self.vertical_container_animation = state
168            .style
169            .left
170            .insert_animation(vertical_container_animation);
171
172        self.container
173    }
174
175    fn on_update(&mut self, state: &mut State, _entity: Entity, data: &Self::Data) {
176        //self.scroll.scroll_pos = data.scroll_pos;
177        //self.scroll.scroll_size = data.scroll_size;
178
179        self.scroll = *data;
180
181        // let overflow = 1.0
182        //     - (state.data.get_width(self.container)
183        //         / state.data.get_width(entity));
184        // let overflow2 = 1.0
185        //     - (state.data.get_width(entity)
186        //         / state.data.get_width(self.container));
187
188        let overflow2 = 1.0 - (1.0 / (1.0 - self.scroll.overflow));
189
190        self.container
191            .set_left(state, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0));
192        self.horizontal_scroll
193            .set_left(state, Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0));
194    }
195
196
197    fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
198        if let Some(window_event) = event.message.downcast::<WindowEvent>() {
199            match window_event {
200                WindowEvent::GeometryChanged(geometry_changed) => {
201                    if event.target == self.container || event.target == entity {
202                        if geometry_changed.contains(GeometryChanged::WIDTH_CHANGED) || geometry_changed.contains(GeometryChanged::HEIGHT_CHANGED) {
203                            self.scroll.scroll_size =
204                                state.data.get_width(entity) / state.data.get_width(self.container);
205
206                            if self.scroll.scroll_size >= 1.0 {
207                                self.scroll.scroll_size = 1.0;
208                                entity.set_disabled(state, true);
209                            }
210
211                            if self.scroll.scroll_size < 1.0 {
212                                entity.set_disabled(state, false);
213                            }
214
215                            if !state.style.left.is_animating(self.horizontal_scroll) {
216                                let dist = state.data.get_posx(self.horizontal_scroll)
217                                    - state.data.get_posx(entity);
218                                let space = state.data.get_width(entity)
219                                    - (self.scroll.scroll_size * state.data.get_width(entity));
220                                self.scroll.scroll_pos = dist / space;
221                            }
222
223                            if self.scroll.scroll_pos.is_nan() {
224                                self.scroll.scroll_pos = 0.0;
225                            }
226
227                            if self.scroll.scroll_pos < 0.0 {
228                                self.scroll.scroll_pos = 0.0;
229                            }
230
231                            if self.scroll.scroll_pos >= 1.0 {
232                                self.scroll.scroll_pos = 1.0;
233                            }
234
235                            // Setting it this way avoid calling Restyle automatically
236                            state
237                                .style
238                                .width
239                                .insert(self.horizontal_scroll, Units::Percentage(self.scroll.scroll_size * 100.0))
240                                .expect("");
241
242                            self.scroll.overflow = 1.0
243                                - (state.data.get_width(self.container)
244                                    / state.data.get_width(entity));
245                            let overflow2 = 1.0 - (1.0 / (1.0 - self.scroll.overflow));
246                            // let overflow2 = 1.0
247                            //     - (state.data.get_width(entity)
248                            //         / state.data.get_width(self.container));
249
250                            state
251                                .style
252                                .left
253                                .insert(self.container, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0))
254                                .expect("");
255
256                            state.style.left.insert(
257                                self.horizontal_scroll,
258                                Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0),
259                            ).expect("");
260
261                            state.insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()).origin(entity));
262                        
263
264                            if let Some(callback) = self.on_scroll.take() {
265                                (callback)(self, state, entity);
266
267                                self.on_scroll = Some(callback);
268                            }
269
270                            // state.insert_event(
271                            //     Event::new(ScrollEvent::Scroll(self.scroll.scroll_pos, self.scroll.scroll_size, overflow)).target(entity).origin(entity),
272                            // );  
273                        }
274                    }
275                }
276
277                WindowEvent::MouseScroll(x, _) => {
278                    if self.scroll_wheel {
279                        self.scroll.overflow = state.data.get_width(entity)
280                            - state.data.get_width(self.horizontal_scroll);
281
282                        if self.scroll.overflow == 0.0 {
283                            return;
284                        }
285
286                        // Need better names for these
287                        self.scroll.overflow = 1.0
288                            - (state.data.get_width(self.container) / state.data.get_width(entity));
289                        let overflow2 = 1.0
290                            - (state.data.get_width(entity) / state.data.get_width(self.container));
291
292                        self.scroll.scroll_pos += (30.0 * -*x) / (state.data.get_width(entity) * self.scroll.overflow);
293
294                        if self.scroll.scroll_pos < 0.0 {
295                            self.scroll.scroll_pos = 0.0;
296                        }
297
298                        if self.scroll.scroll_pos > 1.0 {
299                            self.scroll.scroll_pos = 1.0;
300                        }
301
302                        let _current_scroll_top = state
303                            .style
304                            .left
305                            .get(self.horizontal_scroll)
306                            .cloned()
307                            .unwrap_or_default();
308                        let _current_container_top = state
309                            .style
310                            .left
311                            .get(self.container)
312                            .cloned()
313                            .unwrap_or_default();
314
315                        self.container
316                            .set_left(state, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0));
317                        self.horizontal_scroll
318                            .set_left(state, Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0));
319
320
321                        if let Some(callback) = self.on_scroll.take() {
322                            (callback)(self, state, entity);
323
324                            self.on_scroll = Some(callback);
325                        }
326                        
327                        // state.insert_event(
328                        //     Event::new(ScrollEvent::Scroll(self.scroll.scroll_pos, self.scroll.scroll_size, overflow))
329                        //         .target(entity).origin(entity),
330                        // );
331
332                        // Capture the event to stop it triggering twice
333                        //event.consume();
334                    }
335                }
336
337                WindowEvent::WindowResize(_, _) => {
338                    // let scroll = state
339                    //     .style
340                    //     .scroll
341                    //     .get(self.container)
342                    //     .cloned()
343                    //     .unwrap_or_default();
344
345                    // event_manager.insert_event(
346                    //     Event::new(StyleEvent::Restyle).target(state.root),
347                    // );
348                }
349
350                WindowEvent::MouseDown(button) => match button {
351                    MouseButton::Left => {
352                        if state.hovered == self.horizontal_scroll {
353                            //println!("Clicked on scrollbar");
354                            self.pressedx = state.mouse.cursorx;
355                            self.pressedy = state.mouse.cursory;
356                            self.moving = true;
357                            // let scroll = state
358                            //     .style
359                            //     .scroll
360                            //     .get(self.entity)
361                            //     .cloned()
362                            //     .unwrap_or_default();
363                            //self.position = state.data.get_posy(self.vertical_scroll);
364                            self.position = self.scroll.scroll_pos;
365                            state.capture(entity);
366                        }
367                    }
368                    _ => {}
369                },
370
371                WindowEvent::MouseUp(button) => match button {
372                    MouseButton::Left => {
373                        self.moving = false;
374                        state.release(entity);
375                    }
376
377                    _ => {}
378                },
379
380                WindowEvent::MouseMove(x, _) => {
381                    if self.moving {
382                        let dist_x = *x - self.pressedx;
383                        let scroll_bar_overflow = state.data.get_width(entity)
384                            - state.data.get_width(self.horizontal_scroll);
385
386                        if scroll_bar_overflow == 0.0 {
387                            return;
388                        }
389
390                        let ratio = dist_x / scroll_bar_overflow;
391                        let r = self.position + ratio;
392
393                        // let mut scrollh = state.data.get_height(entity) / state.data.get_height(self.container);
394                        // if scrollh > 1.0 {
395                        //     scrollh = 1.0;
396                        // }
397
398                        self.scroll.scroll_pos = r;
399
400                        if self.scroll.scroll_pos < 0.0 {
401                            self.scroll.scroll_pos = 0.0;
402                        }
403
404                        if self.scroll.scroll_pos > 1.0 {
405                            self.scroll.scroll_pos = 1.0;
406                        }
407
408                        // let scroll = state
409                        //     .style
410                        //     .scroll
411                        //     .get(self.entity)
412                        //     .cloned()
413                        //     .unwrap_or_default();
414                        //self.vertical_scroll
415                        //    .set_top(state, Units::Pixels(self.position + dist_y));
416
417                        self.scroll.overflow = 1.0
418                            - (state.data.get_width(self.container) / state.data.get_width(entity));
419                        let overflow2 = 1.0
420                            - (state.data.get_width(entity) / state.data.get_width(self.container));
421
422                        self.container
423                            .set_left(state, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0));
424                        self.horizontal_scroll
425                            .set_left(state, Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0));
426
427
428                        if let Some(callback) = self.on_scroll.take() {
429                            (callback)(self, state, entity);
430
431                            self.on_scroll = Some(callback);
432                        }
433
434                        // state.insert_event(
435                        //     Event::new(ScrollEvent::Scroll(self.scroll.scroll_pos, self.scroll.scroll_size, overflow))
436                        //         .target(entity).origin(entity),
437                        // );
438
439                        state.insert_event(Event::new(WindowEvent::Restyle));
440                        state
441                            .insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
442                        state.insert_event(Event::new(WindowEvent::Redraw));
443                        //println!("overflow: {}, dist: {}, ratio: {}, scrolly: {}", overflow, dist_y, r, self.scroll.scroll_pos);
444                    }
445                }
446
447                _ => {}
448            }
449        }
450    }
451}
452
453pub struct ScrollContainer {
454    container: Entity,
455    vertical_scroll: Entity,
456    pub scroll: Scroll,
457
458    scrollbar: bool,
459
460    pressedx: f32,
461    pressedy: f32,
462    moving: bool,
463    position: f32,
464
465    vertical_scroll_animation: Animation,
466    vertical_container_animation: Animation,
467
468    on_scroll: Option<Box<dyn Fn(&mut Self, &mut State, Entity)>>,
469}
470
471impl ScrollContainer {
472    /// Create a new ScrollContainer widget
473    pub fn new() -> Self {
474        ScrollContainer {
475            container: Entity::null(),
476            vertical_scroll: Entity::null(),
477            scroll: Scroll::default(),
478
479            scrollbar: true,
480
481            pressedx: 0.0,
482            pressedy: 0.0,
483            moving: false,
484            position: 0.0,
485
486            vertical_scroll_animation: Animation::default(),
487            vertical_container_animation: Animation::default(),
488
489            on_scroll: None,
490        }
491    }
492
493    pub fn disable_scrollbar(mut self) -> Self {
494        self.scrollbar = false;
495
496        self
497    }
498
499    pub fn on_scroll<F>(mut self, callback: F) -> Self 
500    where F: 'static + Fn(&mut Self, &mut State, Entity)
501    {
502        self.on_scroll = Some(Box::new(callback));
503
504        self
505    }
506}
507
508impl Widget for ScrollContainer {
509    type Ret = Entity;
510    type Data = Scroll;
511    fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
512        entity
513            .set_layout_type(state, LayoutType::Row)
514            .set_min_height(state, Pixels(0.0));
515
516        self.container = Element::new().build(state, entity, |builder| {
517            builder
518                //.set_position_type(PositionType::SelfDirected)
519                .set_height(Auto)
520                .set_width(Stretch(1.0))
521                //.set_top(Units::Percentage(0.0))
522                //.set_flex_grow(1.0)
523                //.set_align_self(AlignSelf::FlexStart)
524                .class("container")
525        });
526
527        state.style.clip_widget.insert(self.container, entity);
528
529        self.vertical_scroll = Element::new().build(state, entity, |builder| {
530            builder
531                //.set_position_type(PositionType::SelfDirected)
532                .set_min_height(Pixels(0.0))
533                //.set_top(Units::Percentage(0.0))
534                // .set_width(Units::Pixels(10.0))
535                //.set_height(Units::Percentage(0.0))
536                //.set_align_self(AlignSelf::FlexStart)
537                //.set_background_color(Color::rgb(70, 200, 70))
538                //.set_right(Units::Pixels(0.0))
539                .class("scrollbar")
540
541            //
542        });
543
544        entity.set_disabled(state, true);
545        // self.vertical_scroll =
546        //     Scrollbar::new(self.container, Direction::Vertical).build(state, entity, |builder| {
547        //         builder
548        //             .set_width(Units::Pixels(10.0))
549        //             .set_height(Units::Percentage(1.0))
550        //             .set_background_color(Color::rgb(50, 50, 100))
551        //     });
552
553        entity.set_element(state, "scroll_container");
554
555        let vertical_scroll_animation = AnimationState::new()
556            .with_duration(std::time::Duration::from_millis(100))
557            .with_keyframe((0.0, Units::Percentage(0.0)))
558            .with_keyframe((1.0, Units::Percentage(20.0)));
559
560        self.vertical_scroll_animation =
561            state.style.top.insert_animation(vertical_scroll_animation);
562
563        let vertical_container_animation = AnimationState::new()
564            .with_duration(std::time::Duration::from_millis(100))
565            .with_keyframe((0.0, Units::Percentage(0.0)))
566            .with_keyframe((1.0, Units::Percentage(-20.0)));
567
568        self.vertical_container_animation = state
569            .style
570            .top
571            .insert_animation(vertical_container_animation);
572
573        self.container
574    }
575
576    fn on_update(&mut self, state: &mut State, entity: Entity, data: &Self::Data) {
577        self.scroll = *data;
578
579        
580        let overflow2 = 1.0
581            - (state.data.get_height(entity)
582                / state.data.get_height(self.container));
583
584        self.container
585            .set_top(state, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0));
586        self.vertical_scroll
587            .set_top(state, Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0));
588    }
589
590    fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
591        if let Some(window_event) = event.message.downcast::<WindowEvent>() {
592            match window_event {
593                WindowEvent::GeometryChanged(geometry_changed) => {
594                    if event.target == self.container || event.target == entity {
595                        if geometry_changed.contains(GeometryChanged::WIDTH_CHANGED) || geometry_changed.contains(GeometryChanged::HEIGHT_CHANGED) {
596                            self.scroll.scroll_size = state.data.get_height(entity)
597                                / state.data.get_height(self.container);
598
599                            if self.scroll.scroll_size >= 1.0 {
600                                self.scroll.scroll_size = 1.0;
601                                entity.set_disabled(state, true);
602                            }
603
604                            if self.scroll.scroll_size < 1.0 {
605                                entity.set_disabled(state, false);
606                            }
607
608                            if !state.style.top.is_animating(self.vertical_scroll) {
609                                let dist = state.data.get_posy(self.vertical_scroll)
610                                    - state.data.get_posy(entity);
611                                let space = state.data.get_height(entity)
612                                    - (self.scroll.scroll_size * state.data.get_height(entity));
613                                self.scroll.scroll_pos = dist / space;
614                            }
615
616                            if self.scroll.scroll_pos.is_nan() {
617                                self.scroll.scroll_pos = 0.0;
618                            }
619
620                            if self.scroll.scroll_pos < 0.0 {
621                                self.scroll.scroll_pos = 0.0;
622                            }
623
624                            if self.scroll.scroll_pos >= 1.0 {
625                                self.scroll.scroll_pos = 1.0;
626                            }
627
628                            // Setting it this way avoid calling Restyle automatically
629                            state
630                                .style
631                                .height
632                                .insert(self.vertical_scroll, Units::Percentage(self.scroll.scroll_size * 100.0))
633                                .expect("");
634
635                            self.scroll.overflow = 1.0
636                                - (state.data.get_height(self.container)
637                                    / state.data.get_height(entity));
638                            let overflow2 = 1.0
639                                - (state.data.get_height(entity)
640                                    / state.data.get_height(self.container));
641
642                            state
643                                .style
644                                .top
645                                .insert(self.container, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0)).expect("Failed to set top position of container");
646
647                            state.style.top.insert(
648                                self.vertical_scroll,
649                                Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0),
650                            ).expect("Failed to set top position of vertical scroll bar.");
651
652                            state.insert_event(
653                                Event::new(WindowEvent::Relayout)
654                                    .target(Entity::root())
655                                    .origin(entity),
656                            );
657
658                            if let Some(callback) = self.on_scroll.take() {
659                                (callback)(self, state, entity);
660
661                                self.on_scroll = Some(callback);
662                            }
663
664                            // state.insert_event(
665                            //     Event::new(ScrollEvent::Scroll(self.scroll.scroll_pos, self.scroll.scroll_size, overflow)).target(entity).origin(entity),
666                            // );        
667                        }
668                    }
669                }
670
671                WindowEvent::MouseScroll(_, y) => {
672
673                    self.scroll.overflow =
674                        state.data.get_height(entity) - state.data.get_height(self.vertical_scroll);
675
676                    if self.scroll.overflow == 0.0 {
677                        return;
678                    }
679
680                    // Need better names for these
681                    self.scroll.overflow = 1.0
682                        - (state.data.get_height(self.container) / state.data.get_height(entity));
683                    let overflow2 = 1.0
684                        - (state.data.get_height(entity) / state.data.get_height(self.container));
685
686                    // TODO - Need a way to configure this
687                    self.scroll.scroll_pos += (30.0 * *y) / (state.data.get_height(entity) * self.scroll.overflow);
688
689                    if self.scroll.scroll_pos < 0.0 {
690                        self.scroll.scroll_pos = 0.0;
691                    }
692
693                    if self.scroll.scroll_pos > 1.0 {
694                        self.scroll.scroll_pos = 1.0;
695                    }
696
697                    self.container
698                        .set_top(state, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0));
699                    self.vertical_scroll
700                        .set_top(state, Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0));
701
702                    if let Some(callback) = self.on_scroll.take() {
703                        (callback)(self, state, entity);
704
705                        self.on_scroll = Some(callback);
706                    }
707
708                    // state.insert_event(
709                    //     Event::new(ScrollEvent::Scroll(self.scroll.scroll_pos, self.scroll.scroll_size, overflow)).target(entity).origin(entity),
710                    // );
711
712                    //event.consume();
713                }
714
715                WindowEvent::WindowResize(_, _) => {
716                    // let scroll = state
717                    //     .style
718                    //     .scroll
719                    //     .get(self.container)
720                    //     .cloned()
721                    //     .unwrap_or_default();
722
723                    // event_manager.insert_event(
724                    //     Event::new(StyleEvent::Restyle).target(state.root),
725                    // );
726                }
727
728                WindowEvent::MouseDown(button) => match button {
729                    MouseButton::Left => {
730                        if state.hovered == self.vertical_scroll {
731                            //println!("Clicked on scrollbar");
732                            self.pressedx = state.mouse.cursorx;
733                            self.pressedy = state.mouse.cursory;
734                            self.moving = true;
735                            // let scroll = state
736                            //     .style
737                            //     .scroll
738                            //     .get(self.entity)
739                            //     .cloned()
740                            //     .unwrap_or_default();
741                            //self.position = state.data.get_posy(self.vertical_scroll);
742                            self.position = self.scroll.scroll_pos;
743                            state.capture(entity);
744                        }
745                    }
746                    _ => {}
747                },
748
749                WindowEvent::MouseUp(button) => match button {
750                    MouseButton::Left => {
751                        self.moving = false;
752                        state.release(entity);
753                    }
754
755                    _ => {}
756                },
757
758                WindowEvent::MouseMove(_, y) => {
759                    if self.moving {
760                        let dist_y = *y - self.pressedy;
761                        let scroll_bar_overflow = state.data.get_height(entity)
762                            - state.data.get_height(self.vertical_scroll);
763
764                        if scroll_bar_overflow == 0.0 {
765                            return;
766                        }
767
768                        let ratio = dist_y / scroll_bar_overflow;
769                        let r = self.position + ratio;
770
771                        // let mut scrollh = state.data.get_height(entity) / state.data.get_height(self.container);
772                        // if scrollh > 1.0 {
773                        //     scrollh = 1.0;
774                        // }
775
776                        self.scroll.scroll_pos = r;
777
778                        if self.scroll.scroll_pos < 0.0 {
779                            self.scroll.scroll_pos = 0.0;
780                        }
781
782                        if self.scroll.scroll_pos > 1.0 {
783                            self.scroll.scroll_pos = 1.0;
784                        }
785
786                        // let scroll = state
787                        //     .style
788                        //     .scroll
789                        //     .get(self.entity)
790                        //     .cloned()
791                        //     .unwrap_or_default();
792                        //self.vertical_scroll
793                        //    .set_top(state, Units::Pixels(self.position + dist_y));
794
795                        self.scroll.overflow = 1.0
796                            - (state.data.get_height(self.container)
797                                / state.data.get_height(entity));
798                        let overflow2 = 1.0
799                            - (state.data.get_height(entity)
800                                / state.data.get_height(self.container));
801
802                        self.container
803                            .set_top(state, Units::Percentage(self.scroll.scroll_pos * self.scroll.overflow * 100.0));
804                        self.vertical_scroll
805                            .set_top(state, Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0));
806
807                        if let Some(callback) = self.on_scroll.take() {
808                            (callback)(self, state, entity);
809
810                            self.on_scroll = Some(callback);
811                        }
812
813                        // state.insert_event(
814                        //     Event::new(ScrollEvent::Scroll(self.scroll.scroll_pos, self.scroll.scroll_size, overflow))
815                        //         .target(entity).origin(entity),
816                        // );
817
818                        state.insert_event(Event::new(WindowEvent::Restyle));
819                        state
820                            .insert_event(Event::new(WindowEvent::Relayout).target(Entity::root()));
821                        state.insert_event(Event::new(WindowEvent::Redraw));
822                        //println!("overflow: {}, dist: {}, ratio: {}, scrolly: {}", overflow, dist_y, r, self.scroll.scroll_pos);
823                    }
824                }
825
826                _ => {}
827            }
828        }
829    }
830}
831
832//
833/*
834pub struct ScrollContainerHV {
835    container: Entity,
836    horizontal_scroll: Entity,
837    vertical_scroll: Entity,
838    scrollx: f32,
839    scrolly: f32,
840
841    pressedx: f32,
842    pressedy: f32,
843    moving: bool,
844    position: f32,
845    //vertical_scroll_animation: usize,
846    //vertical_container_animation: usize,
847}
848
849impl ScrollContainerHV {
850    pub fn new() -> Self {
851        ScrollContainerHV {
852            container: Entity::null(),
853            horizontal_scroll: Entity::null(),
854            vertical_scroll: Entity::null(),
855            scrollx: 0.0,
856            scrolly: 0.0,
857
858            pressedx: 0.0,
859            pressedy: 0.0,
860            moving: false,
861            position: 0.0,
862            //vertical_scroll_animation: std::usize::MAX,
863            //vertical_container_animation: std::usize::MAX,
864        }
865    }
866}
867
868impl Widget for ScrollContainerHV {
869    type Ret = Entity;
870    type Data = ();
871    fn on_build(&mut self, state: &mut State, entity: Entity) -> Self::Ret {
872        entity.set_layout_type(state, LayoutType::Row);
873
874        let row = Row::new().build(state, entity, |builder| builder);
875
876        let column = Column::new().build(state, row, |builder| builder);
877
878        self.container = Element::new().build(state, column, |builder| {
879            builder
880                .set_top(Units::Percentage(0.0))
881                //.set_align_self(AlignSelf::FlexStart)
882                .class("container")
883        });
884
885        state.style.clip_widget.insert(self.container, entity);
886
887        //println!("Container: {}", self.container);
888
889        self.vertical_scroll = Element::new().build(state, row, |builder| {
890            builder
891                //.set_position(Position::Absolute)
892                .set_top(Units::Percentage(0.0))
893                .set_width(Units::Pixels(10.0))
894                .set_height(Units::Percentage(100.0))
895            //.set_align_self(AlignSelf::FlexStart)
896            //.set_background_color(Color::rgb(70, 200, 70))
897            //.set_right(Units::Pixels(0.0))
898            //.class("scrollbar")
899
900            //
901        });
902
903        self.vertical_scroll = Element::new().build(state, row, |builder| {
904            builder
905                //.set_position(Position::Absolute)
906                .set_left(Units::Percentage(0.0))
907                .set_height(Units::Pixels(10.0))
908                .set_width(Units::Percentage(100.0))
909            //.set_align_self(AlignSelf::FlexStart)
910            //.set_background_color(Color::rgb(20, 70, 200))
911            //.set_right(Units::Pixels(0.0))
912            //.class("scrollbar")
913
914            //
915        });
916
917        //self.vertical_scroll.set_disabled(state, true);
918
919        // self.vertical_scroll =
920        //     Scrollbar::new(self.container, Direction::Vertical).build(state, entity, |builder| {
921        //         builder
922        //             .set_width(Units::Pixels(10.0))
923        //             .set_height(Units::Percentage(1.0))
924        //             .set_background_color(Color::rgb(50, 50, 100))
925        //     });
926
927        entity.set_element(state, "scroll_containerhv");
928
929        self.container
930    }
931
932    fn on_event(&mut self, state: &mut State, entity: Entity, event: &mut Event) {
933        if let Some(window_event) = event.message.downcast::<WindowEvent>() {
934            match window_event {
935                WindowEvent::Relayout => {
936                    // // To prevent recursive loop when layout event is triggered inside here
937                    if event.origin != entity
938                        && event.origin != self.container
939                        && event.origin != self.vertical_scroll
940                    {
941                        let mut scrollv =
942                            state.data.get_height(entity) / state.data.get_height(self.container);
943
944                        if scrollv >= 1.0 {
945                            scrollv = 1.0;
946                            self.vertical_scroll.set_disabled(state, true);
947                        }
948
949                        if scrollv < 1.0 {
950                            self.vertical_scroll.set_disabled(state, false);
951                        }
952
953                        let mut scrollh =
954                            state.data.get_width(entity) / state.data.get_width(self.container);
955
956                        if scrollh >= 1.0 {
957                            scrollh = 1.0;
958                            self.horizontal_scroll.set_disabled(state, true);
959                        }
960
961                        if scrollh < 1.0 {
962                            self.horizontal_scroll.set_disabled(state, false);
963                        }
964
965                        // BUG: fast scrolling causes smaller scroll because the animation hasn't finished when this function is called again
966                        // One way to fix this might be to check whether the value is currently being animated before setting here
967                        // Possibly not the best solution but it works
968                        // if !state.style.top.is_animating(self.vertical_scroll) {
969                        //     let dist = state.data.get_posy(self.vertical_scroll)
970                        //         - state.data.get_posy(entity);
971                        //     let space = state.data.get_height(entity)
972                        //         - (scrollh * state.data.get_height(entity));
973                        //     self.scroll.scroll_pos = dist / space;
974                        // }
975
976                        if self.scroll.scroll_pos.is_nan() {
977                            self.scroll.scroll_pos = 0.0;
978                        }
979
980                        if self.scroll.scroll_pos < 0.0 {
981                            self.scroll.scroll_pos = 0.0;
982                        }
983
984                        if self.scroll.scroll_pos >= 1.0 {
985                            self.scroll.scroll_pos = 1.0;
986                        }
987
988                        // Setting it this way avoid calling Restyle automatically
989                        state
990                            .style
991                            .height
992                            .insert(self.vertical_scroll, Units::Percentage(scrollv * 100.0));
993
994                        let overflow = 1.0
995                            - (state.data.get_height(self.container)
996                                / state.data.get_height(entity));
997                        let overflow2 = 1.0
998                            - (state.data.get_height(entity)
999                                / state.data.get_height(self.container));
1000
1001                        state
1002                            .style
1003                            .top
1004                            .insert(self.container, Units::Percentage(self.scroll.scroll_pos * overflow * 100.0));
1005
1006                        state.style.top.insert(
1007                            self.vertical_scroll,
1008                            Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0),
1009                        );
1010
1011                        if self.scrollx.is_nan() {
1012                            self.scrollx = 0.0;
1013                        }
1014
1015                        if self.scrollx < 0.0 {
1016                            self.scrollx = 0.0;
1017                        }
1018
1019                        if self.scrollx >= 1.0 {
1020                            self.scrollx = 1.0;
1021                        }
1022
1023                        // Setting it this way avoid calling Restyle automatically
1024                        state
1025                            .style
1026                            .width
1027                            .insert(self.vertical_scroll, Units::Percentage(scrollh * 100.0));
1028
1029                        let overflow = 1.0
1030                            - (state.data.get_width(self.container) / state.data.get_width(entity));
1031                        let overflow2 = 1.0
1032                            - (state.data.get_width(entity) / state.data.get_width(self.container));
1033
1034                        state
1035                            .style
1036                            .left
1037                            .insert(self.container, Units::Percentage(self.scrollx * overflow * 100.0));
1038
1039                        state.style.top.insert(
1040                            self.vertical_scroll,
1041                            Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0),
1042                        );
1043
1044                        // Relayout and Redraw wont get called automatically so need to manually trigger them
1045                        state.insert_event(Event::new(WindowEvent::Relayout).origin(entity));
1046                        //state.insert_event(Event::new(WindowEvent::Redraw));
1047                        //return true;
1048                    }
1049                }
1050
1051                /*
1052                WindowEvent::MouseScroll(_, y) => {
1053                    println!("Mouse Scroll Event");
1054                    // Forward mouse scroll event to the scrollbar
1055                    // state.insert_event(
1056                    //     Event::new(WindowEvent::MouseScroll(*x, *y))
1057                    //         .target(self.vertical_scroll)
1058                    //         .propagate(Propagation::None),
1059                    // );
1060
1061                    //if event.target == entity {
1062
1063                    println!("Height: {}", state.data.get_height(entity));
1064
1065                    let overflow = state.data.get_height(entity)
1066                        - state.data.get_height(self.vertical_scroll);
1067
1068                    if overflow == 0.0 {
1069                        return false;
1070                    }
1071
1072                    // Need better names for these
1073                    let overflow = 1.0
1074                        - (state.data.get_height(self.container)
1075                            / state.data.get_height(entity));
1076                    let overflow2 = 1.0
1077                        - (state.data.get_height(entity)
1078                            / state.data.get_height(self.container));
1079
1080                    self.scroll.scroll_pos += (40.0 * *y) / (state.data.get_height(entity) * overflow);
1081
1082                    if self.scroll.scroll_pos < 0.0 {
1083                        self.scroll.scroll_pos = 0.0;
1084                    }
1085
1086                    if self.scroll.scroll_pos > 1.0 {
1087                        self.scroll.scroll_pos = 1.0;
1088                    }
1089
1090                    //println!("Scroll: {}", self.scroll.scroll_pos);
1091
1092                    // let mut scrollh = state.data.get_height(entity) / state.data.get_height(self.container);
1093                    // if scrollh > 1.0 {
1094                    //     scrollh = 1.0;
1095                    // }
1096
1097                    let current_scroll_top = state
1098                        .style
1099                        .top
1100                        .get(self.vertical_scroll)
1101                        .cloned()
1102                        .unwrap_or_default();
1103                    let current_container_top = state
1104                        .style
1105                        .top
1106                        .get(self.container)
1107                        .cloned()
1108                        .unwrap_or_default();
1109
1110                    self.container
1111                        .set_top(state, Units::Percentage(self.scroll.scroll_pos * overflow));
1112                    self.vertical_scroll
1113                        .set_top(state, Units::Percentage(self.scroll.scroll_pos * overflow2));
1114
1115                    /*
1116                    if let Some(animation) = state.style.top.get_animation_mut(self.vertical_scroll_animation) {
1117                        *animation.keyframes.first_mut().unwrap() = (0.0, current_scroll_top);
1118                        *animation.keyframes.last_mut().unwrap() = (1.0, Units::Percentage(self.scroll.scroll_pos * overflow2));
1119                    }
1120
1121                    state.style.top.play_animation(self.vertical_scroll, self.vertical_scroll_animation);
1122
1123
1124
1125
1126
1127                    if let Some(animation) = state.style.top.get_animation_mut(self.vertical_container_animation) {
1128                        *animation.keyframes.first_mut().unwrap() = (0.0, current_container_top);
1129                        *animation.keyframes.last_mut().unwrap() = (1.0, Units::Percentage(self.scroll.scroll_pos * overflow));
1130                    }
1131
1132                    state.style.top.play_animation(self.container, self.vertical_container_animation);
1133                    */
1134
1135                    //println!("A: {:?}  B: {:?}", current_container_top, self.scroll.scroll_pos * overflow);
1136
1137                    //state.insert_event(Event::new(WindowEvent::Relayout).target(Entity::null()));
1138                    //state.insert_event(Event::new(WindowEvent::Redraw));
1139                    //}
1140
1141                    // Capture the event to stop it triggering twice
1142                    return true;
1143                }
1144                */
1145                WindowEvent::MouseDown(button) => match button {
1146                    MouseButton::Left => {
1147                        if state.hovered == self.vertical_scroll {
1148                            //println!("Clicked on scrollbar");
1149                            self.pressedx = state.mouse.cursorx;
1150                            self.pressedy = state.mouse.cursory;
1151                            self.moving = true;
1152                            // let scroll = state
1153                            //     .style
1154                            //     .scroll
1155                            //     .get(self.entity)
1156                            //     .cloned()
1157                            //     .unwrap_or_default();
1158                            //self.position = state.data.get_posy(self.vertical_scroll);
1159                            self.position = self.scroll.scroll_pos;
1160                            state.capture(entity);
1161                        }
1162
1163                        if state.hovered == self.horizontal_scroll {
1164                            //println!("Clicked on scrollbar");
1165                            self.pressedx = state.mouse.cursorx;
1166                            self.pressedy = state.mouse.cursory;
1167                            self.moving = true;
1168                            // let scroll = state
1169                            //     .style
1170                            //     .scroll
1171                            //     .get(self.entity)
1172                            //     .cloned()
1173                            //     .unwrap_or_default();
1174                            //self.position = state.data.get_posy(self.vertical_scroll);
1175                            self.position = self.scrollx;
1176                            state.capture(entity);
1177                        }
1178                    }
1179                    _ => {}
1180                },
1181
1182                WindowEvent::MouseUp(button) => match button {
1183                    MouseButton::Left => {
1184                        self.moving = false;
1185                        //println!("Scroll release");
1186                        state.release(entity);
1187                    }
1188
1189                    _ => {}
1190                },
1191
1192                WindowEvent::MouseMove(x, y) => {
1193                    if self.moving && state.captured == self.vertical_scroll {
1194                        let dist_y = *y - self.pressedy;
1195                        let overflow = state.data.get_height(entity)
1196                            - state.data.get_height(self.vertical_scroll);
1197
1198                        if overflow == 0.0 {
1199                            return;
1200                        }
1201
1202                        let ratio = dist_y / overflow;
1203                        let r = self.position + ratio;
1204
1205                        // let mut scrollh = state.data.get_height(entity) / state.data.get_height(self.container);
1206                        // if scrollh > 1.0 {
1207                        //     scrollh = 1.0;
1208                        // }
1209
1210                        self.scroll.scroll_pos = r;
1211
1212                        if self.scroll.scroll_pos < 0.0 {
1213                            self.scroll.scroll_pos = 0.0;
1214                        }
1215
1216                        if self.scroll.scroll_pos > 1.0 {
1217                            self.scroll.scroll_pos = 1.0;
1218                        }
1219
1220                        // let scroll = state
1221                        //     .style
1222                        //     .scroll
1223                        //     .get(self.entity)
1224                        //     .cloned()
1225                        //     .unwrap_or_default();
1226                        //self.vertical_scroll
1227                        //    .set_top(state, Units::Pixels(self.position + dist_y));
1228
1229                        let overflow = 1.0
1230                            - (state.data.get_height(self.container)
1231                                / state.data.get_height(entity));
1232                        let overflow2 = 1.0
1233                            - (state.data.get_height(entity)
1234                                / state.data.get_height(self.container));
1235
1236                        self.container
1237                            .set_top(state, Units::Percentage(self.scroll.scroll_pos * overflow * 100.0));
1238                        self.vertical_scroll
1239                            .set_top(state, Units::Percentage(self.scroll.scroll_pos * overflow2 * 100.0));
1240
1241                        state.insert_event(Event::new(WindowEvent::Restyle));
1242                        state
1243                            .insert_event(Event::new(WindowEvent::Relayout).target(Entity::null()));
1244                        state.insert_event(Event::new(WindowEvent::Redraw));
1245                        //println!("overflow: {}, dist: {}, ratio: {}, scrolly: {}", overflow, dist_y, r, self.scroll.scroll_pos);
1246                    }
1247
1248                    if self.moving && state.captured == self.horizontal_scroll {
1249                        let dist_x = *x - self.pressedx;
1250                        let overflow = state.data.get_width(entity)
1251                            - state.data.get_width(self.vertical_scroll);
1252
1253                        if overflow == 0.0 {
1254                            return;
1255                        }
1256
1257                        let ratio = dist_x / overflow;
1258                        let r = self.position + ratio;
1259
1260                        // let mut scrollh = state.data.get_height(entity) / state.data.get_height(self.container);
1261                        // if scrollh > 1.0 {
1262                        //     scrollh = 1.0;
1263                        // }
1264
1265                        self.scrollx = r;
1266
1267                        if self.scrollx < 0.0 {
1268                            self.scrollx = 0.0;
1269                        }
1270
1271                        if self.scrollx > 1.0 {
1272                            self.scrollx = 1.0;
1273                        }
1274
1275                        // let scroll = state
1276                        //     .style
1277                        //     .scroll
1278                        //     .get(self.entity)
1279                        //     .cloned()
1280                        //     .unwrap_or_default();
1281                        //self.vertical_scroll
1282                        //    .set_top(state, Units::Pixels(self.position + dist_y));
1283
1284                        let overflow = 1.0
1285                            - (state.data.get_width(self.container) / state.data.get_width(entity));
1286                        let overflow2 = 1.0
1287                            - (state.data.get_width(entity) / state.data.get_width(self.container));
1288
1289                        self.container
1290                            .set_left(state, Units::Percentage(self.scrollx * overflow * 100.0));
1291                        self.vertical_scroll
1292                            .set_left(state, Units::Percentage(self.scrollx * overflow2 * 100.0));
1293
1294                        state.insert_event(Event::new(WindowEvent::Restyle));
1295                        state
1296                            .insert_event(Event::new(WindowEvent::Relayout).target(Entity::null()));
1297                        state.insert_event(Event::new(WindowEvent::Redraw));
1298                        //println!("overflow: {}, dist: {}, ratio: {}, scrolly: {}", overflow, dist_y, r, self.scroll.scroll_pos);
1299                    }
1300                }
1301
1302                _ => {}
1303            }
1304        }
1305    }
1306}
1307*/