Skip to content

Ability to request a frame / redraw from egui Context with delay or from thread #342

@woelper

Description

@woelper

Hi!

This might be an implementation / integration issue with egui.
When requesting a frame with egui, for example with ui.ctx().request_repaint() this works as expected. However, if a frame is requested with delay or from a long running thread, this does not work. A concept in egui is to be able to clone Context and pass it around so updates can be requested from long-running processes. Below is a modified example from the notan repo:

use std::time::Duration;

use notan::egui::{self, *};
use notan::prelude::*;

#[notan_main]
fn main() -> Result<(), String> {
    let win = WindowConfig::new()
        .set_vsync(true)
        .set_lazy_loop(true)
        .set_high_dpi(true);

    notan::init()
        .add_config(win)
        .add_config(EguiConfig)
        .draw(draw)
        .build()
}

fn draw(app: &mut App, gfx: &mut Graphics, plugins: &mut Plugins) {
    let mut output = plugins.egui(|ctx| {
        egui::SidePanel::left("side_panel").show(ctx, |ui| {
            ui.heading("Egui Plugin Example");

            ui.separator();
            if ui.button("Quit").clicked() {
                app.exit();
            }

            let (mut r, _) = ui.allocate_exact_size(Vec2::splat(40.), Sense::click());
            r = r.translate(vec2(0., (ui.ctx().frame_nr() as f32 * 0.2).sin() * 10.));
            ui.painter()
                .rect(r, Rounding::same(4.), Color32::RED, Stroke::NONE);

            // with this on, the square always moves
            // ui.ctx().request_repaint();

            // this does not work
            ui.ctx().request_repaint_after(Duration::from_millis(1500));
            

            // this is a common pattern to make sure egui updates after something happened
            if ui.button("bounce after 2s (Does not work)").clicked() {
                let ctx = ui.ctx().clone();
                std::thread::spawn(move || {
                    std::thread::sleep(Duration::from_secs(2));
                    println!("Bounce");
                    ctx.request_repaint();
                });
            }


            // this is just to demonstrate that passing the `Context` to a thread works
            if ui.button("bounce always").clicked() {
                let ctx = ui.ctx().clone();
                std::thread::spawn(move || {
                    loop {
                        std::thread::sleep(Duration::from_millis(2));
                        ctx.request_repaint();
                    }
                });
            }

        });
    });

    output.clear_color(Color::BLACK);
    gfx.render(&output);
}

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions