1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
use std::cell::RefCell;
use std::rc::Rc;

use fui_core::*;
use fui_macros::ui;
use typed_builder::TypedBuilder;
use typemap::TypeMap;

use crate::controls::border::Border;
use crate::controls::scroll_area::{ScrollArea, ViewportInfo};
use crate::controls::scroll_bar::ScrollBar;

pub enum ScrollBarVisibility {
    Disabled,
    Auto,
    Hidden,
    Visible,
}

#[derive(TypedBuilder)]
pub struct ScrollViewer {
    #[builder(default = ScrollBarVisibility::Auto)]
    pub horizontal_scroll_bar_visibility: ScrollBarVisibility,

    #[builder(default = ScrollBarVisibility::Auto)]
    pub vertical_scroll_bar_visibility: ScrollBarVisibility,
}

impl ScrollViewer {
    pub fn to_view(
        self,
        _style: Option<Box<dyn Style<Self>>>,
        context: ViewContext,
    ) -> Rc<RefCell<dyn ControlObject>> {
        let offset_x_prop = Property::new(0.0f32);
        let offset_y_prop = Property::new(0.0f32);

        let viewport_info_prop_src = Property::new(ViewportInfo::default());

        let viewport_width_prop =
            Property::binded_c_from(&viewport_info_prop_src, |info: ViewportInfo| {
                info.viewport_width
            });
        let viewport_height_prop =
            Property::binded_c_from(&viewport_info_prop_src, |info: ViewportInfo| {
                info.viewport_height
            });
        let max_offset_x_prop =
            Property::binded_c_from(&viewport_info_prop_src, |info: ViewportInfo| {
                (info.content_width - info.viewport_width).max(0.0f32)
            });
        let max_offset_y_prop =
            Property::binded_c_from(&viewport_info_prop_src, |info: ViewportInfo| {
                (info.content_height - info.viewport_height).max(0.0f32)
            });

        let horizontal_scrollbar_visible_prop =
            Property::binded_c_from(&viewport_info_prop_src, |info: ViewportInfo| {
                info.content_width > info.viewport_width
            });

        let vertical_scrollbar_visible_prop =
            Property::binded_c_from(&viewport_info_prop_src, |info: ViewportInfo| {
                info.content_height > info.viewport_height
            });

        let view = ui! {
            Grid {
                columns: 2,
                widths: vec![(0, Length::Fill(1.0f32)), (1, Length::Auto)],
                heights: vec![(0, Length::Fill(1.0f32)), (1, Length::Auto)],

                Border {
                    ScrollArea {
                        offset_x: offset_x_prop.clone(),
                        offset_y: offset_y_prop.clone(),
                        viewport_info: viewport_info_prop_src,

                        context.children,
                    },
                },

                ScrollBar {
                    Visible: vertical_scrollbar_visible_prop,
                    orientation: Orientation::Vertical,
                    value: offset_y_prop,
                    max_value: max_offset_y_prop,
                    viewport_size: viewport_height_prop,
                    single_step_size: 70.0f32,
                },

                ScrollBar {
                    Visible: horizontal_scrollbar_visible_prop,
                    orientation: Orientation::Horizontal,
                    value: offset_x_prop,
                    max_value: max_offset_x_prop,
                    viewport_size: viewport_width_prop,
                    single_step_size: 70.0f32,
                },
            }
        };

        view.borrow_mut()
            .get_context_mut()
            .set_attached_values(context.attached_values);

        view
    }
}