use std::io::Write;
use rand::Rng;
use crate::decode;
use crate::input_buffer::{self, InputBuffer};
use crate::layout as layout_mod;
use crate::prompt::{
TextEntry, TextEntryLayout, queue_clear_prompt, queue_text_entry, queue_text_entry_with_cursor,
text_entry, text_entry_layout,
};
#[derive(Debug, Clone)]
pub struct TextEntryComponent {
pub label: String,
pub content: String,
pub open: f64,
pub label_reveal: f64,
pub content_reveal: f64,
pub visible: bool,
}
impl TextEntryComponent {
pub fn prompt(label: impl Into<String>, default_value: impl Into<String>) -> Self {
Self {
label: label.into(),
content: default_value.into(),
open: 0.0,
label_reveal: 0.0,
content_reveal: 0.0,
visible: true,
}
}
pub fn hidden() -> Self {
Self {
label: String::new(),
content: String::new(),
open: 0.0,
label_reveal: 0.0,
content_reveal: 0.0,
visible: false,
}
}
#[cfg(not(tarpaulin_include))]
pub fn render_with_cursor<W: Write, R: Rng>(
&self,
writer: &mut W,
layout: &TextEntryLayout,
tw: u16,
buf: &InputBuffer,
rng: &mut R,
) -> std::io::Result<u16> {
if self.open < 1.0 {
self.render_partial_open(writer, layout, tw)?;
return Ok(0);
}
let label_display = if self.label_reveal >= 1.0 {
self.label.clone()
} else {
let revealed = (self.label.chars().count() as f64 * self.label_reveal).round() as usize;
decode::decode_frame(&self.label, revealed, rng)
};
let content_display = if self.content_reveal >= 1.0 {
self.content.clone()
} else {
let revealed = (self.content.chars().count() as f64 * self.content_reveal).round() as usize;
decode::decode_frame(&self.content, revealed, rng)
};
let frame = text_entry(&label_display, &content_display, tw);
let label_width = label_display.chars().count() as u16;
let buf_text = input_buffer::text(buf);
let cursor_pos = input_buffer::cursor(buf);
let selection = input_buffer::selection_range(buf);
queue_text_entry_with_cursor(
writer,
layout,
&frame,
buf_text,
label_width,
cursor_pos,
selection,
)
}
#[cfg(not(tarpaulin_include))]
pub fn render_partial_open<W: Write>(
&self,
writer: &mut W,
layout: &TextEntryLayout,
tw: u16,
) -> std::io::Result<()> {
let full_width = layout.inner_width;
let raw = ((full_width as f64) * self.open).round() as u16;
let even = (raw / 2) * 2;
let current_width = if even == 0 && raw > 0 {
2
} else {
even.min(full_width)
};
if current_width == 0 {
return queue_clear_prompt(writer, layout);
}
let partial = TextEntry {
label: String::new(),
hint: String::new(),
inner_width: current_width,
};
let partial_layout =
text_entry_layout(&partial, layout_mod::size(tw, layout.question_row + 10));
let merged = TextEntryLayout {
question_row: layout.question_row,
box_top_row: layout.box_top_row,
content_row: layout.content_row,
box_bottom_row: layout.box_bottom_row,
hint_row: layout.hint_row,
box_column: partial_layout.box_column,
inner_width: current_width,
};
queue_text_entry(writer, &merged, &partial, "", 0)
}
}