mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-22 12:43:16 +00:00
docs: Adds better documentation for constraints and flex 📚 (#818)
This commit is contained in:
parent
cc6737b8bc
commit
11e4f6a0ba
2 changed files with 157 additions and 93 deletions
|
@ -1,5 +1,8 @@
|
|||
use strum::{Display, EnumString};
|
||||
|
||||
#[allow(unused_imports)]
|
||||
use super::constraint::Constraint;
|
||||
|
||||
/// Defines the options for layout flex justify content in a container.
|
||||
///
|
||||
/// This enumeration controls the distribution of space when layout constraints are met.
|
||||
|
@ -14,28 +17,98 @@ use strum::{Display, EnumString};
|
|||
/// - `SpaceAround`: Adds excess space around each element.
|
||||
#[derive(Copy, Debug, Default, Display, EnumString, Clone, Eq, PartialEq, Hash)]
|
||||
pub enum Flex {
|
||||
/// Fills the available space within the container, putting excess space into the last element.
|
||||
/// This matches the default behavior of ratatui and tui applications without [`Flex`]
|
||||
/// 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
|
||||
/// applications without [`Flex`]
|
||||
///
|
||||
/// The following examples illustrate the allocation of excess in various combinations of
|
||||
/// constraints. As a refresher, the priorities of constraints are as follows:
|
||||
///
|
||||
/// 1. [`Constraint::Fixed`]
|
||||
/// 2. [`Constraint::Min`] / [`Constraint::Max`]
|
||||
/// 3. [`Constraint::Length`] / [`Constraint::Percentage`] / [`Constraint::Ratio`]
|
||||
/// 4. [`Constraint::Proportional`]
|
||||
///
|
||||
/// When every constraint is `Length`, the last element gets the excess.
|
||||
///
|
||||
/// ```plain
|
||||
/// <----------------------------------- 80 px ------------------------------------>
|
||||
/// ┌──────20 px───────┐┌──────20 px───────┐┌────────────────40 px─────────────────┐
|
||||
/// │ Length(20) ││ Length(20) ││ Length(20) │
|
||||
/// └──────────────────┘└──────────────────┘└──────────────────────────────────────┘
|
||||
/// ^^^^^^^^^^^^^^^^ 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 ^^^^^^^^^^^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// Proportional constraints have the lowest priority amongst all the constraints and hence
|
||||
/// will always take up any excess space available.
|
||||
///
|
||||
/// ```plain
|
||||
/// <----------------------------------- 80 px ------------------------------------>
|
||||
/// ┌──────20 px───────┐┌──────20 px───────┐┌──────20 px───────┐┌──────20 px───────┐
|
||||
/// │ Proportional(0) ││ Min(20) ││ Length(20) ││ Fixed(20) │
|
||||
/// └──────────────────┘└──────────────────┘└──────────────────┘└──────────────────┘
|
||||
/// ^^^^^^ EXCESS ^^^^^^
|
||||
/// ```
|
||||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// ```plain
|
||||
///
|
||||
/// Length(20), Length(10)
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
/// ┌───────────30 px────────────┐┌───────────30 px────────────┐┌──────20 px───────┐
|
||||
/// │ Percentage(20) ││ Length(20) ││ Fixed(20) │
|
||||
/// └────────────────────────────┘└────────────────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐┌──────────────────────────────────────────────────────────┐
|
||||
/// │ 20 px ││ 60 px │
|
||||
/// └──────────────────┘└──────────────────────────────────────────────────────────┘
|
||||
///
|
||||
/// Length(20), Fixed(10)
|
||||
/// ┌──────────────────────────60 px───────────────────────────┐┌──────20 px───────┐
|
||||
/// │ Min(20) ││ Max(20) │
|
||||
/// └──────────────────────────────────────────────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌────────────────────────────────────────────────────────────────────┐┌────────┐
|
||||
/// │ 70 px ││ 10 px │
|
||||
/// └────────────────────────────────────────────────────────────────────┘└────────┘
|
||||
/// ┌────────────────────────────────────80 px─────────────────────────────────────┐
|
||||
/// │ Max(20) │
|
||||
/// └──────────────────────────────────────────────────────────────────────────────┘
|
||||
/// ```
|
||||
#[default]
|
||||
StretchLast,
|
||||
|
@ -44,25 +117,21 @@ pub enum Flex {
|
|||
///
|
||||
/// # Examples
|
||||
///
|
||||
/// Length(40), Length(20)
|
||||
///
|
||||
/// ```plain
|
||||
///
|
||||
/// Length(20), Length(10)
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
/// ┌────16 px─────┐┌──────────────────44 px───────────────────┐┌──────20 px───────┐
|
||||
/// │Percentage(20)││ Length(20) ││ Fixed(20) │
|
||||
/// └──────────────┘└──────────────────────────────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────────────────────────┐┌──────────────────────────────────────┐
|
||||
/// │ 40 px ││ 40 px │
|
||||
/// └──────────────────────────────────────┘└──────────────────────────────────────┘
|
||||
///
|
||||
/// Length(20), Fixed(10)
|
||||
/// ┌──────────────────────────60 px───────────────────────────┐┌──────20 px───────┐
|
||||
/// │ Min(20) ││ Max(20) │
|
||||
/// └──────────────────────────────────────────────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌────────────────────────────────────────────────────────────────────┐┌────────┐
|
||||
/// │ 70 px ││ 10 px │
|
||||
/// └────────────────────────────────────────────────────────────────────┘└────────┘
|
||||
/// ┌────────────────────────────────────80 px─────────────────────────────────────┐
|
||||
/// │ Max(20) │
|
||||
/// └──────────────────────────────────────────────────────────────────────────────┘
|
||||
/// ```
|
||||
Stretch,
|
||||
|
||||
|
@ -71,22 +140,20 @@ pub enum Flex {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```plain
|
||||
///
|
||||
/// Length(20), Length(10)
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
/// ┌────16 px─────┐┌──────20 px───────┐┌──────20 px───────┐
|
||||
/// │Percentage(20)││ Length(20) ││ Fixed(20) │
|
||||
/// └──────────────┘└──────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐┌────────┐
|
||||
/// │ 20 px ││ 10 px │
|
||||
/// └──────────────────┘└────────┘
|
||||
///
|
||||
/// Length(20), Fixed(10)
|
||||
/// ┌──────20 px───────┐┌──────20 px───────┐
|
||||
/// │ Min(20) ││ Max(20) │
|
||||
/// └──────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐┌────────┐
|
||||
/// │ 20 px ││ 10 px │
|
||||
/// └──────────────────┘└────────┘
|
||||
/// ┌──────20 px───────┐
|
||||
/// │ Max(20) │
|
||||
/// └──────────────────┘
|
||||
/// ```
|
||||
Start,
|
||||
|
||||
|
@ -95,22 +162,20 @@ pub enum Flex {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```plain
|
||||
///
|
||||
/// Length(20), Length(10)
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
/// ┌────16 px─────┐┌──────20 px───────┐┌──────20 px───────┐
|
||||
/// │Percentage(20)││ Length(20) ││ Fixed(20) │
|
||||
/// └──────────────┘└──────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐┌────────┐
|
||||
/// │ 20 px ││ 10 px │
|
||||
/// └──────────────────┘└────────┘
|
||||
///
|
||||
/// Length(20), Fixed(10)
|
||||
/// ┌──────20 px───────┐┌──────20 px───────┐
|
||||
/// │ Min(20) ││ Max(20) │
|
||||
/// └──────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐┌────────┐
|
||||
/// │ 20 px ││ 10 px │
|
||||
/// └──────────────────┘└────────┘
|
||||
/// ┌──────20 px───────┐
|
||||
/// │ Max(20) │
|
||||
/// └──────────────────┘
|
||||
/// ```
|
||||
End,
|
||||
|
||||
|
@ -119,22 +184,20 @@ pub enum Flex {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```plain
|
||||
///
|
||||
/// Length(20), Length(10)
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
/// ┌────16 px─────┐┌──────20 px───────┐┌──────20 px───────┐
|
||||
/// │Percentage(20)││ Length(20) ││ Fixed(20) │
|
||||
/// └──────────────┘└──────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐┌────────┐
|
||||
/// │ 20 px ││ 10 px │
|
||||
/// └──────────────────┘└────────┘
|
||||
///
|
||||
/// Length(20), Fixed(10)
|
||||
/// ┌──────20 px───────┐┌──────20 px───────┐
|
||||
/// │ Min(20) ││ Max(20) │
|
||||
/// └──────────────────┘└──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐┌────────┐
|
||||
/// │ 20 px ││ 10 px │
|
||||
/// └──────────────────┘└────────┘
|
||||
/// ┌──────20 px───────┐
|
||||
/// │ Max(20) │
|
||||
/// └──────────────────┘
|
||||
/// ```
|
||||
Center,
|
||||
|
||||
|
@ -144,21 +207,20 @@ pub enum Flex {
|
|||
///
|
||||
/// ```plain
|
||||
///
|
||||
/// Length(20), Length(10)
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
/// ┌────16 px─────┐ ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||
/// │Percentage(20)│ │ Length(20) │ │ Fixed(20) │
|
||||
/// └──────────────┘ └──────────────────┘ └──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐ ┌────────┐
|
||||
/// │ 20 px │ │ 10 px │
|
||||
/// └──────────────────┘ └────────┘
|
||||
///
|
||||
/// Length(20), Fixed(10)
|
||||
/// ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||
/// │ Min(20) │ │ Max(20) │
|
||||
/// └──────────────────┘ └──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐ ┌────────┐
|
||||
/// │ 20 px │ │ 10 px │
|
||||
/// └──────────────────┘ └────────┘
|
||||
/// ┌────────────────────────────────────80 px─────────────────────────────────────┐
|
||||
/// │ Max(20) │
|
||||
/// └──────────────────────────────────────────────────────────────────────────────┘
|
||||
/// ```
|
||||
SpaceBetween,
|
||||
|
||||
|
@ -167,22 +229,20 @@ pub enum Flex {
|
|||
/// # Examples
|
||||
///
|
||||
/// ```plain
|
||||
///
|
||||
/// Length(20), Length(10)
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
/// ┌────16 px─────┐ ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||
/// │Percentage(20)│ │ Length(20) │ │ Fixed(20) │
|
||||
/// └──────────────┘ └──────────────────┘ └──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐ ┌────────┐
|
||||
/// │ 20 px │ │ 10 px │
|
||||
/// └──────────────────┘ └────────┘
|
||||
///
|
||||
/// Length(20), Fixed(10)
|
||||
/// ┌──────20 px───────┐ ┌──────20 px───────┐
|
||||
/// │ Min(20) │ │ Max(20) │
|
||||
/// └──────────────────┘ └──────────────────┘
|
||||
///
|
||||
/// <------------------------------------80 px------------------------------------->
|
||||
///
|
||||
/// ┌──────────────────┐ ┌────────┐
|
||||
/// │ 20 px │ │ 10 px │
|
||||
/// └──────────────────┘ └────────┘
|
||||
/// ┌──────20 px───────┐
|
||||
/// │ Max(20) │
|
||||
/// └──────────────────┘
|
||||
/// ```
|
||||
SpaceAround,
|
||||
}
|
||||
|
|
|
@ -527,7 +527,7 @@ impl Layout {
|
|||
// interleave spacers and elements
|
||||
// for `SpaceAround` we want the following
|
||||
// `[spacer, element, spacer, element, ..., element, spacer]`
|
||||
// this is why we use one spacer than elements
|
||||
// this is why we use one more spacer than elements
|
||||
for pair in Itertools::interleave(spacers.iter(), elements.iter())
|
||||
.collect::<Vec<&Element>>()
|
||||
.windows(2)
|
||||
|
@ -537,7 +537,8 @@ impl Layout {
|
|||
}
|
||||
Flex::StretchLast => {
|
||||
// this is the default behavior
|
||||
// within reason, cassowary tends to put excess into the last constraint
|
||||
// by default cassowary tends to put excess into the last constraint of the lowest
|
||||
// priority.
|
||||
if let Some(first) = elements.first() {
|
||||
solver.add_constraint(first.start | EQ(REQUIRED) | area_start)?;
|
||||
}
|
||||
|
@ -550,16 +551,19 @@ impl Layout {
|
|||
}
|
||||
}
|
||||
Flex::Stretch => {
|
||||
// this is the same as `StretchLast`
|
||||
// however, we add one additional constraint to take priority over cassowary's
|
||||
// default behavior.
|
||||
// We prefer equal elements if other constraints are all satisfied.
|
||||
for (left, right) in elements.iter().tuple_combinations() {
|
||||
solver.add_constraint(left.size() | EQ(WEAK) | right.size())?;
|
||||
}
|
||||
if let Some(first) = elements.first() {
|
||||
solver.add_constraint(first.start | EQ(REQUIRED) | area_start)?;
|
||||
}
|
||||
if let Some(last) = elements.last() {
|
||||
solver.add_constraint(last.end | EQ(REQUIRED) | area_end)?;
|
||||
}
|
||||
// prefer equal elements if other constraints are all satisfied
|
||||
for (left, right) in elements.iter().tuple_combinations() {
|
||||
solver.add_constraint(left.size() | EQ(WEAK) | right.size())?;
|
||||
}
|
||||
// ensure there are no gaps between the elements
|
||||
for pair in elements.windows(2) {
|
||||
solver.add_constraint(pair[0].end | EQ(REQUIRED) | pair[1].start)?;
|
||||
|
|
Loading…
Reference in a new issue