Skip to main content

Layout

Struct Layout 

Source
pub struct Layout { /* private fields */ }

Implementations§

Source§

impl Layout

Source

pub fn vertical<C>(constraints: C) -> Self
where C: Into<Vec<Constraint>>,

Creates a vertical layout with the given constraints.

A vertical layout splits the available area from top to bottom into multiple horizontal slices.

In other words:

  • Constraint values are applied to the height
  • All resulting rectangles share the same x and width
  • Rectangles are stacked along the Y axis

This method is equivalent to Layout::default().direction(Direction::Vertical) and effectively replaces the use of Layout::new(...) for vertical layouts.

§Visual representation
+----------------------+
|        Rect 0        |  ← Constraint[0]
+----------------------+
|        Rect 1        |  ← Constraint[1]
+----------------------+
|        Rect 2        |  ← Constraint[2]
+----------------------+
§Example
use altui_core::layout::{Rect, Constraint::*, Layout};

let chunks = Layout::vertical([Length(2),Min(0)])
    .split(Rect {
        x: 0,
        y: 0,
        width: 10,
        height: 6,
    });

// Splits the area into two rows:
// height = 2 and height = 4
assert_eq!(chunks.len(), 2);
assert_eq!(chunks[0].height, 2);
assert_eq!(chunks[1].height, 4);

See also Layout::horizontal for left-to-right layouts.

Source

pub fn horizontal<C>(constraints: C) -> Self
where C: Into<Vec<Constraint>>,

Creates a horizontal layout with the given constraints.

A horizontal layout splits the available area from left to right into multiple vertical slices.

In other words:

  • Constraint values are applied to the width
  • All resulting rectangles share the same y and height
  • Rectangles are stacked along the X axis

This method is equivalent to Layout::default().direction(Direction::Horizontal) and effectively replaces the use of Layout::new(...) for horizontal layouts.

§Visual representation
+---------+---------+---------+
| Rect 0  | Rect 1  | Rect 2  |
|         |         |         |
+---------+---------+---------+
  ↑           ↑
Constraint[0] Constraint[1]
§Example
use altui_core::layout::{Rect, Constraint::*, Layout};

let chunks = Layout::horizontal([Length(3),Min(0)])
    .split(Rect {
        x: 0,
        y: 0,
        width: 10,
        height: 4,
    });

// Splits the area into two columns:
// width = 3 and width = 7
assert_eq!(chunks.len(), 2);
assert_eq!(chunks[0].width, 3);
assert_eq!(chunks[1].width, 7);

See also Layout::vertical for top-to-bottom layouts.

Source

pub fn constraints<C>(self, constraints: C) -> Layout
where C: Into<Vec<Constraint>>,

Source

pub fn margin(self, margin: u16) -> Layout

Source

pub fn horizontal_margin(self, horizontal: u16) -> Layout

Source

pub fn vertical_margin(self, vertical: u16) -> Layout

Source

pub fn direction(self, direction: Direction) -> Layout

Source

pub fn overlap(self, overlap: u16) -> Layout

Sets the amount of allowed overlap between adjacent elements along the main axis.

The overlap value specifies how many neighboring characters are allowed to overlap between adjacent layout items.

Useful for compact layouts with shared borders.

┌────────┌────────┌────────┐
│ Item 1 │ Item 2 │ Item 3 │
└────────└────────└────────┘
§Warning: Unstable API

⚠️ Known Issue: This method may cause incorrect rendering when used together with Layout::split_ext, Flex::SpaceBetween or Flex::SpaceAround.

Source

pub fn cross_overlap(self, cross_overlap: u16) -> Layout

Sets the amount of allowed overlap between adjacent elements along the cross axis.

The overlap value specifies how many neighboring symbols are allowed to overlap between adjacent layout items.

Useful for compact layouts with shared borders.

┌────────┐
│ Item 1 │
┌────────┐
│ Item 2 │
┌────────┐
│ Item 3 │
└────────┘
§Warning: Unstable API

⚠️ Known Issue: This method may cause incorrect rendering when used together with Layout::split_ext, Flex::SpaceBetween or Flex::SpaceAround.

Source

pub fn flex(self, flex: Flex) -> Layout

Sets how free space is distributed between elements along the main axis.

Flex controls the alignment and spacing of elements after all constraints have been resolved.

This affects only the main axis:

  • horizontal layouts → X axis
  • vertical layouts → Y axis

The default value is Flex::Start.

See Flex for a detailed description of each mode.

Source

pub fn cross_flex(self, flex: Flex) -> Layout

Sets how free space is distributed between elements along the cross axis.

Flex controls the alignment and spacing of elements after all constraints have been resolved.

This affects only the cross axis:

  • horizontal layouts → Y axis
  • vertical layouts → X axis

The default value is Flex::Start.

Source

pub fn boxed(self, boxed: bool) -> Layout

Enables or disables boxed layout mode.

When boxed is set to true, fixed-size constraints (Constraint::Length, Constraint::Min) take precedence and are resolved first.

Remaining space is then distributed between:

  • Constraint::Ratio
  • Constraint::Percentage

When boxed is false (default), all constraints participate in layout solving on equal terms.

§Important notes
  • Using boxed = true together with scrolling or wrapping may produce unintuitive results.
  • Percentage and ratio constraints are strongly discouraged when boxed is enabled.
§Default

false

Source

pub fn external_scroll(self) -> Layout

Marks the layout as externally scroll-controlled.

When enabled, the layout does not compute its own scroll bounds. Instead, the scroll size is assumed to be managed by the caller.

This is mainly useful when:

  • multiple layouts share a single scroll state
  • scroll limits are computed elsewhere

This option is only meaningful when using Layout::split_ext.

Source

pub fn wrap(self, cross_size: Constraint) -> Layout

Enables wrapping into multiple lines when the accumulated main-axis length exceeds the given value. Sets line/column size on cross-axis.

Wrapping splits elements into multiple lines/columns, similar to text wrapping.

  • Wrapping is performed based on main-axis length
  • Line/column size along the cross-axis is fixed (Min/Max Constraints work as Length)
  • Enabling wrapping implicitly changes the scroll direction
§Scroll direction
  • Without wrapping:

    • horizontal layout → horizontal scroll
    • vertical layout → vertical scroll
  • With wrapping enabled:

    • horizontal layout → vertical scroll
    • vertical layout → horizontal scroll
§Example

Wrapping a horizontal layout into multiple rows:

[A][B][C]  → wrap
[A][B]
[C]

See also cross_size.

Source

pub fn cross_size(self, cross_size: Constraint) -> Layout

Sets the size of Rect along the cross-axis (or cross-direction) without wrapping

Note!

  • Min/Max constraints work as Length
  • Default is Percentage(100)
Source

pub fn cache_eq(&self, other: &Layout) -> bool

Source

pub fn split(&self, area: Rect) -> Vec<Rect>

Splits the given area into multiple Rects according to the layout configuration, direction, wrapping rules and constraints.

This function is a high-level wrapper around an internal Cassowary-based solver. The layout process consists of two distinct phases:

  1. Line/column construction (preparation phase)
  2. Constraint solving (layout phase)
§Wrapping behavior
  • Wrapping is enabled when Layout::wrap method is used.
  • Each line/column has a fixed cross size determined in the method parameter.
  • When wrapping is enabled, a new line/column is started whenever adding the next constraint would exceed the available main axis (direction) size.
  • Elements with Max constraint and Percentage and Ratio constraints if layout is boxed do not contribute to line/column size and will be collapsed by the solver.
§Examples
§Vertical layout
use altui_core::layout::{Rect, Constraint, Layout};

let chunks = Layout::vertical([Constraint::Length(5), Constraint::Min(0)])
    .split(Rect {
        x: 2,
        y: 2,
        width: 10,
        height: 10,
    });
assert_eq!(
    chunks,
    vec![
        Rect {
            x: 2,
            y: 2,
            width: 10,
            height: 5
        },
        Rect {
            x: 2,
            y: 7,
            width: 10,
            height: 5
        }
    ]
);
§Horizontal layout with ratios
use altui_core::layout::{Rect, Constraint, Layout};

let chunks = Layout::horizontal([Constraint::Ratio(1, 3), Constraint::Ratio(2, 3)])
    .split(Rect {
        x: 0,
        y: 0,
        width: 9,
        height: 2,
    });
assert_eq!(
    chunks,
    vec![
        Rect {
            x: 0,
            y: 0,
            width: 3,
            height: 2
        },
        Rect {
            x: 3,
            y: 0,
            width: 6,
            height: 2
        }
    ]
);
§Wrapping into multiple lines by length
use altui_core::layout::{Rect, Constraint, Layout};

let chunks = Layout::horizontal([
        Constraint::Length(3),
        Constraint::Length(3),
        Constraint::Length(3),
    ])
    .wrap(Constraint::Length(2))
    .split(Rect {
        x: 0,
        y: 0,
        width: 6,
        height: 4,
    });

// Produces two rows with height `2` each:
// [3][3]
// [3]

assert_eq!(
    chunks,
    vec![
        Rect { x: 0, y: 0, width: 3, height: 2 },
        Rect { x: 3, y: 0, width: 3, height: 2 },
        Rect { x: 0, y: 2, width: 3, height: 2 },
    ]
);
§Wrapping into multiple lines by percentage
use altui_core::layout::{Rect, Constraint, Layout};

let chunks = Layout::horizontal([
        Constraint::Length(3),
        Constraint::Length(3),
        Constraint::Length(3),
    ])
    .wrap(Constraint::Percentage(50))
    .split(Rect {
        x: 0,
        y: 0,
        width: 6,
        height: 8,
    });

// Produces two rows with height `4` each:
// [3][3]
// [3]

assert_eq!(
    chunks,
    vec![
        Rect { x: 0, y: 0, width: 3, height: 4 },
        Rect { x: 3, y: 0, width: 3, height: 4 },
        Rect { x: 0, y: 4, width: 3, height: 4 },
    ]
);
Source

pub fn split_ext( &self, area: Rect, scrollstate: &mut u16, scroll: &mut u16, ) -> Vec<Rect>

Splits the given area into multiple Rects with scrolling support.

This method extends Layout::split by introducing a scroll offset and automatically computing the scrollable range based on the layout configuration.

The layout process is identical to split, but the final positioning is shifted by a computed scroll offset along the active scroll axis.

§Scrolling model

Scrolling is single-axis and its direction depends on whether wrapping is enabled:

  • Without wrapping:

    • Scrolling occurs along the main axis of the layout.
    • For example:
      • Direction::Horizontal → horizontal scrolling
      • Direction::Vertical → vertical scrolling
  • With wrapping enabled:

    • Scrolling occurs along the cross axis.
    • The layout grows by adding multiple lines/columns, and scrolling moves between those lines/columns.

This behavior mirrors common UI patterns where wrapping turns a one-dimensional layout into a multi-line structure with perpendicular scrolling.

§Scroll parameters
  • scroll — total scrollable length (output)

    • Updated by this function unless external_scroll is enabled.
    • Represents the full scroll range in layout units.
  • scrollstate — current scroll position (input/output)

    • Clamped automatically to the valid scroll range.
    • Used to compute the effective scroll offset.
§Wrapping and scrolling interaction
  • When wrapping is enabled:

    • The scroll range is computed from the total cross-axis size of all lines/columns.
  • When wrapping is disabled:

    • The scroll range is computed from the total content length along the main axis.
§External scrolling

If external_scroll is enabled:

  • The scroll range is taken from the scroll parameter.
  • This allows integrating the layout with an external scrolling container.
§Constraints and limitations

⚠️ Important: Do not use the following constraint combinations with split_ext:

These combinations may produce undefined or unintuitive scrolling behavior.

§Notes
  • Line construction and wrapping are performed before scrolling is applied.
  • The solver does not decide the scroll direction.
  • Margins are applied before layout and scrolling.
  • Scrolling offsets are quantized to integer values.
§Examples
§Horizontal scrolling without wrapping
 use altui_core::layout::{Rect, Constraint, Layout};

 let mut scroll = 0;
 let mut scrollstate = 0;

 let chunks = Layout::horizontal([
         Constraint::Length(5),
         Constraint::Length(5),
         Constraint::Length(5),
     ])
     .split_ext(
         Rect { x: 0, y: 0, width: 8, height: 2 },
         &mut scrollstate,
         &mut scroll,
     );

 // Content width exceeds available width, so scrolling is horizontal.
 assert!(scroll == 15);
§Vertical scrolling with wrapping enabled
use altui_core::layout::{Rect, Constraint, Layout};

let mut scroll = 0;
let mut scrollstate = 0;

let chunks = Layout::horizontal([
        Constraint::Length(3),
        Constraint::Length(3),
        Constraint::Length(3),
    ])
    .wrap(Constraint::Length(8))
    .split_ext(
        Rect { x: 0, y: 0, width: 6, height: 8 },
        &mut scrollstate,
        &mut scroll,
    );

// Wrapping creates multiple rows; scrolling is now vertical.
assert!(scroll == 16);

See Layout::split for a non-scrolling variant.

Trait Implementations§

Source§

impl Clone for Layout

Source§

fn clone(&self) -> Layout

Returns a duplicate of the value. Read more
1.0.0 · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for Layout

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more
Source§

impl Default for Layout

Source§

fn default() -> Layout

Returns the “default value” for a type. Read more
Source§

impl Hash for Layout

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for Layout

Source§

fn eq(&self, other: &Layout) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Eq for Layout

Source§

impl StructuralPartialEq for Layout

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more