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