kas_widgets/adapt/
align.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//! Alignment
7
8use kas::dir::Directions;
9use kas::prelude::*;
10use kas::theme::MarginStyle;
11
12impl_scope! {
13    /// Apply an alignment hint
14    ///
15    /// The inner widget chooses how to apply (or ignore) this hint.
16    ///
17    /// Usually, this type will be constructed through one of the methods on
18    /// [`AdaptWidget`](crate::adapt::AdaptWidget).
19    #[autoimpl(Deref, DerefMut using self.inner)]
20    #[autoimpl(class_traits using self.inner where W: trait)]
21    #[widget{ derive = self.inner; }]
22    pub struct Align<W: Widget> {
23        pub inner: W,
24        /// Hints may be modified directly.
25        ///
26        /// Use [`Action::RESIZE`] to apply changes.
27        pub hints: AlignHints,
28    }
29
30    impl Self {
31        /// Construct
32        #[inline]
33        pub fn new(inner: W, hints: AlignHints) -> Self {
34            Align { inner, hints }
35        }
36    }
37
38    impl Layout for Self {
39        fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
40            self.inner.set_rect(cx, rect, self.hints.combine(hints));
41        }
42    }
43}
44
45impl_scope! {
46    /// Apply an alignment hint, squash and align the result
47    ///
48    /// The inner widget chooses how to apply (or ignore) this hint.
49    /// The widget is then prevented from stretching beyond its ideal size,
50    /// aligning within the available rect.
51    ///
52    /// Usually, this type will be constructed through one of the methods on
53    /// [`AdaptWidget`](crate::adapt::AdaptWidget).
54    #[autoimpl(Deref, DerefMut using self.inner)]
55    #[autoimpl(class_traits using self.inner where W: trait)]
56    #[widget{ derive = self.inner; }]
57    pub struct Pack<W: Widget> {
58        pub inner: W,
59        /// Hints may be modified directly.
60        ///
61        /// Use [`Action::RESIZE`] to apply changes.
62        pub hints: AlignHints,
63        size: Size,
64    }
65
66    impl Self {
67        /// Construct
68        #[inline]
69        pub fn new(inner: W, hints: AlignHints) -> Self {
70            Pack { inner, hints, size: Size::ZERO }
71        }
72    }
73
74    impl Layout for Self {
75        fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
76            let rules = self.inner.size_rules(sizer, axis);
77            self.size.set_component(axis, rules.ideal_size());
78            rules
79        }
80
81        fn set_rect(&mut self, cx: &mut ConfigCx, rect: Rect, hints: AlignHints) {
82            let align = self.hints.combine(hints).complete_default();
83            let rect = align.aligned_rect(self.size, rect);
84            self.inner.set_rect(cx, rect, hints);
85        }
86    }
87}
88
89impl_scope! {
90    /// Specify margins
91    ///
92    /// This replaces a widget's margins.
93    ///
94    /// Usually, this type will be constructed through one of the methods on
95    /// [`AdaptWidget`](crate::adapt::AdaptWidget).
96    #[autoimpl(Deref, DerefMut using self.inner)]
97    #[autoimpl(class_traits using self.inner where W: trait)]
98    #[widget{ derive = self.inner; }]
99    pub struct Margins<W: Widget> {
100        pub inner: W,
101        dirs: Directions,
102        style: MarginStyle,
103    }
104
105    impl Self {
106        /// Construct
107        #[inline]
108        pub fn new(inner: W, dirs: Directions, style: MarginStyle) -> Self {
109            Margins { inner, dirs, style }
110        }
111    }
112
113    impl Layout for Self {
114        fn size_rules(&mut self, sizer: SizeCx, axis: AxisInfo) -> SizeRules {
115            let mut child_rules = self.inner.size_rules(sizer.re(), axis);
116            if self.dirs.intersects(Directions::from(axis)) {
117                let mut rule_margins = child_rules.margins();
118                let margins = sizer.margins(self.style).extract(axis);
119                if self.dirs.intersects(Directions::LEFT | Directions::UP) {
120                    rule_margins.0 = margins.0;
121                }
122                if self.dirs.intersects(Directions::RIGHT | Directions::DOWN) {
123                    rule_margins.1 = margins.1;
124                }
125                child_rules.set_margins(rule_margins);
126            }
127            child_rules
128        }
129    }
130}