lib: Unify panes and container widget

This commit is contained in:
Erik Kundt
2025-12-11 09:58:37 +01:00
parent 3cd7833e29
commit d85ffb5893
5 changed files with 35 additions and 88 deletions
+10 -10
View File
@@ -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<TextEditState>,
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<Message> 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<Message> 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<Message> 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<Message> 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);
+10 -10
View File
@@ -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<TextEditState>,
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<Message> 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<Message> 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<Message> 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<Message> 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);
+8 -8
View File
@@ -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<HunkState>),
/// 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<Message> 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<Message> 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()
+2 -16
View File
@@ -479,7 +479,7 @@ impl<M> Ui<M>
where
M: Clone,
{
pub fn panes<R>(
pub fn container<R>(
&mut self,
layout: impl Into<Layout>,
focus: &mut Option<usize>,
@@ -497,21 +497,7 @@ where
..self.child_ui(area, layout)
};
widget::Panes::new(len, focus).show(&mut child_ui, add_contents)
}
pub fn container<R>(
&mut self,
layout: impl Into<Layout>,
focus: usize,
add_contents: impl FnOnce(&mut Ui<M>) -> R,
) -> InnerResponse<R> {
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<R>(
+5 -44
View File
@@ -62,12 +62,12 @@ impl Window {
}
#[derive(Clone, Debug, Serialize, Deserialize)]
pub struct PanesState {
pub struct ContainerState {
len: usize,
focus: Option<usize>,
}
impl PanesState {
impl ContainerState {
pub fn new(len: usize, focus: Option<usize>) -> Self {
Self { len, focus }
}
@@ -95,12 +95,12 @@ impl PanesState {
}
}
pub struct Panes<'a> {
pub struct Container<'a> {
focus: &'a mut Option<usize>,
len: usize,
}
impl<'a> Panes<'a> {
impl<'a> Container<'a> {
pub fn new(len: usize, focus: &'a mut Option<usize>) -> 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<M, R>(
self,
ui: &mut Ui<M>,
add_contents: impl FnOnce(&mut Ui<M>) -> R,
) -> InnerResponse<R>
where
M: Clone,
{
self.show_dyn(ui, Box::new(add_contents))
}
pub fn show_dyn<M, R>(
self,
ui: &mut Ui<M>,
add_contents: Box<AddContentFn<M, R>>,
) -> InnerResponse<R>
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 {}