summaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/app.rs31
-rw-r--r--src/app/layout_manager.rs657
-rw-r--r--src/app/widgets.rs58
-rw-r--r--src/app/widgets/base.rs3
-rw-r--r--src/app/widgets/base/carousel.rs42
-rw-r--r--src/app/widgets/base/text_table.rs3
-rw-r--r--src/app/widgets/basic_cpu.rs0
-rw-r--r--src/app/widgets/basic_mem.rs0
-rw-r--r--src/app/widgets/basic_net.rs0
-rw-r--r--src/app/widgets/bottom_widgets.rs35
-rw-r--r--src/app/widgets/bottom_widgets/basic_cpu.rs205
-rw-r--r--src/app/widgets/bottom_widgets/basic_mem.rs164
-rw-r--r--src/app/widgets/bottom_widgets/basic_net.rs134
-rw-r--r--src/app/widgets/bottom_widgets/battery.rs (renamed from src/app/widgets/battery.rs)58
-rw-r--r--src/app/widgets/bottom_widgets/carousel.rs209
-rw-r--r--src/app/widgets/bottom_widgets/cpu.rs (renamed from src/app/widgets/cpu.rs)34
-rw-r--r--src/app/widgets/bottom_widgets/disk.rs (renamed from src/app/widgets/disk.rs)51
-rw-r--r--src/app/widgets/bottom_widgets/empty.rs58
-rw-r--r--src/app/widgets/bottom_widgets/mem.rs (renamed from src/app/widgets/mem.rs)28
-rw-r--r--src/app/widgets/bottom_widgets/net.rs (renamed from src/app/widgets/net.rs)53
-rw-r--r--src/app/widgets/bottom_widgets/process.rs (renamed from src/app/widgets/process.rs)50
-rw-r--r--src/app/widgets/bottom_widgets/temp.rs (renamed from src/app/widgets/temp.rs)46
-rw-r--r--src/app/widgets/tui_widgets.rs3
-rw-r--r--src/app/widgets/tui_widgets/pipe_gauge.rs138
-rw-r--r--src/bin/main.rs7
-rw-r--r--src/canvas.rs170
-rw-r--r--src/canvas/drawing.rs4
-rw-r--r--src/canvas/drawing/cpu_graph.rs288
-rw-r--r--src/canvas/drawing_utils.rs149
-rw-r--r--src/constants.rs52
-rw-r--r--src/options.rs142
-rw-r--r--src/options/layout_options.rs643
32 files changed, 2589 insertions, 926 deletions
diff --git a/src/app.rs b/src/app.rs
index 91b243f3..54dade87 100644
--- a/src/app.rs
+++ b/src/app.rs
@@ -282,8 +282,12 @@ impl AppState {
}
KeyCode::Char('q') => EventResult::Quit,
KeyCode::Char('e') => {
- self.is_expanded = !self.is_expanded;
- EventResult::Redraw
+ if self.app_config_fields.use_basic_mode {
+ EventResult::NoRedraw
+ } else {
+ self.is_expanded = !self.is_expanded;
+ EventResult::Redraw
+ }
}
KeyCode::Char('?') => {
self.help_dialog_state.is_showing_help = true;
@@ -353,14 +357,29 @@ impl AppState {
} else {
for (id, widget) in self.widget_lookup_map.iter_mut() {
if widget.does_border_intersect_mouse(&event) {
- let was_id_already_selected = self.selected_widget == *id;
- self.selected_widget = *id;
-
let result = widget.handle_mouse_event(event);
+
+ let new_id;
+ match widget.selectable_type() {
+ SelectableType::Selectable => {
+ new_id = *id;
+ }
+ SelectableType::Unselectable => {
+ let result = widget.handle_mouse_event(event);
+ return self.convert_widget_event_result(result);
+ }
+ SelectableType::Redirect(redirected_id) => {
+ new_id = redirected_id;
+ }
+ }
+
+ let was_id_already_selected = self.selected_widget == new_id;
+ self.selected_widget = new_id;
+
if was_id_already_selected {
return self.convert_widget_event_result(result);
} else {
- // If the aren't equal, *force* a redraw.
+ // If the weren't equal, *force* a redraw.
let _ = self.convert_widget_event_result(result);
return EventResult::Redraw;
}
diff --git a/src/app/layout_manager.rs b/src/app/layout_manager.rs
index 7105fa73..672fea19 100644
--- a/src/app/layout_manager.rs
+++ b/src/app/layout_manager.rs
@@ -1,12 +1,18 @@
use crate::{
- app::{DiskTable, MemGraph, NetGraph, OldNetGraph, ProcessManager, TempTable},
+ app::{
+ BasicCpu, BasicMem, BasicNet, BatteryTable, Carousel, DiskTable, Empty, MemGraph, NetGraph,
+ OldNetGraph, ProcessManager, TempTable,
+ },
error::{BottomError, Result},
- options::layout_options::{Row, RowChildren},
+ options::{
+ layout_options::{LayoutRule, Row, RowChildren},
+ ProcessDefaults,
+ },
};
use fxhash::FxHashMap;
use indextree::{Arena, NodeId};
-use std::collections::BTreeMap;
-use tui::layout::Constraint;
+use std::{cmp::min, collections::BTreeMap};
+use tui::layout::Rect;
use typed_builder::*;
use crate::app::widgets::Widget;
@@ -910,6 +916,7 @@ pub enum BottomWidgetType {
BasicNet,
BasicTables,
Battery,
+ Carousel,
}
impl BottomWidgetType {
@@ -958,6 +965,9 @@ impl std::str::FromStr for BottomWidgetType {
"disk" => Ok(BottomWidgetType::Disk),
"empty" => Ok(BottomWidgetType::Empty),
"battery" | "batt" => Ok(BottomWidgetType::Battery),
+ "bcpu" => Ok(BottomWidgetType::BasicCpu),
+ "bmem" => Ok(BottomWidgetType::BasicMem),
+ "bnet" => Ok(BottomWidgetType::BasicNet),
_ => Err(BottomError::ConfigError(format!(
"\"{}\" is an invalid widget name.
@@ -987,43 +997,73 @@ Supported widget names:
// --- New stuff ---
/// Represents a row in the layout tree.
-#[derive(PartialEq, Eq, Default)]
+#[derive(PartialEq, Eq, Clone)]
pub struct RowLayout {
last_selected_index: usize,
- pub constraints: Vec<Constraint>,
+ pub parent_rule: LayoutRule,
+ pub bound: Rect,
+}
+
+impl RowLayout {
+ fn new(parent_rule: LayoutRule) -> Self {
+ Self {
+ last_selected_index: 0,
+ parent_rule,
+ bound: Rect::default(),
+ }
+ }
}
/// Represents a column in the layout tree.
-#[derive(PartialEq, Eq, Default)]
+#[derive(PartialEq, Eq, Clone)]
pub struct ColLayout {
last_selected_index: usize,
- pub constraints: Vec<Constraint>,
+ pub parent_rule: LayoutRule,
+ pub bound: Rect,
+}
+
+impl ColLayout {
+ fn new(parent_rule: LayoutRule) -> Self {
+ Self {
+ last_selected_index: 0,
+ parent_rule,
+ bound: Rect::default(),
+ }
+ }
+}
+
+/// Represents a widget in the layout tree.
+#[derive(PartialEq, Eq, Clone, Default)]
+pub struct WidgetLayout {
+ pub bound: Rect,
}
/// A [`LayoutNode`] represents a single node in the overall widget hierarchy. Each node is one of:
/// - [`LayoutNode::Row`] (a non-leaf that distributes its children horizontally)
/// - [`LayoutNode::Col`] (a non-leaf node that distributes its children vertically)
/// - [`LayoutNode::Widget`] (a leaf node that contains the ID of the widget it is associated with)
-#[derive(PartialEq, Eq)]
+#[derive(PartialEq, Eq, Clone)]
pub enum LayoutNode {
/// A non-leaf that distributes its children horizontally
Row(RowLayout),
/// A non-leaf node that distributes its children vertically
Col(ColLayout),
/// A leaf node that contains the ID of the widget it is associated with
- Widget,
+ Widget(WidgetLayout),
}
impl LayoutNode {
- pub fn set_constraints(&mut self, constraints: Vec<Constraint>) {
+ fn set_bound(&mut self, bound: Rect) {
match self {
LayoutNode::Row(row) => {
- row.constraints = constraints;
+ row.bound = bound;
}
LayoutNode::Col(col) => {
- col.constraints = constraints;
+ col.bound = bound;
+ }
+ LayoutNode::Widget(widget) => {
+ widget.bound = bound;
}
- LayoutNode::Widget => {}
}
}
}
@@ -1050,86 +1090,140 @@ pub struct LayoutCreationOutput {
/// selected [`NodeId`].
// FIXME: This is currently jury-rigged "glue" just to work with the existing config system! We are NOT keeping it like this, it's too awful to keep like this!
pub fn create_layout_tree(
- rows: &[Row], process_defaults: crate::options::ProcessDefaults,
- app_config_fields: &AppConfigFields,
+ rows: &[Row], process_defaults: ProcessDefaults, app_config_fields: &AppConfigFields,
) -> Result<LayoutCreationOutput> {
fn add_widget_to_map(
widget_lookup_map: &mut FxHashMap<NodeId, TmpBottomWidget>, widget_type: BottomWidgetType,
- widget_id: NodeId, process_defaults: &crate::options::ProcessDefaults,
- app_config_fields: &AppConfigFields,
+ widget_id: NodeId, process_defaults: &ProcessDefaults, app_config_fields: &AppConfigFields,
+ width: LayoutRule, height: LayoutRule,
) -> Result<()> {
match widget_type {
BottomWidgetType::Cpu => {
- widget_lookup_map
- .insert(widget_id, CpuGraph::from_config(app_config_fields).into());
+ widget_lookup_map.insert(
+ widget_id,
+ CpuGraph::from_config(app_config_fields)
+ .width(width)
+ .height(height)
+ .into(),
+ );
}
BottomWidgetType::Mem => {
let graph = TimeGraph::from_config(app_config_fields);
- widget_lookup_map.insert(widget_id, MemGraph::new(graph).into());
+ widget_lookup_map.insert(
+ widget_id,
+ MemGraph::new(graph).width(width).height(height).into(),
+ );
}
BottomWidgetType::Net => {
if app_config_fields.use_old_network_legend {
widget_lookup_map.insert(
widget_id,
- OldNetGraph::from_config(app_config_fields).into(),
+ OldNetGraph::from_config(app_config_fields)
+ .width(width)
+ .height(height)
+ .into(),
);
} else {
- widget_lookup_map
- .insert(widget_id, NetGraph::from_config(app_config_fields).into());
+ widget_lookup_map.insert(
+ widget_id,
+ NetGraph::from_config(app_config_fields)
+ .width(width)
+ .height(height)
+ .into(),
+ );
}
}
BottomWidgetType::Proc => {
- widget_lookup_map.insert(widget_id, ProcessManager::new(process_defaults).into());
+ widget_lookup_map.insert(
+ widget_id,
+ ProcessManager::new(process_defaults)
+ .width(width)
+ .height(height)
+ .basic_mode(app_config_fields.use_basic_mode)
+ .into(),
+ );
}
BottomWidgetType::Temp => {
widget_lookup_map.insert(
widget_id,
TempTable::default()
.set_temp_type(app_config_fields.temperature_type.clone())
+ .width(width)
+ .height(height)
+ .basic_mode(app_config_fields.use_basic_mode)
.into(),
);
}
BottomWidgetType::Disk => {
- widget_lookup_map.insert(widget_id, DiskTable::default().into());
+ widget_lookup_map.insert(
+ widget_id,
+ DiskTable::default()
+ .width(width)
+ .height(height)
+ .basic_mode(app_config_fields.use_basic_mode)
+ .into(),
+ );
+ }
+ BottomWidgetType::Battery => {
+ widget_lookup_map.insert(
+ widget_id,
+ BatteryTable::default()
+ .width(width)
+ .height(height)
+ .basic_mode(app_config_fields.use_basic_mode)
+ .into(),
+ );
+ }
+ BottomWidgetType::BasicCpu => {
+ widget_lookup_map.insert(
+ widget_id,
+ BasicCpu::from_config(app_config_fields).width(width).into(),
+ );
+ }
+ BottomWidgetType::BasicMem => {
+ widget_lookup_map.insert(widget_id, BasicMem::default().width(width).into());
+ }
+ BottomWidgetType::BasicNet => {
+ widget_lookup_map.insert(
+ widget_id,
+ BasicNet::from_config(app_config_fields).width(width).into(),
+ );
+ }
+ BottomWidgetType::Empty => {
+ widget_lookup_map.insert(
+ widget_id,
+ Empty::default().width(width).height(height).into(),
+ );
}
- BottomWidgetType::Battery => {}
_ => {}
}
Ok(())
}
- let mut layout_tree = Arena::new();
- let root_id = layout_tree.new_node(LayoutNode::Col(ColLayout::default()));
+ let mut arena = Arena::new();
+ let root_id = arena.new_node(LayoutNode::Col(ColLayout::new(LayoutRule::Expand {
+ ratio: 1,
+ })));
let mut widget_lookup_map = FxHashMap::default();
let mut first_selected = None;
- let mut first_widget_seen = None; // Backup
+ let mut first_widget_seen = None; // Backup selected widget
let mut used_widgets = UsedWidgets::default();
- let row_sum: u32 = rows.iter().map(|row| row.ratio.unwrap_or(1)).sum();
- let mut root_constraints = Vec::with_capacity(rows.len());
for row in rows {
- root_constraints.push(Constraint::Ratio(row.ratio.unwrap_or(1), row_sum));
- let layout_node = LayoutNode::Row(RowLayout::default());
- let row_id = layout_tree.new_node(layout_node);
- root_id.append(row_id, &mut layout_tree);
-
- if let Some(cols) = &row.child {
- let mut row_constraints = Vec::with_capacity(cols.len());
- let col_sum: u32 = cols
- .iter()
- .map(|col| match col {
- RowChildren::Widget(widget) => widget.ratio.unwrap_or(1),
- RowChildren::Col { ratio, child: _ } => ratio.unwrap_or(1),
- })
- .sum();
-
- for col in cols {
- match col {
+ let row_id = arena.new_node(LayoutNode::Row(RowLayout::new(
+ row.ratio
+ .map(|ratio| LayoutRule::Expand { ratio })
+ .unwrap_or(LayoutRule::Child),
+ )));
+ root_id.append(row_id, &mut arena);
+
+ if let Some(children) = &row.child {
+ for child in children {
+ match child {
RowChildren::Widget(widget) => {
- row_constraints.push(Constraint::Ratio(widget.ratio.unwrap_or(1), col_sum));
- let widget_id = layout_tree.new_node(LayoutNode::Widget);
- row_id.append(widget_id, &mut layout_tree);
+ let widget_id = arena.new_node(LayoutNode::Widget(WidgetLayout::default()));
+ row_id.append(widget_id, &mut arena);
if let Some(true) = widget.default {
first_selected = Some(widget_id);
@@ -1148,28 +1242,108 @@ pub fn create_layout_tree(
widget_id,
&process_defaults,
app_config_fields,
+ widget.rule.unwrap_or_default(),
+ LayoutRule::default(),
)?;
}
+ RowChildren::Carousel {
+ carousel_children,
+ default,
+ } => {
+ if !carousel_children.is_empty() {
+ let mut child_ids = Vec::with_capacity(carousel_children.len());
+ let carousel_widget_id =
+ arena.new_node(LayoutNode::Widget(WidgetLayout::default()));
+ row_id.append(carousel_widget_id, &mut arena);
+
+ // Add the first widget as a default widget if needed.
+ {
+ let widget_id =
+ arena.new_node(LayoutNode::Widget(WidgetLayout::default()));
+ carousel_widget_id.append(widget_id, &mut arena);
+
+ let widget_type =
+ carousel_children[0].parse::<BottomWidgetType>()?;
+ used_widgets.add(&widget_type);
+
+ if let Some(true) = default {
+ first_selected = Some(widget_id);
+ }
+
+ if first_widget_seen.is_none() {
+ first_widget_seen = Some(widget_id);
+ }
+
+ add_widget_to_map(
+ &mut widget_lookup_map,
+ widget_type,
+ widget_id,
+ &process_defaults,
+ app_config_fields,
+ LayoutRule::default(),
+ LayoutRule::default(),
+ )?;
+
+ child_ids.push(widget_id);
+ }
+
+ // Handle the rest of the children.
+ for child in carousel_children[1..].iter() {
+ let widget_id =
+ arena.new_node(LayoutNode::Widget(WidgetLayout::default()));
+ carousel_widget_id.append(widget_id, &mut arena);
+
+ let widget_type = child.parse::<BottomWidgetType>()?;
+ used_widgets.add(&widget_type);
+
+ add_widget_to_map(
+ &mut widget_lookup_map,
+ widget_type,
+ widget_id,
+ &process_defaults,
+ app_config_fields,
+ LayoutRule::default(),
+ LayoutRule::default(),
+ )?;
+
+ child_ids.push(widget_id);
+ }
+
+ widget_lookup_map.insert(
+ carousel_widget_id,
+ Carousel::new(
+ child_ids
+ .into_iter()
+ .filter_map(|child_id| {
+ if let Some(w) = widget_lookup_map.get(&child_id) {
+ Some((child_id, w.get_pretty_name().into()))
+ } else {
+ None
+ }
+ })
+ .collect(),
+ )
+ .into(),
+ );
+ }
+ }
RowChildren::Col {
ratio,
- child: children,
+ child: col_child,
} => {
- row_constraints.push(Constraint::Ratio(ratio.unwrap_or(1), col_sum));
- let col_node = LayoutNode::Col(ColLayout::default());
- let col_id = layout_tree.new_node(col_node);
- row_id.append(col_id, &mut layout_tree);
-
- let child_sum: u32 =
- children.iter().map(|child| child.ratio.unwrap_or(1)).sum();
-
- let mut col_constraints = Vec::with_capacity(children.len());
- for child in children {
- col_constraints
- .push(Constraint::Ratio(child.ratio.unwrap_or(1), child_sum));
- let widget_id = layout_tree.new_node(LayoutNode::Widget);
- col_id.append(widget_id, &mut layout_tree);
-
- if let Some(true) = child.default {
+ let col_id = arena.new_node(LayoutNode::Col(ColLayout::new(
+ ratio
+ .map(|ratio| LayoutRule::Expand { ratio })
+ .unwrap_or(LayoutRule::Child),
+ )));
+ row_id.append(col_id, &mut arena);
+
+ for widget in col_child {
+ let widget_id =
+ arena.new_node(LayoutNode::Widget(WidgetLayout::default()));
+ col_id.append(widget_id, &mut arena);
+
+ if let Some(true) = widget.default {
first_selected = Some(widget_id);
}
@@ -1177,7 +1351,7 @@ pub fn create_layout_tree(
first_widget_seen = Some(widget_id);
}
- let widget_type = child.widget_type.parse::<BottomWidgetType>()?;
+ let widget_type = widget.widget_type.parse::<BottomWidgetType>()?;
used_widgets.add(&widget_type);
add_widget_to_map(
@@ -1186,25 +1360,17 @@ pub fn create_layout_tree(
widget_id,
&process_defaults,
app_config_fields,
+ LayoutRule::default(),
+ widget.rule.unwrap_or_default(),
)?;
}
- layout_tree[col_id]
- .get_mut()
- .set_constraints(col_constraints);
}
}
}
- layout_tree[row_id]
- .get_mut()
- .set_constraints(row_constraints);
}
}
- layout_tree[root_id]
- .get_mut()
- .set_constraints(root_constraints);
let selected: NodeId;
-
if let Some(first_selected) = first_selected {
selected = first_selected;
} else if let Some(first_widget_seen) = first_widget_seen {
@@ -1216,7 +1382,7 @@ pub fn create_layout_tree(
}
Ok(LayoutCreationOutput {
- layout_tree,
+ layout_tree: arena,
root: root_id,
widget_lookup_map,
selected,
@@ -1264,7 +1430,7 @@ pub fn move_widget_selection(
.and_then(|(parent_id, parent_node)| match parent_node.get() {
LayoutNode::Row(_) => Some((parent_id, current_id)),
LayoutNode::Col(_) => find_first_row(layout_tree, parent_id),
- LayoutNode::Widget => None,
+ LayoutNode::Widget(_) => None,
})
}
@@ -1285,21 +1451,23 @@ pub fn move_widget_selection(
.and_then(|(parent_id, parent_node)| match parent_node.get() {
LayoutNode::Row(_) => find_first_col(layout_tree, parent_id),
LayoutNode::Col(_) => Some((parent_id, current_id)),
- LayoutNode::Widget => None,
+ LayoutNode::Widget(_) => None,
})
}
- /// Descends to a leaf.
+ /// Descends to a leaf node.
fn descend_to_leaf(layout_tree: &Arena<LayoutNode>, current_id: NodeId) -> NodeId {
if let Some(current_node) = layout_tree.get(current_id) {
match current_node.get() {
LayoutNode::Row(RowLayout {
last_selected_index,
- constraints: _,
+ parent_rule: _,
+ bound: _,
})
| LayoutNode::Col(ColLayout {
last_selected_index,
- constraints: _,
+ parent_rule: _,
+ bound: _,
}) => {
if let Some(next_child) =
current_id.children(layout_tree).nth(*last_selected_index)
@@ -1309,8 +1477,9 @@ pub fn move_widget_selection(
current_id
}
}
- LayoutNode::Widget => {
+ LayoutNode::Widget(_) => {
// Halt!
+ // TODO: How does this handle carousel?
current_id
}
}
@@ -1470,3 +1639,317 @@ pub fn move_widget_selection(
}
}
}
+
+/// Generates the bounds for each node in the `arena, taking into account per-leaf desires,
+/// and finally storing the calculated bounds in the given `arena`.
+///
+/// Stored bounds are given in *relative* coordinates - they are relative to their parents.
+/// That is, you may have a child widget "start" at (0, 0), but its parent is actually at x = 5,s
+/// so the absolute coordinate of the child widget is actually (5, 0).
+///
+/// The algorithm is mostly based on the algorithm used by Flutter, adapted to work for
+/// our use case. For more information, check out both:
+///
+/// - [How the constraint system works in Flutter](https://flutter.dev/docs/development/ui/layout/constraints)
+/// - [How Flutter does sublinear layout](https://flutter.dev/docs/resources/inside-flutter#sublinear-layout)
+pub fn generate_layout(
+ root: NodeId, arena: &mut Arena<LayoutNode>, area: Rect,
+ lookup_map: &FxHashMap<NodeId, TmpBottomWidget>,
+) {
+ // TODO: [Layout] Add some caching/dirty mechanisms to reduce calls.
+
+ /// A [`Size`] is a set of widths and heights that a node in our layout wants to be.
+ #[derive(Default, Clone, Copy, Debug)]
+ struct Size {
+ width: u16,
+ height: u16,
+ }
+
+ /// A [`LayoutConstraint`] is just a set of maximal widths/heights.
+ #[derive(Clone, Copy, Debug)]
+ struct LayoutConstraints {
+ max_width: u16,
+ max_height: u16,
+ }
+
+ impl LayoutConstraints {
+ fn new(max_width: u16, max_height: u16) -> Self {
+ Self {
+ max_width,
+ max_height,
+ }
+ }
+
+ /// Shrinks the width of itself given another width.
+ fn shrink_width(&mut self, width: u16) {
+ self.max_width = self.max_width.saturating_sub(width);
+ }
+
+ /// Shrinks the height of itself given another height.
+ fn shrink_height(&mut self, height: u16) {
+ self.max_height = self.max_height.saturating_sub(height);
+ }
+
+ /// Returns a new [`LayoutConstraints`] with a new width given a ratio.
+ fn ratio_width(&self, numerator: u32, denominator: u32) -> Self {
+ Self {
+ max_width: (self.max_width as u32 * numerator / denominator) as u16,
+ max_height: self.max_height,
+ }
+ }
+
+ /// Returns a new [`LayoutConstraints`] with a new height given a ratio.
+ fn ratio_height(&self, numerator: u32, denominator: u32) -> Self {
+ Self {
+ max_width: self.max_width,
+ max_height: (self.max_height as u32 * numerator / denominator) as u16,
+ }
+ }
+ }
+
+ /// The internal recursive call to build a layout. Builds off of `arena` and stores bounds inside it.
+ fn layout(
+ node: NodeId, arena: &mut Arena<LayoutNode>,
+ lookup_map: &FxHashMap<NodeId, TmpBottomWidget>, mut constraints: LayoutConstraints,
+ ) -> Size {
+ if let Some(layout_node) = arena.get(node).map(|n| n.get()) {
+ match layout_node {
+ LayoutNode::Row(row) => {
+ let children = node.children(arena).collect::<Vec<_>>();
+ let mut row_bounds = vec![Size::default(); children.len()];
+
+ if let LayoutRule::Length { length } = row.parent_rule {
+ constraints.max_height = length;
+ }
+
+ let (flexible_indices, inflexible_indices): (Vec<_>, Vec<_>) = children
+ .iter()
+ .enumerate()
+ .filter_map(|(itx, node)| {
+ if let Some(layout_node) = arena.get(*node).map(|n| n.get()) {
+ match layout_node {
+ LayoutNode::Row(RowLayout { parent_rule, .. })
+ | LayoutNode::Col(ColLayout { parent_rule, .. }) => {
+ match parent_rule {
+ LayoutRule::Expand { ratio } => {
+ Some((itx, true, *ratio))
+ }
+ LayoutRule::Child => Some((itx, false, 0)),
+ LayoutRule::Length { .. } => Some((itx, false, 0)),
+ }
+ }