Skip to content

Instantly share code, notes, and snippets.

@amPerl
Last active August 1, 2023 18:04
Show Gist options
  • Save amPerl/30977f02a333294c8a2268d2e215959b to your computer and use it in GitHub Desktop.
Save amPerl/30977f02a333294c8a2268d2e215959b to your computer and use it in GitHub Desktop.
ugly egui util to enqueue state-updating closures
use std::sync::Arc;
use eframe::egui::{self, Context};
mod update_queue;
use update_queue::{AppAsyncExt, ContextAsyncExt};
fn main() {
let native_options = eframe::NativeOptions::default();
eframe::run_native(
"EguiSandbox",
native_options,
Box::new(|cc| Box::new(EguiSandbox::new(cc))),
)
.unwrap();
}
struct EguiSandbox {
cool_value: String,
}
impl EguiSandbox {
fn new(_cc: &eframe::CreationContext<'_>) -> Self {
Self {
cool_value: "Original text".into(),
}
}
}
impl eframe::App for EguiSandbox {
fn update(&mut self, ctx: &Context, _frame: &mut eframe::Frame) {
self.apply_pending_updates(ctx);
egui::CentralPanel::default().show(ctx, |ui| {
ui.label(&self.cool_value);
if ui.button("start timer").clicked() {
let ctx = ctx.clone();
std::thread::spawn(move || {
for i in 1..=60 {
std::thread::sleep(std::time::Duration::from_secs(1));
ctx.queue_update(Arc::new(move |state: &mut Self| {
state.cool_value = format!("time since click: {}s", i);
}));
}
});
}
});
}
}
use eframe::egui;
use std::sync::Arc;
pub type UpdateFn<AppState> = Arc<dyn Fn(&mut AppState) + Send + Sync + 'static>;
pub trait AppAsyncExt {
fn apply_pending_updates(&mut self, ctx: &egui::Context);
}
impl<T> AppAsyncExt for T
where
T: eframe::App + 'static,
{
fn apply_pending_updates(&mut self, ctx: &egui::Context) {
ctx.memory_mut(|memory| {
let update_fns: &mut Vec<UpdateFn<Self>> = memory
.data
.get_temp_mut_or_default(egui::Id::new("_async_ext"));
for update_fn in update_fns.drain(..) {
update_fn(self);
}
});
}
}
pub trait ContextAsyncExt {
fn queue_update<T: eframe::App + AppAsyncExt + 'static>(&self, update_fn: UpdateFn<T>);
}
impl ContextAsyncExt for egui::Context {
fn queue_update<T: eframe::App + AppAsyncExt + 'static>(&self, update_fn: UpdateFn<T>) {
self.memory_mut(|memory| {
let update_fns: &mut Vec<UpdateFn<T>> = memory
.data
.get_temp_mut_or_default(egui::Id::new("_async_ext"));
update_fns.push(update_fn);
});
self.request_repaint();
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment