undo and redo

type-render
korin 3 years ago
parent a5c0bed37d
commit 394f6d2fb8
  1. 37
      TODO.org
  2. 126
      src/main.rs

@ -11,8 +11,8 @@
* [ ] Confine to line unless CTRL is pressed
- [ ] Mouse input
* Editing [0/5]
- [ ] Type text
* Editing [2/7]
- [X] Type text
- [-] Remove text [3/6]
* [X] Character backspace
* [X] Character delete
@ -21,29 +21,36 @@
* [ ] Sentence backspace
* [ ] Sentence delete
- [ ] Select text
- [ ] Cut, Copy, & Paste
- [ ] Undo / Redo
- [-] Cut
- [-] Copy
- [X] Paste
- [-] Undo / Redo
* (Creates a copy of the buffer after a period of inactivity, does not switch said buffer out yet, however)
* Rendering [1/6]
* Rendering [1/8]
- [-] Text [1/3]
* [X] Redneck bitmap
* [ ] Refined bitmap (.otb format)
* [ ] Vector (.ttf, .otf, etc)
- [X] Cursor
- [ ] Multi-panel
- [ ] Selection
- [ ] Scaling/Zoom
- [ ] Scrolling
- [ ] Syntax Highlighting [/]
- [ ] Built-in basic Rust highlighting
- [ ] Syntax Highlighting [0/3]
* [ ] Built-in basic Rust highlighting
* [ ] Built-in basic RON highlighting
* [ ] Built-in basic Lua highlighting
- [-] Status bar
* Misc [0/3]
* Misc [0/4]
- [ ] Search [0/1]
- [ ] Regex support
* [ ] Regex support
- [ ] Replace [0/2]
- [ ] Regex support
- [ ] Sed style
* [ ] Regex support
* [ ] Sed style
- [ ] File handling [0/3]
- [ ] Open files
- [ ] Save files
- [ ] Save files as
- [ ] Folder handling (for projects)
* [ ] Open files
* [ ] Save files
* [ ] Folder handling (for projects)
- [ ] Configuration file

@ -9,8 +9,15 @@ use sdl2::rect::{Point, Rect};
mod editor_render;
static SCREEN_WIDTH: u32 = 1680;
static SCREEN_HEIGHT: u32 = 945;
static SCREEN_WIDTH: u32 = 1280;
static SCREEN_HEIGHT: u32 = 720;
// TODO: Make this configurable
static REFRESH_RATE: u32 = 50;
// TODO: Make this configurable
static UNDO_TIME: u32 = 500;
static UNDO_TIME_COUNT: u32 = (REFRESH_RATE as f32 * (UNDO_TIME as f32 / 1000.0)) as u32;
struct ModifierKeys {
alt: bool,
@ -19,8 +26,9 @@ struct ModifierKeys {
}
pub fn main() -> Result<(), String> {
let mut modifier_keys = ModifierKeys {alt: false, ctrl: false, shift: false};
let mut clipboard_context: ClipboardContext = ClipboardProvider::new().unwrap();
let (glyph_atlas, glyph_metrics) = editor_render::generate_glyph_data();
let sdl_context = sdl2::init()?;
let video_subsys = sdl_context.video()?;
@ -41,9 +49,15 @@ pub fn main() -> Result<(), String> {
let mut cursor_position = 0;
let mut selection_anchor: Option<usize> = None;
let mut undo_history: Vec<(String, usize)> = vec![];
let mut undo_position: usize = 0;
let mut undo_timer: u32 = UNDO_TIME_COUNT;
let pad_offset = Point::new(10, 10);
let mut draw_text = |window_size: (u32, u32), text: &str, pos: usize| -> Result<(), String> {
let (glyph_atlas, glyph_metrics) = editor_render::generate_glyph_data();
let mut draw = |window_size: (u32, u32), text: &str, pos: usize| -> Result<(), String> {
// Draw background
canvas.set_draw_color(Color::RGB(32, 32, 32));
canvas.clear();
@ -96,9 +110,7 @@ pub fn main() -> Result<(), String> {
Ok(())
};
draw_text(window_size, "", cursor_position)?;
let mut modifier_keys = ModifierKeys {alt: false, ctrl: false, shift: false};
draw(window_size, "", cursor_position)?;
'mainloop: loop {
// TODO: Make this completely user-configurable instead of hardcoded
@ -107,11 +119,11 @@ pub fn main() -> Result<(), String> {
Event::Window { win_event, .. } => {
if let WindowEvent::Resized(w, h) = win_event {
window_size = (w as u32, h as u32);
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
}
}
// ESC or SIGKILL
Event::KeyDown { keycode: Some(Keycode::Escape), .. } |
// Event::KeyDown { keycode: Some(Keycode::Escape), .. } |
Event::Quit { .. } => break 'mainloop,
Event::KeyUp { keycode, .. } => {
@ -156,53 +168,68 @@ pub fn main() -> Result<(), String> {
// DELETE key
Some(Keycode::Delete) => {
if buffer.len() > 0 && cursor_position < buffer.len() {
undo_timer = 0;
selection_anchor = None;
buffer.remove(cursor_position);
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
}
},
// ENTER key
Some(Keycode::Return) => {
undo_timer = 0;
selection_anchor = None;
let key = '\n';
buffer.insert(cursor_position, key);
cursor_position += 1;
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
},
// HOME key
Some(Keycode::Home) => {
selection_anchor = None;
cursor_position = 0;
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
},
// END key
Some(Keycode::End) => {
selection_anchor = None;
cursor_position = buffer.len();
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
},
// Left/Back arrow
Some(Keycode::Left) => {
selection_anchor = None;
cursor_position = usize::checked_sub(cursor_position, 1)
.unwrap_or(0);
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
},
// Right/Forward arrow
Some(Keycode::Right) => {
selection_anchor = None;
cursor_position = (cursor_position + 1).min(buffer.len());
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
},
// BACKSPACE key
// Character backspace
Some(Keycode::Backspace) => {
if buffer.len() > 0 {
// Character backspace; regular
undo_timer = 0;
selection_anchor = None;
buffer.remove(cursor_position - 1);
cursor_position -= 1;
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
}
},
@ -213,18 +240,42 @@ pub fn main() -> Result<(), String> {
// CTRL down
(false, true, false) => {
match keycode {
Some(Keycode::Z) => println!("Undo"),
Some(Keycode::Z) => {
if undo_position > 1 {
undo_position -= 1;
let last_undo = undo_history[undo_position - 1].clone();
buffer = last_undo.0;
cursor_position = last_undo.1;
draw(window_size, &buffer, cursor_position)?
}
},
Some(Keycode::X) => println!("Cut"),
Some(Keycode::C) => {
clipboard_context.set_contents(buffer.clone()).unwrap()
},
Some(Keycode::V) => println!("Paste"),
Some(Keycode::V) => {
let paste = clipboard_context.get_contents().unwrap();
for character in paste.chars() {
buffer.insert(cursor_position, character);
cursor_position += 1;
undo_timer = UNDO_TIME_COUNT;
}
draw(window_size, &buffer, cursor_position)?
},
// BACKSPACE key
// Word backspace
// TODO: Clean up this cursed expression
Some(Keycode::Backspace) => {
if buffer.len() > 0 {
undo_timer = 0;
selection_anchor = None;
let buffer_chars: Vec<char> = buffer.chars()
.collect();
while !(buffer_chars[cursor_position - 1] == ' ' ||
@ -236,7 +287,7 @@ pub fn main() -> Result<(), String> {
buffer.remove(cursor_position - 1);
cursor_position -= 1;
draw_text(window_size, &buffer, cursor_position)?
draw(window_size, &buffer, cursor_position)?
}
},
_ => (),
@ -245,8 +296,19 @@ pub fn main() -> Result<(), String> {
(true, true, false) => {
match keycode {
Some(Keycode::Z) => println!("Redo"),
Some(Keycode::Z) => {
if undo_position < undo_history.len() {
undo_position += 1;
let last_redo = undo_history[undo_position - 1].clone();
buffer = last_redo.0;
cursor_position = last_redo.1;
draw(window_size, &buffer, cursor_position)?
}
},
Some(Keycode::X) => println!("Cut line(s)"),
Some(Keycode::C) => println!("Copy line(s)"),
_ => (),
}
@ -257,18 +319,36 @@ pub fn main() -> Result<(), String> {
},
Event::TextInput { text, .. } => {
undo_timer = 0;
selection_anchor = None;
let input_char = text.chars().nth(0).expect("Empty");
buffer.insert(cursor_position, input_char);
cursor_position += 1;
draw_text(window_size, &buffer, cursor_position)?;
draw(window_size, &buffer, cursor_position)?;
},
_ => {}
}
}
::std::thread::sleep(std::time::Duration::new(0, 50_000_000));
// Wait for pause in input to snapshot buffer for undoing/redoing
if undo_timer < UNDO_TIME_COUNT {
undo_timer += 1;
} else if undo_timer == UNDO_TIME_COUNT {
// println!("Saving undo step.");
if undo_position < undo_history.len() {
undo_history.truncate(undo_position);
}
undo_history.push((buffer.clone(), cursor_position));
undo_timer += 1;
undo_position += 1;
//println!("Undo data: {undo_history:?}");
}
::std::thread::sleep(std::time::Duration::new(0, 1_000_000_000 / REFRESH_RATE));
}
format!("{selection_anchor:?}");
println!("{buffer}");

Loading…
Cancel
Save