Files
herdr/src/ui.rs

153 lines
4.7 KiB
Rust

use ratatui::layout::Rect;
mod onboarding;
mod panes;
mod release_notes;
mod scrollbar;
mod sidebar;
mod status;
mod tab_surface;
mod text;
mod widgets;
pub(crate) use self::onboarding::{
onboarding_welcome_continue_rect, ONBOARDING_DESCRIPTION, ONBOARDING_HELP_LABEL,
ONBOARDING_HELP_SUFFIX, ONBOARDING_NEXT, ONBOARDING_PREFIX_LABEL, ONBOARDING_PREFIX_SUFFIX,
ONBOARDING_SUBTITLE, ONBOARDING_TITLE,
};
#[cfg(all(test, unix))]
pub(crate) use self::panes::popup_pane_rects;
use self::panes::resize_popup_pane;
pub(crate) use self::panes::{
apply_pane_chrome, pane_inner_rect, pane_is_scrolled_back, render_selection_highlight,
};
pub(crate) use self::release_notes::{
product_announcement_display_lines, product_announcement_scroll_metrics,
release_notes_close_button_rect, release_notes_display_lines, release_notes_scroll_metrics,
PRODUCT_ANNOUNCEMENT_MODAL_SIZE, RELEASE_NOTES_MODAL_SIZE,
};
pub(crate) use self::scrollbar::{
release_notes_scrollbar_rect, render_pane_scrollbar_buffer, render_scrollbar_buffer,
scrollbar_offset_from_drag_row, scrollbar_offset_from_row, scrollbar_thumb,
scrollbar_thumb_grab_offset,
};
pub(crate) use self::sidebar::{
agent_panel_entries_from, expanded_sidebar_sections, resolved_token_spans, sidebar_agent_rows,
sidebar_section_divider_rect, sidebar_space_rows, AgentPanelEntry, AgentTokenContext,
ResolvedToken, ResolvedTokenKind, SpaceTokenContext,
};
use self::status::copy_feedback_rect;
pub(crate) use self::status::{render_config_diagnostic_buffer, render_copy_feedback_buffer};
pub(crate) use self::tab_surface::{
compute_tab_surface, compute_tab_surface_for, render_tab_surface, resize_tab_surface,
tab_surface_cursor, tab_surface_hyperlinks, TabSurfaceLayout, TabSurfaceTarget, TabSurfaceView,
};
pub(crate) use self::text::truncate_end;
pub(crate) use self::widgets::{centered_popup_rect, modal_stack_areas};
use crate::app::AppState;
use crate::terminal::TerminalRuntimeRegistry;
pub fn compute_view_with_runtime_registry(
app: &mut AppState,
terminal_runtimes: &TerminalRuntimeRegistry,
area: Rect,
) {
compute_view_internal(
app,
terminal_runtimes,
area,
true,
crate::kitty_graphics::HostCellSize::default(),
);
}
pub fn compute_view_with_cell_size(
app: &mut AppState,
terminal_runtimes: &TerminalRuntimeRegistry,
area: Rect,
cell_size: crate::kitty_graphics::HostCellSize,
) {
compute_view_internal(app, terminal_runtimes, area, true, cell_size);
}
pub(crate) fn compute_view_without_resizing_panes(
app: &mut AppState,
terminal_runtimes: &TerminalRuntimeRegistry,
area: Rect,
) {
compute_view_internal(
app,
terminal_runtimes,
area,
false,
crate::kitty_graphics::HostCellSize::default(),
);
}
fn compute_view_internal(
app: &mut AppState,
terminal_runtimes: &TerminalRuntimeRegistry,
area: Rect,
resize_panes: bool,
cell_size: crate::kitty_graphics::HostCellSize,
) {
let TabSurfaceLayout { pane_infos, .. } =
compute_tab_surface(app, terminal_runtimes, area, resize_panes, cell_size);
if resize_panes {
resize_background_tab_panes(app, terminal_runtimes, area, cell_size);
resize_popup_pane(app, terminal_runtimes, area, cell_size);
}
app.view = crate::app::ViewState {
terminal_area: area,
pane_infos,
};
}
fn resize_background_tab_panes(
app: &AppState,
terminal_runtimes: &TerminalRuntimeRegistry,
area: Rect,
cell_size: crate::kitty_graphics::HostCellSize,
) {
for (workspace_index, workspace) in app.workspaces.iter().enumerate() {
for tab_index in 0..workspace.tabs.len() {
if app.active == Some(workspace_index) && tab_index == workspace.active_tab_index() {
continue;
}
resize_tab_surface(
app,
terminal_runtimes,
workspace_index,
tab_index,
area,
cell_size,
);
}
}
}
pub(crate) fn copy_feedback_offset_for_toast(
area: Rect,
feedback: &crate::app::state::CopyFeedback,
base_offset: u16,
position: crate::config::ToastClipboardPosition,
toast_rect: Rect,
) -> u16 {
let feedback_rect = copy_feedback_rect(area, feedback, base_offset, position);
if rectangles_overlap(feedback_rect, toast_rect) {
base_offset.saturating_add(toast_rect.height)
} else {
base_offset
}
}
fn rectangles_overlap(left: Rect, right: Rect) -> bool {
left.x < right.right()
&& right.x < left.right()
&& left.y < right.bottom()
&& right.y < left.bottom()
}