use crate::layout::AppLayout;
use crate::theme::Theme;
use crate::widgets;
use super::{App, Panel};
impl App {
pub fn draw(&mut self, frame: &mut ratatui::Frame) {
let layout = AppLayout::compute(
frame.area(),
self.show_side_panels,
self.desired_input_height(),
);
self.draw_header(frame, layout.header);
if self.sessions.current().show_splash {
widgets::splash::render(frame, layout.chat);
} else {
let mut cache = std::mem::take(&mut self.sessions.current_mut().render_cache);
let max_scroll = widgets::chat::render(self, frame, layout.chat, &mut cache);
self.sessions.current_mut().render_cache = cache;
self.sessions.current_mut().scroll_offset =
self.sessions.current().scroll_offset.min(max_scroll);
}
self.draw_side_panel(frame, &layout);
widgets::chat::render_activity(self, frame, layout.activity);
widgets::input::render(self, frame, layout.input);
widgets::status::render(self, &self.metrics, frame, layout.status);
if let Some(state) = &self.file_picker_state {
widgets::file_picker::render(state, frame, layout.input);
}
if let Some(state) = &self.slash_autocomplete {
widgets::slash_autocomplete::render(state, frame, layout.input);
}
if let Some(state) = &self.confirm_state {
widgets::confirm::render(&state.prompt, frame, frame.area());
}
if let Some(state) = &self.elicitation_state {
widgets::elicitation::render(&state.dialog, frame, frame.area());
}
if let Some(palette) = &self.command_palette {
widgets::command_palette::render(palette, frame, frame.area());
}
if self.show_help {
widgets::help::render(frame, frame.area());
}
}
pub(super) fn draw_header(&self, frame: &mut ratatui::Frame, area: ratatui::layout::Rect) {
use ratatui::text::{Line, Span};
use ratatui::widgets::Paragraph;
let theme = Theme::default();
let provider = if self.metrics.provider_name.is_empty() {
"---"
} else {
&self.metrics.provider_name
};
let model = if self.metrics.model_name.is_empty() {
"---"
} else {
&self.metrics.model_name
};
let ctx_badge = if self.metrics.extended_context {
" [1M CTX]"
} else {
""
};
let text = format!(
" Zeph v{} | Provider: {provider} | Model: {model}{ctx_badge}",
env!("CARGO_PKG_VERSION")
);
let line = Line::from(Span::styled(text, theme.header));
let paragraph = Paragraph::new(line).style(theme.header);
frame.render_widget(paragraph, area);
}
fn draw_side_panel(&mut self, frame: &mut ratatui::Frame, layout: &AppLayout) {
widgets::skills::render(&self.metrics, frame, layout.skills);
widgets::memory::render(&self.metrics, frame, layout.memory);
{
use ratatui::layout::{Constraint, Direction, Layout};
let context_split = Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Length(3),
Constraint::Length(3),
Constraint::Min(0),
])
.split(layout.resources);
widgets::context_gauge::render(&self.metrics, frame, context_split[0]);
widgets::compaction_badge::render(&self.metrics, frame, context_split[1]);
widgets::resources::render(&self.metrics, frame, context_split[2]);
}
let tick = self.throbber_state.index().cast_unsigned();
let has_graph = self.metrics.orchestration_graph.as_ref().is_some_and(|s| {
!s.is_stale()
});
let panel_focused = self.active_panel == Panel::SubAgents;
if panel_focused {
widgets::subagents::render_interactive(
&self.metrics,
&mut self.subagent_sidebar,
frame,
layout.subagents,
tick,
);
} else if has_graph && !self.sessions.current().plan_view_active {
widgets::plan_view::render(&self.metrics, frame, layout.subagents, tick);
} else if self.has_recent_security_events() {
widgets::security::render(&self.metrics, frame, layout.subagents);
} else {
widgets::subagents::render(&self.metrics, frame, layout.subagents);
}
if self.show_task_panel {
if self.task_supervisor.is_some() {
widgets::task_registry::render(
&self.cached_task_snapshots,
tick,
layout.subagents,
frame,
);
} else {
use ratatui::widgets::{Block, Borders, Paragraph, Wrap};
let theme = Theme::default();
let block = Block::default()
.borders(Borders::ALL)
.border_style(theme.panel_border)
.title(" Tasks ");
let paragraph = Paragraph::new(" Task supervisor not available.")
.block(block)
.wrap(Wrap { trim: true });
frame.render_widget(paragraph, layout.subagents);
}
}
}
}