Skip to main content

winio_ui_winui/widgets/
scroll_view.rs

1use inherit_methods_macro::inherit_methods;
2use windows::core::Interface;
3use winio_handle::{AsContainer, BorrowedContainer};
4use winio_primitive::{Point, Rect, Size};
5use winui3::Microsoft::UI::Xaml::{
6    Controls as MUXC, FrameworkElement, HorizontalAlignment, RoutedEventHandler, VerticalAlignment,
7};
8
9use crate::{Result, Widget, widgets::Convertible};
10
11#[derive(Debug)]
12pub struct ScrollView {
13    handle: Widget,
14    view: MUXC::ScrollViewer,
15    canvas: MUXC::Canvas,
16}
17
18fn set_canvas_to_fit_children(canvas: &MUXC::Canvas) -> Result<()> {
19    let rect = canvas
20        .Children()?
21        .into_iter()
22        .map(|c| {
23            let c = c.cast::<FrameworkElement>()?;
24            let left = MUXC::Canvas::GetLeft(&c)?;
25            let top = MUXC::Canvas::GetTop(&c)?;
26            let size = Size::from_native(c.DesiredSize()?);
27            Result::Ok(Rect::new(Point::new(left, top), size))
28        })
29        .reduce(|a, b| a.and_then(|a| b.map(|b| (a, b))).map(|(a, b)| a.union(&b)))
30        .unwrap_or_else(|| Ok(Rect::zero()))?;
31    canvas.SetWidth(rect.max_x())?;
32    canvas.SetHeight(rect.max_y())?;
33    Ok(())
34}
35
36#[inherit_methods(from = "self.handle")]
37impl ScrollView {
38    pub fn new(parent: impl AsContainer) -> Result<Self> {
39        let view = MUXC::ScrollViewer::new()?;
40        let canvas = MUXC::Canvas::new()?;
41        canvas.SetHorizontalAlignment(HorizontalAlignment::Left)?;
42        canvas.SetVerticalAlignment(VerticalAlignment::Top)?;
43        view.SetContent(&canvas)?;
44        view.SetHorizontalScrollBarVisibility(MUXC::ScrollBarVisibility::Auto)?;
45        view.SetVerticalScrollBarVisibility(MUXC::ScrollBarVisibility::Auto)?;
46        canvas.Loaded(&RoutedEventHandler::new(|sender, _| {
47            let canvas = sender.ok()?.cast::<MUXC::Canvas>()?;
48            set_canvas_to_fit_children(&canvas)?;
49            Ok(())
50        }))?;
51        Ok(Self {
52            handle: Widget::new(parent, view.cast()?)?,
53            view,
54            canvas,
55        })
56    }
57
58    pub fn is_visible(&self) -> Result<bool>;
59
60    pub fn set_visible(&mut self, v: bool) -> Result<()>;
61
62    pub fn is_enabled(&self) -> Result<bool>;
63
64    pub fn set_enabled(&mut self, v: bool) -> Result<()>;
65
66    pub fn loc(&self) -> Result<Point>;
67
68    pub fn set_loc(&mut self, p: Point) -> Result<()>;
69
70    pub fn size(&self) -> Result<Size>;
71
72    pub fn set_size(&mut self, v: Size) -> Result<()> {
73        self.handle.set_size(v)?;
74        set_canvas_to_fit_children(&self.canvas)?;
75        Ok(())
76    }
77
78    pub fn hscroll(&self) -> Result<bool> {
79        Ok(self.view.HorizontalScrollBarVisibility()? != MUXC::ScrollBarVisibility::Disabled)
80    }
81
82    pub fn set_hscroll(&mut self, v: bool) -> Result<()> {
83        self.view.SetHorizontalScrollBarVisibility(if v {
84            MUXC::ScrollBarVisibility::Auto
85        } else {
86            MUXC::ScrollBarVisibility::Disabled
87        })?;
88        Ok(())
89    }
90
91    pub fn vscroll(&self) -> Result<bool> {
92        Ok(self.view.VerticalScrollBarVisibility()? != MUXC::ScrollBarVisibility::Disabled)
93    }
94
95    pub fn set_vscroll(&mut self, v: bool) -> Result<()> {
96        self.view.SetVerticalScrollBarVisibility(if v {
97            MUXC::ScrollBarVisibility::Auto
98        } else {
99            MUXC::ScrollBarVisibility::Disabled
100        })?;
101        Ok(())
102    }
103
104    pub async fn start(&self) -> ! {
105        std::future::pending().await
106    }
107}
108
109winio_handle::impl_as_widget!(ScrollView, handle);
110
111impl AsContainer for ScrollView {
112    fn as_container(&self) -> BorrowedContainer<'_> {
113        BorrowedContainer::winui(&self.canvas)
114    }
115}