diff --git a/TODO.org b/TODO.org index cfcca9f..4b1a245 100644 --- a/TODO.org +++ b/TODO.org @@ -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 diff --git a/src/main.rs b/src/main.rs index 14ef7ee..132bb00 100644 --- a/src/main.rs +++ b/src/main.rs @@ -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 = 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 = 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}");