1use crate::container;
2use crate::core::layout;
3use crate::core::mouse;
4use crate::core::overlay;
5use crate::core::renderer;
6use crate::core::widget::{self, Tree};
7use crate::core::{self, Event, Layout, Padding, Point, Rectangle, Shell, Size, Vector, Widget};
8use crate::pane_grid::controls::Controls;
9
10pub struct TitleBar<
14 'a,
15 Message,
16 C = crate::Element<'a, Message>,
17 Theme = crate::Theme,
18 Renderer = crate::Renderer,
19> where
20 Theme: container::Catalog,
21 Renderer: core::Renderer,
22{
23 content: C,
24 controls: Option<Controls<'a, Message, Theme, Renderer>>,
25 padding: Padding,
26 always_show_controls: bool,
27 class: Theme::Class<'a>,
28}
29
30impl<'a, Message, C, Theme, Renderer> TitleBar<'a, Message, C, Theme, Renderer>
31where
32 Theme: container::Catalog,
33 Renderer: core::Renderer,
34{
35 pub fn new(content: C) -> Self {
37 Self {
38 content,
39 controls: None,
40 padding: Padding::ZERO,
41 always_show_controls: false,
42 class: Theme::default(),
43 }
44 }
45
46 pub fn controls(mut self, controls: impl Into<Controls<'a, Message, Theme, Renderer>>) -> Self {
48 self.controls = Some(controls.into());
49 self
50 }
51
52 pub fn padding<P: Into<Padding>>(mut self, padding: P) -> Self {
54 self.padding = padding.into();
55 self
56 }
57
58 pub fn always_show_controls(mut self) -> Self {
67 self.always_show_controls = true;
68 self
69 }
70
71 #[must_use]
73 pub fn style(mut self, style: impl Fn(&Theme) -> container::Style + 'a) -> Self
74 where
75 Theme::Class<'a>: From<container::StyleFn<'a, Theme>>,
76 {
77 self.class = (Box::new(style) as container::StyleFn<'a, Theme>).into();
78 self
79 }
80
81 #[cfg(feature = "advanced")]
83 #[must_use]
84 pub fn class(mut self, class: impl Into<Theme::Class<'a>>) -> Self {
85 self.class = class.into();
86 self
87 }
88}
89
90impl<Message, C, Theme, Renderer> TitleBar<'_, Message, C, Theme, Renderer>
91where
92 C: Widget<Message, Theme, Renderer>,
93 Theme: container::Catalog,
94 Renderer: core::Renderer,
95{
96 pub(super) fn state(&self) -> Tree {
97 let children = match self.controls.as_ref() {
98 Some(controls) => match controls.compact.as_ref() {
99 Some(compact) => vec![
100 Tree::new(&self.content),
101 Tree::new(&controls.full),
102 Tree::new(compact),
103 ],
104 None => vec![
105 Tree::new(&self.content),
106 Tree::new(&controls.full),
107 Tree::empty(),
108 ],
109 },
110 None => {
111 vec![Tree::new(&self.content), Tree::empty(), Tree::empty()]
112 }
113 };
114
115 Tree {
116 children,
117 ..Tree::empty()
118 }
119 }
120
121 pub(super) fn diff(&mut self, tree: &mut Tree) {
122 if tree.children.len() != 3 {
123 *tree = self.state();
124 }
125
126 if let Some(controls) = &mut self.controls {
127 if let Some(compact) = &mut controls.compact {
128 tree.children[2].diff(compact);
129 }
130
131 tree.children[1].diff(&mut controls.full);
132 }
133
134 tree.children[0].diff(&mut self.content);
135 }
136
137 pub fn draw(
141 &self,
142 tree: &Tree,
143 renderer: &mut Renderer,
144 theme: &Theme,
145 inherited_style: &renderer::Style,
146 layout: Layout,
147 cursor: mouse::Cursor,
148 viewport: &Rectangle,
149 show_controls: bool,
150 ) {
151 let bounds = layout.bounds();
152 let style = theme.style(&self.class);
153
154 let inherited_style = renderer::Style {
155 text_color: style.text_color.unwrap_or(inherited_style.text_color),
156 };
157
158 container::draw_background(renderer, &style, bounds);
159
160 let mut children = layout.iter(&tree.children);
161 let (title_layout, title_tree) = children.next().unwrap();
162 let (controls_layout, controls_tree) = children.next().unwrap();
163 let (compact_layout, compact_tree) = children.next().unwrap();
164 let mut show_title = true;
165
166 let padded_width = layout.bounds().width - self.padding.left + self.padding.right;
167
168 if let Some(controls) = &self.controls
169 && (show_controls || self.always_show_controls)
170 {
171 if title_layout.bounds().width + controls_layout.bounds().width > padded_width {
172 if let Some(compact) = controls.compact.as_ref() {
173 compact.draw(
174 compact_tree,
175 renderer,
176 theme,
177 &inherited_style,
178 compact_layout,
179 cursor,
180 viewport,
181 );
182 } else {
183 show_title = false;
184
185 controls.full.draw(
186 controls_tree,
187 renderer,
188 theme,
189 &inherited_style,
190 controls_layout,
191 cursor,
192 viewport,
193 );
194 }
195 } else {
196 controls.full.draw(
197 controls_tree,
198 renderer,
199 theme,
200 &inherited_style,
201 controls_layout,
202 cursor,
203 viewport,
204 );
205 }
206 }
207
208 if show_title {
209 self.content.draw(
210 title_tree,
211 renderer,
212 theme,
213 &inherited_style,
214 title_layout,
215 cursor,
216 viewport,
217 );
218 }
219 }
220
221 pub fn is_over_pick_area(&self, tree: &Tree, layout: Layout, cursor_position: Point) -> bool {
226 if layout.bounds().contains(cursor_position) {
227 let mut children = layout.iter(&tree.children);
228 let (title_layout, _) = children.next().unwrap();
229 let (controls_layout, _) = children.next().unwrap();
230 let (compact_layout, _) = children.next().unwrap();
231
232 let padded_width = layout.bounds().width - self.padding.left + self.padding.right;
233
234 if let Some(controls) = self.controls.as_ref() {
235 if title_layout.bounds().width + controls_layout.bounds().width > padded_width {
236 if controls.compact.is_some() {
237 !compact_layout.bounds().contains(cursor_position)
238 && !title_layout.bounds().contains(cursor_position)
239 } else {
240 !controls_layout.bounds().contains(cursor_position)
241 }
242 } else {
243 !controls_layout.bounds().contains(cursor_position)
244 && !title_layout.bounds().contains(cursor_position)
245 }
246 } else {
247 !title_layout.bounds().contains(cursor_position)
248 }
249 } else {
250 false
251 }
252 }
253
254 pub(crate) fn layout(&mut self, tree: &mut Tree, renderer: &Renderer, limits: &layout::Limits) {
255 let limits = limits.shrink(self.padding);
256 let max_size = limits.max;
257
258 self.content.layout(
259 &mut tree.children[0],
260 renderer,
261 &layout::Limits::new(Size::ZERO, max_size),
262 );
263
264 let title_size = tree.children[0].size;
265
266 let inner_size = if let Some(controls) = &mut self.controls {
267 controls.full.layout(
268 &mut tree.children[1],
269 renderer,
270 &layout::Limits::new(Size::ZERO, max_size),
271 );
272
273 let controls_size = tree.children[1].size;
274
275 if title_size.width + controls_size.width > max_size.width {
276 if let Some(compact) = controls.compact.as_mut() {
277 compact.layout(
278 &mut tree.children[2],
279 renderer,
280 &layout::Limits::new(Size::ZERO, max_size),
281 );
282
283 let compact_size = tree.children[2].size;
284 let space_before_controls = max_size.width - compact_size.width;
285
286 tree.children[1].translation = Vector::ZERO;
287 tree.children[2].translation = Vector::new(space_before_controls, 0.0);
288
289 Size::new(max_size.width, title_size.height.max(compact_size.height))
290 } else {
291 let space_before_controls = max_size.width - controls_size.width;
292
293 tree.children[1].translation = Vector::new(space_before_controls, 0.0);
294
295 Size::new(max_size.width, title_size.height.max(controls_size.height))
296 }
297 } else {
298 let space_before_controls = max_size.width - controls_size.width;
299
300 tree.children[1].translation = Vector::new(space_before_controls, 0.0);
301
302 Size::new(max_size.width, title_size.height.max(controls_size.height))
303 }
304 } else {
305 Size::new(max_size.width, title_size.height)
306 };
307
308 tree.children[0].translation = Vector::ZERO;
309
310 for child in &mut tree.children {
311 child.translation += Vector::new(self.padding.left, self.padding.top);
312 }
313
314 tree.size = inner_size.expand(self.padding);
315 }
316
317 pub(crate) fn operate(
318 &mut self,
319 tree: &mut Tree,
320 layout: Layout,
321 viewport: &Rectangle,
322 renderer: &Renderer,
323 operation: &mut dyn widget::Operation,
324 ) {
325 let mut children = layout.iter_mut(&mut tree.children);
326 let (title_layout, title_tree) = children.next().unwrap();
327 let (controls_layout, controls_tree) = children.next().unwrap();
328 let (compact_layout, compact_tree) = children.next().unwrap();
329 let padded_width = layout.bounds().width - self.padding.left + self.padding.right;
330 let mut show_title = true;
331
332 if let Some(controls) = &mut self.controls {
333 if title_layout.bounds().width + controls_layout.bounds().width > padded_width {
334 if let Some(compact) = controls.compact.as_mut() {
335 compact.operate(compact_tree, compact_layout, viewport, renderer, operation);
336 } else {
337 show_title = false;
338
339 controls.full.operate(
340 controls_tree,
341 controls_layout,
342 viewport,
343 renderer,
344 operation,
345 );
346 }
347 } else {
348 controls.full.operate(
349 controls_tree,
350 controls_layout,
351 viewport,
352 renderer,
353 operation,
354 );
355 }
356 };
357
358 if show_title {
359 self.content
360 .operate(title_tree, title_layout, viewport, renderer, operation);
361 }
362 }
363
364 pub(crate) fn update(
365 &mut self,
366 tree: &mut Tree,
367 event: &Event,
368 layout: Layout,
369 cursor: mouse::Cursor,
370 renderer: &Renderer,
371 shell: &mut Shell<'_, Message>,
372 viewport: &Rectangle,
373 ) {
374 let mut children = layout.iter_mut(&mut tree.children);
375 let (title_layout, title_tree) = children.next().unwrap();
376 let (controls_layout, controls_tree) = children.next().unwrap();
377 let (compact_layout, compact_tree) = children.next().unwrap();
378 let padded_width = layout.bounds().width - self.padding.left + self.padding.right;
379 let mut show_title = true;
380
381 if let Some(controls) = &mut self.controls {
382 if title_layout.bounds().width + controls_layout.bounds().width > padded_width {
383 if let Some(compact) = controls.compact.as_mut() {
384 compact.update(
385 compact_tree,
386 event,
387 compact_layout,
388 cursor,
389 renderer,
390 shell,
391 viewport,
392 );
393 } else {
394 show_title = false;
395
396 controls.full.update(
397 controls_tree,
398 event,
399 controls_layout,
400 cursor,
401 renderer,
402 shell,
403 viewport,
404 );
405 }
406 } else {
407 controls.full.update(
408 controls_tree,
409 event,
410 controls_layout,
411 cursor,
412 renderer,
413 shell,
414 viewport,
415 );
416 }
417 }
418
419 if show_title {
420 self.content.update(
421 title_tree,
422 event,
423 title_layout,
424 cursor,
425 renderer,
426 shell,
427 viewport,
428 );
429 }
430 }
431
432 pub(crate) fn mouse_interaction(
433 &self,
434 tree: &Tree,
435 layout: Layout,
436 cursor: mouse::Cursor,
437 viewport: &Rectangle,
438 renderer: &Renderer,
439 ) -> mouse::Interaction {
440 let mut children = layout.iter(&tree.children);
441 let (title_layout, title_tree) = children.next().unwrap();
442 let (controls_layout, controls_tree) = children.next().unwrap();
443 let (compact_layout, compact_tree) = children.next().unwrap();
444 let padded_width = layout.bounds().width - self.padding.left + self.padding.right;
445
446 let title_interaction =
447 self.content
448 .mouse_interaction(title_tree, title_layout, cursor, viewport, renderer);
449
450 if let Some(controls) = &self.controls {
451 let controls_interaction = controls.full.mouse_interaction(
452 controls_tree,
453 controls_layout,
454 cursor,
455 viewport,
456 renderer,
457 );
458
459 if title_layout.bounds().width + controls_layout.bounds().width > padded_width {
460 if let Some(compact) = controls.compact.as_ref() {
461 let compact_interaction = compact.mouse_interaction(
462 compact_tree,
463 compact_layout,
464 cursor,
465 viewport,
466 renderer,
467 );
468
469 compact_interaction.max(title_interaction)
470 } else {
471 controls_interaction
472 }
473 } else {
474 controls_interaction.max(title_interaction)
475 }
476 } else {
477 title_interaction
478 }
479 }
480
481 pub(crate) fn overlay<'b>(
482 &'b mut self,
483 tree: &'b mut Tree,
484 layout: Layout,
485 renderer: &Renderer,
486 viewport: &Rectangle,
487 translation: Vector,
488 window: Size,
489 ) -> Vec<overlay::Element<'b, Message, Theme, Renderer>> {
490 let mut children = layout.iter_mut(&mut tree.children);
491 let (title_layout, title_tree) = children.next().unwrap();
492 let (controls_layout, controls_tree) = children.next().unwrap();
493 let (compact_layout, compact_tree) = children.next().unwrap();
494 let padded_width = layout.bounds().width - self.padding.left + self.padding.right;
495
496 let Self {
497 content, controls, ..
498 } = self;
499
500 let mut overlays = content.overlay(
501 title_tree,
502 title_layout,
503 renderer,
504 viewport,
505 translation,
506 window,
507 );
508
509 if let Some(controls) = controls {
510 if title_layout.bounds().width + controls_layout.bounds().width > padded_width {
511 if let Some(compact) = &mut controls.compact {
512 overlays.extend(compact.overlay(
513 compact_tree,
514 compact_layout,
515 renderer,
516 viewport,
517 translation,
518 window,
519 ));
520 } else {
521 overlays.extend(controls.full.overlay(
522 controls_tree,
523 controls_layout,
524 renderer,
525 viewport,
526 translation,
527 window,
528 ));
529 }
530 } else {
531 overlays.extend(controls.full.overlay(
532 controls_tree,
533 controls_layout,
534 renderer,
535 viewport,
536 translation,
537 window,
538 ));
539 }
540 }
541
542 overlays
543 }
544}