Implement text typeout

main
Elnu 1 year ago
parent 20a8bf41b7
commit 61d99f7133

@ -1,4 +1,6 @@
use std::path::PathBuf; use std::{path::PathBuf, sync::{Arc, Mutex}};
use std::thread;
use std::time::Duration;
use eframe::egui; use eframe::egui;
use egui::*; use egui::*;
@ -23,38 +25,104 @@ pub fn run(file: PathBuf) -> Result<(), eframe::Error> {
struct App { struct App {
state: State, state: State,
text: String, text: String,
chars: Arc<Mutex<usize>>,
typing_kill: Option<Arc<Mutex<bool>>>,
typing_done: Arc<Mutex<bool>>,
} }
impl App { impl App {
fn from_state(state: State) -> Self { fn from_state(state: State) -> Self {
let mut app = Self { Self {
state, state,
text: "".to_owned(), text: "".to_owned(),
}; chars: Arc::new(Mutex::new(0)),
app.next(); typing_kill: None,
app typing_done: Arc::new(Mutex::new(true)),
}
} }
fn next(&mut self) { fn next(&mut self, ctx: &Context) {
if let Some(Command::Say { name, text }) = self.state.next_command() { if let Some(Command::Say { name, text }) = self.state.next_command() {
self.text = match name { self.text = match name {
Some(name) => format!("{name}: {text}"), Some(name) => format!("{name}: {text}"),
None => text, None => text,
};
self.start_typing(ctx);
}
}
fn kill_typing(&mut self) {
if let Some(kill) = &self.typing_kill {
*kill.lock().unwrap() = true;
}
}
fn interrupt_typing(&mut self) {
self.kill_typing();
*self.chars.lock().unwrap() = self.text.len();
*self.typing_done.lock().unwrap() = true;
}
fn start_typing(&mut self, ctx: &Context) {
// Kill previous typing thread if exists
self.kill_typing();
*self.chars.lock().unwrap() = 0;
*self.typing_done.lock().unwrap() = false;
// Set up references to be passed into thread
let ctx = ctx.clone();
let kill = {
let kill = Arc::new(Mutex::new(false));
self.typing_kill = Some(kill.clone());
kill
};
let done = self.typing_done.clone();
let chars = self.chars.clone();
let len = self.text.len();
thread::spawn(move || {
let mut complete = false;
for i in 0..len {
if *kill.lock().unwrap() {
break;
}
*chars.lock().unwrap() = i;
ctx.request_repaint();
thread::sleep(Duration::from_millis(50));
complete = true;
}
if complete {
*done.lock().unwrap() = true;
} }
});
}
fn handle_interaction(&mut self, ctx: &Context) {
if *self.typing_done.lock().unwrap() {
self.next(ctx);
} else {
self.interrupt_typing();
} }
} }
} }
impl eframe::App for App { impl eframe::App for App {
fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) { fn update(&mut self, ctx: &egui::Context, _frame: &mut eframe::Frame) {
egui::CentralPanel::default().show(ctx, |ui| { egui::CentralPanel::default()
if ctx.input(|i| .frame(Frame {
i.key_pressed(Key::Space) fill: Color32::BLACK,
|| i.pointer.button_clicked(PointerButton::Primary) inner_margin: Margin::same(32.0),
) { ..Default::default()
self.next(); })
} .show(ctx, |ui| {
ui.label(&self.text); if ctx.input(|i|
}); i.key_pressed(Key::Space)
|| i.pointer.button_clicked(PointerButton::Primary)
) {
self.handle_interaction(ctx);
}
ui.with_layout(egui::Layout::left_to_right(Align::Max), |ui| ui.heading(&self.text[0..*self.chars.lock().unwrap()]));
});
} }
} }
Loading…
Cancel
Save