Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

placeholder text support #15

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
8 changes: 8 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,14 @@ required-features = ["crossterm"]
name = "ratatui_minimal"
required-features = ["ratatui-crossterm"]

[[example]]
name = "ratatui_placepop"
required-features = ["ratatui-crossterm"]

[[example]]
name = "placepop"
required-features = ["crossterm"]

[[example]]
name = "ratatui_editor"
required-features = ["ratatui-crossterm", "search"]
Expand Down
64 changes: 64 additions & 0 deletions examples/placepop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use std::io;
use tui::backend::CrosstermBackend;
use tui::layout::Rect;
use tui::style::{Color, Style};
use tui::widgets::{Block, Borders};
use tui::Terminal;
use tui_textarea::{Input, Key, TextArea};

fn main() -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();

enable_raw_mode()?;
crossterm::execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let mut term = Terminal::new(backend)?;

let mut textarea = TextArea::default();
textarea.set_block(
Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::LightBlue))
.title("Crossterm Popup Example"),
);

let area = Rect {
width: 40,
height: 5,
x: 5,
y: 5,
};
textarea.set_style(Style::default().fg(Color::Yellow));

// set placeholder

textarea.set_placeholder_style(Style::default());
textarea.set_placeholder("prompt message".to_string());
loop {
term.draw(|f| {
f.render_widget(textarea.widget(), area);
})?;
match crossterm::event::read()?.into() {
Input { key: Key::Esc, .. } => break,
input => {
textarea.input(input);
}
}
}

disable_raw_mode()?;
crossterm::execute!(
term.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
term.show_cursor()?;

println!("Lines: {:?}", textarea.lines());
Ok(())
}
62 changes: 62 additions & 0 deletions examples/ratatui_placepop.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,62 @@
use crossterm::event::{DisableMouseCapture, EnableMouseCapture};
use crossterm::terminal::{
disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen,
};
use crossterm_026 as crossterm;
use ratatui::backend::CrosstermBackend;
use ratatui::layout::Rect;
use ratatui::style::{Color, Style};
use ratatui::widgets::{Block, Borders};
use ratatui::Terminal;
use std::io;
use tui_textarea::{Input, Key, TextArea};

fn main() -> io::Result<()> {
let stdout = io::stdout();
let mut stdout = stdout.lock();

enable_raw_mode()?;
crossterm::execute!(stdout, EnterAlternateScreen, EnableMouseCapture)?;
let backend = CrosstermBackend::new(stdout);
let mut term = Terminal::new(backend)?;

let mut textarea = TextArea::default();
textarea.set_block(
Block::default()
.borders(Borders::ALL)
.border_style(Style::default().fg(Color::LightBlue))
.title("Crossterm Popup Example"),
);

let area = Rect {
width: 40,
height: 5,
x: 5,
y: 5,
};
textarea.set_style(Style::default().fg(Color::Yellow));
textarea.set_placeholder_style(Style::default());
textarea.set_placeholder("prompt message".to_string());
loop {
term.draw(|f| {
f.render_widget(textarea.widget(), area);
})?;
match crossterm::event::read()?.into() {
Input { key: Key::Esc, .. } => break,
input => {
textarea.input(input);
}
}
}

disable_raw_mode()?;
crossterm::execute!(
term.backend_mut(),
LeaveAlternateScreen,
DisableMouseCapture
)?;
term.show_cursor()?;

println!("Lines: {:?}", textarea.lines());
Ok(())
}
1 change: 1 addition & 0 deletions examples/single_line.rs
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ fn main() -> io::Result<()> {

let mut textarea = TextArea::default();
textarea.set_cursor_line_style(Style::default());
textarea.set_placeholder("enter a valid float, eg 1.56".to_string());
let layout =
Layout::default().constraints([Constraint::Length(3), Constraint::Min(1)].as_slice());
let mut is_valid = validate(&mut textarea);
Expand Down
12 changes: 12 additions & 0 deletions src/textarea.rs
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,8 @@ pub struct TextArea<'a> {
#[cfg(feature = "search")]
search: Search,
alignment: Alignment,
pub(crate) placeholder: Option<String>,
pub(crate) placeholder_style: Option<Style>,
}

/// Convert any iterator whose elements can be converted into [`String`] into [`TextArea`]. Each [`String`] element is
Expand Down Expand Up @@ -147,6 +149,8 @@ impl<'a> TextArea<'a> {
#[cfg(feature = "search")]
search: Search::default(),
alignment: Alignment::Left,
placeholder: None,
placeholder_style: None,
}
}

Expand Down Expand Up @@ -1223,6 +1227,14 @@ impl<'a> TextArea<'a> {
self.line_number_style
}

/// sets the placeholder text
pub fn set_placeholder(&mut self, placeholder: String) {
self.placeholder = Some(placeholder);
}

pub fn set_placeholder_style(&mut self, style: Style) {
self.placeholder_style = Some(style);
}
/// Set the style of cursor. By default, a cursor is rendered in the reversed color. Setting the same style as
/// cursor line hides a cursor.
/// ```
Expand Down
31 changes: 28 additions & 3 deletions src/widget.rs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
use crate::textarea::TextArea;
use crate::tui::buffer::Buffer;
use crate::tui::layout::Rect;
use crate::tui::style::{Color, Style};
use crate::tui::text::Text;
use crate::tui::widgets::{Paragraph, Widget};
use crate::util::num_digits;
Expand Down Expand Up @@ -120,11 +121,35 @@ impl<'a> Widget for Renderer<'a> {
let top_col = next_scroll_top(top_col, cursor.1 as u16, width);

let text = self.text(top_row as usize, height as usize);

// check for placeholder text and style
let mut style = self.0.style();
let text = match &self.0.placeholder {
Some(ph) => {
if self.0.is_empty() {
// placeholder is defined and the box is empty
style = self
.0
.placeholder_style
// default to dark grey if the caller didnt specify
.unwrap_or(Style::default().fg(Color::DarkGray));
Text::from(ph.as_str())
} else {
text
}
}
None => text,
};

// to get fine control over the text color and the surrrounding block they have to be rendered separately
// see https://github.com/tui-rs-revival/ratatui/issues/144
let mut text_area = area;
let mut inner = Paragraph::new(text)
.style(self.0.style())
.style(style)
.alignment(self.0.alignment());
if let Some(b) = self.0.block() {
inner = inner.block(b.clone());
text_area = b.inner(area);
b.clone().render(area, buf)
}
if top_col != 0 {
inner = inner.scroll((0, top_col));
Expand All @@ -133,6 +158,6 @@ impl<'a> Widget for Renderer<'a> {
// Store scroll top position for rendering on the next tick
self.0.viewport.store(top_row, top_col, width, height);

inner.render(area, buf);
inner.render(text_area, buf);
}
}