forked from kent/consciousness
Convert SectionTree and all remaining callers to ScrollPane
SectionTree.scroll is now a ScrollPaneState. All callers of render_scrollable replaced with ScrollPane::render_stateful_widget. Deleted render_scrollable and its imports — no hand-rolled scroll rendering remains outside of scroll_pane.rs. Co-Authored-By: Kent Overstreet <kent.overstreet@gmail.com>
This commit is contained in:
parent
4a1f5acb85
commit
e17118e4c9
3 changed files with 19 additions and 47 deletions
|
|
@ -6,7 +6,7 @@ use ratatui::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{App, ScreenView, screen_legend};
|
use super::{App, ScreenView, screen_legend};
|
||||||
use super::widgets::{SectionTree, SectionView, section_to_view, pane_block, render_scrollable, tree_legend};
|
use super::widgets::{SectionTree, SectionView, section_to_view, pane_block, tree_legend};
|
||||||
use crate::agent::context::{AstNode, NodeBody, Ast};
|
use crate::agent::context::{AstNode, NodeBody, Ast};
|
||||||
|
|
||||||
pub(crate) struct ConsciousScreen {
|
pub(crate) struct ConsciousScreen {
|
||||||
|
|
@ -177,6 +177,7 @@ impl ScreenView for ConsciousScreen {
|
||||||
.title_top(Line::from(screen_legend()).left_aligned())
|
.title_top(Line::from(screen_legend()).left_aligned())
|
||||||
.title_bottom(tree_legend());
|
.title_bottom(tree_legend());
|
||||||
|
|
||||||
render_scrollable(frame, area, lines, block, self.tree.scroll);
|
let widget = super::scroll_pane::ScrollPane::new(&lines).block(block);
|
||||||
|
frame.render_stateful_widget(widget, area, &mut self.tree.scroll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -15,7 +15,7 @@ use ratatui::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::{App, ScreenView, screen_legend};
|
use super::{App, ScreenView, screen_legend};
|
||||||
use super::widgets::{SectionTree, SectionView, section_to_view, pane_block_focused, render_scrollable, tree_legend, format_age, format_ts_age};
|
use super::widgets::{SectionTree, SectionView, section_to_view, pane_block_focused, tree_legend, format_age, format_ts_age};
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq)]
|
#[derive(Clone, Copy, PartialEq)]
|
||||||
enum Pane { Agents, Outputs, History, Context }
|
enum Pane { Agents, Outputs, History, Context }
|
||||||
|
|
@ -282,7 +282,7 @@ impl SubconsciousScreen {
|
||||||
frame.render_stateful_widget(list, area, &mut self.list_state);
|
frame.render_stateful_widget(list, area, &mut self.list_state);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_outputs(&self, frame: &mut Frame, area: Rect, app: &App) {
|
fn draw_outputs(&mut self, frame: &mut Frame, area: Rect, app: &App) {
|
||||||
let sections = self.output_sections(app);
|
let sections = self.output_sections(app);
|
||||||
let mut lines: Vec<Line> = Vec::new();
|
let mut lines: Vec<Line> = Vec::new();
|
||||||
|
|
||||||
|
|
@ -297,7 +297,8 @@ impl SubconsciousScreen {
|
||||||
|
|
||||||
let mut block = pane_block_focused("state", self.focus == Pane::Outputs);
|
let mut block = pane_block_focused("state", self.focus == Pane::Outputs);
|
||||||
if self.focus == Pane::Outputs { block = block.title_bottom(tree_legend()); }
|
if self.focus == Pane::Outputs { block = block.title_bottom(tree_legend()); }
|
||||||
render_scrollable(frame, area, lines, block, self.output_tree.scroll);
|
let widget = super::scroll_pane::ScrollPane::new(&lines).block(block);
|
||||||
|
frame.render_stateful_widget(widget, area, &mut self.output_tree.scroll);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_history(&mut self, frame: &mut Frame, area: Rect, app: &App) {
|
fn draw_history(&mut self, frame: &mut Frame, area: Rect, app: &App) {
|
||||||
|
|
@ -351,7 +352,7 @@ impl SubconsciousScreen {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn draw_context(
|
fn draw_context(
|
||||||
&self,
|
&mut self,
|
||||||
frame: &mut Frame,
|
frame: &mut Frame,
|
||||||
area: Rect,
|
area: Rect,
|
||||||
sections: &[SectionView],
|
sections: &[SectionView],
|
||||||
|
|
@ -374,6 +375,7 @@ impl SubconsciousScreen {
|
||||||
|
|
||||||
let mut block = pane_block_focused(title, self.focus == Pane::Context);
|
let mut block = pane_block_focused(title, self.focus == Pane::Context);
|
||||||
if self.focus == Pane::Context { block = block.title_bottom(tree_legend()); }
|
if self.focus == Pane::Context { block = block.title_bottom(tree_legend()); }
|
||||||
render_scrollable(frame, area, lines, block, self.context_tree.scroll);
|
let widget = super::scroll_pane::ScrollPane::new(&lines).block(block);
|
||||||
|
frame.render_stateful_widget(widget, area, &mut self.context_tree.scroll);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,11 +1,9 @@
|
||||||
// widgets.rs — Shared TUI helpers and reusable components
|
// widgets.rs — Shared TUI helpers and reusable components
|
||||||
|
|
||||||
use ratatui::{
|
use ratatui::{
|
||||||
layout::{Margin, Rect},
|
|
||||||
style::{Color, Modifier, Style},
|
style::{Color, Modifier, Style},
|
||||||
text::Line,
|
text::Line,
|
||||||
widgets::{Block, Borders, Paragraph, Scrollbar, ScrollbarOrientation, ScrollbarState, Wrap},
|
widgets::{Block, Borders},
|
||||||
Frame,
|
|
||||||
crossterm::event::KeyCode,
|
crossterm::event::KeyCode,
|
||||||
};
|
};
|
||||||
use crate::agent::context::{AstNode, Ast};
|
use crate::agent::context::{AstNode, Ast};
|
||||||
|
|
@ -102,35 +100,6 @@ pub fn tree_legend() -> Line<'static> {
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Render a scrollable paragraph with a vertical scrollbar.
|
|
||||||
///
|
|
||||||
/// Legacy wrapper — callers that manage their own `u16` scroll offset
|
|
||||||
/// use this. For new code, prefer ScrollPane + ScrollPaneState.
|
|
||||||
pub fn render_scrollable(
|
|
||||||
frame: &mut Frame,
|
|
||||||
area: Rect,
|
|
||||||
lines: Vec<Line<'_>>,
|
|
||||||
block: Block<'_>,
|
|
||||||
scroll: u16,
|
|
||||||
) {
|
|
||||||
let content_len = lines.len();
|
|
||||||
let para = Paragraph::new(lines)
|
|
||||||
.block(block)
|
|
||||||
.wrap(Wrap { trim: false })
|
|
||||||
.scroll((scroll, 0));
|
|
||||||
frame.render_widget(para, area);
|
|
||||||
|
|
||||||
let visible = area.height.saturating_sub(2) as usize;
|
|
||||||
if content_len > visible {
|
|
||||||
let mut sb_state = ScrollbarState::new(content_len)
|
|
||||||
.position(scroll as usize);
|
|
||||||
frame.render_stateful_widget(
|
|
||||||
Scrollbar::new(ScrollbarOrientation::VerticalRight),
|
|
||||||
area.inner(Margin { vertical: 1, horizontal: 0 }),
|
|
||||||
&mut sb_state,
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// ---------------------------------------------------------------------------
|
// ---------------------------------------------------------------------------
|
||||||
// SectionTree — expand/collapse tree renderer for ContextSection
|
// SectionTree — expand/collapse tree renderer for ContextSection
|
||||||
|
|
@ -139,12 +108,12 @@ pub fn render_scrollable(
|
||||||
pub struct SectionTree {
|
pub struct SectionTree {
|
||||||
pub selected: Option<usize>,
|
pub selected: Option<usize>,
|
||||||
pub expanded: std::collections::HashSet<usize>,
|
pub expanded: std::collections::HashSet<usize>,
|
||||||
pub scroll: u16,
|
pub scroll: super::scroll_pane::ScrollPaneState,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SectionTree {
|
impl SectionTree {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
Self { selected: None, expanded: std::collections::HashSet::new(), scroll: 0 }
|
Self { selected: None, expanded: std::collections::HashSet::new(), scroll: super::scroll_pane::ScrollPaneState::new() }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn total_nodes(&self, sections: &[SectionView]) -> usize {
|
fn total_nodes(&self, sections: &[SectionView]) -> usize {
|
||||||
|
|
@ -184,14 +153,14 @@ impl SectionTree {
|
||||||
KeyCode::PageUp => {
|
KeyCode::PageUp => {
|
||||||
let sel = self.selected.unwrap_or(0);
|
let sel = self.selected.unwrap_or(0);
|
||||||
self.selected = Some(sel.saturating_sub(page));
|
self.selected = Some(sel.saturating_sub(page));
|
||||||
self.scroll = self.scroll.saturating_sub(page as u16);
|
self.scroll.scroll_up(page as u16);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
KeyCode::PageDown => {
|
KeyCode::PageDown => {
|
||||||
let max = item_count.saturating_sub(1);
|
let max = item_count.saturating_sub(1);
|
||||||
let sel = self.selected.map_or(0, |s| (s + page).min(max));
|
let sel = self.selected.map_or(0, |s| (s + page).min(max));
|
||||||
self.selected = Some(sel);
|
self.selected = Some(sel);
|
||||||
self.scroll += page as u16;
|
self.scroll.scroll_down(page as u16);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
KeyCode::Home => {
|
KeyCode::Home => {
|
||||||
|
|
@ -228,10 +197,10 @@ impl SectionTree {
|
||||||
if let Some(sel) = self.selected {
|
if let Some(sel) = self.selected {
|
||||||
let sel_line = sel as u16;
|
let sel_line = sel as u16;
|
||||||
let visible = height.saturating_sub(2);
|
let visible = height.saturating_sub(2);
|
||||||
if sel_line < self.scroll {
|
if sel_line < self.scroll.offset {
|
||||||
self.scroll = sel_line;
|
self.scroll.offset = sel_line;
|
||||||
} else if sel_line >= self.scroll + visible {
|
} else if sel_line >= self.scroll.offset + visible {
|
||||||
self.scroll = sel_line.saturating_sub(visible.saturating_sub(1));
|
self.scroll.offset = sel_line.saturating_sub(visible.saturating_sub(1));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue