x
This commit is contained in:
commit
399b0b7144
3
.gitignore
vendored
Normal file
3
.gitignore
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
/target
|
||||
**/*.rs.bk
|
||||
.idea
|
288
Cargo.lock
generated
Normal file
288
Cargo.lock
generated
Normal file
@ -0,0 +1,288 @@
|
||||
[[package]]
|
||||
name = "bit-set"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "bit-vec"
|
||||
version = "0.4.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "0.7.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "bitflags"
|
||||
version = "1.0.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "c_vec"
|
||||
version = "1.3.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cfg-if"
|
||||
version = "0.1.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "cloudabi"
|
||||
version = "0.0.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "editor"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"plex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "fuchsia-zircon-sys"
|
||||
version = "0.3.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lalr"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "lazy_static"
|
||||
version = "0.2.11"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "libc"
|
||||
version = "0.2.44"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "num"
|
||||
version = "0.1.42"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-integer"
|
||||
version = "0.1.39"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-iter"
|
||||
version = "0.1.37"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "num-traits"
|
||||
version = "0.2.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "plex"
|
||||
version = "0.2.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"lalr 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"redfa 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "proc-macro2"
|
||||
version = "0.4.24"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "quote"
|
||||
version = "0.6.10"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.3.22"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand"
|
||||
version = "0.5.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.2.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rand_core"
|
||||
version = "0.3.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "redfa"
|
||||
version = "0.0.2"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdl2"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"c_vec 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "sdl2-sys"
|
||||
version = "0.31.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "syn"
|
||||
version = "0.14.9"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicode-xid"
|
||||
version = "0.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "vec_map"
|
||||
version = "0.6.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi"
|
||||
version = "0.3.6"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
dependencies = [
|
||||
"winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
"winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "winapi-i686-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[[package]]
|
||||
name = "winapi-x86_64-pc-windows-gnu"
|
||||
version = "0.4.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
|
||||
[metadata]
|
||||
"checksum bit-set 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d9bf6104718e80d7b26a68fdbacff3481cfc05df670821affc7e9cbc1884400c"
|
||||
"checksum bit-vec 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "02b4ff8b16e6076c3e14220b39fbc1fabb6737522281a388998046859400895f"
|
||||
"checksum bitflags 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aad18937a628ec6abcd26d1489012cc0e18c21798210f491af69ded9b881106d"
|
||||
"checksum bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "228047a76f468627ca71776ecdebd732a3423081fcf5125585bcd7c49886ce12"
|
||||
"checksum c_vec 1.3.2 (registry+https://github.com/rust-lang/crates.io-index)" = "6c32b15e95ce816aaf991a41420854e6ba772a2679a9296d906eab1114f1b4e9"
|
||||
"checksum cfg-if 0.1.6 (registry+https://github.com/rust-lang/crates.io-index)" = "082bb9b28e00d3c9d39cc03e64ce4cea0f1bb9b3fde493f0cbc008472d22bdf4"
|
||||
"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f"
|
||||
"checksum fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "2e9763c69ebaae630ba35f74888db465e49e259ba1bc0eda7d06f4a067615d82"
|
||||
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
|
||||
"checksum lalr 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "106d7548f95adbe3019b4fc4954554d7b72535867aa9ce326d2f766b68958de7"
|
||||
"checksum lazy_static 0.2.11 (registry+https://github.com/rust-lang/crates.io-index)" = "76f033c7ad61445c5b347c7382dd1237847eb1bce590fe50365dcb33d546be73"
|
||||
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
|
||||
"checksum num 0.1.42 (registry+https://github.com/rust-lang/crates.io-index)" = "4703ad64153382334aa8db57c637364c322d3372e097840c72000dabdcf6156e"
|
||||
"checksum num-integer 0.1.39 (registry+https://github.com/rust-lang/crates.io-index)" = "e83d528d2677f0518c570baf2b7abdcf0cd2d248860b68507bdcb3e91d4c0cea"
|
||||
"checksum num-iter 0.1.37 (registry+https://github.com/rust-lang/crates.io-index)" = "af3fdbbc3291a5464dc57b03860ec37ca6bf915ed6ee385e7c6c052c422b2124"
|
||||
"checksum num-traits 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "0b3a5d7cc97d6d30d8b9bc8fa19bf45349ffe46241e8816f50f62f6d6aaabee1"
|
||||
"checksum plex 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "59d79bd74b3d0be2619e58217e8b2b96372e3feca8426e5c560623205d70c146"
|
||||
"checksum proc-macro2 0.4.24 (registry+https://github.com/rust-lang/crates.io-index)" = "77619697826f31a02ae974457af0b29b723e5619e113e9397b8b82c6bd253f09"
|
||||
"checksum quote 0.6.10 (registry+https://github.com/rust-lang/crates.io-index)" = "53fa22a1994bd0f9372d7a816207d8a2677ad0325b073f5c5332760f0fb62b5c"
|
||||
"checksum rand 0.3.22 (registry+https://github.com/rust-lang/crates.io-index)" = "15a732abf9d20f0ad8eeb6f909bf6868722d9a06e1e50802b6a70351f40b4eb1"
|
||||
"checksum rand 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8356f47b32624fef5b3301c1be97e5944ecdd595409cc5da11d05f211db6cfbd"
|
||||
"checksum rand 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "e464cd887e869cddcae8792a4ee31d23c7edd516700695608f5b98c67ee0131c"
|
||||
"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372"
|
||||
"checksum rand_core 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "0905b6b7079ec73b314d4c748701f6931eb79fd97c668caa3f1899b22b32c6db"
|
||||
"checksum redfa 0.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "29cc2771cc9f5fb0061cdedc05a37170254694dffec6b89920a6e767f08c4220"
|
||||
"checksum sdl2 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a74c2a98a354b20713b90cce70aef9e927e46110d1bc4ef728fd74e0d53eba60"
|
||||
"checksum sdl2-sys 0.31.0 (registry+https://github.com/rust-lang/crates.io-index)" = "5c543ce8a6e33a30cb909612eeeb22e693848211a84558d5a00bb11e791b7ab7"
|
||||
"checksum syn 0.14.9 (registry+https://github.com/rust-lang/crates.io-index)" = "261ae9ecaa397c42b960649561949d69311f08eeaea86a65696e6e46517cf741"
|
||||
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
|
||||
"checksum vec_map 0.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cac5efe5cb0fa14ec2f84f83c701c562ee63f6dcc680861b21d65c682adfb05f"
|
||||
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
|
||||
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
|
||||
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
|
13
Cargo.toml
Normal file
13
Cargo.toml
Normal file
@ -0,0 +1,13 @@
|
||||
[package]
|
||||
name = "editor"
|
||||
version = "0.1.0"
|
||||
authors = ["Adrian Wozniak <adrian.wozniak@ita-prog.pl>"]
|
||||
edition = "2018"
|
||||
|
||||
[dependencies]
|
||||
rand = "0.5"
|
||||
plex = "*"
|
||||
|
||||
[dependencies.sdl2]
|
||||
version = "0.31.0"
|
||||
features = ["gfx", "image", "mixer", "ttf"]
|
BIN
assets/fonts/Beyond Wonderland.ttf
Normal file
BIN
assets/fonts/Beyond Wonderland.ttf
Normal file
Binary file not shown.
BIN
assets/fonts/hinted-ElaineSans-Medium.ttf
Normal file
BIN
assets/fonts/hinted-ElaineSans-Medium.ttf
Normal file
Binary file not shown.
44
src/app/app_state.rs
Normal file
44
src/app/app_state.rs
Normal file
@ -0,0 +1,44 @@
|
||||
use std::rc::Rc;
|
||||
use std::sync::Arc;
|
||||
use std::boxed::Box;
|
||||
use crate::app::{UpdateResult, WindowCanvas};
|
||||
use crate::file::*;
|
||||
use crate::renderer::Renderer;
|
||||
use crate::file::editor_file::EditorFile;
|
||||
|
||||
pub struct AppState<'a> {
|
||||
pub files: Vec<EditorFile<'a>>,
|
||||
pub current_file: i16,
|
||||
}
|
||||
|
||||
impl<'a> AppState<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
files: vec![],
|
||||
current_file: -1,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_file(&mut self, file_path: String, renderer: &mut Renderer) {
|
||||
use std::fs::read_to_string;
|
||||
if let Ok(buffer) = read_to_string(&file_path) {
|
||||
println!("read: {}\n{}", file_path, buffer);
|
||||
let file = EditorFile::new(file_path.clone(), buffer, renderer);
|
||||
self.current_file = self.files.len() as i16;
|
||||
self.files.push(file);
|
||||
};
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ticks: i32) -> UpdateResult {
|
||||
if let Some(ref mut file) = self.files.get(self.current_file as usize) {
|
||||
file.update(ticks);
|
||||
}
|
||||
UpdateResult::NoOp
|
||||
}
|
||||
|
||||
pub fn render(&mut self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
|
||||
if let Some(ref mut file) = self.files.get(self.current_file as usize) {
|
||||
file.render(canvas, renderer);
|
||||
}
|
||||
}
|
||||
}
|
25
src/app/config.rs
Normal file
25
src/app/config.rs
Normal file
@ -0,0 +1,25 @@
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct EditorConfig {
|
||||
pub character_size: u16,
|
||||
pub font_path: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Config {
|
||||
pub width: u32,
|
||||
pub height: u32,
|
||||
pub editor_config: EditorConfig,
|
||||
}
|
||||
|
||||
impl Config {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
width: 1024,
|
||||
height: 860,
|
||||
editor_config: EditorConfig {
|
||||
character_size: 24,
|
||||
font_path: "./assets/fonts/hinted-ElaineSans-Medium.ttf".to_string(),
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
137
src/app/mod.rs
Normal file
137
src/app/mod.rs
Normal file
@ -0,0 +1,137 @@
|
||||
pub mod app_state;
|
||||
pub mod config;
|
||||
|
||||
use sdl2::event::Event;
|
||||
use sdl2::hint;
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::render::Canvas;
|
||||
use sdl2::video::Window;
|
||||
use sdl2::EventPump;
|
||||
use sdl2::{Sdl, TimerSubsystem};
|
||||
|
||||
use std::thread::sleep;
|
||||
use std::time::Duration;
|
||||
|
||||
pub type WindowCanvas = Canvas<Window>;
|
||||
|
||||
use crate::app::app_state::AppState;
|
||||
use crate::app::config::Config;
|
||||
use crate::renderer::Renderer;
|
||||
|
||||
#[derive(PartialEq, Clone, Debug)]
|
||||
pub enum UpdateResult {
|
||||
NoOp,
|
||||
Stop,
|
||||
RefreshPositions,
|
||||
}
|
||||
|
||||
pub enum Task {
|
||||
OpenFile { file_path: String },
|
||||
}
|
||||
|
||||
pub struct Application {
|
||||
config: Config,
|
||||
sdl_context: Sdl,
|
||||
canvas: WindowCanvas,
|
||||
tasks: Vec<Task>,
|
||||
}
|
||||
|
||||
impl Application {
|
||||
pub fn new() -> Self {
|
||||
let config = Config::new();
|
||||
let sdl_context = sdl2::init().unwrap();
|
||||
hint::set("SDL_GL_MULTISAMPLEBUFFERS", "1");
|
||||
hint::set("SDL_GL_MULTISAMPLESAMPLES", "8");
|
||||
hint::set("SDL_GL_ACCELERATED_VISUAL", "1");
|
||||
hint::set("SDL_HINT_RENDER_SCALE_QUALITY", "2");
|
||||
hint::set("SDL_HINT_VIDEO_ALLOW_SCREENSAVER", "1");
|
||||
let video_subsystem = sdl_context.video().unwrap();
|
||||
let window = video_subsystem
|
||||
.window("Editor", config.width, config.height)
|
||||
.position_centered()
|
||||
.opengl()
|
||||
.build()
|
||||
.unwrap();
|
||||
|
||||
let canvas = window.into_canvas().accelerated().build().unwrap();
|
||||
|
||||
Self {
|
||||
config,
|
||||
sdl_context,
|
||||
canvas,
|
||||
tasks: vec![],
|
||||
}
|
||||
}
|
||||
|
||||
pub fn init(&mut self) {
|
||||
self.clear();
|
||||
}
|
||||
|
||||
pub fn run(&mut self) {
|
||||
let mut timer: TimerSubsystem = self.sdl_context.timer().unwrap();
|
||||
let mut event_pump = self.sdl_context.event_pump().unwrap();
|
||||
let font_context = sdl2::ttf::init().unwrap();
|
||||
let sleep_time = Duration::new(0, 1_000_000_000u32 / 60);
|
||||
let mut app_state = AppState::new();
|
||||
let mut renderer = Renderer::new(
|
||||
self.config.clone(),
|
||||
&font_context,
|
||||
self.canvas.texture_creator()
|
||||
);
|
||||
|
||||
'running: loop {
|
||||
match self.handle_events(&mut event_pump) {
|
||||
UpdateResult::Stop => break 'running,
|
||||
UpdateResult::RefreshPositions => (),
|
||||
UpdateResult::NoOp => (),
|
||||
}
|
||||
for task in self.tasks.iter() {
|
||||
match task {
|
||||
Task::OpenFile { file_path } => {
|
||||
use crate::file::editor_file::*;
|
||||
app_state.open_file(file_path.clone(), &mut renderer);
|
||||
// use std::fs::read_to_string;
|
||||
// if let Ok(buffer) = read_to_string(&file_path) {
|
||||
// println!("read: {}\n{}", file_path, buffer);
|
||||
// let file = EditorFile::new(file_path.clone(), buffer, &mut renderer);
|
||||
// app_state.current_file = app_state.files.len() as i16;
|
||||
// app_state.files.push(file);
|
||||
// }
|
||||
},
|
||||
}
|
||||
}
|
||||
self.tasks.clear();
|
||||
|
||||
self.clear();
|
||||
|
||||
app_state.update(timer.ticks() as i32);
|
||||
app_state.render(&mut self.canvas, &mut renderer);
|
||||
|
||||
self.present();
|
||||
sleep(sleep_time);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn open_file(&mut self, file_path: String) {
|
||||
self.tasks.push(Task::OpenFile { file_path });
|
||||
}
|
||||
|
||||
fn present(&mut self) {
|
||||
self.canvas.present();
|
||||
}
|
||||
|
||||
fn clear(&mut self) {
|
||||
self.canvas.set_draw_color(Color::RGB(255, 255, 255));
|
||||
self.canvas.clear();
|
||||
}
|
||||
|
||||
fn handle_events(&mut self, event_pump: &mut EventPump) -> UpdateResult {
|
||||
for event in event_pump.poll_iter() {
|
||||
match event {
|
||||
Event::Quit { .. } => return UpdateResult::Stop,
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
UpdateResult::NoOp
|
||||
}
|
||||
}
|
19
src/file/caret.rs
Normal file
19
src/file/caret.rs
Normal file
@ -0,0 +1,19 @@
|
||||
pub struct Caret<'a> {
|
||||
character: char,
|
||||
source: Rect,
|
||||
dest: Rect,
|
||||
visible: bool,
|
||||
texture: Option<Rc<Texture<'a>>>,
|
||||
}
|
||||
|
||||
impl<'a> Caret<'a> {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
character: '│',
|
||||
source: Rect::new(0, 0, 0, 0),
|
||||
dest: Rect::new(0, 0, 0, 0),
|
||||
visible: true,
|
||||
texture: None,
|
||||
}
|
||||
}
|
||||
}
|
45
src/file/editor_file.rs
Normal file
45
src/file/editor_file.rs
Normal file
@ -0,0 +1,45 @@
|
||||
use sdl2::rect::Rect;
|
||||
use crate::file::editor_file_section::EditorFileSection;
|
||||
use crate::renderer::Renderer;
|
||||
use crate::app::UpdateResult;
|
||||
use crate::app::WindowCanvas;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EditorFile<'l> {
|
||||
pub path: String,
|
||||
pub sections: Vec<EditorFileSection<'l>>,
|
||||
}
|
||||
|
||||
impl<'l> EditorFile<'l> {
|
||||
pub fn new(path: String, buffer: String, renderer: &'l mut Renderer) -> Self {
|
||||
let section = EditorFileSection::new(buffer, renderer);
|
||||
let sections = vec![section];
|
||||
Self { path, sections }
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ticks: i32) -> UpdateResult {
|
||||
let mut result = UpdateResult::NoOp;
|
||||
for section in self.sections.iter_mut() {
|
||||
result = section.update(ticks);
|
||||
}
|
||||
|
||||
if result == UpdateResult::RefreshPositions {
|
||||
self.refresh_characters_position();
|
||||
result = UpdateResult::NoOp;
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn render(&self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
|
||||
for ref section in self.sections.iter() {
|
||||
section.render(canvas, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
fn refresh_characters_position(&mut self) {
|
||||
let mut current: Rect = Rect::new(0, 0, 0, 0);
|
||||
for section in self.sections.iter_mut() {
|
||||
section.update_positions(&mut current);
|
||||
}
|
||||
}
|
||||
}
|
51
src/file/editor_file_section.rs
Normal file
51
src/file/editor_file_section.rs
Normal file
@ -0,0 +1,51 @@
|
||||
use sdl2::rect::Rect;
|
||||
use crate::lexer::Language;
|
||||
use crate::app::UpdateResult;
|
||||
use crate::app::WindowCanvas;
|
||||
use crate::renderer::Renderer;
|
||||
use crate::file::editor_file_token::EditorFileToken;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EditorFileSection<'l> {
|
||||
pub tokens: Vec<EditorFileToken<'l>>,
|
||||
pub language: Language,
|
||||
}
|
||||
|
||||
impl<'l> EditorFileSection<'l> {
|
||||
pub fn new(buffer: String, renderer: &'l mut Renderer) -> Self {
|
||||
use crate::lexer;
|
||||
let lexer_tokens = lexer::parse(buffer.clone(), Language::PlainText);
|
||||
|
||||
let mut tokens: Vec<EditorFileToken> = vec![];
|
||||
for token_type in lexer_tokens {
|
||||
let token = EditorFileToken::new(
|
||||
renderer,
|
||||
token_type.get_start(),
|
||||
token_type.clone(),
|
||||
);
|
||||
tokens.push(token.clone());
|
||||
}
|
||||
let language = Language::PlainText;
|
||||
Self { tokens, language }
|
||||
}
|
||||
|
||||
pub fn update(&mut self, ticks: i32) -> UpdateResult {
|
||||
let mut result = UpdateResult::NoOp;
|
||||
for file_char in self.tokens.iter_mut() {
|
||||
result = file_char.update(ticks)
|
||||
}
|
||||
result
|
||||
}
|
||||
|
||||
pub fn render(&self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
|
||||
for ref character in self.tokens.iter() {
|
||||
character.render(canvas, renderer);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_positions(&mut self, current: &mut Rect) {
|
||||
for c in self.tokens.iter_mut() {
|
||||
c.update_position(current);
|
||||
}
|
||||
}
|
||||
}
|
117
src/file/editor_file_token.rs
Normal file
117
src/file/editor_file_token.rs
Normal file
@ -0,0 +1,117 @@
|
||||
use std::rc::Rc;
|
||||
use sdl2::rect::Rect;
|
||||
use sdl2::render::Texture;
|
||||
use sdl2::ttf::Font;
|
||||
use crate::lexer::TokenType;
|
||||
use crate::renderer::Renderer;
|
||||
use crate::renderer::managers::TextDetails;
|
||||
use crate::renderer::resolve_color::resolve_color;
|
||||
use crate::app::UpdateResult;
|
||||
use crate::app::WindowCanvas;
|
||||
use crate::renderer::managers::FontDetails;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct EditorFileToken<'l> {
|
||||
pos: usize,
|
||||
text: String,
|
||||
font_size: u16,
|
||||
source: Rect,
|
||||
dest: Rect,
|
||||
token_type: TokenType,
|
||||
texture: Option<Rc<Texture<'l>>>,
|
||||
}
|
||||
|
||||
impl<'l> EditorFileToken<'l> {
|
||||
pub fn new(renderer: &'l mut Renderer, pos: usize, token_type: TokenType) -> Self {
|
||||
let c = match token_type {
|
||||
_ if token_type.is_space() => "°".to_string(),
|
||||
_ if token_type.is_new_line() => "\n".to_string(),
|
||||
TokenType::Whitespace { .. } => "°".to_string(),
|
||||
_ => token_type.get_text(),
|
||||
};
|
||||
let details = TextDetails {
|
||||
text: c.clone(),
|
||||
font_details: FontDetails::new(
|
||||
renderer.config.editor_config.font_path.as_str(),
|
||||
renderer.config.editor_config.character_size.clone(),
|
||||
),
|
||||
color: resolve_color(&token_type),
|
||||
};
|
||||
Self {
|
||||
pos,
|
||||
text: c,
|
||||
font_size: 0,
|
||||
source: Rect::new(0, 0, 0, 0),
|
||||
dest: Rect::new(0, 0, 0, 0),
|
||||
token_type,
|
||||
texture: renderer.render_text(details).clone(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, _ticks: i32) -> UpdateResult {
|
||||
// if self.font_size != config.editor_config.character_size {
|
||||
// self.update_view(renderer);
|
||||
// return UpdateResult::RefreshPositions;
|
||||
// }
|
||||
UpdateResult::NoOp
|
||||
}
|
||||
|
||||
pub fn render(&self, canvas: &mut WindowCanvas, renderer: &mut Renderer) {
|
||||
if self.token_type.is_new_line() {
|
||||
return;
|
||||
}
|
||||
match &self.texture {
|
||||
Some(texture) => {
|
||||
renderer.render_texture(canvas, &texture, &self.source, &self.dest)
|
||||
}
|
||||
_ => {}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update_position(&mut self, current: &mut Rect) {
|
||||
match self.token_type {
|
||||
_ if self.token_type.is_new_line() => {
|
||||
current.set_x(0);
|
||||
current.set_y(
|
||||
(self.token_type.line() as usize * self.source.height() as usize) as i32,
|
||||
);
|
||||
}
|
||||
_ => {
|
||||
self.dest.set_x(current.x());
|
||||
self.dest.set_y(current.y());
|
||||
self.dest.set_width(self.source.width());
|
||||
self.dest.set_height(self.source.height());
|
||||
current.set_x(self.dest.x() + self.source.width() as i32);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn update_view(&mut self, renderer: &mut Renderer) {
|
||||
self.font_size = renderer.config.editor_config.character_size.clone();
|
||||
let font_details = FontDetails::new(
|
||||
renderer.config.editor_config.font_path.as_str(),
|
||||
self.font_size.clone(),
|
||||
);
|
||||
|
||||
if let Ok(font) = renderer.font_manager.load(&font_details) {
|
||||
if let Some((width, height)) = self.measure_text(&font) {
|
||||
self.source.set_width(width as u32);
|
||||
self.source.set_height(height as u32);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
fn measure_text(&self, font: &Rc<Font>) -> Option<(usize, usize)> {
|
||||
let mut w: usize = 0;
|
||||
let mut h: usize = 0;
|
||||
for c in self.text.chars() {
|
||||
if let Ok((width, height)) = font.size_of_char(c) {
|
||||
w += width as usize;
|
||||
h = height as usize;
|
||||
} else {
|
||||
return None;
|
||||
}
|
||||
}
|
||||
Some((w, h))
|
||||
}
|
||||
}
|
3
src/file/mod.rs
Normal file
3
src/file/mod.rs
Normal file
@ -0,0 +1,3 @@
|
||||
pub mod editor_file;
|
||||
pub mod editor_file_section;
|
||||
pub mod editor_file_token;
|
153
src/lexer/mod.rs
Normal file
153
src/lexer/mod.rs
Normal file
@ -0,0 +1,153 @@
|
||||
use std::ops::Deref;
|
||||
|
||||
pub mod plain;
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum Language {
|
||||
PlainText,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub enum TokenType {
|
||||
Whitespace { token: Token },
|
||||
Keyword { token: Token },
|
||||
String { token: Token },
|
||||
Number { token: Token },
|
||||
Identifier { token: Token },
|
||||
}
|
||||
|
||||
impl TokenType {
|
||||
pub fn move_to(&self, line: usize, character: usize, start: usize, end: usize) -> Self {
|
||||
match self {
|
||||
TokenType::Whitespace { token } => TokenType::Whitespace {
|
||||
token: token.move_to(line, character, start, end),
|
||||
},
|
||||
TokenType::Keyword { token } => TokenType::Keyword {
|
||||
token: token.move_to(line, character, start, end),
|
||||
},
|
||||
TokenType::String { token } => TokenType::String {
|
||||
token: token.move_to(line, character, start, end),
|
||||
},
|
||||
TokenType::Number { token } => TokenType::Number {
|
||||
token: token.move_to(line, character, start, end),
|
||||
},
|
||||
TokenType::Identifier { token } => TokenType::Identifier {
|
||||
token: token.move_to(line, character, start, end),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_new_line(&self) -> bool {
|
||||
match self {
|
||||
TokenType::Whitespace { token } => token.text() == "\n".to_string(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn is_space(&self) -> bool {
|
||||
match self {
|
||||
TokenType::Whitespace { token } => token.text() == " ".to_string(),
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_start(&self) -> usize {
|
||||
match self {
|
||||
TokenType::Whitespace { token } => token.start(),
|
||||
TokenType::Keyword { token } => token.start(),
|
||||
TokenType::String { token } => token.start(),
|
||||
TokenType::Number { token } => token.start(),
|
||||
TokenType::Identifier { token } => token.start(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_text(&self) -> String {
|
||||
match self {
|
||||
TokenType::Whitespace { token } => token.text(),
|
||||
TokenType::Keyword { token } => token.text(),
|
||||
TokenType::String { token } => token.text(),
|
||||
TokenType::Number { token } => token.text(),
|
||||
TokenType::Identifier { token } => token.text(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Deref for TokenType {
|
||||
type Target = Token;
|
||||
|
||||
fn deref(&self) -> &<Self as Deref>::Target {
|
||||
match self {
|
||||
TokenType::Whitespace { token } => token,
|
||||
TokenType::Keyword { token } => token,
|
||||
TokenType::String { token } => token,
|
||||
TokenType::Number { token } => token,
|
||||
TokenType::Identifier { token } => token,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct Token {
|
||||
line: usize,
|
||||
character: usize,
|
||||
start: usize,
|
||||
end: usize,
|
||||
pub text: String,
|
||||
}
|
||||
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Span {
|
||||
pub lo: usize,
|
||||
pub hi: usize,
|
||||
}
|
||||
|
||||
impl Token {
|
||||
pub fn new(text: String, line: usize, character: usize, start: usize, end: usize) -> Self {
|
||||
Self {
|
||||
text,
|
||||
line,
|
||||
character,
|
||||
start,
|
||||
end,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn text(&self) -> String {
|
||||
self.text.clone()
|
||||
}
|
||||
|
||||
pub fn line(&self) -> usize {
|
||||
self.line.clone()
|
||||
}
|
||||
|
||||
pub fn character(&self) -> usize {
|
||||
self.character.clone()
|
||||
}
|
||||
|
||||
pub fn start(&self) -> usize {
|
||||
self.start.clone()
|
||||
}
|
||||
|
||||
pub fn end(&self) -> usize {
|
||||
self.end.clone()
|
||||
}
|
||||
|
||||
pub fn move_to(&self, line: usize, character: usize, start: usize, end: usize) -> Self {
|
||||
Self {
|
||||
text: self.text.clone(),
|
||||
line,
|
||||
character,
|
||||
start,
|
||||
end,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn parse(text: String, language: Language) -> Vec<TokenType> {
|
||||
match language {
|
||||
Language::PlainText => plain::lexer::Lexer::new(text.as_str())
|
||||
.inspect(|tok| eprintln!("tok: {:?}", tok))
|
||||
.map(|t| t.0)
|
||||
.collect(),
|
||||
}
|
||||
}
|
79
src/lexer/plain.rs
Normal file
79
src/lexer/plain.rs
Normal file
@ -0,0 +1,79 @@
|
||||
use crate::lexer::{Token, TokenType};
|
||||
|
||||
pub mod lexer {
|
||||
use crate::lexer::{Span, Token, TokenType};
|
||||
use plex::lexer;
|
||||
|
||||
lexer! {
|
||||
fn next_token(text: 'a) -> (TokenType, &'a str);
|
||||
|
||||
r"[ \t\r\n]" => (TokenType::Whitespace {
|
||||
token: Token::new(text.to_string(), 0, 0, 0, 0)
|
||||
}, text),
|
||||
r"[^ \t\r\n]+" => (TokenType::Identifier {
|
||||
token: Token::new(text.to_string(), 0, 0, 0, 0)
|
||||
}, text),
|
||||
}
|
||||
|
||||
pub struct Lexer<'a> {
|
||||
original: &'a str,
|
||||
remaining: &'a str,
|
||||
line: usize,
|
||||
character: usize,
|
||||
}
|
||||
|
||||
impl<'a> Lexer<'a> {
|
||||
pub fn new(s: &'a str) -> Self {
|
||||
Self {
|
||||
original: s,
|
||||
remaining: s,
|
||||
line: 0,
|
||||
character: 0,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Iterator for Lexer<'a> {
|
||||
type Item = (TokenType, Span);
|
||||
|
||||
fn next(&mut self) -> Option<(TokenType, Span)> {
|
||||
loop {
|
||||
let tok: (TokenType, &str) =
|
||||
if let Some(((token_type, text), new_remaining)) = next_token(self.remaining) {
|
||||
self.remaining = new_remaining;
|
||||
if token_type.is_new_line() {
|
||||
self.line += 1;
|
||||
self.character = text.len();
|
||||
} else {
|
||||
self.character += text.len();
|
||||
}
|
||||
(token_type, text)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
match tok {
|
||||
(tok, text) => {
|
||||
let span = self.span_in(text);
|
||||
let token = tok.move_to(
|
||||
self.line.clone(),
|
||||
self.character - text.len(),
|
||||
span.lo.clone(),
|
||||
span.hi.clone(),
|
||||
);
|
||||
return Some((token, span));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Lexer<'a> {
|
||||
fn span_in(&self, s: &str) -> Span {
|
||||
let lo = s.as_ptr() as usize - self.original.as_ptr() as usize;
|
||||
Span {
|
||||
lo,
|
||||
hi: lo + s.len(),
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
20
src/main.rs
Normal file
20
src/main.rs
Normal file
@ -0,0 +1,20 @@
|
||||
#![allow(unused_imports)]
|
||||
#![feature(use_extern_macros)]
|
||||
|
||||
extern crate plex;
|
||||
extern crate rand;
|
||||
extern crate sdl2;
|
||||
|
||||
pub mod app;
|
||||
pub mod file;
|
||||
pub mod lexer;
|
||||
pub mod renderer;
|
||||
|
||||
use crate::app::Application;
|
||||
|
||||
fn main() {
|
||||
let mut app = Application::new();
|
||||
app.init();
|
||||
app.open_file("./tests/example.txt".to_string());
|
||||
app.run();
|
||||
}
|
148
src/renderer/managers.rs
Normal file
148
src/renderer/managers.rs
Normal file
@ -0,0 +1,148 @@
|
||||
use std::borrow::Borrow;
|
||||
use std::collections::HashMap;
|
||||
#[allow(unused_imports)]
|
||||
use std::env;
|
||||
use std::hash::Hash;
|
||||
use std::rc::Rc;
|
||||
|
||||
use sdl2::image::LoadTexture;
|
||||
use sdl2::pixels::Color;
|
||||
use sdl2::render::{Texture, TextureCreator};
|
||||
use sdl2::ttf::{Font, Sdl2TtfContext};
|
||||
|
||||
pub trait ResourceLoader<'l, R> {
|
||||
type Args: ?Sized;
|
||||
|
||||
fn load(&'l self, data: &Self::Args) -> Result<R, String>;
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
|
||||
pub struct FontDetails {
|
||||
pub path: String,
|
||||
pub size: u16,
|
||||
}
|
||||
|
||||
#[derive(Debug, Hash, Eq, PartialEq, Clone)]
|
||||
pub struct TextDetails {
|
||||
pub text: String,
|
||||
pub color: Color,
|
||||
pub font_details: FontDetails,
|
||||
}
|
||||
|
||||
impl TextDetails {
|
||||
pub fn get_cache_key(&self) -> String {
|
||||
format!(
|
||||
"text({}) size({}) {:?}",
|
||||
self.text, self.font_details.size, self.color
|
||||
)
|
||||
.to_string()
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a TextDetails> for TextDetails {
|
||||
fn from(details: &'a Self) -> Self {
|
||||
Self {
|
||||
text: details.text.clone(),
|
||||
color: details.color.clone(),
|
||||
font_details: details.font_details.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl FontDetails {
|
||||
pub fn new(path: &str, size: u16) -> FontDetails {
|
||||
Self {
|
||||
path: path.to_string(),
|
||||
size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> From<&'a FontDetails> for FontDetails {
|
||||
fn from(details: &'a FontDetails) -> Self {
|
||||
Self {
|
||||
path: details.path.clone(),
|
||||
size: details.size,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub type TextureManager<'l, T> = ResourceManager<'l, String, Texture<'l>, TextureCreator<T>>;
|
||||
pub type FontManager<'l> = ResourceManager<'l, FontDetails, Font<'l, 'static>, Sdl2TtfContext>;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct ResourceManager<'l, K, R, L>
|
||||
where
|
||||
K: Hash + Eq,
|
||||
L: 'l + ResourceLoader<'l, R>,
|
||||
{
|
||||
loader: &'l L,
|
||||
cache: HashMap<K, Rc<R>>,
|
||||
}
|
||||
|
||||
impl<'l, K, R, L> ResourceManager<'l, K, R, L>
|
||||
where
|
||||
K: Hash + Eq,
|
||||
L: ResourceLoader<'l, R>,
|
||||
{
|
||||
pub fn new(loader: &'l L) -> Self {
|
||||
Self { cache: HashMap::new(), loader }
|
||||
}
|
||||
|
||||
pub fn load<D>(&mut self, details: &D) -> Result<Rc<R>, String>
|
||||
where
|
||||
L: ResourceLoader<'l, R, Args = D>,
|
||||
D: Eq + Hash + ?Sized,
|
||||
K: Borrow<D> + for<'a> From<&'a D>,
|
||||
{
|
||||
self.cache.get(details).cloned().map_or_else(
|
||||
|| {
|
||||
let resource = Rc::new(self.loader.load(details)?);
|
||||
self.cache.insert(details.into(), resource.clone());
|
||||
Ok(resource)
|
||||
},
|
||||
Ok,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l, T> ResourceLoader<'l, Texture<'l>> for TextureCreator<T> {
|
||||
type Args = str;
|
||||
|
||||
fn load(&'l self, path: &str) -> Result<Texture, String> {
|
||||
println!("Loading {}...", path);
|
||||
self.load_texture(path)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'l> ResourceLoader<'l, Font<'l, 'static>> for Sdl2TtfContext {
|
||||
type Args = FontDetails;
|
||||
|
||||
fn load(&'l self, data: &FontDetails) -> Result<Font<'l, 'static>, String> {
|
||||
println!("Loading font {}...", data.path);
|
||||
self.load_font(&data.path, data.size)
|
||||
}
|
||||
}
|
||||
|
||||
//impl<'l, T> TextureManager<'l, T> {
|
||||
// pub fn load_text(
|
||||
// &mut self,
|
||||
// details: &mut TextDetails,
|
||||
// font: &Font,
|
||||
// ) -> Result<Rc<Texture<'l>>, String> {
|
||||
// let key = details.get_cache_key();
|
||||
// self.cache.get(key.as_str()).cloned().map_or_else(
|
||||
// || {
|
||||
// let surface = font
|
||||
// .render(details.text.as_str())
|
||||
// .blended(details.color)
|
||||
// .unwrap();
|
||||
// let texture = self.loader.create_texture_from_surface(&surface).unwrap();
|
||||
// let resource = Rc::new(texture);
|
||||
// self.cache.insert(key, resource.clone());
|
||||
// Ok(resource)
|
||||
// },
|
||||
// Ok,
|
||||
// )
|
||||
// }
|
||||
//}
|
74
src/renderer/mod.rs
Normal file
74
src/renderer/mod.rs
Normal file
@ -0,0 +1,74 @@
|
||||
pub mod managers;
|
||||
pub mod resolve_color;
|
||||
|
||||
use crate::renderer::managers::{FontManager, TextureManager};
|
||||
|
||||
use sdl2::rect::{Point, Rect};
|
||||
use sdl2::render::{Texture, TextureCreator};
|
||||
use sdl2::ttf::Sdl2TtfContext;
|
||||
use sdl2::video::WindowContext;
|
||||
|
||||
use std::rc::Rc;
|
||||
|
||||
use crate::app::config::Config;
|
||||
use crate::app::WindowCanvas;
|
||||
use crate::renderer::managers::TextDetails;
|
||||
|
||||
pub struct Renderer<'a> {
|
||||
pub config: Config,
|
||||
pub font_manager: FontManager<'a>,
|
||||
pub texture_manager: TextureManager<'a, WindowContext>,
|
||||
pub texture_creator: TextureCreator<WindowContext>,
|
||||
pub scroll: Point,
|
||||
}
|
||||
|
||||
impl<'a> Renderer<'a> {
|
||||
pub fn new(
|
||||
config: Config,
|
||||
font_context: &'a Sdl2TtfContext,
|
||||
texture_creator: TextureCreator<WindowContext>,
|
||||
) -> Self {
|
||||
Self {
|
||||
config,
|
||||
font_manager: FontManager::new(&font_context),
|
||||
texture_manager: TextureManager::new(&texture_creator),
|
||||
texture_creator,
|
||||
scroll: (0, 0).into(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render_texture(&mut self, canvas: &mut WindowCanvas, texture: &Rc<Texture>, src: &Rect, dest: &Rect) {
|
||||
canvas
|
||||
.copy_ex(
|
||||
texture,
|
||||
Some(src.clone()),
|
||||
Some(dest.clone()),
|
||||
0.0,
|
||||
None,
|
||||
false,
|
||||
false,
|
||||
)
|
||||
.unwrap();
|
||||
}
|
||||
|
||||
pub fn render_text(&mut self, details: TextDetails) -> Option<Rc<Texture>> {
|
||||
let font = self.font_manager.load(&details.font_details).unwrap();
|
||||
let surface = font
|
||||
.render(details.text.as_str())
|
||||
.blended(details.color);
|
||||
let surface = if let Ok(s) = surface {
|
||||
s
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
let texture = self
|
||||
.texture_creator
|
||||
.create_texture_from_surface(&surface);
|
||||
let texture = if let Ok(t) = texture {
|
||||
Rc::new(t)
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
Some(texture)
|
||||
}
|
||||
}
|
10
src/renderer/resolve_color.rs
Normal file
10
src/renderer/resolve_color.rs
Normal file
@ -0,0 +1,10 @@
|
||||
use sdl2::pixels::Color;
|
||||
|
||||
use crate::lexer::TokenType;
|
||||
|
||||
pub fn resolve_color(token_type: &TokenType) -> Color {
|
||||
match token_type {
|
||||
&TokenType::Whitespace { .. } => Color::RGBA(220, 220, 220, 90),
|
||||
_ => Color::RGBA(0, 0, 0, 0),
|
||||
}
|
||||
}
|
3
tests/example.txt
Normal file
3
tests/example.txt
Normal file
@ -0,0 +1,3 @@
|
||||
Hello world
|
||||
foo bar
|
||||
example com
|
Loading…
Reference in New Issue
Block a user