@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,1114 +0,0 @@
|
|
|
1
|
-
#![warn(missing_docs)]
|
|
2
|
-
use core::array::TryFromSliceError;
|
|
3
|
-
use core::cmp::{max, min};
|
|
4
|
-
use core::fmt;
|
|
5
|
-
|
|
6
|
-
pub use self::iter::{Columns, Positions, Rows};
|
|
7
|
-
use crate::layout::{Margin, Offset, Position, Size};
|
|
8
|
-
|
|
9
|
-
mod iter;
|
|
10
|
-
mod ops;
|
|
11
|
-
|
|
12
|
-
use super::{Constraint, Flex, Layout};
|
|
13
|
-
|
|
14
|
-
/// A rectangular area in the terminal.
|
|
15
|
-
///
|
|
16
|
-
/// A `Rect` represents a rectangular region in the terminal coordinate system, defined by its
|
|
17
|
-
/// top-left corner position and dimensions. This is the fundamental building block for all layout
|
|
18
|
-
/// operations and widget rendering in Ratatui.
|
|
19
|
-
///
|
|
20
|
-
/// Rectangles are used throughout the layout system to define areas where widgets can be rendered.
|
|
21
|
-
/// They are typically created by [`Layout`] operations that divide terminal space, but can also be
|
|
22
|
-
/// manually constructed for specific positioning needs.
|
|
23
|
-
///
|
|
24
|
-
/// The coordinate system uses the top-left corner as the origin (0, 0), with x increasing to the
|
|
25
|
-
/// right and y increasing downward. All measurements are in character cells.
|
|
26
|
-
///
|
|
27
|
-
/// # Construction and Conversion
|
|
28
|
-
///
|
|
29
|
-
/// - [`new`](Self::new) - Create a new rectangle from coordinates and dimensions
|
|
30
|
-
/// - [`as_position`](Self::as_position) - Convert to a position at the top-left corner
|
|
31
|
-
/// - [`as_size`](Self::as_size) - Convert to a size representing the dimensions
|
|
32
|
-
/// - [`from((Position, Size))`](Self::from) - Create from `(Position, Size)` tuple
|
|
33
|
-
/// - [`from(((u16, u16), (u16, u16)))`](Self::from) - Create from `((u16, u16), (u16, u16))`
|
|
34
|
-
/// coordinate and dimension tuples
|
|
35
|
-
/// - [`into((Position, Size))`] - Convert to `(Position, Size)` tuple
|
|
36
|
-
/// - [`default`](Self::default) - Create a zero-sized rectangle at origin
|
|
37
|
-
///
|
|
38
|
-
/// # Geometry and Properties
|
|
39
|
-
///
|
|
40
|
-
/// - [`area`](Self::area) - Calculate the total area in character cells
|
|
41
|
-
/// - [`is_empty`](Self::is_empty) - Check if the rectangle has zero area
|
|
42
|
-
/// - [`left`](Self::left), [`right`](Self::right), [`top`](Self::top), [`bottom`](Self::bottom) -
|
|
43
|
-
/// Get edge coordinates
|
|
44
|
-
///
|
|
45
|
-
/// # Spatial Operations
|
|
46
|
-
///
|
|
47
|
-
/// - [`inner`](Self::inner), [`outer`](Self::outer) - Apply margins to shrink or expand
|
|
48
|
-
/// - [`offset`](Self::offset) - Move the rectangle by a relative amount
|
|
49
|
-
/// - [`resize`](Self::resize) - Change the rectangle size while keeping the bottom/right in range
|
|
50
|
-
/// - [`union`](Self::union) - Combine with another rectangle to create a bounding box
|
|
51
|
-
/// - [`intersection`](Self::intersection) - Find the overlapping area with another rectangle
|
|
52
|
-
/// - [`clamp`](Self::clamp) - Constrain the rectangle to fit within another
|
|
53
|
-
///
|
|
54
|
-
/// # Positioning and Centering
|
|
55
|
-
///
|
|
56
|
-
/// - [`centered_horizontally`](Self::centered_horizontally) - Center horizontally within a
|
|
57
|
-
/// constraint
|
|
58
|
-
/// - [`centered_vertically`](Self::centered_vertically) - Center vertically within a constraint
|
|
59
|
-
/// - [`centered`](Self::centered) - Center both horizontally and vertically
|
|
60
|
-
///
|
|
61
|
-
/// # Testing and Iteration
|
|
62
|
-
///
|
|
63
|
-
/// - [`contains`](Self::contains) - Check if a position is within the rectangle
|
|
64
|
-
/// - [`intersects`](Self::intersects) - Check if it overlaps with another rectangle
|
|
65
|
-
/// - [`rows`](Self::rows) - Iterate over horizontal rows within the rectangle
|
|
66
|
-
/// - [`columns`](Self::columns) - Iterate over vertical columns within the rectangle
|
|
67
|
-
/// - [`positions`](Self::positions) - Iterate over all positions within the rectangle
|
|
68
|
-
///
|
|
69
|
-
/// # Examples
|
|
70
|
-
///
|
|
71
|
-
/// To create a new `Rect`, use [`Rect::new`]. The size of the `Rect` will be clamped to keep the
|
|
72
|
-
/// right and bottom coordinates within `u16`. Note that this clamping does not occur when creating
|
|
73
|
-
/// a `Rect` directly.
|
|
74
|
-
///
|
|
75
|
-
/// ```rust
|
|
76
|
-
/// use ratatui_core::layout::Rect;
|
|
77
|
-
///
|
|
78
|
-
/// let rect = Rect::new(1, 2, 3, 4);
|
|
79
|
-
/// assert_eq!(
|
|
80
|
-
/// rect,
|
|
81
|
-
/// Rect {
|
|
82
|
-
/// x: 1,
|
|
83
|
-
/// y: 2,
|
|
84
|
-
/// width: 3,
|
|
85
|
-
/// height: 4
|
|
86
|
-
/// }
|
|
87
|
-
/// );
|
|
88
|
-
/// ```
|
|
89
|
-
///
|
|
90
|
-
/// You can also create a `Rect` from a [`Position`] and a [`Size`].
|
|
91
|
-
///
|
|
92
|
-
/// ```rust
|
|
93
|
-
/// use ratatui_core::layout::{Position, Rect, Size};
|
|
94
|
-
///
|
|
95
|
-
/// let position = Position::new(1, 2);
|
|
96
|
-
/// let size = Size::new(3, 4);
|
|
97
|
-
/// let rect = Rect::from((position, size));
|
|
98
|
-
/// assert_eq!(
|
|
99
|
-
/// rect,
|
|
100
|
-
/// Rect {
|
|
101
|
-
/// x: 1,
|
|
102
|
-
/// y: 2,
|
|
103
|
-
/// width: 3,
|
|
104
|
-
/// height: 4
|
|
105
|
-
/// }
|
|
106
|
-
/// );
|
|
107
|
-
/// ```
|
|
108
|
-
///
|
|
109
|
-
/// To move a `Rect` without modifying its size, add or subtract an [`Offset`] to it.
|
|
110
|
-
///
|
|
111
|
-
/// ```rust
|
|
112
|
-
/// use ratatui_core::layout::{Offset, Rect};
|
|
113
|
-
///
|
|
114
|
-
/// let rect = Rect::new(1, 2, 3, 4);
|
|
115
|
-
/// let offset = Offset::new(5, 6);
|
|
116
|
-
/// let moved_rect = rect + offset;
|
|
117
|
-
/// assert_eq!(moved_rect, Rect::new(6, 8, 3, 4));
|
|
118
|
-
/// ```
|
|
119
|
-
///
|
|
120
|
-
/// To resize a `Rect` while ensuring it stays within bounds, use [`Rect::resize`]. The size is
|
|
121
|
-
/// clamped so that `right()` and `bottom()` do not exceed `u16::MAX`.
|
|
122
|
-
///
|
|
123
|
-
/// ```rust
|
|
124
|
-
/// use ratatui_core::layout::{Rect, Size};
|
|
125
|
-
///
|
|
126
|
-
/// let rect = Rect::new(u16::MAX - 1, u16::MAX - 1, 1, 1).resize(Size::new(10, 10));
|
|
127
|
-
/// assert_eq!(rect, Rect::new(u16::MAX - 1, u16::MAX - 1, 1, 1));
|
|
128
|
-
/// ```
|
|
129
|
-
///
|
|
130
|
-
/// For comprehensive layout documentation and examples, see the [`layout`](crate::layout) module.
|
|
131
|
-
|
|
132
|
-
#[derive(Debug, Default, Clone, Copy, Eq, PartialEq, Hash)]
|
|
133
|
-
#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
|
|
134
|
-
pub struct Rect {
|
|
135
|
-
/// The x coordinate of the top left corner of the `Rect`.
|
|
136
|
-
pub x: u16,
|
|
137
|
-
/// The y coordinate of the top left corner of the `Rect`.
|
|
138
|
-
pub y: u16,
|
|
139
|
-
/// The width of the `Rect`.
|
|
140
|
-
pub width: u16,
|
|
141
|
-
/// The height of the `Rect`.
|
|
142
|
-
pub height: u16,
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
impl fmt::Display for Rect {
|
|
146
|
-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
|
147
|
-
write!(f, "{}x{}+{}+{}", self.width, self.height, self.x, self.y)
|
|
148
|
-
}
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
impl Rect {
|
|
152
|
-
/// A zero sized Rect at position 0,0
|
|
153
|
-
pub const ZERO: Self = Self {
|
|
154
|
-
x: 0,
|
|
155
|
-
y: 0,
|
|
156
|
-
width: 0,
|
|
157
|
-
height: 0,
|
|
158
|
-
};
|
|
159
|
-
|
|
160
|
-
/// The minimum possible Rect
|
|
161
|
-
pub const MIN: Self = Self::ZERO;
|
|
162
|
-
|
|
163
|
-
/// The maximum possible Rect
|
|
164
|
-
pub const MAX: Self = Self::new(0, 0, u16::MAX, u16::MAX);
|
|
165
|
-
|
|
166
|
-
/// Creates a new `Rect`, with width and height limited to keep both bounds within `u16`.
|
|
167
|
-
///
|
|
168
|
-
/// If the width or height would cause the right or bottom coordinate to be larger than the
|
|
169
|
-
/// maximum value of `u16`, the width or height will be clamped to keep the right or bottom
|
|
170
|
-
/// coordinate within `u16`.
|
|
171
|
-
///
|
|
172
|
-
/// # Examples
|
|
173
|
-
///
|
|
174
|
-
/// ```
|
|
175
|
-
/// use ratatui_core::layout::Rect;
|
|
176
|
-
///
|
|
177
|
-
/// let rect = Rect::new(1, 2, 3, 4);
|
|
178
|
-
/// ```
|
|
179
|
-
pub const fn new(x: u16, y: u16, width: u16, height: u16) -> Self {
|
|
180
|
-
let width = x.saturating_add(width) - x;
|
|
181
|
-
let height = y.saturating_add(height) - y;
|
|
182
|
-
Self {
|
|
183
|
-
x,
|
|
184
|
-
y,
|
|
185
|
-
width,
|
|
186
|
-
height,
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
|
|
190
|
-
/// The area of the `Rect`.
|
|
191
|
-
pub const fn area(self) -> u32 {
|
|
192
|
-
(self.width as u32) * (self.height as u32)
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
/// Returns true if the `Rect` has no area.
|
|
196
|
-
pub const fn is_empty(self) -> bool {
|
|
197
|
-
self.width == 0 || self.height == 0
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/// Returns the left coordinate of the `Rect`.
|
|
201
|
-
pub const fn left(self) -> u16 {
|
|
202
|
-
self.x
|
|
203
|
-
}
|
|
204
|
-
|
|
205
|
-
/// Returns the right coordinate of the `Rect`. This is the first coordinate outside of the
|
|
206
|
-
/// `Rect`.
|
|
207
|
-
///
|
|
208
|
-
/// If the right coordinate is larger than the maximum value of u16, it will be clamped to
|
|
209
|
-
/// `u16::MAX`.
|
|
210
|
-
pub const fn right(self) -> u16 {
|
|
211
|
-
self.x.saturating_add(self.width)
|
|
212
|
-
}
|
|
213
|
-
|
|
214
|
-
/// Returns the top coordinate of the `Rect`.
|
|
215
|
-
pub const fn top(self) -> u16 {
|
|
216
|
-
self.y
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/// Returns the bottom coordinate of the `Rect`. This is the first coordinate outside of the
|
|
220
|
-
/// `Rect`.
|
|
221
|
-
///
|
|
222
|
-
/// If the bottom coordinate is larger than the maximum value of u16, it will be clamped to
|
|
223
|
-
/// `u16::MAX`.
|
|
224
|
-
pub const fn bottom(self) -> u16 {
|
|
225
|
-
self.y.saturating_add(self.height)
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
/// Returns a new `Rect` inside the current one, with the given margin on each side.
|
|
229
|
-
///
|
|
230
|
-
/// If the margin is larger than the `Rect`, the returned `Rect` will have no area.
|
|
231
|
-
#[must_use = "method returns the modified value"]
|
|
232
|
-
pub const fn inner(self, margin: Margin) -> Self {
|
|
233
|
-
let doubled_margin_horizontal = margin.horizontal.saturating_mul(2);
|
|
234
|
-
let doubled_margin_vertical = margin.vertical.saturating_mul(2);
|
|
235
|
-
|
|
236
|
-
if self.width < doubled_margin_horizontal || self.height < doubled_margin_vertical {
|
|
237
|
-
Self::ZERO
|
|
238
|
-
} else {
|
|
239
|
-
Self {
|
|
240
|
-
x: self.x.saturating_add(margin.horizontal),
|
|
241
|
-
y: self.y.saturating_add(margin.vertical),
|
|
242
|
-
width: self.width.saturating_sub(doubled_margin_horizontal),
|
|
243
|
-
height: self.height.saturating_sub(doubled_margin_vertical),
|
|
244
|
-
}
|
|
245
|
-
}
|
|
246
|
-
}
|
|
247
|
-
|
|
248
|
-
/// Returns a new `Rect` outside the current one, with the given margin applied on each side.
|
|
249
|
-
///
|
|
250
|
-
/// If the margin causes the `Rect`'s bounds to be outside the range of a `u16`, the `Rect` will
|
|
251
|
-
/// be truncated to keep the bounds within `u16`. This will cause the size of the `Rect` to
|
|
252
|
-
/// change.
|
|
253
|
-
///
|
|
254
|
-
/// The generated `Rect` may not fit inside the buffer or containing area, so it consider
|
|
255
|
-
/// constraining the resulting `Rect` with [`Rect::clamp`] before using it.
|
|
256
|
-
#[must_use = "method returns the modified value"]
|
|
257
|
-
pub const fn outer(self, margin: Margin) -> Self {
|
|
258
|
-
let x = self.x.saturating_sub(margin.horizontal);
|
|
259
|
-
let y = self.y.saturating_sub(margin.vertical);
|
|
260
|
-
let width = self
|
|
261
|
-
.right()
|
|
262
|
-
.saturating_add(margin.horizontal)
|
|
263
|
-
.saturating_sub(x);
|
|
264
|
-
let height = self
|
|
265
|
-
.bottom()
|
|
266
|
-
.saturating_add(margin.vertical)
|
|
267
|
-
.saturating_sub(y);
|
|
268
|
-
Self {
|
|
269
|
-
x,
|
|
270
|
-
y,
|
|
271
|
-
width,
|
|
272
|
-
height,
|
|
273
|
-
}
|
|
274
|
-
}
|
|
275
|
-
|
|
276
|
-
/// Moves the `Rect` without modifying its size.
|
|
277
|
-
///
|
|
278
|
-
/// Moves the `Rect` according to the given offset without modifying its [`width`](Rect::width)
|
|
279
|
-
/// or [`height`](Rect::height).
|
|
280
|
-
/// - Positive `x` moves the whole `Rect` to the right, negative to the left.
|
|
281
|
-
/// - Positive `y` moves the whole `Rect` to the bottom, negative to the top.
|
|
282
|
-
///
|
|
283
|
-
/// See [`Offset`] for details.
|
|
284
|
-
#[must_use = "method returns the modified value"]
|
|
285
|
-
pub fn offset(self, offset: Offset) -> Self {
|
|
286
|
-
self + offset
|
|
287
|
-
}
|
|
288
|
-
|
|
289
|
-
/// Resizes the `Rect`, clamping to keep the right and bottom within `u16::MAX`.
|
|
290
|
-
///
|
|
291
|
-
/// The position is preserved. If the requested size would push the `Rect` beyond the bounds of
|
|
292
|
-
/// `u16`, the width or height is reduced so that [`right`](Self::right) and
|
|
293
|
-
/// [`bottom`](Self::bottom) remain within range.
|
|
294
|
-
#[must_use = "method returns the modified value"]
|
|
295
|
-
pub const fn resize(self, size: Size) -> Self {
|
|
296
|
-
Self {
|
|
297
|
-
width: self.x.saturating_add(size.width).saturating_sub(self.x),
|
|
298
|
-
height: self.y.saturating_add(size.height).saturating_sub(self.y),
|
|
299
|
-
..self
|
|
300
|
-
}
|
|
301
|
-
}
|
|
302
|
-
|
|
303
|
-
/// Returns a new `Rect` that contains both the current one and the given one.
|
|
304
|
-
#[must_use = "method returns the modified value"]
|
|
305
|
-
pub fn union(self, other: Self) -> Self {
|
|
306
|
-
let x1 = min(self.x, other.x);
|
|
307
|
-
let y1 = min(self.y, other.y);
|
|
308
|
-
let x2 = max(self.right(), other.right());
|
|
309
|
-
let y2 = max(self.bottom(), other.bottom());
|
|
310
|
-
Self {
|
|
311
|
-
x: x1,
|
|
312
|
-
y: y1,
|
|
313
|
-
width: x2.saturating_sub(x1),
|
|
314
|
-
height: y2.saturating_sub(y1),
|
|
315
|
-
}
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/// Returns a new `Rect` that is the intersection of the current one and the given one.
|
|
319
|
-
///
|
|
320
|
-
/// If the two `Rect`s do not intersect, the returned `Rect` will have no area.
|
|
321
|
-
#[must_use = "method returns the modified value"]
|
|
322
|
-
pub fn intersection(self, other: Self) -> Self {
|
|
323
|
-
let x1 = max(self.x, other.x);
|
|
324
|
-
let y1 = max(self.y, other.y);
|
|
325
|
-
let x2 = min(self.right(), other.right());
|
|
326
|
-
let y2 = min(self.bottom(), other.bottom());
|
|
327
|
-
Self {
|
|
328
|
-
x: x1,
|
|
329
|
-
y: y1,
|
|
330
|
-
width: x2.saturating_sub(x1),
|
|
331
|
-
height: y2.saturating_sub(y1),
|
|
332
|
-
}
|
|
333
|
-
}
|
|
334
|
-
|
|
335
|
-
/// Returns true if the two `Rect`s intersect.
|
|
336
|
-
pub const fn intersects(self, other: Self) -> bool {
|
|
337
|
-
self.x < other.right()
|
|
338
|
-
&& self.right() > other.x
|
|
339
|
-
&& self.y < other.bottom()
|
|
340
|
-
&& self.bottom() > other.y
|
|
341
|
-
}
|
|
342
|
-
|
|
343
|
-
/// Returns true if the given position is inside the `Rect`.
|
|
344
|
-
///
|
|
345
|
-
/// The position is considered inside the `Rect` if it is on the `Rect`'s border.
|
|
346
|
-
///
|
|
347
|
-
/// # Examples
|
|
348
|
-
///
|
|
349
|
-
/// ```rust
|
|
350
|
-
/// use ratatui_core::layout::{Position, Rect};
|
|
351
|
-
///
|
|
352
|
-
/// let rect = Rect::new(1, 2, 3, 4);
|
|
353
|
-
/// assert!(rect.contains(Position { x: 1, y: 2 }));
|
|
354
|
-
/// ````
|
|
355
|
-
pub const fn contains(self, position: Position) -> bool {
|
|
356
|
-
position.x >= self.x
|
|
357
|
-
&& position.x < self.right()
|
|
358
|
-
&& position.y >= self.y
|
|
359
|
-
&& position.y < self.bottom()
|
|
360
|
-
}
|
|
361
|
-
|
|
362
|
-
/// Clamp this `Rect` to fit inside the other `Rect`.
|
|
363
|
-
///
|
|
364
|
-
/// If the width or height of this `Rect` is larger than the other `Rect`, it will be clamped to
|
|
365
|
-
/// the other `Rect`'s width or height.
|
|
366
|
-
///
|
|
367
|
-
/// If the left or top coordinate of this `Rect` is smaller than the other `Rect`, it will be
|
|
368
|
-
/// clamped to the other `Rect`'s left or top coordinate.
|
|
369
|
-
///
|
|
370
|
-
/// If the right or bottom coordinate of this `Rect` is larger than the other `Rect`, it will be
|
|
371
|
-
/// clamped to the other `Rect`'s right or bottom coordinate.
|
|
372
|
-
///
|
|
373
|
-
/// This is different from [`Rect::intersection`] because it will move this `Rect` to fit inside
|
|
374
|
-
/// the other `Rect`, while [`Rect::intersection`] instead would keep this `Rect`'s position and
|
|
375
|
-
/// truncate its size to only that which is inside the other `Rect`.
|
|
376
|
-
///
|
|
377
|
-
/// # Examples
|
|
378
|
-
///
|
|
379
|
-
/// ```rust
|
|
380
|
-
/// use ratatui_core::layout::Rect;
|
|
381
|
-
///
|
|
382
|
-
/// let area = Rect::new(0, 0, 100, 100);
|
|
383
|
-
/// let rect = Rect::new(80, 80, 30, 30).clamp(area);
|
|
384
|
-
/// assert_eq!(rect, Rect::new(70, 70, 30, 30));
|
|
385
|
-
/// ```
|
|
386
|
-
#[must_use = "method returns the modified value"]
|
|
387
|
-
pub fn clamp(self, other: Self) -> Self {
|
|
388
|
-
let width = self.width.min(other.width);
|
|
389
|
-
let height = self.height.min(other.height);
|
|
390
|
-
let x = self.x.clamp(other.x, other.right().saturating_sub(width));
|
|
391
|
-
let y = self.y.clamp(other.y, other.bottom().saturating_sub(height));
|
|
392
|
-
Self::new(x, y, width, height)
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
/// An iterator over rows within the `Rect`.
|
|
396
|
-
///
|
|
397
|
-
/// Each row is a full `Rect` region with height 1 that can be used for rendering widgets
|
|
398
|
-
/// or as input to further layout methods.
|
|
399
|
-
///
|
|
400
|
-
/// # Example
|
|
401
|
-
///
|
|
402
|
-
/// ```
|
|
403
|
-
/// use ratatui_core::buffer::Buffer;
|
|
404
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
405
|
-
/// use ratatui_core::widgets::Widget;
|
|
406
|
-
///
|
|
407
|
-
/// fn render_list(area: Rect, buf: &mut Buffer) {
|
|
408
|
-
/// // Renders "Item 0", "Item 1", etc. in each row
|
|
409
|
-
/// for (i, row) in area.rows().enumerate() {
|
|
410
|
-
/// format!("Item {i}").render(row, buf);
|
|
411
|
-
/// }
|
|
412
|
-
/// }
|
|
413
|
-
///
|
|
414
|
-
/// fn render_with_nested_layout(area: Rect, buf: &mut Buffer) {
|
|
415
|
-
/// // Splits each row into left/right areas and renders labels and content
|
|
416
|
-
/// for (i, row) in area.rows().take(3).enumerate() {
|
|
417
|
-
/// let [left, right] =
|
|
418
|
-
/// Layout::horizontal([Constraint::Percentage(30), Constraint::Fill(1)]).areas(row);
|
|
419
|
-
///
|
|
420
|
-
/// format!("{i}:").render(left, buf);
|
|
421
|
-
/// "Content".render(right, buf);
|
|
422
|
-
/// }
|
|
423
|
-
/// }
|
|
424
|
-
/// ```
|
|
425
|
-
pub const fn rows(self) -> Rows {
|
|
426
|
-
Rows::new(self)
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
/// An iterator over columns within the `Rect`.
|
|
430
|
-
///
|
|
431
|
-
/// Each column is a full `Rect` region with width 1 that can be used for rendering widgets
|
|
432
|
-
/// or as input to further layout methods.
|
|
433
|
-
///
|
|
434
|
-
/// # Example
|
|
435
|
-
///
|
|
436
|
-
/// ```
|
|
437
|
-
/// use ratatui_core::buffer::Buffer;
|
|
438
|
-
/// use ratatui_core::layout::Rect;
|
|
439
|
-
/// use ratatui_core::widgets::Widget;
|
|
440
|
-
///
|
|
441
|
-
/// fn render_columns(area: Rect, buf: &mut Buffer) {
|
|
442
|
-
/// // Renders column indices (0-9 repeating) in each column
|
|
443
|
-
/// for (i, column) in area.columns().enumerate() {
|
|
444
|
-
/// format!("{}", i % 10).render(column, buf);
|
|
445
|
-
/// }
|
|
446
|
-
/// }
|
|
447
|
-
/// ```
|
|
448
|
-
pub const fn columns(self) -> Columns {
|
|
449
|
-
Columns::new(self)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
/// An iterator over the positions within the `Rect`.
|
|
453
|
-
///
|
|
454
|
-
/// The positions are returned in a row-major order (left-to-right, top-to-bottom).
|
|
455
|
-
/// Each position is a `Position` that represents a single cell coordinate.
|
|
456
|
-
///
|
|
457
|
-
/// # Example
|
|
458
|
-
///
|
|
459
|
-
/// ```
|
|
460
|
-
/// use ratatui_core::buffer::Buffer;
|
|
461
|
-
/// use ratatui_core::layout::{Position, Rect};
|
|
462
|
-
/// use ratatui_core::widgets::Widget;
|
|
463
|
-
///
|
|
464
|
-
/// fn render_positions(area: Rect, buf: &mut Buffer) {
|
|
465
|
-
/// // Renders position indices (0-9 repeating) at each cell position
|
|
466
|
-
/// for (i, position) in area.positions().enumerate() {
|
|
467
|
-
/// buf[position].set_symbol(&format!("{}", i % 10));
|
|
468
|
-
/// }
|
|
469
|
-
/// }
|
|
470
|
-
/// ```
|
|
471
|
-
pub const fn positions(self) -> Positions {
|
|
472
|
-
Positions::new(self)
|
|
473
|
-
}
|
|
474
|
-
|
|
475
|
-
/// Returns a [`Position`] with the same coordinates as this `Rect`.
|
|
476
|
-
///
|
|
477
|
-
/// # Examples
|
|
478
|
-
///
|
|
479
|
-
/// ```
|
|
480
|
-
/// use ratatui_core::layout::Rect;
|
|
481
|
-
///
|
|
482
|
-
/// let rect = Rect::new(1, 2, 3, 4);
|
|
483
|
-
/// let position = rect.as_position();
|
|
484
|
-
/// ````
|
|
485
|
-
pub const fn as_position(self) -> Position {
|
|
486
|
-
Position {
|
|
487
|
-
x: self.x,
|
|
488
|
-
y: self.y,
|
|
489
|
-
}
|
|
490
|
-
}
|
|
491
|
-
|
|
492
|
-
/// Converts the `Rect` into a size struct.
|
|
493
|
-
pub const fn as_size(self) -> Size {
|
|
494
|
-
Size {
|
|
495
|
-
width: self.width,
|
|
496
|
-
height: self.height,
|
|
497
|
-
}
|
|
498
|
-
}
|
|
499
|
-
|
|
500
|
-
/// Returns a new Rect, centered horizontally based on the provided constraint.
|
|
501
|
-
///
|
|
502
|
-
/// # Examples
|
|
503
|
-
///
|
|
504
|
-
/// ```
|
|
505
|
-
/// use ratatui_core::layout::Constraint;
|
|
506
|
-
/// use ratatui_core::terminal::Frame;
|
|
507
|
-
///
|
|
508
|
-
/// fn render(frame: &mut Frame) {
|
|
509
|
-
/// let area = frame.area().centered_horizontally(Constraint::Ratio(1, 2));
|
|
510
|
-
/// }
|
|
511
|
-
/// ```
|
|
512
|
-
#[must_use]
|
|
513
|
-
pub fn centered_horizontally(self, constraint: Constraint) -> Self {
|
|
514
|
-
let [area] = self.layout(&Layout::horizontal([constraint]).flex(Flex::Center));
|
|
515
|
-
area
|
|
516
|
-
}
|
|
517
|
-
|
|
518
|
-
/// Returns a new Rect, centered vertically based on the provided constraint.
|
|
519
|
-
///
|
|
520
|
-
/// # Examples
|
|
521
|
-
///
|
|
522
|
-
/// ```
|
|
523
|
-
/// use ratatui_core::layout::Constraint;
|
|
524
|
-
/// use ratatui_core::terminal::Frame;
|
|
525
|
-
///
|
|
526
|
-
/// fn render(frame: &mut Frame) {
|
|
527
|
-
/// let area = frame.area().centered_vertically(Constraint::Ratio(1, 2));
|
|
528
|
-
/// }
|
|
529
|
-
/// ```
|
|
530
|
-
#[must_use]
|
|
531
|
-
pub fn centered_vertically(self, constraint: Constraint) -> Self {
|
|
532
|
-
let [area] = self.layout(&Layout::vertical([constraint]).flex(Flex::Center));
|
|
533
|
-
area
|
|
534
|
-
}
|
|
535
|
-
|
|
536
|
-
/// Returns a new Rect, centered horizontally and vertically based on the provided constraints.
|
|
537
|
-
///
|
|
538
|
-
/// # Examples
|
|
539
|
-
///
|
|
540
|
-
/// ```
|
|
541
|
-
/// use ratatui_core::layout::Constraint;
|
|
542
|
-
/// use ratatui_core::terminal::Frame;
|
|
543
|
-
///
|
|
544
|
-
/// fn render(frame: &mut Frame) {
|
|
545
|
-
/// let area = frame
|
|
546
|
-
/// .area()
|
|
547
|
-
/// .centered(Constraint::Ratio(1, 2), Constraint::Ratio(1, 3));
|
|
548
|
-
/// }
|
|
549
|
-
/// ```
|
|
550
|
-
#[must_use]
|
|
551
|
-
pub fn centered(
|
|
552
|
-
self,
|
|
553
|
-
horizontal_constraint: Constraint,
|
|
554
|
-
vertical_constraint: Constraint,
|
|
555
|
-
) -> Self {
|
|
556
|
-
self.centered_horizontally(horizontal_constraint)
|
|
557
|
-
.centered_vertically(vertical_constraint)
|
|
558
|
-
}
|
|
559
|
-
|
|
560
|
-
/// Split the rect into a number of sub-rects according to the given [`Layout`].
|
|
561
|
-
///
|
|
562
|
-
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
|
|
563
|
-
/// `Rc<[Rect]>`.
|
|
564
|
-
///
|
|
565
|
-
/// This method requires the number of constraints to be known at compile time. If you don't
|
|
566
|
-
/// know the number of constraints at compile time, use [`Layout::split`] instead.
|
|
567
|
-
///
|
|
568
|
-
/// # Panics
|
|
569
|
-
///
|
|
570
|
-
/// Panics if the number of constraints is not equal to the length of the returned array.
|
|
571
|
-
///
|
|
572
|
-
/// # Examples
|
|
573
|
-
///
|
|
574
|
-
/// ```
|
|
575
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
576
|
-
///
|
|
577
|
-
/// let area = Rect::new(0, 0, 10, 10);
|
|
578
|
-
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
|
579
|
-
/// let [top, main] = area.layout(&layout);
|
|
580
|
-
/// assert_eq!(top, Rect::new(0, 0, 10, 1));
|
|
581
|
-
/// assert_eq!(main, Rect::new(0, 1, 10, 9));
|
|
582
|
-
///
|
|
583
|
-
/// // or explicitly specify the number of constraints:
|
|
584
|
-
/// let areas = area.layout::<2>(&layout);
|
|
585
|
-
/// assert_eq!(areas, [Rect::new(0, 0, 10, 1), Rect::new(0, 1, 10, 9),]);
|
|
586
|
-
/// ```
|
|
587
|
-
#[must_use]
|
|
588
|
-
pub fn layout<const N: usize>(self, layout: &Layout) -> [Self; N] {
|
|
589
|
-
let areas = layout.split(self);
|
|
590
|
-
areas.as_ref().try_into().unwrap_or_else(|_| {
|
|
591
|
-
panic!(
|
|
592
|
-
"invalid number of rects: expected {N}, found {}",
|
|
593
|
-
areas.len()
|
|
594
|
-
)
|
|
595
|
-
})
|
|
596
|
-
}
|
|
597
|
-
|
|
598
|
-
/// Split the rect into a number of sub-rects according to the given [`Layout`].
|
|
599
|
-
///
|
|
600
|
-
/// An ergonomic wrapper around [`Layout::split`] that returns a [`Vec`] of `Rect`s instead of
|
|
601
|
-
/// `Rc<[Rect]>`.
|
|
602
|
-
///
|
|
603
|
-
/// # Examples
|
|
604
|
-
///
|
|
605
|
-
/// ```
|
|
606
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
607
|
-
///
|
|
608
|
-
/// let area = Rect::new(0, 0, 10, 10);
|
|
609
|
-
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
|
610
|
-
/// let areas = area.layout_vec(&layout);
|
|
611
|
-
/// assert_eq!(areas, vec![Rect::new(0, 0, 10, 1), Rect::new(0, 1, 10, 9),]);
|
|
612
|
-
/// ```
|
|
613
|
-
///
|
|
614
|
-
/// [`Vec`]: alloc::vec::Vec
|
|
615
|
-
#[must_use]
|
|
616
|
-
pub fn layout_vec(self, layout: &Layout) -> alloc::vec::Vec<Self> {
|
|
617
|
-
layout.split(self).as_ref().to_vec()
|
|
618
|
-
}
|
|
619
|
-
|
|
620
|
-
/// Try to split the rect into a number of sub-rects according to the given [`Layout`].
|
|
621
|
-
///
|
|
622
|
-
/// An ergonomic wrapper around [`Layout::split`] that returns an array of `Rect`s instead of
|
|
623
|
-
/// `Rc<[Rect]>`.
|
|
624
|
-
///
|
|
625
|
-
/// # Errors
|
|
626
|
-
///
|
|
627
|
-
/// Returns an error if the number of constraints is not equal to the length of the returned
|
|
628
|
-
/// array.
|
|
629
|
-
///
|
|
630
|
-
/// # Examples
|
|
631
|
-
///
|
|
632
|
-
/// ```
|
|
633
|
-
/// use ratatui_core::layout::{Constraint, Layout, Rect};
|
|
634
|
-
///
|
|
635
|
-
/// let area = Rect::new(0, 0, 10, 10);
|
|
636
|
-
/// let layout = Layout::vertical([Constraint::Length(1), Constraint::Min(0)]);
|
|
637
|
-
/// let [top, main] = area.try_layout(&layout)?;
|
|
638
|
-
/// assert_eq!(top, Rect::new(0, 0, 10, 1));
|
|
639
|
-
/// assert_eq!(main, Rect::new(0, 1, 10, 9));
|
|
640
|
-
///
|
|
641
|
-
/// // or explicitly specify the number of constraints:
|
|
642
|
-
/// let areas = area.try_layout::<2>(&layout)?;
|
|
643
|
-
/// assert_eq!(areas, [Rect::new(0, 0, 10, 1), Rect::new(0, 1, 10, 9),]);
|
|
644
|
-
/// # Ok::<(), core::array::TryFromSliceError>(())
|
|
645
|
-
/// ``````
|
|
646
|
-
pub fn try_layout<const N: usize>(
|
|
647
|
-
self,
|
|
648
|
-
layout: &Layout,
|
|
649
|
-
) -> Result<[Self; N], TryFromSliceError> {
|
|
650
|
-
layout.split(self).as_ref().try_into()
|
|
651
|
-
}
|
|
652
|
-
|
|
653
|
-
/// indents the x value of the `Rect` by a given `offset`
|
|
654
|
-
///
|
|
655
|
-
/// This is pub(crate) for now as we need to stabilize the naming / design of this API.
|
|
656
|
-
#[must_use]
|
|
657
|
-
pub(crate) const fn indent_x(self, offset: u16) -> Self {
|
|
658
|
-
Self {
|
|
659
|
-
x: self.x.saturating_add(offset),
|
|
660
|
-
width: self.width.saturating_sub(offset),
|
|
661
|
-
..self
|
|
662
|
-
}
|
|
663
|
-
}
|
|
664
|
-
}
|
|
665
|
-
|
|
666
|
-
impl From<(Position, Size)> for Rect {
|
|
667
|
-
fn from((position, size): (Position, Size)) -> Self {
|
|
668
|
-
Self {
|
|
669
|
-
x: position.x,
|
|
670
|
-
y: position.y,
|
|
671
|
-
width: size.width,
|
|
672
|
-
height: size.height,
|
|
673
|
-
}
|
|
674
|
-
}
|
|
675
|
-
}
|
|
676
|
-
|
|
677
|
-
impl From<Size> for Rect {
|
|
678
|
-
/// Creates a new `Rect` with the given size at [`Position::ORIGIN`] (0, 0).
|
|
679
|
-
fn from(size: Size) -> Self {
|
|
680
|
-
Self {
|
|
681
|
-
x: 0,
|
|
682
|
-
y: 0,
|
|
683
|
-
width: size.width,
|
|
684
|
-
height: size.height,
|
|
685
|
-
}
|
|
686
|
-
}
|
|
687
|
-
}
|
|
688
|
-
|
|
689
|
-
#[cfg(test)]
|
|
690
|
-
mod tests {
|
|
691
|
-
use alloc::string::ToString;
|
|
692
|
-
use alloc::vec;
|
|
693
|
-
use alloc::vec::Vec;
|
|
694
|
-
|
|
695
|
-
use pretty_assertions::assert_eq;
|
|
696
|
-
use rstest::rstest;
|
|
697
|
-
|
|
698
|
-
use super::*;
|
|
699
|
-
use crate::layout::{Constraint, Layout};
|
|
700
|
-
|
|
701
|
-
#[test]
|
|
702
|
-
fn to_string() {
|
|
703
|
-
assert_eq!(Rect::new(1, 2, 3, 4).to_string(), "3x4+1+2");
|
|
704
|
-
}
|
|
705
|
-
|
|
706
|
-
#[test]
|
|
707
|
-
fn new() {
|
|
708
|
-
assert_eq!(
|
|
709
|
-
Rect::new(1, 2, 3, 4),
|
|
710
|
-
Rect {
|
|
711
|
-
x: 1,
|
|
712
|
-
y: 2,
|
|
713
|
-
width: 3,
|
|
714
|
-
height: 4
|
|
715
|
-
}
|
|
716
|
-
);
|
|
717
|
-
}
|
|
718
|
-
|
|
719
|
-
#[test]
|
|
720
|
-
fn area() {
|
|
721
|
-
assert_eq!(Rect::new(1, 2, 3, 4).area(), 12);
|
|
722
|
-
}
|
|
723
|
-
|
|
724
|
-
#[test]
|
|
725
|
-
fn is_empty() {
|
|
726
|
-
assert!(!Rect::new(1, 2, 3, 4).is_empty());
|
|
727
|
-
assert!(Rect::new(1, 2, 0, 4).is_empty());
|
|
728
|
-
assert!(Rect::new(1, 2, 3, 0).is_empty());
|
|
729
|
-
}
|
|
730
|
-
|
|
731
|
-
#[test]
|
|
732
|
-
fn left() {
|
|
733
|
-
assert_eq!(Rect::new(1, 2, 3, 4).left(), 1);
|
|
734
|
-
}
|
|
735
|
-
|
|
736
|
-
#[test]
|
|
737
|
-
fn right() {
|
|
738
|
-
assert_eq!(Rect::new(1, 2, 3, 4).right(), 4);
|
|
739
|
-
}
|
|
740
|
-
|
|
741
|
-
#[test]
|
|
742
|
-
fn top() {
|
|
743
|
-
assert_eq!(Rect::new(1, 2, 3, 4).top(), 2);
|
|
744
|
-
}
|
|
745
|
-
|
|
746
|
-
#[test]
|
|
747
|
-
fn bottom() {
|
|
748
|
-
assert_eq!(Rect::new(1, 2, 3, 4).bottom(), 6);
|
|
749
|
-
}
|
|
750
|
-
|
|
751
|
-
#[test]
|
|
752
|
-
fn inner() {
|
|
753
|
-
assert_eq!(
|
|
754
|
-
Rect::new(1, 2, 3, 4).inner(Margin::new(1, 2)),
|
|
755
|
-
Rect::new(2, 4, 1, 0)
|
|
756
|
-
);
|
|
757
|
-
}
|
|
758
|
-
|
|
759
|
-
#[test]
|
|
760
|
-
fn outer() {
|
|
761
|
-
// enough space to grow on all sides
|
|
762
|
-
assert_eq!(
|
|
763
|
-
Rect::new(100, 200, 10, 20).outer(Margin::new(20, 30)),
|
|
764
|
-
Rect::new(80, 170, 50, 80)
|
|
765
|
-
);
|
|
766
|
-
|
|
767
|
-
// left / top saturation should truncate the size (10 less on left / top)
|
|
768
|
-
assert_eq!(
|
|
769
|
-
Rect::new(10, 20, 10, 20).outer(Margin::new(20, 30)),
|
|
770
|
-
Rect::new(0, 0, 40, 70),
|
|
771
|
-
);
|
|
772
|
-
|
|
773
|
-
// right / bottom saturation should truncate the size (10 less on bottom / right)
|
|
774
|
-
assert_eq!(
|
|
775
|
-
Rect::new(u16::MAX - 20, u16::MAX - 40, 10, 20).outer(Margin::new(20, 30)),
|
|
776
|
-
Rect::new(u16::MAX - 40, u16::MAX - 70, 40, 70),
|
|
777
|
-
);
|
|
778
|
-
}
|
|
779
|
-
|
|
780
|
-
#[test]
|
|
781
|
-
fn offset() {
|
|
782
|
-
assert_eq!(
|
|
783
|
-
Rect::new(1, 2, 3, 4).offset(Offset { x: 5, y: 6 }),
|
|
784
|
-
Rect::new(6, 8, 3, 4),
|
|
785
|
-
);
|
|
786
|
-
}
|
|
787
|
-
|
|
788
|
-
#[test]
|
|
789
|
-
fn negative_offset() {
|
|
790
|
-
assert_eq!(
|
|
791
|
-
Rect::new(4, 3, 3, 4).offset(Offset { x: -2, y: -1 }),
|
|
792
|
-
Rect::new(2, 2, 3, 4),
|
|
793
|
-
);
|
|
794
|
-
}
|
|
795
|
-
|
|
796
|
-
#[test]
|
|
797
|
-
fn negative_offset_saturate() {
|
|
798
|
-
assert_eq!(
|
|
799
|
-
Rect::new(1, 2, 3, 4).offset(Offset { x: -5, y: -6 }),
|
|
800
|
-
Rect::new(0, 0, 3, 4),
|
|
801
|
-
);
|
|
802
|
-
}
|
|
803
|
-
|
|
804
|
-
/// Offsets a [`Rect`] making it go outside [`u16::MAX`], it should keep its size.
|
|
805
|
-
#[test]
|
|
806
|
-
fn offset_saturate_max() {
|
|
807
|
-
assert_eq!(
|
|
808
|
-
Rect::new(u16::MAX - 500, u16::MAX - 500, 100, 100).offset(Offset { x: 1000, y: 1000 }),
|
|
809
|
-
Rect::new(u16::MAX - 100, u16::MAX - 100, 100, 100),
|
|
810
|
-
);
|
|
811
|
-
}
|
|
812
|
-
|
|
813
|
-
#[test]
|
|
814
|
-
fn union() {
|
|
815
|
-
assert_eq!(
|
|
816
|
-
Rect::new(1, 2, 3, 4).union(Rect::new(2, 3, 4, 5)),
|
|
817
|
-
Rect::new(1, 2, 5, 6)
|
|
818
|
-
);
|
|
819
|
-
}
|
|
820
|
-
|
|
821
|
-
#[test]
|
|
822
|
-
fn intersection() {
|
|
823
|
-
assert_eq!(
|
|
824
|
-
Rect::new(1, 2, 3, 4).intersection(Rect::new(2, 3, 4, 5)),
|
|
825
|
-
Rect::new(2, 3, 2, 3)
|
|
826
|
-
);
|
|
827
|
-
}
|
|
828
|
-
|
|
829
|
-
#[test]
|
|
830
|
-
fn intersection_underflow() {
|
|
831
|
-
assert_eq!(
|
|
832
|
-
Rect::new(1, 1, 2, 2).intersection(Rect::new(4, 4, 2, 2)),
|
|
833
|
-
Rect::new(4, 4, 0, 0)
|
|
834
|
-
);
|
|
835
|
-
}
|
|
836
|
-
|
|
837
|
-
#[test]
|
|
838
|
-
fn intersects() {
|
|
839
|
-
assert!(Rect::new(1, 2, 3, 4).intersects(Rect::new(2, 3, 4, 5)));
|
|
840
|
-
assert!(!Rect::new(1, 2, 3, 4).intersects(Rect::new(5, 6, 7, 8)));
|
|
841
|
-
}
|
|
842
|
-
|
|
843
|
-
#[rstest]
|
|
844
|
-
#[case::corner(Rect::new(0, 0, 10, 10), Rect::new(10, 10, 20, 20))]
|
|
845
|
-
#[case::edge(Rect::new(0, 0, 10, 10), Rect::new(10, 0, 20, 10))]
|
|
846
|
-
#[case::no_intersect(Rect::new(0, 0, 10, 10), Rect::new(11, 11, 20, 20))]
|
|
847
|
-
#[case::contains(Rect::new(0, 0, 20, 20), Rect::new(5, 5, 10, 10))]
|
|
848
|
-
fn mutual_intersect(#[case] rect0: Rect, #[case] rect1: Rect) {
|
|
849
|
-
assert_eq!(rect0.intersection(rect1), rect1.intersection(rect0));
|
|
850
|
-
assert_eq!(rect0.intersects(rect1), rect1.intersects(rect0));
|
|
851
|
-
}
|
|
852
|
-
|
|
853
|
-
// the bounds of this rect are x: [1..=3], y: [2..=5]
|
|
854
|
-
#[rstest]
|
|
855
|
-
#[case::inside_top_left(Rect::new(1, 2, 3, 4), Position { x: 1, y: 2 }, true)]
|
|
856
|
-
#[case::inside_top_right(Rect::new(1, 2, 3, 4), Position { x: 3, y: 2 }, true)]
|
|
857
|
-
#[case::inside_bottom_left(Rect::new(1, 2, 3, 4), Position { x: 1, y: 5 }, true)]
|
|
858
|
-
#[case::inside_bottom_right(Rect::new(1, 2, 3, 4), Position { x: 3, y: 5 }, true)]
|
|
859
|
-
#[case::outside_left(Rect::new(1, 2, 3, 4), Position { x: 0, y: 2 }, false)]
|
|
860
|
-
#[case::outside_right(Rect::new(1, 2, 3, 4), Position { x: 4, y: 2 }, false)]
|
|
861
|
-
#[case::outside_top(Rect::new(1, 2, 3, 4), Position { x: 1, y: 1 }, false)]
|
|
862
|
-
#[case::outside_bottom(Rect::new(1, 2, 3, 4), Position { x: 1, y: 6 }, false)]
|
|
863
|
-
#[case::outside_top_left(Rect::new(1, 2, 3, 4), Position { x: 0, y: 1 }, false)]
|
|
864
|
-
#[case::outside_bottom_right(Rect::new(1, 2, 3, 4), Position { x: 4, y: 6 }, false)]
|
|
865
|
-
fn contains(#[case] rect: Rect, #[case] position: Position, #[case] expected: bool) {
|
|
866
|
-
assert_eq!(
|
|
867
|
-
rect.contains(position),
|
|
868
|
-
expected,
|
|
869
|
-
"rect: {rect:?}, position: {position:?}",
|
|
870
|
-
);
|
|
871
|
-
}
|
|
872
|
-
|
|
873
|
-
#[test]
|
|
874
|
-
fn size_truncation() {
|
|
875
|
-
assert_eq!(
|
|
876
|
-
Rect::new(u16::MAX - 100, u16::MAX - 1000, 200, 2000),
|
|
877
|
-
Rect {
|
|
878
|
-
x: u16::MAX - 100,
|
|
879
|
-
y: u16::MAX - 1000,
|
|
880
|
-
width: 100,
|
|
881
|
-
height: 1000
|
|
882
|
-
}
|
|
883
|
-
);
|
|
884
|
-
}
|
|
885
|
-
|
|
886
|
-
#[test]
|
|
887
|
-
fn size_preservation() {
|
|
888
|
-
assert_eq!(
|
|
889
|
-
Rect::new(u16::MAX - 100, u16::MAX - 1000, 100, 1000),
|
|
890
|
-
Rect {
|
|
891
|
-
x: u16::MAX - 100,
|
|
892
|
-
y: u16::MAX - 1000,
|
|
893
|
-
width: 100,
|
|
894
|
-
height: 1000
|
|
895
|
-
}
|
|
896
|
-
);
|
|
897
|
-
}
|
|
898
|
-
|
|
899
|
-
#[test]
|
|
900
|
-
fn resize_updates_size() {
|
|
901
|
-
let rect = Rect::new(10, 20, 5, 5).resize(Size::new(30, 40));
|
|
902
|
-
assert_eq!(rect, Rect::new(10, 20, 30, 40));
|
|
903
|
-
}
|
|
904
|
-
|
|
905
|
-
#[test]
|
|
906
|
-
fn resize_clamps_at_bounds() {
|
|
907
|
-
let rect = Rect::new(u16::MAX - 2, u16::MAX - 3, 1, 1).resize(Size::new(10, 10));
|
|
908
|
-
assert_eq!(rect, Rect::new(u16::MAX - 2, u16::MAX - 3, 2, 3));
|
|
909
|
-
}
|
|
910
|
-
|
|
911
|
-
#[test]
|
|
912
|
-
fn can_be_const() {
|
|
913
|
-
const RECT: Rect = Rect {
|
|
914
|
-
x: 0,
|
|
915
|
-
y: 0,
|
|
916
|
-
width: 10,
|
|
917
|
-
height: 10,
|
|
918
|
-
};
|
|
919
|
-
const _AREA: u32 = RECT.area();
|
|
920
|
-
const _LEFT: u16 = RECT.left();
|
|
921
|
-
const _RIGHT: u16 = RECT.right();
|
|
922
|
-
const _TOP: u16 = RECT.top();
|
|
923
|
-
const _BOTTOM: u16 = RECT.bottom();
|
|
924
|
-
assert!(RECT.intersects(RECT));
|
|
925
|
-
}
|
|
926
|
-
|
|
927
|
-
#[test]
|
|
928
|
-
fn split() {
|
|
929
|
-
let [a, b] = Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)])
|
|
930
|
-
.areas(Rect::new(0, 0, 2, 1));
|
|
931
|
-
assert_eq!(a, Rect::new(0, 0, 1, 1));
|
|
932
|
-
assert_eq!(b, Rect::new(1, 0, 1, 1));
|
|
933
|
-
}
|
|
934
|
-
|
|
935
|
-
#[test]
|
|
936
|
-
#[should_panic(expected = "invalid number of rects")]
|
|
937
|
-
fn split_invalid_number_of_recs() {
|
|
938
|
-
let layout = Layout::horizontal([Constraint::Percentage(50), Constraint::Percentage(50)]);
|
|
939
|
-
let [_a, _b, _c] = layout.areas(Rect::new(0, 0, 2, 1));
|
|
940
|
-
}
|
|
941
|
-
|
|
942
|
-
#[rstest]
|
|
943
|
-
#[case::inside(Rect::new(20, 20, 10, 10), Rect::new(20, 20, 10, 10))]
|
|
944
|
-
#[case::up_left(Rect::new(5, 5, 10, 10), Rect::new(10, 10, 10, 10))]
|
|
945
|
-
#[case::up(Rect::new(20, 5, 10, 10), Rect::new(20, 10, 10, 10))]
|
|
946
|
-
#[case::up_right(Rect::new(105, 5, 10, 10), Rect::new(100, 10, 10, 10))]
|
|
947
|
-
#[case::left(Rect::new(5, 20, 10, 10), Rect::new(10, 20, 10, 10))]
|
|
948
|
-
#[case::right(Rect::new(105, 20, 10, 10), Rect::new(100, 20, 10, 10))]
|
|
949
|
-
#[case::down_left(Rect::new(5, 105, 10, 10), Rect::new(10, 100, 10, 10))]
|
|
950
|
-
#[case::down(Rect::new(20, 105, 10, 10), Rect::new(20, 100, 10, 10))]
|
|
951
|
-
#[case::down_right(Rect::new(105, 105, 10, 10), Rect::new(100, 100, 10, 10))]
|
|
952
|
-
#[case::too_wide(Rect::new(5, 20, 200, 10), Rect::new(10, 20, 100, 10))]
|
|
953
|
-
#[case::too_tall(Rect::new(20, 5, 10, 200), Rect::new(20, 10, 10, 100))]
|
|
954
|
-
#[case::too_large(Rect::new(0, 0, 200, 200), Rect::new(10, 10, 100, 100))]
|
|
955
|
-
fn clamp(#[case] rect: Rect, #[case] expected: Rect) {
|
|
956
|
-
let other = Rect::new(10, 10, 100, 100);
|
|
957
|
-
assert_eq!(rect.clamp(other), expected);
|
|
958
|
-
}
|
|
959
|
-
|
|
960
|
-
#[test]
|
|
961
|
-
fn rows() {
|
|
962
|
-
let area = Rect::new(0, 0, 3, 2);
|
|
963
|
-
let rows: Vec<Rect> = area.rows().collect();
|
|
964
|
-
|
|
965
|
-
let expected_rows: Vec<Rect> = vec![Rect::new(0, 0, 3, 1), Rect::new(0, 1, 3, 1)];
|
|
966
|
-
|
|
967
|
-
assert_eq!(rows, expected_rows);
|
|
968
|
-
}
|
|
969
|
-
|
|
970
|
-
#[test]
|
|
971
|
-
fn columns() {
|
|
972
|
-
let area = Rect::new(0, 0, 3, 2);
|
|
973
|
-
let columns: Vec<Rect> = area.columns().collect();
|
|
974
|
-
|
|
975
|
-
let expected_columns: Vec<Rect> = vec![
|
|
976
|
-
Rect::new(0, 0, 1, 2),
|
|
977
|
-
Rect::new(1, 0, 1, 2),
|
|
978
|
-
Rect::new(2, 0, 1, 2),
|
|
979
|
-
];
|
|
980
|
-
|
|
981
|
-
assert_eq!(columns, expected_columns);
|
|
982
|
-
}
|
|
983
|
-
|
|
984
|
-
#[test]
|
|
985
|
-
fn as_position() {
|
|
986
|
-
let rect = Rect::new(1, 2, 3, 4);
|
|
987
|
-
let position = rect.as_position();
|
|
988
|
-
assert_eq!(position.x, 1);
|
|
989
|
-
assert_eq!(position.y, 2);
|
|
990
|
-
}
|
|
991
|
-
|
|
992
|
-
#[test]
|
|
993
|
-
fn as_size() {
|
|
994
|
-
assert_eq!(
|
|
995
|
-
Rect::new(1, 2, 3, 4).as_size(),
|
|
996
|
-
Size {
|
|
997
|
-
width: 3,
|
|
998
|
-
height: 4
|
|
999
|
-
}
|
|
1000
|
-
);
|
|
1001
|
-
}
|
|
1002
|
-
|
|
1003
|
-
#[test]
|
|
1004
|
-
fn from_position_and_size() {
|
|
1005
|
-
let position = Position { x: 1, y: 2 };
|
|
1006
|
-
let size = Size {
|
|
1007
|
-
width: 3,
|
|
1008
|
-
height: 4,
|
|
1009
|
-
};
|
|
1010
|
-
assert_eq!(
|
|
1011
|
-
Rect::from((position, size)),
|
|
1012
|
-
Rect {
|
|
1013
|
-
x: 1,
|
|
1014
|
-
y: 2,
|
|
1015
|
-
width: 3,
|
|
1016
|
-
height: 4
|
|
1017
|
-
}
|
|
1018
|
-
);
|
|
1019
|
-
}
|
|
1020
|
-
|
|
1021
|
-
#[test]
|
|
1022
|
-
fn from_size() {
|
|
1023
|
-
let size = Size {
|
|
1024
|
-
width: 3,
|
|
1025
|
-
height: 4,
|
|
1026
|
-
};
|
|
1027
|
-
assert_eq!(
|
|
1028
|
-
Rect::from(size),
|
|
1029
|
-
Rect {
|
|
1030
|
-
x: 0,
|
|
1031
|
-
y: 0,
|
|
1032
|
-
width: 3,
|
|
1033
|
-
height: 4
|
|
1034
|
-
}
|
|
1035
|
-
);
|
|
1036
|
-
}
|
|
1037
|
-
|
|
1038
|
-
#[test]
|
|
1039
|
-
fn centered_horizontally() {
|
|
1040
|
-
let rect = Rect::new(0, 0, 5, 5);
|
|
1041
|
-
assert_eq!(
|
|
1042
|
-
rect.centered_horizontally(Constraint::Length(3)),
|
|
1043
|
-
Rect::new(1, 0, 3, 5)
|
|
1044
|
-
);
|
|
1045
|
-
}
|
|
1046
|
-
|
|
1047
|
-
#[test]
|
|
1048
|
-
fn centered_vertically() {
|
|
1049
|
-
let rect = Rect::new(0, 0, 5, 5);
|
|
1050
|
-
assert_eq!(
|
|
1051
|
-
rect.centered_vertically(Constraint::Length(1)),
|
|
1052
|
-
Rect::new(0, 2, 5, 1)
|
|
1053
|
-
);
|
|
1054
|
-
}
|
|
1055
|
-
|
|
1056
|
-
#[test]
|
|
1057
|
-
fn centered() {
|
|
1058
|
-
let rect = Rect::new(0, 0, 5, 5);
|
|
1059
|
-
assert_eq!(
|
|
1060
|
-
rect.centered(Constraint::Length(3), Constraint::Length(1)),
|
|
1061
|
-
Rect::new(1, 2, 3, 1)
|
|
1062
|
-
);
|
|
1063
|
-
}
|
|
1064
|
-
|
|
1065
|
-
#[test]
|
|
1066
|
-
fn layout() {
|
|
1067
|
-
let layout = Layout::horizontal([Constraint::Length(3), Constraint::Min(0)]);
|
|
1068
|
-
|
|
1069
|
-
let [a, b] = Rect::new(0, 0, 10, 10).layout(&layout);
|
|
1070
|
-
assert_eq!(a, Rect::new(0, 0, 3, 10));
|
|
1071
|
-
assert_eq!(b, Rect::new(3, 0, 7, 10));
|
|
1072
|
-
|
|
1073
|
-
let areas = Rect::new(0, 0, 10, 10).layout::<2>(&layout);
|
|
1074
|
-
assert_eq!(areas[0], Rect::new(0, 0, 3, 10));
|
|
1075
|
-
assert_eq!(areas[1], Rect::new(3, 0, 7, 10));
|
|
1076
|
-
}
|
|
1077
|
-
|
|
1078
|
-
#[test]
|
|
1079
|
-
#[should_panic(expected = "invalid number of rects: expected 3, found 1")]
|
|
1080
|
-
fn layout_invalid_number_of_rects() {
|
|
1081
|
-
let layout = Layout::horizontal([Constraint::Length(1)]);
|
|
1082
|
-
let [_, _, _] = Rect::new(0, 0, 10, 10).layout(&layout);
|
|
1083
|
-
}
|
|
1084
|
-
|
|
1085
|
-
#[test]
|
|
1086
|
-
fn layout_vec() {
|
|
1087
|
-
let layout = Layout::horizontal([Constraint::Length(3), Constraint::Min(0)]);
|
|
1088
|
-
|
|
1089
|
-
let areas = Rect::new(0, 0, 10, 10).layout_vec(&layout);
|
|
1090
|
-
assert_eq!(areas[0], Rect::new(0, 0, 3, 10));
|
|
1091
|
-
assert_eq!(areas[1], Rect::new(3, 0, 7, 10));
|
|
1092
|
-
}
|
|
1093
|
-
|
|
1094
|
-
#[test]
|
|
1095
|
-
fn try_layout() {
|
|
1096
|
-
let layout = Layout::horizontal([Constraint::Length(3), Constraint::Min(0)]);
|
|
1097
|
-
|
|
1098
|
-
let [a, b] = Rect::new(0, 0, 10, 10).try_layout(&layout).unwrap();
|
|
1099
|
-
assert_eq!(a, Rect::new(0, 0, 3, 10));
|
|
1100
|
-
assert_eq!(b, Rect::new(3, 0, 7, 10));
|
|
1101
|
-
|
|
1102
|
-
let areas = Rect::new(0, 0, 10, 10).try_layout::<2>(&layout).unwrap();
|
|
1103
|
-
assert_eq!(areas[0], Rect::new(0, 0, 3, 10));
|
|
1104
|
-
assert_eq!(areas[1], Rect::new(3, 0, 7, 10));
|
|
1105
|
-
}
|
|
1106
|
-
|
|
1107
|
-
#[test]
|
|
1108
|
-
fn try_layout_invalid_number_of_rects() {
|
|
1109
|
-
let layout = Layout::horizontal([Constraint::Length(1)]);
|
|
1110
|
-
Rect::new(0, 0, 10, 10)
|
|
1111
|
-
.try_layout::<3>(&layout)
|
|
1112
|
-
.unwrap_err();
|
|
1113
|
-
}
|
|
1114
|
-
}
|