use super::*;
use fnv::FnvHashMap;
type AutoCompleteFn = Box<Fn(&Context, &str) -> Vec<AutoCompleteEntry> + Send>;
#[derive(Debug, PartialEq)]
enum FormFocus {
Fields,
Buttons,
TextInput,
}
type Cursor = usize;
impl Default for FormFocus {
fn default() -> FormFocus {
FormFocus::Fields
}
}
pub enum Field {
Text(UText, Option<(AutoCompleteFn, AutoComplete)>),
Choice(Vec<String>, Cursor),
}
impl Debug for Field {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
match self {
Text(s, _) => fmt::Debug::fmt(s, f),
k => fmt::Debug::fmt(k, f),
}
}
}
use crate::Field::*;
impl Default for Field {
fn default() -> Field {
Field::Text(UText::new(String::with_capacity(256)), None)
}
}
impl Field {
pub fn as_str(&self) -> &str {
match self {
Text(ref s, _) => s.as_str(),
Choice(ref v, cursor) => {
if v.is_empty() {
""
} else {
v[*cursor].as_str()
}
}
}
}
pub fn is_empty(&self) -> bool {
self.as_str().is_empty()
}
pub fn into_string(self) -> String {
match self {
Text(s, _) => s.into_string(),
Choice(mut v, cursor) => v.remove(cursor),
}
}
pub fn clear(&mut self) {
match self {
Text(s, _) => s.clear(),
Choice(_, _) => {}
}
}
pub fn draw_cursor(
&mut self,
grid: &mut CellBuffer,
area: Area,
secondary_area: Area,
context: &mut Context,
) {
let upper_left = upper_left!(area);
match self {
Text(ref term, auto_complete_fn) => {
change_colors(
grid,
(
pos_inc(upper_left, (term.grapheme_pos(), 0)),
(pos_inc(upper_left, (term.grapheme_pos(), 0))),
),
Color::Default,
Color::Byte(248),
);
if term.grapheme_len() <= 2 {
return;
}
if let Some((auto_complete_fn, auto_complete)) = auto_complete_fn {
let entries = auto_complete_fn(context, term.as_str());
auto_complete.set_suggestions(entries);
auto_complete.draw(grid, secondary_area, context);
}
}
Choice(_, _cursor) => {}
}
}
}
impl Component for Field {
fn draw(&mut self, grid: &mut CellBuffer, area: Area, _context: &mut Context) {
write_string_to_grid(
self.as_str(),
grid,
Color::Default,
Color::Default,
area,
true,
);
}
fn process_event(&mut self, event: &mut UIEvent, _context: &mut Context) -> bool {
if let Text(ref mut s, Some((_, auto_complete))) = self {
if let UIEvent::InsertInput(Key::Char('\t')) = event {
if let Some(suggestion) = auto_complete.get_suggestion() {
*s = UText::new(suggestion);
let len = s.as_str().len().saturating_sub(1);
s.set_cursor(len);
return true;
}
}
}
match *event {
UIEvent::InsertInput(Key::Up) => {
if let Text(_, Some((_, auto_complete))) = self {
auto_complete.dec_cursor();
} else {
return false;
}
}
UIEvent::InsertInput(Key::Down) => {
if let Text(_, Some((_, auto_complete))) = self {
auto_complete.inc_cursor();
} else {
return false;
}
}
UIEvent::InsertInput(Key::Right) => match self {
Text(ref mut s, _) => {
s.cursor_inc();
}