|
|
|
@ -11,7 +11,7 @@ use sdl2::{ |
|
|
|
video::Window, |
|
|
|
video::Window, |
|
|
|
}; |
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
use crate::file; |
|
|
|
use std::{fs::File, path::Path, io::Read}; |
|
|
|
|
|
|
|
|
|
|
|
type Glyph = Vec<Point>; |
|
|
|
type Glyph = Vec<Point>; |
|
|
|
|
|
|
|
|
|
|
|
@ -31,68 +31,28 @@ pub struct GlyphAtlas { |
|
|
|
metrics: GlyphMetrics, |
|
|
|
metrics: GlyphMetrics, |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
struct ColorRGB { |
|
|
|
/// Reads the file and turns it into a Vec of u8s
|
|
|
|
red: u8, |
|
|
|
fn read_file(file_name: String) -> Vec<u8> { |
|
|
|
green: u8, |
|
|
|
let path = Path::new(&file_name); |
|
|
|
blue: u8, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl ColorRGB { |
|
|
|
if !path.exists() { |
|
|
|
fn new(red: u8, green: u8, blue: u8) -> ColorRGB { |
|
|
|
return String::from("Not Found!").into(); |
|
|
|
ColorRGB { red, green, blue } |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#[allow(dead_code)] |
|
|
|
let mut file_content = Vec::new(); |
|
|
|
enum Colors { |
|
|
|
let mut file = File::open(&file_name).expect("Unable to open file"); |
|
|
|
Background, |
|
|
|
file.read_to_end(&mut file_content).expect("Unable to read"); |
|
|
|
Foreground, |
|
|
|
|
|
|
|
Error, |
|
|
|
|
|
|
|
Warning, |
|
|
|
|
|
|
|
FindBg, |
|
|
|
|
|
|
|
StdFunction, |
|
|
|
|
|
|
|
Comment, |
|
|
|
|
|
|
|
Keyword, |
|
|
|
|
|
|
|
Number, |
|
|
|
|
|
|
|
Operator, |
|
|
|
|
|
|
|
Preprocessor, |
|
|
|
|
|
|
|
SelectionBg, |
|
|
|
|
|
|
|
SelectionFg, |
|
|
|
|
|
|
|
String, |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
impl Colors { |
|
|
|
file_content |
|
|
|
fn color(&self) -> ColorRGB { |
|
|
|
|
|
|
|
match self { |
|
|
|
|
|
|
|
Colors::Background => ColorRGB::new(32, 32, 32), |
|
|
|
|
|
|
|
Colors::Foreground => ColorRGB::new(255, 255, 255), |
|
|
|
|
|
|
|
Colors::Error => ColorRGB::new(255, 0, 0), |
|
|
|
|
|
|
|
Colors::Warning => ColorRGB::new(255, 170, 0), |
|
|
|
|
|
|
|
Colors::FindBg => ColorRGB::new(246, 185, 63), |
|
|
|
|
|
|
|
Colors::StdFunction => ColorRGB::new(170, 255, 255), |
|
|
|
|
|
|
|
Colors::Comment => ColorRGB::new(0, 255, 0), |
|
|
|
|
|
|
|
Colors::Keyword => ColorRGB::new(0, 170, 255), |
|
|
|
|
|
|
|
Colors::Number => ColorRGB::new(85, 255, 255), |
|
|
|
|
|
|
|
Colors::Operator => ColorRGB::new(255, 85, 0), |
|
|
|
|
|
|
|
Colors::Preprocessor => ColorRGB::new(127, 0, 0), |
|
|
|
|
|
|
|
Colors::SelectionBg => ColorRGB::new(110, 161, 241), |
|
|
|
|
|
|
|
Colors::SelectionFg => ColorRGB::new(255, 255, 255), |
|
|
|
|
|
|
|
Colors::String => ColorRGB::new(255, 85, 255), |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn generate_glyph_data() -> Result<GlyphAtlas, String> { |
|
|
|
pub fn generate_glyph_data() -> GlyphAtlas { |
|
|
|
// Retrieve font data from file
|
|
|
|
// Retrieve font data from file
|
|
|
|
// TODO: Get crate path instead of working directory path
|
|
|
|
|
|
|
|
let file_path = String::from("./fonts/Terminus14x8.data"); |
|
|
|
let file_path = String::from("./fonts/Terminus14x8.data"); |
|
|
|
let contents = file::read_file(file_path)?; |
|
|
|
let contents = read_file(file_path); |
|
|
|
|
|
|
|
|
|
|
|
// Get glyph metrics
|
|
|
|
// Get glyph metrics
|
|
|
|
let glyph_metrics = GlyphMetrics { |
|
|
|
let glyph_metrics = GlyphMetrics { width: 8, height: 16 }; |
|
|
|
width: 8, |
|
|
|
|
|
|
|
height: 16, |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
let glyph_width = glyph_metrics.width; |
|
|
|
let glyph_width = glyph_metrics.width; |
|
|
|
|
|
|
|
|
|
|
|
// Get width of image for proper positioning of pixels
|
|
|
|
// Get width of image for proper positioning of pixels
|
|
|
|
@ -100,9 +60,9 @@ pub fn generate_glyph_data() -> Result<GlyphAtlas, String> { |
|
|
|
let width_right_byte = contents[1]; |
|
|
|
let width_right_byte = contents[1]; |
|
|
|
let width_bytes = [width_left_byte, width_right_byte]; |
|
|
|
let width_bytes = [width_left_byte, width_right_byte]; |
|
|
|
let width = u16::from_be_bytes(width_bytes); |
|
|
|
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 pruned_glyph_table = &contents[width as usize + 2..]; |
|
|
|
let gtable_prune = &contents[width as usize + 2 ..]; |
|
|
|
|
|
|
|
|
|
|
|
// Generate the glyph atlas
|
|
|
|
// Generate the glyph atlas
|
|
|
|
let mut glyph_atlas: Vec<Glyph> = vec![]; |
|
|
|
let mut glyph_atlas: Vec<Glyph> = vec![]; |
|
|
|
@ -118,38 +78,30 @@ pub fn generate_glyph_data() -> Result<GlyphAtlas, String> { |
|
|
|
let offset = glyph * glyph_width as u16; |
|
|
|
let offset = glyph * glyph_width as u16; |
|
|
|
let position = (x + multiplier + offset) as usize; |
|
|
|
let position = (x + multiplier + offset) as usize; |
|
|
|
|
|
|
|
|
|
|
|
if pruned_glyph_table[position] == 1 { |
|
|
|
if gtable_prune[position] == 1 { |
|
|
|
new_glyph.push(Point::new(x as i32, y as i32)); |
|
|
|
new_glyph.push(Point::new(x as i32, y as i32)); |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
glyph_atlas.push(new_glyph); |
|
|
|
glyph_atlas.push(new_glyph); |
|
|
|
} |
|
|
|
} |
|
|
|
Ok(GlyphAtlas { |
|
|
|
GlyphAtlas { glyphs: glyph_atlas, metrics: glyph_metrics } |
|
|
|
glyphs: glyph_atlas, |
|
|
|
|
|
|
|
metrics: glyph_metrics, |
|
|
|
|
|
|
|
}) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Method for generating points to render, using given string
|
|
|
|
/// Method for generating points to render, using given string
|
|
|
|
fn draw_text( |
|
|
|
fn draw_text(glyph_atlas: &GlyphAtlas, content: &str, offset: Point) -> Vec<Point> { |
|
|
|
glyph_atlas: &GlyphAtlas, |
|
|
|
|
|
|
|
window_size: (u32, u32), |
|
|
|
|
|
|
|
content: &str, |
|
|
|
|
|
|
|
offset: Point, |
|
|
|
|
|
|
|
) -> Vec<Point> { |
|
|
|
|
|
|
|
let mut points: Vec<Point> = vec![]; |
|
|
|
let mut points: Vec<Point> = vec![]; |
|
|
|
|
|
|
|
|
|
|
|
let glyph_width = glyph_atlas.metrics.width; |
|
|
|
let glyph_width = glyph_atlas.metrics.width; |
|
|
|
let glyph_height = glyph_atlas.metrics.height; |
|
|
|
let glyph_height = glyph_atlas.metrics.height; |
|
|
|
|
|
|
|
|
|
|
|
let content_lines = content.split('\n'); |
|
|
|
let lines = content.split('\n'); |
|
|
|
for (y, line) in content_lines.enumerate() { |
|
|
|
for (y, chars) in lines.enumerate() { |
|
|
|
for (x, character) in line.chars().enumerate() { |
|
|
|
for (x, chara) in chars.chars().enumerate() { |
|
|
|
let index; |
|
|
|
let index; |
|
|
|
if character.is_lowercase() { |
|
|
|
if chara.is_lowercase() { |
|
|
|
index = character.to_ascii_lowercase() as usize; |
|
|
|
index = chara.to_ascii_lowercase() as usize; |
|
|
|
} else { |
|
|
|
} else { |
|
|
|
index = character.to_ascii_uppercase() as usize; |
|
|
|
index = chara.to_ascii_uppercase() as usize; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
for pixel in &glyph_atlas.glyphs[index - 32] { |
|
|
|
for pixel in &glyph_atlas.glyphs[index - 32] { |
|
|
|
@ -158,28 +110,16 @@ fn draw_text( |
|
|
|
|
|
|
|
|
|
|
|
let positioned_pixel = Point::new( |
|
|
|
let positioned_pixel = Point::new( |
|
|
|
pixel.x + x_glyph as i32 + offset.x, |
|
|
|
pixel.x + x_glyph as i32 + offset.x, |
|
|
|
pixel.y + y_glyph as i32 + offset.y, |
|
|
|
pixel.y + y_glyph as i32 + offset.y |
|
|
|
); |
|
|
|
); |
|
|
|
points.push(positioned_pixel); |
|
|
|
points.push(positioned_pixel); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
if x >= (window_size.0 as usize / glyph_width) - 3 { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
if y >= (window_size.1 as usize / glyph_height) - 3 { |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
points |
|
|
|
points |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
pub fn draw_cursor( |
|
|
|
pub fn draw_cursor(glyph_atlas: &GlyphAtlas, mut cursor_position: usize, content: &str, offset: Point) -> (Point, Point) { |
|
|
|
glyph_atlas: &GlyphAtlas, |
|
|
|
|
|
|
|
mut cursor_position: usize, |
|
|
|
|
|
|
|
content: &str, |
|
|
|
|
|
|
|
offset: Point, |
|
|
|
|
|
|
|
) -> (Point, Point) { |
|
|
|
|
|
|
|
let glyph_width = glyph_atlas.metrics.width; |
|
|
|
let glyph_width = glyph_atlas.metrics.width; |
|
|
|
let glyph_height = glyph_atlas.metrics.height; |
|
|
|
let glyph_height = glyph_atlas.metrics.height; |
|
|
|
|
|
|
|
|
|
|
|
@ -187,68 +127,60 @@ pub fn draw_cursor( |
|
|
|
let mut y = 0; |
|
|
|
let mut y = 0; |
|
|
|
if cursor_position > 0 { |
|
|
|
if cursor_position > 0 { |
|
|
|
cursor_position = cursor_position.checked_sub(1).unwrap_or(0); |
|
|
|
cursor_position = cursor_position.checked_sub(1).unwrap_or(0); |
|
|
|
for (idx, character) in content.chars().enumerate() { |
|
|
|
for (idx, chara) in content.chars().enumerate() { |
|
|
|
x += 1; |
|
|
|
x += 1; |
|
|
|
if character == '\n' { |
|
|
|
if chara == '\n' { |
|
|
|
x = 0; |
|
|
|
x = 0; |
|
|
|
y += 1; |
|
|
|
y += 1; |
|
|
|
} |
|
|
|
} |
|
|
|
if idx == cursor_position { |
|
|
|
if idx == cursor_position { |
|
|
|
let point_a = Point::new( |
|
|
|
let point_a = Point::new((x * glyph_width) as i32 + offset.x, |
|
|
|
(x * glyph_width) as i32 + offset.x, |
|
|
|
(y * glyph_height) as i32 + offset.y |
|
|
|
(y * glyph_height) as i32 + offset.y, |
|
|
|
); |
|
|
|
|
|
|
|
let point_b = Point::new(point_a.x, |
|
|
|
|
|
|
|
point_a.y + glyph_height as i32 |
|
|
|
); |
|
|
|
); |
|
|
|
let point_b = Point::new(point_a.x, point_a.y + glyph_height as i32); |
|
|
|
return (point_a, point_b) |
|
|
|
return (point_a, point_b); |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
( |
|
|
|
(Point::new(offset.x, offset.y), Point::new(offset.x, offset.y + glyph_height as i32)) |
|
|
|
Point::new(offset.x, offset.y), |
|
|
|
|
|
|
|
Point::new(offset.x, offset.y + glyph_height as i32), |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/// Draw all contents to the window
|
|
|
|
/// Draw all contents to the window
|
|
|
|
pub fn draw_everything( |
|
|
|
pub fn draw_everything(canvas: &mut Canvas<Window>, |
|
|
|
canvas: &mut Canvas<Window>, |
|
|
|
|
|
|
|
glyph_atlas: &GlyphAtlas, |
|
|
|
glyph_atlas: &GlyphAtlas, |
|
|
|
buffer: &str, |
|
|
|
buffer: &str, |
|
|
|
cursor_position: usize, |
|
|
|
cursor_position: usize) -> Result<(), String> { |
|
|
|
) -> Result<(), String> { |
|
|
|
|
|
|
|
// Quick initialization
|
|
|
|
// Quick initialization
|
|
|
|
let window_size = canvas.output_size()?; |
|
|
|
let window_size = canvas.output_size()?; |
|
|
|
let text_offset = Point::new(10, 10); |
|
|
|
let text_offset = Point::new(10, 10); |
|
|
|
|
|
|
|
|
|
|
|
let bg_color = Colors::Background.color(); |
|
|
|
|
|
|
|
let fg_color = Colors::Foreground.color(); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// Draw background
|
|
|
|
// Draw background
|
|
|
|
canvas.set_draw_color(Color::RGB(bg_color.red, bg_color.green, bg_color.blue)); |
|
|
|
canvas.set_draw_color(Color::RGB(32, 32, 32)); |
|
|
|
canvas.clear(); |
|
|
|
canvas.clear(); |
|
|
|
|
|
|
|
|
|
|
|
// Draw text
|
|
|
|
// Draw text
|
|
|
|
canvas.set_draw_color(Color::RGB(fg_color.red, fg_color.green, fg_color.blue)); |
|
|
|
canvas.set_draw_color(Color::RGB(240, 240, 240)); |
|
|
|
let fb_text = draw_text(&glyph_atlas, window_size, buffer, text_offset); |
|
|
|
let fb_text = draw_text(&glyph_atlas, buffer, text_offset); |
|
|
|
canvas.draw_points(&fb_text[..])?; |
|
|
|
canvas.draw_points(&fb_text[..])?; |
|
|
|
|
|
|
|
|
|
|
|
// Draw info
|
|
|
|
// Draw info
|
|
|
|
let status = buffer.len().to_formatted_string(&Locale::en); |
|
|
|
let status = buffer.len().to_formatted_string(&Locale::en); |
|
|
|
let status_position = Point::new( |
|
|
|
let status_position = Point::new( |
|
|
|
text_offset.x, |
|
|
|
text_offset.x, |
|
|
|
window_size.1 as i32 - glyph_atlas.metrics.height as i32 * 2, |
|
|
|
window_size.1 as i32 - glyph_atlas.metrics.height as i32 * 2 |
|
|
|
); |
|
|
|
); |
|
|
|
|
|
|
|
|
|
|
|
canvas.set_draw_color(Color::RGB(16, 64, 64)); |
|
|
|
canvas.set_draw_color(Color::RGB(16, 64, 64)); |
|
|
|
canvas.fill_rect(Rect::new( |
|
|
|
canvas.fill_rect(Rect::new(0, |
|
|
|
0, |
|
|
|
|
|
|
|
status_position.y - 5, |
|
|
|
status_position.y - 5, |
|
|
|
window_size.0, |
|
|
|
window_size.0, |
|
|
|
glyph_atlas.metrics.height as u32 + 10, |
|
|
|
glyph_atlas.metrics.height as u32 + 10 |
|
|
|
))?; |
|
|
|
))?; |
|
|
|
|
|
|
|
|
|
|
|
canvas.set_draw_color(Color::RGB(127, 240, 240)); |
|
|
|
canvas.set_draw_color(Color::RGB(127, 240, 240)); |
|
|
|
let status_bar = draw_text(&glyph_atlas, window_size, &status, status_position); |
|
|
|
let status_bar = draw_text(&glyph_atlas, &status, status_position); |
|
|
|
canvas.draw_points(&status_bar[..])?; |
|
|
|
canvas.draw_points(&status_bar[..])?; |
|
|
|
|
|
|
|
|
|
|
|
// Draw cursor
|
|
|
|
// Draw cursor
|
|
|
|
|