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.
249 lines
9.7 KiB
249 lines
9.7 KiB
extern crate sdl2;
|
|
|
|
use clipboard::{ClipboardProvider, ClipboardContext};
|
|
use sdl2::event::{Event, WindowEvent};
|
|
use sdl2::keyboard::Keycode;
|
|
use sdl2::pixels::Color;
|
|
use sdl2::rect::Point;
|
|
|
|
mod editor_render;
|
|
|
|
static SCREEN_WIDTH: u32 = 1680;
|
|
static SCREEN_HEIGHT: u32 = 945;
|
|
|
|
struct ModifierKeys {
|
|
alt: bool,
|
|
ctrl: bool,
|
|
shift: bool,
|
|
}
|
|
|
|
pub fn main() -> Result<(), String> {
|
|
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()?;
|
|
|
|
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())?;
|
|
|
|
let mut buffer = String::new();
|
|
let mut cursor_position = 0;
|
|
let mut selection_anchor: Option<usize> = None;
|
|
|
|
let pad_offset = Point::new(10, 10);
|
|
|
|
let mut draw_text = |text: &str, pos: usize| -> Result<(), String> {
|
|
// Draw background
|
|
canvas.set_draw_color(Color::RGB(32, 32, 32));
|
|
canvas.clear();
|
|
|
|
// Draw text
|
|
canvas.set_draw_color(Color::RGB(240, 240, 240));
|
|
let fb_text = editor_render::draw_text(
|
|
&glyph_atlas,
|
|
&glyph_metrics,
|
|
text,
|
|
pad_offset
|
|
);
|
|
canvas.draw_points(&fb_text[..])?;
|
|
|
|
// Draw cursor
|
|
canvas.set_draw_color(Color::RGB(64, 240, 240));
|
|
let fb_cursor = editor_render::draw_cursor(
|
|
&glyph_metrics,
|
|
pos,
|
|
text,
|
|
pad_offset
|
|
);
|
|
canvas.draw_line(fb_cursor.0, fb_cursor.1)?;
|
|
|
|
canvas.present();
|
|
|
|
Ok(())
|
|
};
|
|
|
|
draw_text("", cursor_position)?;
|
|
|
|
let mut modifier_keys = ModifierKeys {alt: false, ctrl: false, shift: false};
|
|
|
|
'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_text(&buffer, cursor_position)?
|
|
}
|
|
}
|
|
// 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
|
|
},
|
|
_ => (),
|
|
};
|
|
|
|
match (modifier_keys.shift, modifier_keys.ctrl, modifier_keys.alt) {
|
|
// All modifiers up
|
|
(false, false, false) => {
|
|
match keycode {
|
|
// DELETE key
|
|
Some(Keycode::Delete) => {
|
|
if buffer.len() > 0 && cursor_position < buffer.len() {
|
|
buffer.remove(cursor_position);
|
|
draw_text(&buffer, cursor_position)?
|
|
}
|
|
},
|
|
|
|
// ENTER key
|
|
Some(Keycode::Return) => {
|
|
let key = '\n';
|
|
buffer.insert(cursor_position, key);
|
|
cursor_position += 1;
|
|
draw_text(&buffer, cursor_position)?
|
|
},
|
|
|
|
// HOME key
|
|
Some(Keycode::Home) => {
|
|
cursor_position = 0;
|
|
draw_text(&buffer, cursor_position)?
|
|
},
|
|
|
|
// END key
|
|
Some(Keycode::End) => {
|
|
cursor_position = buffer.len();
|
|
draw_text(&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(&buffer, cursor_position)?
|
|
},
|
|
|
|
// Right/Forward arrow
|
|
Some(Keycode::Right) => {
|
|
selection_anchor = None;
|
|
cursor_position = (cursor_position + 1).min(buffer.len());
|
|
draw_text(&buffer, cursor_position)?
|
|
},
|
|
|
|
// BACKSPACE key
|
|
Some(Keycode::Backspace) => {
|
|
if buffer.len() > 0 {
|
|
// Character backspace; regular
|
|
buffer.remove(cursor_position - 1);
|
|
cursor_position -= 1;
|
|
draw_text(&buffer, cursor_position)?
|
|
}
|
|
},
|
|
|
|
_ => (),
|
|
}
|
|
},
|
|
|
|
// CTRL down
|
|
(false, true, false) => {
|
|
match keycode {
|
|
Some(Keycode::Z) => println!("Undo"),
|
|
Some(Keycode::X) => println!("Cut"),
|
|
Some(Keycode::C) => {
|
|
clipboard_context.set_contents(buffer.clone()).unwrap()
|
|
},
|
|
Some(Keycode::V) => println!("Paste"),
|
|
|
|
// BACKSPACE key
|
|
// Word backspace
|
|
// TODO: Clean up this cursed expression
|
|
Some(Keycode::Backspace) => {
|
|
if buffer.len() > 0 {
|
|
let buffer_chars: Vec<char> = buffer.chars()
|
|
.collect();
|
|
while !(buffer_chars[cursor_position - 1] == ' ' ||
|
|
buffer_chars[cursor_position - 1] == '\n') &&
|
|
cursor_position > 1 {
|
|
buffer.remove(cursor_position - 1);
|
|
cursor_position -= 1;
|
|
}
|
|
buffer.remove(cursor_position - 1);
|
|
cursor_position -= 1;
|
|
|
|
draw_text(&buffer, cursor_position)?
|
|
}
|
|
},
|
|
_ => (),
|
|
}
|
|
},
|
|
|
|
(true, true, false) => {
|
|
match keycode {
|
|
Some(Keycode::Z) => println!("Redo"),
|
|
Some(Keycode::X) => println!("Cut line(s)"),
|
|
Some(Keycode::C) => println!("Copy line(s)"),
|
|
_ => (),
|
|
}
|
|
},
|
|
|
|
_ => (),
|
|
}
|
|
},
|
|
|
|
Event::TextInput { text, .. } => {
|
|
let input_char = text.chars().nth(0).expect("Empty");
|
|
|
|
buffer.insert(cursor_position, input_char);
|
|
cursor_position += 1;
|
|
draw_text(&buffer, cursor_position)?;
|
|
},
|
|
|
|
_ => {}
|
|
}
|
|
}
|
|
|
|
::std::thread::sleep(std::time::Duration::new(0, 50_000_000));
|
|
}
|
|
format!("{selection_anchor:?}");
|
|
println!("{buffer}");
|
|
Ok(())
|
|
}
|
|
|