mirror of
https://github.com/ratatui/ratatui.git
synced 2025-10-02 15:25:54 +00:00
feat(layout)!: Change Flex::default()
(#881)
This PR makes a number of simplifications to the layout and constraint features that were added after v0.25.0. For users upgrading from v0.25.0, the net effect of this PR (along with the other PRs) is the following: - New `Flex` modes have been added. - `Flex::Start` (new default) - `Flex::Center` - `Flex::End` - `Flex::SpaceAround` - `Flex::SpaceBetween` - `Flex::Legacy` (old default) - `Min(v)` grows to allocate excess space in all `Flex` modes instead of shrinking (except in `Flex::Legacy` where it retains old behavior). - `Fill(1)` grows to allocate excess space, growing equally with `Min(v)`. --- The following contains a summary of the changes in this PR and the motivation behind them. **`Flex`** - Removes `Flex::Stretch` - Renames `Flex::StretchLast` to `Flex::Legacy` **`Constraint`** - Removes `Fixed` - Makes `Min(v)` grow as much as possible everywhere (except `Flex::Legacy` where it retains the old behavior) - Makes `Min(v)` grow equally as `Fill(1)` while respecting `Min` lower bounds. When `Fill` and `Min` are used together, they both fill excess space equally. Allowing `Min(v)` to grow still allows users to build the same layouts as before with `Flex::Start` with no breaking changes to the behavior. This PR also removes the unstable feature `SegmentSize`. This is a breaking change to the behavior of constraints. If users want old behavior, they can use `Flex::Legacy`. ```rust Layout::vertical([Length(25), Length(25)]).flex(Flex::Legacy) ``` Users that have constraint that exceed the available space will probably not see any difference or see an improvement in their layouts. Any layout with `Min` will be identical in `Flex::Start` and `Flex::Legacy` so any layout with `Min` will not be breaking. Previously, `Table` used `EvenDistribution` internally by default, but with that gone the default is now `Flex::Start`. This changes the behavior of `Table` (for the better in most cases). The only way for users to get exactly the same as the old behavior is to change their constraints. I imagine most users will be happier out of the box with the new Table default. Resolves https://github.com/ratatui-org/ratatui/issues/843 Thanks to @joshka for the direction
This commit is contained in:
parent
984afd580b
commit
540fd2df03
@ -100,11 +100,7 @@ underline-color = ["dep:crossterm"]
|
|||||||
#! The following features are unstable and may change in the future:
|
#! The following features are unstable and may change in the future:
|
||||||
|
|
||||||
## Enable all unstable features.
|
## Enable all unstable features.
|
||||||
unstable = ["unstable-segment-size", "unstable-rendered-line-info"]
|
unstable = ["unstable-rendered-line-info"]
|
||||||
|
|
||||||
## Enables the [`Layout::segment_size`](crate::layout::Layout::segment_size) method which is experimental and may change in the
|
|
||||||
## future. See [Issue #536](https://github.com/ratatui-org/ratatui/issues/536) for more details.
|
|
||||||
unstable-segment-size = []
|
|
||||||
|
|
||||||
## Enables the [`Paragraph::line_count`](crate::widgets::Paragraph::line_count)
|
## Enables the [`Paragraph::line_count`](crate::widgets::Paragraph::line_count)
|
||||||
## [`Paragraph::line_width`](crate::widgets::Paragraph::line_width) methods
|
## [`Paragraph::line_width`](crate::widgets::Paragraph::line_width) methods
|
||||||
|
@ -28,8 +28,6 @@ const SPACER_HEIGHT: u16 = 0;
|
|||||||
const ILLUSTRATION_HEIGHT: u16 = 4;
|
const ILLUSTRATION_HEIGHT: u16 = 4;
|
||||||
const EXAMPLE_HEIGHT: u16 = ILLUSTRATION_HEIGHT + SPACER_HEIGHT;
|
const EXAMPLE_HEIGHT: u16 = ILLUSTRATION_HEIGHT + SPACER_HEIGHT;
|
||||||
|
|
||||||
// priority 1
|
|
||||||
const FIXED_COLOR: Color = tailwind::RED.c900;
|
|
||||||
// priority 2
|
// priority 2
|
||||||
const MIN_COLOR: Color = tailwind::BLUE.c900;
|
const MIN_COLOR: Color = tailwind::BLUE.c900;
|
||||||
const MAX_COLOR: Color = tailwind::BLUE.c800;
|
const MAX_COLOR: Color = tailwind::BLUE.c800;
|
||||||
@ -54,7 +52,6 @@ struct App {
|
|||||||
#[derive(Default, Debug, Copy, Clone, Display, FromRepr, EnumIter, PartialEq, Eq)]
|
#[derive(Default, Debug, Copy, Clone, Display, FromRepr, EnumIter, PartialEq, Eq)]
|
||||||
enum SelectedTab {
|
enum SelectedTab {
|
||||||
#[default]
|
#[default]
|
||||||
Fixed,
|
|
||||||
Min,
|
Min,
|
||||||
Max,
|
Max,
|
||||||
Length,
|
Length,
|
||||||
@ -163,8 +160,8 @@ impl App {
|
|||||||
impl Widget for App {
|
impl Widget for App {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let [tabs, axis, demo] = area.split(&Layout::vertical([
|
let [tabs, axis, demo] = area.split(&Layout::vertical([
|
||||||
Constraint::Fixed(3),
|
Constraint::Length(3),
|
||||||
Constraint::Fixed(3),
|
Constraint::Length(3),
|
||||||
Fill(0),
|
Fill(0),
|
||||||
]));
|
]));
|
||||||
|
|
||||||
@ -268,7 +265,6 @@ impl SelectedTab {
|
|||||||
fn get_example_count(&self) -> u16 {
|
fn get_example_count(&self) -> u16 {
|
||||||
use SelectedTab::*;
|
use SelectedTab::*;
|
||||||
match self {
|
match self {
|
||||||
Fixed => 4,
|
|
||||||
Length => 4,
|
Length => 4,
|
||||||
Percentage => 5,
|
Percentage => 5,
|
||||||
Ratio => 4,
|
Ratio => 4,
|
||||||
@ -282,7 +278,6 @@ impl SelectedTab {
|
|||||||
use SelectedTab::*;
|
use SelectedTab::*;
|
||||||
let text = format!(" {value} ");
|
let text = format!(" {value} ");
|
||||||
let color = match value {
|
let color = match value {
|
||||||
Fixed => FIXED_COLOR,
|
|
||||||
Length => LENGTH_COLOR,
|
Length => LENGTH_COLOR,
|
||||||
Percentage => PERCENTAGE_COLOR,
|
Percentage => PERCENTAGE_COLOR,
|
||||||
Ratio => RATIO_COLOR,
|
Ratio => RATIO_COLOR,
|
||||||
@ -297,7 +292,6 @@ impl SelectedTab {
|
|||||||
impl Widget for SelectedTab {
|
impl Widget for SelectedTab {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
match self {
|
match self {
|
||||||
SelectedTab::Fixed => self.render_fixed_example(area, buf),
|
|
||||||
SelectedTab::Length => self.render_length_example(area, buf),
|
SelectedTab::Length => self.render_length_example(area, buf),
|
||||||
SelectedTab::Percentage => self.render_percentage_example(area, buf),
|
SelectedTab::Percentage => self.render_percentage_example(area, buf),
|
||||||
SelectedTab::Ratio => self.render_ratio_example(area, buf),
|
SelectedTab::Ratio => self.render_ratio_example(area, buf),
|
||||||
@ -309,30 +303,18 @@ impl Widget for SelectedTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl SelectedTab {
|
impl SelectedTab {
|
||||||
fn render_fixed_example(&self, area: Rect, buf: &mut Buffer) {
|
|
||||||
let [example1, example2, example3, example4, _] =
|
|
||||||
area.split(&Layout::vertical([Fixed(EXAMPLE_HEIGHT); 5]));
|
|
||||||
|
|
||||||
Example::new(&[Fixed(40), Fill(0)]).render(example1, buf);
|
|
||||||
Example::new(&[Fixed(20), Fixed(20), Fill(0)]).render(example2, buf);
|
|
||||||
Example::new(&[Fixed(20), Min(20), Max(20)]).render(example3, buf);
|
|
||||||
Example::new(&[Length(20), Percentage(20), Ratio(1, 5), Fill(1), Fixed(15)])
|
|
||||||
.render(example4, buf);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn render_length_example(&self, area: Rect, buf: &mut Buffer) {
|
fn render_length_example(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let [example1, example2, example3, example4, _] =
|
let [example1, example2, example3, _] =
|
||||||
area.split(&Layout::vertical([Fixed(EXAMPLE_HEIGHT); 5]));
|
area.split(&Layout::vertical([Length(EXAMPLE_HEIGHT); 4]));
|
||||||
|
|
||||||
Example::new(&[Length(20), Fixed(20)]).render(example1, buf);
|
Example::new(&[Length(20), Length(20)]).render(example1, buf);
|
||||||
Example::new(&[Length(20), Length(20)]).render(example2, buf);
|
Example::new(&[Length(20), Min(20)]).render(example2, buf);
|
||||||
Example::new(&[Length(20), Min(20)]).render(example3, buf);
|
Example::new(&[Length(20), Max(20)]).render(example3, buf);
|
||||||
Example::new(&[Length(20), Max(20)]).render(example4, buf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn render_percentage_example(&self, area: Rect, buf: &mut Buffer) {
|
fn render_percentage_example(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let [example1, example2, example3, example4, example5, _] =
|
let [example1, example2, example3, example4, example5, _] =
|
||||||
area.split(&Layout::vertical([Fixed(EXAMPLE_HEIGHT); 6]));
|
area.split(&Layout::vertical([Length(EXAMPLE_HEIGHT); 6]));
|
||||||
|
|
||||||
Example::new(&[Percentage(75), Fill(0)]).render(example1, buf);
|
Example::new(&[Percentage(75), Fill(0)]).render(example1, buf);
|
||||||
Example::new(&[Percentage(25), Fill(0)]).render(example2, buf);
|
Example::new(&[Percentage(25), Fill(0)]).render(example2, buf);
|
||||||
@ -343,7 +325,7 @@ impl SelectedTab {
|
|||||||
|
|
||||||
fn render_ratio_example(&self, area: Rect, buf: &mut Buffer) {
|
fn render_ratio_example(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let [example1, example2, example3, example4, _] =
|
let [example1, example2, example3, example4, _] =
|
||||||
area.split(&Layout::vertical([Fixed(EXAMPLE_HEIGHT); 5]));
|
area.split(&Layout::vertical([Length(EXAMPLE_HEIGHT); 5]));
|
||||||
|
|
||||||
Example::new(&[Ratio(1, 2); 2]).render(example1, buf);
|
Example::new(&[Ratio(1, 2); 2]).render(example1, buf);
|
||||||
Example::new(&[Ratio(1, 4); 4]).render(example2, buf);
|
Example::new(&[Ratio(1, 4); 4]).render(example2, buf);
|
||||||
@ -352,7 +334,7 @@ impl SelectedTab {
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn render_fill_example(&self, area: Rect, buf: &mut Buffer) {
|
fn render_fill_example(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let [example1, example2, _] = area.split(&Layout::vertical([Fixed(EXAMPLE_HEIGHT); 3]));
|
let [example1, example2, _] = area.split(&Layout::vertical([Length(EXAMPLE_HEIGHT); 3]));
|
||||||
|
|
||||||
Example::new(&[Fill(1), Fill(2), Fill(3)]).render(example1, buf);
|
Example::new(&[Fill(1), Fill(2), Fill(3)]).render(example1, buf);
|
||||||
Example::new(&[Fill(1), Percentage(50), Fill(1)]).render(example2, buf);
|
Example::new(&[Fill(1), Percentage(50), Fill(1)]).render(example2, buf);
|
||||||
@ -360,7 +342,7 @@ impl SelectedTab {
|
|||||||
|
|
||||||
fn render_min_example(&self, area: Rect, buf: &mut Buffer) {
|
fn render_min_example(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let [example1, example2, example3, example4, example5, _] =
|
let [example1, example2, example3, example4, example5, _] =
|
||||||
area.split(&Layout::vertical([Fixed(EXAMPLE_HEIGHT); 6]));
|
area.split(&Layout::vertical([Length(EXAMPLE_HEIGHT); 6]));
|
||||||
|
|
||||||
Example::new(&[Percentage(100), Min(0)]).render(example1, buf);
|
Example::new(&[Percentage(100), Min(0)]).render(example1, buf);
|
||||||
Example::new(&[Percentage(100), Min(20)]).render(example2, buf);
|
Example::new(&[Percentage(100), Min(20)]).render(example2, buf);
|
||||||
@ -371,7 +353,7 @@ impl SelectedTab {
|
|||||||
|
|
||||||
fn render_max_example(&self, area: Rect, buf: &mut Buffer) {
|
fn render_max_example(&self, area: Rect, buf: &mut Buffer) {
|
||||||
let [example1, example2, example3, example4, example5, _] =
|
let [example1, example2, example3, example4, example5, _] =
|
||||||
area.split(&Layout::vertical([Fixed(EXAMPLE_HEIGHT); 6]));
|
area.split(&Layout::vertical([Length(EXAMPLE_HEIGHT); 6]));
|
||||||
|
|
||||||
Example::new(&[Percentage(0), Max(0)]).render(example1, buf);
|
Example::new(&[Percentage(0), Max(0)]).render(example1, buf);
|
||||||
Example::new(&[Percentage(0), Max(20)]).render(example2, buf);
|
Example::new(&[Percentage(0), Max(20)]).render(example2, buf);
|
||||||
@ -396,8 +378,8 @@ impl Example {
|
|||||||
impl Widget for Example {
|
impl Widget for Example {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let [area, _] = area.split(&Layout::vertical([
|
let [area, _] = area.split(&Layout::vertical([
|
||||||
Fixed(ILLUSTRATION_HEIGHT),
|
Length(ILLUSTRATION_HEIGHT),
|
||||||
Fixed(SPACER_HEIGHT),
|
Length(SPACER_HEIGHT),
|
||||||
]));
|
]));
|
||||||
let blocks = Layout::horizontal(&self.constraints).split(area);
|
let blocks = Layout::horizontal(&self.constraints).split(area);
|
||||||
|
|
||||||
@ -411,7 +393,6 @@ impl Widget for Example {
|
|||||||
impl Example {
|
impl Example {
|
||||||
fn illustration(&self, constraint: Constraint, width: u16) -> Paragraph {
|
fn illustration(&self, constraint: Constraint, width: u16) -> Paragraph {
|
||||||
let color = match constraint {
|
let color = match constraint {
|
||||||
Constraint::Fixed(_) => FIXED_COLOR,
|
|
||||||
Constraint::Length(_) => LENGTH_COLOR,
|
Constraint::Length(_) => LENGTH_COLOR,
|
||||||
Constraint::Percentage(_) => PERCENTAGE_COLOR,
|
Constraint::Percentage(_) => PERCENTAGE_COLOR,
|
||||||
Constraint::Ratio(_, _) => RATIO_COLOR,
|
Constraint::Ratio(_, _) => RATIO_COLOR,
|
||||||
|
@ -32,8 +32,8 @@ use strum::{Display, EnumIter, FromRepr, IntoEnumIterator};
|
|||||||
|
|
||||||
const EXAMPLE_DATA: &[(&str, &[Constraint])] = &[
|
const EXAMPLE_DATA: &[(&str, &[Constraint])] = &[
|
||||||
(
|
(
|
||||||
"Min(u16) takes any excess space when using `Stretch` or `StretchLast`",
|
"Min(u16) takes any excess space always",
|
||||||
&[Fixed(10), Min(10), Max(10), Percentage(10), Ratio(1,10)],
|
&[Length(10), Min(10), Max(10), Percentage(10), Ratio(1,10)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Fill(u16) takes any excess space always",
|
"Fill(u16) takes any excess space always",
|
||||||
@ -41,39 +41,51 @@ const EXAMPLE_DATA: &[(&str, &[Constraint])] = &[
|
|||||||
),
|
),
|
||||||
(
|
(
|
||||||
"Here's all constraints in one line",
|
"Here's all constraints in one line",
|
||||||
&[Fixed(10), Min(10), Max(10), Percentage(10), Ratio(1,10), Fill(1)],
|
&[Length(10), Min(10), Max(10), Percentage(10), Ratio(1,10), Fill(1)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"",
|
"",
|
||||||
&[Percentage(50), Percentage(25), Ratio(1, 8), Min(10)],
|
&[Max(50), Min(50)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"In `StretchLast`, the last constraint of lowest priority takes excess space",
|
"",
|
||||||
&[Length(20), Fixed(20), Percentage(20)],
|
&[Max(20), Length(10)],
|
||||||
),
|
),
|
||||||
("", &[Fixed(20), Percentage(20), Length(20)]),
|
(
|
||||||
|
"",
|
||||||
|
&[Max(20), Length(10)],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"Min grows always but also allows Fill to grow",
|
||||||
|
&[Percentage(50), Fill(1), Fill(2), Min(50)],
|
||||||
|
),
|
||||||
|
(
|
||||||
|
"In `Legacy`, the last constraint of lowest priority takes excess space",
|
||||||
|
&[Length(20), Length(20), Percentage(20)],
|
||||||
|
),
|
||||||
|
("", &[Length(20), Percentage(20), Length(20)]),
|
||||||
("A lowest priority constraint will be broken before a high priority constraint", &[Ratio(1,4), Percentage(20)]),
|
("A lowest priority constraint will be broken before a high priority constraint", &[Ratio(1,4), Percentage(20)]),
|
||||||
("`Length` is higher priority than `Percentage`", &[Percentage(20), Length(10)]),
|
("`Length` is higher priority than `Percentage`", &[Percentage(20), Length(10)]),
|
||||||
("`Min/Max` is higher priority than `Length`", &[Length(10), Max(20)]),
|
("`Min/Max` is higher priority than `Length`", &[Length(10), Max(20)]),
|
||||||
("", &[Length(100), Min(20)]),
|
("", &[Length(100), Min(20)]),
|
||||||
("`Fixed` is higher priority than `Min/Max`", &[Max(20), Fixed(10)]),
|
("`Length` is higher priority than `Min/Max`", &[Max(20), Length(10)]),
|
||||||
("", &[Min(20), Fixed(90)]),
|
("", &[Min(20), Length(90)]),
|
||||||
("Fill is the lowest priority and will fill any excess space", &[Fill(1), Ratio(1, 4)]),
|
("Fill is the lowest priority and will fill any excess space", &[Fill(1), Ratio(1, 4)]),
|
||||||
("Fill can be used to scale proportionally with other Fill blocks", &[Fill(1), Percentage(20), Fill(2)]),
|
("Fill can be used to scale proportionally with other Fill blocks", &[Fill(1), Percentage(20), Fill(2)]),
|
||||||
("", &[Ratio(1, 3), Percentage(20), Ratio(2, 3)]),
|
("", &[Ratio(1, 3), Percentage(20), Ratio(2, 3)]),
|
||||||
("StretchLast will stretch the last lowest priority constraint\nStretch will only stretch equal weighted constraints", &[Length(20), Length(15)]),
|
("Legacy will stretch the last lowest priority constraint\nStretch will only stretch equal weighted constraints", &[Length(20), Length(15)]),
|
||||||
("", &[Percentage(20), Length(15)]),
|
("", &[Percentage(20), Length(15)]),
|
||||||
("`Fill(u16)` fills up excess space, but is lower priority to spacers.\ni.e. Fill will only have widths in Flex::Stretch and Flex::StretchLast", &[Fill(1), Fill(1)]),
|
("`Fill(u16)` fills up excess space, but is lower priority to spacers.\ni.e. Fill will only have widths in Flex::Stretch and Flex::Legacy", &[Fill(1), Fill(1)]),
|
||||||
("", &[Length(20), Fixed(20)]),
|
("", &[Length(20), Length(20)]),
|
||||||
(
|
(
|
||||||
"When not using `Flex::Stretch` or `Flex::StretchLast`,\n`Min(u16)` and `Max(u16)` collapse to their lowest values",
|
"When not using `Flex::Stretch` or `Flex::Legacy`,\n`Min(u16)` and `Max(u16)` collapse to their lowest values",
|
||||||
&[Min(20), Max(20)],
|
&[Min(20), Max(20)],
|
||||||
),
|
),
|
||||||
(
|
(
|
||||||
"",
|
"",
|
||||||
&[Max(20)],
|
&[Max(20)],
|
||||||
),
|
),
|
||||||
("", &[Min(20), Max(20), Length(20), Fixed(20)]),
|
("", &[Min(20), Max(20), Length(20), Length(20)]),
|
||||||
("", &[Fill(0), Fill(0)]),
|
("", &[Fill(0), Fill(0)]),
|
||||||
(
|
(
|
||||||
"`Fill(1)` can be to scale with respect to other `Fill(2)`",
|
"`Fill(1)` can be to scale with respect to other `Fill(2)`",
|
||||||
@ -124,8 +136,7 @@ struct Example {
|
|||||||
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, FromRepr, Display, EnumIter)]
|
#[derive(Default, Debug, Copy, Clone, PartialEq, Eq, FromRepr, Display, EnumIter)]
|
||||||
enum SelectedTab {
|
enum SelectedTab {
|
||||||
#[default]
|
#[default]
|
||||||
StretchLast,
|
Legacy,
|
||||||
Stretch,
|
|
||||||
Start,
|
Start,
|
||||||
Center,
|
Center,
|
||||||
End,
|
End,
|
||||||
@ -244,7 +255,7 @@ fn example_height() -> u16 {
|
|||||||
|
|
||||||
impl Widget for App {
|
impl Widget for App {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let layout = Layout::vertical([Fixed(3), Fixed(1), Fill(0)]);
|
let layout = Layout::vertical([Length(3), Length(1), Fill(0)]);
|
||||||
let [tabs, axis, demo] = area.split(&layout);
|
let [tabs, axis, demo] = area.split(&layout);
|
||||||
self.tabs().render(tabs, buf);
|
self.tabs().render(tabs, buf);
|
||||||
let scroll_needed = self.render_demo(demo, buf);
|
let scroll_needed = self.render_demo(demo, buf);
|
||||||
@ -363,8 +374,7 @@ impl SelectedTab {
|
|||||||
use SelectedTab::*;
|
use SelectedTab::*;
|
||||||
let text = value.to_string();
|
let text = value.to_string();
|
||||||
let color = match value {
|
let color = match value {
|
||||||
StretchLast => ORANGE.c400,
|
Legacy => ORANGE.c400,
|
||||||
Stretch => ORANGE.c300,
|
|
||||||
Start => SKY.c400,
|
Start => SKY.c400,
|
||||||
Center => SKY.c300,
|
Center => SKY.c300,
|
||||||
End => SKY.c200,
|
End => SKY.c200,
|
||||||
@ -380,8 +390,7 @@ impl StatefulWidget for SelectedTab {
|
|||||||
fn render(self, area: Rect, buf: &mut Buffer, spacing: &mut Self::State) {
|
fn render(self, area: Rect, buf: &mut Buffer, spacing: &mut Self::State) {
|
||||||
let spacing = *spacing;
|
let spacing = *spacing;
|
||||||
match self {
|
match self {
|
||||||
SelectedTab::StretchLast => self.render_examples(area, buf, Flex::StretchLast, spacing),
|
SelectedTab::Legacy => self.render_examples(area, buf, Flex::Legacy, spacing),
|
||||||
SelectedTab::Stretch => self.render_examples(area, buf, Flex::Stretch, spacing),
|
|
||||||
SelectedTab::Start => self.render_examples(area, buf, Flex::Start, spacing),
|
SelectedTab::Start => self.render_examples(area, buf, Flex::Start, spacing),
|
||||||
SelectedTab::Center => self.render_examples(area, buf, Flex::Center, spacing),
|
SelectedTab::Center => self.render_examples(area, buf, Flex::Center, spacing),
|
||||||
SelectedTab::End => self.render_examples(area, buf, Flex::End, spacing),
|
SelectedTab::End => self.render_examples(area, buf, Flex::End, spacing),
|
||||||
@ -419,7 +428,7 @@ impl Example {
|
|||||||
impl Widget for Example {
|
impl Widget for Example {
|
||||||
fn render(self, area: Rect, buf: &mut Buffer) {
|
fn render(self, area: Rect, buf: &mut Buffer) {
|
||||||
let title_height = get_description_height(&self.description);
|
let title_height = get_description_height(&self.description);
|
||||||
let layout = Layout::vertical([Fixed(title_height), Fill(0)]);
|
let layout = Layout::vertical([Length(title_height), Fill(0)]);
|
||||||
let [title, illustrations] = area.split(&layout);
|
let [title, illustrations] = area.split(&layout);
|
||||||
|
|
||||||
let (blocks, spacers) = Layout::horizontal(&self.constraints)
|
let (blocks, spacers) = Layout::horizontal(&self.constraints)
|
||||||
@ -512,7 +521,6 @@ impl Example {
|
|||||||
fn color_for_constraint(constraint: Constraint) -> Color {
|
fn color_for_constraint(constraint: Constraint) -> Color {
|
||||||
use tailwind::*;
|
use tailwind::*;
|
||||||
match constraint {
|
match constraint {
|
||||||
Constraint::Fixed(_) => RED.c900,
|
|
||||||
Constraint::Min(_) => BLUE.c900,
|
Constraint::Min(_) => BLUE.c900,
|
||||||
Constraint::Max(_) => BLUE.c800,
|
Constraint::Max(_) => BLUE.c800,
|
||||||
Constraint::Length(_) => SLATE.c700,
|
Constraint::Length(_) => SLATE.c700,
|
||||||
|
@ -218,7 +218,6 @@ fn constraint_label(constraint: Constraint) -> String {
|
|||||||
Max(n) => format!("{n}"),
|
Max(n) => format!("{n}"),
|
||||||
Percentage(n) => format!("{n}"),
|
Percentage(n) => format!("{n}"),
|
||||||
Fill(n) => format!("{n}"),
|
Fill(n) => format!("{n}"),
|
||||||
Fixed(n) => format!("{n}"),
|
|
||||||
Ratio(a, b) => format!("{a}:{b}"),
|
Ratio(a, b) => format!("{a}:{b}"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,6 @@ mod layout;
|
|||||||
mod margin;
|
mod margin;
|
||||||
mod position;
|
mod position;
|
||||||
mod rect;
|
mod rect;
|
||||||
mod segment_size;
|
|
||||||
mod size;
|
mod size;
|
||||||
|
|
||||||
pub use alignment::Alignment;
|
pub use alignment::Alignment;
|
||||||
@ -20,8 +19,4 @@ pub use layout::Layout;
|
|||||||
pub use margin::Margin;
|
pub use margin::Margin;
|
||||||
pub use position::Position;
|
pub use position::Position;
|
||||||
pub use rect::*;
|
pub use rect::*;
|
||||||
#[cfg(feature = "unstable-segment-size")]
|
|
||||||
pub use segment_size::SegmentSize;
|
|
||||||
#[cfg(not(feature = "unstable-segment-size"))]
|
|
||||||
pub(crate) use segment_size::SegmentSize;
|
|
||||||
pub use size::Size;
|
pub use size::Size;
|
||||||
|
@ -15,13 +15,12 @@ use strum::EnumIs;
|
|||||||
///
|
///
|
||||||
/// Constraints are prioritized in the following order:
|
/// Constraints are prioritized in the following order:
|
||||||
///
|
///
|
||||||
/// 1. [`Constraint::Fixed`]
|
/// 1. [`Constraint::Min`]
|
||||||
/// 2. [`Constraint::Min`]
|
/// 2. [`Constraint::Max`]
|
||||||
/// 3. [`Constraint::Max`]
|
/// 3. [`Constraint::Length`]
|
||||||
/// 4. [`Constraint::Length`]
|
/// 4. [`Constraint::Percentage`]
|
||||||
/// 5. [`Constraint::Percentage`]
|
/// 5. [`Constraint::Ratio`]
|
||||||
/// 6. [`Constraint::Ratio`]
|
/// 6. [`Constraint::Fill`]
|
||||||
/// 7. [`Constraint::Fill`]
|
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
@ -32,9 +31,6 @@ use strum::EnumIs;
|
|||||||
/// // Create a layout with specified lengths for each element
|
/// // Create a layout with specified lengths for each element
|
||||||
/// let constraints = Constraint::from_lengths([10, 20, 10]);
|
/// let constraints = Constraint::from_lengths([10, 20, 10]);
|
||||||
///
|
///
|
||||||
/// // Create a layout with specified fixed lengths for each element
|
|
||||||
/// let constraints = Constraint::from_fixed_lengths([10, 20, 10]);
|
|
||||||
///
|
|
||||||
/// // Create a centered layout using ratio or percentage constraints
|
/// // Create a centered layout using ratio or percentage constraints
|
||||||
/// let constraints = Constraint::from_ratios([(1, 4), (1, 2), (1, 4)]);
|
/// let constraints = Constraint::from_ratios([(1, 4), (1, 2), (1, 4)]);
|
||||||
/// let constraints = Constraint::from_percentages([25, 50, 25]);
|
/// let constraints = Constraint::from_percentages([25, 50, 25]);
|
||||||
@ -50,29 +46,6 @@ use strum::EnumIs;
|
|||||||
/// ```
|
/// ```
|
||||||
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, EnumIs)]
|
#[derive(Debug, Clone, Copy, Eq, PartialEq, Hash, EnumIs)]
|
||||||
pub enum Constraint {
|
pub enum Constraint {
|
||||||
/// Applies a fixed size to the element
|
|
||||||
///
|
|
||||||
/// The element size is set to the specified amount.
|
|
||||||
/// [`Constraint::Fixed`] will take precedence over all other constraints.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// `[Fixed(40), Fill(1)]`
|
|
||||||
///
|
|
||||||
/// ```plain
|
|
||||||
/// ┌──────────────────────────────────────┐┌────────┐
|
|
||||||
/// │ 40 px ││ 10 px │
|
|
||||||
/// └──────────────────────────────────────┘└────────┘
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// `[Fixed(20), Fixed(20), Fill(1)]`
|
|
||||||
///
|
|
||||||
/// ```plain
|
|
||||||
/// ┌──────────────────┐┌──────────────────┐┌────────┐
|
|
||||||
/// │ 20 px ││ 20 px ││ 10 px │
|
|
||||||
/// └──────────────────┘└──────────────────┘└────────┘
|
|
||||||
/// ```
|
|
||||||
Fixed(u16),
|
|
||||||
/// Applies a minimum size constraint to the element
|
/// Applies a minimum size constraint to the element
|
||||||
///
|
///
|
||||||
/// The element size is set to at least the specified amount.
|
/// The element size is set to at least the specified amount.
|
||||||
@ -95,6 +68,7 @@ pub enum Constraint {
|
|||||||
/// └──────────────────────────────────────┘└────────┘
|
/// └──────────────────────────────────────┘└────────┘
|
||||||
/// ```
|
/// ```
|
||||||
Min(u16),
|
Min(u16),
|
||||||
|
|
||||||
/// Applies a maximum size constraint to the element
|
/// Applies a maximum size constraint to the element
|
||||||
///
|
///
|
||||||
/// The element size is set to at most the specified amount.
|
/// The element size is set to at most the specified amount.
|
||||||
@ -117,21 +91,22 @@ pub enum Constraint {
|
|||||||
/// └──────────────────────────────────────┘└────────┘
|
/// └──────────────────────────────────────┘└────────┘
|
||||||
/// ```
|
/// ```
|
||||||
Max(u16),
|
Max(u16),
|
||||||
|
|
||||||
/// Applies a length constraint to the element
|
/// Applies a length constraint to the element
|
||||||
///
|
///
|
||||||
/// The element size is set to the specified amount.
|
/// The element size is set to the specified amount.
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
///
|
///
|
||||||
/// `[Length(20), Fixed(20)]`
|
/// `[Length(20), Length(20)]`
|
||||||
///
|
///
|
||||||
/// ```plain
|
/// ```plain
|
||||||
/// ┌────────────────────────────┐┌──────────────────┐
|
/// ┌──────────────────┐┌──────────────────┐
|
||||||
/// │ 30 px ││ 20 px │
|
/// │ 20 px ││ 20 px │
|
||||||
/// └────────────────────────────┘└──────────────────┘
|
/// └──────────────────┘└──────────────────┘
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// `[Length(20), Length(20)]`
|
/// `[Length(20), Length(30)]`
|
||||||
///
|
///
|
||||||
/// ```plain
|
/// ```plain
|
||||||
/// ┌──────────────────┐┌────────────────────────────┐
|
/// ┌──────────────────┐┌────────────────────────────┐
|
||||||
@ -139,6 +114,7 @@ pub enum Constraint {
|
|||||||
/// └──────────────────┘└────────────────────────────┘
|
/// └──────────────────┘└────────────────────────────┘
|
||||||
/// ```
|
/// ```
|
||||||
Length(u16),
|
Length(u16),
|
||||||
|
|
||||||
/// Applies a percentage of the available space to the element
|
/// Applies a percentage of the available space to the element
|
||||||
///
|
///
|
||||||
/// Converts the given percentage to a floating-point value and multiplies that with area.
|
/// Converts the given percentage to a floating-point value and multiplies that with area.
|
||||||
@ -162,6 +138,7 @@ pub enum Constraint {
|
|||||||
/// └───────────────────────┘└───────────────────────┘
|
/// └───────────────────────┘└───────────────────────┘
|
||||||
/// ```
|
/// ```
|
||||||
Percentage(u16),
|
Percentage(u16),
|
||||||
|
|
||||||
/// Applies a ratio of the available space to the element
|
/// Applies a ratio of the available space to the element
|
||||||
///
|
///
|
||||||
/// Converts the given ratio to a floating-point value and multiplies that with area.
|
/// Converts the given ratio to a floating-point value and multiplies that with area.
|
||||||
@ -185,6 +162,7 @@ pub enum Constraint {
|
|||||||
/// └───────────┘└──────────┘└───────────┘└──────────┘
|
/// └───────────┘└──────────┘└───────────┘└──────────┘
|
||||||
/// ```
|
/// ```
|
||||||
Ratio(u32, u32),
|
Ratio(u32, u32),
|
||||||
|
|
||||||
/// Applies the scaling factor proportional to all other [`Constraint::Fill`] elements
|
/// Applies the scaling factor proportional to all other [`Constraint::Fill`] elements
|
||||||
/// to fill excess space
|
/// to fill excess space
|
||||||
///
|
///
|
||||||
@ -232,7 +210,6 @@ impl Constraint {
|
|||||||
(percentage * length).min(length) as u16
|
(percentage * length).min(length) as u16
|
||||||
}
|
}
|
||||||
Constraint::Length(l) => length.min(l),
|
Constraint::Length(l) => length.min(l),
|
||||||
Constraint::Fixed(l) => length.min(l),
|
|
||||||
Constraint::Fill(l) => length.min(l),
|
Constraint::Fill(l) => length.min(l),
|
||||||
Constraint::Max(m) => length.min(m),
|
Constraint::Max(m) => length.min(m),
|
||||||
Constraint::Min(m) => length.max(m),
|
Constraint::Min(m) => length.max(m),
|
||||||
@ -256,26 +233,6 @@ impl Constraint {
|
|||||||
lengths.into_iter().map(Constraint::Length).collect_vec()
|
lengths.into_iter().map(Constraint::Length).collect_vec()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert an iterator of fixed lengths into a vector of constraints
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```rust
|
|
||||||
/// # use ratatui::prelude::*;
|
|
||||||
/// # let area = Rect::default();
|
|
||||||
/// let constraints = Constraint::from_fixed_lengths([1, 2, 3]);
|
|
||||||
/// let layout = Layout::default().constraints(constraints).split(area);
|
|
||||||
/// ```
|
|
||||||
pub fn from_fixed_lengths<T>(fixed_lengths: T) -> Vec<Constraint>
|
|
||||||
where
|
|
||||||
T: IntoIterator<Item = u16>,
|
|
||||||
{
|
|
||||||
fixed_lengths
|
|
||||||
.into_iter()
|
|
||||||
.map(Constraint::Fixed)
|
|
||||||
.collect_vec()
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Convert an iterator of ratios into a vector of constraints
|
/// Convert an iterator of ratios into a vector of constraints
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -415,7 +372,6 @@ impl Display for Constraint {
|
|||||||
Constraint::Percentage(p) => write!(f, "Percentage({})", p),
|
Constraint::Percentage(p) => write!(f, "Percentage({})", p),
|
||||||
Constraint::Ratio(n, d) => write!(f, "Ratio({}, {})", n, d),
|
Constraint::Ratio(n, d) => write!(f, "Ratio({}, {})", n, d),
|
||||||
Constraint::Length(l) => write!(f, "Length({})", l),
|
Constraint::Length(l) => write!(f, "Length({})", l),
|
||||||
Constraint::Fixed(l) => write!(f, "Fixed({})", l),
|
|
||||||
Constraint::Fill(l) => write!(f, "Fill({})", l),
|
Constraint::Fill(l) => write!(f, "Fill({})", l),
|
||||||
Constraint::Max(m) => write!(f, "Max({})", m),
|
Constraint::Max(m) => write!(f, "Max({})", m),
|
||||||
Constraint::Min(m) => write!(f, "Min({})", m),
|
Constraint::Min(m) => write!(f, "Min({})", m),
|
||||||
@ -452,17 +408,6 @@ mod tests {
|
|||||||
assert_eq!(Constraint::from_lengths(vec![1, 2, 3]), expected);
|
assert_eq!(Constraint::from_lengths(vec![1, 2, 3]), expected);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn from_fixed_lengths() {
|
|
||||||
let expected = [
|
|
||||||
Constraint::Fixed(1),
|
|
||||||
Constraint::Fixed(2),
|
|
||||||
Constraint::Fixed(3),
|
|
||||||
];
|
|
||||||
assert_eq!(Constraint::from_fixed_lengths([1, 2, 3]), expected);
|
|
||||||
assert_eq!(Constraint::from_fixed_lengths(vec![1, 2, 3]), expected);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn from_ratios() {
|
fn from_ratios() {
|
||||||
let expected = [
|
let expected = [
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
use strum::{Display, EnumString};
|
use strum::{Display, EnumIs, EnumString};
|
||||||
|
|
||||||
#[allow(unused_imports)]
|
#[allow(unused_imports)]
|
||||||
use super::constraint::Constraint;
|
use super::constraint::Constraint;
|
||||||
@ -7,15 +7,14 @@ use super::constraint::Constraint;
|
|||||||
///
|
///
|
||||||
/// This enumeration controls the distribution of space when layout constraints are met.
|
/// This enumeration controls the distribution of space when layout constraints are met.
|
||||||
///
|
///
|
||||||
/// - `StretchLast`: Fills the available space within the container, putting excess space into the
|
/// - `Legacy`: Fills the available space within the container, putting excess space into the last
|
||||||
/// last element.
|
/// element.
|
||||||
/// - `Stretch`: Always fills the available space within the container.
|
|
||||||
/// - `Start`: Aligns items to the start of the container.
|
/// - `Start`: Aligns items to the start of the container.
|
||||||
/// - `End`: Aligns items to the end of the container.
|
/// - `End`: Aligns items to the end of the container.
|
||||||
/// - `Center`: Centers items within the container.
|
/// - `Center`: Centers items within the container.
|
||||||
/// - `SpaceBetween`: Adds excess space between each element.
|
/// - `SpaceBetween`: Adds excess space between each element.
|
||||||
/// - `SpaceAround`: Adds excess space around each element.
|
/// - `SpaceAround`: Adds excess space around each element.
|
||||||
#[derive(Copy, Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash)]
|
#[derive(Copy, Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash, EnumIs)]
|
||||||
pub enum Flex {
|
pub enum Flex {
|
||||||
/// Fills the available space within the container, putting excess space into the last
|
/// Fills the available space within the container, putting excess space into the last
|
||||||
/// constraint of the lowest priority. This matches the default behavior of ratatui and tui
|
/// constraint of the lowest priority. This matches the default behavior of ratatui and tui
|
||||||
@ -24,13 +23,12 @@ pub enum Flex {
|
|||||||
/// The following examples illustrate the allocation of excess in various combinations of
|
/// The following examples illustrate the allocation of excess in various combinations of
|
||||||
/// constraints. As a refresher, the priorities of constraints are as follows:
|
/// constraints. As a refresher, the priorities of constraints are as follows:
|
||||||
///
|
///
|
||||||
/// 1. [`Constraint::Fixed`]
|
/// 1. [`Constraint::Min`]
|
||||||
/// 2. [`Constraint::Min`]
|
/// 2. [`Constraint::Max`]
|
||||||
/// 3. [`Constraint::Max`]
|
/// 3. [`Constraint::Length`]
|
||||||
/// 4. [`Constraint::Length`]
|
/// 4. [`Constraint::Percentage`]
|
||||||
/// 5. [`Constraint::Percentage`]
|
/// 5. [`Constraint::Ratio`]
|
||||||
/// 6. [`Constraint::Ratio`]
|
/// 6. [`Constraint::Fill`]
|
||||||
/// 7. [`Constraint::Fill`]
|
|
||||||
///
|
///
|
||||||
/// When every constraint is `Length`, the last element gets the excess.
|
/// When every constraint is `Length`, the last element gets the excess.
|
||||||
///
|
///
|
||||||
@ -42,55 +40,13 @@ pub enum Flex {
|
|||||||
/// ^^^^^^^^^^^^^^^^ EXCESS ^^^^^^^^^^^^^^^^
|
/// ^^^^^^^^^^^^^^^^ EXCESS ^^^^^^^^^^^^^^^^
|
||||||
/// ```
|
/// ```
|
||||||
///
|
///
|
||||||
/// If we replace the constraint at the end with a `Fixed`, because it has a
|
|
||||||
/// higher priority, the last constraint with the lowest priority, i.e. the last
|
|
||||||
/// `Length` gets the excess.
|
|
||||||
///
|
|
||||||
/// ```plain
|
|
||||||
/// <----------------------------------- 80 px ------------------------------------>
|
|
||||||
/// ┌──────20 px───────┐┌────────────────40 px─────────────────┐┌──────20 px───────┐
|
|
||||||
/// │ Length(20) ││ Length(20) ││ Fixed(20) │
|
|
||||||
/// └──────────────────┘└──────────────────────────────────────┘└──────────────────┘
|
|
||||||
/// ^^^^^^^^^^^^^^^^ EXCESS ^^^^^^^^^^^^^^^^
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Violating a `Max` is lower priority than `Fixed` but higher
|
|
||||||
/// than `Length`.
|
|
||||||
///
|
|
||||||
/// ```plain
|
|
||||||
/// <----------------------------------- 80 px ------------------------------------>
|
|
||||||
/// ┌────────────────40 px─────────────────┐┌──────20 px───────┐┌──────20 px───────┐
|
|
||||||
/// │ Length(20) ││ Max(20) ││ Fixed(20) │
|
|
||||||
/// └──────────────────────────────────────┘└──────────────────┘└──────────────────┘
|
|
||||||
/// ^^^^^^^^^^^^^^^^ EXCESS ^^^^^^^^^^^^^^^^
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// It's important to note that while not violating a `Min` or `Max` constraint is
|
|
||||||
/// prioritized higher than a `Length`, `Min` and `Max` constraints allow for a range
|
|
||||||
/// of values and excess can (and will) be dumped into these ranges first, if possible,
|
|
||||||
/// even if it not the last constraint.
|
|
||||||
///
|
|
||||||
/// ```plain
|
|
||||||
/// <----------------------------------- 80 px ------------------------------------>
|
|
||||||
/// ┌──────20 px───────┐┌────────────────40 px─────────────────┐┌──────20 px───────┐
|
|
||||||
/// │ Length(20) ││ Min(20) ││ Fixed(20) │
|
|
||||||
/// └──────────────────┘└──────────────────────────────────────┘└──────────────────┘
|
|
||||||
/// ^^^^^^^^^^^^^^^^ EXCESS ^^^^^^^^^^^^^^^^
|
|
||||||
///
|
|
||||||
/// <----------------------------------- 80 px ------------------------------------>
|
|
||||||
/// ┌────────────────40 px─────────────────┐┌──────20 px───────┐┌──────20 px───────┐
|
|
||||||
/// │ Min(20) ││ Length(20) ││ Fixed(20) │
|
|
||||||
/// └──────────────────────────────────────┘└──────────────────┘└──────────────────┘
|
|
||||||
/// ^^^^^^^^^^^^^^^^ EXCESS ^^^^^^^^^^^^^^^^
|
|
||||||
/// ```
|
|
||||||
///
|
|
||||||
/// Fill constraints have the lowest priority amongst all the constraints and hence
|
/// Fill constraints have the lowest priority amongst all the constraints and hence
|
||||||
/// will always take up any excess space available.
|
/// will always take up any excess space available.
|
||||||
///
|
///
|
||||||
/// ```plain
|
/// ```plain
|
||||||
/// <----------------------------------- 80 px ------------------------------------>
|
/// <----------------------------------- 80 px ------------------------------------>
|
||||||
/// ┌──────20 px───────┐┌──────20 px───────┐┌──────20 px───────┐┌──────20 px───────┐
|
/// ┌──────20 px───────┐┌──────20 px───────┐┌──────20 px───────┐┌──────20 px───────┐
|
||||||
/// │ Fill(0) ││ Min(20) ││ Length(20) ││ Fixed(20) │
|
/// │ Fill(0) ││ Max(20) ││ Length(20) ││ Length(20) │
|
||||||
/// └──────────────────┘└──────────────────┘└──────────────────┘└──────────────────┘
|
/// └──────────────────┘└──────────────────┘└──────────────────┘└──────────────────┘
|
||||||
/// ^^^^^^ EXCESS ^^^^^^
|
/// ^^^^^^ EXCESS ^^^^^^
|
||||||
/// ```
|
/// ```
|
||||||
@ -99,11 +55,6 @@ pub enum Flex {
|
|||||||
///
|
///
|
||||||
/// ```plain
|
/// ```plain
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌───────────30 px────────────┐┌───────────30 px────────────┐┌──────20 px───────┐
|
|
||||||
/// │ Percentage(20) ││ Length(20) ││ Fixed(20) │
|
|
||||||
/// └────────────────────────────┘└────────────────────────────┘└──────────────────┘
|
|
||||||
///
|
|
||||||
/// <------------------------------------80 px------------------------------------->
|
|
||||||
/// ┌──────────────────────────60 px───────────────────────────┐┌──────20 px───────┐
|
/// ┌──────────────────────────60 px───────────────────────────┐┌──────20 px───────┐
|
||||||
/// │ Min(20) ││ Max(20) │
|
/// │ Min(20) ││ Max(20) │
|
||||||
/// └──────────────────────────────────────────────────────────┘└──────────────────┘
|
/// └──────────────────────────────────────────────────────────┘└──────────────────┘
|
||||||
@ -113,30 +64,7 @@ pub enum Flex {
|
|||||||
/// │ Max(20) │
|
/// │ Max(20) │
|
||||||
/// └──────────────────────────────────────────────────────────────────────────────┘
|
/// └──────────────────────────────────────────────────────────────────────────────┘
|
||||||
/// ```
|
/// ```
|
||||||
#[default]
|
Legacy,
|
||||||
StretchLast,
|
|
||||||
|
|
||||||
/// Always fills the available space within the container.
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// ```plain
|
|
||||||
/// <------------------------------------80 px------------------------------------->
|
|
||||||
/// ┌────16 px─────┐┌──────────────────44 px───────────────────┐┌──────20 px───────┐
|
|
||||||
/// │Percentage(20)││ Length(20) ││ Fixed(20) │
|
|
||||||
/// └──────────────┘└──────────────────────────────────────────┘└──────────────────┘
|
|
||||||
///
|
|
||||||
/// <------------------------------------80 px------------------------------------->
|
|
||||||
/// ┌──────────────────────────60 px───────────────────────────┐┌──────20 px───────┐
|
|
||||||
/// │ Min(20) ││ Max(20) │
|
|
||||||
/// └──────────────────────────────────────────────────────────┘└──────────────────┘
|
|
||||||
///
|
|
||||||
/// <------------------------------------80 px------------------------------------->
|
|
||||||
/// ┌────────────────────────────────────80 px─────────────────────────────────────┐
|
|
||||||
/// │ Max(20) │
|
|
||||||
/// └──────────────────────────────────────────────────────────────────────────────┘
|
|
||||||
/// ```
|
|
||||||
Stretch,
|
|
||||||
|
|
||||||
/// Aligns items to the start of the container.
|
/// Aligns items to the start of the container.
|
||||||
///
|
///
|
||||||
@ -150,7 +78,7 @@ pub enum Flex {
|
|||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌──────20 px───────┐┌──────20 px───────┐
|
/// ┌──────20 px───────┐┌──────20 px───────┐
|
||||||
/// │ Min(20) ││ Max(20) │
|
/// │ Max(20) ││ Max(20) │
|
||||||
/// └──────────────────┘└──────────────────┘
|
/// └──────────────────┘└──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
@ -158,6 +86,7 @@ pub enum Flex {
|
|||||||
/// │ Max(20) │
|
/// │ Max(20) │
|
||||||
/// └──────────────────┘
|
/// └──────────────────┘
|
||||||
/// ```
|
/// ```
|
||||||
|
#[default]
|
||||||
Start,
|
Start,
|
||||||
|
|
||||||
/// Aligns items to the end of the container.
|
/// Aligns items to the end of the container.
|
||||||
@ -167,12 +96,12 @@ pub enum Flex {
|
|||||||
/// ```plain
|
/// ```plain
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌────16 px─────┐┌──────20 px───────┐┌──────20 px───────┐
|
/// ┌────16 px─────┐┌──────20 px───────┐┌──────20 px───────┐
|
||||||
/// │Percentage(20)││ Length(20) ││ Fixed(20) │
|
/// │Percentage(20)││ Length(20) ││ Length(20) │
|
||||||
/// └──────────────┘└──────────────────┘└──────────────────┘
|
/// └──────────────┘└──────────────────┘└──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌──────20 px───────┐┌──────20 px───────┐
|
/// ┌──────20 px───────┐┌──────20 px───────┐
|
||||||
/// │ Min(20) ││ Max(20) │
|
/// │ Max(20) ││ Max(20) │
|
||||||
/// └──────────────────┘└──────────────────┘
|
/// └──────────────────┘└──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
@ -189,12 +118,12 @@ pub enum Flex {
|
|||||||
/// ```plain
|
/// ```plain
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌────16 px─────┐┌──────20 px───────┐┌──────20 px───────┐
|
/// ┌────16 px─────┐┌──────20 px───────┐┌──────20 px───────┐
|
||||||
/// │Percentage(20)││ Length(20) ││ Fixed(20) │
|
/// │Percentage(20)││ Length(20) ││ Length(20) │
|
||||||
/// └──────────────┘└──────────────────┘└──────────────────┘
|
/// └──────────────┘└──────────────────┘└──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌──────20 px───────┐┌──────20 px───────┐
|
/// ┌──────20 px───────┐┌──────20 px───────┐
|
||||||
/// │ Min(20) ││ Max(20) │
|
/// │ Max(20) ││ Max(20) │
|
||||||
/// └──────────────────┘└──────────────────┘
|
/// └──────────────────┘└──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
@ -211,12 +140,12 @@ pub enum Flex {
|
|||||||
/// ```plain
|
/// ```plain
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌────16 px─────┐ ┌──────20 px───────┐ ┌──────20 px───────┐
|
/// ┌────16 px─────┐ ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||||
/// │Percentage(20)│ │ Length(20) │ │ Fixed(20) │
|
/// │Percentage(20)│ │ Length(20) │ │ Length(20) │
|
||||||
/// └──────────────┘ └──────────────────┘ └──────────────────┘
|
/// └──────────────┘ └──────────────────┘ └──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌──────20 px───────┐ ┌──────20 px───────┐
|
/// ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||||
/// │ Min(20) │ │ Max(20) │
|
/// │ Max(20) │ │ Max(20) │
|
||||||
/// └──────────────────┘ └──────────────────┘
|
/// └──────────────────┘ └──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
@ -233,12 +162,12 @@ pub enum Flex {
|
|||||||
/// ```plain
|
/// ```plain
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌────16 px─────┐ ┌──────20 px───────┐ ┌──────20 px───────┐
|
/// ┌────16 px─────┐ ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||||
/// │Percentage(20)│ │ Length(20) │ │ Fixed(20) │
|
/// │Percentage(20)│ │ Length(20) │ │ Length(20) │
|
||||||
/// └──────────────┘ └──────────────────┘ └──────────────────┘
|
/// └──────────────┘ └──────────────────┘ └──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
/// ┌──────20 px───────┐ ┌──────20 px───────┐
|
/// ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||||
/// │ Min(20) │ │ Max(20) │
|
/// │ Max(20) │ │ Max(20) │
|
||||||
/// └──────────────────┘ └──────────────────┘
|
/// └──────────────────┘ └──────────────────┘
|
||||||
///
|
///
|
||||||
/// <------------------------------------80 px------------------------------------->
|
/// <------------------------------------80 px------------------------------------->
|
||||||
|
@ -1,7 +1,7 @@
|
|||||||
use std::{cell::RefCell, collections::HashMap, iter, num::NonZeroUsize, rc::Rc, sync::OnceLock};
|
use std::{cell::RefCell, collections::HashMap, iter, num::NonZeroUsize, rc::Rc, sync::OnceLock};
|
||||||
|
|
||||||
use cassowary::{
|
use cassowary::{
|
||||||
strength::REQUIRED,
|
strength::{REQUIRED, WEAK},
|
||||||
AddConstraintError, Expression, Solver, Variable,
|
AddConstraintError, Expression, Solver, Variable,
|
||||||
WeightedRelation::{EQ, GE, LE},
|
WeightedRelation::{EQ, GE, LE},
|
||||||
};
|
};
|
||||||
@ -9,10 +9,10 @@ use itertools::Itertools;
|
|||||||
use lru::LruCache;
|
use lru::LruCache;
|
||||||
|
|
||||||
use self::strengths::{
|
use self::strengths::{
|
||||||
FILL_GROW, FIXED_SIZE_EQ, LENGTH_SIZE_EQ, MAX_SIZE_EQ, MAX_SIZE_LE, MIN_SIZE_EQ, MIN_SIZE_GE,
|
FILL_GROW, LENGTH_SIZE_EQ, MAX_SIZE_EQ, MAX_SIZE_LE, MIN_SIZE_EQ, MIN_SIZE_GE,
|
||||||
PERCENTAGE_SIZE_EQ, RATIO_SIZE_EQ, *,
|
PERCENTAGE_SIZE_EQ, RATIO_SIZE_EQ, *,
|
||||||
};
|
};
|
||||||
use super::{Flex, SegmentSize};
|
use super::Flex;
|
||||||
use crate::prelude::*;
|
use crate::prelude::*;
|
||||||
|
|
||||||
type Rects = Rc<[Rect]>;
|
type Rects = Rc<[Rect]>;
|
||||||
@ -40,25 +40,21 @@ thread_local! {
|
|||||||
///
|
///
|
||||||
/// A layout is composed of:
|
/// A layout is composed of:
|
||||||
/// - a direction (horizontal or vertical)
|
/// - a direction (horizontal or vertical)
|
||||||
/// - a set of constraints (length, ratio, percentage, min, max)
|
/// - a set of constraints (length, ratio, percentage, fill, min, max)
|
||||||
/// - a margin (horizontal and vertical), the space between the edge of the main area and the split
|
/// - a margin (horizontal and vertical), the space between the edge of the main area and the split
|
||||||
/// areas
|
/// areas
|
||||||
/// - extra options for segment size preferences
|
/// - a flex option
|
||||||
|
/// - a spacing option
|
||||||
///
|
///
|
||||||
/// The algorithm used to compute the layout is based on the [`cassowary-rs`] solver. It is a simple
|
/// The algorithm used to compute the layout is based on the [`cassowary-rs`] solver. It is a simple
|
||||||
/// linear solver that can be used to solve linear equations and inequalities. In our case, we
|
/// linear solver that can be used to solve linear equations and inequalities. In our case, we
|
||||||
/// define a set of constraints that are applied to split the provided area into Rects aligned in a
|
/// define a set of constraints that are applied to split the provided area into Rects aligned in a
|
||||||
/// single direction, and the solver computes the values of the position and sizes that satisfy as
|
/// single direction, and the solver computes the values of the position and sizes that satisfy as
|
||||||
/// many of the constraints as possible.
|
/// many of the constraints in order of their priorities.
|
||||||
///
|
|
||||||
/// By default, the last chunk of the computed layout is expanded to fill the remaining space. To
|
|
||||||
/// avoid this behavior, add an unused `Constraint::Min(0)` as the last constraint. There is also an
|
|
||||||
/// unstable API to prefer equal chunks if other constraints are all satisfied, see [`SegmentSize`]
|
|
||||||
/// for more info.
|
|
||||||
///
|
///
|
||||||
/// When the layout is computed, the result is cached in a thread-local cache, so that subsequent
|
/// When the layout is computed, the result is cached in a thread-local cache, so that subsequent
|
||||||
/// calls with the same parameters are faster. The cache is a simple HashMap, and grows
|
/// calls with the same parameters are faster. The cache is a LruCache, and the size of the cache
|
||||||
/// indefinitely. (See <https://github.com/ratatui-org/ratatui/issues/402> for more information)
|
/// can be configured using [`Layout::init_cache()`].
|
||||||
///
|
///
|
||||||
/// # Constructors
|
/// # Constructors
|
||||||
///
|
///
|
||||||
@ -132,7 +128,7 @@ impl Layout {
|
|||||||
/// Default values for the other fields are:
|
/// Default values for the other fields are:
|
||||||
///
|
///
|
||||||
/// - `margin`: 0, 0
|
/// - `margin`: 0, 0
|
||||||
/// - `flex`: Flex::StretchLast
|
/// - `flex`: Flex::Start
|
||||||
/// - `spacing`: 0
|
/// - `spacing`: 0
|
||||||
///
|
///
|
||||||
/// # Examples
|
/// # Examples
|
||||||
@ -367,9 +363,7 @@ impl Layout {
|
|||||||
///
|
///
|
||||||
/// * `flex`: A `Flex` enum value that represents the flex behavior of the layout. It can be one
|
/// * `flex`: A `Flex` enum value that represents the flex behavior of the layout. It can be one
|
||||||
/// of the following:
|
/// of the following:
|
||||||
/// - [`Flex::Stretch`]: The items are stretched equally after satisfying constraints to fill
|
/// - [`Flex::Legacy`]: The last item is stretched to fill the excess space.
|
||||||
/// excess space.
|
|
||||||
/// - [`Flex::StretchLast`]: The last item is stretched to fill the excess space.
|
|
||||||
/// - [`Flex::Start`]: The items are aligned to the start of the layout.
|
/// - [`Flex::Start`]: The items are aligned to the start of the layout.
|
||||||
/// - [`Flex::Center`]: The items are aligned to the center of the layout.
|
/// - [`Flex::Center`]: The items are aligned to the center of the layout.
|
||||||
/// - [`Flex::End`]: The items are aligned to the end of the layout.
|
/// - [`Flex::End`]: The items are aligned to the end of the layout.
|
||||||
@ -390,7 +384,7 @@ impl Layout {
|
|||||||
///
|
///
|
||||||
/// ```rust
|
/// ```rust
|
||||||
/// # use ratatui::layout::{Flex, Layout, Constraint::*};
|
/// # use ratatui::layout::{Flex, Layout, Constraint::*};
|
||||||
/// let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).flex(Flex::Stretch);
|
/// let layout = Layout::horizontal([Length(20), Length(20), Length(20)]).flex(Flex::Legacy);
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn flex(mut self, flex: Flex) -> Layout {
|
pub const fn flex(mut self, flex: Flex) -> Layout {
|
||||||
self.flex = flex;
|
self.flex = flex;
|
||||||
@ -421,34 +415,6 @@ impl Layout {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set whether chunks should be of equal size.
|
|
||||||
///
|
|
||||||
/// This determines how the space is distributed when the constraints are satisfied. By default,
|
|
||||||
/// the last chunk is expanded to fill the remaining space, but this can be changed to prefer
|
|
||||||
/// equal chunks or to not distribute extra space at all (which is the default used for laying
|
|
||||||
/// out the columns for [`Table`] widgets).
|
|
||||||
///
|
|
||||||
/// This function exists for backwards compatibility reasons. Use [`Layout::flex`] instead.
|
|
||||||
///
|
|
||||||
/// - `Flex::StretchLast` does now what `SegmentSize::LastTakesRemainder` did (default).
|
|
||||||
/// - `Flex::Stretch` does now what `SegmentSize::EvenDistribution` did.
|
|
||||||
/// - `Flex::Start` does now what `SegmentSize::None` did.
|
|
||||||
#[stability::unstable(
|
|
||||||
feature = "segment-size",
|
|
||||||
reason = "The name for this feature is not final and may change in the future",
|
|
||||||
issue = "https://github.com/ratatui-org/ratatui/issues/536"
|
|
||||||
)]
|
|
||||||
#[must_use = "method moves the value of self and returns the modified value"]
|
|
||||||
#[deprecated(since = "0.26.0", note = "You should use `Layout::flex` instead.")]
|
|
||||||
pub const fn segment_size(self, segment_size: SegmentSize) -> Layout {
|
|
||||||
let flex = match segment_size {
|
|
||||||
SegmentSize::None => Flex::Start,
|
|
||||||
SegmentSize::LastTakesRemainder => Flex::StretchLast,
|
|
||||||
SegmentSize::EvenDistribution => Flex::Stretch,
|
|
||||||
};
|
|
||||||
self.flex(flex)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Wrapper function around the cassowary-rs solver to be able to split a given area into
|
/// Wrapper function around the cassowary-rs solver to be able to split a given area into
|
||||||
/// smaller ones based on the preferred widths or heights and the direction.
|
/// smaller ones based on the preferred widths or heights and the direction.
|
||||||
///
|
///
|
||||||
@ -584,7 +550,7 @@ impl Layout {
|
|||||||
// │ │ │ │ │ │ │ │
|
// │ │ │ │ │ │ │ │
|
||||||
// V V V V V V V V
|
// V V V V V V V V
|
||||||
// ┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐
|
// ┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐┌──────────────────┐┌ ┐
|
||||||
// │ Fixed(20) │ │ Min(20) │ │ Max(20) │
|
// │ Max(20) │ │ Max(20) │ │ Max(20) │
|
||||||
// └ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘
|
// └ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘└──────────────────┘└ ┘
|
||||||
// ^ ^ ^ ^ ^ ^ ^ ^
|
// ^ ^ ^ ^ ^ ^ ^ ^
|
||||||
// │ │ │ │ │ │ │ │
|
// │ │ │ │ │ │ │ │
|
||||||
@ -618,9 +584,15 @@ impl Layout {
|
|||||||
let area_size = Element::from((*variables.first().unwrap(), *variables.last().unwrap()));
|
let area_size = Element::from((*variables.first().unwrap(), *variables.last().unwrap()));
|
||||||
configure_area(&mut solver, area_size, area_start, area_end)?;
|
configure_area(&mut solver, area_size, area_start, area_end)?;
|
||||||
configure_variable_constraints(&mut solver, &variables, area_size)?;
|
configure_variable_constraints(&mut solver, &variables, area_size)?;
|
||||||
configure_flex_constraints(&mut solver, area_size, &spacers, &segments, flex, spacing)?;
|
configure_flex_constraints(&mut solver, area_size, &spacers, flex, spacing)?;
|
||||||
configure_constraints(&mut solver, area_size, &segments, constraints)?;
|
configure_constraints(&mut solver, area_size, &segments, constraints, flex)?;
|
||||||
configure_fill_constraints(&mut solver, &segments, constraints)?;
|
configure_fill_constraints(&mut solver, &segments, constraints, flex)?;
|
||||||
|
|
||||||
|
if !flex.is_legacy() {
|
||||||
|
for (left, right) in segments.iter().tuple_windows() {
|
||||||
|
solver.add_constraint(left.has_size(right, WEAK / 100.0))?;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// `solver.fetch_changes()` can only be called once per solve
|
// `solver.fetch_changes()` can only be called once per solve
|
||||||
let changes: HashMap<Variable, f64> = solver.fetch_changes().iter().copied().collect();
|
let changes: HashMap<Variable, f64> = solver.fetch_changes().iter().copied().collect();
|
||||||
@ -668,19 +640,21 @@ fn configure_constraints(
|
|||||||
area: Element,
|
area: Element,
|
||||||
segments: &[Element],
|
segments: &[Element],
|
||||||
constraints: &[Constraint],
|
constraints: &[Constraint],
|
||||||
|
flex: Flex,
|
||||||
) -> Result<(), AddConstraintError> {
|
) -> Result<(), AddConstraintError> {
|
||||||
for (&constraint, &element) in constraints.iter().zip(segments.iter()) {
|
for (&constraint, &element) in constraints.iter().zip(segments.iter()) {
|
||||||
match constraint {
|
match constraint {
|
||||||
Constraint::Fixed(length) => {
|
|
||||||
solver.add_constraint(element.has_int_size(length, FIXED_SIZE_EQ))?
|
|
||||||
}
|
|
||||||
Constraint::Max(max) => {
|
Constraint::Max(max) => {
|
||||||
solver.add_constraint(element.has_max_size(max, MAX_SIZE_LE))?;
|
solver.add_constraint(element.has_max_size(max, MAX_SIZE_LE))?;
|
||||||
solver.add_constraint(element.has_int_size(max, MAX_SIZE_EQ))?;
|
solver.add_constraint(element.has_int_size(max, MAX_SIZE_EQ))?;
|
||||||
}
|
}
|
||||||
Constraint::Min(min) => {
|
Constraint::Min(min) => {
|
||||||
solver.add_constraint(element.has_min_size(min, MIN_SIZE_GE))?;
|
solver.add_constraint(element.has_min_size(min, MIN_SIZE_GE))?;
|
||||||
solver.add_constraint(element.has_int_size(min, MIN_SIZE_EQ))?;
|
if flex.is_legacy() {
|
||||||
|
solver.add_constraint(element.has_int_size(min, MIN_SIZE_EQ))?;
|
||||||
|
} else {
|
||||||
|
solver.add_constraint(element.has_size(area, FILL_GROW))?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Constraint::Length(length) => {
|
Constraint::Length(length) => {
|
||||||
solver.add_constraint(element.has_int_size(length, LENGTH_SIZE_EQ))?
|
solver.add_constraint(element.has_int_size(length, LENGTH_SIZE_EQ))?
|
||||||
@ -707,13 +681,21 @@ fn configure_flex_constraints(
|
|||||||
solver: &mut Solver,
|
solver: &mut Solver,
|
||||||
area: Element,
|
area: Element,
|
||||||
spacers: &[Element],
|
spacers: &[Element],
|
||||||
segments: &[Element],
|
|
||||||
flex: Flex,
|
flex: Flex,
|
||||||
spacing: u16,
|
spacing: u16,
|
||||||
) -> Result<(), AddConstraintError> {
|
) -> Result<(), AddConstraintError> {
|
||||||
let spacers_except_first_and_last = spacers.get(1..spacers.len() - 1).unwrap_or(&[]);
|
let spacers_except_first_and_last = spacers.get(1..spacers.len() - 1).unwrap_or(&[]);
|
||||||
let spacing = f64::from(spacing);
|
let spacing = f64::from(spacing);
|
||||||
match flex {
|
match flex {
|
||||||
|
Flex::Legacy => {
|
||||||
|
for spacer in spacers_except_first_and_last.iter() {
|
||||||
|
solver.add_constraint(spacer.has_size(spacing, SPACER_SIZE_EQ))?;
|
||||||
|
}
|
||||||
|
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
||||||
|
solver.add_constraint(first.is_empty())?;
|
||||||
|
solver.add_constraint(last.is_empty())?;
|
||||||
|
}
|
||||||
|
}
|
||||||
// all spacers are the same size and will grow to fill any remaining space after the
|
// all spacers are the same size and will grow to fill any remaining space after the
|
||||||
// constraints are satisfied
|
// constraints are satisfied
|
||||||
Flex::SpaceAround => {
|
Flex::SpaceAround => {
|
||||||
@ -739,27 +721,6 @@ fn configure_flex_constraints(
|
|||||||
solver.add_constraint(last.is_empty())?;
|
solver.add_constraint(last.is_empty())?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Flex::StretchLast => {
|
|
||||||
for spacer in spacers_except_first_and_last.iter() {
|
|
||||||
solver.add_constraint(spacer.has_size(spacing, SPACER_SIZE_EQ))?;
|
|
||||||
}
|
|
||||||
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
|
||||||
solver.add_constraint(first.is_empty())?;
|
|
||||||
solver.add_constraint(last.is_empty())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Flex::Stretch => {
|
|
||||||
for spacer in spacers_except_first_and_last {
|
|
||||||
solver.add_constraint(spacer.has_size(spacing, SPACER_SIZE_EQ))?;
|
|
||||||
}
|
|
||||||
for (left, right) in segments.iter().tuple_combinations() {
|
|
||||||
solver.add_constraint(left.has_size(right, GROW))?;
|
|
||||||
}
|
|
||||||
if let (Some(first), Some(last)) = (spacers.first(), spacers.last()) {
|
|
||||||
solver.add_constraint(first.is_empty())?;
|
|
||||||
solver.add_constraint(last.is_empty())?;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Flex::Start => {
|
Flex::Start => {
|
||||||
for spacer in spacers_except_first_and_last {
|
for spacer in spacers_except_first_and_last {
|
||||||
solver.add_constraint(spacer.has_size(spacing, SPACER_SIZE_EQ))?;
|
solver.add_constraint(spacer.has_size(spacing, SPACER_SIZE_EQ))?;
|
||||||
@ -800,7 +761,7 @@ fn configure_flex_constraints(
|
|||||||
/// │abcdef││abcdef│
|
/// │abcdef││abcdef│
|
||||||
/// └──────┘└──────┘
|
/// └──────┘└──────┘
|
||||||
///
|
///
|
||||||
/// [Fill(1), Fill(2)]
|
/// [Min(0), Fill(2)]
|
||||||
/// ┌──────┐┌────────────┐
|
/// ┌──────┐┌────────────┐
|
||||||
/// │abcdef││abcdefabcdef│
|
/// │abcdef││abcdefabcdef│
|
||||||
/// └──────┘└────────────┘
|
/// └──────┘└────────────┘
|
||||||
@ -810,44 +771,29 @@ fn configure_fill_constraints(
|
|||||||
solver: &mut Solver,
|
solver: &mut Solver,
|
||||||
segments: &[Element],
|
segments: &[Element],
|
||||||
constraints: &[Constraint],
|
constraints: &[Constraint],
|
||||||
|
flex: Flex,
|
||||||
) -> Result<(), AddConstraintError> {
|
) -> Result<(), AddConstraintError> {
|
||||||
for ((&l_constraint, &l_element), (&r_constraint, &r_element)) in constraints
|
for ((&left_constraint, &left_element), (&right_constraint, &right_element)) in constraints
|
||||||
.iter()
|
.iter()
|
||||||
.zip(segments.iter())
|
.zip(segments.iter())
|
||||||
.filter(|(c, _)| c.is_fill())
|
.filter(|(c, _)| c.is_fill() || (!flex.is_legacy() && c.is_min()))
|
||||||
.tuple_combinations()
|
.tuple_combinations()
|
||||||
{
|
{
|
||||||
// `Fill` will only expand into _excess_ available space. You can think of
|
let left_scaling_factor = match left_constraint {
|
||||||
// `Fill` element sizes as starting from `0` and incrementally
|
Constraint::Fill(scale) => f64::from(scale).max(1e-6),
|
||||||
// increasing while proportionally matching other `Fill` spaces AND
|
Constraint::Min(_) => 1.0,
|
||||||
// also meeting all other constraints.
|
_ => unreachable!(),
|
||||||
if let (Constraint::Fill(l_scaling_factor), Constraint::Fill(r_scaling_factor)) =
|
};
|
||||||
(l_constraint, r_constraint)
|
let right_scaling_factor = match right_constraint {
|
||||||
{
|
Constraint::Fill(scale) => f64::from(scale).max(1e-6),
|
||||||
// because of the way cassowary works, we need to use `*` instead of `/`
|
Constraint::Min(_) => 1.0,
|
||||||
// l_size / l_scaling_factor == l_size / l_scaling_factor
|
_ => unreachable!(),
|
||||||
// ≡
|
};
|
||||||
// l_size * r_scaling_factor == r_size * r_scaling_factor
|
solver.add_constraint(
|
||||||
//
|
(right_scaling_factor * left_element.size())
|
||||||
// we make `0` act as `1e-6`.
|
| EQ(GROW)
|
||||||
// this gives us a numerically stable solution and more consistent behavior along
|
| (left_scaling_factor * right_element.size()),
|
||||||
// the number line
|
)?;
|
||||||
//
|
|
||||||
// I choose `1e-6` because we want a value that is as close to `0.0` as possible
|
|
||||||
// without causing it to behave like `0.0`. `1e-9` for example gives the same
|
|
||||||
// results as true `0.0`.
|
|
||||||
// I found `1e-6` worked well in all the various combinations of constraints I
|
|
||||||
// experimented with.
|
|
||||||
let (l_scaling_factor, r_scaling_factor) = (
|
|
||||||
f64::from(l_scaling_factor).max(1e-6),
|
|
||||||
f64::from(r_scaling_factor).max(1e-6),
|
|
||||||
);
|
|
||||||
solver.add_constraint(
|
|
||||||
(r_scaling_factor * l_element.size())
|
|
||||||
| EQ(FILL_SCALING_EQ)
|
|
||||||
| (l_scaling_factor * r_element.size()),
|
|
||||||
)?;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
@ -967,20 +913,6 @@ mod strengths {
|
|||||||
/// └ ┘└───┘└ ┘└───┘└ ┘
|
/// └ ┘└───┘└ ┘└───┘└ ┘
|
||||||
pub const SPACER_SIZE_EQ: f64 = REQUIRED - 1.0;
|
pub const SPACER_SIZE_EQ: f64 = REQUIRED - 1.0;
|
||||||
|
|
||||||
/// The strength to apply to Fill constraints so that their sizes are proportional.
|
|
||||||
///
|
|
||||||
/// ┌───────────────┐┌───────────────┐
|
|
||||||
/// │ Fill(x) ││ Fill(x) │
|
|
||||||
/// └───────────────┘└───────────────┘
|
|
||||||
pub const FILL_SCALING_EQ: f64 = REQUIRED - 1.0;
|
|
||||||
|
|
||||||
/// The strength to apply to Fixed constraints.
|
|
||||||
///
|
|
||||||
/// ┌──────────┐
|
|
||||||
/// │Fixed(==x)│
|
|
||||||
/// └──────────┘
|
|
||||||
pub const FIXED_SIZE_EQ: f64 = REQUIRED / 10.0;
|
|
||||||
|
|
||||||
/// The strength to apply to Min inequality constraints.
|
/// The strength to apply to Min inequality constraints.
|
||||||
///
|
///
|
||||||
/// ┌────────┐
|
/// ┌────────┐
|
||||||
@ -1016,13 +948,6 @@ mod strengths {
|
|||||||
/// └────────────┘
|
/// └────────────┘
|
||||||
pub const RATIO_SIZE_EQ: f64 = MEDIUM;
|
pub const RATIO_SIZE_EQ: f64 = MEDIUM;
|
||||||
|
|
||||||
/// The strength to apply to Min equality constraints.
|
|
||||||
///
|
|
||||||
/// ┌────────┐
|
|
||||||
/// │Min(==x)│
|
|
||||||
/// └────────┘
|
|
||||||
pub const MIN_SIZE_EQ: f64 = MEDIUM / 10.0;
|
|
||||||
|
|
||||||
/// The strength to apply to Max equality constraints.
|
/// The strength to apply to Max equality constraints.
|
||||||
///
|
///
|
||||||
/// ┌────────┐
|
/// ┌────────┐
|
||||||
@ -1030,6 +955,13 @@ mod strengths {
|
|||||||
/// └────────┘
|
/// └────────┘
|
||||||
pub const MAX_SIZE_EQ: f64 = MEDIUM / 10.0;
|
pub const MAX_SIZE_EQ: f64 = MEDIUM / 10.0;
|
||||||
|
|
||||||
|
/// The strength to apply to Min equality constraints.
|
||||||
|
///
|
||||||
|
/// ┌────────┐
|
||||||
|
/// │Min(==x)│
|
||||||
|
/// └────────┘
|
||||||
|
pub const MIN_SIZE_EQ: f64 = MEDIUM / 10.0;
|
||||||
|
|
||||||
/// The strength to apply to Fill growing constraints.
|
/// The strength to apply to Fill growing constraints.
|
||||||
///
|
///
|
||||||
/// ┌─────────────────────┐
|
/// ┌─────────────────────┐
|
||||||
@ -1053,12 +985,8 @@ mod strengths {
|
|||||||
|
|
||||||
#[allow(dead_code)]
|
#[allow(dead_code)]
|
||||||
pub fn is_valid() -> bool {
|
pub fn is_valid() -> bool {
|
||||||
SPACER_SIZE_EQ > FIXED_SIZE_EQ
|
SPACER_SIZE_EQ > MAX_SIZE_LE
|
||||||
&& FILL_SCALING_EQ > FIXED_SIZE_EQ
|
|
||||||
&& FIXED_SIZE_EQ > MIN_SIZE_GE
|
|
||||||
&& MIN_SIZE_GE > MIN_SIZE_EQ
|
|
||||||
&& MAX_SIZE_LE > MAX_SIZE_EQ
|
&& MAX_SIZE_LE > MAX_SIZE_EQ
|
||||||
&& MIN_SIZE_EQ == MAX_SIZE_EQ
|
|
||||||
&& MIN_SIZE_GE == MAX_SIZE_LE
|
&& MIN_SIZE_GE == MAX_SIZE_LE
|
||||||
&& MAX_SIZE_LE > LENGTH_SIZE_EQ
|
&& MAX_SIZE_LE > LENGTH_SIZE_EQ
|
||||||
&& LENGTH_SIZE_EQ > PERCENTAGE_SIZE_EQ
|
&& LENGTH_SIZE_EQ > PERCENTAGE_SIZE_EQ
|
||||||
@ -1082,13 +1010,10 @@ mod tests {
|
|||||||
fn strength() {
|
fn strength() {
|
||||||
assert!(strengths::is_valid());
|
assert!(strengths::is_valid());
|
||||||
assert_eq!(strengths::SPACER_SIZE_EQ, REQUIRED - 1.0);
|
assert_eq!(strengths::SPACER_SIZE_EQ, REQUIRED - 1.0);
|
||||||
assert_eq!(strengths::FILL_SCALING_EQ, REQUIRED - 1.0);
|
|
||||||
assert_eq!(strengths::FIXED_SIZE_EQ, REQUIRED / 10.0);
|
|
||||||
assert_eq!(strengths::MIN_SIZE_GE, STRONG * 10.0);
|
assert_eq!(strengths::MIN_SIZE_GE, STRONG * 10.0);
|
||||||
assert_eq!(strengths::LENGTH_SIZE_EQ, STRONG / 10.0);
|
assert_eq!(strengths::LENGTH_SIZE_EQ, STRONG / 10.0);
|
||||||
assert_eq!(strengths::PERCENTAGE_SIZE_EQ, MEDIUM * 10.0);
|
assert_eq!(strengths::PERCENTAGE_SIZE_EQ, MEDIUM * 10.0);
|
||||||
assert_eq!(strengths::RATIO_SIZE_EQ, MEDIUM);
|
assert_eq!(strengths::RATIO_SIZE_EQ, MEDIUM);
|
||||||
assert_eq!(strengths::MIN_SIZE_EQ, MEDIUM / 10.0);
|
|
||||||
assert_eq!(strengths::FILL_GROW, WEAK * 10.0);
|
assert_eq!(strengths::FILL_GROW, WEAK * 10.0);
|
||||||
assert_eq!(strengths::GROW, WEAK);
|
assert_eq!(strengths::GROW, WEAK);
|
||||||
assert_eq!(strengths::SPACE_GROW, WEAK / 10.0);
|
assert_eq!(strengths::SPACE_GROW, WEAK / 10.0);
|
||||||
@ -1322,28 +1247,7 @@ mod tests {
|
|||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
fn flex_default() {
|
fn flex_default() {
|
||||||
assert_eq!(Layout::default().flex, Flex::StretchLast);
|
assert_eq!(Layout::default().flex, Flex::Start);
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
#[allow(deprecated)]
|
|
||||||
fn segment_size() {
|
|
||||||
assert_eq!(
|
|
||||||
Layout::default()
|
|
||||||
.segment_size(SegmentSize::EvenDistribution)
|
|
||||||
.flex,
|
|
||||||
Flex::Stretch
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Layout::default()
|
|
||||||
.segment_size(SegmentSize::LastTakesRemainder)
|
|
||||||
.flex,
|
|
||||||
Flex::StretchLast
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
Layout::default().segment_size(SegmentSize::None).flex,
|
|
||||||
Flex::Start
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Tests for the `Layout::split()` function.
|
/// Tests for the `Layout::split()` function.
|
||||||
@ -1405,7 +1309,7 @@ mod tests {
|
|||||||
#[case] constraints: &[Constraint],
|
#[case] constraints: &[Constraint],
|
||||||
#[case] expected: &str,
|
#[case] expected: &str,
|
||||||
) {
|
) {
|
||||||
letters(area, constraints, expected, Flex::Stretch)
|
letters(area, constraints, expected, Flex::Legacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@ -1431,8 +1335,8 @@ mod tests {
|
|||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(0), Length(3)], "bb")] // zero, overflow
|
#[case(Rect::new(0, 0, 2, 1), &[Length(0), Length(3)], "bb")] // zero, overflow
|
||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(0)], "ab")] // underflow, zero
|
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(0)], "ab")] // underflow, zero
|
||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(1)], "ab")] // underflow, underflow
|
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(1)], "ab")] // underflow, underflow
|
||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(2)], "ab")] // underflow, exact with stretchlast
|
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(2)], "ab")] // underflow, exact
|
||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(3)], "ab")] // underflow, overflow with stretchlast
|
#[case(Rect::new(0, 0, 2, 1), &[Length(1), Length(3)], "ab")] // underflow, overflow
|
||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(2), Length(0)], "aa")] // exact, zero
|
#[case(Rect::new(0, 0, 2, 1), &[Length(2), Length(0)], "aa")] // exact, zero
|
||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(2), Length(1)], "aa")] // exact, underflow
|
#[case(Rect::new(0, 0, 2, 1), &[Length(2), Length(1)], "aa")] // exact, underflow
|
||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(2), Length(2)], "aa")] // exact, exact
|
#[case(Rect::new(0, 0, 2, 1), &[Length(2), Length(2)], "aa")] // exact, exact
|
||||||
@ -1443,7 +1347,7 @@ mod tests {
|
|||||||
#[case(Rect::new(0, 0, 2, 1), &[Length(3), Length(3)], "aa")] // overflow, overflow
|
#[case(Rect::new(0, 0, 2, 1), &[Length(3), Length(3)], "aa")] // overflow, overflow
|
||||||
#[case(Rect::new(0, 0, 3, 1), &[Length(2), Length(2)], "aab")] // with stretchlast
|
#[case(Rect::new(0, 0, 3, 1), &[Length(2), Length(2)], "aab")] // with stretchlast
|
||||||
fn length(#[case] area: Rect, #[case] constraints: &[Constraint], #[case] expected: &str) {
|
fn length(#[case] area: Rect, #[case] constraints: &[Constraint], #[case] expected: &str) {
|
||||||
letters(area, constraints, expected, Flex::StretchLast)
|
letters(area, constraints, expected, Flex::Legacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@ -1481,7 +1385,7 @@ mod tests {
|
|||||||
#[case(Rect::new(0, 0, 2, 1), &[Max(3), Max(3)], "aa")] // overflow, overflow
|
#[case(Rect::new(0, 0, 2, 1), &[Max(3), Max(3)], "aa")] // overflow, overflow
|
||||||
#[case(Rect::new(0, 0, 3, 1), &[Max(2), Max(2)], "aab")]
|
#[case(Rect::new(0, 0, 3, 1), &[Max(2), Max(2)], "aab")]
|
||||||
fn max(#[case] area: Rect, #[case] constraints: &[Constraint], #[case] expected: &str) {
|
fn max(#[case] area: Rect, #[case] constraints: &[Constraint], #[case] expected: &str) {
|
||||||
letters(area, constraints, expected, Flex::StretchLast)
|
letters(area, constraints, expected, Flex::Legacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
@ -1512,7 +1416,7 @@ mod tests {
|
|||||||
#[case(Rect::new(0, 0, 2, 1), &[Min(3), Min(3)], "aa")] // overflow, overflow
|
#[case(Rect::new(0, 0, 2, 1), &[Min(3), Min(3)], "aa")] // overflow, overflow
|
||||||
#[case(Rect::new(0, 0, 3, 1), &[Min(2), Min(2)], "aab")]
|
#[case(Rect::new(0, 0, 3, 1), &[Min(2), Min(2)], "aab")]
|
||||||
fn min(#[case] area: Rect, #[case] constraints: &[Constraint], #[case] expected: &str) {
|
fn min(#[case] area: Rect, #[case] constraints: &[Constraint], #[case] expected: &str) {
|
||||||
letters(area, constraints, expected, Flex::StretchLast)
|
letters(area, constraints, expected, Flex::Legacy)
|
||||||
}
|
}
|
||||||
|
|
||||||
mod percentage {
|
mod percentage {
|
||||||
@ -1601,7 +1505,7 @@ mod tests {
|
|||||||
#[case] constraints: &[Constraint],
|
#[case] constraints: &[Constraint],
|
||||||
#[case] expected: &str,
|
#[case] expected: &str,
|
||||||
) {
|
) {
|
||||||
letters(area, constraints, expected, Flex::StretchLast)
|
letters(area, constraints, expected, Flex::Legacy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1690,7 +1594,7 @@ mod tests {
|
|||||||
#[case] constraints: &[Constraint],
|
#[case] constraints: &[Constraint],
|
||||||
#[case] expected: &str,
|
#[case] expected: &str,
|
||||||
) {
|
) {
|
||||||
letters(area, constraints, expected, Flex::StretchLast)
|
letters(area, constraints, expected, Flex::Legacy)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1771,19 +1675,6 @@ mod tests {
|
|||||||
]
|
]
|
||||||
);
|
);
|
||||||
|
|
||||||
let layout = Layout::default()
|
|
||||||
.constraints([Min(1), Fixed(0), Min(1)])
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.split(Rect::new(0, 0, 1, 1));
|
|
||||||
assert_eq!(
|
|
||||||
layout[..],
|
|
||||||
[
|
|
||||||
Rect::new(0, 0, 1, 1),
|
|
||||||
Rect::new(1, 0, 0, 1),
|
|
||||||
Rect::new(1, 0, 0, 1),
|
|
||||||
]
|
|
||||||
);
|
|
||||||
|
|
||||||
// This stretches the 2nd last length instead of the last min based on ranking
|
// This stretches the 2nd last length instead of the last min based on ranking
|
||||||
let layout = Layout::default()
|
let layout = Layout::default()
|
||||||
.constraints([Length(3), Min(4), Length(1), Min(4)])
|
.constraints([Length(3), Min(4), Length(1), Min(4)])
|
||||||
@ -1809,14 +1700,14 @@ mod tests {
|
|||||||
#[case::length_priority(vec![75, 25], vec![Percentage(25), Length(25)])]
|
#[case::length_priority(vec![75, 25], vec![Percentage(25), Length(25)])]
|
||||||
#[case::length_priority(vec![25, 75], vec![Length(25), Ratio(1, 4)])]
|
#[case::length_priority(vec![25, 75], vec![Length(25), Ratio(1, 4)])]
|
||||||
#[case::length_priority(vec![75, 25], vec![Ratio(1, 4), Length(25)])]
|
#[case::length_priority(vec![75, 25], vec![Ratio(1, 4), Length(25)])]
|
||||||
#[case::length_priority(vec![75, 25], vec![Length(25), Fixed(25)])]
|
#[case::length_priority(vec![25, 75], vec![Length(25), Length(25)])]
|
||||||
#[case::length_priority(vec![25, 75], vec![Fixed(25), Length(25)])]
|
|
||||||
#[case::excess_in_last_variable(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
#[case::excess_in_last_variable(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
||||||
#[case::excess_in_last_variable(vec![15, 35, 50], vec![Length(15), Length(35), Length(25)])]
|
#[case::excess_in_last_variable(vec![15, 35, 50], vec![Length(15), Length(35), Length(25)])]
|
||||||
#[case::three_lengths(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
#[case::three_lengths(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
||||||
fn constraint_length(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
fn constraint_length(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
||||||
let rect = Rect::new(0, 0, 100, 1);
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
let r = Layout::horizontal(constraints)
|
let r = Layout::horizontal(constraints)
|
||||||
|
.flex(Flex::Legacy)
|
||||||
.split(rect)
|
.split(rect)
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -1826,8 +1717,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::table_length_test(vec![Length(4), Length(4)], vec![(0, 4), (5, 2)], 7)]
|
#[case::table_length_test(vec![Length(4), Length(4)], vec![(0, 3), (4, 3)], 7)]
|
||||||
#[case::table_length_test(vec![Length(4), Length(4)], vec![(0, 3), (4, 0)], 4)]
|
#[case::table_length_test(vec![Length(4), Length(4)], vec![(0, 2), (3, 1)], 4)]
|
||||||
fn table_length(
|
fn table_length(
|
||||||
#[case] constraints: Vec<Constraint>,
|
#[case] constraints: Vec<Constraint>,
|
||||||
#[case] expected: Vec<(u16, u16)>,
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
@ -1846,26 +1737,29 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::fixed_is_higher_priority_than_min_max(vec![50, 25, 25], vec![Min(25), Fixed(25), Max(25)])]
|
#[case::length_is_higher_priority_than_min_max(vec![50, 25, 25], vec![Min(25), Length(25), Max(25)])]
|
||||||
#[case::fixed_is_higher_priority_than_min_max(vec![25, 25, 50], vec![Max(25), Fixed(25), Min(25)])]
|
#[case::length_is_higher_priority_than_min_max(vec![25, 25, 50], vec![Max(25), Length(25), Min(25)])]
|
||||||
#[case::excess_in_lowest_priority(vec![33, 33, 34], vec![Fixed(33), Fixed(33), Fixed(33)])]
|
#[case::excess_in_lowest_priority(vec![33, 33, 34], vec![Length(33), Length(33), Length(33)])]
|
||||||
#[case::excess_in_lowest_priority(vec![25, 25, 50], vec![Fixed(25), Fixed(25), Fixed(25)])]
|
#[case::excess_in_lowest_priority(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
||||||
#[case::fixed_higher_priority(vec![25, 25, 50], vec![Percentage(25), Fixed(25), Ratio(1, 4)])]
|
#[case::length_higher_priority(vec![25, 25, 50], vec![Percentage(25), Length(25), Ratio(1, 4)])]
|
||||||
#[case::fixed_higher_priority(vec![25, 50, 25], vec![Fixed(25), Ratio(1, 4), Percentage(25)])]
|
#[case::length_higher_priority(vec![25, 50, 25], vec![Length(25), Ratio(1, 4), Percentage(25)])]
|
||||||
#[case::fixed_higher_priority(vec![50, 25, 25], vec![Ratio(1, 4), Fixed(25), Percentage(25)])]
|
#[case::length_higher_priority(vec![50, 25, 25], vec![Ratio(1, 4), Length(25), Percentage(25)])]
|
||||||
#[case::fixed_higher_priority(vec![50, 25, 25], vec![Ratio(1, 4), Percentage(25), Fixed(25)])]
|
#[case::length_higher_priority(vec![50, 25, 25], vec![Ratio(1, 4), Percentage(25), Length(25)])]
|
||||||
#[case::fixed_higher_priority(vec![79, 1, 20], vec![Length(100), Fixed(1), Min(20)])]
|
#[case::length_higher_priority(vec![80, 0, 20], vec![Length(100), Length(1), Min(20)])]
|
||||||
#[case::fixed_higher_priority(vec![20, 1, 79], vec![Min(20), Fixed(1), Length(100)])]
|
#[case::length_higher_priority(vec![20, 1, 79], vec![Min(20), Length(1), Length(100)])]
|
||||||
#[case::fixed_higher_priority(vec![45, 10, 45], vec![Fill(1), Fixed(10), Fill(1)])]
|
#[case::length_higher_priority(vec![45, 10, 45], vec![Fill(1), Length(10), Fill(1)])]
|
||||||
#[case::fixed_higher_priority(vec![30, 10, 60], vec![Fill(1), Fixed(10), Fill(2)])]
|
#[case::length_higher_priority(vec![30, 10, 60], vec![Fill(1), Length(10), Fill(2)])]
|
||||||
#[case::fixed_higher_priority(vec![18, 10, 72], vec![Fill(1), Fixed(10), Fill(4)])]
|
#[case::length_higher_priority(vec![18, 10, 72], vec![Fill(1), Length(10), Fill(4)])]
|
||||||
#[case::fixed_higher_priority(vec![15, 10, 75], vec![Fill(1), Fixed(10), Fill(5)])]
|
#[case::length_higher_priority(vec![15, 10, 75], vec![Fill(1), Length(10), Fill(5)])]
|
||||||
#[case::three_lengths_reference(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
#[case::three_lengths_reference(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
||||||
// #[case::previously_unstable_test(vec![25, 50, 25], vec![Length(25), Length(25),
|
#[case::previously_unstable_test(vec![25, 25, 50], vec![Length(25), Length(25), Length(25)])]
|
||||||
// Fixed(25)])]
|
fn length_is_higher_priority(
|
||||||
fn fixed(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
#[case] expected: Vec<u16>,
|
||||||
|
#[case] constraints: Vec<Constraint>,
|
||||||
|
) {
|
||||||
let rect = Rect::new(0, 0, 100, 1);
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
let r = Layout::horizontal(constraints)
|
let r = Layout::horizontal(constraints)
|
||||||
|
.flex(Flex::Legacy)
|
||||||
.split(rect)
|
.split(rect)
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -1875,11 +1769,83 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::excess_in_last_variable(vec![13, 10, 27], vec![Fill(1), Fixed(10), Fill(2)])]
|
#[case::length_is_higher_priority_than_min_max(vec![50, 25, 25], vec![Min(25), Length(25), Max(25)])]
|
||||||
#[case::excess_in_last_variable(vec![10, 27, 13], vec![Fixed(10), Fill(2), Fill(1)])] // might be unstable?
|
#[case::length_is_higher_priority_than_min_max(vec![25, 25, 50], vec![Max(25), Length(25), Min(25)])]
|
||||||
|
#[case::excess_in_lowest_priority(vec![33, 33, 33], vec![Length(33), Length(33), Length(33)])]
|
||||||
|
#[case::excess_in_lowest_priority(vec![25, 25, 25], vec![Length(25), Length(25), Length(25)])]
|
||||||
|
#[case::length_higher_priority(vec![25, 25, 25], vec![Percentage(25), Length(25), Ratio(1, 4)])]
|
||||||
|
#[case::length_higher_priority(vec![25, 25, 25], vec![Length(25), Ratio(1, 4), Percentage(25)])]
|
||||||
|
#[case::length_higher_priority(vec![25, 25, 25], vec![Ratio(1, 4), Length(25), Percentage(25)])]
|
||||||
|
#[case::length_higher_priority(vec![25, 25, 25], vec![Ratio(1, 4), Percentage(25), Length(25)])]
|
||||||
|
#[case::length_higher_priority(vec![79, 1, 20], vec![Length(100), Length(1), Min(20)])]
|
||||||
|
#[case::length_higher_priority(vec![20, 1, 79], vec![Min(20), Length(1), Length(100)])]
|
||||||
|
#[case::length_higher_priority(vec![45, 10, 45], vec![Fill(1), Length(10), Fill(1)])]
|
||||||
|
#[case::length_higher_priority(vec![30, 10, 60], vec![Fill(1), Length(10), Fill(2)])]
|
||||||
|
#[case::length_higher_priority(vec![18, 10, 72], vec![Fill(1), Length(10), Fill(4)])]
|
||||||
|
#[case::length_higher_priority(vec![15, 10, 75], vec![Fill(1), Length(10), Fill(5)])]
|
||||||
|
#[case::previously_unstable_test(vec![25, 25, 25], vec![Length(25), Length(25), Length(25)])]
|
||||||
|
fn length_is_higher_priority_in_flex(
|
||||||
|
#[case] expected: Vec<u16>,
|
||||||
|
#[case] constraints: Vec<Constraint>,
|
||||||
|
) {
|
||||||
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
|
let r = Layout::horizontal(&constraints)
|
||||||
|
.flex(Flex::Start)
|
||||||
|
.split(rect)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|r| r.width)
|
||||||
|
.collect::<Vec<u16>>();
|
||||||
|
assert_eq!(expected, r);
|
||||||
|
|
||||||
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
|
let r = Layout::horizontal(&constraints)
|
||||||
|
.flex(Flex::Center)
|
||||||
|
.split(rect)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|r| r.width)
|
||||||
|
.collect::<Vec<u16>>();
|
||||||
|
assert_eq!(expected, r);
|
||||||
|
|
||||||
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
|
let r = Layout::horizontal(&constraints)
|
||||||
|
.flex(Flex::End)
|
||||||
|
.split(rect)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|r| r.width)
|
||||||
|
.collect::<Vec<u16>>();
|
||||||
|
assert_eq!(expected, r);
|
||||||
|
|
||||||
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
|
let r = Layout::horizontal(&constraints)
|
||||||
|
.flex(Flex::SpaceAround)
|
||||||
|
.split(rect)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|r| r.width)
|
||||||
|
.collect::<Vec<u16>>();
|
||||||
|
assert_eq!(expected, r);
|
||||||
|
|
||||||
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
|
let r = Layout::horizontal(&constraints)
|
||||||
|
.flex(Flex::SpaceBetween)
|
||||||
|
.split(rect)
|
||||||
|
.iter()
|
||||||
|
.cloned()
|
||||||
|
.map(|r| r.width)
|
||||||
|
.collect::<Vec<u16>>();
|
||||||
|
assert_eq!(expected, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case::excess_in_last_variable(vec![13, 10, 27], vec![Fill(1), Length(10), Fill(2)])]
|
||||||
|
#[case::excess_in_last_variable(vec![10, 27, 13], vec![Length(10), Fill(2), Fill(1)])] // might be unstable?
|
||||||
fn fixed_with_50_width(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
fn fixed_with_50_width(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
||||||
let rect = Rect::new(0, 0, 50, 1);
|
let rect = Rect::new(0, 0, 50, 1);
|
||||||
let r = Layout::horizontal(constraints)
|
let r = Layout::horizontal(constraints)
|
||||||
|
.flex(Flex::Legacy)
|
||||||
.split(rect)
|
.split(rect)
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -1893,13 +1859,13 @@ mod tests {
|
|||||||
#[case::incremental(vec![10, 20, 30, 40], vec![Fill(1), Fill(2), Fill(3), Fill(4)])]
|
#[case::incremental(vec![10, 20, 30, 40], vec![Fill(1), Fill(2), Fill(3), Fill(4)])]
|
||||||
#[case::decremental(vec![40, 30, 20, 10], vec![Fill(4), Fill(3), Fill(2), Fill(1)])]
|
#[case::decremental(vec![40, 30, 20, 10], vec![Fill(4), Fill(3), Fill(2), Fill(1)])]
|
||||||
#[case::randomly_ordered(vec![10, 30, 20, 40], vec![Fill(1), Fill(3), Fill(2), Fill(4)])]
|
#[case::randomly_ordered(vec![10, 30, 20, 40], vec![Fill(1), Fill(3), Fill(2), Fill(4)])]
|
||||||
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Fixed(50), Fill(2), Fill(4)])]
|
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Length(50), Fill(2), Fill(4)])]
|
||||||
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Length(50), Fill(2), Fill(4)])]
|
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Length(50), Fill(2), Fill(4)])]
|
||||||
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Percentage(50), Fill(2), Fill(4)])]
|
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Percentage(50), Fill(2), Fill(4)])]
|
||||||
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Min(50), Fill(2), Fill(4)])]
|
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Min(50), Fill(2), Fill(4)])]
|
||||||
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Max(50), Fill(2), Fill(4)])]
|
#[case::randomly_ordered(vec![5, 15, 50, 10, 20], vec![Fill(1), Fill(3), Max(50), Fill(2), Fill(4)])]
|
||||||
#[case::zero_width(vec![0, 100, 0], vec![Fill(0), Fill(1), Fill(0)])]
|
#[case::zero_width(vec![0, 100, 0], vec![Fill(0), Fill(1), Fill(0)])]
|
||||||
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Fixed(1), Fill(0)])]
|
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Length(1), Fill(0)])]
|
||||||
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Length(1), Fill(0)])]
|
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Length(1), Fill(0)])]
|
||||||
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Percentage(1), Fill(0)])]
|
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Percentage(1), Fill(0)])]
|
||||||
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Min(1), Fill(0)])]
|
#[case::zero_width(vec![50, 1, 49], vec![Fill(0), Min(1), Fill(0)])]
|
||||||
@ -1914,7 +1880,7 @@ mod tests {
|
|||||||
#[case::space_filler(vec![80, 20], vec![Fill(1), Percentage(20)])]
|
#[case::space_filler(vec![80, 20], vec![Fill(1), Percentage(20)])]
|
||||||
#[case::space_filler(vec![80, 20], vec![Fill(u16::MAX), Percentage(20)])]
|
#[case::space_filler(vec![80, 20], vec![Fill(u16::MAX), Percentage(20)])]
|
||||||
#[case::space_filler(vec![80, 0, 20], vec![Fill(u16::MAX), Fill(0), Percentage(20)])]
|
#[case::space_filler(vec![80, 0, 20], vec![Fill(u16::MAX), Fill(0), Percentage(20)])]
|
||||||
#[case::space_filler(vec![80, 20], vec![Fill(0), Fixed(20)])]
|
#[case::space_filler(vec![80, 20], vec![Fill(0), Length(20)])]
|
||||||
#[case::space_filler(vec![80, 20], vec![Fill(0), Length(20)])]
|
#[case::space_filler(vec![80, 20], vec![Fill(0), Length(20)])]
|
||||||
#[case::space_filler(vec![80, 20], vec![Fill(0), Min(20)])]
|
#[case::space_filler(vec![80, 20], vec![Fill(0), Min(20)])]
|
||||||
#[case::space_filler(vec![80, 20], vec![Fill(0), Max(20)])]
|
#[case::space_filler(vec![80, 20], vec![Fill(0), Max(20)])]
|
||||||
@ -1927,6 +1893,7 @@ mod tests {
|
|||||||
fn fill(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
fn fill(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
||||||
let rect = Rect::new(0, 0, 100, 1);
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
let r = Layout::horizontal(constraints)
|
let r = Layout::horizontal(constraints)
|
||||||
|
.flex(Flex::Legacy)
|
||||||
.split(rect)
|
.split(rect)
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -1944,6 +1911,7 @@ mod tests {
|
|||||||
) {
|
) {
|
||||||
let rect = Rect::new(0, 0, 100, 1);
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
let r = Layout::horizontal(constraints)
|
let r = Layout::horizontal(constraints)
|
||||||
|
.flex(Flex::Legacy)
|
||||||
.split(rect)
|
.split(rect)
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -1962,6 +1930,7 @@ mod tests {
|
|||||||
fn min_max(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
fn min_max(#[case] expected: Vec<u16>, #[case] constraints: Vec<Constraint>) {
|
||||||
let rect = Rect::new(0, 0, 100, 1);
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
let r = Layout::horizontal(constraints)
|
let r = Layout::horizontal(constraints)
|
||||||
|
.flex(Flex::Legacy)
|
||||||
.split(rect)
|
.split(rect)
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -1971,69 +1940,48 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::length(vec![(0, 100)], vec![Constraint::Length(50)], Flex::StretchLast)]
|
#[case::length(vec![(0, 100)], vec![Length(50)], Flex::Legacy)]
|
||||||
#[case::length(vec![(0, 100)], vec![Constraint::Length(50)], Flex::Stretch)]
|
#[case::length(vec![(0, 50)], vec![Length(50)], Flex::Start)]
|
||||||
#[case::length(vec![(0, 50)], vec![Constraint::Length(50)], Flex::Start)]
|
#[case::length(vec![(50, 50)], vec![Length(50)], Flex::End)]
|
||||||
#[case::length(vec![(50, 50)], vec![Constraint::Length(50)], Flex::End)]
|
#[case::length(vec![(25, 50)], vec![Length(50)], Flex::Center)]
|
||||||
#[case::length(vec![(25, 50)], vec![Constraint::Length(50)], Flex::Center)]
|
#[case::ratio(vec![(0, 100)], vec![Ratio(1, 2)], Flex::Legacy)]
|
||||||
#[case::fixed(vec![(0, 100)], vec![Fixed(50)], Flex::StretchLast)]
|
|
||||||
#[case::fixed(vec![(0, 100)], vec![Fixed(50)], Flex::Stretch)]
|
|
||||||
#[case::fixed(vec![(0, 50)], vec![Fixed(50)], Flex::Start)]
|
|
||||||
#[case::fixed(vec![(50, 50)], vec![Fixed(50)], Flex::End)]
|
|
||||||
#[case::fixed(vec![(25, 50)], vec![Fixed(50)], Flex::Center)]
|
|
||||||
#[case::ratio(vec![(0, 100)], vec![Ratio(1, 2)], Flex::StretchLast)]
|
|
||||||
#[case::ratio(vec![(0, 100)], vec![Ratio(1, 2)], Flex::Stretch)]
|
|
||||||
#[case::ratio(vec![(0, 50)], vec![Ratio(1, 2)], Flex::Start)]
|
#[case::ratio(vec![(0, 50)], vec![Ratio(1, 2)], Flex::Start)]
|
||||||
#[case::ratio(vec![(50, 50)], vec![Ratio(1, 2)], Flex::End)]
|
#[case::ratio(vec![(50, 50)], vec![Ratio(1, 2)], Flex::End)]
|
||||||
#[case::ratio(vec![(25, 50)], vec![Ratio(1, 2)], Flex::Center)]
|
#[case::ratio(vec![(25, 50)], vec![Ratio(1, 2)], Flex::Center)]
|
||||||
#[case::percent(vec![(0, 100)], vec![Percentage(50)], Flex::StretchLast)]
|
#[case::percent(vec![(0, 100)], vec![Percentage(50)], Flex::Legacy)]
|
||||||
#[case::percent(vec![(0, 100)], vec![Percentage(50)], Flex::Stretch)]
|
|
||||||
#[case::percent(vec![(0, 50)], vec![Percentage(50)], Flex::Start)]
|
#[case::percent(vec![(0, 50)], vec![Percentage(50)], Flex::Start)]
|
||||||
#[case::percent(vec![(50, 50)], vec![Percentage(50)], Flex::End)]
|
#[case::percent(vec![(50, 50)], vec![Percentage(50)], Flex::End)]
|
||||||
#[case::percent(vec![(25, 50)], vec![Percentage(50)], Flex::Center)]
|
#[case::percent(vec![(25, 50)], vec![Percentage(50)], Flex::Center)]
|
||||||
#[case::min(vec![(0, 100)], vec![Min(50)], Flex::StretchLast)]
|
#[case::min(vec![(0, 100)], vec![Min(50)], Flex::Legacy)]
|
||||||
#[case::min(vec![(0, 100)], vec![Min(50)], Flex::Stretch)]
|
#[case::min(vec![(0, 100)], vec![Min(50)], Flex::Start)]
|
||||||
#[case::min(vec![(0, 50)], vec![Min(50)], Flex::Start)]
|
#[case::min(vec![(0, 100)], vec![Min(50)], Flex::End)]
|
||||||
#[case::min(vec![(50, 50)], vec![Min(50)], Flex::End)]
|
#[case::min(vec![(0, 100)], vec![Min(50)], Flex::Center)]
|
||||||
#[case::min(vec![(25, 50)], vec![Min(50)], Flex::Center)]
|
#[case::max(vec![(0, 100)], vec![Max(50)], Flex::Legacy)]
|
||||||
#[case::max(vec![(0, 100)], vec![Max(50)], Flex::StretchLast)]
|
|
||||||
#[case::max(vec![(0, 100)], vec![Max(50)], Flex::Stretch)]
|
|
||||||
#[case::max(vec![(0, 50)], vec![Max(50)], Flex::Start)]
|
#[case::max(vec![(0, 50)], vec![Max(50)], Flex::Start)]
|
||||||
#[case::max(vec![(50, 50)], vec![Max(50)], Flex::End)]
|
#[case::max(vec![(50, 50)], vec![Max(50)], Flex::End)]
|
||||||
#[case::max(vec![(25, 50)], vec![Max(50)], Flex::Center)]
|
#[case::max(vec![(25, 50)], vec![Max(50)], Flex::Center)]
|
||||||
#[case::spacebetween_becomes_stretch(vec![(0, 100)], vec![Min(1)], Flex::SpaceBetween)]
|
#[case::spacebetween_becomes_stretch(vec![(0, 100)], vec![Min(1)], Flex::SpaceBetween)]
|
||||||
#[case::spacebetween_becomes_stretch(vec![(0, 100)], vec![Max(20)], Flex::SpaceBetween)]
|
#[case::spacebetween_becomes_stretch(vec![(0, 100)], vec![Max(20)], Flex::SpaceBetween)]
|
||||||
#[case::spacebetween_becomes_stretch(vec![(0, 100)], vec![Fixed(20)], Flex::SpaceBetween)]
|
#[case::spacebetween_becomes_stretch(vec![(0, 100)], vec![Length(20)], Flex::SpaceBetween)]
|
||||||
#[case::length(vec![(0, 25), (25, 75)], vec![Length(25), Length(25)], Flex::StretchLast)]
|
#[case::length(vec![(0, 25), (25, 75)], vec![Length(25), Length(25)], Flex::Legacy)]
|
||||||
#[case::length(vec![(0, 50), (50, 50)], vec![Length(25), Length(25)], Flex::Stretch)]
|
|
||||||
#[case::length(vec![(0, 25), (25, 25)], vec![Length(25), Length(25)], Flex::Start)]
|
#[case::length(vec![(0, 25), (25, 25)], vec![Length(25), Length(25)], Flex::Start)]
|
||||||
#[case::length(vec![(25, 25), (50, 25)], vec![Length(25), Length(25)], Flex::Center)]
|
#[case::length(vec![(25, 25), (50, 25)], vec![Length(25), Length(25)], Flex::Center)]
|
||||||
#[case::length(vec![(50, 25), (75, 25)], vec![Length(25), Length(25)], Flex::End)]
|
#[case::length(vec![(50, 25), (75, 25)], vec![Length(25), Length(25)], Flex::End)]
|
||||||
#[case::length(vec![(0, 25), (75, 25)], vec![Length(25), Length(25)], Flex::SpaceBetween)]
|
#[case::length(vec![(0, 25), (75, 25)], vec![Length(25), Length(25)], Flex::SpaceBetween)]
|
||||||
#[case::length(vec![(17, 25), (58, 25)], vec![Length(25), Length(25)], Flex::SpaceAround)]
|
#[case::length(vec![(17, 25), (58, 25)], vec![Length(25), Length(25)], Flex::SpaceAround)]
|
||||||
#[case::fixed(vec![(0, 25), (25, 75)], vec![Fixed(25), Fixed(25)], Flex::StretchLast)]
|
#[case::percentage(vec![(0, 25), (25, 75)], vec![Percentage(25), Percentage(25)], Flex::Legacy)]
|
||||||
#[case::fixed(vec![(0, 50), (50, 50)], vec![Fixed(25), Fixed(25)], Flex::Stretch)]
|
|
||||||
#[case::fixed(vec![(0, 25), (25, 25)], vec![Fixed(25), Fixed(25)], Flex::Start)]
|
|
||||||
#[case::fixed(vec![(25, 25), (50, 25)], vec![Fixed(25), Fixed(25)], Flex::Center)]
|
|
||||||
#[case::fixed(vec![(50, 25), (75, 25)], vec![Fixed(25), Fixed(25)], Flex::End)]
|
|
||||||
#[case::fixed(vec![(0, 25), (75, 25)], vec![Fixed(25), Fixed(25)], Flex::SpaceBetween)]
|
|
||||||
#[case::fixed(vec![(17, 25), (58, 25)], vec![Fixed(25), Fixed(25)], Flex::SpaceAround)]
|
|
||||||
#[case::percentage(vec![(0, 25), (25, 75)], vec![Percentage(25), Percentage(25)], Flex::StretchLast)]
|
|
||||||
#[case::percentage(vec![(0, 50), (50, 50)], vec![Percentage(25), Percentage(25)], Flex::Stretch)]
|
|
||||||
#[case::percentage(vec![(0, 25), (25, 25)], vec![Percentage(25), Percentage(25)], Flex::Start)]
|
#[case::percentage(vec![(0, 25), (25, 25)], vec![Percentage(25), Percentage(25)], Flex::Start)]
|
||||||
#[case::percentage(vec![(25, 25), (50, 25)], vec![Percentage(25), Percentage(25)], Flex::Center)]
|
#[case::percentage(vec![(25, 25), (50, 25)], vec![Percentage(25), Percentage(25)], Flex::Center)]
|
||||||
#[case::percentage(vec![(50, 25), (75, 25)], vec![Percentage(25), Percentage(25)], Flex::End)]
|
#[case::percentage(vec![(50, 25), (75, 25)], vec![Percentage(25), Percentage(25)], Flex::End)]
|
||||||
#[case::percentage(vec![(0, 25), (75, 25)], vec![Percentage(25), Percentage(25)], Flex::SpaceBetween)]
|
#[case::percentage(vec![(0, 25), (75, 25)], vec![Percentage(25), Percentage(25)], Flex::SpaceBetween)]
|
||||||
#[case::percentage(vec![(17, 25), (58, 25)], vec![Percentage(25), Percentage(25)], Flex::SpaceAround)]
|
#[case::percentage(vec![(17, 25), (58, 25)], vec![Percentage(25), Percentage(25)], Flex::SpaceAround)]
|
||||||
#[case::min(vec![(0, 25), (25, 75)], vec![Min(25), Min(25)], Flex::StretchLast)]
|
#[case::min(vec![(0, 25), (25, 75)], vec![Min(25), Min(25)], Flex::Legacy)]
|
||||||
#[case::min(vec![(0, 50), (50, 50)], vec![Min(25), Min(25)], Flex::Stretch)]
|
#[case::min(vec![(0, 50), (50, 50)], vec![Min(25), Min(25)], Flex::Start)]
|
||||||
#[case::min(vec![(0, 25), (25, 25)], vec![Min(25), Min(25)], Flex::Start)]
|
#[case::min(vec![(0, 50), (50, 50)], vec![Min(25), Min(25)], Flex::Center)]
|
||||||
#[case::min(vec![(25, 25), (50, 25)], vec![Min(25), Min(25)], Flex::Center)]
|
#[case::min(vec![(0, 50), (50, 50)], vec![Min(25), Min(25)], Flex::End)]
|
||||||
#[case::min(vec![(50, 25), (75, 25)], vec![Min(25), Min(25)], Flex::End)]
|
#[case::min(vec![(0, 50), (50, 50)], vec![Min(25), Min(25)], Flex::SpaceBetween)]
|
||||||
#[case::min(vec![(0, 25), (75, 25)], vec![Min(25), Min(25)], Flex::SpaceBetween)]
|
#[case::min(vec![(0, 50), (50, 50)], vec![Min(25), Min(25)], Flex::SpaceAround)]
|
||||||
#[case::min(vec![(17, 25), (58, 25)], vec![Min(25), Min(25)], Flex::SpaceAround)]
|
#[case::max(vec![(0, 25), (25, 75)], vec![Max(25), Max(25)], Flex::Legacy)]
|
||||||
#[case::max(vec![(0, 25), (25, 75)], vec![Max(25), Max(25)], Flex::StretchLast)]
|
|
||||||
#[case::max(vec![(0, 50), (50, 50)], vec![Max(25), Max(25)], Flex::Stretch)]
|
|
||||||
#[case::max(vec![(0, 25), (25, 25)], vec![Max(25), Max(25)], Flex::Start)]
|
#[case::max(vec![(0, 25), (25, 25)], vec![Max(25), Max(25)], Flex::Start)]
|
||||||
#[case::max(vec![(25, 25), (50, 25)], vec![Max(25), Max(25)], Flex::Center)]
|
#[case::max(vec![(25, 25), (50, 25)], vec![Max(25), Max(25)], Flex::Center)]
|
||||||
#[case::max(vec![(50, 25), (75, 25)], vec![Max(25), Max(25)], Flex::End)]
|
#[case::max(vec![(50, 25), (75, 25)], vec![Max(25), Max(25)], Flex::End)]
|
||||||
@ -2061,11 +2009,9 @@ mod tests {
|
|||||||
#[case::length_spacing(vec![(0 , 20), (22, 20) , (44, 20)], vec![Length(20), Length(20), Length(20)], Flex::Start , 2)]
|
#[case::length_spacing(vec![(0 , 20), (22, 20) , (44, 20)], vec![Length(20), Length(20), Length(20)], Flex::Start , 2)]
|
||||||
#[case::length_spacing(vec![(18, 20), (40, 20) , (62, 20)], vec![Length(20), Length(20), Length(20)], Flex::Center , 2)]
|
#[case::length_spacing(vec![(18, 20), (40, 20) , (62, 20)], vec![Length(20), Length(20), Length(20)], Flex::Center , 2)]
|
||||||
#[case::length_spacing(vec![(36, 20), (58, 20) , (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::End , 2)]
|
#[case::length_spacing(vec![(36, 20), (58, 20) , (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::End , 2)]
|
||||||
#[case::length_spacing(vec![(0 , 32), (34, 32) , (68, 32)], vec![Length(20), Length(20), Length(20)], Flex::Stretch , 2)]
|
#[case::length_spacing(vec![(0 , 20), (22, 20) , (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::Legacy , 2)]
|
||||||
#[case::length_spacing(vec![(0 , 20), (22, 20) , (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::StretchLast, 2)]
|
#[case::length_spacing(vec![(0 , 20), (40, 20) , (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceBetween, 2)]
|
||||||
#[case::fixed_spacing(vec![(0 , 20), (22, 20) , (44, 56)], vec![Fixed(20) , Fixed(20) , Fixed(20)] , Flex::StretchLast, 2)]
|
#[case::length_spacing(vec![(10, 20), (40, 20) , (70, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceAround, 2)]
|
||||||
#[case::fixed_spacing(vec![(0 , 32), (34, 32) , (68, 32)], vec![Fixed(20) , Fixed(20) , Fixed(20)] , Flex::Stretch , 2)]
|
|
||||||
#[case::fixed_spacing(vec![(10 , 20), (40, 20) , (70, 20)], vec![Fixed(20) , Fixed(20) , Fixed(20)] , Flex::SpaceAround, 2)]
|
|
||||||
fn flex_spacing(
|
fn flex_spacing(
|
||||||
#[case] expected: Vec<(u16, u16)>,
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
#[case] constraints: Vec<Constraint>,
|
#[case] constraints: Vec<Constraint>,
|
||||||
@ -2085,30 +2031,30 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::a(vec![(0, 25), (25, 75)], vec![Fixed(25), Length(25)])]
|
#[case::a(vec![(0, 25), (25, 75)], vec![Length(25), Length(25)])]
|
||||||
#[case::b(vec![(0, 75), (75, 25)], vec![Length(25), Fixed(25)])]
|
#[case::b(vec![(0, 25), (25, 75)], vec![Length(25), Percentage(25)])]
|
||||||
#[case::c(vec![(0, 25), (25, 75)], vec![Length(25), Percentage(25)])]
|
#[case::c(vec![(0, 75), (75, 25)], vec![Percentage(25), Length(25)])]
|
||||||
#[case::d(vec![(0, 75), (75, 25)], vec![Percentage(25), Length(25)])]
|
#[case::d(vec![(0, 75), (75, 25)], vec![Min(25), Percentage(25)])]
|
||||||
#[case::e(vec![(0, 75), (75, 25)], vec![Min(25), Percentage(25)])]
|
#[case::e(vec![(0, 25), (25, 75)], vec![Percentage(25), Min(25)])]
|
||||||
#[case::f(vec![(0, 25), (25, 75)], vec![Percentage(25), Min(25)])]
|
#[case::f(vec![(0, 25), (25, 75)], vec![Min(25), Percentage(100)])]
|
||||||
#[case::g(vec![(0, 25), (25, 75)], vec![Min(25), Percentage(100)])]
|
#[case::g(vec![(0, 75), (75, 25)], vec![Percentage(100), Min(25)])]
|
||||||
#[case::h(vec![(0, 75), (75, 25)], vec![Percentage(100), Min(25)])]
|
#[case::h(vec![(0, 25), (25, 75)], vec![Max(75), Percentage(75)])]
|
||||||
#[case::i(vec![(0, 25), (25, 75)], vec![Max(75), Percentage(75)])]
|
#[case::i(vec![(0, 75), (75, 25)], vec![Percentage(75), Max(75)])]
|
||||||
#[case::j(vec![(0, 75), (75, 25)], vec![Percentage(75), Max(75)])]
|
#[case::j(vec![(0, 25), (25, 75)], vec![Max(25), Percentage(25)])]
|
||||||
#[case::k(vec![(0, 25), (25, 75)], vec![Max(25), Percentage(25)])]
|
#[case::k(vec![(0, 75), (75, 25)], vec![Percentage(25), Max(25)])]
|
||||||
#[case::l(vec![(0, 75), (75, 25)], vec![Percentage(25), Max(25)])]
|
#[case::l(vec![(0, 25), (25, 75)], vec![Length(25), Ratio(1, 4)])]
|
||||||
#[case::m(vec![(0, 25), (25, 75)], vec![Length(25), Ratio(1, 4)])]
|
#[case::m(vec![(0, 75), (75, 25)], vec![Ratio(1, 4), Length(25)])]
|
||||||
#[case::n(vec![(0, 75), (75, 25)], vec![Ratio(1, 4), Length(25)])]
|
#[case::n(vec![(0, 25), (25, 75)], vec![Percentage(25), Ratio(1, 4)])]
|
||||||
#[case::o(vec![(0, 25), (25, 75)], vec![Percentage(25), Ratio(1, 4)])]
|
#[case::o(vec![(0, 75), (75, 25)], vec![Ratio(1, 4), Percentage(25)])]
|
||||||
#[case::p(vec![(0, 75), (75, 25)], vec![Ratio(1, 4), Percentage(25)])]
|
#[case::p(vec![(0, 25), (25, 75)], vec![Ratio(1, 4), Fill(25)])]
|
||||||
#[case::q(vec![(0, 25), (25, 75)], vec![Ratio(1, 4), Fill(25)])]
|
#[case::q(vec![(0, 75), (75, 25)], vec![Fill(25), Ratio(1, 4)])]
|
||||||
#[case::r(vec![(0, 75), (75, 25)], vec![Fill(25), Ratio(1, 4)])]
|
|
||||||
fn constraint_specification_tests_for_priority(
|
fn constraint_specification_tests_for_priority(
|
||||||
#[case] expected: Vec<(u16, u16)>,
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
#[case] constraints: Vec<Constraint>,
|
#[case] constraints: Vec<Constraint>,
|
||||||
) {
|
) {
|
||||||
let rect = Rect::new(0, 0, 100, 1);
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
let r = Layout::horizontal(constraints)
|
let r = Layout::horizontal(constraints)
|
||||||
|
.flex(Flex::Legacy)
|
||||||
.split(rect)
|
.split(rect)
|
||||||
.iter()
|
.iter()
|
||||||
.cloned()
|
.cloned()
|
||||||
@ -2121,11 +2067,9 @@ mod tests {
|
|||||||
#[case::a(vec![(0, 20), (20, 20), (40, 20)], vec![Length(20), Length(20), Length(20)], Flex::Start, 0)]
|
#[case::a(vec![(0, 20), (20, 20), (40, 20)], vec![Length(20), Length(20), Length(20)], Flex::Start, 0)]
|
||||||
#[case::b(vec![(18, 20), (40, 20), (62, 20)], vec![Length(20), Length(20), Length(20)], Flex::Center, 2)]
|
#[case::b(vec![(18, 20), (40, 20), (62, 20)], vec![Length(20), Length(20), Length(20)], Flex::Center, 2)]
|
||||||
#[case::c(vec![(36, 20), (58, 20), (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::End, 2)]
|
#[case::c(vec![(36, 20), (58, 20), (80, 20)], vec![Length(20), Length(20), Length(20)], Flex::End, 2)]
|
||||||
#[case::d(vec![(0, 32), (34, 32), (68, 32)], vec![Length(20), Length(20), Length(20)], Flex::Stretch, 2)]
|
#[case::d(vec![(0, 20), (22, 20), (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::Legacy, 2)]
|
||||||
#[case::e(vec![(0, 20), (22, 20), (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::StretchLast, 2)]
|
#[case::e(vec![(0, 20), (22, 20), (44, 56)], vec![Length(20), Length(20), Length(20)], Flex::Legacy, 2)]
|
||||||
#[case::f(vec![(0, 20), (22, 20), (44, 56)], vec![Fixed(20), Fixed(20), Fixed(20)], Flex::StretchLast, 2)]
|
#[case::f(vec![(10, 20), (40, 20), (70, 20)], vec![Length(20), Length(20), Length(20)], Flex::SpaceAround, 2)]
|
||||||
#[case::g(vec![(0, 32), (34, 32), (68, 32)], vec![Fixed(20), Fixed(20), Fixed(20)], Flex::Stretch, 2)]
|
|
||||||
#[case::h(vec![(10, 20), (40, 20), (70, 20)], vec![Fixed(20), Fixed(20), Fixed(20)], Flex::SpaceAround, 2)]
|
|
||||||
fn constraint_specification_tests_for_priority_with_spacing(
|
fn constraint_specification_tests_for_priority_with_spacing(
|
||||||
#[case] expected: Vec<(u16, u16)>,
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
#[case] constraints: Vec<Constraint>,
|
#[case] constraints: Vec<Constraint>,
|
||||||
@ -2145,16 +2089,16 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::prop(vec![(0 , 10), (10, 80), (90 , 10)] , vec![Fixed(10), Fill(1), Fixed(10)], Flex::Stretch)]
|
#[case::prop(vec![(0 , 10), (10, 80), (90 , 10)] , vec![Length(10), Fill(1), Length(10)], Flex::Legacy)]
|
||||||
#[case::flex(vec![(0 , 10), (90 , 10)] , vec![Fixed(10), Fixed(10)], Flex::SpaceBetween)]
|
#[case::flex(vec![(0 , 10), (90 , 10)] , vec![Length(10), Length(10)], Flex::SpaceBetween)]
|
||||||
#[case::prop(vec![(0 , 27), (27, 10), (37, 26), (63, 10), (73, 27)] , vec![Fill(1), Fixed(10), Fill(1), Fixed(10), Fill(1)], Flex::Stretch)]
|
#[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)]
|
||||||
#[case::flex(vec![(27 , 10), (63, 10)] , vec![Fixed(10), Fixed(10)], Flex::SpaceAround)]
|
#[case::flex(vec![(27 , 10), (63, 10)] , vec![Length(10), Length(10)], Flex::SpaceAround)]
|
||||||
#[case::prop(vec![(0 , 10), (10, 10), (20 , 80)] , vec![Fixed(10), Fixed(10), Fill(1)], Flex::Stretch)]
|
#[case::prop(vec![(0 , 10), (10, 10), (20 , 80)] , vec![Length(10), Length(10), Fill(1)], Flex::Legacy)]
|
||||||
#[case::flex(vec![(0 , 10), (10, 10)] , vec![Fixed(10), Fixed(10)], Flex::Start)]
|
#[case::flex(vec![(0 , 10), (10, 10)] , vec![Length(10), Length(10)], Flex::Start)]
|
||||||
#[case::prop(vec![(0 , 80), (80 , 10), (90, 10)] , vec![Fill(1), Fixed(10), Fixed(10)], Flex::Stretch)]
|
#[case::prop(vec![(0 , 80), (80 , 10), (90, 10)] , vec![Fill(1), Length(10), Length(10)], Flex::Legacy)]
|
||||||
#[case::flex(vec![(80 , 10), (90, 10)] , vec![Fixed(10), Fixed(10)], Flex::End)]
|
#[case::flex(vec![(80 , 10), (90, 10)] , vec![Length(10), Length(10)], Flex::End)]
|
||||||
#[case::prop(vec![(0 , 40), (40, 10), (50, 10), (60, 40)] , vec![Fill(1), Fixed(10), Fixed(10), Fill(1)], Flex::Stretch)]
|
#[case::prop(vec![(0 , 40), (40, 10), (50, 10), (60, 40)] , vec![Fill(1), Length(10), Length(10), Fill(1)], Flex::Legacy)]
|
||||||
#[case::flex(vec![(40 , 10), (50, 10)] , vec![Fixed(10), Fixed(10)], Flex::Center)]
|
#[case::flex(vec![(40 , 10), (50, 10)] , vec![Length(10), Length(10)], Flex::Center)]
|
||||||
fn fill_vs_flex(
|
fn fill_vs_flex(
|
||||||
#[case] expected: Vec<(u16, u16)>,
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
#[case] constraints: Vec<Constraint>,
|
#[case] constraints: Vec<Constraint>,
|
||||||
@ -2170,36 +2114,32 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Stretch , 0)]
|
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Legacy , 0)]
|
||||||
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::StretchLast , 0)]
|
|
||||||
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , 0)]
|
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , 0)]
|
||||||
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , 0)]
|
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , 0)]
|
||||||
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Start , 0)]
|
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Start , 0)]
|
||||||
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Center , 0)]
|
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::Center , 0)]
|
||||||
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::End , 0)]
|
#[case::flex0(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::End , 0)]
|
||||||
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Stretch , 10)]
|
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Legacy , 10)]
|
||||||
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::StretchLast , 10)]
|
|
||||||
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Start , 10)]
|
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Start , 10)]
|
||||||
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Center , 10)]
|
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::Center , 10)]
|
||||||
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::End , 10)]
|
#[case::flex10(vec![(0 , 45), (55 , 45)] , vec![Fill(1), Fill(1)], Flex::End , 10)]
|
||||||
// SpaceAround and SpaceBetween spacers behave differently from other flexes
|
// SpaceAround and SpaceBetween spacers behave differently from other flexes
|
||||||
#[case::flex10(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , 10)]
|
#[case::flex10(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceAround , 10)]
|
||||||
#[case::flex10(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , 10)]
|
#[case::flex10(vec![(0 , 50), (50 , 50)] , vec![Fill(1), Fill(1)], Flex::SpaceBetween , 10)]
|
||||||
#[case::flex_fixed0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::Stretch , 0)]
|
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::Legacy , 0)]
|
||||||
#[case::flex_fixed0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::StretchLast , 0)]
|
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceAround , 0)]
|
||||||
#[case::flex_fixed0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::SpaceAround , 0)]
|
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceBetween , 0)]
|
||||||
#[case::flex_fixed0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::SpaceBetween , 0)]
|
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::Start , 0)]
|
||||||
#[case::flex_fixed0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::Start , 0)]
|
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::Center , 0)]
|
||||||
#[case::flex_fixed0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::Center , 0)]
|
#[case::flex_length0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::End , 0)]
|
||||||
#[case::flex_fixed0(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::End , 0)]
|
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::Legacy , 10)]
|
||||||
#[case::flex_fixed10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::Stretch , 10)]
|
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::Start , 10)]
|
||||||
#[case::flex_fixed10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::StretchLast , 10)]
|
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::Center , 10)]
|
||||||
#[case::flex_fixed10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::Start , 10)]
|
#[case::flex_length10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Length(10), Fill(1)], Flex::End , 10)]
|
||||||
#[case::flex_fixed10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::Center , 10)]
|
|
||||||
#[case::flex_fixed10(vec![(0 , 35), (45, 10), (65 , 35)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::End , 10)]
|
|
||||||
// SpaceAround and SpaceBetween spacers behave differently from other flexes
|
// SpaceAround and SpaceBetween spacers behave differently from other flexes
|
||||||
#[case::flex_fixed10(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::SpaceAround , 10)]
|
#[case::flex_length10(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceAround , 10)]
|
||||||
#[case::flex_fixed10(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Fixed(10), Fill(1)], Flex::SpaceBetween , 10)]
|
#[case::flex_length10(vec![(0 , 45), (45, 10), (55 , 45)] , vec![Fill(1), Length(10), Fill(1)], Flex::SpaceBetween , 10)]
|
||||||
fn fill_spacing(
|
fn fill_spacing(
|
||||||
#[case] expected: Vec<(u16, u16)>,
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
#[case] constraints: Vec<Constraint>,
|
#[case] constraints: Vec<Constraint>,
|
||||||
@ -2219,7 +2159,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::flex_fixed10(vec![(0, 10), (90, 10)], vec![Length(10), Length(10)], Flex::Center, 80)]
|
#[case::flex_length10(vec![(0, 10), (90, 10)], vec![Length(10), Length(10)], Flex::Center, 80)]
|
||||||
fn flex_spacing_lower_priority_than_user_spacing(
|
fn flex_spacing_lower_priority_than_user_spacing(
|
||||||
#[case] expected: Vec<(u16, u16)>,
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
#[case] constraints: Vec<Constraint>,
|
#[case] constraints: Vec<Constraint>,
|
||||||
@ -2239,8 +2179,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::spacers(vec![(0, 0), (10, 0), (100, 0)], vec![Length(10), Length(10)], Flex::StretchLast)]
|
#[case::spacers(vec![(0, 0), (10, 0), (100, 0)], vec![Length(10), Length(10)], Flex::Legacy)]
|
||||||
#[case::spacers(vec![(0, 0), (50, 0), (100, 0)], vec![Length(10), Length(10)], Flex::Stretch)]
|
|
||||||
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween)]
|
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween)]
|
||||||
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceAround)]
|
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceAround)]
|
||||||
#[case::spacers(vec![(0, 0), (10, 0), (20, 80)], vec![Length(10), Length(10)], Flex::Start)]
|
#[case::spacers(vec![(0, 0), (10, 0), (20, 80)], vec![Length(10), Length(10)], Flex::Start)]
|
||||||
@ -2264,8 +2203,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::spacers(vec![(0, 0), (10, 5), (100, 0)], vec![Length(10), Length(10)], Flex::StretchLast, 5)]
|
#[case::spacers(vec![(0, 0), (10, 5), (100, 0)], vec![Length(10), Length(10)], Flex::Legacy, 5)]
|
||||||
#[case::spacers(vec![(0, 0), (48, 5), (100, 0)], vec![Length(10), Length(10)], Flex::Stretch, 5)]
|
|
||||||
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween, 5)]
|
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween, 5)]
|
||||||
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceAround, 5)]
|
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceAround, 5)]
|
||||||
#[case::spacers(vec![(0, 0), (10, 5), (25, 75)], vec![Length(10), Length(10)], Flex::Start, 5)]
|
#[case::spacers(vec![(0, 0), (10, 5), (25, 75)], vec![Length(10), Length(10)], Flex::Start, 5)]
|
||||||
@ -2291,8 +2229,7 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[rstest]
|
#[rstest]
|
||||||
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::StretchLast, 200)]
|
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::Legacy, 200)]
|
||||||
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::Stretch, 200)]
|
|
||||||
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween, 200)]
|
#[case::spacers(vec![(0, 0), (10, 80), (100, 0)], vec![Length(10), Length(10)], Flex::SpaceBetween, 200)]
|
||||||
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceAround, 200)]
|
#[case::spacers(vec![(0, 27), (37, 26), (73, 27)], vec![Length(10), Length(10)], Flex::SpaceAround, 200)]
|
||||||
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::Start, 200)]
|
#[case::spacers(vec![(0, 0), (0, 100), (100, 0)], vec![Length(10), Length(10)], Flex::Start, 200)]
|
||||||
@ -2316,6 +2253,27 @@ mod tests {
|
|||||||
.collect::<Vec<(u16, u16)>>();
|
.collect::<Vec<(u16, u16)>>();
|
||||||
assert_eq!(expected, result);
|
assert_eq!(expected, result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[rstest]
|
||||||
|
#[case::compare(vec![(0, 90), (90, 10)], vec![Min(10), Length(10)], Flex::Legacy)]
|
||||||
|
#[case::compare(vec![(0, 90), (90, 10)], vec![Min(10), Length(10)], Flex::Start)]
|
||||||
|
#[case::compare(vec![(0, 10), (10, 90)], vec![Min(10), Percentage(100)], Flex::Legacy)]
|
||||||
|
#[case::compare(vec![(0, 10), (10, 90)], vec![Min(10), Percentage(100)], Flex::Start)]
|
||||||
|
#[case::compare(vec![(0, 50), (50, 50)], vec![Percentage(50), Percentage(50)], Flex::Legacy)]
|
||||||
|
#[case::compare(vec![(0, 50), (50, 50)], vec![Percentage(50), Percentage(50)], Flex::Start)]
|
||||||
|
fn legacy_vs_default(
|
||||||
|
#[case] expected: Vec<(u16, u16)>,
|
||||||
|
#[case] constraints: Vec<Constraint>,
|
||||||
|
#[case] flex: Flex,
|
||||||
|
) {
|
||||||
|
let rect = Rect::new(0, 0, 100, 1);
|
||||||
|
let r = Layout::horizontal(constraints).flex(flex).split(rect);
|
||||||
|
let result = r
|
||||||
|
.iter()
|
||||||
|
.map(|r| (r.x, r.width))
|
||||||
|
.collect::<Vec<(u16, u16)>>();
|
||||||
|
assert_eq!(expected, result);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
|
@ -1,147 +0,0 @@
|
|||||||
use strum::{Display, EnumString};
|
|
||||||
|
|
||||||
/// Option for segment size preferences
|
|
||||||
///
|
|
||||||
/// This controls how the space is distributed when the constraints are satisfied. By default, the
|
|
||||||
/// last chunk is expanded to fill the remaining space, but this can be changed to prefer equal
|
|
||||||
/// chunks or to not distribute extra space at all (which is the default used for laying out the
|
|
||||||
/// columns for [`Table`] widgets).
|
|
||||||
///
|
|
||||||
/// Note: If you're using this feature please help us come up with a good name. See [Issue
|
|
||||||
/// #536](https://github.com/ratatui-org/ratatui/issues/536) for more information.
|
|
||||||
///
|
|
||||||
/// [`Table`]: crate::widgets::Table
|
|
||||||
#[stability::unstable(
|
|
||||||
feature = "segment-size",
|
|
||||||
reason = "The name for this feature is not final and may change in the future",
|
|
||||||
issue = "https://github.com/ratatui-org/ratatui/issues/536"
|
|
||||||
)]
|
|
||||||
#[derive(Copy, Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash)]
|
|
||||||
pub enum SegmentSize {
|
|
||||||
/// prefer equal chunks if other constraints are all satisfied
|
|
||||||
EvenDistribution,
|
|
||||||
|
|
||||||
/// the last chunk is expanded to fill the remaining space
|
|
||||||
#[default]
|
|
||||||
LastTakesRemainder,
|
|
||||||
|
|
||||||
/// extra space is not distributed
|
|
||||||
None,
|
|
||||||
}
|
|
||||||
#[cfg(test)]
|
|
||||||
mod tests {
|
|
||||||
use strum::ParseError;
|
|
||||||
|
|
||||||
use super::{SegmentSize::*, *};
|
|
||||||
use crate::prelude::{Constraint::*, *};
|
|
||||||
#[test]
|
|
||||||
fn segment_size_to_string() {
|
|
||||||
assert_eq!(EvenDistribution.to_string(), "EvenDistribution");
|
|
||||||
assert_eq!(LastTakesRemainder.to_string(), "LastTakesRemainder");
|
|
||||||
assert_eq!(None.to_string(), "None");
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn segment_size_from_string() {
|
|
||||||
assert_eq!(
|
|
||||||
"EvenDistribution".parse::<SegmentSize>(),
|
|
||||||
Ok(EvenDistribution)
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
"LastTakesRemainder".parse::<SegmentSize>(),
|
|
||||||
Ok(LastTakesRemainder)
|
|
||||||
);
|
|
||||||
assert_eq!("None".parse::<SegmentSize>(), Ok(None));
|
|
||||||
assert_eq!("".parse::<SegmentSize>(), Err(ParseError::VariantNotFound));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_x_width_with_segment_size(
|
|
||||||
segment_size: SegmentSize,
|
|
||||||
constraints: Vec<Constraint>,
|
|
||||||
target: Rect,
|
|
||||||
) -> Vec<(u16, u16)> {
|
|
||||||
#[allow(deprecated)]
|
|
||||||
let layout = Layout::default()
|
|
||||||
.direction(Direction::Horizontal)
|
|
||||||
.constraints(constraints)
|
|
||||||
.segment_size(segment_size);
|
|
||||||
let chunks = layout.split(target);
|
|
||||||
chunks.iter().map(|r| (r.x, r.width)).collect()
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_split_equally_in_underspecified_case() {
|
|
||||||
let target = Rect::new(100, 200, 10, 10);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(LastTakesRemainder, vec![Min(2), Min(2), Min(0)], target),
|
|
||||||
[(100, 2), (102, 2), (104, 6)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(EvenDistribution, vec![Min(2), Min(2), Min(0)], target),
|
|
||||||
[(100, 3), (103, 4), (107, 3)]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_split_equally_in_overconstrained_case_for_min() {
|
|
||||||
let target = Rect::new(100, 200, 100, 10);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(
|
|
||||||
LastTakesRemainder,
|
|
||||||
vec![Percentage(50), Min(10), Percentage(50)],
|
|
||||||
target
|
|
||||||
),
|
|
||||||
[(100, 50), (150, 10), (160, 40)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(
|
|
||||||
EvenDistribution,
|
|
||||||
vec![Percentage(50), Min(10), Percentage(50)],
|
|
||||||
target
|
|
||||||
),
|
|
||||||
[(100, 45), (145, 10), (155, 45)]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_split_equally_in_overconstrained_case_for_max() {
|
|
||||||
let target = Rect::new(100, 200, 100, 10);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(
|
|
||||||
LastTakesRemainder,
|
|
||||||
vec![Percentage(30), Max(10), Percentage(30)],
|
|
||||||
target
|
|
||||||
),
|
|
||||||
[(100, 30), (130, 10), (140, 60)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(
|
|
||||||
EvenDistribution,
|
|
||||||
vec![Percentage(30), Max(10), Percentage(30)],
|
|
||||||
target
|
|
||||||
),
|
|
||||||
[(100, 45), (145, 10), (155, 45)]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
#[test]
|
|
||||||
fn test_split_equally_in_overconstrained_case_for_length() {
|
|
||||||
let target = Rect::new(100, 200, 100, 10);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(
|
|
||||||
LastTakesRemainder,
|
|
||||||
vec![Percentage(50), Length(10), Percentage(50)],
|
|
||||||
target
|
|
||||||
),
|
|
||||||
[(100, 50), (150, 10), (160, 40)]
|
|
||||||
);
|
|
||||||
assert_eq!(
|
|
||||||
get_x_width_with_segment_size(
|
|
||||||
EvenDistribution,
|
|
||||||
vec![Percentage(50), Length(10), Percentage(50)],
|
|
||||||
target
|
|
||||||
),
|
|
||||||
[(100, 45), (145, 10), (155, 45)]
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,11 +1,7 @@
|
|||||||
use itertools::Itertools;
|
use itertools::Itertools;
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
use crate::{
|
use crate::{layout::Flex, prelude::*, widgets::Block};
|
||||||
layout::{Flex, SegmentSize},
|
|
||||||
prelude::*,
|
|
||||||
widgets::Block,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A widget to display data in formatted columns.
|
/// A widget to display data in formatted columns.
|
||||||
///
|
///
|
||||||
@ -539,42 +535,6 @@ impl<'a> Table<'a> {
|
|||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Set how extra space is distributed amongst columns.
|
|
||||||
///
|
|
||||||
/// This determines how the space is distributed when the constraints are satisfied. By default,
|
|
||||||
/// the extra space is not distributed at all. But this can be changed to distribute all extra
|
|
||||||
/// space to the last column or to distribute it equally.
|
|
||||||
///
|
|
||||||
/// This is a fluent setter method which must be chained or used as it consumes self
|
|
||||||
///
|
|
||||||
/// # Examples
|
|
||||||
///
|
|
||||||
/// Create a table that needs at least 30 columns to display. Any extra space will be assigned
|
|
||||||
/// to the last column.
|
|
||||||
#[cfg_attr(feature = "unstable", doc = " ```")]
|
|
||||||
#[cfg_attr(not(feature = "unstable"), doc = " ```ignore")]
|
|
||||||
/// # use ratatui::layout::{Constraint, SegmentSize};
|
|
||||||
/// # use ratatui::widgets::{Table, Row};
|
|
||||||
/// let widths = [Constraint::Min(10), Constraint::Min(10), Constraint::Min(10)];
|
|
||||||
/// let table = Table::new(Vec::<Row>::new(), widths)
|
|
||||||
/// .segment_size(SegmentSize::LastTakesRemainder);
|
|
||||||
/// ```
|
|
||||||
#[stability::unstable(
|
|
||||||
feature = "segment-size",
|
|
||||||
reason = "The name for this feature is not final and may change in the future",
|
|
||||||
issue = "https://github.com/ratatui-org/ratatui/issues/536"
|
|
||||||
)]
|
|
||||||
#[deprecated(since = "0.26.0", note = "You should use Table::flex instead.")]
|
|
||||||
pub const fn segment_size(self, segment_size: SegmentSize) -> Self {
|
|
||||||
let translated_to_flex = match segment_size {
|
|
||||||
SegmentSize::None => Flex::Start,
|
|
||||||
SegmentSize::EvenDistribution => Flex::Stretch,
|
|
||||||
SegmentSize::LastTakesRemainder => Flex::StretchLast,
|
|
||||||
};
|
|
||||||
|
|
||||||
self.flex(translated_to_flex)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Set how extra space is distributed amongst columns.
|
/// Set how extra space is distributed amongst columns.
|
||||||
///
|
///
|
||||||
/// This determines how the space is distributed when the constraints are satisfied. By default,
|
/// This determines how the space is distributed when the constraints are satisfied. By default,
|
||||||
@ -595,7 +555,7 @@ impl<'a> Table<'a> {
|
|||||||
/// Constraint::Min(10),
|
/// Constraint::Min(10),
|
||||||
/// Constraint::Min(10),
|
/// Constraint::Min(10),
|
||||||
/// ];
|
/// ];
|
||||||
/// let table = Table::new(Vec::<Row>::new(), widths).flex(Flex::StretchLast);
|
/// let table = Table::new(Vec::<Row>::new(), widths).flex(Flex::Legacy);
|
||||||
/// ```
|
/// ```
|
||||||
pub const fn flex(mut self, flex: Flex) -> Self {
|
pub const fn flex(mut self, flex: Flex) -> Self {
|
||||||
self.flex = flex;
|
self.flex = flex;
|
||||||
@ -774,7 +734,7 @@ impl Table<'_> {
|
|||||||
// this will always allocate a selection area
|
// this will always allocate a selection area
|
||||||
let [_selection_area, columns_area] =
|
let [_selection_area, columns_area] =
|
||||||
Rect::new(0, 0, max_width, 1).split(&Layout::horizontal([
|
Rect::new(0, 0, max_width, 1).split(&Layout::horizontal([
|
||||||
Constraint::Fixed(selection_width),
|
Constraint::Length(selection_width),
|
||||||
Constraint::Fill(0),
|
Constraint::Fill(0),
|
||||||
]));
|
]));
|
||||||
let rects = Layout::horizontal(widths)
|
let rects = Layout::horizontal(widths)
|
||||||
@ -1246,16 +1206,16 @@ mod tests {
|
|||||||
|
|
||||||
// without selection, less than needed width
|
// without selection, less than needed width
|
||||||
let table = Table::default().widths([Length(4), Length(4)]);
|
let table = Table::default().widths([Length(4), Length(4)]);
|
||||||
assert_eq!(table.get_columns_widths(7, 0), [(0, 4), (5, 2)]);
|
assert_eq!(table.get_columns_widths(7, 0), [(0, 3), (4, 3)]);
|
||||||
|
|
||||||
// with selection, less than needed width
|
// with selection, less than needed width
|
||||||
// <--------7px-------->
|
// <--------7px-------->
|
||||||
// ┌────────┐x┌────────┐
|
// ┌────────┐x┌────────┐
|
||||||
// │ (3, 3) │x│ (7, 0) │
|
// │ (3, 2) │x│ (6, 1) │
|
||||||
// └────────┘x└────────┘
|
// └────────┘x└────────┘
|
||||||
// column spacing (i.e. `x`) is always prioritized
|
// column spacing (i.e. `x`) is always prioritized
|
||||||
let table = Table::default().widths([Length(4), Length(4)]);
|
let table = Table::default().widths([Length(4), Length(4)]);
|
||||||
assert_eq!(table.get_columns_widths(7, 3), [(3, 3), (7, 0)]);
|
assert_eq!(table.get_columns_widths(7, 3), [(3, 2), (6, 1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1270,11 +1230,11 @@ mod tests {
|
|||||||
|
|
||||||
// without selection, less than needed width
|
// without selection, less than needed width
|
||||||
let table = Table::default().widths([Max(4), Max(4)]);
|
let table = Table::default().widths([Max(4), Max(4)]);
|
||||||
assert_eq!(table.get_columns_widths(7, 0), [(0, 4), (5, 2)]);
|
assert_eq!(table.get_columns_widths(7, 0), [(0, 3), (4, 3)]);
|
||||||
|
|
||||||
// with selection, less than needed width
|
// with selection, less than needed width
|
||||||
let table = Table::default().widths([Max(4), Max(4)]);
|
let table = Table::default().widths([Max(4), Max(4)]);
|
||||||
assert_eq!(table.get_columns_widths(7, 3), [(3, 3), (7, 0)]);
|
assert_eq!(table.get_columns_widths(7, 3), [(3, 2), (6, 1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1285,21 +1245,21 @@ mod tests {
|
|||||||
|
|
||||||
// without selection, more than needed width
|
// without selection, more than needed width
|
||||||
let table = Table::default().widths([Min(4), Min(4)]);
|
let table = Table::default().widths([Min(4), Min(4)]);
|
||||||
assert_eq!(table.get_columns_widths(20, 0), [(0, 4), (5, 4)]);
|
assert_eq!(table.get_columns_widths(20, 0), [(0, 10), (11, 9)]);
|
||||||
|
|
||||||
// with selection, more than needed width
|
// with selection, more than needed width
|
||||||
let table = Table::default().widths([Min(4), Min(4)]);
|
let table = Table::default().widths([Min(4), Min(4)]);
|
||||||
assert_eq!(table.get_columns_widths(20, 3), [(3, 4), (8, 4)]);
|
assert_eq!(table.get_columns_widths(20, 3), [(3, 8), (12, 8)]);
|
||||||
|
|
||||||
// without selection, less than needed width
|
// without selection, less than needed width
|
||||||
// allocates spacer
|
// allocates spacer
|
||||||
let table = Table::default().widths([Min(4), Min(4)]);
|
let table = Table::default().widths([Min(4), Min(4)]);
|
||||||
assert_eq!(table.get_columns_widths(7, 0), [(0, 4), (5, 2)]);
|
assert_eq!(table.get_columns_widths(7, 0), [(0, 3), (4, 3)]);
|
||||||
|
|
||||||
// with selection, less than needed width
|
// with selection, less than needed width
|
||||||
// always allocates selection and spacer
|
// always allocates selection and spacer
|
||||||
let table = Table::default().widths([Min(4), Min(4)]);
|
let table = Table::default().widths([Min(4), Min(4)]);
|
||||||
assert_eq!(table.get_columns_widths(7, 3), [(3, 3), (7, 0)]);
|
assert_eq!(table.get_columns_widths(7, 3), [(3, 2), (6, 1)]);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1352,12 +1312,12 @@ mod tests {
|
|||||||
let table = Table::default().widths([Min(10), Min(10), Min(1)]);
|
let table = Table::default().widths([Min(10), Min(10), Min(1)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
table.get_columns_widths(62, 0),
|
table.get_columns_widths(62, 0),
|
||||||
&[(0, 10), (11, 10), (22, 1)]
|
&[(0, 20), (21, 20), (42, 20)]
|
||||||
);
|
);
|
||||||
|
|
||||||
let table = Table::default()
|
let table = Table::default()
|
||||||
.widths([Min(10), Min(10), Min(1)])
|
.widths([Min(10), Min(10), Min(1)])
|
||||||
.flex(Flex::StretchLast);
|
.flex(Flex::Legacy);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
table.get_columns_widths(62, 0),
|
table.get_columns_widths(62, 0),
|
||||||
&[(0, 10), (11, 10), (22, 40)]
|
&[(0, 10), (11, 10), (22, 40)]
|
||||||
@ -1365,10 +1325,10 @@ mod tests {
|
|||||||
|
|
||||||
let table = Table::default()
|
let table = Table::default()
|
||||||
.widths([Min(10), Min(10), Min(1)])
|
.widths([Min(10), Min(10), Min(1)])
|
||||||
.flex(Flex::Stretch);
|
.flex(Flex::SpaceBetween);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
table.get_columns_widths(62, 0),
|
table.get_columns_widths(62, 0),
|
||||||
&[(0, 20), (21, 20), (42, 20)]
|
&[(0, 21), (21, 20), (41, 21)]
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1379,24 +1339,16 @@ mod tests {
|
|||||||
let table = Table::default().widths([Min(10), Min(10), Min(1)]);
|
let table = Table::default().widths([Min(10), Min(10), Min(1)]);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
table.get_columns_widths(62, 0),
|
table.get_columns_widths(62, 0),
|
||||||
&[(0, 10), (11, 10), (22, 1)]
|
&[(0, 20), (21, 20), (42, 20)]
|
||||||
);
|
);
|
||||||
|
|
||||||
let table = Table::default()
|
let table = Table::default()
|
||||||
.widths([Min(10), Min(10), Min(1)])
|
.widths([Min(10), Min(10), Min(1)])
|
||||||
.segment_size(SegmentSize::LastTakesRemainder);
|
.flex(Flex::Legacy);
|
||||||
assert_eq!(
|
assert_eq!(
|
||||||
table.get_columns_widths(62, 0),
|
table.get_columns_widths(62, 0),
|
||||||
&[(0, 10), (11, 10), (22, 40)]
|
&[(0, 10), (11, 10), (22, 40)]
|
||||||
);
|
);
|
||||||
|
|
||||||
let table = Table::default()
|
|
||||||
.widths([Min(10), Min(10), Min(1)])
|
|
||||||
.segment_size(SegmentSize::EvenDistribution);
|
|
||||||
assert_eq!(
|
|
||||||
table.get_columns_widths(62, 0),
|
|
||||||
&[(0, 20), (21, 20), (42, 20)]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[test]
|
#[test]
|
||||||
@ -1526,7 +1478,7 @@ mod tests {
|
|||||||
Some(0), // selection
|
Some(0), // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
">>>ABCDE 12345", // row 1
|
">>>ABCDE 12345 ", // row 1
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1541,7 +1493,7 @@ mod tests {
|
|||||||
None, // selection
|
None, // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
" ABCDE 12345", // row 1
|
" ABCDE 12345 ", // row 1
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1556,7 +1508,7 @@ mod tests {
|
|||||||
Some(0), // selection
|
Some(0), // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
">>>ABCDE 12345", // row 1
|
">>>ABCDE 12345 ", // row 1
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1609,7 +1561,7 @@ mod tests {
|
|||||||
None, // selection
|
None, // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
" ABCDE 1", // highlight_symbol and spacing are prioritized
|
" ABC 123", // highlight_symbol and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1624,7 +1576,7 @@ mod tests {
|
|||||||
None, // selection
|
None, // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
" ABCD 1", // highlight_symbol and spacing are prioritized
|
" ABC 12", // highlight_symbol and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1637,7 +1589,7 @@ mod tests {
|
|||||||
None, // selection
|
None, // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
" ABCD ", // highlight_symbol and spacing are prioritized
|
" AB 12", // highlight_symbol and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1650,7 +1602,7 @@ mod tests {
|
|||||||
None, // selection
|
None, // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
" ABC ", // highlight_symbol and spacing are prioritized
|
" AB 1", // highlight_symbol and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1659,7 +1611,22 @@ mod tests {
|
|||||||
let table = Table::default()
|
let table = Table::default()
|
||||||
.rows(vec![Row::new(vec!["ABCDE", "12345"])])
|
.rows(vec![Row::new(vec!["ABCDE", "12345"])])
|
||||||
.highlight_spacing(HighlightSpacing::Always)
|
.highlight_spacing(HighlightSpacing::Always)
|
||||||
.flex(Flex::Stretch)
|
.flex(Flex::Legacy)
|
||||||
|
.highlight_symbol(">>>")
|
||||||
|
.column_spacing(1);
|
||||||
|
let area = Rect::new(0, 0, 10, 3);
|
||||||
|
let mut buf = Buffer::empty(area);
|
||||||
|
Widget::render(table, area, &mut buf);
|
||||||
|
// highlight_symbol and spacing are prioritized but columns are evenly distributed
|
||||||
|
assert_buffer_eq!(
|
||||||
|
buf,
|
||||||
|
Buffer::with_lines(vec![" ABCDE 1", " ", " ",])
|
||||||
|
);
|
||||||
|
|
||||||
|
let table = Table::default()
|
||||||
|
.rows(vec![Row::new(vec!["ABCDE", "12345"])])
|
||||||
|
.highlight_spacing(HighlightSpacing::Always)
|
||||||
|
.flex(Flex::Start)
|
||||||
.highlight_symbol(">>>")
|
.highlight_symbol(">>>")
|
||||||
.column_spacing(1);
|
.column_spacing(1);
|
||||||
let area = Rect::new(0, 0, 10, 3);
|
let area = Rect::new(0, 0, 10, 3);
|
||||||
@ -1693,7 +1660,7 @@ mod tests {
|
|||||||
Some(0), // selection
|
Some(0), // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
">>>ABCDE 1", // row 1
|
">>>ABC 123", // row 1
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1707,7 +1674,7 @@ mod tests {
|
|||||||
Some(0), // selection
|
Some(0), // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
">>>ABCDE 1", // highlight column and spacing are prioritized
|
">>>ABC 123", // highlight column and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1754,7 +1721,7 @@ mod tests {
|
|||||||
None, // selection
|
None, // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
" ABCDE12", // highlight column and spacing are prioritized
|
" ABCD123", // highlight column and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1780,7 +1747,7 @@ mod tests {
|
|||||||
Some(0), // selection
|
Some(0), // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
">>>ABCDE12", // highlight column and spacing are prioritized
|
">>>ABCD123", // highlight column and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
@ -1793,7 +1760,7 @@ mod tests {
|
|||||||
Some(0), // selection
|
Some(0), // selection
|
||||||
),
|
),
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
">>>ABCDE12", // highlight column and spacing are prioritized
|
">>>ABCD123", // highlight column and spacing are prioritized
|
||||||
" ", // row 2
|
" ", // row 2
|
||||||
" ", // row 3
|
" ", // row 3
|
||||||
])
|
])
|
||||||
|
@ -97,12 +97,12 @@ fn widgets_table_column_spacing_can_be_changed() {
|
|||||||
7,
|
7,
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
"┌────────────────────────────┐",
|
"┌────────────────────────────┐",
|
||||||
"│Head1 Head2 Head│",
|
"│Head1 Head Head3│",
|
||||||
"│ │",
|
"│ │",
|
||||||
"│Row11 Row12 Row1│",
|
"│Row11 Row1 Row13│",
|
||||||
"│Row21 Row22 Row2│",
|
"│Row21 Row2 Row23│",
|
||||||
"│Row31 Row32 Row3│",
|
"│Row31 Row3 Row33│",
|
||||||
"│Row41 Row42 Row4│",
|
"│Row41 Row4 Row43│",
|
||||||
"│ │",
|
"│ │",
|
||||||
"│ │",
|
"│ │",
|
||||||
"└────────────────────────────┘",
|
"└────────────────────────────┘",
|
||||||
@ -408,12 +408,12 @@ fn widgets_table_columns_widths_can_use_mixed_constraints() {
|
|||||||
],
|
],
|
||||||
Buffer::with_lines(vec![
|
Buffer::with_lines(vec![
|
||||||
"┌────────────────────────────┐",
|
"┌────────────────────────────┐",
|
||||||
"│Head1 Head2 │",
|
"│Head1 Head2 Head3 │",
|
||||||
"│ │",
|
"│ │",
|
||||||
"│Row11 Row12 │",
|
"│Row11 Row12 Row13 │",
|
||||||
"│Row21 Row22 │",
|
"│Row21 Row22 Row23 │",
|
||||||
"│Row31 Row32 │",
|
"│Row31 Row32 Row33 │",
|
||||||
"│Row41 Row42 │",
|
"│Row41 Row42 Row43 │",
|
||||||
"│ │",
|
"│ │",
|
||||||
"│ │",
|
"│ │",
|
||||||
"└────────────────────────────┘",
|
"└────────────────────────────┘",
|
||||||
|
Loading…
x
Reference in New Issue
Block a user