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
124
125
126
127
128
129
130
131
132
133
use embedded_graphics::prelude::Size;

use crate::{align::Alignment, prelude::*};

/// Secondary alignment is used to align views perpendicular to the placement axis.
///
/// For example, use [`horizontal::Right`] to align views to the right in a vertical linear layout.
///
/// `SecondaryAlignment` should be implemented by custom `Alignment` types, otherwise they won't be
/// compatible with [`LinearLayout`].
///
/// [`LinearLayout`]: crate::layout::linear::LinearLayout
pub trait SecondaryAlignment: Alignment {
    /// The secondary alignment of the first view
    type First: Alignment;

    /// Return the combined `Size` occupied by both `Views` after they are arranged.
    ///
    /// I.e. [`horizontal::Left`] returns the maximum width, while [`horizontal::LeftToRight`]
    /// returns the sum of the two widths.
    fn measure(prev: Size, view_size: Size) -> Size;
}

fn max_width(prev_size: Size, view_size: Size) -> Size {
    Size::new(
        prev_size.width.max(view_size.width),
        prev_size.height + view_size.height,
    )
}

const fn cascading(prev_size: Size, view_size: Size) -> Size {
    Size::new(
        prev_size.width + view_size.width,
        prev_size.height + view_size.height,
    )
}

impl SecondaryAlignment for horizontal::Left {
    type First = horizontal::Left;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        max_width(prev_size, view_size)
    }
}

impl SecondaryAlignment for horizontal::Center {
    type First = horizontal::Center;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        max_width(prev_size, view_size)
    }
}

impl SecondaryAlignment for horizontal::Right {
    type First = horizontal::Right;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        max_width(prev_size, view_size)
    }
}

impl SecondaryAlignment for horizontal::RightToLeft {
    type First = horizontal::Right;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        cascading(prev_size, view_size)
    }
}

impl SecondaryAlignment for horizontal::LeftToRight {
    type First = horizontal::Left;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        cascading(prev_size, view_size)
    }
}

fn max_height(prev_size: Size, view_size: Size) -> Size {
    Size::new(
        prev_size.width + view_size.width,
        prev_size.height.max(view_size.height),
    )
}

impl SecondaryAlignment for vertical::Top {
    type First = vertical::Top;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        max_height(prev_size, view_size)
    }
}

impl SecondaryAlignment for vertical::Center {
    type First = vertical::Center;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        max_height(prev_size, view_size)
    }
}

impl SecondaryAlignment for vertical::Bottom {
    type First = vertical::Bottom;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        max_height(prev_size, view_size)
    }
}

impl SecondaryAlignment for vertical::TopToBottom {
    type First = vertical::Top;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        cascading(prev_size, view_size)
    }
}

impl SecondaryAlignment for vertical::BottomToTop {
    type First = vertical::Bottom;

    #[inline]
    fn measure(prev_size: Size, view_size: Size) -> Size {
        cascading(prev_size, view_size)
    }
}