veloren_voxygen/ui/ice/widget/
overlay.rs1use iced::{
2 Align, Clipboard, Element, Event, Hasher, Layout, Length, Padding, Point, Rectangle, Size,
3 Widget, layout, mouse,
4};
5use std::hash::Hash;
6
7pub struct Overlay<'a, M, R: Renderer> {
13 padding: Padding,
14 width: Length,
15 height: Length,
16 max_width: u32,
17 max_height: u32,
18 horizontal_alignment: Align,
19 vertical_alignment: Align,
20 over: Element<'a, M, R>,
21 under: Element<'a, M, R>,
22 pos: Option<Point>,
23 }
25
26impl<'a, M, R> Overlay<'a, M, R>
27where
28 R: Renderer,
29{
30 pub fn new<O, U>(over: O, under: U) -> Self
31 where
32 O: Into<Element<'a, M, R>>,
33 U: Into<Element<'a, M, R>>,
34 {
35 Self {
36 padding: Padding::ZERO,
37 width: Length::Shrink,
38 height: Length::Shrink,
39 max_width: u32::MAX,
40 max_height: u32::MAX,
41 horizontal_alignment: Align::Start,
42 vertical_alignment: Align::Start,
43 over: over.into(),
44 under: under.into(),
45 pos: None,
46 }
47 }
48
49 #[must_use]
50 pub fn over_position(mut self, pos: Point) -> Self {
51 self.pos = Some(pos);
52 self
53 }
54
55 #[must_use]
56 pub fn padding<P: Into<Padding>>(mut self, pad: P) -> Self {
57 self.padding = pad.into();
58 self
59 }
60
61 #[must_use]
62 pub fn width(mut self, width: Length) -> Self {
63 self.width = width;
64 self
65 }
66
67 #[must_use]
68 pub fn height(mut self, height: Length) -> Self {
69 self.height = height;
70 self
71 }
72
73 #[must_use]
74 pub fn max_width(mut self, max_width: u32) -> Self {
75 self.max_width = max_width;
76 self
77 }
78
79 #[must_use]
80 pub fn max_height(mut self, max_height: u32) -> Self {
81 self.max_height = max_height;
82 self
83 }
84
85 #[must_use]
86 pub fn align_x(mut self, align_x: Align) -> Self {
87 self.horizontal_alignment = align_x;
88 self
89 }
90
91 #[must_use]
92 pub fn align_y(mut self, align_y: Align) -> Self {
93 self.vertical_alignment = align_y;
94 self
95 }
96
97 #[must_use]
98 pub fn center_x(mut self) -> Self {
99 self.horizontal_alignment = Align::Center;
100 self
101 }
102
103 #[must_use]
104 pub fn center_y(mut self) -> Self {
105 self.vertical_alignment = Align::Center;
106 self
107 }
108}
109
110impl<M, R> Widget<M, R> for Overlay<'_, M, R>
111where
112 R: Renderer,
113{
114 fn width(&self) -> Length { self.width }
115
116 fn height(&self) -> Length { self.height }
117
118 fn layout(&self, renderer: &R, limits: &layout::Limits) -> layout::Node {
119 let limits = limits
120 .loose()
121 .max_width(self.max_width)
122 .max_height(self.max_height)
123 .width(self.width)
124 .height(self.height);
125
126 let under = self.under.layout(renderer, &limits.loose());
127 let under_size = under.size();
128
129 let limits = limits.pad(self.padding);
130 let mut over = self.over.layout(renderer, &limits.loose());
131 let over_size = over.size();
132
133 let size = limits.resolve(
134 Size {
135 width: under_size.width.max(over_size.width),
136 height: under_size.height.max(over_size.height),
137 }
138 .pad(self.padding),
139 );
140
141 over.move_to(
142 self.pos
143 .unwrap_or_else(|| Point::new(self.padding.left.into(), self.padding.top.into())),
144 );
145 over.align(self.horizontal_alignment, self.vertical_alignment, size);
146
147 layout::Node::with_children(size, vec![over, under])
148 }
149
150 fn draw(
151 &self,
152 renderer: &mut R,
153 defaults: &R::Defaults,
154 layout: Layout<'_>,
155 cursor_position: Point,
156 viewport: &Rectangle,
157 ) -> R::Output {
158 let mut children = layout.children();
159 renderer.draw(
160 defaults,
161 layout.bounds(),
162 cursor_position,
163 viewport,
164 &self.over,
165 children.next().unwrap(),
166 &self.under,
167 children.next().unwrap(),
168 )
169 }
170
171 fn hash_layout(&self, state: &mut Hasher) {
172 struct Marker;
173 std::any::TypeId::of::<Marker>().hash(state);
174
175 self.padding.hash(state);
176 self.width.hash(state);
177 self.height.hash(state);
178 self.max_width.hash(state);
179 self.max_height.hash(state);
180
181 self.over.hash_layout(state);
182 self.under.hash_layout(state);
183 }
184
185 fn on_event(
186 &mut self,
187 event: Event,
188 layout: Layout<'_>,
189 cursor_position: Point,
190 renderer: &R,
191 clipboard: &mut dyn Clipboard,
192 messages: &mut Vec<M>,
193 ) -> iced::event::Status {
194 let mut children = layout.children();
195 let over_layout = children.next().unwrap();
196
197 let status = self.over.on_event(
199 event.clone(),
200 over_layout,
201 cursor_position,
202 renderer,
203 clipboard,
204 messages,
205 );
206
207 if !matches!(&event, Event::Mouse(mouse::Event::ButtonPressed(_)))
210 || !over_layout.bounds().contains(cursor_position)
211 {
212 self.under
213 .on_event(
214 event,
215 children.next().unwrap(),
216 cursor_position,
217 renderer,
218 clipboard,
219 messages,
220 )
221 .merge(status)
222 } else {
223 status
224 }
225 }
226
227 fn overlay(&mut self, layout: Layout<'_>) -> Option<iced::overlay::Element<'_, M, R>> {
228 let mut children = layout.children();
229 let (over, under) = (&mut self.over, &mut self.under);
230 over.overlay(children.next().unwrap())
231 .or_else(move || under.overlay(children.next().unwrap()))
232 }
233}
234
235pub trait Renderer: iced::Renderer {
236 fn draw<M>(
237 &mut self,
238 defaults: &Self::Defaults,
239 bounds: Rectangle,
240 cursor_position: Point,
241 viewport: &Rectangle,
242 over: &Element<'_, M, Self>,
243 over_layout: Layout<'_>,
244 under: &Element<'_, M, Self>,
245 under_layout: Layout<'_>,
246 ) -> Self::Output;
247}
248
249impl<'a, M, R> From<Overlay<'a, M, R>> for Element<'a, M, R>
250where
251 R: 'a + Renderer,
252 M: 'a,
253{
254 fn from(overlay: Overlay<'a, M, R>) -> Element<'a, M, R> { Element::new(overlay) }
255}