Move caret right

This commit is contained in:
Adrian Wozniak 2019-01-04 17:47:58 +01:00
parent 9460b6931a
commit 3a5587dbcc
No known key found for this signature in database
GPG Key ID: 3B441F7808FC43C7
7 changed files with 394 additions and 68 deletions

View File

@ -5,6 +5,8 @@ use crate::ui::caret::Caret;
use crate::ui::file::editor_file::EditorFile;
use crate::ui::file::*;
use crate::ui::menu_bar::MenuBar;
use crate::ui::caret::{CaretPosition, MoveDirection};
use crate::ui::text_character::TextCharacter;
use crate::ui::*;
use sdl2::rect::{Point, Rect};
use sdl2::VideoSubsystem;
@ -52,15 +54,29 @@ impl AppState {
};
let mut buffer: String = file.buffer();
let caret: &mut Caret = &mut self.caret;
let position: usize = caret.text_position();
if position == 0 {
let position: CaretPosition = caret.position().clone();
if position.text_position() == 0 {
return;
}
buffer.remove(position - 1);
match file.get_character_at(position - 1) {
let c: char = buffer.chars().collect::<Vec<char>>()[position.text_position() - 1];
buffer.remove(position.text_position() - 1);
let position = match c {
'\n' => CaretPosition::new(
position.text_position() - 1,
position.line_number() - 1,
0,
),
_ => CaretPosition::new(
position.text_position() - 1,
position.line_number(),
position.line_position(),
)
};
match file.get_character_at(position.text_position()) {
Some(character) => {
let dest: &Rect = character.dest();
caret.move_caret(position - 1, Point::new(dest.x(), dest.y()));
caret.move_caret(position, Point::new(dest.x(), dest.y()));
}
_ => {
caret.reset_caret();
@ -101,12 +117,16 @@ impl AppState {
_ => return,
};
let mut pos = Point::new(current.dest().x(), current.dest().y());
let mut position: usize = caret.text_position();
let mut position: CaretPosition = caret.position().clone();
for character in text.chars() {
buffer.insert(position, character);
buffer.insert(position.text_position(), character);
if let Some(rect) = get_text_character_rect(character, renderer) {
pos = pos + Point::new(rect.width() as i32, 0);
position += 1;
position = CaretPosition::new(
position.text_position() + 1,
position.line_number(),
position.line_position(),
);
caret.move_caret(position, pos.clone());
}
}
@ -115,9 +135,42 @@ impl AppState {
self.files[self.current_file] = new_file;
}
// fn current_file(&self) -> Option<&EditorFile> {
// self.files.get(self.current_file)
// }
pub fn insert_new_line(&mut self, renderer: &mut Renderer) {
let file: &mut EditorFile = if let Some(file) = self.files.get_mut(self.current_file) {
file
} else {
return;
};
let mut buffer: String = file.buffer();
let caret: &mut Caret = &mut self.caret;
let current = match file.get_character_at(caret.text_position()) {
Some(c) => c,
_ => return,
};
let mut pos = Point::new(current.dest().x(), current.dest().y());
let mut position: CaretPosition = caret.position().clone();
buffer.insert(position.text_position(), '\n');
if let Some(rect) = get_text_character_rect('\n', renderer) {
pos = Point::new(
self.config.editor_left_margin(),
pos.y() + rect.height() as i32,
);
position = CaretPosition::new(
position.text_position(),
position.line_number() + 1,
0,
);
caret.move_caret(position, pos.clone());
}
let new_file = EditorFile::new(file.path(), buffer, self.config.clone());
self.files[self.current_file] = new_file;
}
fn current_file(&self) -> Option<&EditorFile> {
self.files.get(self.current_file)
}
fn current_file_mut(&mut self) -> Option<&mut EditorFile> {
self.files.get_mut(self.current_file)
@ -147,6 +200,54 @@ impl AppState {
UpdateResult::NoOp
}
pub fn move_caret(&mut self, dir: MoveDirection) {
match dir {
MoveDirection::Left => {}
MoveDirection::Right =>
self.move_caret_right(),
MoveDirection::Up => {}
MoveDirection::Down => {}
}
}
fn move_caret_right(&mut self) {
let file: &EditorFile = match self.current_file() {
None => return,
Some(f) => f,
};
let line = self.caret.line_number().clone();
let characters: Vec<&TextCharacter> = match file.get_line(&line) {
None =>
return,
Some(characters) => characters,
};
let mut idx = 0;
for (i, c) in characters.iter().enumerate() {
if c.position() == self.caret.text_position() {
idx = i + 1;
break;
}
};
let text_character: &TextCharacter = match characters.get(idx) {
Some(text_character) => text_character,
None => return,
};
let line = text_character.line() - self.caret.line_number();
let pos = self.caret
.position()
.moved(1, line, 0);
let mut d: Rect = text_character.dest().clone();
if text_character.is_new_line() {
let prev = match characters.get(idx - 1) {
Some(c) => c,
_ => return,
};
d = prev.dest().clone();
d.set_x(d.x() + d.width() as i32);
}
self.caret.move_caret(pos, Point::new(d.x(), d.y()));
}
}
impl Render for AppState {

View File

@ -3,6 +3,7 @@ use crate::config::Config;
use crate::renderer::Renderer;
use crate::themes::*;
use crate::ui::*;
use crate::ui::caret::{CaretPosition,MoveDirection};
use std::rc::Rc;
use std::thread::sleep;
@ -30,10 +31,15 @@ pub enum UpdateResult {
Stop,
RefreshPositions,
MouseLeftClicked(Point),
MoveCaret(Rect, usize),
MoveCaret(Rect, CaretPosition),
DeleteFront,
DeleteBack,
Input(String),
InsertNewLine,
MoveCaretLeft,
MoveCaretRight,
MoveCaretUp,
MoveCaretDown,
}
pub enum Task {
@ -109,9 +115,23 @@ impl Application {
app_state.delete_back();
}
UpdateResult::Input(text) => {
println!("text input: {}", text);
app_state.insert_text(text, &mut renderer);
}
UpdateResult::InsertNewLine => {
app_state.insert_new_line(&mut renderer);
}
UpdateResult::MoveCaretLeft => {
app_state.move_caret(MoveDirection::Left);
}
UpdateResult::MoveCaretRight => {
app_state.move_caret(MoveDirection::Right);
}
UpdateResult::MoveCaretUp => {
app_state.move_caret(MoveDirection::Up);
}
UpdateResult::MoveCaretDown => {
app_state.move_caret(MoveDirection::Down);
}
}
for task in self.tasks.iter() {
match task {
@ -165,6 +185,11 @@ impl Application {
match keycode {
Keycode::Backspace => return UpdateResult::DeleteFront,
Keycode::Delete => return UpdateResult::DeleteBack,
Keycode::KpEnter | Keycode::Return => return UpdateResult::InsertNewLine,
Keycode::Left => return UpdateResult::MoveCaretLeft,
Keycode::Right => return UpdateResult::MoveCaretRight,
Keycode::Up => return UpdateResult::MoveCaretUp,
Keycode::Down => return UpdateResult::MoveCaretDown,
_ => UpdateResult::NoOp,
};
}

View File

@ -7,6 +7,7 @@ use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};
use sdl2::render::Texture;
use std::rc::Rc;
use std::ops::Deref;
#[derive(Clone, Debug, PartialEq)]
enum CaretState {
@ -15,42 +16,159 @@ enum CaretState {
}
#[derive(Clone, Debug, PartialEq)]
pub struct Caret {
pending: bool,
pub enum MoveDirection {
Left,
Right,
Up,
Down
}
//#[derive(Clone, Debug, PartialEq)]
//pub enum CaretLocation {
// FirstLineFirstCharacter,
// FirstLine(usize), // with character location
// LastLineFirstCharacter,
// LastLine(usize), // with character location
// FirstCharacter(usize),// with line number
// LastCharacter(usize), // with line number
// Other(usize, usize), // with line number and character number
//}
#[derive(Clone, Copy, Debug, PartialEq)]
pub struct CaretPosition {
text_position: usize,
blink_delay: u8,
// config: Rc<Config>,
state: CaretState,
line_number: usize,
line_position: usize,
}
impl CaretPosition {
pub fn new(text_position: usize, line_number: usize, line_position: usize,) -> Self {
Self {
text_position,
line_number,
line_position
}
}
pub fn text_position(&self) -> usize {
self.text_position.clone()
}
pub fn line_number(&self) -> usize {
self.line_number.clone()
}
pub fn line_position(&self) -> usize {
self.line_position.clone()
}
pub fn reset(&mut self) {
self.text_position = 0;
self.line_number = 0;
self.line_position = 0;
}
pub fn set_text_position(&mut self, n: usize) {
self.text_position = n;
}
pub fn set_line_number(&mut self, n: usize) {
self.line_number = n;
}
pub fn set_line_position(&mut self, n: usize) {
self.line_position = n;
}
pub fn moved(&self, text_position: usize, line_number: usize, line_position: usize) -> Self {
Self {
text_position: self.text_position + text_position,
line_number: self.line_number + line_number,
line_position: self.line_position + line_position
}
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct CaretRenderPosition {
dest: Rect,
reset_position: Rect,
bright_character_color: Color,
blur_character_color: Color,
}
impl CaretRenderPosition {
pub fn dest(&self) -> &Rect {
&self.dest
}
pub fn reset_position(&self) -> &Rect {
&self.reset_position
}
pub fn reset(&mut self) {
self.dest = self.reset_position.clone()
}
pub fn move_to(&mut self, p: &Point) {
self.dest.set_x(p.x());
self.dest.set_y(p.y());
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct CaretColor {
bright: Color,
blur: Color,
}
impl CaretColor {
pub fn bright(&self) -> &Color {
&self.bright
}
pub fn blur(&self) -> &Color {
&self.blur
}
}
#[derive(Clone, Debug, PartialEq)]
pub struct Caret {
pending: bool,
blink_delay: u8,
state: CaretState,
position: CaretPosition,
render_position: CaretRenderPosition,
colors: CaretColor,
}
impl Caret {
pub fn new(config: Rc<Config>) -> Self {
let bright_character_color = config.theme().caret().bright().color().into();
let blur_character_color = config.theme().caret().blur().color().into();
let bright = config.theme().caret().bright().color().into();
let blur = config.theme().caret().blur().color().into();
Self {
state: CaretState::Bright,
blink_delay: 0,
dest: Rect::new(
config.editor_left_margin(),
config.editor_top_margin(),
4,
0,
),
reset_position: Rect::new(
config.editor_left_margin(),
config.editor_top_margin(),
4,
0,
),
bright_character_color,
blur_character_color,
render_position: CaretRenderPosition {
dest: Rect::new(
config.editor_left_margin(),
config.editor_top_margin(),
4,
0,
),
reset_position: Rect::new(
config.editor_left_margin(),
config.editor_top_margin(),
4,
0,
),
},
colors: CaretColor { bright, blur },
pending: true,
text_position: 0,
// config,
position: CaretPosition {
text_position: 0,
line_number: 0,
line_position: 0,
},
// config,
}
}
@ -63,44 +181,48 @@ impl Caret {
}
pub fn reset_caret(&mut self) {
self.dest = self.reset_position.clone();
self.text_position = 0;
self.render_position.reset();
self.position.reset();
}
pub fn move_caret(&mut self, position: usize, pos: Point) {
self.text_position = position;
self.dest.set_x(pos.x());
self.dest.set_y(pos.y());
pub fn move_caret(&mut self, position: CaretPosition, pos: Point) {
self.position = position;
self.render_position.move_to(&pos);
}
pub fn text_position(&self) -> usize {
self.text_position
pub fn position(&self) -> &CaretPosition {
&self.position
}
}
impl Deref for Caret {
type Target = CaretPosition;
fn deref(&self) -> &<Self as Deref>::Target {
self.position()
}
}
impl Render for Caret {
fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) -> UpdateResult {
if self.pending {
use crate::renderer::managers::FontDetails;
let config = renderer.config().clone();
let font = renderer
.font_manager()
.load(&FontDetails {
path: config.editor_config().font_path().clone(),
size: config.editor_config().character_size(),
})
.unwrap_or_else(|_| panic!("Unable to load font"));
if let Ok((_, h)) = font.size_of_char('W') {
self.dest.set_height(h);
self.reset_position = self.dest.clone();
if let Some(rect) = get_text_character_rect('W', renderer) {
let mut dest = self.render_position.dest().clone();
dest.set_height(rect.height());
let reset_position = dest.clone();
self.render_position = CaretRenderPosition {
dest,
reset_position,
};
}
self.pending = false;
}
let start = Point::new(self.dest.x(), self.dest.y());
let end = Point::new(self.dest.x(), self.dest.y() + self.dest.height() as i32);
let dest = self.render_position.dest();
let start = Point::new(dest.x(), dest.y());
let end = Point::new(dest.x(), dest.y() + dest.height() as i32);
let color = match self.state {
CaretState::Bright => &self.bright_character_color,
CaretState::Blur => &self.blur_character_color,
CaretState::Bright => self.colors.bright(),
CaretState::Blur => self.colors.blur(),
};
canvas.set_draw_color(color.clone());
canvas
@ -128,6 +250,6 @@ impl ClickHandler for Caret {
}
fn is_left_click_target(&self, point: &Point) -> bool {
is_in_rect(point, &self.dest)
is_in_rect(point, &self.render_position.dest())
}
}

View File

@ -48,6 +48,23 @@ impl EditorFile {
None
}
pub fn get_line(&self, line: &usize) -> Option<Vec<&TextCharacter>> {
let mut vec: Vec<&TextCharacter> = vec![];
for section in self.sections.iter() {
match section.get_line(line) {
Some(v) => vec.append(&mut v.clone()),
_ => (),
}
}
if vec.is_empty() {
None
} else {
Some(vec)
}
}
fn refresh_characters_position(&mut self) {
let mut current: Rect = self.render_position.clone();
for section in self.sections.iter_mut() {

View File

@ -48,6 +48,21 @@ impl EditorFileSection {
}
None
}
pub fn get_line(&self, line: &usize) -> Option<Vec<&TextCharacter>> {
let mut vec: Vec<&TextCharacter> = vec![];
for token in self.tokens.iter() {
match token.get_line(line) {
Some(v) => vec.append(&mut v.clone()),
_ => (),
};
}
if vec.is_empty() {
None
} else {
Some(vec)
}
}
}
impl Render for EditorFileSection {

View File

@ -42,6 +42,33 @@ impl EditorFileToken {
None
}
pub fn get_line(&self, line: &usize) -> Option<Vec<&TextCharacter>> {
let mut vec: Vec<&TextCharacter> = vec![];
for c in self.characters.iter() {
let _tmp = (line.clone(), c.line().clone(), self.token_type.is_new_line(), c.text_character());
match (line.clone(), c.line().clone(), self.token_type.is_new_line()) {
(0, 0, true) => {
vec.push(c);
},
(a, b, true) if (a + 1) == b => {
vec.push(c);
},
(a, b, true) if a != (b + 1) =>
(),
(a, b, false) if a == b => {
vec.push(c);
}
_t =>
(),
}
}
if vec.is_empty() {
None
} else {
Some(vec)
}
}
fn update_view(&mut self, renderer: &mut Renderer) -> UpdateResult {
let config = renderer.config().theme().code_highlighting();
let color: Color = match self.token_type {

View File

@ -1,10 +1,10 @@
use crate::app::{UpdateResult, WindowCanvas};
use crate::config::Config;
use crate::lexer::TokenType;
use crate::renderer::managers::FontDetails;
use crate::renderer::managers::TextDetails;
use crate::renderer::managers::{TextDetails, FontDetails};
use crate::renderer::Renderer;
use crate::ui::*;
use crate::ui::caret::CaretPosition;
use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};
@ -79,7 +79,11 @@ impl TextCharacter {
.load(&font_details)
.unwrap_or_else(|_| panic!("Font not found {:?}", font_details));
if let Some(rect) = get_text_character_rect(self.text_character.clone(), renderer) {
let c = match self.text_character {
'\n' => 'W',
c => c,
};
if let Some(rect) = get_text_character_rect(c, renderer) {
self.source = rect.clone();
self.dest = rect.clone();
}
@ -98,7 +102,7 @@ impl TextCharacter {
}
#[inline]
fn is_new_line(&self) -> bool {
pub fn is_new_line(&self) -> bool {
self.text_character == '\n'
}
@ -110,6 +114,14 @@ impl TextCharacter {
pub fn position(&self) -> usize {
self.position
}
pub fn line(&self) -> usize {
self.line
}
pub fn text_character(&self) -> char {
self.text_character.clone()
}
}
impl Render for TextCharacter {
@ -154,7 +166,14 @@ impl Update for TextCharacter {
impl ClickHandler for TextCharacter {
fn on_left_click(&mut self, _point: &Point) -> UpdateResult {
UpdateResult::MoveCaret(self.dest().clone(), self.position())
UpdateResult::MoveCaret(
self.dest().clone(),
CaretPosition::new(
self.position(),
self.line(),
0,
),
)
}
fn is_left_click_target(&self, point: &Point) -> bool {