You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

282 lines
10 KiB

extern crate sdl2;
use clipboard::{ClipboardContext, ClipboardProvider};
use sdl2::{
event::{Event, WindowEvent},
keyboard::Keycode,
};
mod file;
mod input;
mod render;
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 = 250;
static UNDO_TIME_COUNT: u32 = (REFRESH_RATE as f32 * (UNDO_TIME as f32 / 1000.0)) as u32;
pub fn main() -> Result<(), String> {
// Initialize clipboard
let mut clipboard_context: ClipboardContext = ClipboardProvider::new().unwrap();
// Initialize SDL2, window, and canvas
let sdl_context = sdl2::init()?;
let video_subsys = sdl_context.video()?;
let window = video_subsys
.window("Rude", SCREEN_WIDTH, SCREEN_HEIGHT)
.position_centered()
.resizable()
.opengl()
.build()
.map_err(|e| e.to_string())?;
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
// Initalize buffer
let mut buffer = String::new();
// Initialize undo data & values
let mut undo_history: Vec<(String, usize)> = vec![];
let mut undo_position: usize = 0;
let mut undo_timer: u32 = UNDO_TIME_COUNT;
// Initialize input values
let mut modifier_keys = input::ModifierKeys::new();
let mut cursor_position = 0;
let mut selection_anchor: Option<usize> = None;
// Initialize graphics data and values
let glyph_atlas = render::generate_glyph_data()?;
// Easier way to please the borrow checker
macro_rules! draw {
() => {
render::draw_everything(&mut canvas, &glyph_atlas, &buffer, cursor_position)?
};
}
draw!();
'mainloop: loop {
// TODO: Make this completely user-configurable instead of hardcoded
for event in sdl_context.event_pump()?.poll_iter() {
match event {
Event::Window { win_event, .. } => {
if let WindowEvent::Resized(_w, _h) = win_event {
draw!();
}
}
// ESC or SIGKILL
// Event::KeyDown { keycode: Some(Keycode::Escape), .. } |
Event::Quit { .. } => break 'mainloop,
Event::KeyUp { keycode, .. } => match keycode {
Some(Keycode::LAlt) | Some(Keycode::RAlt) => modifier_keys.alt = false,
Some(Keycode::LCtrl) | Some(Keycode::RCtrl) => modifier_keys.ctrl = false,
Some(Keycode::LShift) | Some(Keycode::RShift) => modifier_keys.shift = false,
Some(Keycode::LGui) | Some(Keycode::RGui) => break,
_ => (),
},
Event::KeyDown { keycode, .. } => {
match keycode {
Some(Keycode::LAlt) | Some(Keycode::RAlt) => modifier_keys.alt = true,
Some(Keycode::LCtrl) | Some(Keycode::RCtrl) => modifier_keys.ctrl = true,
Some(Keycode::LShift) | Some(Keycode::RShift) => modifier_keys.shift = true,
Some(Keycode::LGui) | Some(Keycode::RGui) => break,
// DELETE key
Some(Keycode::Delete) => {
if buffer.len() > 0 && cursor_position < buffer.len() {
undo_timer = 0;
selection_anchor = None;
input::delete(&mut buffer, cursor_position, &modifier_keys);
draw!();
}
}
// BACKSPACE key
Some(Keycode::Backspace) => {
if buffer.len() > 0 {
undo_timer = 0;
selection_anchor = None;
input::backspace(&mut buffer, &mut cursor_position, &modifier_keys);
draw!();
}
}
_ => (),
};
match (modifier_keys.shift, modifier_keys.ctrl, modifier_keys.alt) {
// All modifiers up
(false, false, false) => {
match keycode {
// ENTER key
Some(Keycode::Return) => {
undo_timer = 0;
selection_anchor = None;
let key = '\n';
buffer.insert(cursor_position, key);
cursor_position += 1;
draw!();
}
// HOME key
Some(Keycode::Home) => {
selection_anchor = None;
cursor_position = 0;
draw!();
}
// END key
Some(Keycode::End) => {
selection_anchor = None;
cursor_position = buffer.len();
draw!();
}
// Left/Back arrow
Some(Keycode::Left) => {
selection_anchor = None;
cursor_position =
usize::checked_sub(cursor_position, 1).unwrap_or(0);
draw!();
}
// Right/Forward arrow
Some(Keycode::Right) => {
selection_anchor = None;
cursor_position = (cursor_position + 1).min(buffer.len());
draw!();
}
_ => (),
}
}
// CTRL down
(false, true, false) => {
match keycode {
// Select all
Some(Keycode::A) => {
selection_anchor = Some(buffer.len());
cursor_position = 0;
draw!()
}
// 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!()
}
}
// TODO: Cut
Some(Keycode::X) => println!("Cut"),
// Copy
// TODO: Use selection
Some(Keycode::C) => {
clipboard_context.set_contents(buffer.clone()).unwrap()
}
// 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!()
}
_ => (),
}
}
// SHIFT + CTRL down
(true, true, false) => match keycode {
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!();
}
}
Some(Keycode::X) => println!("Cut line(s)"),
Some(Keycode::C) => println!("Copy line(s)"),
_ => (),
},
_ => (),
}
}
// Process user input
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!();
}
_ => {}
}
}
// 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 {
// Upon editing after an undo, this clears every action after such undo
if undo_position < undo_history.len() {
undo_history.truncate(undo_position);
}
undo_history.push((buffer.clone(), cursor_position));
undo_timer += 1;
undo_position += 1;
}
std::thread::sleep(std::time::Duration::new(0, 1_000_000_000 / REFRESH_RATE));
}
format!("{selection_anchor:?}");
println!("{buffer}");
Ok(())
}