kas_core/widgets/
adapt.rs

1// Licensed under the Apache License, Version 2.0 (the "License");
2// you may not use this file except in compliance with the License.
3// You may obtain a copy of the License in the LICENSE-APACHE file or at:
4//     https://www.apache.org/licenses/LICENSE-2.0
5
6//! Adapter widgets (wrappers)
7
8#[allow(unused)] use crate::Action;
9use crate::event::ConfigCx;
10use crate::geom::{Rect, Size};
11use crate::layout::{AlignHints, AxisInfo, SizeRules};
12use crate::theme::SizeCx;
13use crate::{Layout, Widget};
14use kas_macros::{autoimpl, impl_self};
15
16#[impl_self]
17mod MapAny {
18    /// Map any input data to `()`
19    ///
20    /// This is a generic data-mapping widget-wrapper with fixed `()` input
21    /// data type.
22    ///
23    /// This struct is a thin wrapper around the inner widget without its own
24    /// [`Id`](crate::Id). It supports [`Deref`](std::ops::Deref) and
25    /// [`DerefMut`](std::ops::DerefMut) to the inner widget.
26    #[autoimpl(Deref, DerefMut using self.inner)]
27    #[autoimpl(Clone, Default where W: trait)]
28    #[autoimpl(Scrollable using self.inner where W: trait)]
29    #[derive_widget(type Data = A)]
30    pub struct MapAny<A, W: Widget<Data = ()>> {
31        _a: std::marker::PhantomData<A>,
32        /// The inner widget
33        #[widget(&())]
34        pub inner: W,
35    }
36
37    impl Self {
38        /// Construct
39        pub fn new(inner: W) -> Self {
40            MapAny {
41                _a: std::marker::PhantomData,
42                inner,
43            }
44        }
45    }
46}
47
48#[impl_self]
49mod Align {
50    /// Apply an alignment hint
51    ///
52    /// The inner widget chooses how to apply (or ignore) this hint.
53    ///
54    /// Usually, this type will be constructed through one of the methods on
55    /// [`AdaptWidget`](https://docs.rs/kas/latest/kas/widgets/trait.AdaptWidget.html).
56    #[derive_widget]
57    pub struct Align<W: Widget> {
58        #[widget]
59        pub inner: W,
60        /// Hints may be modified directly.
61        ///
62        /// Use [`Action::RESIZE`] to apply changes.
63        pub hints: AlignHints,
64    }
65
66    impl Self {
67        /// Construct
68        #[inline]
69        pub fn new(inner: W, hints: AlignHints) -> Self {
70            Align { inner, hints }
71        }
72    }
73
74    impl Layout for Self {
75        fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
76            self.inner.set_rect(cx, rect, self.hints.combine(hints));
77        }
78    }
79}
80
81#[impl_self]
82mod Pack {
83    /// Apply an alignment hint, squash and align the result
84    ///
85    /// The inner widget chooses how to apply (or ignore) this hint.
86    /// The widget is then prevented from stretching beyond its ideal size,
87    /// aligning within the available rect.
88    ///
89    /// Usually, this type will be constructed through one of the methods on
90    /// [`AdaptWidget`](https://docs.rs/kas/latest/kas/widgets/trait.AdaptWidget.html).
91    #[derive_widget]
92    pub struct Pack<W: Widget> {
93        #[widget]
94        pub inner: W,
95        /// Hints may be modified directly.
96        ///
97        /// Use [`Action::RESIZE`] to apply changes.
98        pub hints: AlignHints,
99        size: Size,
100    }
101
102    impl Self {
103        /// Construct
104        #[inline]
105        pub fn new(inner: W, hints: AlignHints) -> Self {
106            Pack {
107                inner,
108                hints,
109                size: Size::ZERO,
110            }
111        }
112    }
113
114    impl Layout for Self {
115        fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
116            let rules = self.inner.size_rules(sizer, axis);
117            self.size.set_component(axis, rules.ideal_size());
118            rules
119        }
120
121        fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
122            let align = self.hints.combine(hints).complete_default();
123            let rect = align.aligned_rect(self.size, rect);
124            self.inner.set_rect(cx, rect, hints);
125        }
126    }
127}