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:
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user