Skip to content

Commit

Permalink
terminal: Migrate from tui to ratatui and newer crossterm.
Browse files Browse the repository at this point in the history
  • Loading branch information
kpreid committed Dec 16, 2023
1 parent 50cb6ea commit 38d60c5
Show file tree
Hide file tree
Showing 5 changed files with 73 additions and 57 deletions.
48 changes: 31 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

6 changes: 3 additions & 3 deletions all-is-cubes-desktop/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -36,8 +36,8 @@ anyhow = { workspace = true }
bytemuck = { workspace = true }
cfg-if = { workspace = true }
clap = { workspace = true }
# Note: keep crossterm in sync with tui's crossterm dependency.
crossterm = "0.25.0"
# Note: keep crossterm in sync with ratatui's crossterm dependency.
crossterm = "0.27.0"
directories-next = "2.0.0"
indicatif = { version = "0.17.0", default-features = false }
kira = { version = "0.8.3", default-features = false, features = ["cpal"] }
Expand All @@ -54,7 +54,7 @@ simplelog = { workspace = true }
strum = { workspace = true, features = ["derive", "std"] }
thiserror = { workspace = true }
tokio = { workspace = true, features = ["rt-multi-thread", "sync"] }
tui = { version = "0.19.0", default-features = false, features = ["crossterm"] }
ratatui = { version = "0.24.0", default-features = false, features = ["crossterm"] }
unicode-width = { version = "0.1.9", default-features = false }
# Note on feature selection: winit requires either "x11" or "wayland" to build at all on Linux, which is harmless elsewhere. I picked x11 because it should be the most compatible.
# TODO: drop rwh_05 when wgpu is updated
Expand Down
4 changes: 3 additions & 1 deletion all-is-cubes-desktop/src/terminal.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use std::time::{Duration, Instant};

use anyhow::Context;
use crossterm::event::{Event, KeyCode, KeyEvent, KeyModifiers, MouseEvent, MouseEventKind};
use tui::layout::Rect;
use ratatui::layout::Rect;

use all_is_cubes::arcstr::literal_substr;
use all_is_cubes::camera::{self, Camera, StandardCameras, Viewport};
Expand Down Expand Up @@ -235,6 +235,8 @@ fn run(
MouseEventKind::Up(_)
| MouseEventKind::Drag(_)
| MouseEventKind::Moved
| MouseEventKind::ScrollLeft
| MouseEventKind::ScrollRight
| MouseEventKind::ScrollDown
| MouseEventKind::ScrollUp => {}
}
Expand Down
5 changes: 3 additions & 2 deletions all-is-cubes-desktop/src/terminal/chars.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ use crossterm::QueueableCommand as _;
use all_is_cubes::camera::ImagePixel;
use all_is_cubes::euclid::Vector2D;
use all_is_cubes::math::{Rgb, Rgba};
use ratatui::backend::Backend;

use super::options::{CharacterMode, ColorMode};
use super::{TextAndColor, TextRayImage};
Expand Down Expand Up @@ -190,7 +191,7 @@ const BRAILLE_TABLE: [&str; 256] = [
"⣰","⣱","⣲","⣳","⣴","⣵","⣶","⣷","⣸","⣹","⣺","⣻","⣼","⣽","⣾","⣿",
];

pub(crate) fn write_colored_and_measure<B: tui::backend::Backend + io::Write>(
pub(crate) fn write_colored_and_measure<B: Backend + io::Write>(
backend: &mut B,
has_terminal_stdin: bool,
width_table: &mut HashMap<String, u16>,
Expand All @@ -214,7 +215,7 @@ pub(crate) fn write_colored_and_measure<B: tui::backend::Backend + io::Write>(
///
/// Returns an error if the string could not be written. If an error was encountered
/// measuring the width, returns an estimate instead.
fn write_and_measure<B: tui::backend::Backend + io::Write>(
fn write_and_measure<B: Backend + io::Write>(
backend: &mut B,
has_terminal_stdin: bool,
width_table: &mut HashMap<String, u16>,
Expand Down
67 changes: 33 additions & 34 deletions all-is-cubes-desktop/src/terminal/ui.rs
Original file line number Diff line number Diff line change
@@ -1,19 +1,18 @@
use std::borrow::Cow;
use std::collections::HashMap;
use std::convert::TryInto;
use std::io::{self, Write as _};
use std::sync::mpsc;

use anyhow::Context as _;
use crossterm::cursor::{self, MoveTo};
use crossterm::style::{Attribute, Color, Colors, SetAttribute, SetColors};
use crossterm::QueueableCommand as _;
use tui::backend::CrosstermBackend;
use tui::layout::{Constraint, Direction, Layout, Rect};
use tui::style::{Color as TuiColor, Modifier, Style};
use tui::text::{Span, Spans};
use tui::widgets::{Borders, Paragraph};
use tui::Terminal;
use ratatui::backend::CrosstermBackend;
use ratatui::layout::{Constraint, Direction, Layout, Rect};
use ratatui::style::{Color as TuiColor, Modifier, Style};
use ratatui::text::Span;
use ratatui::widgets::{Borders, Paragraph};
use ratatui::Terminal;

use all_is_cubes::character::{Character, Cursor};
use all_is_cubes::euclid::Vector2D;
Expand Down Expand Up @@ -250,7 +249,7 @@ impl TerminalState {
}

/// Reset terminal state, as before exiting.
fn clean_up_terminal(&mut self) -> crossterm::Result<()> {
fn clean_up_terminal(&mut self) -> io::Result<()> {
if self.terminal_state_dirty {
fn log_if_fails<T, E: std::error::Error>(r: Result<T, E>) {
match r {
Expand All @@ -276,7 +275,7 @@ impl TerminalState {
///
/// If `draw_into_rect` is true, moves the cursor to fit into `self.viewport_position`.
/// If it is false, does not affect the cursor position and uses newlines.
fn write_frame(&mut self, image: &TextRayImage, draw_into_rect: bool) -> crossterm::Result<()> {
fn write_frame(&mut self, image: &TextRayImage, draw_into_rect: bool) -> io::Result<()> {
// Now separately draw the frame data. This is done because we want to use a precise
// strategy for measuring the width of characters (draw them and read back the cursor
// position) whereas tui-rs assumes that `unicode_width`'s answers match the terminal.
Expand Down Expand Up @@ -358,8 +357,8 @@ impl TerminalState {
Term color: N Term chars: M\n\
Quit: Esc, ^C, or ^D";

let [viewport_rect_tmp, toolbar_rect, gfx_info_rect, cursor_and_help_rect]: [Rect; 4] =
Layout::default()
let [viewport_rect_tmp, toolbar_rect, gfx_info_rect, cursor_and_help_rect] =
*Layout::default()
.direction(Direction::Vertical)
.constraints([
Constraint::Min(1),
Expand All @@ -368,14 +367,16 @@ impl TerminalState {
Constraint::Length(3),
])
.split(f.size())
.try_into()
.unwrap();
let [cursor_rect, help_rect]: [Rect; 2] = Layout::default()
else {
unreachable!()
};
let [cursor_rect, help_rect] = *Layout::default()
.direction(Direction::Horizontal)
.constraints([Constraint::Min(0), Constraint::Length(30)])
.split(cursor_and_help_rect)
.try_into()
.unwrap();
else {
unreachable!()
};
// Toolbar
{
const SLOTS: usize = InventoryDisplay::SLOTS;
Expand Down Expand Up @@ -407,12 +408,10 @@ impl TerminalState {
.split(toolbar_rect);

let selected_slots = ui_frame.inventory.selected_slots;
for ((i, rect), slot) in slot_rects
.into_iter()
.enumerate()
.zip(&ui_frame.inventory.slots)
for ((i, &rect), slot) in
slot_rects.iter().enumerate().zip(&ui_frame.inventory.slots)
{
let slot_info = Spans::from(vec![
let slot_info: Vec<Span<'_>> = vec![
if selected_slots[0] == i {
SELECTED_0
} else {
Expand All @@ -424,8 +423,8 @@ impl TerminalState {
} else {
SELECTED_BLANK
},
]);
let block = tui::widgets::Block::default()
];
let block = ratatui::widgets::Block::default()
.title(slot_info)
.borders(Borders::ALL);
f.render_widget(
Expand All @@ -452,17 +451,17 @@ impl TerminalState {

// Graphics info line
{
let [frame_info_rect, colors_info_rect, render_info_rect]: [Rect; 3] =
Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(30),
Constraint::Percentage(30),
Constraint::Percentage(30),
])
.split(gfx_info_rect)
.try_into()
.unwrap();
let [frame_info_rect, colors_info_rect, render_info_rect] = *Layout::default()
.direction(Direction::Horizontal)
.constraints([
Constraint::Percentage(30),
Constraint::Percentage(30),
Constraint::Percentage(30),
])
.split(gfx_info_rect)
else {
unreachable!()
};

f.render_widget(
Paragraph::new(format!("{:5.1} FPS", ui_frame.frames_per_second)),
Expand Down

0 comments on commit 38d60c5

Please sign in to comment.