Render wrapped text and start editing actions
parent
81cd5ef641
commit
da3647c9e5
91
src/main.rs
91
src/main.rs
|
@ -13,16 +13,41 @@ fn string_err(e: impl ToString) -> String {
|
||||||
e.to_string()
|
e.to_string()
|
||||||
}
|
}
|
||||||
|
|
||||||
const WIDTH: u32 = 800;
|
const PADDING: i32 = 32;
|
||||||
const HEIGHT: u32 = 600;
|
|
||||||
|
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> {
|
fn main() -> Result<(), String> {
|
||||||
|
let mut state = State::default();
|
||||||
let context = sdl2::init()?;
|
let context = sdl2::init()?;
|
||||||
let video = context.video()?;
|
let video = context.video()?;
|
||||||
let ttf_context = ttf::init().map_err(string_err)?;
|
let ttf_context = ttf::init().map_err(string_err)?;
|
||||||
|
|
||||||
let window = video
|
let window = video
|
||||||
.window("medit", WIDTH, HEIGHT)
|
.window("medit", state.width, state.height)
|
||||||
.position_centered()
|
.position_centered()
|
||||||
.allow_highdpi()
|
.allow_highdpi()
|
||||||
.build()
|
.build()
|
||||||
|
@ -31,57 +56,85 @@ fn main() -> Result<(), String> {
|
||||||
let mut canvas = window.into_canvas().build().map_err(string_err)?;
|
let mut canvas = window.into_canvas().build().map_err(string_err)?;
|
||||||
let texture_creator = canvas.texture_creator();
|
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.set_draw_color(Color::WHITE);
|
||||||
canvas.clear();
|
canvas.clear();
|
||||||
|
canvas.present();
|
||||||
|
|
||||||
let mut event_pump = context.event_pump()?;
|
let mut event_pump = context.event_pump()?;
|
||||||
let mut x = 0;
|
|
||||||
'running: loop {
|
'running: loop {
|
||||||
for event in event_pump.poll_iter() {
|
for event in event_pump.poll_iter() {
|
||||||
match event {
|
let action = match event {
|
||||||
Event::Quit { .. }
|
Event::Quit { .. }
|
||||||
| Event::KeyDown {
|
| Event::KeyDown {
|
||||||
keycode: Some(Keycode::Escape),
|
keycode: Some(Keycode::Escape),
|
||||||
..
|
..
|
||||||
} => break 'running,
|
} => break 'running,
|
||||||
|
Event::TextEditing { .. } => {
|
||||||
|
todo!("handle TextEdit event")
|
||||||
|
}
|
||||||
|
Event::TextInput { text, .. } => Action::Input(text),
|
||||||
Event::KeyDown {
|
Event::KeyDown {
|
||||||
keycode: Some(k), ..
|
keycode: Some(k), ..
|
||||||
} if is_drawable_key(k) => {
|
} 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();
|
canvas.clear();
|
||||||
let texture = string_texture(&font, &texture_creator, k.name())?;
|
if let Some(texture) = string_texture(&font, &state, &texture_creator, &state.content)? {
|
||||||
let target = target_rect(x, 0, &texture);
|
let target = target_rect(PADDING, PADDING, &texture);
|
||||||
x += target.width() as i32;
|
|
||||||
canvas.copy(&texture, None, Some(target))?;
|
canvas.copy(&texture, None, Some(target))?;
|
||||||
}
|
}
|
||||||
_ => {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
canvas.present();
|
canvas.present();
|
||||||
std::thread::sleep(std::time::Duration::new(0, 1_000_000_000u32 / 60));
|
std::thread::sleep(std::time::Duration::new(0, 1_000_000_000u32 / 60));
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_drawable_key(key: Keycode) -> bool {
|
fn control_key_action(keycode: &Keycode) -> Option<Action> {
|
||||||
let key = key as i32;
|
let action = match keycode {
|
||||||
(key >= Keycode::A as i32 && key <= Keycode::Z as i32)
|
Keycode::Backspace => Action::Backspace,
|
||||||
|| (key >= Keycode::Num0 as i32 && key <= Keycode::Num9 as i32)
|
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>(
|
fn string_texture<'f, 't>(
|
||||||
font: &Font<'f, 'f>,
|
font: &Font<'f, 'f>,
|
||||||
|
state: &State,
|
||||||
texture_creator: &'t TextureCreator<WindowContext>,
|
texture_creator: &'t TextureCreator<WindowContext>,
|
||||||
string: impl AsRef<str>,
|
string: impl AsRef<str>,
|
||||||
) -> Result<Texture<'t>, String> {
|
) -> Result<Option<Texture<'t>>, String> {
|
||||||
|
if string.as_ref().is_empty() {
|
||||||
|
return Ok(None);
|
||||||
|
}
|
||||||
let surface = font
|
let surface = font
|
||||||
.render(string.as_ref())
|
.render(string.as_ref())
|
||||||
.blended(Color::BLACK)
|
.blended_wrapped(Color::BLACK, (state.width - PADDING as u32) * 2)
|
||||||
.map_err(string_err)?;
|
.map_err(string_err)?;
|
||||||
texture_creator
|
texture_creator
|
||||||
.create_texture_from_surface(surface)
|
.create_texture_from_surface(surface)
|
||||||
.map_err(string_err)
|
.map_err(string_err)
|
||||||
|
.map(Some)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn target_rect(x: i32, y: i32, texture: &Texture) -> Rect {
|
fn target_rect(x: i32, y: i32, texture: &Texture) -> Rect {
|
||||||
|
|
Loading…
Reference in New Issue