use super::{CloneCell, Color, CopyCell, Event, Place, Point, Rect, Renderer, Widget, Window};
use super::callback::{Click, Enter};
use super::cell::CheckSet;
use std::cmp::min;
use std::sync::Arc;
pub struct TextBox {
pub rect: CopyCell<Rect>,
pub text: CloneCell<String>,
pub text_i: CopyCell<usize>,
pub bg: Color,
pub fg: Color,
pub fg_cursor: Color,
click_callback: Option<Arc<Fn(&TextBox, Point)>>,
enter_callback: Option<Arc<Fn(&TextBox)>>,
pressed: CopyCell<bool>,
}
impl TextBox {
pub fn new() -> Self {
TextBox {
rect: CopyCell::new(Rect::default()),
text: CloneCell::new(String::new()),
text_i: CopyCell::new(0),
bg: Color::rgb(255, 255, 255),
fg: Color::rgb(0, 0, 0),
fg_cursor: Color::rgb(128, 128, 128),
click_callback: None,
enter_callback: None,
pressed: CopyCell::new(false),
}
}
pub fn place(self, window: &mut Window) -> Arc<Self> {
let arc = Arc::new(self);
window.widgets.push(arc.clone());
arc
}
pub fn text(self, text: &str) -> Self {
self.text.set(text.to_string());
self.text_i.set(text.len());
self
}
}
impl Click for TextBox {
fn emit_click(&self, point: Point) {
if let Some(ref click_callback) = self.click_callback {
click_callback(self, point);
}
}
fn on_click<T: Fn(&Self, Point) + 'static>(mut self, func: T) -> Self {
self.click_callback = Some(Arc::new(func));
self
}
}
impl Enter for TextBox {
fn emit_enter(&self) {
if let Some(ref enter_callback) = self.enter_callback {
enter_callback(self)
}
}
fn on_enter<T: Fn(&Self) + 'static>(mut self, func: T) -> Self {
self.enter_callback = Some(Arc::new(func));
self
}
}
impl Place for TextBox {
fn position(self, x: i32, y: i32) -> Self {
let mut rect = self.rect.get();
rect.x = x;
rect.y = y;
self.rect.set(rect);
self
}
fn size(self, width: u32, height: u32) -> Self {
let mut rect = self.rect.get();
rect.width = width;
rect.height = height;
self.rect.set(rect);
self
}
}
impl Widget for TextBox {
fn draw(&self, renderer: &mut Renderer, focused: bool) {
let rect = self.rect.get();
renderer.rect(rect, self.bg);
let text_i = self.text_i.get();
let text = self.text.borrow();
let mut x = 0;
let mut y = 0;
for (i, c) in text.char_indices() {
if c == '\n' {
if i == text_i && focused && x + 8 <= rect.width as i32 &&
y + 16 <= rect.height as i32 {
renderer.rect(Rect::new(x + rect.x, y + rect.y, 8, 16), self.fg_cursor);
}
x = 0;
y += 16;
} else {
if x + 8 <= rect.width as i32 && y + 16 <= rect.height as i32 {
if i == text_i && focused {
renderer.rect(Rect::new(x + rect.x, y + rect.y, 8, 16), self.fg_cursor);
}
renderer.char(Point::new(x, y) + rect.point(), c, self.fg);
}
x += 8;
}
}
if text.len() == text_i && focused && x + 8 <= rect.width as i32 &&
y + 16 <= rect.height as i32 {
renderer.rect(Rect::new(x + rect.x, y + rect.y, 8, 16), self.fg_cursor);
}
}
fn event(&self, event: Event, mut focused: bool, redraw: &mut bool) -> bool {
match event {
Event::Mouse { point, left_button, .. } => {
let mut click = false;
let rect = self.rect.get();
if rect.contains(point) {
if left_button {
if self.pressed.check_set(true) {
*redraw = true;
}
} else {
if self.pressed.check_set(false) {
click = true;
*redraw = true;
}
}
} else {
if ! left_button {
if self.pressed.check_set(false) {
*redraw = true;
}
}
}
if click {
focused = true;
let click_point: Point = point - rect.point();
{
let text = self.text.borrow();
let mut new_text_i = None;
let mut x = 0;
let mut y = 0;
for (i, c) in text.char_indices() {
if c == '\n' {
if x + 8 <= rect.width as i32 && click_point.x >= x &&
y + 16 <= rect.height as i32 &&
click_point.y >= y &&
click_point.y < y + 16 {
new_text_i = Some(i);
break;
}
x = 0;
y += 16;
} else {
if x + 8 <= rect.width as i32 && click_point.x >= x &&
click_point.x < x + 8 &&
y + 16 <= rect.height as i32 &&
click_point.y >= y &&
click_point.y < y + 16 {
new_text_i = Some(i);
break;
}
x += 8;
}
}
if new_text_i.is_none() && x + 8 <= rect.width as i32 &&
click_point.x >= x &&
y + 16 <= rect.height as i32 &&
click_point.y >= y ||
click_point.y >= y + 16 {
new_text_i = Some(text.len());
}
if let Some(text_i) = new_text_i {
self.text_i.set(text_i);
}
}
self.emit_click(click_point);
}
}
Event::Text { c } => {
if focused {
let mut text = self.text.borrow_mut();
let text_i = self.text_i.get();
if text.is_char_boundary(text_i) {
text.insert(text_i, c);
self.text_i.set(min(text.char_range_at(text_i).next, text.len()));
}
*redraw = true;
}
}
Event::Enter => {
if focused {
if self.enter_callback.is_some() {
self.emit_enter();
} else {
let mut text = self.text.borrow_mut();
let text_i = self.text_i.get();
if text.is_char_boundary(text_i) {
text.insert(text_i, '\n');
self.text_i.set(min(text.char_range_at(text_i).next, text.len()));
}
}
*redraw = true;
}
}
Event::Backspace => {
if focused {
let mut text = self.text.borrow_mut();
let mut text_i = self.text_i.get();
if text.is_char_boundary(text_i) && text_i > 0 {
text_i = min(text.char_range_at_reverse(text_i).next, text.len());
if text.is_char_boundary(text_i) && text_i < text.len() {
text.remove(text_i);
self.text_i.set(min(text_i, text.len()));
}
}
*redraw = true;
}
}
Event::Delete => {
if focused {
let mut text = self.text.borrow_mut();
let text_i = self.text_i.get();
if text.is_char_boundary(text_i) && text_i < text.len() {
text.remove(text_i);
self.text_i.set(min(text_i, text.len()));
}
*redraw = true;
}
}
Event::Home => {
if focused {
let text = self.text.borrow();
let mut text_i = self.text_i.get();
while text.is_char_boundary(text_i) && text_i > 0 {
let range = text.char_range_at_reverse(text_i);
if range.ch == '\n' {
break;
}
text_i = range.next;
}
self.text_i.set(text_i);
*redraw = true;
}
}
Event::End => {
if focused {
let text = self.text.borrow();
let mut text_i = self.text_i.get();
while text.is_char_boundary(text_i) && text_i < text.len() {
let range = text.char_range_at(text_i);
if range.ch == '\n' {
break;
}
text_i = range.next;
}
self.text_i.set(text_i);
*redraw = true;
}
}
Event::UpArrow => {
if focused {
let text = self.text.borrow();
let mut text_i = self.text_i.get();
let mut offset = 0;
while text.is_char_boundary(text_i) && text_i > 0 {
let range = text.char_range_at_reverse(text_i);
text_i = range.next;
if range.ch == '\n' {
break;
}
offset += 1;
}
while text.is_char_boundary(text_i) && text_i > 0 {
let range = text.char_range_at_reverse(text_i);
if range.ch == '\n' {
break;
}
text_i = range.next;
}
while text.is_char_boundary(text_i) && offset > 0 && text_i < text.len() {
let range = text.char_range_at(text_i);
if range.ch == '\n' {
break;
}
text_i = range.next;
offset -= 1;
}
self.text_i.set(text_i);
*redraw = true;
}
}
Event::DownArrow => {
if focused {
let text = self.text.borrow();
let mut text_i = self.text_i.get();
let mut offset = 0;
while text.is_char_boundary(text_i) && text_i > 0 {
let range = text.char_range_at_reverse(text_i);
if range.ch == '\n' {
break;
}
text_i = range.next;
offset += 1;
}
while text.is_char_boundary(text_i) && text_i < text.len() {
let range = text.char_range_at(text_i);
text_i = range.next;
if range.ch == '\n' {
break;
}
}
while text.is_char_boundary(text_i) && offset > 0 && text_i < text.len() {
let range = text.char_range_at(text_i);
if range.ch == '\n' {
break;
}
text_i = range.next;
offset -= 1;
}
self.text_i.set(text_i);
*redraw = true;
}
}
Event::LeftArrow => {
if focused {
let text = self.text.borrow();
let text_i = self.text_i.get();
if text.is_char_boundary(text_i) && text_i > 0 {
self.text_i.set(min(text.char_range_at_reverse(text_i).next, text.len()));
}
*redraw = true;
}
}
Event::RightArrow => {
if focused {
let text = self.text.borrow();
let text_i = self.text_i.get();
if text.is_char_boundary(text_i) && text_i < text.len() {
self.text_i.set(min(text.char_range_at(text_i).next, text.len()));
}
*redraw = true;
}
}
_ => (),
}
focused
}
}