tlc: phase 18c — migrate 7 more dialogs to render_popup

Continue Phase 18 mechanical migration of centered dialogs to the
shared terminal::popup::render_popup() shell (MC-matching rounded
borders + drop shadow):

  permission, owner, connection_dialog, config_dialog,
  compare, sort_dialog, progress

All 7 share the same pattern: inline Clear + Block + title replaced
with render_popup() + centered_cols_rect()/centered_percent_rect().
Title color now derives from [dialog] dtitle via the unified shell.

compare.rs also dropped its local centered_rect helper (used only
for the popup shell; the body Block stays inline since it's a
sub-frame, not the popup shell).

Tree (full-screen directory tree dialog) intentionally skipped — it
uses the entire frame area, not a centered popup, so it does not
benefit from the popup shell or shadow.

Tests: 1112 passed (no regressions).
This commit is contained in:
vasilito
2026-06-20 17:49:50 +03:00
parent a4dc44a8e0
commit 2b2b5803ba
7 changed files with 43 additions and 137 deletions
@@ -9,11 +9,12 @@ use std::path::Path;
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
use ratatui::widgets::{Block, Borders, Paragraph};
use ratatui::Frame;
use crate::key::Key;
use crate::terminal::color::Theme;
use crate::terminal::popup::{centered_percent_rect, render_popup};
/// Maximum lines to read from each file (prevents OOM on huge files).
const MAX_LINES: usize = 10_000;
@@ -121,19 +122,18 @@ impl CompareDialog {
/// Render the dialog.
pub fn render(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
let popup = centered_rect(area, 90, 80);
frame.render_widget(Clear, popup);
let popup = centered_percent_rect(area, 0.9, 0.8);
let title = if self.error.is_some() {
"Compare: error".to_string()
} else {
format!("Compare: {}{}", self.left_name, self.right_name)
};
let inner = render_popup(frame, popup, title.as_str(), theme);
let chunks = Layout::default()
.direction(ratatui::layout::Direction::Vertical)
.constraints([Constraint::Length(2), Constraint::Min(1)])
.split(popup);
let title = if self.error.is_some() {
format!(" Compare: error ")
} else {
format!(" Compare: {}{} ", self.left_name, self.right_name)
};
.split(inner);
let header = Paragraph::new(Line::from(vec![Span::styled(
title,
@@ -236,25 +236,6 @@ fn compute_diff(a: &[String], b: &[String]) -> Vec<DiffLine> {
result
}
fn centered_rect(area: Rect, pct_x: u16, pct_y: u16) -> Rect {
let pop_rect = Layout::default()
.direction(ratatui::layout::Direction::Vertical)
.constraints([
Constraint::Percentage((100 - pct_y) / 2),
Constraint::Percentage(pct_y),
Constraint::Percentage((100 - pct_y) / 2),
])
.split(area);
Layout::default()
.direction(ratatui::layout::Direction::Horizontal)
.constraints([
Constraint::Percentage((100 - pct_x) / 2),
Constraint::Percentage(pct_x),
Constraint::Percentage((100 - pct_x) / 2),
])
.split(pop_rect[1])[1]
}
#[cfg(test)]
mod tests {
use super::*;
@@ -22,11 +22,12 @@
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
use ratatui::widgets::Paragraph;
use ratatui::Frame;
use crate::key::Key;
use crate::terminal::color::Theme;
use crate::terminal::popup::{centered_cols_rect, render_popup};
/// The result of the configuration dialog after a key event.
#[derive(Debug, Clone, PartialEq, Eq)]
@@ -181,25 +182,8 @@ impl ConfigDialog {
/// Render the dialog centered on `area`.
pub fn render(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
let w = 44u16.min(area.width.saturating_sub(2));
let h = 12u16.min(area.height.saturating_sub(2));
let x = area.x + (area.width - w) / 2;
let y = area.y + (area.height - h) / 2;
let dlg = Rect::new(x, y, w, h);
frame.render_widget(Clear, dlg);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.title_fg))
.title(Span::styled(
" Configuration ",
Style::default()
.fg(theme.title_fg)
.bg(theme.title_bg)
.add_modifier(Modifier::BOLD),
));
let inner = block.inner(dlg);
frame.render_widget(block, dlg);
let dlg = centered_cols_rect(area, 44, 12);
let inner = render_popup(frame, dlg, "Configuration", theme);
let rows = Layout::default()
.direction(Direction::Vertical)
@@ -19,11 +19,12 @@ use std::path::PathBuf;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
use ratatui::widgets::Paragraph;
use ratatui::Frame;
use crate::key::Key;
use crate::terminal::color::Theme;
use crate::terminal::popup::{centered_cols_rect, render_popup};
use crate::vfs::VfsPath;
use crate::widget::input::Input;
@@ -205,25 +206,8 @@ impl ConnectionDialog {
/// Render the dialog centered on `area`.
pub fn render(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
let w = 60u16.min(area.width.saturating_sub(2));
let h = 8u16.min(area.height.saturating_sub(2));
let x = area.x + (area.width.saturating_sub(w)) / 2;
let y = area.y + (area.height.saturating_sub(h)) / 2;
let dlg = Rect::new(x, y, w, h);
frame.render_widget(Clear, dlg);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.title_fg))
.title(Span::styled(
self.kind.title(),
Style::default()
.fg(theme.title_fg)
.bg(theme.title_bg)
.add_modifier(Modifier::BOLD),
));
let inner = block.inner(dlg);
frame.render_widget(block, dlg);
let dlg = centered_cols_rect(area, 60, 8);
let inner = render_popup(frame, dlg, self.kind.title(), theme);
let chunks = Layout::default()
.direction(Direction::Vertical)
@@ -14,11 +14,12 @@ use std::path::PathBuf;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph, Wrap};
use ratatui::widgets::{Paragraph, Wrap};
use ratatui::Frame;
use crate::key::Key;
use crate::terminal::color::Theme;
use crate::terminal::popup::{centered_percent_rect, render_popup};
use crate::widget::input::Input;
/// Which field currently has focus.
@@ -170,21 +171,13 @@ impl OwnerDialog {
/// `theme` supplies the title, body, and hint colours so the
/// dialog follows the active skin.
pub fn render(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
let popup = centered_rect(area, self.width_pct, self.height_pct);
frame.render_widget(Clear, popup);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.title_fg))
.title(Span::styled(
format!(" {} ", crate::locale::t("dialog_title_owner")),
Style::default()
.fg(theme.title_fg)
.bg(theme.title_bg)
.add_modifier(Modifier::BOLD),
));
let inner = block.inner(popup);
frame.render_widget(block, popup);
let popup = centered_percent_rect(area, self.width_pct, self.height_pct);
let inner = render_popup(
frame,
popup,
crate::locale::t("dialog_title_owner"),
theme,
);
let chunks = Layout::default()
.direction(Direction::Vertical)
@@ -15,11 +15,12 @@ use std::path::PathBuf;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph, Wrap};
use ratatui::widgets::{Paragraph, Wrap};
use ratatui::Frame;
use crate::key::Key;
use crate::terminal::color::Theme;
use crate::terminal::popup::{centered_percent_rect, render_popup};
/// One cell in the 3x3 permission grid.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
@@ -211,21 +212,13 @@ impl PermissionDialog {
/// `theme` supplies the title, border, hint, and button colours so
/// the dialog follows the active skin.
pub fn render(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
let popup = centered_rect(area, self.width_pct, self.height_pct);
frame.render_widget(Clear, popup);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.title_fg))
.title(Span::styled(
format!(" {} ", crate::locale::t("dialog_title_permission")),
Style::default()
.fg(theme.title_fg)
.bg(theme.title_bg)
.add_modifier(Modifier::BOLD),
));
let inner = block.inner(popup);
frame.render_widget(block, popup);
let popup = centered_percent_rect(area, self.width_pct, self.height_pct);
let inner = render_popup(
frame,
popup,
crate::locale::t("dialog_title_permission"),
theme,
);
// Inner split: header line, 3-row grid, hint line.
let chunks = Layout::default()
@@ -3,7 +3,7 @@
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::text::Span;
use ratatui::widgets::{Block, Borders, Clear, Paragraph};
use ratatui::widgets::Paragraph;
use ratatui::Frame;
use crate::filemanager::panel::SortField;
@@ -130,25 +130,8 @@ impl SortDialog {
pub fn render(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
let w = 36u16.min(area.width.saturating_sub(2));
let h = 12u16.min(area.height.saturating_sub(2));
let x = area.x + (area.width - w) / 2;
let y = area.y + (area.height - h) / 2;
let dlg = Rect::new(x, y, w, h);
frame.render_widget(Clear, dlg);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.border))
.title(Span::styled(
" Sort Order ",
Style::default()
.fg(theme.title_fg)
.bg(theme.title_bg)
.add_modifier(Modifier::BOLD),
))
.style(Style::default().bg(theme.background).fg(theme.foreground));
let inner = block.inner(dlg);
frame.render_widget(block, dlg);
let dlg = crate::terminal::popup::centered_cols_rect(area, w, h);
let inner = crate::terminal::popup::render_popup(frame, dlg, "Sort Order", theme);
let mut constraints = vec![Constraint::Length(1)];
for _ in 0..FIELDS.len() {
@@ -7,12 +7,13 @@ use std::time::Instant;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Modifier, Style};
use ratatui::text::{Line, Span};
use ratatui::widgets::{Block, Borders, Clear, Paragraph, Wrap};
use ratatui::widgets::{Paragraph, Wrap};
use ratatui::Frame;
use crate::ops::OpHandle;
use crate::terminal::color::Theme;
use crate::terminal::popup::{centered_percent_rect, render_popup};
use crate::widget::ProgressGauge;
/// The progress dialog. Renders a running operation with a
@@ -57,21 +58,8 @@ impl ProgressDialog {
/// `theme` supplies the title, current file, gauge, and cancel
/// button colours so the progress dialog follows the active skin.
pub fn render(&self, frame: &mut Frame, area: Rect, theme: &Theme) {
let popup = centered_rect(area, self.width_pct, self.height_pct);
frame.render_widget(Clear, popup);
let block = Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(theme.title_fg))
.title(Span::styled(
format!(" {} ", self.title),
Style::default()
.fg(theme.title_fg)
.bg(theme.title_bg)
.add_modifier(Modifier::BOLD),
));
let inner = block.inner(popup);
frame.render_widget(block, popup);
let popup = centered_percent_rect(area, self.width_pct, self.height_pct);
let inner = render_popup(frame, popup, self.title.as_str(), theme);
let chunks = Layout::default()
.direction(Direction::Vertical)