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
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use std::ops::Deref;

use crate::prelude::{Area, Point2D, Size2D};

#[derive(Default, PartialEq, Clone, Debug)]
pub struct AbsolutePosition {
    pub top: Option<f32>,
    pub right: Option<f32>,
    pub bottom: Option<f32>,
    pub left: Option<f32>,
}

#[derive(Default, PartialEq, Clone, Debug)]
pub enum Position {
    #[default]
    Stacked,

    Absolute(Box<AbsolutePosition>),
}

impl Position {
    pub fn is_empty(&self) -> bool {
        match self {
            Self::Absolute(absolute_position) => {
                let AbsolutePosition {
                    top,
                    right,
                    bottom,
                    left,
                } = absolute_position.deref();
                top.is_some() && right.is_some() && bottom.is_some() && left.is_some()
            }
            Self::Stacked => true,
        }
    }

    pub fn new_absolute() -> Self {
        Self::Absolute(Box::new(AbsolutePosition {
            top: None,
            right: None,
            bottom: None,
            left: None,
        }))
    }

    pub fn is_absolute(&self) -> bool {
        matches!(self, Self::Absolute { .. })
    }

    pub fn set_top(&mut self, value: f32) {
        if !self.is_absolute() {
            *self = Self::new_absolute();
        }
        if let Self::Absolute(absolute_position) = self {
            absolute_position.top = Some(value)
        }
    }

    pub fn set_right(&mut self, value: f32) {
        if !self.is_absolute() {
            *self = Self::new_absolute();
        }
        if let Self::Absolute(absolute_position) = self {
            absolute_position.right = Some(value)
        }
    }

    pub fn set_bottom(&mut self, value: f32) {
        if !self.is_absolute() {
            *self = Self::new_absolute();
        }
        if let Self::Absolute(absolute_position) = self {
            absolute_position.bottom = Some(value)
        }
    }

    pub fn set_left(&mut self, value: f32) {
        if !self.is_absolute() {
            *self = Self::new_absolute();
        }
        if let Self::Absolute(absolute_position) = self {
            absolute_position.left = Some(value)
        }
    }

    pub fn get_origin(
        &self,
        available_parent_area: &Area,
        parent_area: &Area,
        area_size: &Size2D,
    ) -> Point2D {
        match self {
            Position::Stacked => available_parent_area.origin,
            Position::Absolute(absolute_position) => {
                let AbsolutePosition {
                    top,
                    right,
                    bottom,
                    left,
                } = absolute_position.deref();
                let y = {
                    let mut y = parent_area.min_y();
                    if let Some(top) = top {
                        y += top;
                    } else if let Some(bottom) = bottom {
                        y = parent_area.max_y() - bottom - area_size.height;
                    }
                    y
                };
                let x = {
                    let mut x = parent_area.min_x();
                    if let Some(left) = left {
                        x += left;
                    } else if let Some(right) = right {
                        x = parent_area.max_x() - right - area_size.width;
                    }
                    x
                };
                Point2D::new(x, y)
            }
        }
    }
}