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
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
use crate::*;

/// Indicates when to wrap the current line to a new line. See also [`Direction`].
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum LineWrap {
    /// Never wrap to a new line.
    None,

    /// Wrap to a new line when the available width is exhausted.
    Overflow,
}
impl LineWrap {
    /// TODO(JP): Replace these with LineWrap::default() when
    /// <https://github.com/rust-lang/rust/issues/67792> gets done
    pub const DEFAULT: LineWrap = LineWrap::None;
}
impl Default for LineWrap {
    fn default() -> Self {
        LineWrap::DEFAULT
    }
}

/// Configure how a [`CxLayoutBox`] is going to walk, typically bounded by the
/// dimensions of a parent [`CxLayoutBox`].
#[derive(Copy, Clone, Debug)]
pub(crate) struct Layout {
    /// See [`LayoutSize`].
    pub layout_size: LayoutSize,
    /// See [`Padding`].
    pub padding: Padding,
    /// See [`Direction`].
    pub direction: Direction,
    /// See [`LineWrap`].
    pub line_wrap: LineWrap,
    /// Absolutely position by overriding the [`CxLayoutBox::origin`] with (0,0) instead of using the parent's
    /// current position.
    pub absolute: bool,
    /// Override the maximum size of the [`Window`]/[`Pass`]. Should typically
    /// not be used; instead set [`CxLayoutBox::width`] and [`CxLayoutBox::height`]
    /// through [`Layout::layout_size`].
    pub abs_size: Option<Vec2>,
}

impl Layout {
    /// TODO(JP): Replace these with Layout::default() when
    /// <https://github.com/rust-lang/rust/issues/67792> gets done
    pub const DEFAULT: Layout = Layout {
        layout_size: LayoutSize::DEFAULT,
        padding: Padding::DEFAULT,
        direction: Direction::DEFAULT,
        line_wrap: LineWrap::DEFAULT,
        absolute: false,
        abs_size: None,
    };
}

impl Default for Layout {
    fn default() -> Self {
        Layout::DEFAULT
    }
}

/// Determines how a [`CxLayoutBox`] should walk. Can be applied to a new [`CxLayoutBox`]
/// through [`Layout::layout_size`], or directly to move an existing [`CxLayoutBox`] by
/// using [`Cx::add_box`].
#[derive(Copy, Clone, Debug)]
pub struct LayoutSize {
    pub width: Width,
    pub height: Height,
}

impl LayoutSize {
    /// TODO(JP): Replace these with Align::default() when
    /// <https://github.com/rust-lang/rust/issues/67792> gets done
    pub const DEFAULT: LayoutSize = LayoutSize { width: Width::DEFAULT, height: Height::DEFAULT };
    pub const FILL: LayoutSize = LayoutSize { width: Width::Fill, height: Height::Fill };

    pub const fn new(w: Width, h: Height) -> Self {
        Self { width: w, height: h }
    }
}
impl Default for LayoutSize {
    fn default() -> Self {
        LayoutSize::DEFAULT
    }
}

/// The direction in which the [`CxLayoutBox`] should walk. It will typically walk
/// in a straight line in this direction. E.g. when walking to [`Direction::Right`],
/// it will only walk horizontally, not vertically, until it hits the [`CxLayoutBox::width`],
/// at which point it will wrap around using [`LineWrap`], based on the maximum
/// height of widgets that have been drawn so far, which is registered in
/// [`CxLayoutBox::biggest`].
///
/// TODO(JP): This line wrapping behavior makes sense for [`Direction::Right`],
/// but not so much for [`Direction::Down`].. Maybe we should split [`CxLayoutBox`]
/// into different kinds of behavior?
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Direction {
    Right,
    Down,
}
impl Direction {
    /// TODO(JP): Replace these with Direction::default() when
    /// <https://github.com/rust-lang/rust/issues/67792> gets done
    pub const DEFAULT: Direction = Direction::Right;
}
impl Default for Direction {
    fn default() -> Self {
        Direction::DEFAULT
    }
}

/// Different ways in which a [`LayoutSize`] can get a width.
///
/// TODO(JP): See [`Height::DEFAULT`] for a related TODO.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Width {
    /// Fill up as much of the available space as possible.
    Fill,
    /// Use a fixed width.
    Fix(f32),
    /// Will defer computation of [`CxLayoutBox::width`] by setting it to [`f32::NAN`],
    /// and only properly computing it later on.
    ///
    /// TODO(JP): This can also be passed into [`Cx::add_box`] but there it
    /// makes no sense!
    Compute,
    /// Fill up as much of the available space as possible up to provided width
    FillUntil(f32),
}
impl Width {
    /// TODO(JP): Replace these with Width::default() when
    /// <https://github.com/rust-lang/rust/issues/67792> gets done
    pub const DEFAULT: Width = Width::Fill;
}
impl Default for Width {
    fn default() -> Self {
        Width::Fill
    }
}

/// Different ways in which a [`LayoutSize`] can get a height.
///
/// See [`Width`] for more documentation, since it's analogous.
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum Height {
    /// See [`Width::Fill`].
    Fill,
    /// See [`Width::Fix`].
    Fix(f32),
    /// See [`Width::Compute`].
    Compute,
    /// See [`Width::FillUntil`],
    FillUntil(f32),
}
impl Height {
    /// TODO(JP): [`Height::Fill`] might be a bad default, because if you use
    /// [`Direction::Down`] it will push out everything out it below.
    /// HTML/CSS uses something more like [`Height::Compute`] by default for height,
    /// and only [`Height::Fill`] for width (for block-layout elements).
    ///
    /// TODO(JP): Replace these with Height::default() when
    /// <https://github.com/rust-lang/rust/issues/67792> gets done
    pub const DEFAULT: Height = Height::Fill;
}
impl Default for Height {
    fn default() -> Self {
        Height::Fill
    }
}

/// Defines how elements on [`Cx::layout_box_align_list`] should be moved horizontally
pub(crate) struct AlignX(pub f32);

impl AlignX {
    // Note: LEFT is the default so not needed as explicit option
    pub(crate) const CENTER: AlignX = AlignX(0.5);
    #[allow(dead_code)]
    pub(crate) const RIGHT: AlignX = AlignX(1.0);
}

/// Defines how elements on [`Cx::layout_box_align_list`] should be moved vertically
pub(crate) struct AlignY(pub f32);

impl AlignY {
    // Note: TOP is the default so not needed as explicit option
    pub(crate) const CENTER: AlignY = AlignY(0.5);
    #[allow(dead_code)]
    pub(crate) const BOTTOM: AlignY = AlignY(1.0);
}