Compare commits

..

No commits in common. 'f267c12e5cf4e6e0978a343e276f1882298ff544' and '394f6d2fb8550c0dda55d76b42224560b8563d65' have entirely different histories.

  1. 88
      src/editor_render.rs
  2. 48
      src/input.rs
  3. 160
      src/main.rs

@ -3,21 +3,13 @@
//! This takes a janky ass raw image file with width info inserted
//! and turns it into a bunch of points for SDL2 to read.
use num_format::{Locale, ToFormattedString};
use sdl2::{
pixels::Color,
rect::{Point, Rect},
render::Canvas,
video::Window,
};
use std::{fs::File, path::Path, io::Read};
type Glyph = Vec<Point>;
use sdl2::rect::Point;
struct GlyphMetrics {
width: usize,
height: usize,
pub struct GlyphMetrics {
pub width: usize,
pub height: usize,
}
impl GlyphMetrics {
@ -26,10 +18,7 @@ impl GlyphMetrics {
}
}
pub struct GlyphAtlas {
glyphs: Vec<Glyph>,
metrics: GlyphMetrics,
}
type Glyph = Vec<Point>;
/// Reads the file and turns it into a Vec of u8s
fn read_file(file_name: String) -> Vec<u8> {
@ -46,7 +35,7 @@ fn read_file(file_name: String) -> Vec<u8> {
file_content
}
pub fn generate_glyph_data() -> GlyphAtlas {
pub fn generate_glyph_data() -> (Vec<Glyph>, GlyphMetrics) {
// Retrieve font data from file
let file_path = String::from("./fonts/Terminus14x8.data");
let contents = read_file(file_path);
@ -60,7 +49,7 @@ pub fn generate_glyph_data() -> GlyphAtlas {
let width_right_byte = contents[1];
let width_bytes = [width_left_byte, width_right_byte];
let width = u16::from_be_bytes(width_bytes);
// println!("Left Byte: {width_left_byte}, Right Byte: {width_right_byte}, Byte Pair: {width}");
println!("Left Byte: {width_left_byte}, Right Byte: {width_right_byte}, Byte Pair: {width}");
let gtable_prune = &contents[width as usize + 2 ..];
@ -84,15 +73,15 @@ pub fn generate_glyph_data() -> GlyphAtlas {
}
glyph_atlas.push(new_glyph);
}
GlyphAtlas { glyphs: glyph_atlas, metrics: glyph_metrics }
(glyph_atlas, glyph_metrics)
}
/// Method for generating points to render, using given string
fn draw_text(glyph_atlas: &GlyphAtlas, content: &str, offset: Point) -> Vec<Point> {
pub fn draw_text(glyph_atlas: &Vec<Glyph>, glyph_metrics: &GlyphMetrics, content: &str, offset: Point) -> Vec<Point> {
let mut points: Vec<Point> = vec![];
let glyph_width = glyph_atlas.metrics.width;
let glyph_height = glyph_atlas.metrics.height;
let glyph_width = glyph_metrics.width;
let glyph_height = glyph_metrics.height;
let lines = content.split('\n');
for (y, chars) in lines.enumerate() {
@ -104,7 +93,7 @@ fn draw_text(glyph_atlas: &GlyphAtlas, content: &str, offset: Point) -> Vec<Poin
index = chara.to_ascii_uppercase() as usize;
}
for pixel in &glyph_atlas.glyphs[index - 32] {
for pixel in &glyph_atlas[index - 32] {
let x_glyph = x * glyph_width;
let y_glyph = y * glyph_height;
@ -119,9 +108,9 @@ fn draw_text(glyph_atlas: &GlyphAtlas, content: &str, offset: Point) -> Vec<Poin
points
}
pub fn draw_cursor(glyph_atlas: &GlyphAtlas, mut cursor_position: usize, content: &str, offset: Point) -> (Point, Point) {
let glyph_width = glyph_atlas.metrics.width;
let glyph_height = glyph_atlas.metrics.height;
pub fn draw_cursor(glyph_metrics: &GlyphMetrics, mut cursor_position: usize, content: &str, offset: Point) -> (Point, Point) {
let glyph_width = glyph_metrics.width;
let glyph_height = glyph_metrics.height;
let mut x = 0;
let mut y = 0;
@ -129,6 +118,7 @@ pub fn draw_cursor(glyph_atlas: &GlyphAtlas, mut cursor_position: usize, content
cursor_position = cursor_position.checked_sub(1).unwrap_or(0);
for (idx, chara) in content.chars().enumerate() {
x += 1;
if chara == '\n' {
x = 0;
y += 1;
@ -146,49 +136,3 @@ pub fn draw_cursor(glyph_atlas: &GlyphAtlas, mut cursor_position: usize, content
}
(Point::new(offset.x, offset.y), Point::new(offset.x, offset.y + glyph_height as i32))
}
/// Draw all contents to the window
pub fn draw_everything(canvas: &mut Canvas<Window>,
glyph_atlas: &GlyphAtlas,
buffer: &str,
cursor_position: usize) -> Result<(), String> {
// Quick initialization
let window_size = canvas.output_size()?;
let text_offset = Point::new(10, 10);
// 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 = draw_text(&glyph_atlas, buffer, text_offset);
canvas.draw_points(&fb_text[..])?;
// Draw info
let status = buffer.len().to_formatted_string(&Locale::en);
let status_position = Point::new(
text_offset.x,
window_size.1 as i32 - glyph_atlas.metrics.height as i32 * 2
);
canvas.set_draw_color(Color::RGB(16, 64, 64));
canvas.fill_rect(Rect::new(0,
status_position.y - 5,
window_size.0,
glyph_atlas.metrics.height as u32 + 10
))?;
canvas.set_draw_color(Color::RGB(127, 240, 240));
let status_bar = draw_text(&glyph_atlas, &status, status_position);
canvas.draw_points(&status_bar[..])?;
// Draw cursor
canvas.set_draw_color(Color::RGB(64, 240, 240));
let fb_cursor = draw_cursor(&glyph_atlas, cursor_position, buffer, text_offset);
canvas.draw_line(fb_cursor.0, fb_cursor.1)?;
canvas.present();
Ok(())
}

@ -1,48 +0,0 @@
use sdl2::keyboard::Keycode;
mod keybinds {
pub(super) enum Clipboard {
CutSelection,
CutLines,
CopySelection,
CopyLines,
Paste,
PasteOverwrite,
}
pub(super) enum Editing {
Undo,
Redo,
NewLines,
DeleteLines,
}
pub(super) enum Movement {
DocBegin,
DocEnd,
LineBack,
LineBegin,
LineForward,
LineEnd,
CharBack,
CharForward,
WordBack,
WordForward,
ParaBack,
ParaForward,
}
pub(super) enum Selection {
CharBack,
Forward,
WordBack,
WordForward,
ParaBack,
ParaForward,
WholeLines,
}
}
fn input(buffer: &str, modifiers: crate::ModifierKeys, key: Keycode) {
}

@ -1,13 +1,13 @@
extern crate sdl2;
use clipboard::{ClipboardProvider, ClipboardContext};
use sdl2::{
event::{Event, WindowEvent},
keyboard::Keycode,
};
use num_format::{Locale, ToFormattedString};
use sdl2::event::{Event, WindowEvent};
use sdl2::keyboard::Keycode;
use sdl2::pixels::Color;
use sdl2::rect::{Point, Rect};
mod render;
mod input;
mod editor_render;
static SCREEN_WIDTH: u32 = 1280;
static SCREEN_HEIGHT: u32 = 720;
@ -16,7 +16,7 @@ static SCREEN_HEIGHT: u32 = 720;
static REFRESH_RATE: u32 = 50;
// TODO: Make this configurable
static UNDO_TIME: u32 = 250;
static UNDO_TIME: u32 = 500;
static UNDO_TIME_COUNT: u32 = (REFRESH_RATE as f32 * (UNDO_TIME as f32 / 1000.0)) as u32;
struct ModifierKeys {
@ -25,16 +25,11 @@ struct ModifierKeys {
shift: bool,
}
// struct EditorGraphics {
// canvas: Canvas<Window>,
// glyph_atlas: GlyphAtlas,
// }
pub fn main() -> Result<(), String> {
// Initialize clipboard
let mut modifier_keys = ModifierKeys {alt: false, ctrl: false, shift: false};
let mut clipboard_context: ClipboardContext = ClipboardProvider::new().unwrap();
// Initialize SDL2, window, and canvas
let sdl_context = sdl2::init()?;
let video_subsys = sdl_context.video()?;
@ -48,38 +43,83 @@ pub fn main() -> Result<(), String> {
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?;
// Initalize buffer
let mut window_size = canvas.output_size()?;
let mut buffer = String::new();
let mut cursor_position = 0;
let mut selection_anchor: Option<usize> = None;
// 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 = ModifierKeys {alt: false, ctrl: false, shift: false};
let mut cursor_position = 0;
let mut selection_anchor: Option<usize> = None;
let pad_offset = Point::new(10, 10);
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();
// 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 info
let status = text.len().to_formatted_string(&Locale::en);
let status_position = Point::new(
pad_offset.x,
window_size.1 as i32 - glyph_metrics.height as i32 * 2
);
canvas.set_draw_color(Color::RGB(16, 64, 64));
canvas.fill_rect(Rect::new(0,
status_position.y - 5,
window_size.0,
glyph_metrics.height as u32 + 10
))?;
canvas.set_draw_color(Color::RGB(127, 240, 240));
let status_bar = editor_render::draw_text(
&glyph_atlas,
&glyph_metrics,
&status,
status_position
);
canvas.draw_points(&status_bar[..])?;
// 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();
// 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)?
Ok(())
};
}
draw!();
draw(window_size, "", cursor_position)?;
'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!();
if let WindowEvent::Resized(w, h) = win_event {
window_size = (w as u32, h as u32);
draw(window_size, &buffer, cursor_position)?
}
}
// ESC or SIGKILL
@ -132,8 +172,7 @@ pub fn main() -> Result<(), String> {
selection_anchor = None;
buffer.remove(cursor_position);
draw!();
draw(window_size, &buffer, cursor_position)?
}
},
@ -145,8 +184,7 @@ pub fn main() -> Result<(), String> {
let key = '\n';
buffer.insert(cursor_position, key);
cursor_position += 1;
draw!();
draw(window_size, &buffer, cursor_position)?
},
// HOME key
@ -154,8 +192,7 @@ pub fn main() -> Result<(), String> {
selection_anchor = None;
cursor_position = 0;
draw!();
draw(window_size, &buffer, cursor_position)?
},
// END key
@ -163,8 +200,7 @@ pub fn main() -> Result<(), String> {
selection_anchor = None;
cursor_position = buffer.len();
draw!();
draw(window_size, &buffer, cursor_position)?
},
// Left/Back arrow
@ -173,8 +209,7 @@ pub fn main() -> Result<(), String> {
cursor_position = usize::checked_sub(cursor_position, 1)
.unwrap_or(0);
draw!();
draw(window_size, &buffer, cursor_position)?
},
// Right/Forward arrow
@ -182,8 +217,7 @@ pub fn main() -> Result<(), String> {
selection_anchor = None;
cursor_position = (cursor_position + 1).min(buffer.len());
draw!();
draw(window_size, &buffer, cursor_position)?
},
// BACKSPACE key
@ -195,8 +229,7 @@ pub fn main() -> Result<(), String> {
buffer.remove(cursor_position - 1);
cursor_position -= 1;
draw!();
draw(window_size, &buffer, cursor_position)?
}
},
@ -207,15 +240,6 @@ pub fn main() -> Result<(), String> {
// 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;
@ -223,20 +247,15 @@ pub fn main() -> Result<(), String> {
buffer = last_undo.0;
cursor_position = last_undo.1;
draw!()
draw(window_size, &buffer, cursor_position)?
}
},
// 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() {
@ -244,8 +263,9 @@ pub fn main() -> Result<(), String> {
cursor_position += 1;
undo_timer = UNDO_TIME_COUNT;
}
draw!()
draw(window_size, &buffer, cursor_position)?
},
// BACKSPACE key
@ -267,14 +287,13 @@ pub fn main() -> Result<(), String> {
buffer.remove(cursor_position - 1);
cursor_position -= 1;
draw!()
draw(window_size, &buffer, cursor_position)?
}
},
_ => (),
}
},
// SHIFT + CTRL down
(true, true, false) => {
match keycode {
Some(Keycode::Z) => {
@ -284,7 +303,7 @@ pub fn main() -> Result<(), String> {
buffer = last_redo.0;
cursor_position = last_redo.1;
draw!();
draw(window_size, &buffer, cursor_position)?
}
},
@ -299,16 +318,15 @@ pub fn main() -> Result<(), String> {
}
},
// 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!();
draw(window_size, &buffer, cursor_position)?;
},
_ => {}
@ -319,18 +337,20 @@ pub fn main() -> Result<(), String> {
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
// 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));
::std::thread::sleep(std::time::Duration::new(0, 1_000_000_000 / REFRESH_RATE));
}
format!("{selection_anchor:?}");
println!("{buffer}");
Ok(())
}

Loading…
Cancel
Save