mirror of
https://github.com/ratatui-org/ratatui
synced 2024-11-10 07:04:17 +00:00
feat!: add get/set_cursor_position()
methods to Terminal and Backend (#1284)
The new methods return/accept `Into<Position>` which can be either a Position or a (u16, u16) tuple. ```rust backend.set_cursor_position(Position { x: 0, y: 20 })?; let position = backend.get_cursor_position()?; terminal.set_cursor_position((0, 20))?; let position = terminal.set_cursor_position()?; ```
This commit is contained in:
parent
afe15349c8
commit
c68ee6c64a
9 changed files with 190 additions and 90 deletions
|
@ -11,10 +11,12 @@ GitHub with a [breaking change] label.
|
|||
This is a quick summary of the sections below:
|
||||
|
||||
- [v0.28.0](#v0280) (unreleased)
|
||||
⁻ `Backend::size` returns `Size` instead of `Rect`
|
||||
- `Backend` trait migrates to `get/set_cursor_position`
|
||||
- Ratatui now requires Crossterm 0.28.0
|
||||
- `Axis::labels` now accepts `IntoIterator<Into<Line>>`
|
||||
- `Layout::init_cache` no longer returns bool and takes a `NonZeroUsize` instead of `usize`
|
||||
- `ratatui::terminal` module is now private
|
||||
- `Axis::labels` now accepts `IntoIterator<Into<Line>>`
|
||||
- `ToText` no longer has a lifetime
|
||||
- [v0.27.0](#v0270)
|
||||
- List no clamps the selected index to list
|
||||
|
@ -71,6 +73,17 @@ This is a quick summary of the sections below:
|
|||
The `Backend::size` method returns a `Size` instead of a `Rect`.
|
||||
There is no need for the position here as it was always 0,0.
|
||||
|
||||
### `Backend` trait migrates to `get/set_cursor_position` ([#1284])
|
||||
|
||||
[#1284]: https://github.com/ratatui-org/ratatui/pull/1284
|
||||
|
||||
If you just use the types implementing the `Backend` trait, you will see deprecation hints but
|
||||
nothing is a breaking change for you.
|
||||
|
||||
If you implement the Backend trait yourself, you need to update the implementation and add the
|
||||
`get/set_cursor_position` method. You can remove the `get/set_cursor` methods as they are deprecated
|
||||
and a default implementation for them exists.
|
||||
|
||||
### Ratatui now requires Crossterm 0.28.0 ([#1278])
|
||||
|
||||
[#1278]: https://github.com/ratatui-org/ratatui/pull/1278
|
||||
|
|
|
@ -36,7 +36,7 @@ use ratatui::{
|
|||
execute,
|
||||
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
|
||||
},
|
||||
layout::{Constraint, Layout},
|
||||
layout::{Constraint, Layout, Position},
|
||||
style::{Color, Modifier, Style, Stylize},
|
||||
text::{Line, Span, Text},
|
||||
widgets::{Block, List, ListItem, Paragraph},
|
||||
|
@ -245,22 +245,19 @@ fn ui(f: &mut Frame, app: &App) {
|
|||
.block(Block::bordered().title("Input"));
|
||||
f.render_widget(input, input_area);
|
||||
match app.input_mode {
|
||||
InputMode::Normal =>
|
||||
// Hide the cursor. `Frame` does this by default, so we don't need to do anything here
|
||||
{}
|
||||
InputMode::Normal => {}
|
||||
|
||||
InputMode::Editing => {
|
||||
// Make the cursor visible and ask ratatui to put it at the specified coordinates after
|
||||
// rendering
|
||||
#[allow(clippy::cast_possible_truncation)]
|
||||
f.set_cursor(
|
||||
InputMode::Editing => f.set_cursor_position(Position::new(
|
||||
// Draw the cursor at the current position in the input field.
|
||||
// This position is can be controlled via the left and right arrow key
|
||||
input_area.x + app.character_index as u16 + 1,
|
||||
// Move one line down, from the border to the input line
|
||||
input_area.y + 1,
|
||||
);
|
||||
}
|
||||
)),
|
||||
}
|
||||
|
||||
let messages: Vec<ListItem> = app
|
||||
|
|
|
@ -104,7 +104,10 @@ use std::io;
|
|||
|
||||
use strum::{Display, EnumString};
|
||||
|
||||
use crate::{buffer::Cell, layout::Size};
|
||||
use crate::{
|
||||
buffer::Cell,
|
||||
layout::{Position, Size},
|
||||
};
|
||||
|
||||
#[cfg(feature = "termion")]
|
||||
mod termion;
|
||||
|
@ -192,25 +195,25 @@ pub trait Backend {
|
|||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
///
|
||||
/// [`show_cursor`]: Backend::show_cursor
|
||||
/// [`show_cursor`]: Self::show_cursor
|
||||
fn hide_cursor(&mut self) -> io::Result<()>;
|
||||
|
||||
/// Show the cursor on the terminal screen.
|
||||
///
|
||||
/// See [`hide_cursor`] for an example.
|
||||
///
|
||||
/// [`hide_cursor`]: Backend::hide_cursor
|
||||
/// [`hide_cursor`]: Self::hide_cursor
|
||||
fn show_cursor(&mut self) -> io::Result<()>;
|
||||
|
||||
/// Get the current cursor position on the terminal screen.
|
||||
///
|
||||
/// The returned tuple contains the x and y coordinates of the cursor. The origin
|
||||
/// (0, 0) is at the top left corner of the screen.
|
||||
/// The returned tuple contains the x and y coordinates of the cursor.
|
||||
/// The origin (0, 0) is at the top left corner of the screen.
|
||||
///
|
||||
/// See [`set_cursor`] for an example.
|
||||
/// See [`set_cursor_position`] for an example.
|
||||
///
|
||||
/// [`set_cursor`]: Backend::set_cursor
|
||||
fn get_cursor(&mut self) -> io::Result<(u16, u16)>;
|
||||
/// [`set_cursor_position`]: Self::set_cursor_position
|
||||
fn get_cursor_position(&mut self) -> io::Result<Position>;
|
||||
|
||||
/// Set the cursor position on the terminal screen to the given x and y coordinates.
|
||||
///
|
||||
|
@ -220,14 +223,31 @@ pub trait Backend {
|
|||
///
|
||||
/// ```rust
|
||||
/// # use ratatui::backend::{Backend, TestBackend};
|
||||
/// # use ratatui::layout::Position;
|
||||
/// # let mut backend = TestBackend::new(80, 25);
|
||||
/// backend.set_cursor(10, 20)?;
|
||||
/// assert_eq!(backend.get_cursor()?, (10, 20));
|
||||
/// backend.set_cursor_position(Position { x: 10, y: 20 })?;
|
||||
/// assert_eq!(backend.get_cursor_position()?, Position { x: 10, y: 20 });
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> io::Result<()>;
|
||||
|
||||
/// Get the current cursor position on the terminal screen.
|
||||
///
|
||||
/// [`get_cursor`]: Backend::get_cursor
|
||||
fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()>;
|
||||
/// The returned tuple contains the x and y coordinates of the cursor. The origin
|
||||
/// (0, 0) is at the top left corner of the screen.
|
||||
#[deprecated = "the method get_cursor_position indicates more clearly what about the cursor to get"]
|
||||
fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
|
||||
let Position { x, y } = self.get_cursor_position()?;
|
||||
Ok((x, y))
|
||||
}
|
||||
|
||||
/// Set the cursor position on the terminal screen to the given x and y coordinates.
|
||||
///
|
||||
/// The origin (0, 0) is at the top left corner of the screen.
|
||||
#[deprecated = "the method set_cursor_position indicates more clearly what about the cursor to set"]
|
||||
fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
|
||||
self.set_cursor_position(Position { x, y })
|
||||
}
|
||||
|
||||
/// Clears the whole terminal screen
|
||||
///
|
||||
|
@ -261,7 +281,7 @@ pub trait Backend {
|
|||
/// This method will return an error if the terminal screen could not be cleared. It will also
|
||||
/// return an error if the `clear_type` is not supported by the backend.
|
||||
///
|
||||
/// [`clear`]: Backend::clear
|
||||
/// [`clear`]: Self::clear
|
||||
fn clear_region(&mut self, clear_type: ClearType) -> io::Result<()> {
|
||||
match clear_type {
|
||||
ClearType::All => self.clear(),
|
||||
|
|
|
@ -212,12 +212,14 @@ where
|
|||
execute!(self.writer, Show)
|
||||
}
|
||||
|
||||
fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
|
||||
fn get_cursor_position(&mut self) -> io::Result<Position> {
|
||||
crossterm::cursor::position()
|
||||
.map(|(x, y)| Position { x, y })
|
||||
.map_err(|e| io::Error::new(io::ErrorKind::Other, e.to_string()))
|
||||
}
|
||||
|
||||
fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
|
||||
fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> io::Result<()> {
|
||||
let Position { x, y } = position.into();
|
||||
execute!(self.writer, MoveTo(x, y))
|
||||
}
|
||||
|
||||
|
|
|
@ -157,11 +157,13 @@ where
|
|||
self.writer.flush()
|
||||
}
|
||||
|
||||
fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
|
||||
termion::cursor::DetectCursorPos::cursor_pos(&mut self.writer).map(|(x, y)| (x - 1, y - 1))
|
||||
fn get_cursor_position(&mut self) -> io::Result<Position> {
|
||||
termion::cursor::DetectCursorPos::cursor_pos(&mut self.writer)
|
||||
.map(|(x, y)| Position { x: x - 1, y: y - 1 })
|
||||
}
|
||||
|
||||
fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
|
||||
fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> io::Result<()> {
|
||||
let Position { x, y } = position.into();
|
||||
write!(self.writer, "{}", termion::cursor::Goto(x + 1, y + 1))?;
|
||||
self.writer.flush()
|
||||
}
|
||||
|
|
|
@ -191,12 +191,16 @@ impl Backend for TermwizBackend {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
|
||||
fn get_cursor_position(&mut self) -> io::Result<crate::layout::Position> {
|
||||
let (x, y) = self.buffered_terminal.cursor_position();
|
||||
Ok((x as u16, y as u16))
|
||||
Ok((x as u16, y as u16).into())
|
||||
}
|
||||
|
||||
fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
|
||||
fn set_cursor_position<P: Into<crate::layout::Position>>(
|
||||
&mut self,
|
||||
position: P,
|
||||
) -> io::Result<()> {
|
||||
let crate::layout::Position { x, y } = position.into();
|
||||
self.buffered_terminal.add_change(Change::CursorPosition {
|
||||
x: Position::Absolute(x as usize),
|
||||
y: Position::Absolute(y as usize),
|
||||
|
|
|
@ -11,7 +11,7 @@ use unicode_width::UnicodeWidthStr;
|
|||
use crate::{
|
||||
backend::{Backend, ClearType, WindowSize},
|
||||
buffer::{Buffer, Cell},
|
||||
layout::{Rect, Size},
|
||||
layout::{Position, Rect, Size},
|
||||
};
|
||||
|
||||
/// A [`Backend`] implementation used for integration testing that renders to an memory buffer.
|
||||
|
@ -117,6 +117,19 @@ impl TestBackend {
|
|||
{
|
||||
self.assert_buffer(&Buffer::with_lines(expected));
|
||||
}
|
||||
|
||||
/// Asserts that the `TestBackend`'s cursor position is equal to the expected one.
|
||||
///
|
||||
/// This is a shortcut for `assert_eq!(self.get_cursor_position().unwrap(), expected)`.
|
||||
///
|
||||
/// # Panics
|
||||
/// When they are not equal, a panic occurs with a detailed error message showing the
|
||||
/// differences between the expected and actual position.
|
||||
#[track_caller]
|
||||
pub fn assert_cursor_position<P: Into<Position>>(&mut self, position: P) {
|
||||
let actual = self.get_cursor_position().unwrap();
|
||||
assert_eq!(actual, position.into());
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for TestBackend {
|
||||
|
@ -148,12 +161,12 @@ impl Backend for TestBackend {
|
|||
Ok(())
|
||||
}
|
||||
|
||||
fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
|
||||
Ok(self.pos)
|
||||
fn get_cursor_position(&mut self) -> io::Result<Position> {
|
||||
Ok(self.pos.into())
|
||||
}
|
||||
|
||||
fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
|
||||
self.pos = (x, y);
|
||||
fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> io::Result<()> {
|
||||
self.pos = position.into().into();
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -203,7 +216,7 @@ impl Backend for TestBackend {
|
|||
/// case but this limit is instead replaced with scrolling in most backend implementations) will
|
||||
/// be added after the current position and the cursor will be moved to the last row.
|
||||
fn append_lines(&mut self, n: u16) -> io::Result<()> {
|
||||
let (cur_x, cur_y) = self.get_cursor()?;
|
||||
let Position { x: cur_x, y: cur_y } = self.get_cursor_position()?;
|
||||
let Rect { width, height, .. } = self.buffer.area;
|
||||
|
||||
// the next column ensuring that we don't go past the last column
|
||||
|
@ -218,13 +231,13 @@ impl Backend for TestBackend {
|
|||
self.clear()?;
|
||||
}
|
||||
|
||||
self.set_cursor(0, rotate_by)?;
|
||||
self.set_cursor_position(Position { x: 0, y: rotate_by })?;
|
||||
self.clear_region(ClearType::BeforeCursor)?;
|
||||
self.buffer.content.rotate_left((width * rotate_by).into());
|
||||
}
|
||||
|
||||
let new_cursor_y = cur_y.saturating_add(n).min(max_y);
|
||||
self.set_cursor(new_cursor_x, new_cursor_y)?;
|
||||
self.set_cursor_position(Position::new(new_cursor_x, new_cursor_y))?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
@ -340,15 +353,23 @@ mod tests {
|
|||
}
|
||||
|
||||
#[test]
|
||||
fn get_cursor() {
|
||||
fn get_cursor_position() {
|
||||
let mut backend = TestBackend::new(10, 2);
|
||||
assert_eq!(backend.get_cursor().unwrap(), (0, 0));
|
||||
assert_eq!(backend.get_cursor_position().unwrap(), Position::ORIGIN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_cursor() {
|
||||
fn assert_cursor_position() {
|
||||
let mut backend = TestBackend::new(10, 2);
|
||||
backend.assert_cursor_position(Position::ORIGIN);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn set_cursor_position() {
|
||||
let mut backend = TestBackend::new(10, 10);
|
||||
backend.set_cursor(5, 5).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 5, y: 5 })
|
||||
.unwrap();
|
||||
assert_eq!(backend.pos, (5, 5));
|
||||
}
|
||||
|
||||
|
@ -394,7 +415,9 @@ mod tests {
|
|||
"aaaaaaaaaa",
|
||||
]);
|
||||
|
||||
backend.set_cursor(3, 2).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 3, y: 2 })
|
||||
.unwrap();
|
||||
backend.clear_region(ClearType::AfterCursor).unwrap();
|
||||
backend.assert_buffer_lines([
|
||||
"aaaaaaaaaa",
|
||||
|
@ -416,7 +439,9 @@ mod tests {
|
|||
"aaaaaaaaaa",
|
||||
]);
|
||||
|
||||
backend.set_cursor(5, 3).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 5, y: 3 })
|
||||
.unwrap();
|
||||
backend.clear_region(ClearType::BeforeCursor).unwrap();
|
||||
backend.assert_buffer_lines([
|
||||
" ",
|
||||
|
@ -438,7 +463,9 @@ mod tests {
|
|||
"aaaaaaaaaa",
|
||||
]);
|
||||
|
||||
backend.set_cursor(3, 1).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 3, y: 1 })
|
||||
.unwrap();
|
||||
backend.clear_region(ClearType::CurrentLine).unwrap();
|
||||
backend.assert_buffer_lines([
|
||||
"aaaaaaaaaa",
|
||||
|
@ -460,7 +487,9 @@ mod tests {
|
|||
"aaaaaaaaaa",
|
||||
]);
|
||||
|
||||
backend.set_cursor(3, 0).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 3, y: 0 })
|
||||
.unwrap();
|
||||
backend.clear_region(ClearType::UntilNewLine).unwrap();
|
||||
backend.assert_buffer_lines([
|
||||
"aaa ",
|
||||
|
@ -482,22 +511,22 @@ mod tests {
|
|||
"eeeeeeeeee",
|
||||
]);
|
||||
|
||||
backend.set_cursor(0, 0).unwrap();
|
||||
backend.set_cursor_position(Position::ORIGIN).unwrap();
|
||||
|
||||
// If the cursor is not at the last line in the terminal the addition of a
|
||||
// newline simply moves the cursor down and to the right
|
||||
|
||||
backend.append_lines(1).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (1, 1));
|
||||
backend.assert_cursor_position(Position { x: 1, y: 1 });
|
||||
|
||||
backend.append_lines(1).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (2, 2));
|
||||
backend.assert_cursor_position(Position { x: 2, y: 2 });
|
||||
|
||||
backend.append_lines(1).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (3, 3));
|
||||
backend.assert_cursor_position(Position { x: 3, y: 3 });
|
||||
|
||||
backend.append_lines(1).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (4, 4));
|
||||
backend.assert_cursor_position(Position { x: 4, y: 4 });
|
||||
|
||||
// As such the buffer should remain unchanged
|
||||
backend.assert_buffer_lines([
|
||||
|
@ -522,7 +551,9 @@ mod tests {
|
|||
|
||||
// If the cursor is at the last line in the terminal the addition of a
|
||||
// newline will scroll the contents of the buffer
|
||||
backend.set_cursor(0, 4).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 0, y: 4 })
|
||||
.unwrap();
|
||||
|
||||
backend.append_lines(1).unwrap();
|
||||
|
||||
|
@ -536,7 +567,7 @@ mod tests {
|
|||
|
||||
// It also moves the cursor to the right, as is common of the behaviour of
|
||||
// terminals in raw-mode
|
||||
assert_eq!(backend.get_cursor().unwrap(), (1, 4));
|
||||
backend.assert_cursor_position(Position { x: 1, y: 4 });
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -550,13 +581,13 @@ mod tests {
|
|||
"eeeeeeeeee",
|
||||
]);
|
||||
|
||||
backend.set_cursor(0, 0).unwrap();
|
||||
backend.set_cursor_position(Position::ORIGIN).unwrap();
|
||||
|
||||
// If the cursor is not at the last line in the terminal the addition of multiple
|
||||
// newlines simply moves the cursor n lines down and to the right by 1
|
||||
|
||||
backend.append_lines(4).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (1, 4));
|
||||
backend.assert_cursor_position(Position { x: 1, y: 4 });
|
||||
|
||||
// As such the buffer should remain unchanged
|
||||
backend.assert_buffer_lines([
|
||||
|
@ -579,10 +610,12 @@ mod tests {
|
|||
"eeeeeeeeee",
|
||||
]);
|
||||
|
||||
backend.set_cursor(0, 3).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 0, y: 3 })
|
||||
.unwrap();
|
||||
|
||||
backend.append_lines(3).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (1, 4));
|
||||
backend.assert_cursor_position(Position { x: 1, y: 4 });
|
||||
|
||||
backend.assert_buffer_lines([
|
||||
"cccccccccc",
|
||||
|
@ -604,10 +637,12 @@ mod tests {
|
|||
"eeeeeeeeee",
|
||||
]);
|
||||
|
||||
backend.set_cursor(0, 4).unwrap();
|
||||
backend
|
||||
.set_cursor_position(Position { x: 0, y: 4 })
|
||||
.unwrap();
|
||||
|
||||
backend.append_lines(5).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (1, 4));
|
||||
backend.assert_cursor_position(Position { x: 1, y: 4 });
|
||||
|
||||
backend.assert_buffer_lines([
|
||||
" ",
|
||||
|
@ -629,10 +664,10 @@ mod tests {
|
|||
"eeeeeeeeee",
|
||||
]);
|
||||
|
||||
backend.set_cursor(0, 0).unwrap();
|
||||
backend.set_cursor_position(Position::ORIGIN).unwrap();
|
||||
|
||||
backend.append_lines(5).unwrap();
|
||||
assert_eq!(backend.get_cursor().unwrap(), (1, 4));
|
||||
backend.assert_cursor_position(Position { x: 1, y: 4 });
|
||||
|
||||
backend.assert_buffer_lines([
|
||||
"bbbbbbbbbb",
|
||||
|
|
|
@ -175,11 +175,22 @@ impl Frame<'_> {
|
|||
/// After drawing this frame, make the cursor visible and put it at the specified (x, y)
|
||||
/// coordinates. If this method is not called, the cursor will be hidden.
|
||||
///
|
||||
/// Note that this will interfere with calls to `Terminal::hide_cursor()`,
|
||||
/// `Terminal::show_cursor()`, and `Terminal::set_cursor()`. Pick one of the APIs and stick
|
||||
/// with it.
|
||||
/// Note that this will interfere with calls to [`Terminal::hide_cursor`],
|
||||
/// [`Terminal::show_cursor`], and [`Terminal::set_cursor_position`]. Pick one of the APIs and
|
||||
/// stick with it.
|
||||
pub fn set_cursor_position<P: Into<Position>>(&mut self, position: P) {
|
||||
self.cursor_position = Some(position.into());
|
||||
}
|
||||
|
||||
/// After drawing this frame, make the cursor visible and put it at the specified (x, y)
|
||||
/// coordinates. If this method is not called, the cursor will be hidden.
|
||||
///
|
||||
/// Note that this will interfere with calls to [`Terminal::hide_cursor`],
|
||||
/// [`Terminal::show_cursor`], and [`Terminal::set_cursor_position`]. Pick one of the APIs and
|
||||
/// stick with it.
|
||||
#[deprecated = "the method set_cursor_position indicates more clearly what about the cursor to set"]
|
||||
pub fn set_cursor(&mut self, x: u16, y: u16) {
|
||||
self.cursor_position = Some(Position { x, y });
|
||||
self.set_cursor_position(Position { x, y });
|
||||
}
|
||||
|
||||
/// Gets the buffer that this `Frame` draws into as a mutable reference.
|
||||
|
|
|
@ -28,16 +28,16 @@ use crate::{backend::ClearType, prelude::*, CompletedFrame, TerminalOptions, Vie
|
|||
/// # Examples
|
||||
///
|
||||
/// ```rust,no_run
|
||||
/// # use ratatui::prelude::*;
|
||||
/// use std::io::stdout;
|
||||
///
|
||||
/// use ratatui::{prelude::*, widgets::Paragraph};
|
||||
/// use ratatui::widgets::Paragraph;
|
||||
///
|
||||
/// let backend = CrosstermBackend::new(stdout());
|
||||
/// let mut terminal = Terminal::new(backend)?;
|
||||
/// terminal.draw(|frame| {
|
||||
/// let area = frame.size();
|
||||
/// frame.render_widget(Paragraph::new("Hello World!"), area);
|
||||
/// frame.set_cursor(0, 0);
|
||||
/// })?;
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
|
@ -275,17 +275,16 @@ where
|
|||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// # use ratatui::layout::Position;
|
||||
/// # let backend = ratatui::backend::TestBackend::new(10, 10);
|
||||
/// # let mut terminal = ratatui::Terminal::new(backend)?;
|
||||
/// use std::io;
|
||||
///
|
||||
/// use ratatui::widgets::Paragraph;
|
||||
///
|
||||
/// // with a closure
|
||||
/// terminal.draw(|frame| {
|
||||
/// let area = frame.size();
|
||||
/// frame.render_widget(Paragraph::new("Hello World!"), area);
|
||||
/// frame.set_cursor(0, 0);
|
||||
/// frame.set_cursor_position(Position { x: 0, y: 0 });
|
||||
/// })?;
|
||||
///
|
||||
/// // or with a function
|
||||
|
@ -294,7 +293,7 @@ where
|
|||
/// fn render(frame: &mut ratatui::Frame) {
|
||||
/// frame.render_widget(Paragraph::new("Hello World!"), frame.size());
|
||||
/// }
|
||||
/// # io::Result::Ok(())
|
||||
/// # std::io::Result::Ok(())
|
||||
/// ```
|
||||
pub fn draw<F>(&mut self, render_callback: F) -> io::Result<CompletedFrame>
|
||||
where
|
||||
|
@ -345,6 +344,7 @@ where
|
|||
/// # Examples
|
||||
///
|
||||
/// ```should_panic
|
||||
/// # use ratatui::layout::Position;;
|
||||
/// # let backend = ratatui::backend::TestBackend::new(10, 10);
|
||||
/// # let mut terminal = ratatui::Terminal::new(backend)?;
|
||||
/// use std::io;
|
||||
|
@ -356,7 +356,7 @@ where
|
|||
/// let value: u8 = "not a number".parse().map_err(io::Error::other)?;
|
||||
/// let area = frame.size();
|
||||
/// frame.render_widget(Paragraph::new("Hello World!"), area);
|
||||
/// frame.set_cursor(0, 0);
|
||||
/// frame.set_cursor_position(Position { x: 0, y: 0 });
|
||||
/// io::Result::Ok(())
|
||||
/// })?;
|
||||
///
|
||||
|
@ -393,9 +393,9 @@ where
|
|||
|
||||
match cursor_position {
|
||||
None => self.hide_cursor()?,
|
||||
Some(Position { x, y }) => {
|
||||
Some(position) => {
|
||||
self.show_cursor()?;
|
||||
self.set_cursor(x, y)?;
|
||||
self.set_cursor_position(position)?;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -434,14 +434,30 @@ where
|
|||
///
|
||||
/// This is the position of the cursor after the last draw call and is returned as a tuple of
|
||||
/// `(x, y)` coordinates.
|
||||
#[deprecated = "the method get_cursor_position indicates more clearly what about the cursor to get"]
|
||||
pub fn get_cursor(&mut self) -> io::Result<(u16, u16)> {
|
||||
self.backend.get_cursor()
|
||||
let Position { x, y } = self.get_cursor_position()?;
|
||||
Ok((x, y))
|
||||
}
|
||||
|
||||
/// Sets the cursor position.
|
||||
#[deprecated = "the method aet_cursor_position indicates more clearly what about the cursor to set"]
|
||||
pub fn set_cursor(&mut self, x: u16, y: u16) -> io::Result<()> {
|
||||
self.backend.set_cursor(x, y)?;
|
||||
self.last_known_cursor_pos = Position { x, y };
|
||||
self.set_cursor_position(Position { x, y })
|
||||
}
|
||||
|
||||
/// Gets the current cursor position.
|
||||
///
|
||||
/// This is the position of the cursor after the last draw call.
|
||||
pub fn get_cursor_position(&mut self) -> io::Result<Position> {
|
||||
self.backend.get_cursor_position()
|
||||
}
|
||||
|
||||
/// Sets the cursor position.
|
||||
pub fn set_cursor_position<P: Into<Position>>(&mut self, position: P) -> io::Result<()> {
|
||||
let position = position.into();
|
||||
self.backend.set_cursor_position(position)?;
|
||||
self.last_known_cursor_pos = position;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
|
@ -451,12 +467,12 @@ where
|
|||
Viewport::Fullscreen => self.backend.clear_region(ClearType::All)?,
|
||||
Viewport::Inline(_) => {
|
||||
self.backend
|
||||
.set_cursor(self.viewport_area.left(), self.viewport_area.top())?;
|
||||
.set_cursor_position(self.viewport_area.as_position())?;
|
||||
self.backend.clear_region(ClearType::AfterCursor)?;
|
||||
}
|
||||
Viewport::Fixed(area) => {
|
||||
for row in area.top()..area.bottom() {
|
||||
self.backend.set_cursor(0, row)?;
|
||||
for y in area.top()..area.bottom() {
|
||||
self.backend.set_cursor_position(Position { x: 0, y })?;
|
||||
self.backend.clear_region(ClearType::AfterCursor)?;
|
||||
}
|
||||
}
|
||||
|
@ -571,7 +587,7 @@ where
|
|||
});
|
||||
self.backend.draw(iter)?;
|
||||
self.backend.flush()?;
|
||||
self.set_cursor(self.viewport_area.left(), self.viewport_area.top())?;
|
||||
self.set_cursor_position(self.viewport_area.as_position())?;
|
||||
}
|
||||
|
||||
Ok(())
|
||||
|
@ -584,7 +600,7 @@ fn compute_inline_size<B: Backend>(
|
|||
size: Size,
|
||||
offset_in_previous_viewport: u16,
|
||||
) -> io::Result<(Rect, Position)> {
|
||||
let pos: Position = backend.get_cursor()?.into();
|
||||
let pos = backend.get_cursor_position()?;
|
||||
let mut row = pos.y;
|
||||
|
||||
let max_height = size.height.min(height);
|
||||
|
|
Loading…
Reference in a new issue