summaryrefslogtreecommitdiffstats
path: root/src/tuice/component/base/container.rs
blob: 67872d8e937f389eef91e07fa7b19610aac6568e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
use tui::{backend::Backend, layout::Rect, Frame};

use crate::tuice::{Bounds, Component, DrawContext, Element, Event, LayoutNode, Size, Status};

/// A [`Container`] just contains a child, as well as being able to be sized.
///
/// Inspired by Flutter's [Container class](https://api.flutter.dev/flutter/widgets/Container-class.html).
#[derive(Default)]
pub struct Container<'a, Message> {
    width: Option<u16>,
    height: Option<u16>,
    child: Option<Box<Element<'a, Message>>>,
}

impl<'a, Message> Container<'a, Message> {
    pub fn with_child(child: Element<'a, Message>) -> Self {
        Self {
            width: None,
            height: None,
            child: Some(child.into()),
        }
    }

    pub fn child(mut self, child: Option<Element<'a, Message>>) -> Self {
        self.child = child.map(|c| c.into());
        self
    }

    pub fn width(mut self, width: Option<u16>) -> Self {
        self.width = width;
        self
    }

    pub fn height(mut self, height: Option<u16>) -> Self {
        self.height = height;
        self
    }
}

impl<'a, Message, B: Backend> Component<Message, B> for Container<'a, Message> {
    fn draw(&mut self, context: DrawContext<'_>, _frame: &mut Frame<'_, B>) {
        todo!()
    }

    fn on_event(&mut self, _area: Rect, _event: Event, _messages: &mut Vec<Message>) -> Status {
        todo!()
    }

    fn layout(&self, bounds: Bounds, node: &mut LayoutNode) -> Size {
        let (width, height) = if let Some(child) = &self.child {
            let mut child_node = LayoutNode::default();

            fn bounds_if_exist(val: Option<u16>, min_bound: u16, max_bound: u16) -> (u16, u16) {
                if let Some(val) = val {
                    let val = val.clamp(min_bound, max_bound);
                    (val, val)
                } else {
                    (min_bound, max_bound)
                }
            }

            let child_bounds = {
                let (min_width, max_width) =
                    bounds_if_exist(self.width, bounds.min_width, bounds.max_width);
                let (min_height, max_height) =
                    bounds_if_exist(self.height, bounds.min_height, bounds.max_height);

                Bounds {
                    min_width,
                    min_height,
                    max_width,
                    max_height,
                }
            };

            let child_size = child.layout(child_bounds, &mut child_node);

            // Note that this is implicitly bounded by our above calculations,
            // no need to recheck if it's valid!
            (child_size.width, child_size.height)
        } else {
            (bounds.min_width, bounds.min_height)
        };

        Size { height, width }
    }
}