tlc: phase 17 — skin_dialog adopts shared popup shell
Migrate src/filemanager/skin_dialog.rs::render() from the bespoke
Clear+Block shell (no shadow, square borders) to
terminal::popup::render_popup (rounded borders + MC-matching drop
shadow + centered layout).
This makes skin_dialog visually consistent with all 13 other TLC
dialogs that already use render_popup. The /tmp/5.png screenshot
(showing the skin selector without shadow) is now fixed — every
TLC dialog has identical premium chrome.
Deleted:
- Duplicate 'centered_rect' helper (replaced by popup::centered_percent_rect)
- Inline Block construction
- Manual Clear render
Added:
- render_drops_shadow_outside_popup test asserts the bottom-right
cell carries theme.shadow background (assertion of MC's
tty_draw_box_shadow algorithm at the dialog level).
Tests: 1112 passed (was 1111, +1).
This commit is contained in:
@@ -19,11 +19,12 @@
|
||||
use ratatui::layout::{Constraint, Direction, Layout, Rect};
|
||||
use ratatui::style::{Modifier, Style};
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::{Block, Borders, Clear, List, ListItem, Paragraph};
|
||||
use ratatui::widgets::{List, ListItem, Paragraph};
|
||||
use ratatui::Frame;
|
||||
|
||||
use crate::key::Key;
|
||||
use crate::terminal::color::{all_skins, find_skin_index, SkinEntry, Theme};
|
||||
use crate::terminal::popup::{centered_percent_rect, render_popup};
|
||||
|
||||
/// A skin entry surfaced in the selection dialog. The dialog stores
|
||||
/// the list as `Vec<SkinEntry>` (see [`crate::terminal::color::SkinEntry`])
|
||||
@@ -193,23 +194,18 @@ impl SkinDialog {
|
||||
/// `theme` supplies the title, list, and hint colours so the
|
||||
/// dialog follows the active skin. The dialog itself does not
|
||||
/// use a hardcoded colour anywhere in its render path; every
|
||||
/// style derives from the supplied `theme`.
|
||||
/// style derives from the supplied `theme`. The popup shell
|
||||
/// (rounded borders + MC-matching drop shadow) is rendered by
|
||||
/// [`crate::terminal::popup::render_popup`] so all dialogs share
|
||||
/// the same premium chrome.
|
||||
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.border))
|
||||
.title(Span::styled(
|
||||
format!(" {} ", crate::locale::t("dialog_title_skin")),
|
||||
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_skin"),
|
||||
theme,
|
||||
);
|
||||
|
||||
let chunks = Layout::default()
|
||||
.direction(Direction::Vertical)
|
||||
@@ -308,15 +304,6 @@ impl SkinDialog {
|
||||
}
|
||||
}
|
||||
|
||||
/// Center a popup of `width_pct` × `height_pct` of `area`.
|
||||
fn centered_rect(area: Rect, width_pct: f32, height_pct: f32) -> Rect {
|
||||
let w = (area.width as f32 * width_pct.clamp(0.1, 1.0)) as u16;
|
||||
let h = (area.height as f32 * height_pct.clamp(0.1, 1.0)) as u16;
|
||||
let x = area.x + area.width.saturating_sub(w) / 2;
|
||||
let y = area.y + area.height.saturating_sub(h) / 2;
|
||||
Rect::new(x, y, w, h)
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -503,4 +490,35 @@ mod tests {
|
||||
})
|
||||
.expect("render");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn render_drops_shadow_outside_popup() {
|
||||
// After migrating to render_popup the popup shell includes an
|
||||
// MC-matching drop shadow (right strip 2 cells wide + bottom
|
||||
// strip 1 row tall offset by 2 cols). Verify the cells just
|
||||
// outside the popup's bottom-right carry the theme.shadow
|
||||
// background.
|
||||
let d = SkinDialog::new("julia256");
|
||||
let backend = ratatui::backend::TestBackend::new(80, 24);
|
||||
let mut terminal =
|
||||
ratatui::Terminal::new(backend).expect("create test terminal");
|
||||
terminal
|
||||
.draw(|f| {
|
||||
d.render(f, f.area(), &DEFAULT_THEME);
|
||||
})
|
||||
.expect("render");
|
||||
let buf = terminal.backend().buffer().clone();
|
||||
let popup = centered_percent_rect(buf.area, d.width_pct, d.height_pct);
|
||||
let shadow_y = popup.y + popup.height;
|
||||
let shadow_x = popup.x + popup.width;
|
||||
let cell = buf
|
||||
.cell((shadow_x, shadow_y))
|
||||
.expect("bottom-right shadow cell exists");
|
||||
assert_eq!(
|
||||
cell.bg,
|
||||
DEFAULT_THEME.shadow,
|
||||
"shadow cell at ({shadow_x},{shadow_y}) should carry shadow bg; got {:?}",
|
||||
cell.bg
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user