Files
Kigi-CLI/crates/codegen/kigi-pager-render/src/render/video_overlay.rs
T
ZacharyZhang-NY a02b555e66 docs(comments): rewrite comments across all crates to the guidelines
Sweep every first-party crate source (1956 .rs files) to the project comment
guidelines: delete redundant restatements, decorative banners, change
narration, and end-of-line comments; keep and tighten the crucial ones
(invariants, bug rationale, SAFETY blocks, ported-source attribution).

No functional code changed. Every edit is proven comment-only against the
prior tree by a comment-stripping lexer (string/char/raw-string aware) plus a
separate doctest-fence check. Where removing a comment made rustfmt or clippy
want to re-lay-out adjacent code, the minimal triggering comment is restored so
code tokens stay byte-identical.

Gates green: cargo fmt --all --check (0 diffs), cargo check and cargo clippy
--workspace --all-targets (0 warnings).

Adds scripts/check_codegen_comment_guidelines.py — the enforcement gate for
these guidelines (flags banners, end-of-line comments, change narration, and
commented-out code).
2026-07-23 16:55:39 -04:00

143 lines
3.9 KiB
Rust

//! Video playback overlay chrome (border, title, progress bar).
//!
//! The video frame itself is rendered via post-flush escape sequences
//! by the caller, matching the image viewer pattern.
use ratatui::buffer::Buffer;
use ratatui::layout::Rect;
use ratatui::style::{Color, Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, BorderType, Borders, Widget};
use crate::prompt_images::VideoViewerState;
use crate::render::safe_buf::SafeBuf;
pub fn render_video_overlay(
buf: &mut Buffer,
area: Rect,
viewer: &VideoViewerState,
bg: Color,
text_fg: Color,
border_fg: Color,
) -> Option<Rect> {
if area.height < 8 || area.width < 20 {
return None;
}
crate::render::color::dim_area(buf, area, bg, 0.5);
let popup_width = ((area.width as u32 * 90) / 100)
.max(28)
.min(area.width as u32) as u16;
let popup_height = ((area.height as u32 * 90) / 100)
.max(8)
.min(area.height as u32) as u16;
let popup_x = area.x + (area.width.saturating_sub(popup_width)) / 2;
let popup_y = area.y + (area.height.saturating_sub(popup_height)) / 2;
let popup_rect = Rect::new(popup_x, popup_y, popup_width, popup_height);
ratatui::widgets::Clear.render(popup_rect, buf);
buf.set_style(popup_rect, Style::default().fg(text_fg).bg(bg));
Block::default()
.borders(Borders::ALL)
.border_type(BorderType::Rounded)
.border_style(Style::default().fg(border_fg).bg(bg))
.style(Style::default().bg(bg))
.render(popup_rect, buf);
let title = match viewer.title {
Some(ref name) => format!(
" {} ({}\u{00d7}{}) ",
name, viewer.video_width, viewer.video_height
),
None => format!(
" Video ({}\u{00d7}{}) ",
viewer.video_width, viewer.video_height
),
};
let title_style = Style::default()
.fg(text_fg)
.bg(bg)
.add_modifier(Modifier::BOLD);
let tw = title.len() as u16;
let tx = popup_rect.x + (popup_rect.width.saturating_sub(tw)) / 2;
buf.set_span_safe(tx, popup_rect.y, &Span::styled(&title, title_style), tw);
render_progress_bar(buf, popup_rect, viewer, text_fg, border_fg, bg);
Some(popup_rect)
}
fn render_progress_bar(
buf: &mut Buffer,
popup_rect: Rect,
viewer: &VideoViewerState,
text_fg: Color,
bar_dim: Color,
bg: Color,
) {
let bar_y = popup_rect.y + popup_rect.height.saturating_sub(1);
let inner_width = popup_rect.width.saturating_sub(2) as usize;
if inner_width <= 10 {
return;
}
let icon = if viewer.playing {
"\u{25b6}"
} else {
"\u{23f8}"
};
let time_label = format!(
"{icon} {}/{} ",
format_time(viewer.position_secs()),
format_time(viewer.duration_secs),
);
let bar_width = inner_width.saturating_sub(time_label.len());
if bar_width <= 4 {
return;
}
let filled = ((viewer.progress() * bar_width as f64).round() as usize).min(bar_width);
let empty = bar_width.saturating_sub(filled);
let line = Line::from(vec![
Span::styled(time_label, Style::default().fg(text_fg).bg(bg)),
Span::styled(
"\u{2501}".repeat(filled),
Style::default().fg(text_fg).bg(bg),
),
Span::styled(
"\u{2500}".repeat(empty),
Style::default().fg(bar_dim).bg(bg),
),
]);
buf.set_line_safe(popup_rect.x + 1, bar_y, &line, inner_width as u16);
}
fn format_time(secs: f64) -> String {
let total = secs.round() as u64;
format!("{}:{:02}", total / 60, total % 60)
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn format_time_zero() {
assert_eq!(format_time(0.0), "0:00");
}
#[test]
fn format_time_short() {
assert_eq!(format_time(5.4), "0:05");
}
#[test]
fn format_time_minutes() {
assert_eq!(format_time(90.0), "1:30");
}
}