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