@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.
Files changed (67) hide show
  1. package/README.ja.md +106 -146
  2. package/README.md +103 -143
  3. package/bin/gwt.cjs +1 -1
  4. package/package.json +5 -5
  5. package/rustfmt.toml +0 -2
  6. package/scripts/check-release-flow.sh +2 -8
  7. package/scripts/postinstall.js +17 -7
  8. package/scripts/run-local-backend-tests-on-commit.sh +6 -12
  9. package/scripts/test-all.sh +1 -5
  10. package/scripts/check-e2e-coverage-threshold.mjs +0 -238
  11. package/scripts/run-local-e2e-coverage-on-commit.sh +0 -69
  12. package/scripts/run-local-e2e-on-commit.sh +0 -60
  13. package/scripts/verify-ci-node-toolchain.sh +0 -76
  14. package/scripts/voice-eval.sh +0 -48
  15. package/vendor/ratatui-core/src/backend/test.rs +0 -1077
  16. package/vendor/ratatui-core/src/backend.rs +0 -405
  17. package/vendor/ratatui-core/src/buffer/assert.rs +0 -71
  18. package/vendor/ratatui-core/src/buffer/buffer.rs +0 -1388
  19. package/vendor/ratatui-core/src/buffer/cell.rs +0 -377
  20. package/vendor/ratatui-core/src/buffer.rs +0 -9
  21. package/vendor/ratatui-core/src/layout/alignment.rs +0 -89
  22. package/vendor/ratatui-core/src/layout/constraint.rs +0 -526
  23. package/vendor/ratatui-core/src/layout/direction.rs +0 -63
  24. package/vendor/ratatui-core/src/layout/flex.rs +0 -212
  25. package/vendor/ratatui-core/src/layout/layout.rs +0 -2838
  26. package/vendor/ratatui-core/src/layout/margin.rs +0 -79
  27. package/vendor/ratatui-core/src/layout/offset.rs +0 -66
  28. package/vendor/ratatui-core/src/layout/position.rs +0 -253
  29. package/vendor/ratatui-core/src/layout/rect/iter.rs +0 -356
  30. package/vendor/ratatui-core/src/layout/rect/ops.rs +0 -136
  31. package/vendor/ratatui-core/src/layout/rect.rs +0 -1114
  32. package/vendor/ratatui-core/src/layout/size.rs +0 -147
  33. package/vendor/ratatui-core/src/layout.rs +0 -333
  34. package/vendor/ratatui-core/src/lib.rs +0 -82
  35. package/vendor/ratatui-core/src/style/anstyle.rs +0 -348
  36. package/vendor/ratatui-core/src/style/color.rs +0 -788
  37. package/vendor/ratatui-core/src/style/palette/material.rs +0 -608
  38. package/vendor/ratatui-core/src/style/palette/tailwind.rs +0 -653
  39. package/vendor/ratatui-core/src/style/palette.rs +0 -6
  40. package/vendor/ratatui-core/src/style/palette_conversion.rs +0 -82
  41. package/vendor/ratatui-core/src/style/stylize.rs +0 -668
  42. package/vendor/ratatui-core/src/style.rs +0 -1069
  43. package/vendor/ratatui-core/src/symbols/bar.rs +0 -51
  44. package/vendor/ratatui-core/src/symbols/block.rs +0 -51
  45. package/vendor/ratatui-core/src/symbols/border.rs +0 -709
  46. package/vendor/ratatui-core/src/symbols/braille.rs +0 -21
  47. package/vendor/ratatui-core/src/symbols/half_block.rs +0 -3
  48. package/vendor/ratatui-core/src/symbols/line.rs +0 -259
  49. package/vendor/ratatui-core/src/symbols/marker.rs +0 -82
  50. package/vendor/ratatui-core/src/symbols/merge.rs +0 -748
  51. package/vendor/ratatui-core/src/symbols/pixel.rs +0 -30
  52. package/vendor/ratatui-core/src/symbols/scrollbar.rs +0 -46
  53. package/vendor/ratatui-core/src/symbols/shade.rs +0 -5
  54. package/vendor/ratatui-core/src/symbols.rs +0 -15
  55. package/vendor/ratatui-core/src/terminal/frame.rs +0 -192
  56. package/vendor/ratatui-core/src/terminal/terminal.rs +0 -926
  57. package/vendor/ratatui-core/src/terminal/viewport.rs +0 -58
  58. package/vendor/ratatui-core/src/terminal.rs +0 -40
  59. package/vendor/ratatui-core/src/text/grapheme.rs +0 -84
  60. package/vendor/ratatui-core/src/text/line.rs +0 -1678
  61. package/vendor/ratatui-core/src/text/masked.rs +0 -149
  62. package/vendor/ratatui-core/src/text/span.rs +0 -904
  63. package/vendor/ratatui-core/src/text/text.rs +0 -1434
  64. package/vendor/ratatui-core/src/text.rs +0 -64
  65. package/vendor/ratatui-core/src/widgets/stateful_widget.rs +0 -193
  66. package/vendor/ratatui-core/src/widgets/widget.rs +0 -174
  67. 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
- }