Skip to content

Popups (overwrite regions)

Ratatui は、アプリケーションがバッファに書き込む順序でテキストをレンダリングします。つまり、前の命令は後の命令によって上書きされます。ただし、ウィジェットはレンダリング先の領域内のすべてのセルを常にクリアするわけではないことに注意してください。これにより、以前にバッファにレンダリングされたシンボルとスタイルが、それらのセルの上にレンダリングされたセルに「にじみ出る」可能性があります。

次のコードはこの問題を示しています。

use lipsum::lipsum;
use ratatui::{
backend::CrosstermBackend,
crossterm::{
event::{self, Event},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand,
},
layout::Rect,
style::{Style, Stylize},
widgets::{Block, Borders, Paragraph, Wrap},
Frame, Terminal,
};
// -- snip --
fn ui(frame: &mut Frame) {
let area = frame.area();
let background_text = Paragraph::new(lipsum(1000))
.wrap(Wrap { trim: true })
.light_blue()
.italic()
.on_black();
frame.render_widget(background_text, area);
// take up a third of the screen vertically and half horizontally
let popup_area = Rect {
x: area.width / 4,
y: area.height / 3,
width: area.width / 2,
height: area.height / 3,
};
let bad_popup = Paragraph::new("Hello world!")
.wrap(Wrap { trim: true })
.style(Style::new().yellow())
.block(
Block::new()
.title("Without Clear")
.title_style(Style::new().white().bold())
.borders(Borders::ALL)
.border_style(Style::new().red()),
);
frame.render_widget(bad_popup, popup_area);
}

problem

背景色 (この場合は黒) 、イタリック体、およびロレムのipsumの背景テキストがポップアップを介して表示されることに注意してください。

この問題は、メインポップアップをレンダリングする前にClearウィジェットをレンダリングすることにより、簡単に防ぐことができます。この手法を使用して Popup ウィジェットを作成する方法の例を次に示します。

use derive_setters::Setters;
use lipsum::lipsum;
use ratatui::{
backend::CrosstermBackend,
buffer::Buffer,
crossterm::{
event::{self, Event},
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
ExecutableCommand,
},
layout::Rect,
style::{Style, Stylize},
text::{Line, Text},
widgets::{Block, Borders, Clear, Paragraph, Widget, Wrap},
Frame, Terminal,
};
#[derive(Debug, Default, Setters)]
struct Popup<'a> {
#[setters(into)]
title: Line<'a>,
#[setters(into)]
content: Text<'a>,
border_style: Style,
title_style: Style,
style: Style,
}
impl Widget for Popup<'_> {
fn render(self, area: Rect, buf: &mut Buffer) {
// ensure that all cells under the popup are cleared to avoid leaking content
Clear.render(area, buf);
let block = Block::new()
.title(self.title)
.title_style(self.title_style)
.borders(Borders::ALL)
.border_style(self.border_style);
Paragraph::new(self.content)
.wrap(Wrap { trim: true })
.style(self.style)
.block(block)
.render(area, buf);
}
}

次のコードで新しい Popup ウィジェットを使用できます。

let popup = Popup::default()
.content("Hello world!")
.style(Style::new().yellow())
.title("With Clear")
.title_style(Style::new().white().bold())
.border_style(Style::new().red());
frame.render_widget(popup, popup_area);

次の結果が得られます。

demo

背景はデフォルトの背景に設定されており、背景テキストから斜体やシンボルがないことに注意してください。

この記事の完全なソースは、https://github.com/ratatui/ratatui-website/tree/main/code/how-to-overwrite-regions で入手できます