@akiojin/gwt 9.0.4 → 9.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.ja.md +106 -146
- package/README.md +103 -143
- package/bin/gwt.cjs +1 -1
- package/package.json +5 -5
- package/rustfmt.toml +0 -2
- package/scripts/check-release-flow.sh +2 -8
- package/scripts/postinstall.js +17 -7
- package/scripts/run-local-backend-tests-on-commit.sh +6 -12
- package/scripts/test-all.sh +1 -5
- package/scripts/check-e2e-coverage-threshold.mjs +0 -238
- package/scripts/run-local-e2e-coverage-on-commit.sh +0 -69
- package/scripts/run-local-e2e-on-commit.sh +0 -60
- package/scripts/verify-ci-node-toolchain.sh +0 -76
- package/scripts/voice-eval.sh +0 -48
- package/vendor/ratatui-core/src/backend/test.rs +0 -1077
- package/vendor/ratatui-core/src/backend.rs +0 -405
- package/vendor/ratatui-core/src/buffer/assert.rs +0 -71
- package/vendor/ratatui-core/src/buffer/buffer.rs +0 -1388
- package/vendor/ratatui-core/src/buffer/cell.rs +0 -377
- package/vendor/ratatui-core/src/buffer.rs +0 -9
- package/vendor/ratatui-core/src/layout/alignment.rs +0 -89
- package/vendor/ratatui-core/src/layout/constraint.rs +0 -526
- package/vendor/ratatui-core/src/layout/direction.rs +0 -63
- package/vendor/ratatui-core/src/layout/flex.rs +0 -212
- package/vendor/ratatui-core/src/layout/layout.rs +0 -2838
- package/vendor/ratatui-core/src/layout/margin.rs +0 -79
- package/vendor/ratatui-core/src/layout/offset.rs +0 -66
- package/vendor/ratatui-core/src/layout/position.rs +0 -253
- package/vendor/ratatui-core/src/layout/rect/iter.rs +0 -356
- package/vendor/ratatui-core/src/layout/rect/ops.rs +0 -136
- package/vendor/ratatui-core/src/layout/rect.rs +0 -1114
- package/vendor/ratatui-core/src/layout/size.rs +0 -147
- package/vendor/ratatui-core/src/layout.rs +0 -333
- package/vendor/ratatui-core/src/lib.rs +0 -82
- package/vendor/ratatui-core/src/style/anstyle.rs +0 -348
- package/vendor/ratatui-core/src/style/color.rs +0 -788
- package/vendor/ratatui-core/src/style/palette/material.rs +0 -608
- package/vendor/ratatui-core/src/style/palette/tailwind.rs +0 -653
- package/vendor/ratatui-core/src/style/palette.rs +0 -6
- package/vendor/ratatui-core/src/style/palette_conversion.rs +0 -82
- package/vendor/ratatui-core/src/style/stylize.rs +0 -668
- package/vendor/ratatui-core/src/style.rs +0 -1069
- package/vendor/ratatui-core/src/symbols/bar.rs +0 -51
- package/vendor/ratatui-core/src/symbols/block.rs +0 -51
- package/vendor/ratatui-core/src/symbols/border.rs +0 -709
- package/vendor/ratatui-core/src/symbols/braille.rs +0 -21
- package/vendor/ratatui-core/src/symbols/half_block.rs +0 -3
- package/vendor/ratatui-core/src/symbols/line.rs +0 -259
- package/vendor/ratatui-core/src/symbols/marker.rs +0 -82
- package/vendor/ratatui-core/src/symbols/merge.rs +0 -748
- package/vendor/ratatui-core/src/symbols/pixel.rs +0 -30
- package/vendor/ratatui-core/src/symbols/scrollbar.rs +0 -46
- package/vendor/ratatui-core/src/symbols/shade.rs +0 -5
- package/vendor/ratatui-core/src/symbols.rs +0 -15
- package/vendor/ratatui-core/src/terminal/frame.rs +0 -192
- package/vendor/ratatui-core/src/terminal/terminal.rs +0 -926
- package/vendor/ratatui-core/src/terminal/viewport.rs +0 -58
- package/vendor/ratatui-core/src/terminal.rs +0 -40
- package/vendor/ratatui-core/src/text/grapheme.rs +0 -84
- package/vendor/ratatui-core/src/text/line.rs +0 -1678
- package/vendor/ratatui-core/src/text/masked.rs +0 -149
- package/vendor/ratatui-core/src/text/span.rs +0 -904
- package/vendor/ratatui-core/src/text/text.rs +0 -1434
- package/vendor/ratatui-core/src/text.rs +0 -64
- package/vendor/ratatui-core/src/widgets/stateful_widget.rs +0 -193
- package/vendor/ratatui-core/src/widgets/widget.rs +0 -174
- package/vendor/ratatui-core/src/widgets.rs +0 -9
|
@@ -1,2838 +0,0 @@
|
|
|
1
|
-
use alloc::rc::Rc;
|
|
2
|
-
use alloc::vec::Vec;
|
|
3
|
-
use core::array::TryFromSliceError;
|
|
4
|
-
use core::iter;
|
|
5
|
-
#[cfg(feature = "layout-cache")]
|
|
6
|
-
use core::num::NonZeroUsize;
|
|
7
|
-
|
|
8
|
-
use hashbrown::HashMap;
|
|
9
|
-
use itertools::Itertools;
|
|
10
|
-
use kasuari::WeightedRelation::{EQ, GE, LE};
|
|
11
|
-
use kasuari::{AddConstraintError, Expression, Solver, Strength, Variable};
|
|
12
|
-
#[cfg(feature = "layout-cache")]
|
|
13
|
-
use lru::LruCache;
|
|
14
|
-
|
|
15
|
-
use self::strengths::{
|
|
16
|
-
ALL_SEGMENT_GROW, FILL_GROW, GROW, LENGTH_SIZE_EQ, MAX_SIZE_EQ, MAX_SIZE_LE, MIN_SIZE_EQ,
|
|
17
|
-
MIN_SIZE_GE, PERCENTAGE_SIZE_EQ, RATIO_SIZE_EQ, SPACE_GROW, SPACER_SIZE_EQ,
|
|
18
|
-
};
|
|
19
|
-
use crate::layout::{Constraint, Direction, Flex, Margin, Rect};
|
|
20
|
-
|
|
21
|
-
type Rects = Rc<[Rect]>;
|
|
22
|
-
type Segments = Rects;
|
|
23
|
-
type Spacers = Rects;
|
|
24
|
-
// The solution to a Layout solve contains two `Rects`, where `Rects` is effectively a `[Rect]`.
|
|
25
|
-
//
|
|
26
|
-
// 1. `[Rect]` that contains positions for the segments corresponding to user provided constraints
|
|
27
|
-
// 2. `[Rect]` that contains spacers around the user provided constraints
|
|
28
|
-
//
|
|
29
|
-
// <------------------------------------80 px------------------------------------->
|
|
30
|
-
// ┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐
|
|
31
|
-
// 1 │ a │ 2 │ b │ 3 │ c │ 4
|
|
32
|
-
// └ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘
|
|
33
|
-
//
|
|
34
|
-
// Number of spacers will always be one more than number of segments.
|
|
35
|
-
#[cfg(feature = "layout-cache")]
|
|
36
|
-
type Cache = LruCache<(Rect, Layout), (Segments, Spacers)>;
|
|
37
|
-
|
|
38
|
-
// Multiplier that decides floating point precision when rounding.
|
|
39
|
-
// The number of zeros in this number is the precision for the rounding of f64 to u16 in layout
|
|
40
|
-
// calculations.
|
|
41
|
-
const FLOAT_PRECISION_MULTIPLIER: f64 = 100.0;
|
|
42
|
-
|
|
43
|
-
#[cfg(feature = "layout-cache")]
|
|
44
|
-
std::thread_local! {
|
|
45
|
-
static LAYOUT_CACHE: core::cell::RefCell<Cache> = core::cell::RefCell::new(Cache::new(
|
|
46
|
-
NonZeroUsize::new(Layout::DEFAULT_CACHE_SIZE).unwrap(),
|
|
47
|
-
));
|
|
48
|
-
}
|
|
49
|
-
|
|
50
|
-
/// Represents the spacing between segments in a layout.
|
|
51
|
-
///
|
|
52
|
-
/// The `Spacing` enum is used to define the spacing between segments in a layout. It can represent
|
|
53
|
-
/// either positive spacing (space between segments) or negative spacing (overlap between segments).
|
|
54
|
-
///
|
|
55
|
-
/// # Variants
|
|
56
|
-
///
|
|
57
|
-
/// - `Space(u16)`: Represents positive spacing between segments. The value indicates the number of
|
|
58
|
-
/// cells.
|
|
59
|
-
/// - `Overlap(u16)`: Represents negative spacing, causing overlap between segments. The value
|
|
60
|
-
/// indicates the number of overlapping cells.
|
|
61
|
-
///
|
|
62
|
-
/// # Default
|
|
63
|
-
///
|
|
64
|
-
/// The default value for `Spacing` is `Space(0)`, which means no spacing or no overlap between
|
|
65
|
-
/// segments.
|
|
66
|
-
///
|
|
67
|
-
/// # Conversions
|
|
68
|
-
///
|
|
69
|
-
/// The `Spacing` enum can be created from different integer types:
|
|
70
|
-
///
|
|
71
|
-
/// - From `u16`: Directly converts the value to `Spacing::Space`.
|
|
72
|
-
/// - From `i16`: Converts negative values to `Spacing::Overlap` and non-negative values to
|
|
73
|
-
/// `Spacing::Space`.
|
|
74
|
-
/// - From `i32`: Clamps the value to the range of `i16` and converts negative values to
|
|
75
|
-
/// `Spacing::Overlap` and non-negative values to `Spacing::Space`.
|
|
76
|
-
///
|
|
77
|
-
/// See the [`Layout::spacing`] method for details on how to use this enum.
|
|
78
|
-
#[derive(Debug, Clone, Eq, PartialEq, Hash)]
|
|
79
|
-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
80
|
-
pub enum Spacing {
|
|
81
|
-
Space(u16),
|
|
82
|
-
Overlap(u16),
|
|
83
|
-
}
|
|
84
|
-
|
|
85
|
-
impl Default for Spacing {
|
|
86
|
-
fn default() -> Self {
|
|
87
|
-
Self::Space(0)
|
|
88
|
-
}
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
impl From<i32> for Spacing {
|
|
92
|
-
fn from(value: i32) -> Self {
|
|
93
|
-
Self::from(value.clamp(i32::from(i16::MIN), i32::from(i16::MAX)) as i16)
|
|
94
|
-
}
|
|
95
|
-
}
|
|
96
|
-
|
|
97
|
-
impl From<u16> for Spacing {
|
|
98
|
-
fn from(value: u16) -> Self {
|
|
99
|
-
Self::Space(value)
|
|
100
|
-
}
|
|
101
|
-
}
|
|
102
|
-
|
|
103
|
-
impl From<i16> for Spacing {
|
|
104
|
-
fn from(value: i16) -> Self {
|
|
105
|
-
if value < 0 {
|
|
106
|
-
Self::Overlap(value.unsigned_abs())
|
|
107
|
-
} else {
|
|
108
|
-
Self::Space(value.unsigned_abs())
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
/// The primary layout engine for dividing terminal space using constraints and direction.
|
|
114
|
-
///
|
|
115
|
-
/// A layout is a set of constraints that can be applied to a given area to split it into smaller
|
|
116
|
-
/// rectangular areas. This is the core building block for creating structured user interfaces in
|
|
117
|
-
/// terminal applications.
|
|
118
|
-
///
|
|
119
|
-
/// A layout is composed of:
|
|
120
|
-
/// - a direction (horizontal or vertical)
|
|
121
|
-
/// - a set of constraints (length, ratio, percentage, fill, min, max)
|
|
122
|
-
/// - a margin (horizontal and vertical), the space between the edge of the main area and the split
|
|
123
|
-
/// areas
|
|
124
|
-
/// - a flex option that controls space distribution
|
|
125
|
-
/// - a spacing option that controls gaps between segments
|
|
126
|
-
///
|
|
127
|
-
/// The algorithm used to compute the layout is based on the [`kasuari`] solver, a linear constraint
|
|
128
|
-
/// solver that computes positions and sizes to satisfy as many constraints as possible in order of
|
|
129
|
-
/// their priorities.
|
|
130
|
-
///
|
|
131
|
-
/// When the layout is computed, the result is cached in a thread-local cache, so that subsequent
|
|
132
|
-
/// calls with the same parameters are faster. The cache is a `LruCache`, and the size of the cache
|
|
133
|
-
/// can be configured using [`Layout::init_cache()`] when the `layout-cache` feature is enabled.
|
|
134
|
-
///
|
|
135
|
-
/// # Construction
|
|
136
|
-
///
|
|
137
|
-
/// - [`default`](Default::default) - Create a layout with default values (vertical direction, no
|
|
138
|
-
/// constraints, no margin)
|
|
139
|
-
/// - [`new`](Self::new) - Create a new layout with a given direction and constraints
|
|
140
|
-
/// - [`vertical`](Self::vertical) - Create a new vertical layout with the given constraints
|
|
141
|
-
/// - [`horizontal`](Self::horizontal) - Create a new horizontal layout with the given constraints
|
|
142
|
-
///
|
|
143
|
-
/// # Configuration
|
|
144
|
-
///
|
|
145
|
-
/// - [`direction`](Self::direction) - Set the direction of the layout
|
|
146
|
-
/// - [`constraints`](Self::constraints) - Set the constraints of the layout
|
|
147
|
-
/// - [`margin`](Self::margin) - Set uniform margin on all sides
|
|
148
|
-
/// - [`horizontal_margin`](Self::horizontal_margin) - Set the horizontal margin of the layout
|
|
149
|
-
/// - [`vertical_margin`](Self::vertical_margin) - Set the vertical margin of the layout
|
|
150
|
-
/// - [`flex`](Self::flex) - Set the way space is distributed when constraints are satisfied
|
|
151
|
-
/// - [`spacing`](Self::spacing) - Set the gap between the constraints of the layout
|
|
152
|
-
///
|
|
153
|
-
/// # Layout Operations
|
|
154
|
-
///
|
|
155
|
-
/// - [`areas`](Self::areas) - Split area into fixed number of rectangles (compile-time known)
|
|
156
|
-
/// - [`spacers`](Self::spacers) - Get spacer rectangles between layout areas
|
|
157
|
-
/// - [`split`](Self::split) - Split area into rectangles (runtime determined count)
|
|
158
|
-
/// - [`split_with_spacers`](Self::split_with_spacers) - Split area and return both areas and
|
|
159
|
-
/// spacers
|
|
160
|
-
///
|
|
161
|
-
/// # Cache Management
|
|
162
|
-
///
|
|
163
|
-
/// - [`init_cache`](Self::init_cache) - Initialize layout cache with custom size
|
|
164
|
-
///
|
|
165
|
-
/// # Example
|
|
166
|
-
///
|
|
167
|
-
/// ```rust
|
|
168
|
-
/// use ratatui_core::buffer::Buffer;
|
|
169
|
-
/// use ratatui_core::layout::{Constraint, Direction, Layout, Rect};
|
|
170
|
-
/// use ratatui_core::text::Text;
|
|
171
|
-
/// use ratatui_core::widgets::Widget;
|
|
172
|
-
///
|
|
173
|
-
/// fn render(area: Rect, buf: &mut Buffer) {
|
|
174
|
-
/// let layout = Layout::vertical([Constraint::Length(5), Constraint::Fill(1)]);
|
|
175
|
-
/// let [top, bottom] = layout.areas(area);
|
|
176
|
-
/// Text::from("foo").render(top, buf);
|
|
177
|
-
/// Text::from("bar").render(bottom, buf);
|
|
178
|
-
/// }
|
|
179
|
-
/// ```
|
|
180
|
-
///
|
|
181
|
-
/// See the `layout`, `flex`, and `constraints` examples in the [Examples] folder for more details
|
|
182
|
-
/// about how to use layouts.
|
|
183
|
-
///
|
|
184
|
-
/// For comprehensive layout documentation and examples, see the [`layout`](crate::layout) module.
|
|
185
|
-
///
|
|
186
|
-
/// 
|
|
188
|
-
///
|
|
189
|
-
/// [`kasuari`]: https://crates.io/crates/kasuari
|
|
190
|
-
/// [Examples]: https://github.com/ratatui/ratatui/blob/main/examples/README.md
|
|
191
|
-
#[derive(Debug, Default, Clone, Eq, PartialEq, Hash)]
|
|
192
|
-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
193
|
-
pub struct Layout {
|
|
194
|
-
direction: Direction,
|
|
195
|
-
constraints: Vec<Constraint>,
|
|
196
|
-
margin: Margin,
|
|
197
|
-
flex: Flex,
|
|
198
|
-
spacing: Spacing,
|
|
199
|
-
}
|
|
200
|
-
|
|
201
|
-
impl Layout {
|
|
202
|
-
/// This is a somewhat arbitrary size for the layout cache based on adding the columns and rows
|
|
203
|
-
/// on my laptop's terminal (171+51 = 222) and doubling it for good measure and then adding a
|
|
204
|
-
/// bit more to make it a round number. This gives enough entries to store a layout for every
|
|
205
|
-
/// row and every column, twice over, which should be enough for most apps. For those that need
|
|
206
|
-
/// more, the cache size can be set with `Layout::init_cache()` (requires the `layout-cache`
|
|
207
|
-
/// feature).
|
|
208
|
-
#[cfg(feature = "layout-cache")]
|
|
209
|
-
pub const DEFAULT_CACHE_SIZE: usize = 500;
|
|
210
|
-
|
|
211
|
-
/// Creates a new layout with default values.
|
|
212
|
-
///
|
|
213
|
-
/// The `constraints` parameter accepts any type that implements `IntoIterator<Item =
|
|
214
|
-
/// Into<Constraint>>`. This includes arrays, slices, vectors, iterators. `Into<Constraint>` is
|
|
215
|
-
/// implemented on `u16`, so you can pass an array, `Vec`, etc. of `u16` to this function to
|
|
216
|
-
/// create a layout with fixed size chunks.
|
|
217
|
-
///
|
|
218
|
-
/// Default values for the other fields are:
|
|
219
|
-
///
|
|
220
|
-
/// - `margin`: 0, 0
|
|
221
|
-
/// - `flex`: [`Flex::Start`]
|
|
222
|
-
/// - `spacing`: 0
|
|
223
|
-
///
|
|
224
|
-
/// # Examples
|
|
225
|
-
///
|
|
226
|
-
/// ```rust
|
|
227
|
-
/// use ratatui_core::layout::{Constraint, Direction, Layout};
|
|
228
|
-
///
|
|
229
|
-
/// Layout::new(
|
|
230
|
-
/// Direction::Horizontal,
|
|
231
|
-
/// [Constraint::Length(5), Constraint::Fill(1)],
|
|
232
|
-
/// );
|
|
233
|
-
///
|
|
234
|
-
/// Layout::new(
|
|
235
|
-
/// Direction::Vertical,
|
|
236
|
-
/// [1, 2, 3].iter().map(|&c| Constraint::Length(c)),
|
|
237
|
-
/// );
|
|
238
|
-
///
|
|
239
|
-
/// Layout::new(Direction::Horizontal, vec![1, 2]);
|
|
240
|
-
/// ```
|
|
241
|
-
pub fn new<I>(direction: Direction, constraints: I) -> Self
|
|
242
|
-
where
|
|
243
|
-
I: IntoIterator,
|
|
244
|
-
I::Item: Into<Constraint>,
|
|
245
|
-
{
|
|
246
|
-
Self {
|
|
247
|
-
direction,
|
|
248
|
-
constraints: constraints.into_iter().map(Into::into).collect(),
|
|
249
|
-
..Self::default()
|
|
250
|
-
}
|
|
251
|
-
}
|
|
252
|
-
|
|
253
|
-
/// Creates a new vertical layout with default values.
|
|
254
|
-
///
|
|
255
|
-
/// The `constraints` parameter accepts any type that implements `IntoIterator<Item =
|
|
256
|
-
/// Into<Constraint>>`. This includes arrays, slices, vectors, iterators, etc.
|
|
257
|
-
///
|
|
258
|
-
/// # Examples
|
|
259
|
-
///
|
|
260
|
-
/// ```rust
|
|
261
|
-
/// use ratatui_core::layout::{Constraint, Layout};
|
|
262
|
-
///
|
|
263
|
-
/// let layout = Layout::vertical([Constraint::Length(5), Constraint::Fill(1)]);
|
|
264
|
-
/// ```
|
|
265
|
-
pub fn vertical<I>(constraints: I) -> Self
|
|
266
|
-
where
|
|
267
|
-
I: IntoIterator,
|
|
268
|
-
I::Item: Into<Constraint>,
|
|
269
|
-
{
|
|
270
|
-
Self::new(Direction::Vertical, constraints.into_iter().map(Into::into))
|
|
271
|
-
}
|
|
272
|
-
|
|
273
|
-
/// Creates a new horizontal layout with default values.
|
|
274
|
-
///
|
|
275
|
-
/// The `constraints` parameter accepts any type that implements `IntoIterator<Item =
|
|
276
|
-
/// Into<Constraint>>`. This includes arrays, slices, vectors, iterators, etc.
|
|
277
|
-
///
|
|
278
|
-
/// # Examples
|
|
279
|
-
///
|
|
280
|
-
/// ```rust
|
|
281
|
-
/// use ratatui_core::layout::{Constraint, Layout};
|
|
282
|
-
///
|
|
283
|
-
/// let layout = Layout::horizontal([Constraint::Length(5), Constraint::Fill(1)]);
|
|
284
|
-
/// ```
|
|
285
|
-
pub fn horizontal<I>(constraints: I) -> Self
|
|
286
|
-
where
|
|
287
|
-
I: IntoIterator,
|
|
288
|
-
I::Item: Into<Constraint>,
|
|
289
|
-
{
|
|
290
|
-
Self::new(
|
|
291
|
-
Direction::Horizontal,
|
|
292
|
-
constraints.into_iter().map(Into::into),
|
|
293
|
-
)
|
|
294
|
-
}
|
|
295
|
-
|
|
296
|
-
/// Initialize an empty cache with a custom size. The cache is keyed on the layout and area, so
|
|
297
|
-
/// that subsequent calls with the same parameters are faster. The cache is a `LruCache`, and
|
|
298
|
-
/// grows until `cache_size` is reached.
|
|
299
|
-
///
|
|
300
|
-
/// By default, the cache size is [`Self::DEFAULT_CACHE_SIZE`].
|
|
301
|
-
#[cfg(feature = "layout-cache")]
|
|
302
|
-
pub fn init_cache(cache_size: NonZeroUsize) {
|
|
303
|
-
LAYOUT_CACHE.with_borrow_mut(|cache| cache.resize(cache_size));
|
|
304
|
-
}
|
|
305
|
-
|
|
306
|
-
/// Set the direction of the layout.
|
|
307
|
-
///
|
|
308
|
-
/// # Examples
|
|
309
|
-
///
|
|
310
|
-
/// ```rust
|
|
311
|
-
/// use ratatui_core::layout::{Constraint, Direction, Layout, Rect};
|
|
312
|
-
///
|
|
313
|
-
/// let layout = Layout::default()
|
|
314
|
-
/// .direction(Direction::Horizontal)
|
|
315
|
-
/// .constraints([Constraint::Length(5), Constraint::Fill(1)])
|
|
316
|
-
/// .split(Rect::new(0, 0, 10, 10));
|
|
317
|
-
/// assert_eq!(layout[..], [Rect::new(0, 0, 5, 10), Rect::new(5, 0, 5, 10)]);
|
|
318
|
-
///
|
|
319
|
-
/// let layout = Layout::default()
|
|
320
|
-
/// .direction(Direction::Vertical)
|
|
321
|
-
/// .constraints([Constraint::Length(5), Constraint::Fill(1)])
|
|
322
|
-
/// .split(Rect::new(0, 0, 10, 10));
|
|
323
|
-
/// assert_eq!(layout[..], [Rect::new(0, 0, 10, 5), Rect::new(0, 5, 10, 5)]);
|
|
324
|
-
/// ```
|
|
325
|
-
#[must_use = "method moves the value of self and returns the modified value"]
|
|
326
|
-
pub const fn direction(mut self, direction: Direction) -> Self {
|
|
327
|
-
self.direction = direction;
|
|
328
|
-
self
|
|
329
|
-
}
|
|
330
|
-
|
|
331
|
-
/// Sets the constraints of the layout.
|
|
332
|
-
///
|
|
333
|
-
/// The `constraints` parameter accepts any type that implements `IntoIterator<Item =
|
|
334
|
-
/// Into<Constraint>>`. This includes arrays, slices, vectors, iterators. `Into<Constraint>` is
|
|
335
|
-
/// implemented on u16, so you can pass an array or vec of u16 to this function to create a
|
|
336
|
-
/// layout with fixed size chunks.
|
|
337
|
-
///
|
|
338
|
-
/// Note that the constraints are applied to the whole area that is to be split, so using
|
|
339
|
-
/// percentages and ratios with the other constraints may not have the desired effect of
|
|
340
|
-
/// splitting the area up. (e.g. splitting 100 into [min 20, 50%, 50%], may not result in [20,
|
|
341
|
-
/// 40, 40] but rather an indeterminate result between [20, 50, 30] and [20, 30, 50]).
|
|
342
|
-
///
|
|
343
|
-
/// # Examples
|
|
344
|
-
///
|
|
345
|
-
/// ```rust
|
|
346
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
347
|
-
///
|
|
348
|
-
/// let layout = Layout::default()
|
|
349
|
-
/// .constraints([
|
|
350
|
-
/// Constraint::Percentage(20),
|
|
351
|
-
/// Constraint::Ratio(1, 5),
|
|
352
|
-
/// Constraint::Length(2),
|
|
353
|
-
/// Constraint::Min(2),
|
|
354
|
-
/// Constraint::Max(2),
|
|
355
|
-
/// ])
|
|
356
|
-
/// .split(Rect::new(0, 0, 10, 10));
|
|
357
|
-
/// assert_eq!(
|
|
358
|
-
/// layout[..],
|
|
359
|
-
/// [
|
|
360
|
-
/// Rect::new(0, 0, 10, 2),
|
|
361
|
-
/// Rect::new(0, 2, 10, 2),
|
|
362
|
-
/// Rect::new(0, 4, 10, 2),
|
|
363
|
-
/// Rect::new(0, 6, 10, 2),
|
|
364
|
-
/// Rect::new(0, 8, 10, 2),
|
|
365
|
-
/// ]
|
|
366
|
-
/// );
|
|
367
|
-
///
|
|
368
|
-
/// Layout::default().constraints([Constraint::Fill(1)]);
|
|
369
|
-
/// Layout::default().constraints(&[Constraint::Fill(1)]);
|
|
370
|
-
/// Layout::default().constraints(vec![Constraint::Fill(1)]);
|
|
371
|
-
/// Layout::default().constraints([Constraint::Fill(1)].iter().filter(|_| true));
|
|
372
|
-
/// Layout::default().constraints([1, 2, 3].iter().map(|&c| Constraint::Length(c)));
|
|
373
|
-
/// Layout::default().constraints([1, 2, 3]);
|
|
374
|
-
/// Layout::default().constraints(vec![1, 2, 3]);
|
|
375
|
-
/// ```
|
|
376
|
-
#[must_use = "method moves the value of self and returns the modified value"]
|
|
377
|
-
pub fn constraints<I>(mut self, constraints: I) -> Self
|
|
378
|
-
where
|
|
379
|
-
I: IntoIterator,
|
|
380
|
-
I::Item: Into<Constraint>,
|
|
381
|
-
{
|
|
382
|
-
self.constraints = constraints.into_iter().map(Into::into).collect();
|
|
383
|
-
self
|
|
384
|
-
}
|
|
385
|
-
|
|
386
|
-
/// Set the margin of the layout.
|
|
387
|
-
///
|
|
388
|
-
/// # Examples
|
|
389
|
-
///
|
|
390
|
-
/// ```rust
|
|
391
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
392
|
-
///
|
|
393
|
-
/// let layout = Layout::default()
|
|
394
|
-
/// .constraints([Constraint::Fill(1)])
|
|
395
|
-
/// .margin(2)
|
|
396
|
-
/// .split(Rect::new(0, 0, 10, 10));
|
|
397
|
-
/// assert_eq!(layout[..], [Rect::new(2, 2, 6, 6)]);
|
|
398
|
-
/// ```
|
|
399
|
-
#[must_use = "method moves the value of self and returns the modified value"]
|
|
400
|
-
pub const fn margin(mut self, margin: u16) -> Self {
|
|
401
|
-
self.margin = Margin {
|
|
402
|
-
horizontal: margin,
|
|
403
|
-
vertical: margin,
|
|
404
|
-
};
|
|
405
|
-
self
|
|
406
|
-
}
|
|
407
|
-
|
|
408
|
-
/// Set the horizontal margin of the layout.
|
|
409
|
-
///
|
|
410
|
-
/// # Examples
|
|
411
|
-
///
|
|
412
|
-
/// ```rust
|
|
413
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
414
|
-
///
|
|
415
|
-
/// let layout = Layout::default()
|
|
416
|
-
/// .constraints([Constraint::Fill(1)])
|
|
417
|
-
/// .horizontal_margin(2)
|
|
418
|
-
/// .split(Rect::new(0, 0, 10, 10));
|
|
419
|
-
/// assert_eq!(layout[..], [Rect::new(2, 0, 6, 10)]);
|
|
420
|
-
/// ```
|
|
421
|
-
#[must_use = "method moves the value of self and returns the modified value"]
|
|
422
|
-
pub const fn horizontal_margin(mut self, horizontal: u16) -> Self {
|
|
423
|
-
self.margin.horizontal = horizontal;
|
|
424
|
-
self
|
|
425
|
-
}
|
|
426
|
-
|
|
427
|
-
/// Set the vertical margin of the layout.
|
|
428
|
-
///
|
|
429
|
-
/// # Examples
|
|
430
|
-
///
|
|
431
|
-
/// ```rust
|
|
432
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
433
|
-
///
|
|
434
|
-
/// let layout = Layout::default()
|
|
435
|
-
/// .constraints([Constraint::Fill(1)])
|
|
436
|
-
/// .vertical_margin(2)
|
|
437
|
-
/// .split(Rect::new(0, 0, 10, 10));
|
|
438
|
-
/// assert_eq!(layout[..], [Rect::new(0, 2, 10, 6)]);
|
|
439
|
-
/// ```
|
|
440
|
-
#[must_use = "method moves the value of self and returns the modified value"]
|
|
441
|
-
pub const fn vertical_margin(mut self, vertical: u16) -> Self {
|
|
442
|
-
self.margin.vertical = vertical;
|
|
443
|
-
self
|
|
444
|
-
}
|
|
445
|
-
|
|
446
|
-
/// The `flex` method allows you to specify the flex behavior of the layout.
|
|
447
|
-
///
|
|
448
|
-
/// # Arguments
|
|
449
|
-
///
|
|
450
|
-
/// * `flex`: A [`Flex`] enum value that represents the flex behavior of the layout. It can be
|
|
451
|
-
/// one of the following:
|
|
452
|
-
/// - [`Flex::Legacy`]: The last item is stretched to fill the excess space.
|
|
453
|
-
/// - [`Flex::Start`]: The items are aligned to the start of the layout.
|
|
454
|
-
/// - [`Flex::Center`]: The items are aligned to the center of the layout.
|
|
455
|
-
/// - [`Flex::End`]: The items are aligned to the end of the layout.
|
|
456
|
-
/// - [`Flex::SpaceBetween`]: The items are evenly distributed with equal space between them.
|
|
457
|
-
/// - [`Flex::SpaceAround`]: The items are evenly distributed with equal space around them,
|
|
458
|
-
/// except the first and last items, which have half the space on their sides.
|
|
459
|
-
/// - [`Flex::SpaceEvenly`]: The items are evenly distributed with equal space around them.
|
|
460
|
-
///
|
|
461
|
-
/// # Examples
|
|
462
|
-
///
|
|
463
|
-
/// In this example, the items in the layout will be aligned to the start.
|
|
464
|
-
///
|
|
465
|
-
/// ```rust
|
|
466
|
-
/// use ratatui_core::layout::Constraint::*;
|
|
467
|
-
/// use ratatui_core::layout::{Flex, Layout};
|
|
468
|
-
///
|
|
469
|
-
/// let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).flex(Flex::Start);
|
|
470
|
-
/// ```
|
|
471
|
-
///
|
|
472
|
-
/// In this example, the items in the layout will be stretched equally to fill the available
|
|
473
|
-
/// space.
|
|
474
|
-
///
|
|
475
|
-
/// ```rust
|
|
476
|
-
/// use ratatui_core::layout::Constraint::*;
|
|
477
|
-
/// use ratatui_core::layout::{Flex, Layout};
|
|
478
|
-
///
|
|
479
|
-
/// let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).flex(Flex::Legacy);
|
|
480
|
-
/// ```
|
|
481
|
-
#[must_use = "method moves the value of self and returns the modified value"]
|
|
482
|
-
pub const fn flex(mut self, flex: Flex) -> Self {
|
|
483
|
-
self.flex = flex;
|
|
484
|
-
self
|
|
485
|
-
}
|
|
486
|
-
|
|
487
|
-
/// Sets the spacing between items in the layout.
|
|
488
|
-
///
|
|
489
|
-
/// The `spacing` method sets the spacing between items in the layout. The spacing is applied
|
|
490
|
-
/// evenly between all segments. The spacing value represents the number of cells between each
|
|
491
|
-
/// item.
|
|
492
|
-
///
|
|
493
|
-
/// Spacing can be positive integers, representing gaps between segments; or negative integers
|
|
494
|
-
/// representing overlaps. Additionally, one of the variants of the [`Spacing`] enum can be
|
|
495
|
-
/// passed to this function. See the documentation of the [`Spacing`] enum for more information.
|
|
496
|
-
///
|
|
497
|
-
/// Note that if the layout has only one segment, the spacing will not be applied.
|
|
498
|
-
/// Also, spacing will not be applied for [`Flex::SpaceAround`], [`Flex::SpaceEvenly`] and
|
|
499
|
-
/// [`Flex::SpaceBetween`]
|
|
500
|
-
///
|
|
501
|
-
/// # Examples
|
|
502
|
-
///
|
|
503
|
-
/// In this example, the spacing between each item in the layout is set to 2 cells.
|
|
504
|
-
///
|
|
505
|
-
/// ```rust
|
|
506
|
-
/// use ratatui_core::layout::Constraint::*;
|
|
507
|
-
/// use ratatui_core::layout::Layout;
|
|
508
|
-
///
|
|
509
|
-
/// let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).spacing(2);
|
|
510
|
-
/// ```
|
|
511
|
-
///
|
|
512
|
-
/// In this example, the spacing between each item in the layout is set to -1 cells, i.e. the
|
|
513
|
-
/// three segments will have an overlapping border.
|
|
514
|
-
///
|
|
515
|
-
/// ```rust
|
|
516
|
-
/// use ratatui_core::layout::Constraint::*;
|
|
517
|
-
/// use ratatui_core::layout::Layout;
|
|
518
|
-
/// let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).spacing(-1);
|
|
519
|
-
/// ```
|
|
520
|
-
#[must_use = "method moves the value of self and returns the modified value"]
|
|
521
|
-
pub fn spacing<T>(mut self, spacing: T) -> Self
|
|
522
|
-
where
|
|
523
|
-
T: Into<Spacing>,
|
|
524
|
-
{
|
|
525
|
-
self.spacing = spacing.into();
|
|
526
|
-
self
|
|
527
|
-
}
|
|
528
|
-
|
|
529
|
-
/// Split the rect into a number of sub-rects according to the given [`Layout`].
|
|
530
|
-
///
|
|
531
|
-
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
|
|
532
|
-
/// `Rc<[Rect]>`.
|
|
533
|
-
///
|
|
534
|
-
/// This method requires the number of constraints to be known at compile time. If you don't
|
|
535
|
-
/// know the number of constraints at compile time, use [`Layout::split`] instead.
|
|
536
|
-
///
|
|
537
|
-
/// # Panics
|
|
538
|
-
///
|
|
539
|
-
/// Panics if the number of constraints is not equal to the length of the returned array.
|
|
540
|
-
///
|
|
541
|
-
/// # Examples
|
|
542
|
-
///
|
|
543
|
-
/// ```rust
|
|
544
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
545
|
-
///
|
|
546
|
-
/// let area = Rect::new(0, 0, 10, 10);
|
|
547
|
-
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
|
548
|
-
/// let [top, main] = layout.areas(area);
|
|
549
|
-
///
|
|
550
|
-
/// // or explicitly specify the number of constraints:
|
|
551
|
-
/// let areas = layout.areas::<2>(area);
|
|
552
|
-
/// ```
|
|
553
|
-
pub fn areas<const N: usize>(&self, area: Rect) -> [Rect; N] {
|
|
554
|
-
let areas = self.split(area);
|
|
555
|
-
areas.as_ref().try_into().unwrap_or_else(|_| {
|
|
556
|
-
panic!(
|
|
557
|
-
"invalid number of rects: expected {N}, found {}",
|
|
558
|
-
areas.len()
|
|
559
|
-
)
|
|
560
|
-
})
|
|
561
|
-
}
|
|
562
|
-
|
|
563
|
-
/// Split the rect into a number of sub-rects according to the given [`Layout`].
|
|
564
|
-
///
|
|
565
|
-
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
|
|
566
|
-
/// `Rc<[Rect]>`.
|
|
567
|
-
///
|
|
568
|
-
/// This method requires the number of constraints to be known at compile time. If you don't
|
|
569
|
-
/// know the number of constraints at compile time, use [`Layout::split`] instead.
|
|
570
|
-
///
|
|
571
|
-
/// # Errors
|
|
572
|
-
///
|
|
573
|
-
/// Returns an error if the number of constraints is not equal to the length of the returned
|
|
574
|
-
/// array.
|
|
575
|
-
///
|
|
576
|
-
/// # Examples
|
|
577
|
-
///
|
|
578
|
-
/// ```rust
|
|
579
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
580
|
-
///
|
|
581
|
-
/// let area = Rect::new(0, 0, 10, 10);
|
|
582
|
-
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
|
583
|
-
/// let [top, main] = layout.try_areas(area)?;
|
|
584
|
-
///
|
|
585
|
-
/// // or explicitly specify the number of constraints:
|
|
586
|
-
/// let areas = layout.try_areas::<2>(area)?;
|
|
587
|
-
/// # Ok::<(), core::array::TryFromSliceError>(())
|
|
588
|
-
/// ```
|
|
589
|
-
pub fn try_areas<const N: usize>(&self, area: Rect) -> Result<[Rect; N], TryFromSliceError> {
|
|
590
|
-
self.split(area).as_ref().try_into()
|
|
591
|
-
}
|
|
592
|
-
|
|
593
|
-
/// Split the rect into a number of sub-rects according to the given [`Layout`] and return just
|
|
594
|
-
/// the spacers between the areas.
|
|
595
|
-
///
|
|
596
|
-
/// This method requires the number of constraints to be known at compile time. If you don't
|
|
597
|
-
/// know the number of constraints at compile time, use [`Layout::split_with_spacers`] instead.
|
|
598
|
-
///
|
|
599
|
-
/// This method is similar to [`Layout::areas`], and can be called with the same parameters, but
|
|
600
|
-
/// it returns just the spacers between the areas. The result of calling the `areas` method is
|
|
601
|
-
/// cached, so this will generally not re-run the solver, but will just return the cached
|
|
602
|
-
/// result.
|
|
603
|
-
///
|
|
604
|
-
/// # Panics
|
|
605
|
-
///
|
|
606
|
-
/// Panics if the number of constraints + 1 is not equal to the length of the returned array.
|
|
607
|
-
///
|
|
608
|
-
/// # Examples
|
|
609
|
-
///
|
|
610
|
-
/// ```rust
|
|
611
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
612
|
-
///
|
|
613
|
-
/// let area = Rect::new(0, 0, 10, 10);
|
|
614
|
-
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Fill(1)]);
|
|
615
|
-
/// let [top, main] = layout.areas(area);
|
|
616
|
-
/// let [before, inbetween, after] = layout.spacers(area);
|
|
617
|
-
///
|
|
618
|
-
/// // or explicitly specify the number of constraints:
|
|
619
|
-
/// let spacers = layout.spacers::<3>(area);
|
|
620
|
-
/// ```
|
|
621
|
-
pub fn spacers<const N: usize>(&self, area: Rect) -> [Rect; N] {
|
|
622
|
-
let (_, spacers) = self.split_with_spacers(area);
|
|
623
|
-
spacers
|
|
624
|
-
.as_ref()
|
|
625
|
-
.try_into()
|
|
626
|
-
.expect("invalid number of rects")
|
|
627
|
-
}
|
|
628
|
-
|
|
629
|
-
/// Wrapper function around the [`kasuari`] solver to be able to split a given area into
|
|
630
|
-
/// smaller ones based on the preferred widths or heights and the direction.
|
|
631
|
-
///
|
|
632
|
-
/// Note that the constraints are applied to the whole area that is to be split, so using
|
|
633
|
-
/// percentages and ratios with the other constraints may not have the desired effect of
|
|
634
|
-
/// splitting the area up. (e.g. splitting 100 into [min 20, 50%, 50%], may not result in [20,
|
|
635
|
-
/// 40, 40] but rather an indeterminate result between [20, 50, 30] and [20, 30, 50]).
|
|
636
|
-
///
|
|
637
|
-
/// This method stores the result of the computation in a thread-local cache keyed on the layout
|
|
638
|
-
/// and area, so that subsequent calls with the same parameters are faster. The cache is a
|
|
639
|
-
/// `LruCache`, and grows until [`Self::DEFAULT_CACHE_SIZE`] is reached by default. If the cache
|
|
640
|
-
/// is initialized with [`Layout::init_cache()`], it grows until the initialized cache size.
|
|
641
|
-
///
|
|
642
|
-
/// There is a helper method that can be used to split the whole area into smaller ones based on
|
|
643
|
-
/// the layout: [`Layout::areas()`]. That method is a shortcut for calling this method. It
|
|
644
|
-
/// allows you to destructure the result directly into variables, which is useful when you know
|
|
645
|
-
/// at compile time the number of areas that will be created.
|
|
646
|
-
///
|
|
647
|
-
/// # Examples
|
|
648
|
-
///
|
|
649
|
-
/// ```
|
|
650
|
-
/// use ratatui_core::layout::{Constraint, Direction, Layout, Rect};
|
|
651
|
-
/// let layout = Layout::default()
|
|
652
|
-
/// .direction(Direction::Vertical)
|
|
653
|
-
/// .constraints([Constraint::Length(5), Constraint::Fill(1)])
|
|
654
|
-
/// .split(Rect::new(2, 2, 10, 10));
|
|
655
|
-
/// assert_eq!(layout[..], [Rect::new(2, 2, 10, 5), Rect::new(2, 7, 10, 5)]);
|
|
656
|
-
///
|
|
657
|
-
/// let layout = Layout::default()
|
|
658
|
-
/// .direction(Direction::Horizontal)
|
|
659
|
-
/// .constraints([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)])
|
|
660
|
-
/// .split(Rect::new(0, 0, 9, 2));
|
|
661
|
-
/// assert_eq!(layout[..], [Rect::new(0, 0, 3, 2), Rect::new(3, 0, 6, 2)]);
|
|
662
|
-
/// ```
|
|
663
|
-
pub fn split(&self, area: Rect) -> Rects {
|
|
664
|
-
self.split_with_spacers(area).0
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
/// Wrapper function around the [`kasuari`] solver that splits the given area into smaller ones
|
|
668
|
-
/// based on the preferred widths or heights and the direction, with the ability to include
|
|
669
|
-
/// spacers between the areas.
|
|
670
|
-
///
|
|
671
|
-
/// This method is similar to `split`, but it returns two sets of rectangles: one for the areas
|
|
672
|
-
/// and one for the spacers.
|
|
673
|
-
///
|
|
674
|
-
/// This method stores the result of the computation in a thread-local cache keyed on the layout
|
|
675
|
-
/// and area, so that subsequent calls with the same parameters are faster. The cache is a
|
|
676
|
-
/// `LruCache`, and grows until [`Self::DEFAULT_CACHE_SIZE`] is reached by default. If the cache
|
|
677
|
-
/// is initialized with [`Layout::init_cache()`], it grows until the initialized cache size.
|
|
678
|
-
///
|
|
679
|
-
/// # Examples
|
|
680
|
-
///
|
|
681
|
-
/// ```
|
|
682
|
-
/// use ratatui_core::layout::{Constraint, Direction, Layout, Rect};
|
|
683
|
-
///
|
|
684
|
-
/// let (areas, spacers) = Layout::default()
|
|
685
|
-
/// .direction(Direction::Vertical)
|
|
686
|
-
/// .constraints([Constraint::Length(5), Constraint::Fill(1)])
|
|
687
|
-
/// .split_with_spacers(Rect::new(2, 2, 10, 10));
|
|
688
|
-
/// assert_eq!(areas[..], [Rect::new(2, 2, 10, 5), Rect::new(2, 7, 10, 5)]);
|
|
689
|
-
/// assert_eq!(
|
|
690
|
-
/// spacers[..],
|
|
691
|
-
/// [
|
|
692
|
-
/// Rect::new(2, 2, 10, 0),
|
|
693
|
-
/// Rect::new(2, 7, 10, 0),
|
|
694
|
-
/// Rect::new(2, 12, 10, 0)
|
|
695
|
-
/// ]
|
|
696
|
-
/// );
|
|
697
|
-
///
|
|
698
|
-
/// let (areas, spacers) = Layout::default()
|
|
699
|
-
/// .direction(Direction::Horizontal)
|
|
700
|
-
/// .spacing(1)
|
|
701
|
-
/// .constraints([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)])
|
|
702
|
-
/// .split_with_spacers(Rect::new(0, 0, 10, 2));
|
|
703
|
-
/// assert_eq!(areas[..], [Rect::new(0, 0, 3, 2), Rect::new(4, 0, 6, 2)]);
|
|
704
|
-
/// assert_eq!(
|
|
705
|
-
/// spacers[..],
|
|
706
|
-
/// [
|
|
707
|
-
/// Rect::new(0, 0, 0, 2),
|
|
708
|
-
/// Rect::new(3, 0, 1, 2),
|
|
709
|
-
/// Rect::new(10, 0, 0, 2)
|
|
710
|
-
/// ]
|
|
711
|
-
/// );
|
|
712
|
-
/// ```
|
|
713
|
-
pub fn split_with_spacers(&self, area: Rect) -> (Segments, Spacers) {
|
|
714
|
-
let split = || self.try_split(area).expect("failed to split");
|
|
715
|
-
|
|
716
|
-
#[cfg(feature = "layout-cache")]
|
|
717
|
-
{
|
|
718
|
-
LAYOUT_CACHE.with_borrow_mut(|cache| {
|
|
719
|
-
let key = (area, self.clone());
|
|
720
|
-
cache.get_or_insert(key, split).clone()
|
|
721
|
-
})
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
#[cfg(not(feature = "layout-cache"))]
|
|
725
|
-
split()
|
|
726
|
-
}
|
|
727
|
-
|
|
728
|
-
fn try_split(&self, area: Rect) -> Result<(Segments, Spacers), AddConstraintError> {
|
|
729
|
-
// To take advantage of all of [`kasuari`] features, we would want to store the `Solver` in
|
|
730
|
-
// one of the fields of the Layout struct. And we would want to set it up such that we could
|
|
731
|
-
// add or remove constraints as and when needed.
|
|
732
|
-
// The advantage of doing it as described above is that it would allow users to
|
|
733
|
-
// incrementally add and remove constraints efficiently.
|
|
734
|
-
// Solves will just one constraint different would not need to resolve the entire layout.
|
|
735
|
-
//
|
|
736
|
-
// The disadvantage of this approach is that it requires tracking which constraints were
|
|
737
|
-
// added, and which variables they correspond to.
|
|
738
|
-
// This will also require introducing and maintaining the API for users to do so.
|
|
739
|
-
//
|
|
740
|
-
// Currently we don't support that use case and do not intend to support it in the future,
|
|
741
|
-
// and instead we require that the user re-solve the layout every time they call `split`.
|
|
742
|
-
// To minimize the time it takes to solve the same problem over and over again, we
|
|
743
|
-
// cache the `Layout` struct along with the results.
|
|
744
|
-
//
|
|
745
|
-
// `try_split` is the inner method in `split` that is called only when the LRU cache doesn't
|
|
746
|
-
// match the key. So inside `try_split`, we create a new instance of the solver.
|
|
747
|
-
//
|
|
748
|
-
// This is equivalent to storing the solver in `Layout` and calling `solver.reset()` here.
|
|
749
|
-
let mut solver = Solver::new();
|
|
750
|
-
|
|
751
|
-
let inner_area = area.inner(self.margin);
|
|
752
|
-
let (area_start, area_end) = match self.direction {
|
|
753
|
-
Direction::Horizontal => (
|
|
754
|
-
f64::from(inner_area.x) * FLOAT_PRECISION_MULTIPLIER,
|
|
755
|
-
f64::from(inner_area.right()) * FLOAT_PRECISION_MULTIPLIER,
|
|
756
|
-
),
|
|
757
|
-
Direction::Vertical => (
|
|
758
|
-
f64::from(inner_area.y) * FLOAT_PRECISION_MULTIPLIER,
|
|
759
|
-
f64::from(inner_area.bottom()) * FLOAT_PRECISION_MULTIPLIER,
|
|
760
|
-
),
|
|
761
|
-
};
|
|
762
|
-
|
|
763
|
-
// ```plain
|
|
764
|
-
// <───────────────────────────────────area_size──────────────────────────────────>
|
|
765
|
-
// ┌─area_start area_end─┐
|
|
766
|
-
// V V
|
|
767
|
-
// ┌────┬───────────────────┬────┬─────variables─────┬────┬───────────────────┬────┐
|
|
768
|
-
// │ │ │ │ │ │ │ │
|
|
769
|
-
// V V V V V V V V
|
|
770
|
-
// ┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐
|
|
771
|
-
// │ Max(20) │ │ Max(20) │ │ Max(20) │
|
|
772
|
-
// └ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘
|
|
773
|
-
// ^ ^ ^ ^ ^ ^ ^ ^
|
|
774
|
-
// │ │ │ │ │ │ │ │
|
|
775
|
-
// └─┬──┶━━━━━━━━━┳━━━━━━━━━┵─┬──┶━━━━━━━━━┳━━━━━━━━━┵─┬──┶━━━━━━━━━┳━━━━━━━━━┵─┬──┘
|
|
776
|
-
// │ ┃ │ ┃ │ ┃ │
|
|
777
|
-
// └────────────╂───────────┴────────────╂───────────┴────────────╂──Spacers──┘
|
|
778
|
-
// ┃ ┃ ┃
|
|
779
|
-
// ┗━━━━━━━━━━━━━━━━━━━━━━━━┻━━━━━━━━Segments━━━━━━━━┛
|
|
780
|
-
// ```
|
|
781
|
-
|
|
782
|
-
let variable_count = self.constraints.len() * 2 + 2;
|
|
783
|
-
let variables = iter::repeat_with(Variable::new)
|
|
784
|
-
.take(variable_count)
|
|
785
|
-
.collect_vec();
|
|
786
|
-
let spacers = variables
|
|
787
|
-
.iter()
|
|
788
|
-
.tuples()
|
|
789
|
-
.map(|(a, b)| Element::from((*a, *b)))
|
|
790
|
-
.collect_vec();
|
|
791
|
-
let segments = variables
|
|
792
|
-
.iter()
|
|
793
|
-
.skip(1)
|
|
794
|
-
.tuples()
|
|
795
|
-
.map(|(a, b)| Element::from((*a, *b)))
|
|
796
|
-
.collect_vec();
|
|
797
|
-
|
|
798
|
-
let flex = self.flex;
|
|
799
|
-
|
|
800
|
-
let spacing = match self.spacing {
|
|
801
|
-
Spacing::Space(x) => x as i16,
|
|
802
|
-
Spacing::Overlap(x) => -(x as i16),
|
|
803
|
-
};
|
|
804
|
-
|
|
805
|
-
let constraints = &self.constraints;
|
|
806
|
-
|
|
807
|
-
let area_size = Element::from((*variables.first().unwrap(), *variables.last().unwrap()));
|
|
808
|
-
configure_area(&mut solver, area_size, area_start, area_end)?;
|
|
809
|
-
configure_variable_in_area_constraints(&mut solver, &variables, area_size)?;
|
|
810
|
-
configure_variable_constraints(&mut solver, &variables)?;
|
|
811
|
-
configure_flex_constraints(&mut solver, area_size, &spacers, flex, spacing)?;
|
|
812
|
-
configure_constraints(&mut solver, area_size, &segments, constraints, flex)?;
|
|
813
|
-
configure_fill_constraints(&mut solver, &segments, constraints, flex)?;
|
|
814
|
-
|
|
815
|
-
if !flex.is_legacy() {
|
|
816
|
-
for (left, right) in segments.iter().tuple_windows() {
|
|
817
|
-
solver.add_constraint(left.has_size(right, ALL_SEGMENT_GROW))?;
|
|
818
|
-
}
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
// `solver.fetch_changes()` can only be called once per solve
|
|
822
|
-
let changes: HashMap<Variable, f64> = solver.fetch_changes().iter().copied().collect();
|
|
823
|
-
// debug_elements(&segments, &changes);
|
|
824
|
-
// debug_elements(&spacers, &changes);
|
|
825
|
-
|
|
826
|
-
let segment_rects = changes_to_rects(&changes, &segments, inner_area, self.direction);
|
|
827
|
-
let spacer_rects = changes_to_rects(&changes, &spacers, inner_area, self.direction);
|
|
828
|
-
|
|
829
|
-
Ok((segment_rects, spacer_rects))
|
|
830
|
-
}
|
|
831
|
-
}
|
|
832
|
-
|
|
833
|
-
fn configure_area(
|
|
834
|
-
solver: &mut Solver,
|
|
835
|
-
area: Element,
|
|
836
|
-
area_start: f64,
|
|
837
|
-
area_end: f64,
|
|
838
|
-
) -> Result<(), AddConstraintError> {
|
|
839
|
-
solver.add_constraint(area.start | EQ(Strength::REQUIRED) | area_start)?;
|
|
840
|
-
solver.add_constraint(area.end | EQ(Strength::REQUIRED) | area_end)?;
|
|
841
|
-
Ok(())
|
|
842
|
-
}
|
|
843
|
-
|
|
844
|
-
fn configure_variable_in_area_constraints(
|
|
845
|
-
solver: &mut Solver,
|
|
846
|
-
variables: &[Variable],
|
|
847
|
-
area: Element,
|
|
848
|
-
) -> Result<(), AddConstraintError> {
|
|
849
|
-
// all variables are in the range [area.start, area.end]
|
|
850
|
-
for &variable in variables {
|
|
851
|
-
solver.add_constraint(variable | GE(Strength::REQUIRED) | area.start)?;
|
|
852
|
-
solver.add_constraint(variable | LE(Strength::REQUIRED) | area.end)?;
|
|
853
|
-
}
|
|
854
|
-
|
|
855
|
-
Ok(())
|
|
856
|
-
}
|
|
857
|
-
|
|
858
|
-
fn configure_variable_constraints(
|
|
859
|
-
solver: &mut Solver,
|
|
860
|
-
variables: &[Variable],
|
|
861
|
-
) -> Result<(), AddConstraintError> {
|
|
862
|
-
// ┌────┬───────────────────┬────┬─────variables─────┬────┬───────────────────┬────┐
|
|
863
|
-
// │ │ │ │ │ │ │ │
|
|
864
|
-
// v v v v v v v v
|
|
865
|
-
// ┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐
|
|
866
|
-
// │ Max(20) │ │ Max(20) │ │ Max(20) │
|
|
867
|
-
// └ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘
|
|
868
|
-
// ^ ^ ^ ^ ^ ^ ^ ^
|
|
869
|
-
// └v0 └v1 └v2 └v3 └v4 └v5 └v6 └v7
|
|
870
|
-
|
|
871
|
-
for (&left, &right) in variables.iter().skip(1).tuples() {
|
|
872
|
-
solver.add_constraint(left | LE(Strength::REQUIRED) | right)?;
|
|
873
|
-
}
|
|
874
|
-
Ok(())
|
|
875
|
-
}
|
|
876
|
-
|
|
877
|
-
fn configure_constraints(
|
|
878
|
-
solver: &mut Solver,
|
|
879
|
-
area: Element,
|
|
880
|
-
segments: &[Element],
|
|
881
|
-
constraints: &[Constraint],
|
|
882
|
-
flex: Flex,
|
|
883
|
-
) -> Result<(), AddConstraintError> {
|
|
884
|
-
for (&constraint, &segment) in constraints.iter().zip(segments.iter()) {
|
|
885
|
-
match constraint {
|
|
886
|
-
Constraint::Max(max) => {
|
|
887
|
-
solver.add_constraint(segment.has_max_size(max, MAX_SIZE_LE))?;
|
|
888
|
-
solver.add_constraint(segment.has_int_size(max, MAX_SIZE_EQ))?;
|
|
889
|
-
}
|
|
890
|
-
Constraint::Min(min) => {
|
|
891
|
-
solver.add_constraint(segment.has_min_size(min as i16, MIN_SIZE_GE))?;
|
|
892
|
-
if flex.is_legacy() {
|
|
893
|
-
solver.add_constraint(segment.has_int_size(min, MIN_SIZE_EQ))?;
|
|
894
|
-
} else {
|
|
895
|
-
solver.add_constraint(segment.has_size(area, FILL_GROW))?;
|
|
896
|
-
}
|
|
897
|
-
}
|
|
898
|
-
Constraint::Length(length) => {
|
|
899
|
-
solver.add_constraint(segment.has_int_size(length, LENGTH_SIZE_EQ))?;
|
|
900
|
-
}
|
|
901
|
-
Constraint::Percentage(p) => {
|
|
902
|
-
let size = area.size() * f64::from(p) / 100.00;
|
|
903
|
-
solver.add_constraint(segment.has_size(size, PERCENTAGE_SIZE_EQ))?;
|
|
904
|
-
}
|
|
905
|
-
Constraint::Ratio(num, den) => {
|
|
906
|
-
// avoid division by zero by using 1 when denominator is 0
|
|
907
|
-
let size = area.size() * f64::from(num) / f64::from(den.max(1));
|
|
908
|
-
solver.add_constraint(segment.has_size(size, RATIO_SIZE_EQ))?;
|
|
909
|
-
}
|
|
910
|
-
Constraint::Fill(_) => {
|
|
911
|
-
// given no other constraints, this segment will grow as much as possible.
|
|
912
|
-
solver.add_constraint(segment.has_size(area, FILL_GROW))?;
|
|
913
|
-
}
|
|
914
|
-
}
|
|
915
|
-
}
|
|
916
|
-
Ok(())
|
|
917
|
-
}
|
|
918
|
-
|
|
919
|
-
fn configure_flex_constraints(
|
|
920
|
-
solver: &mut Solver,
|
|
921
|
-
area: Element,
|
|
922
|
-
spacers: &[Element],
|
|
923
|
-
flex: Flex,
|
|
924
|
-
spacing: i16,
|
|
925
|
-
) -> Result<(), AddConstraintError> {
|
|
926
|
-
let spacers_except_first_and_last = spacers.get(1..spacers.len() - 1).unwrap_or(&[]);
|
|
927
|
-
let spacing_f64 = f64::from(spacing) * FLOAT_PRECISION_MULTIPLIER;
|
|
928
|
-
match flex {
|
|
929
|
-
Flex::Legacy => {
|
|
930
|
-
for spacer in spacers_except_first_and_last {
|
|
931
|
-
solver.add_constraint(spacer.has_size(spacing_f64, SPACER_SIZE_EQ))?;
|
|
932
|
-
}
|
|
933
|
-
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
|
934
|
-
solver.add_constraint(first.is_empty())?;
|
|
935
|
-
solver.add_constraint(last.is_empty())?;
|
|
936
|
-
}
|
|
937
|
-
}
|
|
938
|
-
|
|
939
|
-
// All spacers excluding first and last are the same size and will grow to fill
|
|
940
|
-
// any remaining space after the constraints are satisfied.
|
|
941
|
-
// All spacers excluding first and last are also twice the size of the first and last
|
|
942
|
-
// spacers
|
|
943
|
-
Flex::SpaceAround => {
|
|
944
|
-
if spacers.len() <= 2 {
|
|
945
|
-
// If there are two or less spacers, fallback to Flex::SpaceEvenly
|
|
946
|
-
for (left, right) in spacers.iter().tuple_combinations() {
|
|
947
|
-
solver.add_constraint(left.has_size(right, SPACER_SIZE_EQ))?;
|
|
948
|
-
}
|
|
949
|
-
for spacer in spacers {
|
|
950
|
-
solver.add_constraint(spacer.has_min_size(spacing, SPACER_SIZE_EQ))?;
|
|
951
|
-
solver.add_constraint(spacer.has_size(area, SPACE_GROW))?;
|
|
952
|
-
}
|
|
953
|
-
} else {
|
|
954
|
-
// Separate the first and last spacer from the middle ones
|
|
955
|
-
let (first, rest) = spacers.split_first().unwrap();
|
|
956
|
-
let (last, middle) = rest.split_last().unwrap();
|
|
957
|
-
|
|
958
|
-
// All middle spacers should be equal in size
|
|
959
|
-
for (left, right) in middle.iter().tuple_combinations() {
|
|
960
|
-
solver.add_constraint(left.has_size(right, SPACER_SIZE_EQ))?;
|
|
961
|
-
}
|
|
962
|
-
|
|
963
|
-
// First and last spacers should be half the size of any middle spacer
|
|
964
|
-
if let Some(first_middle) = middle.first() {
|
|
965
|
-
solver.add_constraint(first_middle.has_double_size(first, SPACER_SIZE_EQ))?;
|
|
966
|
-
solver.add_constraint(first_middle.has_double_size(last, SPACER_SIZE_EQ))?;
|
|
967
|
-
}
|
|
968
|
-
|
|
969
|
-
// Apply minimum size and growth constraints
|
|
970
|
-
for spacer in spacers {
|
|
971
|
-
solver.add_constraint(spacer.has_min_size(spacing, SPACER_SIZE_EQ))?;
|
|
972
|
-
solver.add_constraint(spacer.has_size(area, SPACE_GROW))?;
|
|
973
|
-
}
|
|
974
|
-
}
|
|
975
|
-
}
|
|
976
|
-
|
|
977
|
-
// All spacers are the same size and will grow to fill any remaining space after the
|
|
978
|
-
// constraints are satisfied
|
|
979
|
-
Flex::SpaceEvenly => {
|
|
980
|
-
for (left, right) in spacers.iter().tuple_combinations() {
|
|
981
|
-
solver.add_constraint(left.has_size(right, SPACER_SIZE_EQ))?;
|
|
982
|
-
}
|
|
983
|
-
for spacer in spacers {
|
|
984
|
-
solver.add_constraint(spacer.has_min_size(spacing, SPACER_SIZE_EQ))?;
|
|
985
|
-
solver.add_constraint(spacer.has_size(area, SPACE_GROW))?;
|
|
986
|
-
}
|
|
987
|
-
}
|
|
988
|
-
|
|
989
|
-
// All spacers excluding first and last are the same size and will grow to fill
|
|
990
|
-
// any remaining space after the constraints are satisfied.
|
|
991
|
-
// The first and last spacers are zero size.
|
|
992
|
-
Flex::SpaceBetween => {
|
|
993
|
-
for (left, right) in spacers_except_first_and_last.iter().tuple_combinations() {
|
|
994
|
-
solver.add_constraint(left.has_size(right.size(), SPACER_SIZE_EQ))?;
|
|
995
|
-
}
|
|
996
|
-
for spacer in spacers_except_first_and_last {
|
|
997
|
-
solver.add_constraint(spacer.has_min_size(spacing, SPACER_SIZE_EQ))?;
|
|
998
|
-
solver.add_constraint(spacer.has_size(area, SPACE_GROW))?;
|
|
999
|
-
}
|
|
1000
|
-
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
|
1001
|
-
solver.add_constraint(first.is_empty())?;
|
|
1002
|
-
solver.add_constraint(last.is_empty())?;
|
|
1003
|
-
}
|
|
1004
|
-
}
|
|
1005
|
-
|
|
1006
|
-
Flex::Start => {
|
|
1007
|
-
for spacer in spacers_except_first_and_last {
|
|
1008
|
-
solver.add_constraint(spacer.has_size(spacing_f64, SPACER_SIZE_EQ))?;
|
|
1009
|
-
}
|
|
1010
|
-
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
|
1011
|
-
solver.add_constraint(first.is_empty())?;
|
|
1012
|
-
solver.add_constraint(last.has_size(area, GROW))?;
|
|
1013
|
-
}
|
|
1014
|
-
}
|
|
1015
|
-
Flex::Center => {
|
|
1016
|
-
for spacer in spacers_except_first_and_last {
|
|
1017
|
-
solver.add_constraint(spacer.has_size(spacing_f64, SPACER_SIZE_EQ))?;
|
|
1018
|
-
}
|
|
1019
|
-
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
|
1020
|
-
solver.add_constraint(first.has_size(area, GROW))?;
|
|
1021
|
-
solver.add_constraint(last.has_size(area, GROW))?;
|
|
1022
|
-
solver.add_constraint(first.has_size(last, SPACER_SIZE_EQ))?;
|
|
1023
|
-
}
|
|
1024
|
-
}
|
|
1025
|
-
Flex::End => {
|
|
1026
|
-
for spacer in spacers_except_first_and_last {
|
|
1027
|
-
solver.add_constraint(spacer.has_size(spacing_f64, SPACER_SIZE_EQ))?;
|
|
1028
|
-
}
|
|
1029
|
-
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
|
1030
|
-
solver.add_constraint(last.is_empty())?;
|
|
1031
|
-
solver.add_constraint(first.has_size(area, GROW))?;
|
|
1032
|
-
}
|
|
1033
|
-
}
|
|
1034
|
-
}
|
|
1035
|
-
Ok(())
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
/// Make every `Fill` constraint proportionally equal to each other
|
|
1039
|
-
/// This will make it fill up empty spaces equally
|
|
1040
|
-
///
|
|
1041
|
-
/// [Fill(1), Fill(1)]
|
|
1042
|
-
/// ┌──────┐┌──────┐
|
|
1043
|
-
/// │abcdef││abcdef│
|
|
1044
|
-
/// └──────┘└──────┘
|
|
1045
|
-
///
|
|
1046
|
-
/// [Fill(1), Fill(2)]
|
|
1047
|
-
/// ┌──────┐┌────────────┐
|
|
1048
|
-
/// │abcdef││abcdefabcdef│
|
|
1049
|
-
/// └──────┘└────────────┘
|
|
1050
|
-
///
|
|
1051
|
-
/// `size == base_element * scaling_factor`
|
|
1052
|
-
fn configure_fill_constraints(
|
|
1053
|
-
solver: &mut Solver,
|
|
1054
|
-
segments: &[Element],
|
|
1055
|
-
constraints: &[Constraint],
|
|
1056
|
-
flex: Flex,
|
|
1057
|
-
) -> Result<(), AddConstraintError> {
|
|
1058
|
-
for ((&left_constraint, &left_segment), (&right_constraint, &right_segment)) in constraints
|
|
1059
|
-
.iter()
|
|
1060
|
-
.zip(segments.iter())
|
|
1061
|
-
.filter(|(c, _)| c.is_fill() || (!flex.is_legacy() && c.is_min()))
|
|
1062
|
-
.tuple_combinations()
|
|
1063
|
-
{
|
|
1064
|
-
let left_scaling_factor = match left_constraint {
|
|
1065
|
-
Constraint::Fill(scale) => f64::from(scale).max(1e-6),
|
|
1066
|
-
Constraint::Min(_) => 1.0,
|
|
1067
|
-
_ => unreachable!(),
|
|
1068
|
-
};
|
|
1069
|
-
let right_scaling_factor = match right_constraint {
|
|
1070
|
-
Constraint::Fill(scale) => f64::from(scale).max(1e-6),
|
|
1071
|
-
Constraint::Min(_) => 1.0,
|
|
1072
|
-
_ => unreachable!(),
|
|
1073
|
-
};
|
|
1074
|
-
solver.add_constraint(
|
|
1075
|
-
(right_scaling_factor * left_segment.size())
|
|
1076
|
-
| EQ(GROW)
|
|
1077
|
-
| (left_scaling_factor * right_segment.size()),
|
|
1078
|
-
)?;
|
|
1079
|
-
}
|
|
1080
|
-
Ok(())
|
|
1081
|
-
}
|
|
1082
|
-
|
|
1083
|
-
// Used instead of `f64::round` directly, to provide fallback for `no_std`.
|
|
1084
|
-
#[cfg(feature = "std")]
|
|
1085
|
-
#[inline]
|
|
1086
|
-
fn round(value: f64) -> f64 {
|
|
1087
|
-
value.round()
|
|
1088
|
-
}
|
|
1089
|
-
|
|
1090
|
-
// A rounding fallback for `no_std` in pure rust.
|
|
1091
|
-
#[cfg(not(feature = "std"))]
|
|
1092
|
-
#[inline]
|
|
1093
|
-
fn round(value: f64) -> f64 {
|
|
1094
|
-
(value + 0.5f64.copysign(value)) as i64 as f64
|
|
1095
|
-
}
|
|
1096
|
-
|
|
1097
|
-
fn changes_to_rects(
|
|
1098
|
-
changes: &HashMap<Variable, f64>,
|
|
1099
|
-
elements: &[Element],
|
|
1100
|
-
area: Rect,
|
|
1101
|
-
direction: Direction,
|
|
1102
|
-
) -> Rects {
|
|
1103
|
-
// convert to Rects
|
|
1104
|
-
elements
|
|
1105
|
-
.iter()
|
|
1106
|
-
.map(|element| {
|
|
1107
|
-
let start = changes.get(&element.start).unwrap_or(&0.0);
|
|
1108
|
-
let end = changes.get(&element.end).unwrap_or(&0.0);
|
|
1109
|
-
let start = round(round(*start) / FLOAT_PRECISION_MULTIPLIER) as u16;
|
|
1110
|
-
let end = round(round(*end) / FLOAT_PRECISION_MULTIPLIER) as u16;
|
|
1111
|
-
let size = end.saturating_sub(start);
|
|
1112
|
-
match direction {
|
|
1113
|
-
Direction::Horizontal => Rect {
|
|
1114
|
-
x: start,
|
|
1115
|
-
y: area.y,
|
|
1116
|
-
width: size,
|
|
1117
|
-
height: area.height,
|
|
1118
|
-
},
|
|
1119
|
-
Direction::Vertical => Rect {
|
|
1120
|
-
x: area.x,
|
|
1121
|
-
y: start,
|
|
1122
|
-
width: area.width,
|
|
1123
|
-
height: size,
|
|
1124
|
-
},
|
|
1125
|
-
}
|
|
1126
|
-
})
|
|
1127
|
-
.collect::<Rects>()
|
|
1128
|
-
}
|
|
1129
|
-
|
|
1130
|
-
/// please leave this here as it's useful for debugging unit tests when we make any changes to
|
|
1131
|
-
/// layout code - we should replace this with tracing in the future.
|
|
1132
|
-
#[expect(dead_code)]
|
|
1133
|
-
#[cfg(feature = "std")]
|
|
1134
|
-
fn debug_elements(elements: &[Element], changes: &HashMap<Variable, f64>) {
|
|
1135
|
-
let variables = alloc::format!(
|
|
1136
|
-
"{:?}",
|
|
1137
|
-
elements
|
|
1138
|
-
.iter()
|
|
1139
|
-
.map(|e| (
|
|
1140
|
-
changes.get(&e.start).unwrap_or(&0.0) / FLOAT_PRECISION_MULTIPLIER,
|
|
1141
|
-
changes.get(&e.end).unwrap_or(&0.0) / FLOAT_PRECISION_MULTIPLIER,
|
|
1142
|
-
))
|
|
1143
|
-
.collect::<Vec<(f64, f64)>>()
|
|
1144
|
-
);
|
|
1145
|
-
std::dbg!(variables);
|
|
1146
|
-
}
|
|
1147
|
-
|
|
1148
|
-
/// A container used by the solver inside split
|
|
1149
|
-
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash)]
|
|
1150
|
-
struct Element {
|
|
1151
|
-
start: Variable,
|
|
1152
|
-
end: Variable,
|
|
1153
|
-
}
|
|
1154
|
-
|
|
1155
|
-
impl From<(Variable, Variable)> for Element {
|
|
1156
|
-
fn from((start, end): (Variable, Variable)) -> Self {
|
|
1157
|
-
Self { start, end }
|
|
1158
|
-
}
|
|
1159
|
-
}
|
|
1160
|
-
|
|
1161
|
-
impl Element {
|
|
1162
|
-
#[expect(dead_code)]
|
|
1163
|
-
fn new() -> Self {
|
|
1164
|
-
Self {
|
|
1165
|
-
start: Variable::new(),
|
|
1166
|
-
end: Variable::new(),
|
|
1167
|
-
}
|
|
1168
|
-
}
|
|
1169
|
-
|
|
1170
|
-
fn size(&self) -> Expression {
|
|
1171
|
-
self.end - self.start
|
|
1172
|
-
}
|
|
1173
|
-
|
|
1174
|
-
fn has_max_size(&self, size: u16, strength: Strength) -> kasuari::Constraint {
|
|
1175
|
-
self.size() | LE(strength) | (f64::from(size) * FLOAT_PRECISION_MULTIPLIER)
|
|
1176
|
-
}
|
|
1177
|
-
|
|
1178
|
-
fn has_min_size(&self, size: i16, strength: Strength) -> kasuari::Constraint {
|
|
1179
|
-
self.size() | GE(strength) | (f64::from(size) * FLOAT_PRECISION_MULTIPLIER)
|
|
1180
|
-
}
|
|
1181
|
-
|
|
1182
|
-
fn has_int_size(&self, size: u16, strength: Strength) -> kasuari::Constraint {
|
|
1183
|
-
self.size() | EQ(strength) | (f64::from(size) * FLOAT_PRECISION_MULTIPLIER)
|
|
1184
|
-
}
|
|
1185
|
-
|
|
1186
|
-
fn has_size<E: Into<Expression>>(&self, size: E, strength: Strength) -> kasuari::Constraint {
|
|
1187
|
-
self.size() | EQ(strength) | size.into()
|
|
1188
|
-
}
|
|
1189
|
-
|
|
1190
|
-
fn has_double_size<E: Into<Expression>>(
|
|
1191
|
-
&self,
|
|
1192
|
-
size: E,
|
|
1193
|
-
strength: Strength,
|
|
1194
|
-
) -> kasuari::Constraint {
|
|
1195
|
-
self.size() | EQ(strength) | (size.into() * 2.0)
|
|
1196
|
-
}
|
|
1197
|
-
|
|
1198
|
-
fn is_empty(&self) -> kasuari::Constraint {
|
|
1199
|
-
self.size() | EQ(Strength::REQUIRED - Strength::WEAK) | 0.0
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
|
|
1203
|
-
/// allow the element to represent its own size in expressions
|
|
1204
|
-
impl From<Element> for Expression {
|
|
1205
|
-
fn from(element: Element) -> Self {
|
|
1206
|
-
element.size()
|
|
1207
|
-
}
|
|
1208
|
-
}
|
|
1209
|
-
|
|
1210
|
-
/// allow the element to represent its own size in expressions
|
|
1211
|
-
impl From<&Element> for Expression {
|
|
1212
|
-
fn from(element: &Element) -> Self {
|
|
1213
|
-
element.size()
|
|
1214
|
-
}
|
|
1215
|
-
}
|
|
1216
|
-
|
|
1217
|
-
mod strengths {
|
|
1218
|
-
use kasuari::Strength;
|
|
1219
|
-
|
|
1220
|
-
/// The strength to apply to Spacers to ensure that their sizes are equal.
|
|
1221
|
-
///
|
|
1222
|
-
/// ┌ ┐┌───┐┌ ┐┌───┐┌ ┐
|
|
1223
|
-
/// ==x │ │ ==x │ │ ==x
|
|
1224
|
-
/// └ ┘└───┘└ ┘└───┘└ ┘
|
|
1225
|
-
pub const SPACER_SIZE_EQ: Strength = Strength::REQUIRED.div_f64(10.0);
|
|
1226
|
-
|
|
1227
|
-
/// The strength to apply to Min inequality constraints.
|
|
1228
|
-
///
|
|
1229
|
-
/// ┌────────┐
|
|
1230
|
-
/// │Min(>=x)│
|
|
1231
|
-
/// └────────┘
|
|
1232
|
-
pub const MIN_SIZE_GE: Strength = Strength::STRONG.mul_f64(100.0);
|
|
1233
|
-
|
|
1234
|
-
/// The strength to apply to Max inequality constraints.
|
|
1235
|
-
///
|
|
1236
|
-
/// ┌────────┐
|
|
1237
|
-
/// │Max(<=x)│
|
|
1238
|
-
/// └────────┘
|
|
1239
|
-
pub const MAX_SIZE_LE: Strength = Strength::STRONG.mul_f64(100.0);
|
|
1240
|
-
|
|
1241
|
-
/// The strength to apply to Length constraints.
|
|
1242
|
-
///
|
|
1243
|
-
/// ┌───────────┐
|
|
1244
|
-
/// │Length(==x)│
|
|
1245
|
-
/// └───────────┘
|
|
1246
|
-
pub const LENGTH_SIZE_EQ: Strength = Strength::STRONG.mul_f64(10.0);
|
|
1247
|
-
|
|
1248
|
-
/// The strength to apply to Percentage constraints.
|
|
1249
|
-
///
|
|
1250
|
-
/// ┌───────────────┐
|
|
1251
|
-
/// │Percentage(==x)│
|
|
1252
|
-
/// └───────────────┘
|
|
1253
|
-
pub const PERCENTAGE_SIZE_EQ: Strength = Strength::STRONG;
|
|
1254
|
-
|
|
1255
|
-
/// The strength to apply to Ratio constraints.
|
|
1256
|
-
///
|
|
1257
|
-
/// ┌────────────┐
|
|
1258
|
-
/// │Ratio(==x,y)│
|
|
1259
|
-
/// └────────────┘
|
|
1260
|
-
pub const RATIO_SIZE_EQ: Strength = Strength::STRONG.div_f64(10.0);
|
|
1261
|
-
|
|
1262
|
-
/// The strength to apply to Min equality constraints.
|
|
1263
|
-
///
|
|
1264
|
-
/// ┌────────┐
|
|
1265
|
-
/// │Min(==x)│
|
|
1266
|
-
/// └────────┘
|
|
1267
|
-
pub const MIN_SIZE_EQ: Strength = Strength::MEDIUM.mul_f64(10.0);
|
|
1268
|
-
|
|
1269
|
-
/// The strength to apply to Max equality constraints.
|
|
1270
|
-
///
|
|
1271
|
-
/// ┌────────┐
|
|
1272
|
-
/// │Max(==x)│
|
|
1273
|
-
/// └────────┘
|
|
1274
|
-
pub const MAX_SIZE_EQ: Strength = Strength::MEDIUM.mul_f64(10.0);
|
|
1275
|
-
|
|
1276
|
-
/// The strength to apply to Fill growing constraints.
|
|
1277
|
-
///
|
|
1278
|
-
/// ┌─────────────────────┐
|
|
1279
|
-
/// │<= Fill(x) =>│
|
|
1280
|
-
/// └─────────────────────┘
|
|
1281
|
-
pub const FILL_GROW: Strength = Strength::MEDIUM;
|
|
1282
|
-
|
|
1283
|
-
/// The strength to apply to growing constraints.
|
|
1284
|
-
///
|
|
1285
|
-
/// ┌────────────┐
|
|
1286
|
-
/// │<= Min(x) =>│
|
|
1287
|
-
/// └────────────┘
|
|
1288
|
-
pub const GROW: Strength = Strength::MEDIUM.div_f64(10.0);
|
|
1289
|
-
|
|
1290
|
-
/// The strength to apply to Spacer growing constraints.
|
|
1291
|
-
///
|
|
1292
|
-
/// ┌ ┐
|
|
1293
|
-
/// <= x =>
|
|
1294
|
-
/// └ ┘
|
|
1295
|
-
pub const SPACE_GROW: Strength = Strength::WEAK.mul_f64(10.0);
|
|
1296
|
-
|
|
1297
|
-
/// The strength to apply to growing the size of all segments equally.
|
|
1298
|
-
///
|
|
1299
|
-
/// ┌───────┐
|
|
1300
|
-
/// │<= x =>│
|
|
1301
|
-
/// └───────┘
|
|
1302
|
-
pub const ALL_SEGMENT_GROW: Strength = Strength::WEAK;
|
|
1303
|
-
}
|
|
1304
|
-
|
|
1305
|
-
#[cfg(test)]
|
|
1306
|
-
mod tests {
|
|
1307
|
-
use alloc::borrow::ToOwned;
|
|
1308
|
-
use alloc::vec;
|
|
1309
|
-
use alloc::vec::Vec;
|
|
1310
|
-
|
|
1311
|
-
use super::*;
|
|
1312
|
-
|
|
1313
|
-
#[test]
|
|
1314
|
-
// The compiler will optimize out the comparisons, but this ensures that the constants are
|
|
1315
|
-
// defined in the correct order of priority.
|
|
1316
|
-
pub fn strength_is_valid() {
|
|
1317
|
-
use strengths::*;
|
|
1318
|
-
assert!(SPACER_SIZE_EQ > MAX_SIZE_LE);
|
|
1319
|
-
assert!(MAX_SIZE_LE > MAX_SIZE_EQ);
|
|
1320
|
-
assert!(MIN_SIZE_GE == MAX_SIZE_LE);
|
|
1321
|
-
assert!(MAX_SIZE_LE > LENGTH_SIZE_EQ);
|
|
1322
|
-
assert!(LENGTH_SIZE_EQ > PERCENTAGE_SIZE_EQ);
|
|
1323
|
-
assert!(PERCENTAGE_SIZE_EQ > RATIO_SIZE_EQ);
|
|
1324
|
-
assert!(RATIO_SIZE_EQ > MAX_SIZE_EQ);
|
|
1325
|
-
assert!(MIN_SIZE_GE > FILL_GROW);
|
|
1326
|
-
assert!(FILL_GROW > GROW);
|
|
1327
|
-
assert!(GROW > SPACE_GROW);
|
|
1328
|
-
assert!(SPACE_GROW > ALL_SEGMENT_GROW);
|
|
1329
|
-
}
|
|
1330
|
-
|
|
1331
|
-
#[test]
|
|
1332
|
-
#[cfg(feature = "layout-cache")]
|
|
1333
|
-
fn cache_size() {
|
|
1334
|
-
LAYOUT_CACHE.with_borrow(|cache| {
|
|
1335
|
-
assert_eq!(cache.cap().get(), Layout::DEFAULT_CACHE_SIZE);
|
|
1336
|
-
});
|
|
1337
|
-
|
|
1338
|
-
Layout::init_cache(NonZeroUsize::new(10).unwrap());
|
|
1339
|
-
LAYOUT_CACHE.with_borrow(|cache| {
|
|
1340
|
-
assert_eq!(cache.cap().get(), 10);
|
|
1341
|
-
});
|
|
1342
|
-
}
|
|
1343
|
-
|
|
1344
|
-
#[test]
|
|
1345
|
-
fn default() {
|
|
1346
|
-
assert_eq!(
|
|
1347
|
-
Layout::default(),
|
|
1348
|
-
Layout {
|
|
1349
|
-
direction: Direction::Vertical,
|
|
1350
|
-
margin: Margin::new(0, 0),
|
|
1351
|
-
constraints: vec![],
|
|
1352
|
-
flex: Flex::default(),
|
|
1353
|
-
spacing: Spacing::default(),
|
|
1354
|
-
}
|
|
1355
|
-
);
|
|
1356
|
-
}
|
|
1357
|
-
|
|
1358
|
-
#[test]
|
|
1359
|
-
fn new() {
|
|
1360
|
-
// array
|
|
1361
|
-
let fixed_size_array = [Constraint::Min(0)];
|
|
1362
|
-
let layout = Layout::new(Direction::Horizontal, fixed_size_array);
|
|
1363
|
-
assert_eq!(layout.direction, Direction::Horizontal);
|
|
1364
|
-
assert_eq!(layout.constraints, [Constraint::Min(0)]);
|
|
1365
|
-
|
|
1366
|
-
// array_ref
|
|
1367
|
-
#[expect(clippy::needless_borrows_for_generic_args)] // backwards compatibility test
|
|
1368
|
-
let layout = Layout::new(Direction::Horizontal, &[Constraint::Min(0)]);
|
|
1369
|
-
assert_eq!(layout.direction, Direction::Horizontal);
|
|
1370
|
-
assert_eq!(layout.constraints, [Constraint::Min(0)]);
|
|
1371
|
-
|
|
1372
|
-
// vec
|
|
1373
|
-
let layout = Layout::new(Direction::Horizontal, vec![Constraint::Min(0)]);
|
|
1374
|
-
assert_eq!(layout.direction, Direction::Horizontal);
|
|
1375
|
-
assert_eq!(layout.constraints, [Constraint::Min(0)]);
|
|
1376
|
-
|
|
1377
|
-
// vec_ref
|
|
1378
|
-
#[expect(clippy::needless_borrows_for_generic_args)] // backwards compatibility test
|
|
1379
|
-
let layout = Layout::new(Direction::Horizontal, &(vec![Constraint::Min(0)]));
|
|
1380
|
-
assert_eq!(layout.direction, Direction::Horizontal);
|
|
1381
|
-
assert_eq!(layout.constraints, [Constraint::Min(0)]);
|
|
1382
|
-
|
|
1383
|
-
// iterator
|
|
1384
|
-
let layout = Layout::new(Direction::Horizontal, iter::once(Constraint::Min(0)));
|
|
1385
|
-
assert_eq!(layout.direction, Direction::Horizontal);
|
|
1386
|
-
assert_eq!(layout.constraints, [Constraint::Min(0)]);
|
|
1387
|
-
}
|
|
1388
|
-
|
|
1389
|
-
#[test]
|
|
1390
|
-
fn vertical() {
|
|
1391
|
-
assert_eq!(
|
|
1392
|
-
Layout::vertical([Constraint::Min(0)]),
|
|
1393
|
-
Layout {
|
|
1394
|
-
direction: Direction::Vertical,
|
|
1395
|
-
margin: Margin::new(0, 0),
|
|
1396
|
-
constraints: vec![Constraint::Min(0)],
|
|
1397
|
-
flex: Flex::default(),
|
|
1398
|
-
spacing: Spacing::default(),
|
|
1399
|
-
}
|
|
1400
|
-
);
|
|
1401
|
-
}
|
|
1402
|
-
|
|
1403
|
-
#[test]
|
|
1404
|
-
fn horizontal() {
|
|
1405
|
-
assert_eq!(
|
|
1406
|
-
Layout::horizontal([Constraint::Min(0)]),
|
|
1407
|
-
Layout {
|
|
1408
|
-
direction: Direction::Horizontal,
|
|
1409
|
-
margin: Margin::new(0, 0),
|
|
1410
|
-
constraints: vec![Constraint::Min(0)],
|
|
1411
|
-
flex: Flex::default(),
|
|
1412
|
-
spacing: Spacing::default(),
|
|
1413
|
-
}
|
|
1414
|
-
);
|
|
1415
|
-
}
|
|
1416
|
-
|
|
1417
|
-
/// The purpose of this test is to ensure that layout can be constructed with any type that
|
|
1418
|
-
/// implements `IntoIterator<Item = AsRef<Constraint>>`.
|
|
1419
|
-
#[test]
|
|
1420
|
-
fn constraints() {
|
|
1421
|
-
const CONSTRAINTS: [Constraint; 2] = [Constraint::Min(0), Constraint::Max(10)];
|
|
1422
|
-
let fixed_size_array = CONSTRAINTS;
|
|
1423
|
-
assert_eq!(
|
|
1424
|
-
Layout::default().constraints(fixed_size_array).constraints,
|
|
1425
|
-
CONSTRAINTS,
|
|
1426
|
-
"constraints should be settable with an array"
|
|
1427
|
-
);
|
|
1428
|
-
|
|
1429
|
-
let slice_of_fixed_size_array = &CONSTRAINTS;
|
|
1430
|
-
assert_eq!(
|
|
1431
|
-
Layout::default()
|
|
1432
|
-
.constraints(slice_of_fixed_size_array)
|
|
1433
|
-
.constraints,
|
|
1434
|
-
CONSTRAINTS,
|
|
1435
|
-
"constraints should be settable with a slice"
|
|
1436
|
-
);
|
|
1437
|
-
|
|
1438
|
-
let vec = CONSTRAINTS.to_vec();
|
|
1439
|
-
let slice_of_vec = vec.as_slice();
|
|
1440
|
-
assert_eq!(
|
|
1441
|
-
Layout::default().constraints(slice_of_vec).constraints,
|
|
1442
|
-
CONSTRAINTS,
|
|
1443
|
-
"constraints should be settable with a slice"
|
|
1444
|
-
);
|
|
1445
|
-
|
|
1446
|
-
assert_eq!(
|
|
1447
|
-
Layout::default().constraints(vec).constraints,
|
|
1448
|
-
CONSTRAINTS,
|
|
1449
|
-
"constraints should be settable with a Vec"
|
|
1450
|
-
);
|
|
1451
|
-
|
|
1452
|
-
let iter = CONSTRAINTS.iter();
|
|
1453
|
-
assert_eq!(
|
|
1454
|
-
Layout::default().constraints(iter).constraints,
|
|
1455
|
-
CONSTRAINTS,
|
|
1456
|
-
"constraints should be settable with an iter"
|
|
1457
|
-
);
|
|
1458
|
-
|
|
1459
|
-
let iterator = CONSTRAINTS.iter().map(ToOwned::to_owned);
|
|
1460
|
-
assert_eq!(
|
|
1461
|
-
Layout::default().constraints(iterator).constraints,
|
|
1462
|
-
CONSTRAINTS,
|
|
1463
|
-
"constraints should be settable with an iterator"
|
|
1464
|
-
);
|
|
1465
|
-
|
|
1466
|
-
let iterator_ref = CONSTRAINTS.iter().map(AsRef::as_ref);
|
|
1467
|
-
assert_eq!(
|
|
1468
|
-
Layout::default().constraints(iterator_ref).constraints,
|
|
1469
|
-
CONSTRAINTS,
|
|
1470
|
-
"constraints should be settable with an iterator of refs"
|
|
1471
|
-
);
|
|
1472
|
-
}
|
|
1473
|
-
|
|
1474
|
-
#[test]
|
|
1475
|
-
fn direction() {
|
|
1476
|
-
assert_eq!(
|
|
1477
|
-
Layout::default().direction(Direction::Horizontal).direction,
|
|
1478
|
-
Direction::Horizontal
|
|
1479
|
-
);
|
|
1480
|
-
assert_eq!(
|
|
1481
|
-
Layout::default().direction(Direction::Vertical).direction,
|
|
1482
|
-
Direction::Vertical
|
|
1483
|
-
);
|
|
1484
|
-
}
|
|
1485
|
-
|
|
1486
|
-
#[test]
|
|
1487
|
-
fn margins() {
|
|
1488
|
-
assert_eq!(Layout::default().margin(10).margin, Margin::new(10, 10));
|
|
1489
|
-
assert_eq!(
|
|
1490
|
-
Layout::default().horizontal_margin(10).margin,
|
|
1491
|
-
Margin::new(10, 0)
|
|
1492
|
-
);
|
|
1493
|
-
assert_eq!(
|
|
1494
|
-
Layout::default().vertical_margin(10).margin,
|
|
1495
|
-
Margin::new(0, 10)
|
|
1496
|
-
);
|
|
1497
|
-
assert_eq!(
|
|
1498
|
-
Layout::default()
|
|
1499
|
-
.horizontal_margin(10)
|
|
1500
|
-
.vertical_margin(20)
|
|
1501
|
-
.margin,
|
|
1502
|
-
Margin::new(10, 20)
|
|
1503
|
-
);
|
|
1504
|
-
}
|
|
1505
|
-
|
|
1506
|
-
#[test]
|
|
1507
|
-
fn flex() {
|
|
1508
|
-
assert_eq!(Layout::default().flex, Flex::Start);
|
|
1509
|
-
assert_eq!(Layout::default().flex(Flex::Center).flex, Flex::Center);
|
|
1510
|
-
}
|
|
1511
|
-
|
|
1512
|
-
#[test]
|
|
1513
|
-
fn spacing() {
|
|
1514
|
-
assert_eq!(Layout::default().spacing(10).spacing, Spacing::Space(10));
|
|
1515
|
-
assert_eq!(Layout::default().spacing(0).spacing, Spacing::Space(0));
|
|
1516
|
-
assert_eq!(Layout::default().spacing(-10).spacing, Spacing::Overlap(10));
|
|
1517
|
-
}
|
|
1518
|
-
|
|
1519
|
-
/// Tests for the `Layout::split()` function.
|
|
1520
|
-
///
|
|
1521
|
-
/// There are many tests in this as the number of edge cases that are caused by the interaction
|
|
1522
|
-
/// between the constraints is quite large. The tests are split into sections based on the type
|
|
1523
|
-
/// of constraints that are used.
|
|
1524
|
-
///
|
|
1525
|
-
/// These tests are characterization tests. This means that they are testing the way the code
|
|
1526
|
-
/// currently works, and not the way it should work. This is because the current behavior is not
|
|
1527
|
-
/// well defined, and it is not clear what the correct behavior should be. This means that if
|
|
1528
|
-
/// the behavior changes, these tests should be updated to match the new behavior.
|
|
1529
|
-
///
|
|
1530
|
-
/// EOL comments in each test are intended to communicate the purpose of each test and to make
|
|
1531
|
-
/// it easy to see that the tests are as exhaustive as feasible:
|
|
1532
|
-
/// - zero: constraint is zero
|
|
1533
|
-
/// - exact: constraint is equal to the space
|
|
1534
|
-
/// - underflow: constraint is for less than the full space
|
|
1535
|
-
/// - overflow: constraint is for more than the full space
|
|
1536
|
-
mod split {
|
|
1537
|
-
use alloc::string::ToString;
|
|
1538
|
-
use core::ops::Range;
|
|
1539
|
-
|
|
1540
|
-
use itertools::Itertools;
|
|
1541
|
-
use pretty_assertions::assert_eq;
|
|
1542
|
-
use rstest::rstest;
|
|
1543
|
-
|
|
1544
|
-
use super::*;
|
|
1545
|
-
use crate::buffer::Buffer;
|
|
1546
|
-
use crate::layout::Constraint::{self, *};
|
|
1547
|
-
use crate::layout::{Direction, Flex, Layout, Rect};
|
|
1548
|
-
use crate::text::Text;
|
|
1549
|
-
use crate::widgets::Widget;
|
|
1550
|
-
|
|
1551
|
-
/// Test that the given constraints applied to the given area result in the expected layout.
|
|
1552
|
-
/// Each chunk is filled with a letter repeated as many times as the width of the chunk. The
|
|
1553
|
-
/// resulting buffer is compared to the expected string.
|
|
1554
|
-
///
|
|
1555
|
-
/// This approach is used rather than testing the resulting rects directly because it is
|
|
1556
|
-
/// easier to visualize the result, and it leads to more concise tests that are easier to
|
|
1557
|
-
/// compare against each other. E.g. `"abc"` is much more concise than `[Rect::new(0, 0, 1,
|
|
1558
|
-
/// 1), Rect::new(1, 0, 1, 1), Rect::new(2, 0, 1, 1)]`.
|
|
1559
|
-
#[track_caller]
|
|
1560
|
-
fn letters(flex: Flex, constraints: &[Constraint], width: u16, expected: &str) {
|
|
1561
|
-
let area = Rect::new(0, 0, width, 1);
|
|
1562
|
-
let layout = Layout::default()
|
|
1563
|
-
.direction(Direction::Horizontal)
|
|
1564
|
-
.constraints(constraints)
|
|
1565
|
-
.flex(flex)
|
|
1566
|
-
.split(area);
|
|
1567
|
-
let mut buffer = Buffer::empty(area);
|
|
1568
|
-
for (c, &area) in ('a'..='z').take(constraints.len()).zip(layout.iter()) {
|
|
1569
|
-
let s = c.to_string().repeat(area.width as usize);
|
|
1570
|
-
Text::from(s).render(area, &mut buffer);
|
|
1571
|
-
}
|
|
1572
|
-
assert_eq!(buffer, Buffer::with_lines([expected]));
|
|
1573
|
-
}
|
|
1574
|
-
|
|
1575
|
-
#[rstest]
|
|
1576
|
-
// flex, width, lengths, expected
|
|
1577
|
-
#[case(Flex::Legacy, 1, &[Length(0)], "a")] // zero
|
|
1578
|
-
#[case(Flex::Legacy, 1, &[Length(1)], "a")] // exact
|
|
1579
|
-
#[case(Flex::Legacy, 1, &[Length(2)], "a")] // overflow
|
|
1580
|
-
#[case(Flex::Legacy, 2, &[Length(0)], "aa")] // zero
|
|
1581
|
-
#[case(Flex::Legacy, 2, &[Length(1)], "aa")] // underflow
|
|
1582
|
-
#[case(Flex::Legacy, 2, &[Length(2)], "aa")] // exact
|
|
1583
|
-
#[case(Flex::Legacy, 2, &[Length(3)], "aa")] // overflow
|
|
1584
|
-
#[case(Flex::Legacy, 1, &[Length(0), Length(0)], "b")] // zero, zero
|
|
1585
|
-
#[case(Flex::Legacy, 1, &[Length(0), Length(1)], "b")] // zero, exact
|
|
1586
|
-
#[case(Flex::Legacy, 1, &[Length(0), Length(2)], "b")] // zero, overflow
|
|
1587
|
-
#[case(Flex::Legacy, 1, &[Length(1), Length(0)], "a")] // exact, zero
|
|
1588
|
-
#[case(Flex::Legacy, 1, &[Length(1), Length(1)], "a")] // exact, exact
|
|
1589
|
-
#[case(Flex::Legacy, 1, &[Length(1), Length(2)], "a")] // exact, overflow
|
|
1590
|
-
#[case(Flex::Legacy, 1, &[Length(2), Length(0)], "a")] // overflow, zero
|
|
1591
|
-
#[case(Flex::Legacy, 1, &[Length(2), Length(1)], "a")] // overflow, exact
|
|
1592
|
-
#[case(Flex::Legacy, 1, &[Length(2), Length(2)], "a")] // overflow, overflow
|
|
1593
|
-
#[case(Flex::Legacy, 2, &[Length(0), Length(0)], "bb")] // zero, zero
|
|
1594
|
-
#[case(Flex::Legacy, 2, &[Length(0), Length(1)], "bb")] // zero, underflow
|
|
1595
|
-
#[case(Flex::Legacy, 2, &[Length(0), Length(2)], "bb")] // zero, exact
|
|
1596
|
-
#[case(Flex::Legacy, 2, &[Length(0), Length(3)], "bb")] // zero, overflow
|
|
1597
|
-
#[case(Flex::Legacy, 2, &[Length(1), Length(0)], "ab")] // underflow, zero
|
|
1598
|
-
#[case(Flex::Legacy, 2, &[Length(1), Length(1)], "ab")] // underflow, underflow
|
|
1599
|
-
#[case(Flex::Legacy, 2, &[Length(1), Length(2)], "ab")] // underflow, exact
|
|
1600
|
-
#[case(Flex::Legacy, 2, &[Length(1), Length(3)], "ab")] // underflow, overflow
|
|
1601
|
-
#[case(Flex::Legacy, 2, &[Length(2), Length(0)], "aa")] // exact, zero
|
|
1602
|
-
#[case(Flex::Legacy, 2, &[Length(2), Length(1)], "aa")] // exact, underflow
|
|
1603
|
-
#[case(Flex::Legacy, 2, &[Length(2), Length(2)], "aa")] // exact, exact
|
|
1604
|
-
#[case(Flex::Legacy, 2, &[Length(2), Length(3)], "aa")] // exact, overflow
|
|
1605
|
-
#[case(Flex::Legacy, 2, &[Length(3), Length(0)], "aa")] // overflow, zero
|
|
1606
|
-
#[case(Flex::Legacy, 2, &[Length(3), Length(1)], "aa")] // overflow, underflow
|
|
1607
|
-
#[case(Flex::Legacy, 2, &[Length(3), Length(2)], "aa")] // overflow, exact
|
|
1608
|
-
#[case(Flex::Legacy, 2, &[Length(3), Length(3)], "aa")] // overflow, overflow
|
|
1609
|
-
#[case(Flex::Legacy, 3, &[Length(2), Length(2)], "aab")] // with stretchlast
|
|
1610
|
-
fn length(
|
|
1611
|
-
#[case] flex: Flex,
|
|
1612
|
-
#[case] width: u16,
|
|
1613
|
-
#[case] constraints: &[Constraint],
|
|
1614
|
-
#[case] expected: &str,
|
|
1615
|
-
) {
|
|
1616
|
-
letters(flex, constraints, width, expected);
|
|
1617
|
-
}
|
|
1618
|
-
|
|
1619
|
-
#[rstest]
|
|
1620
|
-
#[case(Flex::Legacy, 1, &[Max(0)], "a")] // zero
|
|
1621
|
-
#[case(Flex::Legacy, 1, &[Max(1)], "a")] // exact
|
|
1622
|
-
#[case(Flex::Legacy, 1, &[Max(2)], "a")] // overflow
|
|
1623
|
-
#[case(Flex::Legacy, 2, &[Max(0)], "aa")] // zero
|
|
1624
|
-
#[case(Flex::Legacy, 2, &[Max(1)], "aa")] // underflow
|
|
1625
|
-
#[case(Flex::Legacy, 2, &[Max(2)], "aa")] // exact
|
|
1626
|
-
#[case(Flex::Legacy, 2, &[Max(3)], "aa")] // overflow
|
|
1627
|
-
#[case(Flex::Legacy, 1, &[Max(0), Max(0)], "b")] // zero, zero
|
|
1628
|
-
#[case(Flex::Legacy, 1, &[Max(0), Max(1)], "b")] // zero, exact
|
|
1629
|
-
#[case(Flex::Legacy, 1, &[Max(0), Max(2)], "b")] // zero, overflow
|
|
1630
|
-
#[case(Flex::Legacy, 1, &[Max(1), Max(0)], "a")] // exact, zero
|
|
1631
|
-
#[case(Flex::Legacy, 1, &[Max(1), Max(1)], "a")] // exact, exact
|
|
1632
|
-
#[case(Flex::Legacy, 1, &[Max(1), Max(2)], "a")] // exact, overflow
|
|
1633
|
-
#[case(Flex::Legacy, 1, &[Max(2), Max(0)], "a")] // overflow, zero
|
|
1634
|
-
#[case(Flex::Legacy, 1, &[Max(2), Max(1)], "a")] // overflow, exact
|
|
1635
|
-
#[case(Flex::Legacy, 1, &[Max(2), Max(2)], "a")] // overflow, overflow
|
|
1636
|
-
#[case(Flex::Legacy, 2, &[Max(0), Max(0)], "bb")] // zero, zero
|
|
1637
|
-
#[case(Flex::Legacy, 2, &[Max(0), Max(1)], "bb")] // zero, underflow
|
|
1638
|
-
#[case(Flex::Legacy, 2, &[Max(0), Max(2)], "bb")] // zero, exact
|
|
1639
|
-
#[case(Flex::Legacy, 2, &[Max(0), Max(3)], "bb")] // zero, overflow
|
|
1640
|
-
#[case(Flex::Legacy, 2, &[Max(1), Max(0)], "ab")] // underflow, zero
|
|
1641
|
-
#[case(Flex::Legacy, 2, &[Max(1), Max(1)], "ab")] // underflow, underflow
|
|
1642
|
-
#[case(Flex::Legacy, 2, &[Max(1), Max(2)], "ab")] // underflow, exact
|
|
1643
|
-
#[case(Flex::Legacy, 2, &[Max(1), Max(3)], "ab")] // underflow, overflow
|
|
1644
|
-
#[case(Flex::Legacy, 2, &[Max(2), Max(0)], "aa")] // exact, zero
|
|
1645
|
-
#[case(Flex::Legacy, 2, &[Max(2), Max(1)], "aa")] // exact, underflow
|
|
1646
|
-
#[case(Flex::Legacy, 2, &[Max(2), Max(2)], "aa")] // exact, exact
|
|
1647
|
-
#[case(Flex::Legacy, 2, &[Max(2), Max(3)], "aa")] // exact, overflow
|
|
1648
|
-
#[case(Flex::Legacy, 2, &[Max(3), Max(0)], "aa")] // overflow, zero
|
|
1649
|
-
#[case(Flex::Legacy, 2, &[Max(3), Max(1)], "aa")] // overflow, underflow
|
|
1650
|
-
#[case(Flex::Legacy, 2, &[Max(3), Max(2)], "aa")] // overflow, exact
|
|
1651
|
-
#[case(Flex::Legacy, 2, &[Max(3), Max(3)], "aa")] // overflow, overflow
|
|
1652
|
-
#[case(Flex::Legacy, 3, &[Max(2), Max(2)], "aab")]
|
|
1653
|
-
fn max(
|
|
1654
|
-
#[case] flex: Flex,
|
|
1655
|
-
#[case] width: u16,
|
|
1656
|
-
#[case] constraints: &[Constraint],
|
|
1657
|
-
#[case] expected: &str,
|
|
1658
|
-
) {
|
|
1659
|
-
letters(flex, constraints, width, expected);
|
|
1660
|
-
}
|
|
1661
|
-
|
|
1662
|
-
#[rstest]
|
|
1663
|
-
#[case(Flex::Legacy, 1, &[Min(0), Min(0)], "b")] // zero, zero
|
|
1664
|
-
#[case(Flex::Legacy, 1, &[Min(0), Min(1)], "b")] // zero, exact
|
|
1665
|
-
#[case(Flex::Legacy, 1, &[Min(0), Min(2)], "b")] // zero, overflow
|
|
1666
|
-
#[case(Flex::Legacy, 1, &[Min(1), Min(0)], "a")] // exact, zero
|
|
1667
|
-
#[case(Flex::Legacy, 1, &[Min(1), Min(1)], "a")] // exact, exact
|
|
1668
|
-
#[case(Flex::Legacy, 1, &[Min(1), Min(2)], "a")] // exact, overflow
|
|
1669
|
-
#[case(Flex::Legacy, 1, &[Min(2), Min(0)], "a")] // overflow, zero
|
|
1670
|
-
#[case(Flex::Legacy, 1, &[Min(2), Min(1)], "a")] // overflow, exact
|
|
1671
|
-
#[case(Flex::Legacy, 1, &[Min(2), Min(2)], "a")] // overflow, overflow
|
|
1672
|
-
#[case(Flex::Legacy, 2, &[Min(0), Min(0)], "bb")] // zero, zero
|
|
1673
|
-
#[case(Flex::Legacy, 2, &[Min(0), Min(1)], "bb")] // zero, underflow
|
|
1674
|
-
#[case(Flex::Legacy, 2, &[Min(0), Min(2)], "bb")] // zero, exact
|
|
1675
|
-
#[case(Flex::Legacy, 2, &[Min(0), Min(3)], "bb")] // zero, overflow
|
|
1676
|
-
#[case(Flex::Legacy, 2, &[Min(1), Min(0)], "ab")] // underflow, zero
|
|
1677
|
-
#[case(Flex::Legacy, 2, &[Min(1), Min(1)], "ab")] // underflow, underflow
|
|
1678
|
-
#[case(Flex::Legacy, 2, &[Min(1), Min(2)], "ab")] // underflow, exact
|
|
1679
|
-
#[case(Flex::Legacy, 2, &[Min(1), Min(3)], "ab")] // underflow, overflow
|
|
1680
|
-
#[case(Flex::Legacy, 2, &[Min(2), Min(0)], "aa")] // exact, zero
|
|
1681
|
-
#[case(Flex::Legacy, 2, &[Min(2), Min(1)], "aa")] // exact, underflow
|
|
1682
|
-
#[case(Flex::Legacy, 2, &[Min(2), Min(2)], "aa")] // exact, exact
|
|
1683
|
-
#[case(Flex::Legacy, 2, &[Min(2), Min(3)], "aa")] // exact, overflow
|
|
1684
|
-
#[case(Flex::Legacy, 2, &[Min(3), Min(0)], "aa")] // overflow, zero
|
|
1685
|
-
#[case(Flex::Legacy, 2, &[Min(3), Min(1)], "aa")] // overflow, underflow
|
|
1686
|
-
#[case(Flex::Legacy, 2, &[Min(3), Min(2)], "aa")] // overflow, exact
|
|
1687
|
-
#[case(Flex::Legacy, 2, &[Min(3), Min(3)], "aa")] // overflow, overflow
|
|
1688
|
-
#[case(Flex::Legacy, 3, &[Min(2), Min(2)], "aab")]
|
|
1689
|
-
fn min(
|
|
1690
|
-
#[case] flex: Flex,
|
|
1691
|
-
#[case] width: u16,
|
|
1692
|
-
#[case] constraints: &[Constraint],
|
|
1693
|
-
#[case] expected: &str,
|
|
1694
|
-
) {
|
|
1695
|
-
letters(flex, constraints, width, expected);
|
|
1696
|
-
}
|
|
1697
|
-
|
|
1698
|
-
#[rstest] // flex, width, lengths, expected
|
|
1699
|
-
// One constraint will take all the space (width = 1)
|
|
1700
|
-
#[case(Flex::Legacy, 1, &[Percentage(0)], "a")]
|
|
1701
|
-
#[case(Flex::Legacy, 1, &[Percentage(25)], "a")]
|
|
1702
|
-
#[case(Flex::Legacy, 1, &[Percentage(50)], "a")]
|
|
1703
|
-
#[case(Flex::Legacy, 1, &[Percentage(90)], "a")]
|
|
1704
|
-
#[case(Flex::Legacy, 1, &[Percentage(100)], "a")]
|
|
1705
|
-
#[case(Flex::Legacy, 1, &[Percentage(200)], "a")]
|
|
1706
|
-
// One constraint will take all the space (width = 2)
|
|
1707
|
-
#[case(Flex::Legacy, 2, &[Percentage(0)], "aa")]
|
|
1708
|
-
#[case(Flex::Legacy, 2, &[Percentage(10)], "aa")]
|
|
1709
|
-
#[case(Flex::Legacy, 2, &[Percentage(25)], "aa")]
|
|
1710
|
-
#[case(Flex::Legacy, 2, &[Percentage(50)], "aa")]
|
|
1711
|
-
#[case(Flex::Legacy, 2, &[Percentage(66)], "aa")]
|
|
1712
|
-
#[case(Flex::Legacy, 2, &[Percentage(100)], "aa")]
|
|
1713
|
-
#[case(Flex::Legacy, 2, &[Percentage(200)], "aa")]
|
|
1714
|
-
// One constraint will take all the space (width = 3)
|
|
1715
|
-
#[case(Flex::Legacy, 10, &[Percentage(0)], "aaaaaaaaaa")]
|
|
1716
|
-
#[case(Flex::Legacy, 10, &[Percentage(10)], "aaaaaaaaaa")]
|
|
1717
|
-
#[case(Flex::Legacy, 10, &[Percentage(25)], "aaaaaaaaaa")]
|
|
1718
|
-
#[case(Flex::Legacy, 10, &[Percentage(50)], "aaaaaaaaaa")]
|
|
1719
|
-
#[case(Flex::Legacy, 10, &[Percentage(66)], "aaaaaaaaaa")]
|
|
1720
|
-
#[case(Flex::Legacy, 10, &[Percentage(100)], "aaaaaaaaaa")]
|
|
1721
|
-
#[case(Flex::Legacy, 10, &[Percentage(200)], "aaaaaaaaaa")]
|
|
1722
|
-
// 0%/any allocates all the space to the second constraint
|
|
1723
|
-
#[case(Flex::Legacy, 1, &[Percentage(0), Percentage(0)], "b")]
|
|
1724
|
-
#[case(Flex::Legacy, 1, &[Percentage(0), Percentage(10)], "b")]
|
|
1725
|
-
#[case(Flex::Legacy, 1, &[Percentage(0), Percentage(50)], "b")]
|
|
1726
|
-
#[case(Flex::Legacy, 1, &[Percentage(0), Percentage(90)], "b")]
|
|
1727
|
-
#[case(Flex::Legacy, 1, &[Percentage(0), Percentage(100)], "b")]
|
|
1728
|
-
#[case(Flex::Legacy, 1, &[Percentage(0), Percentage(200)], "b")]
|
|
1729
|
-
// 10%/any allocates all the space to the second constraint (even if it is 0)
|
|
1730
|
-
#[case(Flex::Legacy, 1, &[Percentage(10), Percentage(0)], "b")]
|
|
1731
|
-
#[case(Flex::Legacy, 1, &[Percentage(10), Percentage(10)], "b")]
|
|
1732
|
-
#[case(Flex::Legacy, 1, &[Percentage(10), Percentage(50)], "b")]
|
|
1733
|
-
#[case(Flex::Legacy, 1, &[Percentage(10), Percentage(90)], "b")]
|
|
1734
|
-
#[case(Flex::Legacy, 1, &[Percentage(10), Percentage(100)], "b")]
|
|
1735
|
-
#[case(Flex::Legacy, 1, &[Percentage(10), Percentage(200)], "b")]
|
|
1736
|
-
// 50%/any allocates all the space to the first constraint
|
|
1737
|
-
#[case(Flex::Legacy, 1, &[Percentage(50), Percentage(0)], "a")]
|
|
1738
|
-
#[case(Flex::Legacy, 1, &[Percentage(50), Percentage(50)], "a")]
|
|
1739
|
-
#[case(Flex::Legacy, 1, &[Percentage(50), Percentage(100)], "a")]
|
|
1740
|
-
#[case(Flex::Legacy, 1, &[Percentage(50), Percentage(200)], "a")]
|
|
1741
|
-
// 90%/any allocates all the space to the first constraint
|
|
1742
|
-
#[case(Flex::Legacy, 1, &[Percentage(90), Percentage(0)], "a")]
|
|
1743
|
-
#[case(Flex::Legacy, 1, &[Percentage(90), Percentage(50)], "a")]
|
|
1744
|
-
#[case(Flex::Legacy, 1, &[Percentage(90), Percentage(100)], "a")]
|
|
1745
|
-
#[case(Flex::Legacy, 1, &[Percentage(90), Percentage(200)], "a")]
|
|
1746
|
-
// 100%/any allocates all the space to the first constraint
|
|
1747
|
-
#[case(Flex::Legacy, 1, &[Percentage(100), Percentage(0)], "a")]
|
|
1748
|
-
#[case(Flex::Legacy, 1, &[Percentage(100), Percentage(50)], "a")]
|
|
1749
|
-
#[case(Flex::Legacy, 1, &[Percentage(100), Percentage(100)], "a")]
|
|
1750
|
-
#[case(Flex::Legacy, 1, &[Percentage(100), Percentage(200)], "a")]
|
|
1751
|
-
// 0%/any allocates all the space to the second constraint
|
|
1752
|
-
#[case(Flex::Legacy, 2, &[Percentage(0), Percentage(0)], "bb")]
|
|
1753
|
-
#[case(Flex::Legacy, 2, &[Percentage(0), Percentage(25)], "bb")]
|
|
1754
|
-
#[case(Flex::Legacy, 2, &[Percentage(0), Percentage(50)], "bb")]
|
|
1755
|
-
#[case(Flex::Legacy, 2, &[Percentage(0), Percentage(100)], "bb")]
|
|
1756
|
-
#[case(Flex::Legacy, 2, &[Percentage(0), Percentage(200)], "bb")]
|
|
1757
|
-
// 10%/any allocates all the space to the second constraint
|
|
1758
|
-
#[case(Flex::Legacy, 2, &[Percentage(10), Percentage(0)], "bb")]
|
|
1759
|
-
#[case(Flex::Legacy, 2, &[Percentage(10), Percentage(25)], "bb")]
|
|
1760
|
-
#[case(Flex::Legacy, 2, &[Percentage(10), Percentage(50)], "bb")]
|
|
1761
|
-
#[case(Flex::Legacy, 2, &[Percentage(10), Percentage(100)], "bb")]
|
|
1762
|
-
#[case(Flex::Legacy, 2, &[Percentage(10), Percentage(200)], "bb")]
|
|
1763
|
-
// 25% * 2 = 0.5, which rounds up to 1, so the first constraint gets 1
|
|
1764
|
-
#[case(Flex::Legacy, 2, &[Percentage(25), Percentage(0)], "ab")]
|
|
1765
|
-
#[case(Flex::Legacy, 2, &[Percentage(25), Percentage(25)], "ab")]
|
|
1766
|
-
#[case(Flex::Legacy, 2, &[Percentage(25), Percentage(50)], "ab")]
|
|
1767
|
-
#[case(Flex::Legacy, 2, &[Percentage(25), Percentage(100)], "ab")]
|
|
1768
|
-
#[case(Flex::Legacy, 2, &[Percentage(25), Percentage(200)], "ab")]
|
|
1769
|
-
// 33% * 2 = 0.66, so the first constraint gets 1
|
|
1770
|
-
#[case(Flex::Legacy, 2, &[Percentage(33), Percentage(0)], "ab")]
|
|
1771
|
-
#[case(Flex::Legacy, 2, &[Percentage(33), Percentage(25)], "ab")]
|
|
1772
|
-
#[case(Flex::Legacy, 2, &[Percentage(33), Percentage(50)], "ab")]
|
|
1773
|
-
#[case(Flex::Legacy, 2, &[Percentage(33), Percentage(100)], "ab")]
|
|
1774
|
-
#[case(Flex::Legacy, 2, &[Percentage(33), Percentage(200)], "ab")]
|
|
1775
|
-
// 50% * 2 = 1, so the first constraint gets 1
|
|
1776
|
-
#[case(Flex::Legacy, 2, &[Percentage(50), Percentage(0)], "ab")]
|
|
1777
|
-
#[case(Flex::Legacy, 2, &[Percentage(50), Percentage(50)], "ab")]
|
|
1778
|
-
#[case(Flex::Legacy, 2, &[Percentage(50), Percentage(100)], "ab")]
|
|
1779
|
-
// 100%/any allocates all the space to the first constraint
|
|
1780
|
-
// This is probably not the correct behavior, but it is the current behavior
|
|
1781
|
-
#[case(Flex::Legacy, 2, &[Percentage(100), Percentage(0)], "aa")]
|
|
1782
|
-
#[case(Flex::Legacy, 2, &[Percentage(100), Percentage(50)], "aa")]
|
|
1783
|
-
#[case(Flex::Legacy, 2, &[Percentage(100), Percentage(100)], "aa")]
|
|
1784
|
-
// 33%/any allocates 1 to the first constraint the rest to the second
|
|
1785
|
-
#[case(Flex::Legacy, 3, &[Percentage(33), Percentage(33)], "abb")]
|
|
1786
|
-
#[case(Flex::Legacy, 3, &[Percentage(33), Percentage(66)], "abb")]
|
|
1787
|
-
// 33%/any allocates 1.33 = 1 to the first constraint the rest to the second
|
|
1788
|
-
#[case(Flex::Legacy, 4, &[Percentage(33), Percentage(33)], "abbb")]
|
|
1789
|
-
#[case(Flex::Legacy, 4, &[Percentage(33), Percentage(66)], "abbb")]
|
|
1790
|
-
// Longer tests zero allocates everything to the second constraint
|
|
1791
|
-
#[case(Flex::Legacy, 10, &[Percentage(0), Percentage(0)], "bbbbbbbbbb" )]
|
|
1792
|
-
#[case(Flex::Legacy, 10, &[Percentage(0), Percentage(25)], "bbbbbbbbbb" )]
|
|
1793
|
-
#[case(Flex::Legacy, 10, &[Percentage(0), Percentage(50)], "bbbbbbbbbb" )]
|
|
1794
|
-
#[case(Flex::Legacy, 10, &[Percentage(0), Percentage(100)], "bbbbbbbbbb" )]
|
|
1795
|
-
#[case(Flex::Legacy, 10, &[Percentage(0), Percentage(200)], "bbbbbbbbbb" )]
|
|
1796
|
-
// 10% allocates a single character to the first constraint
|
|
1797
|
-
#[case(Flex::Legacy, 10, &[Percentage(10), Percentage(0)], "abbbbbbbbb" )]
|
|
1798
|
-
#[case(Flex::Legacy, 10, &[Percentage(10), Percentage(25)], "abbbbbbbbb" )]
|
|
1799
|
-
#[case(Flex::Legacy, 10, &[Percentage(10), Percentage(50)], "abbbbbbbbb" )]
|
|
1800
|
-
#[case(Flex::Legacy, 10, &[Percentage(10), Percentage(100)], "abbbbbbbbb" )]
|
|
1801
|
-
#[case(Flex::Legacy, 10, &[Percentage(10), Percentage(200)], "abbbbbbbbb" )]
|
|
1802
|
-
// 25% allocates 2.5 = 3 characters to the first constraint
|
|
1803
|
-
#[case(Flex::Legacy, 10, &[Percentage(25), Percentage(0)], "aaabbbbbbb" )]
|
|
1804
|
-
#[case(Flex::Legacy, 10, &[Percentage(25), Percentage(25)], "aaabbbbbbb" )]
|
|
1805
|
-
#[case(Flex::Legacy, 10, &[Percentage(25), Percentage(50)], "aaabbbbbbb" )]
|
|
1806
|
-
#[case(Flex::Legacy, 10, &[Percentage(25), Percentage(100)], "aaabbbbbbb" )]
|
|
1807
|
-
#[case(Flex::Legacy, 10, &[Percentage(25), Percentage(200)], "aaabbbbbbb" )]
|
|
1808
|
-
// 33% allocates 3.3 = 3 characters to the first constraint
|
|
1809
|
-
#[case(Flex::Legacy, 10, &[Percentage(33), Percentage(0)], "aaabbbbbbb" )]
|
|
1810
|
-
#[case(Flex::Legacy, 10, &[Percentage(33), Percentage(25)], "aaabbbbbbb" )]
|
|
1811
|
-
#[case(Flex::Legacy, 10, &[Percentage(33), Percentage(50)], "aaabbbbbbb" )]
|
|
1812
|
-
#[case(Flex::Legacy, 10, &[Percentage(33), Percentage(100)], "aaabbbbbbb" )]
|
|
1813
|
-
#[case(Flex::Legacy, 10, &[Percentage(33), Percentage(200)], "aaabbbbbbb" )]
|
|
1814
|
-
// 50% allocates 5 characters to the first constraint
|
|
1815
|
-
#[case(Flex::Legacy, 10, &[Percentage(50), Percentage(0)], "aaaaabbbbb" )]
|
|
1816
|
-
#[case(Flex::Legacy, 10, &[Percentage(50), Percentage(50)], "aaaaabbbbb" )]
|
|
1817
|
-
#[case(Flex::Legacy, 10, &[Percentage(50), Percentage(100)], "aaaaabbbbb" )]
|
|
1818
|
-
// 100% allocates everything to the first constraint
|
|
1819
|
-
#[case(Flex::Legacy, 10, &[Percentage(100), Percentage(0)], "aaaaaaaaaa" )]
|
|
1820
|
-
#[case(Flex::Legacy, 10, &[Percentage(100), Percentage(50)], "aaaaaaaaaa" )]
|
|
1821
|
-
#[case(Flex::Legacy, 10, &[Percentage(100), Percentage(100)], "aaaaaaaaaa" )]
|
|
1822
|
-
fn percentage(
|
|
1823
|
-
#[case] flex: Flex,
|
|
1824
|
-
#[case] width: u16,
|
|
1825
|
-
#[case] constraints: &[Constraint],
|
|
1826
|
-
#[case] expected: &str,
|
|
1827
|
-
) {
|
|
1828
|
-
letters(flex, constraints, width, expected);
|
|
1829
|
-
}
|
|
1830
|
-
|
|
1831
|
-
#[rstest]
|
|
1832
|
-
#[case(Flex::Start, 10, &[Percentage(0), Percentage(0)], " " )]
|
|
1833
|
-
#[case(Flex::Start, 10, &[Percentage(0), Percentage(25)], "bbb " )]
|
|
1834
|
-
#[case(Flex::Start, 10, &[Percentage(0), Percentage(50)], "bbbbb " )]
|
|
1835
|
-
#[case(Flex::Start, 10, &[Percentage(0), Percentage(100)], "bbbbbbbbbb" )]
|
|
1836
|
-
#[case(Flex::Start, 10, &[Percentage(0), Percentage(200)], "bbbbbbbbbb" )]
|
|
1837
|
-
#[case(Flex::Start, 10, &[Percentage(10), Percentage(0)], "a " )]
|
|
1838
|
-
#[case(Flex::Start, 10, &[Percentage(10), Percentage(25)], "abbb " )]
|
|
1839
|
-
#[case(Flex::Start, 10, &[Percentage(10), Percentage(50)], "abbbbb " )]
|
|
1840
|
-
#[case(Flex::Start, 10, &[Percentage(10), Percentage(100)], "abbbbbbbbb" )]
|
|
1841
|
-
#[case(Flex::Start, 10, &[Percentage(10), Percentage(200)], "abbbbbbbbb" )]
|
|
1842
|
-
#[case(Flex::Start, 10, &[Percentage(25), Percentage(0)], "aaa " )]
|
|
1843
|
-
#[case(Flex::Start, 10, &[Percentage(25), Percentage(25)], "aaabb " )]
|
|
1844
|
-
#[case(Flex::Start, 10, &[Percentage(25), Percentage(50)], "aaabbbbb " )]
|
|
1845
|
-
#[case(Flex::Start, 10, &[Percentage(25), Percentage(100)], "aaabbbbbbb" )]
|
|
1846
|
-
#[case(Flex::Start, 10, &[Percentage(25), Percentage(200)], "aaabbbbbbb" )]
|
|
1847
|
-
#[case(Flex::Start, 10, &[Percentage(33), Percentage(0)], "aaa " )]
|
|
1848
|
-
#[case(Flex::Start, 10, &[Percentage(33), Percentage(25)], "aaabbb " )]
|
|
1849
|
-
#[case(Flex::Start, 10, &[Percentage(33), Percentage(50)], "aaabbbbb " )]
|
|
1850
|
-
#[case(Flex::Start, 10, &[Percentage(33), Percentage(100)], "aaabbbbbbb" )]
|
|
1851
|
-
#[case(Flex::Start, 10, &[Percentage(33), Percentage(200)], "aaabbbbbbb" )]
|
|
1852
|
-
#[case(Flex::Start, 10, &[Percentage(50), Percentage(0)], "aaaaa " )]
|
|
1853
|
-
#[case(Flex::Start, 10, &[Percentage(50), Percentage(50)], "aaaaabbbbb" )]
|
|
1854
|
-
#[case(Flex::Start, 10, &[Percentage(50), Percentage(100)], "aaaaabbbbb" )]
|
|
1855
|
-
#[case(Flex::Start, 10, &[Percentage(100), Percentage(0)], "aaaaaaaaaa" )]
|
|
1856
|
-
#[case(Flex::Start, 10, &[Percentage(100), Percentage(50)], "aaaaabbbbb" )]
|
|
1857
|
-
#[case(Flex::Start, 10, &[Percentage(100), Percentage(100)], "aaaaabbbbb" )]
|
|
1858
|
-
#[case(Flex::Start, 10, &[Percentage(100), Percentage(200)], "aaaaabbbbb" )]
|
|
1859
|
-
fn percentage_start(
|
|
1860
|
-
#[case] flex: Flex,
|
|
1861
|
-
#[case] width: u16,
|
|
1862
|
-
#[case] constraints: &[Constraint],
|
|
1863
|
-
#[case] expected: &str,
|
|
1864
|
-
) {
|
|
1865
|
-
letters(flex, constraints, width, expected);
|
|
1866
|
-
}
|
|
1867
|
-
|
|
1868
|
-
#[rstest]
|
|
1869
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(0), Percentage(0)], " " )]
|
|
1870
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(0), Percentage(25)], " bb" )]
|
|
1871
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(0), Percentage(50)], " bbbbb" )]
|
|
1872
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(0), Percentage(100)], "bbbbbbbbbb" )]
|
|
1873
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(0), Percentage(200)], "bbbbbbbbbb" )]
|
|
1874
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(10), Percentage(0)], "a " )]
|
|
1875
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(10), Percentage(25)], "a bb" )]
|
|
1876
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(10), Percentage(50)], "a bbbbb" )]
|
|
1877
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(10), Percentage(100)], "abbbbbbbbb" )]
|
|
1878
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(10), Percentage(200)], "abbbbbbbbb" )]
|
|
1879
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(25), Percentage(0)], "aaa " )]
|
|
1880
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(25), Percentage(25)], "aaa bb" )]
|
|
1881
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(25), Percentage(50)], "aaa bbbbb" )]
|
|
1882
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(25), Percentage(100)], "aaabbbbbbb" )]
|
|
1883
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(25), Percentage(200)], "aaabbbbbbb" )]
|
|
1884
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(33), Percentage(0)], "aaa " )]
|
|
1885
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(33), Percentage(25)], "aaa bb" )]
|
|
1886
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(33), Percentage(50)], "aaa bbbbb" )]
|
|
1887
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(33), Percentage(100)], "aaabbbbbbb" )]
|
|
1888
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(33), Percentage(200)], "aaabbbbbbb" )]
|
|
1889
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(50), Percentage(0)], "aaaaa " )]
|
|
1890
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(50), Percentage(50)], "aaaaabbbbb" )]
|
|
1891
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(50), Percentage(100)], "aaaaabbbbb" )]
|
|
1892
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(100), Percentage(0)], "aaaaaaaaaa" )]
|
|
1893
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(100), Percentage(50)], "aaaaabbbbb" )]
|
|
1894
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(100), Percentage(100)], "aaaaabbbbb" )]
|
|
1895
|
-
#[case(Flex::SpaceBetween, 10, &[Percentage(100), Percentage(200)], "aaaaabbbbb" )]
|
|
1896
|
-
fn percentage_spacebetween(
|
|
1897
|
-
#[case] flex: Flex,
|
|
1898
|
-
#[case] width: u16,
|
|
1899
|
-
#[case] constraints: &[Constraint],
|
|
1900
|
-
#[case] expected: &str,
|
|
1901
|
-
) {
|
|
1902
|
-
letters(flex, constraints, width, expected);
|
|
1903
|
-
}
|
|
1904
|
-
|
|
1905
|
-
#[rstest]
|
|
1906
|
-
// flex, width, ratios, expected
|
|
1907
|
-
// Just one ratio takes up the whole space
|
|
1908
|
-
#[case(Flex::Legacy, 1, &[Ratio(0, 1)], "a")]
|
|
1909
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 4)], "a")]
|
|
1910
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 2)], "a")]
|
|
1911
|
-
#[case(Flex::Legacy, 1, &[Ratio(9, 10)], "a")]
|
|
1912
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 1)], "a")]
|
|
1913
|
-
#[case(Flex::Legacy, 1, &[Ratio(2, 1)], "a")]
|
|
1914
|
-
#[case(Flex::Legacy, 2, &[Ratio(0, 1)], "aa")]
|
|
1915
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 10)], "aa")]
|
|
1916
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 4)], "aa")]
|
|
1917
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 2)], "aa")]
|
|
1918
|
-
#[case(Flex::Legacy, 2, &[Ratio(2, 3)], "aa")]
|
|
1919
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 1)], "aa")]
|
|
1920
|
-
#[case(Flex::Legacy, 2, &[Ratio(2, 1)], "aa")]
|
|
1921
|
-
#[case(Flex::Legacy, 1, &[Ratio(0, 1), Ratio(0, 1)], "b")]
|
|
1922
|
-
#[case(Flex::Legacy, 1, &[Ratio(0, 1), Ratio(1, 10)], "b")]
|
|
1923
|
-
#[case(Flex::Legacy, 1, &[Ratio(0, 1), Ratio(1, 2)], "b")]
|
|
1924
|
-
#[case(Flex::Legacy, 1, &[Ratio(0, 1), Ratio(9, 10)], "b")]
|
|
1925
|
-
#[case(Flex::Legacy, 1, &[Ratio(0, 1), Ratio(1, 1)], "b")]
|
|
1926
|
-
#[case(Flex::Legacy, 1, &[Ratio(0, 1), Ratio(2, 1)], "b")]
|
|
1927
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 10), Ratio(0, 1)], "b")]
|
|
1928
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 10), Ratio(1, 10)], "b")]
|
|
1929
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 10), Ratio(1, 2)], "b")]
|
|
1930
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 10), Ratio(9, 10)], "b")]
|
|
1931
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 10), Ratio(1, 1)], "b")]
|
|
1932
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 10), Ratio(2, 1)], "b")]
|
|
1933
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 2), Ratio(0, 1)], "a")]
|
|
1934
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 2), Ratio(1, 2)], "a")]
|
|
1935
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 2), Ratio(1, 1)], "a")]
|
|
1936
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 2), Ratio(2, 1)], "a")]
|
|
1937
|
-
#[case(Flex::Legacy, 1, &[Ratio(9, 10), Ratio(0, 1)], "a")]
|
|
1938
|
-
#[case(Flex::Legacy, 1, &[Ratio(9, 10), Ratio(1, 2)], "a")]
|
|
1939
|
-
#[case(Flex::Legacy, 1, &[Ratio(9, 10), Ratio(1, 1)], "a")]
|
|
1940
|
-
#[case(Flex::Legacy, 1, &[Ratio(9, 10), Ratio(2, 1)], "a")]
|
|
1941
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 1), Ratio(0, 1)], "a")]
|
|
1942
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 1), Ratio(1, 2)], "a")]
|
|
1943
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 1), Ratio(1, 1)], "a")]
|
|
1944
|
-
#[case(Flex::Legacy, 1, &[Ratio(1, 1), Ratio(2, 1)], "a")]
|
|
1945
|
-
#[case(Flex::Legacy, 2, &[Ratio(0, 1), Ratio(0, 1)], "bb")]
|
|
1946
|
-
#[case(Flex::Legacy, 2, &[Ratio(0, 1), Ratio(1, 4)], "bb")]
|
|
1947
|
-
#[case(Flex::Legacy, 2, &[Ratio(0, 1), Ratio(1, 2)], "bb")]
|
|
1948
|
-
#[case(Flex::Legacy, 2, &[Ratio(0, 1), Ratio(1, 1)], "bb")]
|
|
1949
|
-
#[case(Flex::Legacy, 2, &[Ratio(0, 1), Ratio(2, 1)], "bb")]
|
|
1950
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 10), Ratio(0, 1)], "bb")]
|
|
1951
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 10), Ratio(1, 4)], "bb")]
|
|
1952
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 10), Ratio(1, 2)], "bb")]
|
|
1953
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 10), Ratio(1, 1)], "bb")]
|
|
1954
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 10), Ratio(2, 1)], "bb")]
|
|
1955
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 4), Ratio(0, 1)], "ab")]
|
|
1956
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 4), Ratio(1, 4)], "ab")]
|
|
1957
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 4), Ratio(1, 2)], "ab")]
|
|
1958
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 4), Ratio(1, 1)], "ab")]
|
|
1959
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 4), Ratio(2, 1)], "ab")]
|
|
1960
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 3), Ratio(0, 1)], "ab")]
|
|
1961
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 3), Ratio(1, 4)], "ab")]
|
|
1962
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 3), Ratio(1, 2)], "ab")]
|
|
1963
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 3), Ratio(1, 1)], "ab")]
|
|
1964
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 3), Ratio(2, 1)], "ab")]
|
|
1965
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 2), Ratio(0, 1)], "ab")]
|
|
1966
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 2), Ratio(1, 2)], "ab")]
|
|
1967
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 2), Ratio(1, 1)], "ab")]
|
|
1968
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 1), Ratio(0, 1)], "aa")]
|
|
1969
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 1), Ratio(1, 2)], "aa")]
|
|
1970
|
-
#[case(Flex::Legacy, 2, &[Ratio(1, 1), Ratio(1, 1)], "aa")]
|
|
1971
|
-
#[case(Flex::Legacy, 3, &[Ratio(1, 3), Ratio(1, 3)], "abb")]
|
|
1972
|
-
#[case(Flex::Legacy, 3, &[Ratio(1, 3), Ratio(2,3)], "abb")]
|
|
1973
|
-
#[case(Flex::Legacy, 10, &[Ratio(0, 1), Ratio(0, 1)], "bbbbbbbbbb" )]
|
|
1974
|
-
#[case(Flex::Legacy, 10, &[Ratio(0, 1), Ratio(1, 4)], "bbbbbbbbbb" )]
|
|
1975
|
-
#[case(Flex::Legacy, 10, &[Ratio(0, 1), Ratio(1, 2)], "bbbbbbbbbb" )]
|
|
1976
|
-
#[case(Flex::Legacy, 10, &[Ratio(0, 1), Ratio(1, 1)], "bbbbbbbbbb" )]
|
|
1977
|
-
#[case(Flex::Legacy, 10, &[Ratio(0, 1), Ratio(2, 1)], "bbbbbbbbbb" )]
|
|
1978
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 10), Ratio(0, 1)], "abbbbbbbbb" )]
|
|
1979
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 10), Ratio(1, 4)], "abbbbbbbbb" )]
|
|
1980
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 10), Ratio(1, 2)], "abbbbbbbbb" )]
|
|
1981
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 10), Ratio(1, 1)], "abbbbbbbbb" )]
|
|
1982
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 10), Ratio(2, 1)], "abbbbbbbbb" )]
|
|
1983
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 4), Ratio(0, 1)], "aaabbbbbbb" )]
|
|
1984
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 4), Ratio(1, 4)], "aaabbbbbbb" )]
|
|
1985
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 4), Ratio(1, 2)], "aaabbbbbbb" )]
|
|
1986
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 4), Ratio(1, 1)], "aaabbbbbbb" )]
|
|
1987
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 4), Ratio(2, 1)], "aaabbbbbbb" )]
|
|
1988
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 3), Ratio(0, 1)], "aaabbbbbbb" )]
|
|
1989
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 3), Ratio(1, 4)], "aaabbbbbbb" )]
|
|
1990
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 3), Ratio(1, 2)], "aaabbbbbbb" )]
|
|
1991
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 3), Ratio(1, 1)], "aaabbbbbbb" )]
|
|
1992
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 3), Ratio(2, 1)], "aaabbbbbbb" )]
|
|
1993
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 2), Ratio(0, 1)], "aaaaabbbbb" )]
|
|
1994
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 2), Ratio(1, 2)], "aaaaabbbbb" )]
|
|
1995
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 2), Ratio(1, 1)], "aaaaabbbbb" )]
|
|
1996
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 1), Ratio(0, 1)], "aaaaaaaaaa" )]
|
|
1997
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 1), Ratio(1, 2)], "aaaaaaaaaa" )]
|
|
1998
|
-
#[case(Flex::Legacy, 10, &[Ratio(1, 1), Ratio(1, 1)], "aaaaaaaaaa" )]
|
|
1999
|
-
fn ratio(
|
|
2000
|
-
#[case] flex: Flex,
|
|
2001
|
-
#[case] width: u16,
|
|
2002
|
-
#[case] constraints: &[Constraint],
|
|
2003
|
-
#[case] expected: &str,
|
|
2004
|
-
) {
|
|
2005
|
-
letters(flex, constraints, width, expected);
|
|
2006
|
-
}
|
|
2007
|
-
|
|
2008
|
-
#[rstest]
|
|
2009
|
-
#[case(Flex::Start, 10, &[Ratio(0, 1), Ratio(0, 1)], " " )]
|
|
2010
|
-
#[case(Flex::Start, 10, &[Ratio(0, 1), Ratio(1, 4)], "bbb " )]
|
|
2011
|
-
#[case(Flex::Start, 10, &[Ratio(0, 1), Ratio(1, 2)], "bbbbb " )]
|
|
2012
|
-
#[case(Flex::Start, 10, &[Ratio(0, 1), Ratio(1, 1)], "bbbbbbbbbb" )]
|
|
2013
|
-
#[case(Flex::Start, 10, &[Ratio(0, 1), Ratio(2, 1)], "bbbbbbbbbb" )]
|
|
2014
|
-
#[case(Flex::Start, 10, &[Ratio(1, 10), Ratio(0, 1)], "a " )]
|
|
2015
|
-
#[case(Flex::Start, 10, &[Ratio(1, 10), Ratio(1, 4)], "abbb " )]
|
|
2016
|
-
#[case(Flex::Start, 10, &[Ratio(1, 10), Ratio(1, 2)], "abbbbb " )]
|
|
2017
|
-
#[case(Flex::Start, 10, &[Ratio(1, 10), Ratio(1, 1)], "abbbbbbbbb" )]
|
|
2018
|
-
#[case(Flex::Start, 10, &[Ratio(1, 10), Ratio(2, 1)], "abbbbbbbbb" )]
|
|
2019
|
-
#[case(Flex::Start, 10, &[Ratio(1, 4), Ratio(0, 1)], "aaa " )]
|
|
2020
|
-
#[case(Flex::Start, 10, &[Ratio(1, 4), Ratio(1, 4)], "aaabb " )]
|
|
2021
|
-
#[case(Flex::Start, 10, &[Ratio(1, 4), Ratio(1, 2)], "aaabbbbb " )]
|
|
2022
|
-
#[case(Flex::Start, 10, &[Ratio(1, 4), Ratio(1, 1)], "aaabbbbbbb" )]
|
|
2023
|
-
#[case(Flex::Start, 10, &[Ratio(1, 4), Ratio(2, 1)], "aaabbbbbbb" )]
|
|
2024
|
-
#[case(Flex::Start, 10, &[Ratio(1, 3), Ratio(0, 1)], "aaa " )]
|
|
2025
|
-
#[case(Flex::Start, 10, &[Ratio(1, 3), Ratio(1, 4)], "aaabbb " )]
|
|
2026
|
-
#[case(Flex::Start, 10, &[Ratio(1, 3), Ratio(1, 2)], "aaabbbbb " )]
|
|
2027
|
-
#[case(Flex::Start, 10, &[Ratio(1, 3), Ratio(1, 1)], "aaabbbbbbb" )]
|
|
2028
|
-
#[case(Flex::Start, 10, &[Ratio(1, 3), Ratio(2, 1)], "aaabbbbbbb" )]
|
|
2029
|
-
#[case(Flex::Start, 10, &[Ratio(1, 2), Ratio(0, 1)], "aaaaa " )]
|
|
2030
|
-
#[case(Flex::Start, 10, &[Ratio(1, 2), Ratio(1, 2)], "aaaaabbbbb" )]
|
|
2031
|
-
#[case(Flex::Start, 10, &[Ratio(1, 2), Ratio(1, 1)], "aaaaabbbbb" )]
|
|
2032
|
-
#[case(Flex::Start, 10, &[Ratio(1, 1), Ratio(0, 1)], "aaaaaaaaaa" )]
|
|
2033
|
-
#[case(Flex::Start, 10, &[Ratio(1, 1), Ratio(1, 2)], "aaaaabbbbb" )]
|
|
2034
|
-
#[case(Flex::Start, 10, &[Ratio(1, 1), Ratio(1, 1)], "aaaaabbbbb" )]
|
|
2035
|
-
#[case(Flex::Start, 10, &[Ratio(1, 1), Ratio(2, 1)], "aaaaabbbbb" )]
|
|
2036
|
-
fn ratio_start(
|
|
2037
|
-
#[case] flex: Flex,
|
|
2038
|
-
#[case] width: u16,
|
|
2039
|
-
#[case] constraints: &[Constraint],
|
|
2040
|
-
#[case] expected: &str,
|
|
2041
|
-
) {
|
|
2042
|
-
letters(flex, constraints, width, expected);
|
|
2043
|
-
}
|
|
2044
|
-
|
|
2045
|
-
#[rstest]
|
|
2046
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(0, 1), Ratio(0, 1)], " " )]
|
|
2047
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(0, 1), Ratio(1, 4)], " bb" )]
|
|
2048
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(0, 1), Ratio(1, 2)], " bbbbb" )]
|
|
2049
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(0, 1), Ratio(1, 1)], "bbbbbbbbbb" )]
|
|
2050
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(0, 1), Ratio(2, 1)], "bbbbbbbbbb" )]
|
|
2051
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 10), Ratio(0, 1)], "a " )]
|
|
2052
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 10), Ratio(1, 4)], "a bb" )]
|
|
2053
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 10), Ratio(1, 2)], "a bbbbb" )]
|
|
2054
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 10), Ratio(1, 1)], "abbbbbbbbb" )]
|
|
2055
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 10), Ratio(2, 1)], "abbbbbbbbb" )]
|
|
2056
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 4), Ratio(0, 1)], "aaa " )]
|
|
2057
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 4), Ratio(1, 4)], "aaa bb" )]
|
|
2058
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 4), Ratio(1, 2)], "aaa bbbbb" )]
|
|
2059
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 4), Ratio(1, 1)], "aaabbbbbbb" )]
|
|
2060
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 4), Ratio(2, 1)], "aaabbbbbbb" )]
|
|
2061
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 3), Ratio(0, 1)], "aaa " )]
|
|
2062
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 3), Ratio(1, 4)], "aaa bb" )]
|
|
2063
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 3), Ratio(1, 2)], "aaa bbbbb" )]
|
|
2064
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 3), Ratio(1, 1)], "aaabbbbbbb" )]
|
|
2065
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 3), Ratio(2, 1)], "aaabbbbbbb" )]
|
|
2066
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 2), Ratio(0, 1)], "aaaaa " )]
|
|
2067
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 2), Ratio(1, 2)], "aaaaabbbbb" )]
|
|
2068
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 2), Ratio(1, 1)], "aaaaabbbbb" )]
|
|
2069
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 1), Ratio(0, 1)], "aaaaaaaaaa" )]
|
|
2070
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 1), Ratio(1, 2)], "aaaaabbbbb" )]
|
|
2071
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 1), Ratio(1, 1)], "aaaaabbbbb" )]
|
|
2072
|
-
#[case(Flex::SpaceBetween, 10, &[Ratio(1, 1), Ratio(2, 1)], "aaaaabbbbb" )]
|
|
2073
|
-
fn ratio_spacebetween(
|
|
2074
|
-
#[case] flex: Flex,
|
|
2075
|
-
#[case] width: u16,
|
|
2076
|
-
#[case] constraints: &[Constraint],
|
|
2077
|
-
#[case] expected: &str,
|
|
2078
|
-
) {
|
|
2079
|
-
letters(flex, constraints, width, expected);
|
|
2080
|
-
}
|
|
2081
|
-
|
|
2082
|
-
#[test]
|
|
2083
|
-
fn vertical_split_by_height() {
|
|
2084
|
-
let target = Rect {
|
|
2085
|
-
x: 2,
|
|
2086
|
-
y: 2,
|
|
2087
|
-
width: 10,
|
|
2088
|
-
height: 10,
|
|
2089
|
-
};
|
|
2090
|
-
|
|
2091
|
-
let chunks = Layout::default()
|
|
2092
|
-
.direction(Direction::Vertical)
|
|
2093
|
-
.constraints([
|
|
2094
|
-
Constraint::Percentage(10),
|
|
2095
|
-
Constraint::Max(5),
|
|
2096
|
-
Constraint::Min(1),
|
|
2097
|
-
])
|
|
2098
|
-
.split(target);
|
|
2099
|
-
|
|
2100
|
-
assert_eq!(chunks.iter().map(|r| r.height).sum::<u16>(), target.height);
|
|
2101
|
-
chunks.windows(2).for_each(|w| assert!(w[0].y <= w[1].y));
|
|
2102
|
-
}
|
|
2103
|
-
|
|
2104
|
-
#[test]
|
|
2105
|
-
fn edge_cases() {
|
|
2106
|
-
// stretches into last
|
|
2107
|
-
let layout = Layout::default()
|
|
2108
|
-
.constraints([
|
|
2109
|
-
Constraint::Percentage(50),
|
|
2110
|
-
Constraint::Percentage(50),
|
|
2111
|
-
Constraint::Min(0),
|
|
2112
|
-
])
|
|
2113
|
-
.split(Rect::new(0, 0, 1, 1));
|
|
2114
|
-
assert_eq!(
|
|
2115
|
-
layout[..],
|
|
2116
|
-
[
|
|
2117
|
-
Rect::new(0, 0, 1, 1),
|
|
2118
|
-
Rect::new(0, 1, 1, 0),
|
|
2119
|
-
Rect::new(0, 1, 1, 0)
|
|
2120
|
-
]
|
|
2121
|
-
);
|
|
2122
|
-
|
|
2123
|
-
// stretches into last
|
|
2124
|
-
let layout = Layout::default()
|
|
2125
|
-
.constraints([
|
|
2126
|
-
Constraint::Max(1),
|
|
2127
|
-
Constraint::Percentage(99),
|
|
2128
|
-
Constraint::Min(0),
|
|
2129
|
-
])
|
|
2130
|
-
.split(Rect::new(0, 0, 1, 1));
|
|
2131
|
-
assert_eq!(
|
|
2132
|
-
layout[..],
|
|
2133
|
-
[
|
|
2134
|
-
Rect::new(0, 0, 1, 0),
|
|
2135
|
-
Rect::new(0, 0, 1, 1),
|
|
2136
|
-
Rect::new(0, 1, 1, 0)
|
|
2137
|
-
]
|
|
2138
|
-
);
|
|
2139
|
-
|
|
2140
|
-
// minimal bug from
|
|
2141
|
-
// https://github.com/ratatui/ratatui/pull/404#issuecomment-1681850644
|
|
2142
|
-
// TODO: check if this bug is now resolved?
|
|
2143
|
-
let layout = Layout::default()
|
|
2144
|
-
.constraints([Min(1), Length(0), Min(1)])
|
|
2145
|
-
.direction(Direction::Horizontal)
|
|
2146
|
-
.split(Rect::new(0, 0, 1, 1));
|
|
2147
|
-
assert_eq!(
|
|
2148
|
-
layout[..],
|
|
2149
|
-
[
|
|
2150
|
-
Rect::new(0, 0, 1, 1),
|
|
2151
|
-
Rect::new(1, 0, 0, 1),
|
|
2152
|
-
Rect::new(1, 0, 0, 1),
|
|
2153
|
-
]
|
|
2154
|
-
);
|
|
2155
|
-
|
|
2156
|
-
// This stretches the 2nd last length instead of the last min based on ranking
|
|
2157
|
-
let layout = Layout::default()
|
|
2158
|
-
.constraints([Length(3), Min(4), Length(1), Min(4)])
|
|
2159
|
-
.direction(Direction::Horizontal)
|
|
2160
|
-
.split(Rect::new(0, 0, 7, 1));
|
|
2161
|
-
assert_eq!(
|
|
2162
|
-
layout[..],
|
|
2163
|
-
[
|
|
2164
|
-
Rect::new(0, 0, 0, 1),
|
|
2165
|
-
Rect::new(0, 0, 4, 1),
|
|
2166
|
-
Rect::new(4, 0, 0, 1),
|
|
2167
|
-
Rect::new(4, 0, 3, 1),
|
|
2168
|
-
]
|
|
2169
|
-
);
|
|
2170
|
-
}
|
|
2171
|
-
|
|
2172
|
-
#[rstest]
|
|
2173
|
-
#[case::len_min1(vec![Length(25), Min(100)], vec![0..0, 0..100])]
|
|
2174
|
-
#[case::len_min2(vec![Length(25), Min(0)], vec![0..25, 25..100])]
|
|
2175
|
-
#[case::len_max1(vec![Length(25), Max(0)], vec![0..100, 100..100])]
|
|
2176
|
-
#[case::len_max2(vec![Length(25), Max(100)], vec![0..25, 25..100])]
|
|
2177
|
-
#[case::len_perc(vec![Length(25), Percentage(25)], vec![0..25, 25..100])]
|
|
2178
|
-
#[case::perc_len(vec![Percentage(25), Length(25)], vec![0..75, 75..100])]
|
|
2179
|
-
#[case::len_ratio(vec![Length(25), Ratio(1, 4)], vec![0..25, 25..100])]
|
|
2180
|
-
#[case::ratio_len(vec![Ratio(1, 4), Length(25)], vec![0..75, 75..100])]
|
|
2181
|
-
#[case::len_len(vec![Length(25), Length(25)], vec![0..25, 25..100])]
|
|
2182
|
-
#[case::len1(vec![Length(25), Length(25), Length(25)], vec![0..25, 25..50, 50..100])]
|
|
2183
|
-
#[case::len2(vec![Length(15), Length(35), Length(25)], vec![0..15, 15..50, 50..100])]
|
|
2184
|
-
#[case::len3(vec![Length(25), Length(25), Length(25)], vec![0..25, 25..50, 50..100])]
|
|
2185
|
-
fn constraint_length(
|
|
2186
|
-
#[case] constraints: Vec<Constraint>,
|
|
2187
|
-
#[case] expected: Vec<Range<u16>>,
|
|
2188
|
-
) {
|
|
2189
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2190
|
-
let ranges = Layout::horizontal(constraints)
|
|
2191
|
-
.flex(Flex::Legacy)
|
|
2192
|
-
.split(rect)
|
|
2193
|
-
.iter()
|
|
2194
|
-
.map(|r| r.left()..r.right())
|
|
2195
|
-
.collect_vec();
|
|
2196
|
-
assert_eq!(ranges, expected);
|
|
2197
|
-
}
|
|
2198
|
-
|
|
2199
|
-
#[rstest]
|
|
2200
|
-
#[case(7, vec![Length(4), Length(4)], vec![0..3, 4..7])]
|
|
2201
|
-
#[case(4, vec![Length(4), Length(4)], vec![0..2, 3..4])]
|
|
2202
|
-
fn table_length(
|
|
2203
|
-
#[case] width: u16,
|
|
2204
|
-
#[case] constraints: Vec<Constraint>,
|
|
2205
|
-
#[case] expected: Vec<Range<u16>>,
|
|
2206
|
-
) {
|
|
2207
|
-
let rect = Rect::new(0, 0, width, 1);
|
|
2208
|
-
let ranges = Layout::horizontal(constraints)
|
|
2209
|
-
.spacing(1)
|
|
2210
|
-
.flex(Flex::Start)
|
|
2211
|
-
.split(rect)
|
|
2212
|
-
.iter()
|
|
2213
|
-
.map(|r| r.left()..r.right())
|
|
2214
|
-
.collect::<Vec<Range<u16>>>();
|
|
2215
|
-
assert_eq!(ranges, expected);
|
|
2216
|
-
}
|
|
2217
|
-
|
|
2218
|
-
#[rstest]
|
|
2219
|
-
#[case::min_len_max(vec![Min(25), Length(25), Max(25)], vec![0..50, 50..75, 75..100])]
|
|
2220
|
-
#[case::max_len_min(vec![Max(25), Length(25), Min(25)], vec![0..25, 25..50, 50..100])]
|
|
2221
|
-
#[case::len_len_len(vec![Length(33), Length(33), Length(33)], vec![0..33, 33..66, 66..100])]
|
|
2222
|
-
#[case::len_len_len_25(vec![Length(25), Length(25), Length(25)], vec![0..25, 25..50, 50..100])]
|
|
2223
|
-
#[case::perc_len_ratio(vec![Percentage(25), Length(25), Ratio(1, 4)], vec![0..25, 25..50, 50..100])]
|
|
2224
|
-
#[case::len_ratio_perc(vec![Length(25), Ratio(1, 4), Percentage(25)], vec![0..25, 25..75, 75..100])]
|
|
2225
|
-
#[case::ratio_len_perc(vec![Ratio(1, 4), Length(25), Percentage(25)], vec![0..50, 50..75, 75..100])]
|
|
2226
|
-
#[case::ratio_perc_len(vec![Ratio(1, 4), Percentage(25), Length(25)], vec![0..50, 50..75, 75..100])]
|
|
2227
|
-
#[case::len_len_min(vec![Length(100), Length(1), Min(20)], vec![0..80, 80..80, 80..100])]
|
|
2228
|
-
#[case::min_len_len(vec![Min(20), Length(1), Length(100)], vec![0..20, 20..21, 21..100])]
|
|
2229
|
-
#[case::fill_len_fill(vec![Fill(1), Length(10), Fill(1)], vec![0..45, 45..55, 55..100])]
|
|
2230
|
-
#[case::fill_len_fill_2(vec![Fill(1), Length(10), Fill(2)], vec![0..30, 30..40, 40..100])]
|
|
2231
|
-
#[case::fill_len_fill_4(vec![Fill(1), Length(10), Fill(4)], vec![0..18, 18..28, 28..100])]
|
|
2232
|
-
#[case::fill_len_fill_5(vec![Fill(1), Length(10), Fill(5)], vec![0..15, 15..25, 25..100])]
|
|
2233
|
-
#[case::len_len_len_25(vec![Length(25), Length(25), Length(25)], vec![0..25, 25..50, 50..100])]
|
|
2234
|
-
#[case::unstable_test(vec![Length(25), Length(25), Length(25)], vec![0..25, 25..50, 50..100])]
|
|
2235
|
-
fn length_is_higher_priority(
|
|
2236
|
-
#[case] constraints: Vec<Constraint>,
|
|
2237
|
-
#[case] expected: Vec<Range<u16>>,
|
|
2238
|
-
) {
|
|
2239
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2240
|
-
let ranges = Layout::horizontal(constraints)
|
|
2241
|
-
.flex(Flex::Legacy)
|
|
2242
|
-
.split(rect)
|
|
2243
|
-
.iter()
|
|
2244
|
-
.map(|r| r.left()..r.right())
|
|
2245
|
-
.collect_vec();
|
|
2246
|
-
assert_eq!(ranges, expected);
|
|
2247
|
-
}
|
|
2248
|
-
|
|
2249
|
-
#[rstest]
|
|
2250
|
-
#[case::min_len_max(vec![Min(25), Length(25), Max(25)], vec![50, 25, 25])]
|
|
2251
|
-
#[case::max_len_min(vec![Max(25), Length(25), Min(25)], vec![25, 25, 50])]
|
|
2252
|
-
#[case::len_len_len1(vec![Length(33), Length(33), Length(33)], vec![33, 33, 33])]
|
|
2253
|
-
#[case::len_len_len2(vec![Length(25), Length(25), Length(25)], vec![25, 25, 25])]
|
|
2254
|
-
#[case::perc_len_ratio(vec![Percentage(25), Length(25), Ratio(1, 4)], vec![25, 25, 25])]
|
|
2255
|
-
#[case::len_ratio_perc(vec![Length(25), Ratio(1, 4), Percentage(25)], vec![25, 25, 25])]
|
|
2256
|
-
#[case::ratio_len_perc(vec![Ratio(1, 4), Length(25), Percentage(25)], vec![25, 25, 25])]
|
|
2257
|
-
#[case::ratio_perc_len(vec![Ratio(1, 4), Percentage(25), Length(25)], vec![25, 25, 25])]
|
|
2258
|
-
#[case::len_len_min(vec![Length(100), Length(1), Min(20)], vec![79, 1, 20])]
|
|
2259
|
-
#[case::min_len_len(vec![Min(20), Length(1), Length(100)], vec![20, 1, 79])]
|
|
2260
|
-
#[case::fill_len_fill1(vec![Fill(1), Length(10), Fill(1)], vec![45, 10, 45])]
|
|
2261
|
-
#[case::fill_len_fill2(vec![Fill(1), Length(10), Fill(2)], vec![30, 10, 60])]
|
|
2262
|
-
#[case::fill_len_fill4(vec![Fill(1), Length(10), Fill(4)], vec![18, 10, 72])]
|
|
2263
|
-
#[case::fill_len_fill5(vec![Fill(1), Length(10), Fill(5)], vec![15, 10, 75])]
|
|
2264
|
-
#[case::len_len_len3(vec![Length(25), Length(25), Length(25)], vec![25, 25, 25])]
|
|
2265
|
-
fn length_is_higher_priority_in_flex(
|
|
2266
|
-
#[case] constraints: Vec<Constraint>,
|
|
2267
|
-
#[case] expected: Vec<u16>,
|
|
2268
|
-
) {
|
|
2269
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2270
|
-
for flex in [
|
|
2271
|
-
Flex::Start,
|
|
2272
|
-
Flex::End,
|
|
2273
|
-
Flex::Center,
|
|
2274
|
-
Flex::SpaceAround,
|
|
2275
|
-
Flex::SpaceEvenly,
|
|
2276
|
-
Flex::SpaceBetween,
|
|
2277
|
-
] {
|
|
2278
|
-
let widths = Layout::horizontal(&constraints)
|
|
2279
|
-
.flex(flex)
|
|
2280
|
-
.split(rect)
|
|
2281
|
-
.iter()
|
|
2282
|
-
.map(|r| r.width)
|
|
2283
|
-
.collect_vec();
|
|
2284
|
-
assert_eq!(widths, expected);
|
|
2285
|
-
}
|
|
2286
|
-
}
|
|
2287
|
-
|
|
2288
|
-
#[rstest]
|
|
2289
|
-
#[case::fill_len_fill(vec![Fill(1), Length(10), Fill(2)], vec![0..13, 13..23, 23..50])]
|
|
2290
|
-
#[case::len_fill_fill(vec![Length(10), Fill(2), Fill(1)], vec![0..10, 10..37, 37..50])] // might be unstable?
|
|
2291
|
-
fn fixed_with_50_width(
|
|
2292
|
-
#[case] constraints: Vec<Constraint>,
|
|
2293
|
-
#[case] expected: Vec<Range<u16>>,
|
|
2294
|
-
) {
|
|
2295
|
-
let rect = Rect::new(0, 0, 50, 1);
|
|
2296
|
-
let ranges = Layout::horizontal(constraints)
|
|
2297
|
-
.flex(Flex::Legacy)
|
|
2298
|
-
.split(rect)
|
|
2299
|
-
.iter()
|
|
2300
|
-
.map(|r| r.left()..r.right())
|
|
2301
|
-
.collect_vec();
|
|
2302
|
-
assert_eq!(ranges, expected);
|
|
2303
|
-
}
|
|
2304
|
-
|
|
2305
|
-
#[rstest]
|
|
2306
|
-
#[case::same_fill(vec![Fill(1), Fill(2), Fill(1), Fill(1)], vec![0..20, 20..60, 60..80, 80..100])]
|
|
2307
|
-
#[case::inc_fill(vec![Fill(1), Fill(2), Fill(3), Fill(4)], vec![0..10, 10..30, 30..60, 60..100])]
|
|
2308
|
-
#[case::dec_fill(vec![Fill(4), Fill(3), Fill(2), Fill(1)], vec![0..40, 40..70, 70..90, 90..100])]
|
|
2309
|
-
#[case::rand_fill1(vec![Fill(1), Fill(3), Fill(2), Fill(4)], vec![0..10, 10..40, 40..60, 60..100])]
|
|
2310
|
-
#[case::rand_fill2(vec![Fill(1), Fill(3), Length(50), Fill(2), Fill(4)], vec![0..5, 5..20, 20..70, 70..80, 80..100])]
|
|
2311
|
-
#[case::rand_fill3(vec![Fill(1), Fill(3), Percentage(50), Fill(2), Fill(4)], vec![0..5, 5..20, 20..70, 70..80, 80..100])]
|
|
2312
|
-
#[case::rand_fill4(vec![Fill(1), Fill(3), Min(50), Fill(2), Fill(4)], vec![0..5, 5..20, 20..70, 70..80, 80..100])]
|
|
2313
|
-
#[case::rand_fill5(vec![Fill(1), Fill(3), Max(50), Fill(2), Fill(4)], vec![0..5, 5..20, 20..70, 70..80, 80..100])]
|
|
2314
|
-
#[case::zero_fill1(vec![Fill(0), Fill(1), Fill(0)], vec![0..0, 0..100, 100..100])]
|
|
2315
|
-
#[case::zero_fill2(vec![Fill(0), Length(1), Fill(0)], vec![0..50, 50..51, 51..100])]
|
|
2316
|
-
#[case::zero_fill3(vec![Fill(0), Percentage(1), Fill(0)], vec![0..50, 50..51, 51..100])]
|
|
2317
|
-
#[case::zero_fill4(vec![Fill(0), Min(1), Fill(0)], vec![0..50, 50..51, 51..100])]
|
|
2318
|
-
#[case::zero_fill5(vec![Fill(0), Max(1), Fill(0)], vec![0..50, 50..51, 51..100])]
|
|
2319
|
-
#[case::zero_fill6(vec![Fill(0), Fill(2), Fill(0), Fill(1)], vec![0..0, 0..67, 67..67, 67..100])]
|
|
2320
|
-
#[case::space_fill1(vec![Fill(0), Fill(2), Percentage(20)], vec![0..0, 0..80, 80..100])]
|
|
2321
|
-
#[case::space_fill2(vec![Fill(0), Fill(0), Percentage(20)], vec![0..40, 40..80, 80..100])]
|
|
2322
|
-
#[case::space_fill3(vec![Fill(0), Ratio(1, 5)], vec![0..80, 80..100])]
|
|
2323
|
-
#[case::space_fill4(vec![Fill(0), Fill(u16::MAX)], vec![0..0, 0..100])]
|
|
2324
|
-
#[case::space_fill5(vec![Fill(u16::MAX), Fill(0)], vec![0..100, 100..100])]
|
|
2325
|
-
#[case::space_fill6(vec![Fill(0), Percentage(20)], vec![0..80, 80..100])]
|
|
2326
|
-
#[case::space_fill7(vec![Fill(1), Percentage(20)], vec![0..80, 80..100])]
|
|
2327
|
-
#[case::space_fill8(vec![Fill(u16::MAX), Percentage(20)], vec![0..80, 80..100])]
|
|
2328
|
-
#[case::space_fill9(vec![Fill(u16::MAX), Fill(0), Percentage(20)], vec![0..80, 80..80, 80..100])]
|
|
2329
|
-
#[case::space_fill10(vec![Fill(0), Length(20)], vec![0..80, 80..100])]
|
|
2330
|
-
#[case::space_fill11(vec![Fill(0), Min(20)], vec![0..80, 80..100])]
|
|
2331
|
-
#[case::space_fill12(vec![Fill(0), Max(20)], vec![0..80, 80..100])]
|
|
2332
|
-
#[case::fill_collapse1(vec![Fill(1), Fill(1), Fill(1), Min(30), Length(50)], vec![0..7, 7..13, 13..20, 20..50, 50..100])]
|
|
2333
|
-
#[case::fill_collapse2(vec![Fill(1), Fill(1), Fill(1), Length(50), Length(50)], vec![0..0, 0..0, 0..0, 0..50, 50..100])]
|
|
2334
|
-
#[case::fill_collapse3(vec![Fill(1), Fill(1), Fill(1), Length(75), Length(50)], vec![0..0, 0..0, 0..0, 0..75, 75..100])]
|
|
2335
|
-
#[case::fill_collapse4(vec![Fill(1), Fill(1), Fill(1), Min(50), Max(50)], vec![0..0, 0..0, 0..0, 0..50, 50..100])]
|
|
2336
|
-
#[case::fill_collapse5(vec![Fill(1), Fill(1), Fill(1), Ratio(1, 1)], vec![0..0, 0..0, 0..0, 0..100])]
|
|
2337
|
-
#[case::fill_collapse6(vec![Fill(1), Fill(1), Fill(1), Percentage(100)], vec![0..0, 0..0, 0..0, 0..100])]
|
|
2338
|
-
fn fill(#[case] constraints: Vec<Constraint>, #[case] expected: Vec<Range<u16>>) {
|
|
2339
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2340
|
-
let ranges = Layout::horizontal(constraints)
|
|
2341
|
-
.flex(Flex::Legacy)
|
|
2342
|
-
.split(rect)
|
|
2343
|
-
.iter()
|
|
2344
|
-
.map(|r| r.left()..r.right())
|
|
2345
|
-
.collect_vec();
|
|
2346
|
-
assert_eq!(ranges, expected);
|
|
2347
|
-
}
|
|
2348
|
-
|
|
2349
|
-
#[rstest]
|
|
2350
|
-
#[case::min_percentage(vec![Min(0), Percentage(20)], vec![0..80, 80..100])]
|
|
2351
|
-
#[case::max_percentage(vec![Max(0), Percentage(20)], vec![0..0, 0..100])]
|
|
2352
|
-
fn percentage_parameterized(
|
|
2353
|
-
#[case] constraints: Vec<Constraint>,
|
|
2354
|
-
#[case] expected: Vec<Range<u16>>,
|
|
2355
|
-
) {
|
|
2356
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2357
|
-
let ranges = Layout::horizontal(constraints)
|
|
2358
|
-
.flex(Flex::Legacy)
|
|
2359
|
-
.split(rect)
|
|
2360
|
-
.iter()
|
|
2361
|
-
.map(|r| r.left()..r.right())
|
|
2362
|
-
.collect_vec();
|
|
2363
|
-
assert_eq!(ranges, expected);
|
|
2364
|
-
}
|
|
2365
|
-
|
|
2366
|
-
#[rstest]
|
|
2367
|
-
#[case::max_min(vec![Max(100), Min(0)], vec![0..100, 100..100])]
|
|
2368
|
-
#[case::min_max(vec![Min(0), Max(100)], vec![0..0, 0..100])]
|
|
2369
|
-
#[case::length_min(vec![Length(u16::MAX), Min(10)], vec![0..90, 90..100])]
|
|
2370
|
-
#[case::min_length(vec![Min(10), Length(u16::MAX)], vec![0..10, 10..100])]
|
|
2371
|
-
#[case::length_max(vec![Length(0), Max(10)], vec![0..90, 90..100])]
|
|
2372
|
-
#[case::max_length(vec![Max(10), Length(0)], vec![0..10, 10..100])]
|
|
2373
|
-
fn min_max(#[case] constraints: Vec<Constraint>, #[case] expected: Vec<Range<u16>>) {
|
|
2374
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2375
|
-
let ranges = Layout::horizontal(constraints)
|
|
2376
|
-
.flex(Flex::Legacy)
|
|
2377
|
-
.split(rect)
|
|
2378
|
-
.iter()
|
|
2379
|
-
.map(|r| r.left()..r.right())
|
|
2380
|
-
.collect_vec();
|
|
2381
|
-
assert_eq!(ranges, expected);
|
|
2382
|
-
}
|
|
2383
|
-
|
|
2384
|
-
#[rstest]
|
|
2385
|
-
#[case::length_legacy(vec![Length(50)], vec![0..100], Flex::Legacy)]
|
|
2386
|
-
#[case::length_start(vec![Length(50)], vec![0..50], Flex::Start)]
|
|
2387
|
-
#[case::length_end(vec![Length(50)], vec![50..100], Flex::End)]
|
|
2388
|
-
#[case::length_center(vec![Length(50)], vec![25..75], Flex::Center)]
|
|
2389
|
-
#[case::ratio_legacy(vec![Ratio(1, 2)], vec![0..100], Flex::Legacy)]
|
|
2390
|
-
#[case::ratio_start(vec![Ratio(1, 2)], vec![0..50], Flex::Start)]
|
|
2391
|
-
#[case::ratio_end(vec![Ratio(1, 2)], vec![50..100], Flex::End)]
|
|
2392
|
-
#[case::ratio_center(vec![Ratio(1, 2)], vec![25..75], Flex::Center)]
|
|
2393
|
-
#[case::percent_legacy(vec![Percentage(50)], vec![0..100], Flex::Legacy)]
|
|
2394
|
-
#[case::percent_start(vec![Percentage(50)], vec![0..50], Flex::Start)]
|
|
2395
|
-
#[case::percent_end(vec![Percentage(50)], vec![50..100], Flex::End)]
|
|
2396
|
-
#[case::percent_center(vec![Percentage(50)], vec![25..75], Flex::Center)]
|
|
2397
|
-
#[case::min_legacy(vec![Min(50)], vec![0..100], Flex::Legacy)]
|
|
2398
|
-
#[case::min_start(vec![Min(50)], vec![0..100], Flex::Start)]
|
|
2399
|
-
#[case::min_end(vec![Min(50)], vec![0..100], Flex::End)]
|
|
2400
|
-
#[case::min_center(vec![Min(50)], vec![0..100], Flex::Center)]
|
|
2401
|
-
#[case::max_legacy(vec![Max(50)], vec![0..100], Flex::Legacy)]
|
|
2402
|
-
#[case::max_start(vec![Max(50)], vec![0..50], Flex::Start)]
|
|
2403
|
-
#[case::max_end(vec![Max(50)], vec![50..100], Flex::End)]
|
|
2404
|
-
#[case::max_center(vec![Max(50)], vec![25..75], Flex::Center)]
|
|
2405
|
-
#[case::spacebetween_becomes_stretch1(vec![Min(1)], vec![0..100], Flex::SpaceBetween)]
|
|
2406
|
-
#[case::spacebetween_becomes_stretch2(vec![Max(20)], vec![0..100], Flex::SpaceBetween)]
|
|
2407
|
-
#[case::spacebetween_becomes_stretch3(vec![Length(20)], vec![0..100], Flex::SpaceBetween)]
|
|
2408
|
-
#[case::length_legacy2(vec![Length(25), Length(25)], vec![0..25, 25..100], Flex::Legacy)]
|
|
2409
|
-
#[case::length_start2(vec![Length(25), Length(25)], vec![0..25, 25..50], Flex::Start)]
|
|
2410
|
-
#[case::length_center2(vec![Length(25), Length(25)], vec![25..50, 50..75], Flex::Center)]
|
|
2411
|
-
#[case::length_end2(vec![Length(25), Length(25)], vec![50..75, 75..100], Flex::End)]
|
|
2412
|
-
#[case::length_spacebetween(vec![Length(25), Length(25)], vec![0..25, 75..100], Flex::SpaceBetween)]
|
|
2413
|
-
#[case::length_spaceevenly(vec![Length(25), Length(25)], vec![17..42, 58..83], Flex::SpaceEvenly)]
|
|
2414
|
-
#[case::length_spacearound(vec![Length(25), Length(25)], vec![13..38, 63..88], Flex::SpaceAround)]
|
|
2415
|
-
#[case::percentage_legacy(vec![Percentage(25), Percentage(25)], vec![0..25, 25..100], Flex::Legacy)]
|
|
2416
|
-
#[case::percentage_start(vec![Percentage(25), Percentage(25)], vec![0..25, 25..50], Flex::Start)]
|
|
2417
|
-
#[case::percentage_center(vec![Percentage(25), Percentage(25)], vec![25..50, 50..75], Flex::Center)]
|
|
2418
|
-
#[case::percentage_end(vec![Percentage(25), Percentage(25)], vec![50..75, 75..100], Flex::End)]
|
|
2419
|
-
#[case::percentage_spacebetween(vec![Percentage(25), Percentage(25)], vec![0..25, 75..100], Flex::SpaceBetween)]
|
|
2420
|
-
#[case::percentage_spaceevenly(vec![Percentage(25), Percentage(25)], vec![17..42, 58..83], Flex::SpaceEvenly)]
|
|
2421
|
-
#[case::percentage_spacearound(vec![Percentage(25), Percentage(25)], vec![13..38, 63..88], Flex::SpaceAround)]
|
|
2422
|
-
#[case::min_legacy2(vec![Min(25), Min(25)], vec![0..25, 25..100], Flex::Legacy)]
|
|
2423
|
-
#[case::min_start2(vec![Min(25), Min(25)], vec![0..50, 50..100], Flex::Start)]
|
|
2424
|
-
#[case::min_center2(vec![Min(25), Min(25)], vec![0..50, 50..100], Flex::Center)]
|
|
2425
|
-
#[case::min_end2(vec![Min(25), Min(25)], vec![0..50, 50..100], Flex::End)]
|
|
2426
|
-
#[case::min_spacebetween(vec![Min(25), Min(25)], vec![0..50, 50..100], Flex::SpaceBetween)]
|
|
2427
|
-
#[case::min_spaceevenly(vec![Min(25), Min(25)], vec![0..50, 50..100], Flex::SpaceEvenly)]
|
|
2428
|
-
#[case::min_spacearound(vec![Min(25), Min(25)], vec![0..50, 50..100], Flex::SpaceAround)]
|
|
2429
|
-
#[case::max_legacy2(vec![Max(25), Max(25)], vec![0..25, 25..100], Flex::Legacy)]
|
|
2430
|
-
#[case::max_start2(vec![Max(25), Max(25)], vec![0..25, 25..50], Flex::Start)]
|
|
2431
|
-
#[case::max_center2(vec![Max(25), Max(25)], vec![25..50, 50..75], Flex::Center)]
|
|
2432
|
-
#[case::max_end2(vec![Max(25), Max(25)], vec![50..75, 75..100], Flex::End)]
|
|
2433
|
-
#[case::max_spacebetween(vec![Max(25), Max(25)], vec![0..25, 75..100], Flex::SpaceBetween)]
|
|
2434
|
-
#[case::max_spaceevenly(vec![Max(25), Max(25)], vec![17..42, 58..83], Flex::SpaceEvenly)]
|
|
2435
|
-
#[case::max_spacearound(vec![Max(25), Max(25)], vec![13..38, 63..88], Flex::SpaceAround)]
|
|
2436
|
-
#[case::length_spaced_around(vec![Length(25), Length(25), Length(25)], vec![0..25, 38..63, 75..100], Flex::SpaceBetween)]
|
|
2437
|
-
#[case::one_segment_legacy(vec![Length(50)], vec![0..100], Flex::Legacy)]
|
|
2438
|
-
#[case::one_segment_start(vec![Length(50)], vec![0..50], Flex::Start)]
|
|
2439
|
-
#[case::one_segment_end(vec![Length(50)], vec![50..100], Flex::End)]
|
|
2440
|
-
#[case::one_segment_center(vec![Length(50)], vec![25..75], Flex::Center)]
|
|
2441
|
-
#[case::one_segment_spacebetween(vec![Length(50)], vec![0..100], Flex::SpaceBetween)]
|
|
2442
|
-
#[case::one_segment_spaceevenly(vec![Length(50)], vec![25..75], Flex::SpaceEvenly)]
|
|
2443
|
-
#[case::one_segment_spacearound(vec![Length(50)], vec![25..75], Flex::SpaceAround)]
|
|
2444
|
-
fn flex_constraint(
|
|
2445
|
-
#[case] constraints: Vec<Constraint>,
|
|
2446
|
-
#[case] expected: Vec<Range<u16>>,
|
|
2447
|
-
#[case] flex: Flex,
|
|
2448
|
-
) {
|
|
2449
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2450
|
-
let ranges = Layout::horizontal(constraints)
|
|
2451
|
-
.flex(flex)
|
|
2452
|
-
.split(rect)
|
|
2453
|
-
.iter()
|
|
2454
|
-
.map(|r| r.left()..r.right())
|
|
2455
|
-
.collect_vec();
|
|
2456
|
-
assert_eq!(ranges, expected);
|
|
2457
|
-
}
|
|
2458
|
-
|
|
2459
|
-
#[rstest]
|
|
2460
|
-
#[case::length_overlap1(vec![(0 , 20) , (20 , 20) , (40 , 20)] , vec![Length(20) , Length(20) , Length(20)] , Flex::Start , 0)]
|
|
2461
|
-
#[case::length_overlap2(vec![(0 , 20) , (19 , 20) , (38 , 20)] , vec![Length(20) , Length(20) , Length(20)] , Flex::Start , -1)]
|
|
2462
|
-
#[case::length_overlap3(vec![(21 , 20) , (40 , 20) , (59 , 20)] , vec![Length(20) , Length(20) , Length(20)] , Flex::Center , -1)]
|
|
2463
|
-
#[case::length_overlap4(vec![(42 , 20) , (61 , 20) , (80 , 20)] , vec![Length(20) , Length(20) , Length(20)] , Flex::End , -1)]
|
|
2464
|
-
#[case::length_overlap5(vec![(0 , 20) , (19 , 20) , (38 , 62)] , vec![Length(20) , Length(20) , Length(20)] , Flex::Legacy , -1)]
|
|
2465
|
-
#[case::length_overlap6(vec![(0 , 20) , (40 , 20) , (80 , 20)] , vec![Length(20) , Length(20) , Length(20)] , Flex::SpaceBetween , -1)]
|
|
2466
|
-
#[case::length_overlap7(vec![(10 , 20) , (40 , 20) , (70 , 20)] , vec![Length(20) , Length(20) , Length(20)] , Flex::SpaceEvenly , -1)]
|
|
2467
|
-
#[case::length_overlap7(vec![(7 , 20) , (40 , 20) , (73 , 20)] , vec![Length(20) , Length(20) , Length(20)] , Flex::SpaceAround , -1)]
|
|
2468
|
-
fn flex_overlap(
|
|
2469
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2470
|
-
#[case] constraints: Vec<Constraint>,
|
|
2471
|
-
#[case] flex: Flex,
|
|
2472
|
-
#[case] spacing: i16,
|
|
2473
|
-
) {
|
|
2474
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2475
|
-
let r = Layout::horizontal(constraints)
|
|
2476
|
-
.flex(flex)
|
|
2477
|
-
.spacing(spacing)
|
|
2478
|
-
.split(rect);
|
|
2479
|
-
let result = r
|
|
2480
|
-
.iter()
|
|
2481
|
-
.map(|r| (r.x, r.width))
|
|
2482
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2483
|
-
|
|
2484
|
-
assert_eq!(result, expected);
|
|
2485
|
-
}
|
|
2486
|
-
|
|
2487
|
-
#[rstest]
|
|
2488
|
-
#[case::length_spacing(vec![(0 , 20), (20, 20) , (40, 20)], vec![Length(20), Length(20), Length(20)], Flex::Start , 0)]
|
|
2489
|
-
#[case::length_spacing(vec![(0 , 20), (22, 20) , (44, 20)], vec![Length(20), Length(20), Length(20)], Flex::Start , 2)]
|
|
2490
|
-
#[case::length_spacing(vec![(18, 20), (40, 20) , (62, 20)], vec![Length(20), Length(20), Length(20)], Flex::Center , 2)]
|
|
2491
|
-
#[case::length_spacing(vec![(36, 20), (58, 20) , (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::End , 2)]
|
|
2492
|
-
#[case::length_spacing(vec![(0 , 20), (22, 20) , (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::Legacy , 2)]
|
|
2493
|
-
#[case::length_spacing(vec![(0 , 20), (40, 20) , (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceBetween, 2)]
|
|
2494
|
-
#[case::length_spacing(vec![(10, 20), (40, 20) , (70, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceEvenly, 2)]
|
|
2495
|
-
#[case::length_spacing(vec![(7, 20), (40, 20) , (73, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceAround, 2)]
|
|
2496
|
-
fn flex_spacing(
|
|
2497
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2498
|
-
#[case] constraints: Vec<Constraint>,
|
|
2499
|
-
#[case] flex: Flex,
|
|
2500
|
-
#[case] spacing: i16,
|
|
2501
|
-
) {
|
|
2502
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2503
|
-
let r = Layout::horizontal(constraints)
|
|
2504
|
-
.flex(flex)
|
|
2505
|
-
.spacing(spacing)
|
|
2506
|
-
.split(rect);
|
|
2507
|
-
let result = r
|
|
2508
|
-
.iter()
|
|
2509
|
-
.map(|r| (r.x, r.width))
|
|
2510
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2511
|
-
assert_eq!(result, expected);
|
|
2512
|
-
}
|
|
2513
|
-
|
|
2514
|
-
#[rstest]
|
|
2515
|
-
#[case::a(vec![(0, 25), (25, 75)], vec![Length(25), Length(25)])]
|
|
2516
|
-
#[case::b(vec![(0, 25), (25, 75)], vec![Length(25), Percentage(25)])]
|
|
2517
|
-
#[case::c(vec![(0, 75), (75, 25)], vec![Percentage(25), Length(25)])]
|
|
2518
|
-
#[case::d(vec![(0, 75), (75, 25)], vec![Min(25), Percentage(25)])]
|
|
2519
|
-
#[case::e(vec![(0, 25), (25, 75)], vec![Percentage(25), Min(25)])]
|
|
2520
|
-
#[case::f(vec![(0, 25), (25, 75)], vec![Min(25), Percentage(100)])]
|
|
2521
|
-
#[case::g(vec![(0, 75), (75, 25)], vec![Percentage(100), Min(25)])]
|
|
2522
|
-
#[case::h(vec![(0, 25), (25, 75)], vec![Max(75), Percentage(75)])]
|
|
2523
|
-
#[case::i(vec![(0, 75), (75, 25)], vec![Percentage(75), Max(75)])]
|
|
2524
|
-
#[case::j(vec![(0, 25), (25, 75)], vec![Max(25), Percentage(25)])]
|
|
2525
|
-
#[case::k(vec![(0, 75), (75, 25)], vec![Percentage(25), Max(25)])]
|
|
2526
|
-
#[case::l(vec![(0, 25), (25, 75)], vec![Length(25), Ratio(1, 4)])]
|
|
2527
|
-
#[case::m(vec![(0, 75), (75, 25)], vec![Ratio(1, 4), Length(25)])]
|
|
2528
|
-
#[case::n(vec![(0, 25), (25, 75)], vec![Percentage(25), Ratio(1, 4)])]
|
|
2529
|
-
#[case::o(vec![(0, 75), (75, 25)], vec![Ratio(1, 4), Percentage(25)])]
|
|
2530
|
-
#[case::p(vec![(0, 25), (25, 75)], vec![Ratio(1, 4), Fill(25)])]
|
|
2531
|
-
#[case::q(vec![(0, 75), (75, 25)], vec![Fill(25), Ratio(1, 4)])]
|
|
2532
|
-
fn constraint_specification_tests_for_priority(
|
|
2533
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2534
|
-
#[case] constraints: Vec<Constraint>,
|
|
2535
|
-
) {
|
|
2536
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2537
|
-
let r = Layout::horizontal(constraints)
|
|
2538
|
-
.flex(Flex::Legacy)
|
|
2539
|
-
.split(rect)
|
|
2540
|
-
.iter()
|
|
2541
|
-
.map(|r| (r.x, r.width))
|
|
2542
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2543
|
-
assert_eq!(r, expected);
|
|
2544
|
-
}
|
|
2545
|
-
|
|
2546
|
-
#[rstest]
|
|
2547
|
-
#[case::a(vec![(0, 20), (20, 20), (40, 20)], vec![Length(20), Length(20), Length(20)], Flex::Start, 0)]
|
|
2548
|
-
#[case::b(vec![(18, 20), (40, 20), (62, 20)], vec![Length(20), Length(20), Length(20)], Flex::Center, 2)]
|
|
2549
|
-
#[case::c(vec![(36, 20), (58, 20), (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::End, 2)]
|
|
2550
|
-
#[case::d(vec![(0, 20), (22, 20), (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::Legacy, 2)]
|
|
2551
|
-
#[case::e(vec![(0, 20), (22, 20), (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::Legacy, 2)]
|
|
2552
|
-
#[case::f(vec![(10, 20), (40, 20), (70, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceEvenly, 2)]
|
|
2553
|
-
#[case::f(vec![(7, 20), (40, 20), (73, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceAround, 2)]
|
|
2554
|
-
fn constraint_specification_tests_for_priority_with_spacing(
|
|
2555
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2556
|
-
#[case] constraints: Vec<Constraint>,
|
|
2557
|
-
#[case] flex: Flex,
|
|
2558
|
-
#[case] spacing: i16,
|
|
2559
|
-
) {
|
|
2560
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2561
|
-
let r = Layout::horizontal(constraints)
|
|
2562
|
-
.spacing(spacing)
|
|
2563
|
-
.flex(flex)
|
|
2564
|
-
.split(rect)
|
|
2565
|
-
.iter()
|
|
2566
|
-
.map(|r| (r.x, r.width))
|
|
2567
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2568
|
-
assert_eq!(r, expected);
|
|
2569
|
-
}
|
|
2570
|
-
|
|
2571
|
-
#[rstest]
|
|
2572
|
-
#[case::prop(vec![(0 , 10), (10, 80), (90 , 10)] , vec![Length(10), Fill(1), Length(10)], Flex::Legacy)]
|
|
2573
|
-
#[case::flex(vec![(0 , 10), (90 , 10)] , vec![Length(10), Length(10)], Flex::SpaceBetween)]
|
|
2574
|
-
#[case::prop(vec![(0 , 27), (27, 10), (37, 26), (63, 10), (73, 27)] , vec![Fill(1), Length(10), Fill(1), Length(10), Fill(1)], Flex::Legacy)]
|
|
2575
|
-
#[case::flex(vec![(27 , 10), (63, 10)] , vec![Length(10), Length(10)], Flex::SpaceEvenly)]
|
|
2576
|
-
#[case::prop(vec![(0 , 10), (10, 10), (20 , 80)] , vec![Length(10), Length(10), Fill(1)], Flex::Legacy)]
|
|
2577
|
-
#[case::flex(vec![(0 , 10), (10, 10)] , vec![Length(10), Length(10)], Flex::Start)]
|
|
2578
|
-
#[case::prop(vec![(0 , 80), (80 , 10), (90, 10)] , vec![Fill(1), Length(10), Length(10)], Flex::Legacy)]
|
|
2579
|
-
#[case::flex(vec![(80 , 10), (90, 10)] , vec![Length(10), Length(10)], Flex::End)]
|
|
2580
|
-
#[case::prop(vec![(0 , 40), (40, 10), (50, 10), (60, 40)] , vec![Fill(1), Length(10), Length(10), Fill(1)], Flex::Legacy)]
|
|
2581
|
-
#[case::flex(vec![(40 , 10), (50, 10)] , vec![Length(10), Length(10)], Flex::Center)]
|
|
2582
|
-
#[case::flex(vec![(20 , 10), (70, 10)] , vec![Length(10), Length(10)], Flex::SpaceAround)]
|
|
2583
|
-
fn fill_vs_flex(
|
|
2584
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2585
|
-
#[case] constraints: Vec<Constraint>,
|
|
2586
|
-
#[case] flex: Flex,
|
|
2587
|
-
) {
|
|
2588
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2589
|
-
let r = Layout::horizontal(constraints).flex(flex).split(rect);
|
|
2590
|
-
let result = r
|
|
2591
|
-
.iter()
|
|
2592
|
-
.map(|r| (r.x, r.width))
|
|
2593
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2594
|
-
assert_eq!(result, expected);
|
|
2595
|
-
}
|
|
2596
|
-
|
|
2597
|
-
#[rstest]
|
|
2598
|
-
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Legacy , 0)]
|
|
2599
|
-
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceEvenly , 0)]
|
|
2600
|
-
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , 0)]
|
|
2601
|
-
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , 0)]
|
|
2602
|
-
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Start , 0)]
|
|
2603
|
-
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Center , 0)]
|
|
2604
|
-
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::End , 0)]
|
|
2605
|
-
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Legacy , 10)]
|
|
2606
|
-
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Start , 10)]
|
|
2607
|
-
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Center , 10)]
|
|
2608
|
-
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::End , 10)]
|
|
2609
|
-
#[case::flex10(vec![(10 , 35), (55 , 35)] , vec![Fill(1), Fill(1)], Flex::SpaceEvenly , 10)]
|
|
2610
|
-
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , 10)]
|
|
2611
|
-
#[case::flex10(vec![(10 , 30), (60 , 30)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , 10)]
|
|
2612
|
-
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::Legacy , 0)]
|
|
2613
|
-
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceEvenly , 0)]
|
|
2614
|
-
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceBetween , 0)]
|
|
2615
|
-
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceAround , 0)]
|
|
2616
|
-
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::Start , 0)]
|
|
2617
|
-
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::Center , 0)]
|
|
2618
|
-
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::End , 0)]
|
|
2619
|
-
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::Legacy , 10)]
|
|
2620
|
-
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::Start , 10)]
|
|
2621
|
-
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::Center , 10)]
|
|
2622
|
-
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::End , 10)]
|
|
2623
|
-
#[case::flex_length10(vec![(10 , 25), (45, 10), (65 , 25)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceEvenly , 10)]
|
|
2624
|
-
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceBetween , 10)]
|
|
2625
|
-
#[case::flex_length10(vec![(10 , 15), (45, 10), (75 , 15)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceAround , 10)]
|
|
2626
|
-
fn fill_spacing(
|
|
2627
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2628
|
-
#[case] constraints: Vec<Constraint>,
|
|
2629
|
-
#[case] flex: Flex,
|
|
2630
|
-
#[case] spacing: i16,
|
|
2631
|
-
) {
|
|
2632
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2633
|
-
let r = Layout::horizontal(constraints)
|
|
2634
|
-
.flex(flex)
|
|
2635
|
-
.spacing(spacing)
|
|
2636
|
-
.split(rect);
|
|
2637
|
-
let result = r
|
|
2638
|
-
.iter()
|
|
2639
|
-
.map(|r| (r.x, r.width))
|
|
2640
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2641
|
-
assert_eq!(expected, result);
|
|
2642
|
-
}
|
|
2643
|
-
|
|
2644
|
-
#[rstest]
|
|
2645
|
-
#[case::flex0_1(vec![(0 , 55), (45 , 55)] , vec![Fill(1), Fill(1)], Flex::Legacy , -10)]
|
|
2646
|
-
#[case::flex0_2(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , -10)]
|
|
2647
|
-
#[case::flex0_3(vec![(0 , 55), (45 , 55)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , -10)]
|
|
2648
|
-
#[case::flex0_4(vec![(0 , 55), (45 , 55)] , vec![Fill(1), Fill(1)], Flex::Start , -10)]
|
|
2649
|
-
#[case::flex0_5(vec![(0 , 55), (45 , 55)] , vec![Fill(1), Fill(1)], Flex::Center , -10)]
|
|
2650
|
-
#[case::flex0_6(vec![(0 , 55), (45 , 55)] , vec![Fill(1), Fill(1)], Flex::End , -10)]
|
|
2651
|
-
#[case::flex0_7(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceEvenly , -10)]
|
|
2652
|
-
#[case::flex10_1(vec![(0 , 51), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Legacy , -1)]
|
|
2653
|
-
#[case::flex10_2(vec![(0 , 51), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Start , -1)]
|
|
2654
|
-
#[case::flex10_3(vec![(0 , 51), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Center , -1)]
|
|
2655
|
-
#[case::flex10_4(vec![(0 , 51), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::End , -1)]
|
|
2656
|
-
#[case::flex10_5(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , -1)]
|
|
2657
|
-
#[case::flex10_6(vec![(0 , 51), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , -1)]
|
|
2658
|
-
#[case::flex10_7(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceEvenly , -1)]
|
|
2659
|
-
#[case::flex_length0_1(vec![(0 , 55), (45, 10), (45 , 55)] , vec![Fill(1), Length(10), Fill(1)], Flex::Legacy , -10)]
|
|
2660
|
-
#[case::flex_length0_2(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceAround , -10)]
|
|
2661
|
-
#[case::flex_length0_3(vec![(0 , 55), (45, 10), (45 , 55)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceBetween , -10)]
|
|
2662
|
-
#[case::flex_length0_4(vec![(0 , 55), (45, 10), (45 , 55)] , vec![Fill(1), Length(10), Fill(1)], Flex::Start , -10)]
|
|
2663
|
-
#[case::flex_length0_5(vec![(0 , 55), (45, 10), (45 , 55)] , vec![Fill(1), Length(10), Fill(1)], Flex::Center , -10)]
|
|
2664
|
-
#[case::flex_length0_6(vec![(0 , 55), (45, 10), (45 , 55)] , vec![Fill(1), Length(10), Fill(1)], Flex::End , -10)]
|
|
2665
|
-
#[case::flex_length0_7(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceEvenly , -10)]
|
|
2666
|
-
#[case::flex_length10_1(vec![(0 , 46), (45, 10), (54 , 46)] , vec![Fill(1), Length(10), Fill(1)], Flex::Legacy , -1)]
|
|
2667
|
-
#[case::flex_length10_2(vec![(0 , 46), (45, 10), (54 , 46)] , vec![Fill(1), Length(10), Fill(1)], Flex::Start , -1)]
|
|
2668
|
-
#[case::flex_length10_3(vec![(0 , 46), (45, 10), (54 , 46)] , vec![Fill(1), Length(10), Fill(1)], Flex::Center , -1)]
|
|
2669
|
-
#[case::flex_length10_4(vec![(0 , 46), (45, 10), (54 , 46)] , vec![Fill(1), Length(10), Fill(1)], Flex::End , -1)]
|
|
2670
|
-
#[case::flex_length10_5(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceAround , -1)]
|
|
2671
|
-
#[case::flex_length10_6(vec![(0 , 46), (45, 10), (54 , 46)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceBetween , -1)]
|
|
2672
|
-
#[case::flex_length10_7(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceEvenly , -1)]
|
|
2673
|
-
fn fill_overlap(
|
|
2674
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2675
|
-
#[case] constraints: Vec<Constraint>,
|
|
2676
|
-
#[case] flex: Flex,
|
|
2677
|
-
#[case] spacing: i16,
|
|
2678
|
-
) {
|
|
2679
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2680
|
-
let r = Layout::horizontal(constraints)
|
|
2681
|
-
.flex(flex)
|
|
2682
|
-
.spacing(spacing)
|
|
2683
|
-
.split(rect);
|
|
2684
|
-
let result = r
|
|
2685
|
-
.iter()
|
|
2686
|
-
.map(|r| (r.x, r.width))
|
|
2687
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2688
|
-
assert_eq!(result, expected);
|
|
2689
|
-
}
|
|
2690
|
-
|
|
2691
|
-
#[rstest]
|
|
2692
|
-
#[case::flex_length10(vec![(0, 10), (90, 10)], vec![Length(10), Length(10)], Flex::Center, 80)]
|
|
2693
|
-
fn flex_spacing_lower_priority_than_user_spacing(
|
|
2694
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2695
|
-
#[case] constraints: Vec<Constraint>,
|
|
2696
|
-
#[case] flex: Flex,
|
|
2697
|
-
#[case] spacing: i16,
|
|
2698
|
-
) {
|
|
2699
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2700
|
-
let r = Layout::horizontal(constraints)
|
|
2701
|
-
.flex(flex)
|
|
2702
|
-
.spacing(spacing)
|
|
2703
|
-
.split(rect);
|
|
2704
|
-
let result = r
|
|
2705
|
-
.iter()
|
|
2706
|
-
.map(|r| (r.x, r.width))
|
|
2707
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2708
|
-
assert_eq!(result, expected);
|
|
2709
|
-
}
|
|
2710
|
-
|
|
2711
|
-
#[rstest]
|
|
2712
|
-
#[case::spacers(vec![(0, 0), (10, 0), (100, 0)], vec![Length(10), Length(10)], Flex::Legacy)]
|
|
2713
|
-
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween)]
|
|
2714
|
-
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceEvenly)]
|
|
2715
|
-
#[case::spacers(vec![(0, 20), (30, 40), (80, 20)], vec![Length(10), Length(10)], Flex::SpaceAround)]
|
|
2716
|
-
#[case::spacers(vec![(0, 0), (10, 0), (20, 80)], vec![Length(10), Length(10)], Flex::Start)]
|
|
2717
|
-
#[case::spacers(vec![(0, 40), (50, 0), (60, 40)], vec![Length(10), Length(10)], Flex::Center)]
|
|
2718
|
-
#[case::spacers(vec![(0, 80), (90, 0), (100, 0)], vec![Length(10), Length(10)], Flex::End)]
|
|
2719
|
-
fn split_with_spacers_no_spacing(
|
|
2720
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2721
|
-
#[case] constraints: Vec<Constraint>,
|
|
2722
|
-
#[case] flex: Flex,
|
|
2723
|
-
) {
|
|
2724
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2725
|
-
let (_, s) = Layout::horizontal(&constraints)
|
|
2726
|
-
.flex(flex)
|
|
2727
|
-
.split_with_spacers(rect);
|
|
2728
|
-
assert_eq!(s.len(), constraints.len() + 1);
|
|
2729
|
-
let result = s
|
|
2730
|
-
.iter()
|
|
2731
|
-
.map(|r| (r.x, r.width))
|
|
2732
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2733
|
-
assert_eq!(result, expected);
|
|
2734
|
-
}
|
|
2735
|
-
|
|
2736
|
-
#[rstest]
|
|
2737
|
-
#[case::spacers(vec![(0, 0), (10, 5), (100, 0)], vec![Length(10), Length(10)], Flex::Legacy, 5)]
|
|
2738
|
-
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween, 5)]
|
|
2739
|
-
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceEvenly, 5)]
|
|
2740
|
-
#[case::spacers(vec![(0, 20), (30, 40), (80, 20)], vec![Length(10), Length(10)], Flex::SpaceAround, 5)]
|
|
2741
|
-
#[case::spacers(vec![(0, 0), (10, 5), (25, 75)], vec![Length(10), Length(10)], Flex::Start, 5)]
|
|
2742
|
-
#[case::spacers(vec![(0, 38), (48, 5), (63, 37)], vec![Length(10), Length(10)], Flex::Center, 5)]
|
|
2743
|
-
#[case::spacers(vec![(0, 75), (85, 5), (100, 0)], vec![Length(10), Length(10)], Flex::End, 5)]
|
|
2744
|
-
fn split_with_spacers_and_spacing(
|
|
2745
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2746
|
-
#[case] constraints: Vec<Constraint>,
|
|
2747
|
-
#[case] flex: Flex,
|
|
2748
|
-
#[case] spacing: i16,
|
|
2749
|
-
) {
|
|
2750
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2751
|
-
let (_, s) = Layout::horizontal(&constraints)
|
|
2752
|
-
.flex(flex)
|
|
2753
|
-
.spacing(spacing)
|
|
2754
|
-
.split_with_spacers(rect);
|
|
2755
|
-
assert_eq!(s.len(), constraints.len() + 1);
|
|
2756
|
-
let result = s
|
|
2757
|
-
.iter()
|
|
2758
|
-
.map(|r| (r.x, r.width))
|
|
2759
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2760
|
-
assert_eq!(expected, result);
|
|
2761
|
-
}
|
|
2762
|
-
|
|
2763
|
-
#[rstest]
|
|
2764
|
-
#[case::spacers_1(vec![(0, 0), (10, 0), (100, 0)], vec![Length(10), Length(10)], Flex::Legacy, -1)]
|
|
2765
|
-
#[case::spacers_2(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween, -1)]
|
|
2766
|
-
#[case::spacers_3(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceEvenly, -1)]
|
|
2767
|
-
#[case::spacers_3(vec![(0, 20), (30, 40), (80, 20)], vec![Length(10), Length(10)], Flex::SpaceAround, -1)]
|
|
2768
|
-
#[case::spacers_4(vec![(0, 0), (10, 0), (19, 81)], vec![Length(10), Length(10)], Flex::Start, -1)]
|
|
2769
|
-
#[case::spacers_5(vec![(0, 41), (51, 0), (60, 40)], vec![Length(10), Length(10)], Flex::Center, -1)]
|
|
2770
|
-
#[case::spacers_6(vec![(0, 81), (91, 0), (100, 0)], vec![Length(10), Length(10)], Flex::End, -1)]
|
|
2771
|
-
fn split_with_spacers_and_overlap(
|
|
2772
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2773
|
-
#[case] constraints: Vec<Constraint>,
|
|
2774
|
-
#[case] flex: Flex,
|
|
2775
|
-
#[case] spacing: i16,
|
|
2776
|
-
) {
|
|
2777
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2778
|
-
let (_, s) = Layout::horizontal(&constraints)
|
|
2779
|
-
.flex(flex)
|
|
2780
|
-
.spacing(spacing)
|
|
2781
|
-
.split_with_spacers(rect);
|
|
2782
|
-
assert_eq!(s.len(), constraints.len() + 1);
|
|
2783
|
-
let result = s
|
|
2784
|
-
.iter()
|
|
2785
|
-
.map(|r| (r.x, r.width))
|
|
2786
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2787
|
-
assert_eq!(result, expected);
|
|
2788
|
-
}
|
|
2789
|
-
|
|
2790
|
-
#[rstest]
|
|
2791
|
-
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::Legacy, 200)]
|
|
2792
|
-
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween, 200)]
|
|
2793
|
-
#[case::spacers(vec![(0, 33), (33, 34), (67, 33)], vec![Length(10), Length(10)], Flex::SpaceEvenly, 200)]
|
|
2794
|
-
#[case::spacers(vec![(0, 25), (25, 50), (75, 25)], vec![Length(10), Length(10)], Flex::SpaceAround, 200)]
|
|
2795
|
-
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::Start, 200)]
|
|
2796
|
-
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::Center, 200)]
|
|
2797
|
-
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::End, 200)]
|
|
2798
|
-
fn split_with_spacers_and_too_much_spacing(
|
|
2799
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2800
|
-
#[case] constraints: Vec<Constraint>,
|
|
2801
|
-
#[case] flex: Flex,
|
|
2802
|
-
#[case] spacing: i16,
|
|
2803
|
-
) {
|
|
2804
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2805
|
-
let (_, s) = Layout::horizontal(&constraints)
|
|
2806
|
-
.flex(flex)
|
|
2807
|
-
.spacing(spacing)
|
|
2808
|
-
.split_with_spacers(rect);
|
|
2809
|
-
assert_eq!(s.len(), constraints.len() + 1);
|
|
2810
|
-
let result = s
|
|
2811
|
-
.iter()
|
|
2812
|
-
.map(|r| (r.x, r.width))
|
|
2813
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2814
|
-
assert_eq!(result, expected);
|
|
2815
|
-
}
|
|
2816
|
-
|
|
2817
|
-
#[rstest]
|
|
2818
|
-
#[case::compare(vec![(0, 90), (90, 10)], vec![Min(10), Length(10)], Flex::Legacy)]
|
|
2819
|
-
#[case::compare(vec![(0, 90), (90, 10)], vec![Min(10), Length(10)], Flex::Start)]
|
|
2820
|
-
#[case::compare(vec![(0, 10), (10, 90)], vec![Min(10), Percentage(100)], Flex::Legacy)]
|
|
2821
|
-
#[case::compare(vec![(0, 10), (10, 90)], vec![Min(10), Percentage(100)], Flex::Start)]
|
|
2822
|
-
#[case::compare(vec![(0, 50), (50, 50)], vec![Percentage(50), Percentage(50)], Flex::Legacy)]
|
|
2823
|
-
#[case::compare(vec![(0, 50), (50, 50)], vec![Percentage(50), Percentage(50)], Flex::Start)]
|
|
2824
|
-
fn legacy_vs_default(
|
|
2825
|
-
#[case] expected: Vec<(u16, u16)>,
|
|
2826
|
-
#[case] constraints: Vec<Constraint>,
|
|
2827
|
-
#[case] flex: Flex,
|
|
2828
|
-
) {
|
|
2829
|
-
let rect = Rect::new(0, 0, 100, 1);
|
|
2830
|
-
let r = Layout::horizontal(constraints).flex(flex).split(rect);
|
|
2831
|
-
let result = r
|
|
2832
|
-
.iter()
|
|
2833
|
-
.map(|r| (r.x, r.width))
|
|
2834
|
-
.collect::<Vec<(u16, u16)>>();
|
|
2835
|
-
assert_eq!(result, expected);
|
|
2836
|
-
}
|
|
2837
|
-
}
|
|
2838
|
-
}
|