use super::{App, HORIZONTAL_SCROLL_STEP};
use anyhow::Result;
use ratatui::prelude::*;
impl App {
pub(super) fn clamp_logs_scroll_position(&mut self) -> Result<()> {
let lines_count = self.logs_block.get_lines_count();
let current_position = self.logs_block.get_scroll_position();
let viewport_height = if let Some(area) = self.last_logs_area {
let is_focused = self.is_log_block_focused().unwrap_or(false);
let [main_content_area, _] =
Layout::horizontal([Constraint::Fill(1), Constraint::Length(1)])
.margin(0)
.areas(area);
let [content_area, _] = Layout::vertical([Constraint::Fill(1), Constraint::Length(1)])
.margin(0)
.areas(main_content_area);
let inner_area = self.logs_block.get_content_rect(content_area, is_focused);
inner_area.height as usize
} else {
1 };
let adjusted_position = if let Some(prev_height) = self.last_logs_viewport_height {
if prev_height != viewport_height {
let prev_bottom_item = current_position
.saturating_add(prev_height)
.saturating_sub(1)
.min(lines_count.saturating_sub(1));
let new_position = prev_bottom_item
.saturating_add(1)
.saturating_sub(viewport_height);
log::debug!(
"Viewport height changed: {} -> {}, adjusting scroll: {} -> {} (preserving bottom item: {})",
prev_height,
viewport_height,
current_position,
new_position,
prev_bottom_item
);
new_position
} else {
current_position
}
} else {
current_position
};
self.last_logs_viewport_height = Some(viewport_height);
let max_scroll = lines_count.saturating_sub(viewport_height);
let clamped_position = adjusted_position.min(max_scroll);
if clamped_position != current_position {
self.logs_block.set_scroll_position(clamped_position);
}
self.logs_block
.update_scrollbar_state(lines_count, Some(clamped_position));
Ok(())
}
pub(super) fn handle_log_item_scrolling(
&mut self,
move_next: bool,
circular: bool,
) -> Result<()> {
match (move_next, circular) {
(true, true) => {
self.displaying_logs.select_next_circular();
}
(true, false) => {
self.displaying_logs.select_next();
}
(false, true) => {
self.displaying_logs.select_previous_circular();
}
(false, false) => {
self.displaying_logs.select_previous();
}
}
self.update_selected_uuid();
self.after_selection_change()?;
Ok(())
}
pub(super) fn handle_logs_view_scrolling(&mut self, move_down: bool) -> Result<()> {
let lines_count = self.logs_block.get_lines_count();
let current_position = self.logs_block.get_scroll_position();
let viewport_height = if let Some(area) = self.last_logs_area {
let is_focused = self.is_log_block_focused().unwrap_or(false);
let [main_content_area, _] =
Layout::horizontal([Constraint::Fill(1), Constraint::Length(1)])
.margin(0)
.areas(area);
let [content_area, _] = Layout::vertical([Constraint::Fill(1), Constraint::Length(1)])
.margin(0)
.areas(main_content_area);
let inner_area = self.logs_block.get_content_rect(content_area, is_focused);
inner_area.height as usize
} else {
1 };
let max_scroll = lines_count.saturating_sub(viewport_height);
let new_position = if move_down {
if current_position >= max_scroll {
current_position } else {
current_position.saturating_add(1)
}
} else {
current_position.saturating_sub(1)
};
self.logs_block.set_scroll_position(new_position);
self.clamp_logs_scroll_position()?;
Ok(())
}
pub(super) fn handle_details_block_scrolling(&mut self, move_next: bool) -> Result<()> {
let lines_count = self.details_block.get_lines_count();
if lines_count == 0 {
self.details_block.set_scroll_position(0);
self.details_block.update_scrollbar_state(0, Some(0));
return Ok(());
}
let current_position = self.details_block.get_scroll_position();
let last_index = lines_count.saturating_sub(1);
let new_position = if move_next {
current_position
.min(last_index) .saturating_add(1)
.min(last_index) } else {
current_position.saturating_sub(1)
};
self.details_block.set_scroll_position(new_position);
self.details_block
.update_scrollbar_state(lines_count, Some(new_position));
Ok(())
}
pub(super) fn handle_debug_logs_scrolling(&mut self, move_next: bool) -> Result<()> {
let lines_count = self.debug_block.get_lines_count();
if lines_count == 0 {
self.debug_block.set_scroll_position(0);
self.debug_block.update_scrollbar_state(0, Some(0));
return Ok(());
}
let current_position = self.debug_block.get_scroll_position();
let last_index = lines_count.saturating_sub(1);
let new_position = if move_next {
current_position
.min(last_index)
.saturating_add(1)
.min(last_index)
} else {
current_position.saturating_sub(1)
};
self.debug_block.set_scroll_position(new_position);
self.debug_block
.update_scrollbar_state(lines_count, Some(new_position));
Ok(())
}
pub(super) fn handle_horizontal_scrolling(
&mut self,
block_id: uuid::Uuid,
move_right: bool,
) -> Result<()> {
let (block, area) = if block_id == self.logs_block.id() {
(&mut self.logs_block, self.last_logs_area)
} else if block_id == self.details_block.id() {
(&mut self.details_block, self.last_details_area)
} else if block_id == self.debug_block.id() {
(&mut self.debug_block, self.last_debug_area)
} else {
return Ok(());
};
let Some(area) = area else {
return Ok(());
};
let current_position = block.get_horizontal_scroll_position();
let content_width = block.get_content_width();
let [main_content_area, _scrollbar_area] = Layout::horizontal([
Constraint::Fill(1), Constraint::Length(1), ])
.margin(0)
.areas(area);
let [content_area, _horizontal_scrollbar_area] = Layout::vertical([
Constraint::Fill(1), Constraint::Length(1), ])
.margin(0)
.areas(main_content_area);
let content_rect = block.get_content_rect(content_area, true);
let viewport_width = content_rect.width as usize;
if content_width <= viewport_width {
return Ok(());
}
let max_scroll = content_width.saturating_sub(viewport_width);
let new_position = if move_right {
current_position
.saturating_add(HORIZONTAL_SCROLL_STEP)
.min(max_scroll)
} else {
current_position.saturating_sub(HORIZONTAL_SCROLL_STEP)
};
block.set_horizontal_scroll_position(new_position);
block.update_horizontal_scrollbar_state(content_width, viewport_width);
Ok(())
}
}