Skip to main content

kas_widgets/adapt/
reserve.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//! Size reservation
7
8#[allow(unused)] use crate::adapt::AdaptWidget;
9use kas::prelude::*;
10use kas::theme::MarginStyle;
11
12#[impl_self]
13mod Reserve {
14    /// A generic widget for size reservations
15    ///
16    /// In a few cases it is desirable to reserve more space for a widget than
17    /// required for the current content, e.g. if a label's text may change. This
18    /// widget can be used for this by wrapping the base widget.
19    ///
20    /// Usually, this type will be constructed through one of the methods on
21    /// [`AdaptWidget`].
22    #[autoimpl(Deref, DerefMut using self.inner)]
23    #[autoimpl(Viewport using self.inner where W: trait)]
24    #[derive_widget]
25    pub struct Reserve<W: Widget> {
26        #[widget]
27        pub inner: W,
28        reserve: Box<dyn Fn(&mut SizeCx, AxisInfo) -> SizeRules + 'static>,
29    }
30
31    impl Self {
32        /// Construct a reserve
33        ///
34        /// The closure `reserve` should generate `SizeRules` on request, just like
35        /// [`Layout::size_rules`]. For example:
36        ///```
37        /// use kas_widgets::adapt::Reserve;
38        /// use kas_widgets::Filler;
39        /// use kas::prelude::*;
40        ///
41        /// let label = Reserve::new(Filler::new(), |cx: &mut SizeCx<'_>, axis| {
42        ///     cx.logical(100.0, 100.0).build(axis)
43        /// });
44        ///```
45        /// The resulting `SizeRules` will be the max of those for the inner widget
46        /// and the result of the `reserve` closure.
47        #[inline]
48        pub fn new(
49            inner: W,
50            reserve: impl Fn(&mut SizeCx, AxisInfo) -> SizeRules + 'static,
51        ) -> Self {
52            let reserve = Box::new(reserve);
53            Reserve { inner, reserve }
54        }
55    }
56
57    impl Layout for Self {
58        fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
59            let inner_rules = self.inner.size_rules(cx, axis);
60            let reserve_rules = (self.reserve)(cx, axis);
61            inner_rules.max(reserve_rules)
62        }
63    }
64}
65
66#[impl_self]
67mod WithMarginStyle {
68    /// Specify margins via a style
69    ///
70    /// This replaces a widget's margins.
71    ///
72    /// Usually, this type will be constructed using
73    /// [`AdaptWidget::with_margin_style`].
74    #[autoimpl(Deref, DerefMut using self.inner)]
75    #[autoimpl(Viewport using self.inner where W: trait)]
76    #[derive_widget]
77    pub struct WithMarginStyle<W: Widget> {
78        #[widget]
79        pub inner: W,
80        style: MarginStyle,
81    }
82
83    impl Self {
84        /// Construct
85        #[inline]
86        pub fn new(inner: W, style: MarginStyle) -> Self {
87            WithMarginStyle { inner, style }
88        }
89    }
90
91    impl Layout for Self {
92        fn size_rules(&mut self, cx: &mut SizeCx, axis: AxisInfo) -> SizeRules {
93            let child_rules = self.inner.size_rules(cx, axis);
94            let margins = cx.margins(self.style).extract(axis);
95            child_rules.with_margins(margins)
96        }
97    }
98}