From da3647c9e5f78b5b62fc86661e3cbb29dc4fc3b8 Mon Sep 17 00:00:00 2001 From: mat ess Date: Fri, 19 Aug 2022 18:42:49 -0400 Subject: [PATCH] Render wrapped text and start editing actions --- src/main.rs | 91 ++++++++++++++++++++++++++++++++++++++++++----------- 1 file changed, 72 insertions(+), 19 deletions(-) diff --git a/src/main.rs b/src/main.rs index 90a51b5..20a6d4a 100644 --- a/src/main.rs +++ b/src/main.rs @@ -13,16 +13,41 @@ fn string_err(e: impl ToString) -> String { e.to_string() } -const WIDTH: u32 = 800; -const HEIGHT: u32 = 600; +const PADDING: i32 = 32; + +struct State { + pub width: u32, + pub height: u32, + pub line: usize, + pub content: String, +} + +impl Default for State { + fn default() -> Self { + Self { + width: 800, + height: 600, + line: 0, + content: String::new(), + } + } +} + +enum Action { + Input(String), + Backspace, + Newline, + NoOp, +} fn main() -> Result<(), String> { + let mut state = State::default(); let context = sdl2::init()?; let video = context.video()?; let ttf_context = ttf::init().map_err(string_err)?; let window = video - .window("medit", WIDTH, HEIGHT) + .window("medit", state.width, state.height) .position_centered() .allow_highdpi() .build() @@ -31,57 +56,85 @@ fn main() -> Result<(), String> { let mut canvas = window.into_canvas().build().map_err(string_err)?; let texture_creator = canvas.texture_creator(); - let font = ttf_context.load_font("resources/fonts/ttf/FiraCode-VF.ttf", 128)?; + let font = ttf_context.load_font("resources/fonts/ttf/FiraCode-Retina.ttf", 64)?; canvas.set_draw_color(Color::WHITE); canvas.clear(); + canvas.present(); let mut event_pump = context.event_pump()?; - let mut x = 0; 'running: loop { for event in event_pump.poll_iter() { - match event { + let action = match event { Event::Quit { .. } | Event::KeyDown { keycode: Some(Keycode::Escape), .. } => break 'running, + Event::TextEditing { .. } => { + todo!("handle TextEdit event") + } + Event::TextInput { text, .. } => Action::Input(text), Event::KeyDown { keycode: Some(k), .. - } if is_drawable_key(k) => { - canvas.clear(); - let texture = string_texture(&font, &texture_creator, k.name())?; - let target = target_rect(x, 0, &texture); - x += target.width() as i32; - canvas.copy(&texture, None, Some(target))?; + } if is_control_key(&k) => control_key_action(&k).unwrap(), + _ => Action::NoOp, + }; + match action { + Action::Input(text) => state.content += &text, + Action::Backspace => { + if !state.content.is_empty() { + state.content.truncate(state.content.len() - 1) + } } - _ => {} + Action::Newline => { + state.line += 1; + state.content += "\n"; + } + Action::NoOp => {} } } + canvas.clear(); + if let Some(texture) = string_texture(&font, &state, &texture_creator, &state.content)? { + let target = target_rect(PADDING, PADDING, &texture); + canvas.copy(&texture, None, Some(target))?; + } canvas.present(); std::thread::sleep(std::time::Duration::new(0, 1_000_000_000u32 / 60)); } Ok(()) } -fn is_drawable_key(key: Keycode) -> bool { - let key = key as i32; - (key >= Keycode::A as i32 && key <= Keycode::Z as i32) - || (key >= Keycode::Num0 as i32 && key <= Keycode::Num9 as i32) +fn control_key_action(keycode: &Keycode) -> Option { + let action = match keycode { + Keycode::Backspace => Action::Backspace, + Keycode::Return | Keycode::Return2 => Action::Newline, + _ => return None, + }; + Some(action) +} + +fn is_control_key(keycode: &Keycode) -> bool { + control_key_action(keycode).is_some() } fn string_texture<'f, 't>( font: &Font<'f, 'f>, + state: &State, texture_creator: &'t TextureCreator, string: impl AsRef, -) -> Result, String> { +) -> Result>, String> { + if string.as_ref().is_empty() { + return Ok(None); + } let surface = font .render(string.as_ref()) - .blended(Color::BLACK) + .blended_wrapped(Color::BLACK, (state.width - PADDING as u32) * 2) .map_err(string_err)?; texture_creator .create_texture_from_surface(surface) .map_err(string_err) + .map(Some) } fn target_rect(x: i32, y: i32, texture: &Texture) -> Rect {