From 52bd9cc30bb11f15286b76411d0f92a6dd9f97f2 Mon Sep 17 00:00:00 2001 From: Paul Campbell Date: Wed, 28 Aug 2024 22:25:31 +0100 Subject: [PATCH] feat(tui): forge widgets only use required lines Rather than filling all the space available, the ForgeWidget now only uses as many lines as it needs to show its contents. --- .../cli/src/tui/components/configured_app.rs | 33 +++++++++++++------ .../cli/src/tui/components/forge/collapsed.rs | 7 ++++ .../cli/src/tui/components/forge/expanded.rs | 23 ++++++++++--- crates/cli/src/tui/components/forge/mod.rs | 23 +++++++++++-- 4 files changed, 69 insertions(+), 17 deletions(-) diff --git a/crates/cli/src/tui/components/configured_app.rs b/crates/cli/src/tui/components/configured_app.rs index 493c4a7..908b410 100644 --- a/crates/cli/src/tui/components/configured_app.rs +++ b/crates/cli/src/tui/components/configured_app.rs @@ -3,17 +3,26 @@ use std::collections::BTreeMap; use git_next_core::ForgeAlias; use ratatui::{ buffer::Buffer, - layout::{Constraint, Direction, Layout, Rect}, + layout::{Direction, Layout, Rect}, widgets::Widget, }; -use crate::tui::actor::{ForgeState, ViewState}; +use crate::tui::actor::ForgeState; -use super::forge::ForgeWidget; +use super::{forge::ForgeWidget, HeightContraintLength}; pub struct ConfiguredAppWidget<'a> { pub forges: &'a BTreeMap, } +impl<'a> HeightContraintLength for ConfiguredAppWidget<'a> { + fn height_constraint_length(&self) -> u16 { + self.children() + .iter() + .map(HeightContraintLength::height_constraint_length) + .sum::() + + 2 // top + bottom borders + } +} impl<'a> Widget for ConfiguredAppWidget<'a> { fn render(self, area: Rect, buf: &mut Buffer) where @@ -22,15 +31,20 @@ impl<'a> Widget for ConfiguredAppWidget<'a> { let layout_forge_list = Layout::default() .direction(Direction::Vertical) .constraints( - self.forges + self.children() .iter() - .map(|(_alias, state)| match state.view_state { - ViewState::Collapsed => Constraint::Length(1), - ViewState::Expanded => Constraint::Fill(1), - }), + .map(HeightContraintLength::height_constraint_length), ) .split(area); + self.children() + .into_iter() + .enumerate() + .for_each(|(i, w)| w.render(layout_forge_list[i], buf)); + } +} +impl<'a> ConfiguredAppWidget<'a> { + fn children(&self) -> Vec> { self.forges .iter() .map(|(forge_alias, state)| ForgeWidget { @@ -38,7 +52,6 @@ impl<'a> Widget for ConfiguredAppWidget<'a> { repos: &state.repos, view_state: state.view_state, }) - .enumerate() - .for_each(|(i, w)| w.render(layout_forge_list[i], buf)); + .collect::>() } } diff --git a/crates/cli/src/tui/components/forge/collapsed.rs b/crates/cli/src/tui/components/forge/collapsed.rs index 72761e5..3245efc 100644 --- a/crates/cli/src/tui/components/forge/collapsed.rs +++ b/crates/cli/src/tui/components/forge/collapsed.rs @@ -2,9 +2,16 @@ use git_next_core::ForgeAlias; use ratatui::{buffer::Buffer, layout::Rect, text::Text, widgets::Widget}; +use crate::tui::components::HeightContraintLength; + pub struct CollapsedForgeWidget<'a> { pub forge_alias: &'a ForgeAlias, } +impl<'a> HeightContraintLength for CollapsedForgeWidget<'a> { + fn height_constraint_length(&self) -> u16 { + 1 + } +} impl<'a> Widget for CollapsedForgeWidget<'a> { fn render(self, area: Rect, buf: &mut Buffer) where diff --git a/crates/cli/src/tui/components/forge/expanded.rs b/crates/cli/src/tui/components/forge/expanded.rs index ea989ab..514bd02 100644 --- a/crates/cli/src/tui/components/forge/expanded.rs +++ b/crates/cli/src/tui/components/forge/expanded.rs @@ -17,6 +17,15 @@ pub struct ExpandedForgeWidget<'a> { pub forge_alias: &'a ForgeAlias, pub repos: &'a BTreeMap, } +impl<'a> HeightContraintLength for ExpandedForgeWidget<'a> { + fn height_constraint_length(&self) -> u16 { + self.children() + .iter() + .map(HeightContraintLength::height_constraint_length) + .sum::() + + 2 // top + bottom borders + } +} impl<'a> Widget for ExpandedForgeWidget<'a> { fn render(self, area: Rect, buf: &mut Buffer) where @@ -25,11 +34,7 @@ impl<'a> Widget for ExpandedForgeWidget<'a> { let block = Block::default() .title(Title::from(format!(" forge: {} ", self.forge_alias)).alignment(Alignment::Left)) .borders(Borders::ALL); - let children = self - .repos - .values() - .map(|repo_state| RepoWidget { repo_state }) - .collect::>(); + let children = self.children(); let layout = Layout::default() .direction(Direction::Vertical) .constraints( @@ -45,3 +50,11 @@ impl<'a> Widget for ExpandedForgeWidget<'a> { .for_each(|(i, w)| w.render(layout[i], buf)); } } +impl<'a> ExpandedForgeWidget<'a> { + fn children(&self) -> Vec> { + self.repos + .values() + .map(|repo_state| RepoWidget { repo_state }) + .collect::>() + } +} diff --git a/crates/cli/src/tui/components/forge/mod.rs b/crates/cli/src/tui/components/forge/mod.rs index 3851d78..afce0e8 100644 --- a/crates/cli/src/tui/components/forge/mod.rs +++ b/crates/cli/src/tui/components/forge/mod.rs @@ -4,27 +4,46 @@ mod expanded; use std::collections::BTreeMap; +use collapsed::CollapsedForgeWidget; +use expanded::ExpandedForgeWidget; use git_next_core::{ForgeAlias, RepoAlias}; use ratatui::{buffer::Buffer, layout::Rect, widgets::Widget}; use crate::tui::actor::{RepoState, ViewState}; +use super::HeightContraintLength; + pub struct ForgeWidget<'a> { pub forge_alias: &'a ForgeAlias, pub repos: &'a BTreeMap, pub view_state: ViewState, } +impl<'a> HeightContraintLength for ForgeWidget<'a> { + fn height_constraint_length(&self) -> u16 { + match self.view_state { + ViewState::Collapsed => CollapsedForgeWidget { + forge_alias: self.forge_alias, + } + .height_constraint_length(), + ViewState::Expanded => ExpandedForgeWidget { + forge_alias: self.forge_alias, + repos: self.repos, + } + .height_constraint_length(), + } + } +} impl<'a> Widget for ForgeWidget<'a> { fn render(self, area: Rect, buf: &mut Buffer) where Self: Sized, { match self.view_state { - ViewState::Collapsed => collapsed::CollapsedForgeWidget { + ViewState::Collapsed => CollapsedForgeWidget { forge_alias: self.forge_alias, } .render(area, buf), - ViewState::Expanded => expanded::ExpandedForgeWidget { + ViewState::Expanded => ExpandedForgeWidget { forge_alias: self.forge_alias, repos: self.repos, }