commit
289c318804
3 changed files with 279 additions and 0 deletions
@ -0,0 +1,31 @@ |
||||
//let sdl_context = sdl2::init()?;
|
||||
//let video_subsys = sdl_context.video()?;
|
||||
//let ttf_context = sdl2::ttf::init().map_err(|e| e.to_string())?;
|
||||
|
||||
const GLYPH_METRICS_CAPACITY: usize = 128; |
||||
|
||||
struct GlyphMetric { |
||||
ax: f32, // advance.x
|
||||
ay: f32, // advance.y
|
||||
|
||||
bw: f32, // bitmap.width;
|
||||
bh: f32, // bitmap.rows;
|
||||
|
||||
bl: f32, // bitmap_left;
|
||||
bt: f32, // bitmap_top;
|
||||
|
||||
tx: f32, // x offset of glyph in texture coordinates
|
||||
} |
||||
|
||||
struct FreeGlyphAtlas { |
||||
atlas_width: usize, // TODO: Get FT_Uint from FT2build
|
||||
atlas_height: usize, |
||||
glyphs_texture: GLuint, |
||||
metrics: [GlyphMetric; GLYPH_METRICS_CAPACITY], |
||||
} |
||||
|
||||
fn free_glyph_atlas_init(atlas: FreeGlyphAtlas, face: FT_Face) { |
||||
for i in 32..127 { |
||||
// something something sdl2::ttf::GlyphMetrics
|
||||
} |
||||
} |
||||
@ -0,0 +1,14 @@ |
||||
use std::fs; |
||||
|
||||
struct TypeFace { |
||||
type_char: [[bool; 8]; 14], |
||||
} |
||||
|
||||
fn get_font() { |
||||
let file_path = "./fonts/Terminus14x8.data"; |
||||
|
||||
println!("In file {}", file_path); |
||||
|
||||
let contents = fs::read_to_string(file_path) |
||||
.expect("File could not be read"); |
||||
} |
||||
@ -0,0 +1,234 @@ |
||||
extern crate sdl2; |
||||
|
||||
use std::path::Path; |
||||
|
||||
use sdl2::event::Event; |
||||
use sdl2::keyboard::Keycode; |
||||
use sdl2::pixels::Color; |
||||
use sdl2::rect::Rect; |
||||
use sdl2::render::TextureQuery; |
||||
|
||||
//mod _catlas;
|
||||
//use _catlas::*;
|
||||
|
||||
mod font_build; |
||||
use font_build::*; |
||||
|
||||
static SCREEN_WIDTH: u32 = 1680; |
||||
static SCREEN_HEIGHT: u32 = 945; |
||||
|
||||
struct ModifierKeys { |
||||
alt: bool, |
||||
ctrl: bool, |
||||
shift: bool, |
||||
} |
||||
|
||||
// handle the annoying Rect i32
|
||||
macro_rules! rect( |
||||
($x:expr, $y:expr, $w:expr, $h:expr) => ( |
||||
Rect::new($x as i32, $y as i32, $w as u32, $h as u32) |
||||
) |
||||
); |
||||
|
||||
// Scale fonts to a reasonable size when they're too big (though they might look less smooth)
|
||||
/* |
||||
fn get_centered_rect(rect_width: u32, rect_height: u32, cons_width: u32, cons_height: u32) -> Rect { |
||||
let wr = rect_width as f32 / cons_width as f32; |
||||
let hr = rect_height as f32 / cons_height as f32; |
||||
|
||||
let (w, h) = if wr > 1f32 || hr > 1f32 { |
||||
if wr > hr { |
||||
println!("Scaling down! The text will look worse!"); |
||||
let h = (rect_height as f32 / wr) as i32; |
||||
(cons_width as i32, h) |
||||
} else { |
||||
println!("Scaling down! The text will look worse!"); |
||||
let w = (rect_width as f32 / hr) as i32; |
||||
(w, cons_height as i32) |
||||
} |
||||
} else { |
||||
(rect_width as i32, rect_height as i32) |
||||
}; |
||||
|
||||
let cx = (SCREEN_WIDTH as i32 - w) / 2; |
||||
let cy = (SCREEN_HEIGHT as i32 - h) / 2; |
||||
rect!(cx, cy, w, h) |
||||
} |
||||
*/ |
||||
|
||||
fn get_corner_rect(rect_width: u32, rect_height: u32) -> Rect { |
||||
let (w,h) = (rect_width as i32, rect_height as i32); |
||||
let cx = 15; |
||||
let cy = 15; |
||||
rect!(cx, cy, w, h) |
||||
} |
||||
|
||||
|
||||
pub fn main() -> Result<(), String> { |
||||
let font_path: &Path = Path::new("./fonts/Monoid-Regular.ttf"); |
||||
|
||||
let sdl_context = sdl2::init()?; |
||||
let video_subsys = sdl_context.video()?; |
||||
let ttf_context = sdl2::ttf::init().map_err(|e| e.to_string())?; |
||||
|
||||
let window = video_subsys |
||||
.window("SDL2_TTF Example", SCREEN_WIDTH, SCREEN_HEIGHT) |
||||
.position_centered() |
||||
.opengl() |
||||
.build() |
||||
.map_err(|e| e.to_string())?; |
||||
|
||||
let mut canvas = window.into_canvas().build().map_err(|e| e.to_string())?; |
||||
let texture_creator = canvas.texture_creator(); |
||||
|
||||
// Load a font
|
||||
let mut font = ttf_context.load_font(font_path, 12)?; |
||||
font.set_style(sdl2::ttf::FontStyle::BOLD); |
||||
|
||||
let mut buffer = String::new(); |
||||
let mut cursor_position = 0; |
||||
|
||||
let mut draw_text = |text: &str| -> Result<(), String> { |
||||
// render a surface, and convert it to a texture bound to the canvas
|
||||
let surface = font |
||||
.render(text) |
||||
.blended(Color::RGBA(255, 255, 255, 255)) |
||||
.map_err(|e| e.to_string())?; |
||||
let texture = texture_creator |
||||
.create_texture_from_surface(&surface) |
||||
.map_err(|e| e.to_string())?; |
||||
|
||||
canvas.set_draw_color(Color::RGB(32, 32, 32)); |
||||
canvas.clear(); |
||||
|
||||
let TextureQuery { width, height, .. } = texture.query(); |
||||
|
||||
// If the example text is too big for the screen, downscale it (and center regardless)
|
||||
// let padding = 64;
|
||||
let target = get_corner_rect( |
||||
width, |
||||
height, |
||||
); |
||||
|
||||
canvas.copy(&texture, None, Some(target))?; |
||||
canvas.present(); |
||||
|
||||
Ok(()) |
||||
}; |
||||
|
||||
let mut modifier_keys = ModifierKeys {alt: false, ctrl: false, shift: false}; |
||||
|
||||
'mainloop: loop { |
||||
for event in sdl_context.event_pump()?.poll_iter() { |
||||
match event { |
||||
// ESC or SIGKILL
|
||||
Event::KeyDown { keycode: Some(Keycode::Escape), .. } | |
||||
Event::Quit { .. } => break 'mainloop, |
||||
|
||||
// ALT down
|
||||
Event::KeyDown { keycode: Some(Keycode::LAlt), .. } | |
||||
Event::KeyDown { keycode: Some(Keycode::RAlt), .. } => { |
||||
modifier_keys.alt = true |
||||
}, |
||||
|
||||
// ALT up
|
||||
Event::KeyUp { keycode: Some(Keycode::LAlt), .. } | |
||||
Event::KeyUp { keycode: Some(Keycode::RAlt), .. } => { |
||||
modifier_keys.alt = false |
||||
}, |
||||
|
||||
// CTRL down
|
||||
Event::KeyDown { keycode: Some(Keycode::LCtrl), .. } | |
||||
Event::KeyDown { keycode: Some(Keycode::RCtrl), .. } => { |
||||
modifier_keys.ctrl = true |
||||
}, |
||||
|
||||
// CTRL up
|
||||
Event::KeyUp { keycode: Some(Keycode::LCtrl), .. } | |
||||
Event::KeyUp { keycode: Some(Keycode::RCtrl), .. } => { |
||||
modifier_keys.ctrl = false |
||||
}, |
||||
|
||||
// SHIFT down
|
||||
Event::KeyDown { keycode: Some(Keycode::LShift), .. } | |
||||
Event::KeyDown { keycode: Some(Keycode::RShift), .. } => { |
||||
modifier_keys.shift = true |
||||
}, |
||||
|
||||
// SHIFT up
|
||||
Event::KeyUp { keycode: Some(Keycode::LShift), .. } | |
||||
Event::KeyUp { keycode: Some(Keycode::RShift), .. } => { |
||||
modifier_keys.shift = false |
||||
}, |
||||
|
||||
// Ignore SUPER
|
||||
Event::KeyDown { keycode: Some(Keycode::LGui), .. } | |
||||
Event::KeyDown { keycode: Some(Keycode::RGui), .. } => (), |
||||
|
||||
// Type spacebar
|
||||
Event::KeyDown { keycode: Some(Keycode::Space), .. } => { |
||||
buffer.insert(cursor_position, ' '); |
||||
cursor_position += 1; |
||||
draw_text(&buffer)? |
||||
}, |
||||
|
||||
// Backspace
|
||||
Event::KeyDown { keycode: Some(Keycode::Backspace), .. } => { |
||||
buffer.remove(cursor_position - 1); |
||||
cursor_position -= 1; |
||||
draw_text(&buffer)? |
||||
}, |
||||
|
||||
// Enter
|
||||
Event::KeyDown { keycode: Some(Keycode::Return), .. } => { |
||||
let key = '\n'; |
||||
buffer.insert(cursor_position, key); |
||||
cursor_position += 1; |
||||
draw_text(&buffer)? |
||||
}, |
||||
|
||||
// Left/Back arrow
|
||||
Event::KeyDown { keycode: Some(Keycode::Left), .. } => { |
||||
cursor_position = usize::checked_sub(cursor_position, 1) |
||||
.unwrap_or(0) |
||||
}, |
||||
|
||||
// Home key
|
||||
Event::KeyDown { keycode: Some(Keycode::Home), .. } => { |
||||
cursor_position = 0 |
||||
}, |
||||
|
||||
// End key
|
||||
Event::KeyDown { keycode: Some(Keycode::End), .. } => { |
||||
cursor_position = buffer.len() |
||||
}, |
||||
|
||||
// Right/Forward arrow
|
||||
Event::KeyDown { keycode: Some(Keycode::Right), .. } => { |
||||
cursor_position = (cursor_position + 1).min(buffer.len()) |
||||
}, |
||||
|
||||
Event::KeyDown { keycode, .. } => { |
||||
let key = keycode.unwrap().to_string(); |
||||
|
||||
// Ignore multi-char keycodes
|
||||
if key.len() > 1 { break } |
||||
|
||||
let key_case = match modifier_keys.shift { |
||||
true => key.to_uppercase(), |
||||
false => key.to_lowercase() |
||||
}.chars().nth(0).expect("Empty"); |
||||
|
||||
buffer.insert(cursor_position, key_case); |
||||
cursor_position += 1; |
||||
draw_text(&buffer)?; |
||||
println!("{key}"); |
||||
}, |
||||
|
||||
_ => {} |
||||
} |
||||
} |
||||
} |
||||
|
||||
Ok(()) |
||||
} |
||||
Loading…
Reference in new issue