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}