From d85ffb58931f03be7e89911c3cdad0240160dc24 Mon Sep 17 00:00:00 2001 From: Erik Kundt Date: Thu, 11 Dec 2025 09:58:27 +0100 Subject: [PATCH] lib: Unify panes and container widget --- bin/commands/inbox/list.rs | 20 +++++++-------- bin/commands/patch/list.rs | 20 +++++++-------- bin/commands/patch/review.rs | 16 ++++++------ src/ui/im.rs | 18 ++----------- src/ui/im/widget.rs | 49 ++++-------------------------------- 5 files changed, 35 insertions(+), 88 deletions(-) diff --git a/bin/commands/inbox/list.rs b/bin/commands/inbox/list.rs index 2e422494..dccd6b9e 100644 --- a/bin/commands/inbox/list.rs +++ b/bin/commands/inbox/list.rs @@ -23,7 +23,7 @@ use radicle_tui as tui; use tui::store; use tui::task::{Process, Task}; use tui::ui::im; -use tui::ui::im::widget::{PanesState, TableState, TextEditState, TextViewState, Window}; +use tui::ui::im::widget::{ContainerState, TableState, TextEditState, TextViewState, Window}; use tui::ui::im::{Borders, Show}; use tui::ui::{BufferedValue, Column}; use tui::{Channel, Exit}; @@ -102,7 +102,7 @@ pub enum Change { page: Page, }, MainGroup { - state: PanesState, + state: ContainerState, }, Patches { state: TableState, @@ -136,7 +136,7 @@ pub enum Page { #[derive(Clone, Debug)] pub struct AppState { page: Page, - main_group: PanesState, + main_group: ContainerState, patches: TableState, search: BufferedValue, show_search: bool, @@ -169,7 +169,7 @@ impl TryFrom<&Context> for App { notifications: Arc::new(Mutex::new(vec![])), state: AppState { page: Page::Main, - main_group: PanesState::new(3, Some(0)), + main_group: ContainerState::new(3, Some(0)), patches: TableState::new(Some(0)), search: BufferedValue::new(TextEditState { text: search.clone(), @@ -204,12 +204,12 @@ impl store::Update for App { }), }), Message::ShowSearch => { - self.state.main_group = PanesState::new(3, None); + self.state.main_group = ContainerState::new(3, None); self.state.show_search = true; None } Message::HideSearch { apply } => { - self.state.main_group = PanesState::new(3, Some(0)); + self.state.main_group = ContainerState::new(3, Some(0)); self.state.show_search = false; if apply { @@ -276,13 +276,13 @@ impl Show for App { let show_search = self.state.show_search; let mut page_focus = if show_search { Some(1) } else { Some(0) }; - ui.panes( + ui.container( Layout::vertical([Constraint::Fill(1), Constraint::Length(2)]), &mut page_focus, |ui| { let mut group_focus = self.state.main_group.focus(); - let group = ui.panes( + let group = ui.container( im::Layout::Expandable3 { left_only: true }, &mut group_focus, |ui| { @@ -291,7 +291,7 @@ impl Show for App { ); if group.response.changed { ui.send_message(Message::Changed(Change::MainGroup { - state: PanesState::new(3, group_focus), + state: ContainerState::new(3, group_focus), })); } @@ -312,7 +312,7 @@ impl Show for App { Constraint::Length(1), ]); - ui.container(layout, 1, |ui| { + ui.container(layout, &mut Some(1), |ui| { self.show_help_text(frame, ui); self.show_help_context(frame, ui); diff --git a/bin/commands/patch/list.rs b/bin/commands/patch/list.rs index 3b7aefa5..0dc19d3c 100644 --- a/bin/commands/patch/list.rs +++ b/bin/commands/patch/list.rs @@ -19,7 +19,7 @@ use radicle_tui as tui; use tui::store; use tui::task::EmptyProcessors; use tui::ui::im; -use tui::ui::im::widget::{PanesState, TableState, TextEditState, TextViewState, Window}; +use tui::ui::im::widget::{ContainerState, TableState, TextEditState, TextViewState, Window}; use tui::ui::im::Borders; use tui::ui::im::Show; use tui::ui::{BufferedValue, Column, Spacing}; @@ -89,7 +89,7 @@ pub enum Change { page: Page, }, MainGroup { - state: PanesState, + state: ContainerState, }, Patches { state: TableState, @@ -122,7 +122,7 @@ pub enum Page { pub struct AppState { mode: Mode, page: Page, - main_group: PanesState, + main_group: ContainerState, patches: TableState, search: BufferedValue, show_search: bool, @@ -161,7 +161,7 @@ impl TryFrom<&Context> for App { state: AppState { mode: context.mode.clone(), page: Page::Main, - main_group: PanesState::new(3, Some(0)), + main_group: ContainerState::new(3, Some(0)), patches: TableState::new(Some(0)), search: BufferedValue::new(TextEditState { text: search.clone(), @@ -203,12 +203,12 @@ impl store::Update for App { }) } Message::ShowSearch => { - self.state.main_group = PanesState::new(3, None); + self.state.main_group = ContainerState::new(3, None); self.state.show_search = true; None } Message::HideSearch { apply } => { - self.state.main_group = PanesState::new(3, Some(0)); + self.state.main_group = ContainerState::new(3, Some(0)); self.state.show_search = false; if apply { @@ -259,13 +259,13 @@ impl Show for App { let show_search = self.state.show_search; let mut page_focus = if show_search { Some(1) } else { Some(0) }; - ui.panes( + ui.container( Layout::vertical([Constraint::Fill(1), Constraint::Length(2)]), &mut page_focus, |ui| { let mut group_focus = self.state.main_group.focus(); - let group = ui.panes( + let group = ui.container( im::Layout::Expandable3 { left_only: true }, &mut group_focus, |ui| { @@ -274,7 +274,7 @@ impl Show for App { ); if group.response.changed { ui.send_message(Message::Changed(Change::MainGroup { - state: PanesState::new(3, group_focus), + state: ContainerState::new(3, group_focus), })); } @@ -295,7 +295,7 @@ impl Show for App { Constraint::Length(1), ]); - ui.container(layout, 1, |ui| { + ui.container(layout, &mut Some(1), |ui| { self.show_help_text(frame, ui); self.show_help_context(frame, ui); diff --git a/bin/commands/patch/review.rs b/bin/commands/patch/review.rs index c63a2a5d..0442b925 100644 --- a/bin/commands/patch/review.rs +++ b/bin/commands/patch/review.rs @@ -24,7 +24,7 @@ use radicle_tui as tui; use tui::store; use tui::task::EmptyProcessors; -use tui::ui::im::widget::{PanesState, TableState, TextViewState, Window}; +use tui::ui::im::widget::{ContainerState, TableState, TextViewState, Window}; use tui::ui::im::{Borders, Context, Show, Ui}; use tui::ui::span; use tui::ui::{Column, Spacing}; @@ -130,7 +130,7 @@ impl Tui { #[derive(Clone, Debug)] pub enum Message { ShowMain, - PanesChanged { state: PanesState }, + PanesChanged { state: ContainerState }, HunkChanged { state: TableState }, HunkViewChanged { state: DiffViewState }, ShowHelp, @@ -167,7 +167,7 @@ pub struct AppState { /// Current app page. page: AppPage, /// State of panes widget on the main page. - panes: PanesState, + panes: ContainerState, /// The hunks' table widget state. hunks: (TableState, Vec), /// Diff view states (cursor position is stored per hunk) @@ -192,7 +192,7 @@ impl AppState { title, revision, page: AppPage::Main, - panes: PanesState::new(2, Some(0)), + panes: ContainerState::new(2, Some(0)), hunks: ( TableState::new(Some(0)), vec![HunkState::Rejected; hunks.len()], @@ -379,7 +379,7 @@ impl App<'_> { .map(|state| state.cursor) .unwrap_or_default(); - ui.container(layout::container(), 1, |ui| { + ui.container(layout::container(), &mut Some(1), |ui| { ui.column_bar( frame, hunk.inner().header(), @@ -529,13 +529,13 @@ impl Show for App<'_> { }; ui.layout(layout::page(), Some(0), |ui| { - let group = ui.panes(layout::list_item(), &mut focus, |ui| { + let group = ui.container(layout::list_item(), &mut focus, |ui| { self.show_hunk_list(ui, frame); self.show_hunk(ui, frame); }); if group.response.changed { ui.send_message(Message::PanesChanged { - state: PanesState::new(count, focus), + state: ContainerState::new(count, focus), }); } @@ -545,7 +545,7 @@ impl Show for App<'_> { } AppPage::Help => { ui.layout(layout::page(), Some(0), |ui| { - ui.container(layout::container(), 1, |ui| { + ui.container(layout::container(), &mut Some(1), |ui| { let mut cursor = { let state = self.state.lock().unwrap(); state.help.cursor() diff --git a/src/ui/im.rs b/src/ui/im.rs index 08ba5602..a45fe460 100644 --- a/src/ui/im.rs +++ b/src/ui/im.rs @@ -479,7 +479,7 @@ impl Ui where M: Clone, { - pub fn panes( + pub fn container( &mut self, layout: impl Into, focus: &mut Option, @@ -497,21 +497,7 @@ where ..self.child_ui(area, layout) }; - widget::Panes::new(len, focus).show(&mut child_ui, add_contents) - } - - pub fn container( - &mut self, - layout: impl Into, - focus: usize, - add_contents: impl FnOnce(&mut Ui) -> R, - ) -> InnerResponse { - let (area, area_focus) = self.next_area().unwrap_or_default(); - - let mut child_ui = self.child_ui(area, layout); - child_ui.has_focus = area_focus; - - widget::Container::new(focus).show(&mut child_ui, add_contents) + widget::Container::new(len, focus).show(&mut child_ui, add_contents) } pub fn popup( diff --git a/src/ui/im/widget.rs b/src/ui/im/widget.rs index 276aed19..c88c305a 100644 --- a/src/ui/im/widget.rs +++ b/src/ui/im/widget.rs @@ -62,12 +62,12 @@ impl Window { } #[derive(Clone, Debug, Serialize, Deserialize)] -pub struct PanesState { +pub struct ContainerState { len: usize, focus: Option, } -impl PanesState { +impl ContainerState { pub fn new(len: usize, focus: Option) -> Self { Self { len, focus } } @@ -95,12 +95,12 @@ impl PanesState { } } -pub struct Panes<'a> { +pub struct Container<'a> { focus: &'a mut Option, len: usize, } -impl<'a> Panes<'a> { +impl<'a> Container<'a> { pub fn new(len: usize, focus: &'a mut Option) -> Self { Self { len, focus } } @@ -126,7 +126,7 @@ impl<'a> Panes<'a> { { let mut response = Response::default(); - let mut state = PanesState { + let mut state = ContainerState { focus: *self.focus, len: self.len, }; @@ -176,45 +176,6 @@ impl CompositeState { } } -pub struct Container { - focus: usize, -} - -impl Container { - pub fn new(focus: usize) -> Self { - Self { focus } - } - - pub fn show( - self, - ui: &mut Ui, - add_contents: impl FnOnce(&mut Ui) -> R, - ) -> InnerResponse - where - M: Clone, - { - self.show_dyn(ui, Box::new(add_contents)) - } - - pub fn show_dyn( - self, - ui: &mut Ui, - add_contents: Box>, - ) -> InnerResponse - where - M: Clone, - { - let mut ui = Ui { - focus_area: Some(self.focus), - ..ui.clone() - }; - - let inner = add_contents(&mut ui); - - InnerResponse::new(inner, Response::default()) - } -} - #[derive(Default)] pub struct Popup {}