Feat: fixing ratatui big-text and UX
This commit is contained in:
@@ -1,9 +1,8 @@
|
||||
use ratatui::layout::{Alignment, Constraint, Layout, Rect};
|
||||
use ratatui::style::Style;
|
||||
use ratatui::text::{Line, Span};
|
||||
use ratatui::widgets::Paragraph;
|
||||
use ratatui::widgets::{Cell, Paragraph, Row, Table};
|
||||
use ratatui::Frame;
|
||||
#[cfg(not(feature = "desktop"))]
|
||||
use tui_big_text::{BigText, PixelSize};
|
||||
|
||||
use crate::state::ui::UiState;
|
||||
@@ -17,7 +16,6 @@ pub fn render(frame: &mut Frame, area: Rect, ui: &UiState) {
|
||||
let link_style = Style::new().fg(theme.title.link);
|
||||
let license_style = Style::new().fg(theme.title.license);
|
||||
|
||||
#[cfg(not(feature = "desktop"))]
|
||||
let big_title = BigText::builder()
|
||||
.pixel_size(PixelSize::Full)
|
||||
.style(Style::new().fg(theme.title.big_title).bold())
|
||||
@@ -25,99 +23,111 @@ pub fn render(frame: &mut Frame, area: Rect, ui: &UiState) {
|
||||
.centered()
|
||||
.build();
|
||||
|
||||
#[cfg(feature = "desktop")]
|
||||
let big_title = Paragraph::new(Line::from(Span::styled(
|
||||
"CAGIRE",
|
||||
Style::new().fg(theme.title.big_title).bold(),
|
||||
)))
|
||||
.alignment(Alignment::Center);
|
||||
|
||||
let version_style = Style::new().fg(theme.title.subtitle);
|
||||
|
||||
let subtitle_lines = vec![
|
||||
let info_lines = vec![
|
||||
Line::from(""),
|
||||
Line::from(Span::styled(
|
||||
"A Forth Music Sequencer",
|
||||
Style::new().fg(theme.title.subtitle),
|
||||
)),
|
||||
Line::from(vec![
|
||||
Span::styled("A Forth Music Sequencer by ", Style::new().fg(theme.title.subtitle)),
|
||||
Span::styled("BuboBubo", author_style),
|
||||
]),
|
||||
Line::from(Span::styled(
|
||||
format!("v{}", env!("CARGO_PKG_VERSION")),
|
||||
version_style,
|
||||
Style::new().fg(theme.title.subtitle),
|
||||
)),
|
||||
Line::from(""),
|
||||
Line::from(Span::styled("by BuboBubo", author_style)),
|
||||
Line::from(""),
|
||||
Line::from(Span::styled("https://raphaelforment.fr", link_style)),
|
||||
Line::from(""),
|
||||
Line::from(Span::styled("AGPL-3.0", license_style)),
|
||||
Line::from(""),
|
||||
Line::from(""),
|
||||
Line::from(vec![
|
||||
Span::styled("Ctrl+Arrows", Style::new().fg(theme.title.link)),
|
||||
Span::styled(": navigate views", Style::new().fg(theme.title.prompt)),
|
||||
]),
|
||||
Line::from(vec![
|
||||
Span::styled("Enter", Style::new().fg(theme.title.link)),
|
||||
Span::styled(": edit step ", Style::new().fg(theme.title.prompt)),
|
||||
Span::styled("Space", Style::new().fg(theme.title.link)),
|
||||
Span::styled(": play/stop", Style::new().fg(theme.title.prompt)),
|
||||
]),
|
||||
Line::from(vec![
|
||||
Span::styled("s", Style::new().fg(theme.title.link)),
|
||||
Span::styled(": save ", Style::new().fg(theme.title.prompt)),
|
||||
Span::styled("l", Style::new().fg(theme.title.link)),
|
||||
Span::styled(": load ", Style::new().fg(theme.title.prompt)),
|
||||
Span::styled("q", Style::new().fg(theme.title.link)),
|
||||
Span::styled(": quit", Style::new().fg(theme.title.prompt)),
|
||||
]),
|
||||
Line::from(vec![
|
||||
Span::styled("?", Style::new().fg(theme.title.link)),
|
||||
Span::styled(": keybindings", Style::new().fg(theme.title.prompt)),
|
||||
]),
|
||||
Line::from(""),
|
||||
Line::from(Span::styled(
|
||||
"Press any key to continue",
|
||||
Style::new().fg(theme.title.subtitle),
|
||||
)),
|
||||
];
|
||||
|
||||
#[cfg(not(feature = "desktop"))]
|
||||
let big_text_height = 8;
|
||||
#[cfg(feature = "desktop")]
|
||||
let big_text_height = 1;
|
||||
let min_title_width = 30;
|
||||
let subtitle_height = subtitle_lines.len() as u16;
|
||||
let keybindings = [
|
||||
("Ctrl+Arrows", "Navigate Views"),
|
||||
("Enter", "Edit Step"),
|
||||
("Space", "Play/Stop"),
|
||||
("s", "Save"),
|
||||
("l", "Load"),
|
||||
("q", "Quit"),
|
||||
("?", "Keybindings"),
|
||||
];
|
||||
|
||||
let key_style = Style::new().fg(theme.modal.confirm);
|
||||
let desc_style = Style::new().fg(theme.ui.text_primary);
|
||||
let rows: Vec<Row> = keybindings
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, (key, desc))| {
|
||||
let bg = if i % 2 == 0 {
|
||||
theme.table.row_even
|
||||
} else {
|
||||
theme.table.row_odd
|
||||
};
|
||||
Row::new(vec![
|
||||
Cell::from(*key).style(key_style),
|
||||
Cell::from(*desc).style(desc_style),
|
||||
])
|
||||
.style(Style::new().bg(bg))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let table = Table::new(
|
||||
rows,
|
||||
[Constraint::Length(14), Constraint::Fill(1)],
|
||||
)
|
||||
.column_spacing(2);
|
||||
|
||||
let press_line = Line::from(Span::styled(
|
||||
"Press any key to continue",
|
||||
Style::new().fg(theme.title.subtitle),
|
||||
));
|
||||
|
||||
let info_height = info_lines.len() as u16;
|
||||
let table_height = keybindings.len() as u16;
|
||||
let table_width: u16 = 42;
|
||||
|
||||
let big_text_height: u16 = 8;
|
||||
|
||||
let content_height = info_height + table_height + 3; // +3 for gap + empty line + press line
|
||||
let show_big_title =
|
||||
area.height >= (big_text_height + subtitle_height) && area.width >= min_title_width;
|
||||
area.height >= (big_text_height + content_height) && area.width >= 30;
|
||||
|
||||
let total_height = if show_big_title {
|
||||
big_text_height + content_height
|
||||
} else {
|
||||
content_height
|
||||
};
|
||||
let v_pad = area.height.saturating_sub(total_height) / 2;
|
||||
|
||||
let mut constraints = Vec::new();
|
||||
constraints.push(Constraint::Length(v_pad));
|
||||
if show_big_title {
|
||||
constraints.push(Constraint::Length(big_text_height));
|
||||
}
|
||||
constraints.push(Constraint::Length(info_height));
|
||||
constraints.push(Constraint::Length(1)); // gap
|
||||
constraints.push(Constraint::Length(table_height));
|
||||
constraints.push(Constraint::Length(1)); // empty line
|
||||
constraints.push(Constraint::Length(1)); // press any key
|
||||
constraints.push(Constraint::Fill(1));
|
||||
|
||||
let areas = Layout::vertical(constraints).split(area);
|
||||
let mut idx = 1; // skip padding
|
||||
|
||||
if show_big_title {
|
||||
let total_height = big_text_height + subtitle_height;
|
||||
let vertical_padding = area.height.saturating_sub(total_height) / 2;
|
||||
|
||||
let [_, title_area, subtitle_area, _] = Layout::vertical([
|
||||
Constraint::Length(vertical_padding),
|
||||
Constraint::Length(big_text_height),
|
||||
Constraint::Length(subtitle_height),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(area);
|
||||
|
||||
frame.render_widget(big_title, title_area);
|
||||
|
||||
let subtitle = Paragraph::new(subtitle_lines).alignment(Alignment::Center);
|
||||
frame.render_widget(subtitle, subtitle_area);
|
||||
} else {
|
||||
let vertical_padding = area.height.saturating_sub(subtitle_height) / 2;
|
||||
|
||||
let [_, subtitle_area, _] = Layout::vertical([
|
||||
Constraint::Length(vertical_padding),
|
||||
Constraint::Length(subtitle_height),
|
||||
Constraint::Fill(1),
|
||||
])
|
||||
.areas(area);
|
||||
|
||||
let subtitle = Paragraph::new(subtitle_lines).alignment(Alignment::Center);
|
||||
frame.render_widget(subtitle, subtitle_area);
|
||||
frame.render_widget(big_title, areas[idx]);
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
let info = Paragraph::new(info_lines).alignment(Alignment::Center);
|
||||
frame.render_widget(info, areas[idx]);
|
||||
idx += 1;
|
||||
|
||||
idx += 1; // skip gap
|
||||
|
||||
let tw = table_width.min(areas[idx].width);
|
||||
let tx = areas[idx].x + (areas[idx].width.saturating_sub(tw)) / 2;
|
||||
let table_area = Rect::new(tx, areas[idx].y, tw, areas[idx].height);
|
||||
frame.render_widget(table, table_area);
|
||||
idx += 2; // skip empty line
|
||||
|
||||
let press = Paragraph::new(press_line).alignment(Alignment::Center);
|
||||
frame.render_widget(press, areas[idx]);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user