Add Context::request_repaint_after (#1694)
This commit is contained in:
parent
1a89cb35e1
commit
935913b1ec
13 changed files with 180 additions and 43 deletions
|
@ -16,6 +16,7 @@ NOTE: [`epaint`](epaint/CHANGELOG.md), [`eframe`](eframe/CHANGELOG.md), [`egui-w
|
||||||
|
|
||||||
### Changed
|
### Changed
|
||||||
* `PaintCallback` shapes now require the whole callback to be put in an `Arc<dyn Any>` with the value being a backend-specific callback type. ([#1684](https://github.com/emilk/egui/pull/1684))
|
* `PaintCallback` shapes now require the whole callback to be put in an `Arc<dyn Any>` with the value being a backend-specific callback type. ([#1684](https://github.com/emilk/egui/pull/1684))
|
||||||
|
* Replaced `needs_repaint` in `FullOutput` with `repaint_after`. Used to force repaint after the set duration in reactive mode.([#1694](https://github.com/emilk/egui/pull/1694)).
|
||||||
|
|
||||||
### Fixed 🐛
|
### Fixed 🐛
|
||||||
* Fixed `ImageButton`'s changing background padding on hover ([#1595](https://github.com/emilk/egui/pull/1595)).
|
* Fixed `ImageButton`'s changing background padding on hover ([#1595](https://github.com/emilk/egui/pull/1595)).
|
||||||
|
|
|
@ -120,7 +120,7 @@ pub fn run_glow(
|
||||||
|
|
||||||
let egui::FullOutput {
|
let egui::FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
needs_repaint,
|
repaint_after,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = integration.update(app.as_mut(), window);
|
} = integration.update(app.as_mut(), window);
|
||||||
|
@ -148,9 +148,18 @@ pub fn run_glow(
|
||||||
|
|
||||||
*control_flow = if integration.should_quit() {
|
*control_flow = if integration.should_quit() {
|
||||||
winit::event_loop::ControlFlow::Exit
|
winit::event_loop::ControlFlow::Exit
|
||||||
} else if needs_repaint {
|
} else if repaint_after.is_zero() {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
winit::event_loop::ControlFlow::Poll
|
winit::event_loop::ControlFlow::Poll
|
||||||
|
} else if let Some(repaint_after_instant) =
|
||||||
|
std::time::Instant::now().checked_add(repaint_after)
|
||||||
|
{
|
||||||
|
// if repaint_after is something huge and can't be added to Instant,
|
||||||
|
// we will use `ControlFlow::Wait` instead.
|
||||||
|
// technically, this might lead to some weird corner cases where the user *WANTS*
|
||||||
|
// winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own
|
||||||
|
// egui backend impl i guess.
|
||||||
|
winit::event_loop::ControlFlow::WaitUntil(repaint_after_instant)
|
||||||
} else {
|
} else {
|
||||||
winit::event_loop::ControlFlow::Wait
|
winit::event_loop::ControlFlow::Wait
|
||||||
};
|
};
|
||||||
|
@ -167,7 +176,6 @@ pub fn run_glow(
|
||||||
std::thread::sleep(std::time::Duration::from_millis(10));
|
std::thread::sleep(std::time::Duration::from_millis(10));
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
match event {
|
match event {
|
||||||
// Platform-dependent event handlers to workaround a winit bug
|
// Platform-dependent event handlers to workaround a winit bug
|
||||||
// See: https://github.com/rust-windowing/winit/issues/987
|
// See: https://github.com/rust-windowing/winit/issues/987
|
||||||
|
@ -209,7 +217,12 @@ pub fn run_glow(
|
||||||
painter.destroy();
|
painter.destroy();
|
||||||
}
|
}
|
||||||
winit::event::Event::UserEvent(RequestRepaintEvent) => window.request_redraw(),
|
winit::event::Event::UserEvent(RequestRepaintEvent) => window.request_redraw(),
|
||||||
_ => (),
|
winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached {
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
window.request_redraw();
|
||||||
|
}
|
||||||
|
_ => {}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
@ -298,7 +311,7 @@ pub fn run_wgpu(
|
||||||
|
|
||||||
let egui::FullOutput {
|
let egui::FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
needs_repaint,
|
repaint_after,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = integration.update(app.as_mut(), window);
|
} = integration.update(app.as_mut(), window);
|
||||||
|
@ -319,9 +332,18 @@ pub fn run_wgpu(
|
||||||
|
|
||||||
*control_flow = if integration.should_quit() {
|
*control_flow = if integration.should_quit() {
|
||||||
winit::event_loop::ControlFlow::Exit
|
winit::event_loop::ControlFlow::Exit
|
||||||
} else if needs_repaint {
|
} else if repaint_after.is_zero() {
|
||||||
window.request_redraw();
|
window.request_redraw();
|
||||||
winit::event_loop::ControlFlow::Poll
|
winit::event_loop::ControlFlow::Poll
|
||||||
|
} else if let Some(repaint_after_instant) =
|
||||||
|
std::time::Instant::now().checked_add(repaint_after)
|
||||||
|
{
|
||||||
|
// if repaint_after is something huge and can't be added to Instant,
|
||||||
|
// we will use `ControlFlow::Wait` instead.
|
||||||
|
// technically, this might lead to some weird corner cases where the user *WANTS*
|
||||||
|
// winit to use `WaitUntil(MAX_INSTANT)` explicitly. they can roll their own
|
||||||
|
// egui backend impl i guess.
|
||||||
|
winit::event_loop::ControlFlow::WaitUntil(repaint_after_instant)
|
||||||
} else {
|
} else {
|
||||||
winit::event_loop::ControlFlow::Wait
|
winit::event_loop::ControlFlow::Wait
|
||||||
};
|
};
|
||||||
|
@ -395,6 +417,11 @@ pub fn run_wgpu(
|
||||||
painter.destroy();
|
painter.destroy();
|
||||||
}
|
}
|
||||||
winit::event::Event::UserEvent(RequestRepaintEvent) => window.request_redraw(),
|
winit::event::Event::UserEvent(RequestRepaintEvent) => window.request_redraw(),
|
||||||
|
winit::event::Event::NewEvents(winit::event::StartCause::ResumeTimeReached {
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
window.request_redraw();
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -251,10 +251,10 @@ impl AppRunner {
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if egui requests a repaint.
|
/// Returns how long to wait until the next repaint.
|
||||||
///
|
///
|
||||||
/// Call [`Self::paint`] later to paint
|
/// Call [`Self::paint`] later to paint
|
||||||
pub fn logic(&mut self) -> Result<(bool, Vec<egui::ClippedPrimitive>), JsValue> {
|
pub fn logic(&mut self) -> Result<(std::time::Duration, Vec<egui::ClippedPrimitive>), JsValue> {
|
||||||
let frame_start = now_sec();
|
let frame_start = now_sec();
|
||||||
|
|
||||||
resize_canvas_to_screen_size(self.canvas_id(), self.app.max_size_points());
|
resize_canvas_to_screen_size(self.canvas_id(), self.app.max_size_points());
|
||||||
|
@ -266,7 +266,7 @@ impl AppRunner {
|
||||||
});
|
});
|
||||||
let egui::FullOutput {
|
let egui::FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
needs_repaint,
|
repaint_after,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = full_output;
|
} = full_output;
|
||||||
|
@ -288,7 +288,7 @@ impl AppRunner {
|
||||||
}
|
}
|
||||||
|
|
||||||
self.frame.info.cpu_usage = Some((now_sec() - frame_start) as f32);
|
self.frame.info.cpu_usage = Some((now_sec() - frame_start) as f32);
|
||||||
Ok((needs_repaint, clipped_primitives))
|
Ok((repaint_after, clipped_primitives))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear_color_buffer(&self) {
|
pub fn clear_color_buffer(&self) {
|
||||||
|
|
|
@ -9,11 +9,12 @@ pub fn paint_and_schedule(
|
||||||
let mut runner_lock = runner_ref.lock();
|
let mut runner_lock = runner_ref.lock();
|
||||||
if runner_lock.needs_repaint.fetch_and_clear() {
|
if runner_lock.needs_repaint.fetch_and_clear() {
|
||||||
runner_lock.clear_color_buffer();
|
runner_lock.clear_color_buffer();
|
||||||
let (needs_repaint, clipped_primitives) = runner_lock.logic()?;
|
let (repaint_after, clipped_primitives) = runner_lock.logic()?;
|
||||||
runner_lock.paint(&clipped_primitives)?;
|
runner_lock.paint(&clipped_primitives)?;
|
||||||
if needs_repaint {
|
if repaint_after.is_zero() {
|
||||||
runner_lock.needs_repaint.set_true();
|
runner_lock.needs_repaint.set_true();
|
||||||
}
|
}
|
||||||
|
// TODO: schedule a repaint after `repaint_after` when it is not zero
|
||||||
runner_lock.auto_save();
|
runner_lock.auto_save();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -479,7 +479,6 @@ impl State {
|
||||||
mutable_text_under_cursor: _, // only used in eframe web
|
mutable_text_under_cursor: _, // only used in eframe web
|
||||||
text_cursor_pos,
|
text_cursor_pos,
|
||||||
} = platform_output;
|
} = platform_output;
|
||||||
|
|
||||||
self.current_pixels_per_point = egui_ctx.pixels_per_point(); // someone can have changed it to scale the UI
|
self.current_pixels_per_point = egui_ctx.pixels_per_point(); // someone can have changed it to scale the UI
|
||||||
|
|
||||||
self.set_cursor_icon(window, cursor_icon);
|
self.set_cursor_icon(window, cursor_icon);
|
||||||
|
|
|
@ -28,7 +28,6 @@ impl Default for WrappedTextureManager {
|
||||||
}
|
}
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Default)]
|
#[derive(Default)]
|
||||||
struct ContextImpl {
|
struct ContextImpl {
|
||||||
/// `None` until the start of the first frame.
|
/// `None` until the start of the first frame.
|
||||||
|
@ -47,7 +46,9 @@ struct ContextImpl {
|
||||||
output: PlatformOutput,
|
output: PlatformOutput,
|
||||||
|
|
||||||
paint_stats: PaintStats,
|
paint_stats: PaintStats,
|
||||||
|
/// the duration backend will poll for new events, before forcing another egui update
|
||||||
|
/// even if there's no new events.
|
||||||
|
repaint_after: std::time::Duration,
|
||||||
/// While positive, keep requesting repaints. Decrement at the end of each frame.
|
/// While positive, keep requesting repaints. Decrement at the end of each frame.
|
||||||
repaint_requests: u32,
|
repaint_requests: u32,
|
||||||
request_repaint_callbacks: Option<Box<dyn Fn() + Send + Sync>>,
|
request_repaint_callbacks: Option<Box<dyn Fn() + Send + Sync>>,
|
||||||
|
@ -574,6 +575,39 @@ impl Context {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Request repaint after the specified duration elapses in the case of no new input
|
||||||
|
/// events being received.
|
||||||
|
///
|
||||||
|
/// The function can be multiple times, but only the *smallest* duration will be considered.
|
||||||
|
/// So, if the function is called two times with `1 second` and `2 seconds`, egui will repaint
|
||||||
|
/// after `1 second`
|
||||||
|
///
|
||||||
|
/// This is primarily useful for applications who would like to save battery by avoiding wasted
|
||||||
|
/// redraws when the app is not in focus. But sometimes the GUI of the app might become stale
|
||||||
|
/// and outdated if it is not updated for too long.
|
||||||
|
///
|
||||||
|
/// Lets say, something like a stop watch widget that displays the time in seconds. You would waste
|
||||||
|
/// resources repainting multiple times within the same second (when you have no input),
|
||||||
|
/// just calculate the difference of duration between current time and next second change,
|
||||||
|
/// and call this function, to make sure that you are displaying the latest updated time, but
|
||||||
|
/// not wasting resources on needless repaints within the same second.
|
||||||
|
///
|
||||||
|
/// NOTE: only works if called before `Context::end_frame()`. to force egui to update,
|
||||||
|
/// use `Context::request_repaint()` instead.
|
||||||
|
///
|
||||||
|
/// ### Quirk:
|
||||||
|
/// Duration begins at the next frame. lets say for example that its a very inefficient app
|
||||||
|
/// and takes 500 milliseconds per frame at 2 fps. The widget / user might want a repaint in
|
||||||
|
/// next 500 milliseconds. Now, app takes 1000 ms per frame (1 fps) because the backend event
|
||||||
|
/// timeout takes 500 milli seconds AFTER the vsync swap buffer.
|
||||||
|
/// So, its not that we are requesting repaint within X duration. We are rather timing out
|
||||||
|
/// during app idle time where we are not receiving any new input events.
|
||||||
|
pub fn request_repaint_after(&self, duration: std::time::Duration) {
|
||||||
|
// Maybe we can check if duration is ZERO, and call self.request_repaint()?
|
||||||
|
let mut ctx = self.write();
|
||||||
|
ctx.repaint_after = ctx.repaint_after.min(duration);
|
||||||
|
}
|
||||||
|
|
||||||
/// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`].
|
/// For integrations: this callback will be called when an egui user calls [`Self::request_repaint`].
|
||||||
///
|
///
|
||||||
/// This lets you wake up a sleeping UI thread.
|
/// This lets you wake up a sleeping UI thread.
|
||||||
|
@ -805,19 +839,26 @@ impl Context {
|
||||||
|
|
||||||
let platform_output: PlatformOutput = std::mem::take(&mut self.output());
|
let platform_output: PlatformOutput = std::mem::take(&mut self.output());
|
||||||
|
|
||||||
let needs_repaint = if self.read().repaint_requests > 0 {
|
// if repaint_requests is greater than zero. just set the duration to zero for immediate
|
||||||
|
// repaint. if there's no repaint requests, then we can use the actual repaint_after instead.
|
||||||
|
let repaint_after = if self.read().repaint_requests > 0 {
|
||||||
self.write().repaint_requests -= 1;
|
self.write().repaint_requests -= 1;
|
||||||
true
|
std::time::Duration::ZERO
|
||||||
} else {
|
} else {
|
||||||
false
|
self.read().repaint_after
|
||||||
};
|
};
|
||||||
self.write().requested_repaint_last_frame = needs_repaint;
|
|
||||||
|
|
||||||
|
self.write().requested_repaint_last_frame = repaint_after.is_zero();
|
||||||
|
// make sure we reset the repaint_after duration.
|
||||||
|
// otherwise, if repaint_after is low, then any widget setting repaint_after next frame,
|
||||||
|
// will fail to overwrite the previous lower value. and thus, repaints will never
|
||||||
|
// go back to higher values.
|
||||||
|
self.write().repaint_after = std::time::Duration::MAX;
|
||||||
let shapes = self.drain_paint_lists();
|
let shapes = self.drain_paint_lists();
|
||||||
|
|
||||||
FullOutput {
|
FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
needs_repaint,
|
repaint_after,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
}
|
}
|
||||||
|
|
|
@ -10,10 +10,15 @@ pub struct FullOutput {
|
||||||
/// Non-rendering related output.
|
/// Non-rendering related output.
|
||||||
pub platform_output: PlatformOutput,
|
pub platform_output: PlatformOutput,
|
||||||
|
|
||||||
/// If `true`, egui is requesting immediate repaint (i.e. on the next frame).
|
/// If `Duration::is_zero()`, egui is requesting immediate repaint (i.e. on the next frame).
|
||||||
///
|
///
|
||||||
/// This happens for instance when there is an animation, or if a user has called `Context::request_repaint()`.
|
/// This happens for instance when there is an animation, or if a user has called `Context::request_repaint()`.
|
||||||
pub needs_repaint: bool,
|
///
|
||||||
|
/// If `Duration` is greater than zero, egui wants to be repainted at or before the specified
|
||||||
|
/// duration elapses. when in reactive mode, egui spends forever waiting for input and only then,
|
||||||
|
/// will it repaint itself. this can be used to make sure that backend will only wait for a
|
||||||
|
/// specified amount of time, and repaint egui without any new input.
|
||||||
|
pub repaint_after: std::time::Duration,
|
||||||
|
|
||||||
/// Texture changes since last frame (including the font texture).
|
/// Texture changes since last frame (including the font texture).
|
||||||
///
|
///
|
||||||
|
@ -32,13 +37,13 @@ impl FullOutput {
|
||||||
pub fn append(&mut self, newer: Self) {
|
pub fn append(&mut self, newer: Self) {
|
||||||
let Self {
|
let Self {
|
||||||
platform_output,
|
platform_output,
|
||||||
needs_repaint,
|
repaint_after,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = newer;
|
} = newer;
|
||||||
|
|
||||||
self.platform_output.append(platform_output);
|
self.platform_output.append(platform_output);
|
||||||
self.needs_repaint = needs_repaint; // if the last frame doesn't need a repaint, then we don't need to repaint
|
self.repaint_after = repaint_after; // if the last frame doesn't need a repaint, then we don't need to repaint
|
||||||
self.textures_delta.append(textures_delta);
|
self.textures_delta.append(textures_delta);
|
||||||
self.shapes = shapes; // Only paint the latest
|
self.shapes = shapes; // Only paint the latest
|
||||||
}
|
}
|
||||||
|
@ -49,7 +54,7 @@ impl FullOutput {
|
||||||
/// You can access (and modify) this with [`crate::Context::output`].
|
/// You can access (and modify) this with [`crate::Context::output`].
|
||||||
///
|
///
|
||||||
/// The backend should use this.
|
/// The backend should use this.
|
||||||
#[derive(Clone, Default, PartialEq)]
|
#[derive(Default, Clone, PartialEq)]
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
pub struct PlatformOutput {
|
pub struct PlatformOutput {
|
||||||
/// Set the cursor to this icon.
|
/// Set the cursor to this icon.
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use egui::Widget;
|
||||||
|
|
||||||
/// How often we repaint the demo app by default
|
/// How often we repaint the demo app by default
|
||||||
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
#[derive(Clone, Copy, Debug, Eq, PartialEq)]
|
||||||
enum RunMode {
|
enum RunMode {
|
||||||
|
@ -41,7 +43,6 @@ impl Default for RunMode {
|
||||||
|
|
||||||
// ----------------------------------------------------------------------------
|
// ----------------------------------------------------------------------------
|
||||||
|
|
||||||
#[derive(Default)]
|
|
||||||
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
#[cfg_attr(feature = "serde", derive(serde::Deserialize, serde::Serialize))]
|
||||||
#[cfg_attr(feature = "serde", serde(default))]
|
#[cfg_attr(feature = "serde", serde(default))]
|
||||||
pub struct BackendPanel {
|
pub struct BackendPanel {
|
||||||
|
@ -51,6 +52,10 @@ pub struct BackendPanel {
|
||||||
// go back to [`Reactive`] mode each time we start
|
// go back to [`Reactive`] mode each time we start
|
||||||
run_mode: RunMode,
|
run_mode: RunMode,
|
||||||
|
|
||||||
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
|
// reset to 1 second as default repaint_after idle timeout.
|
||||||
|
repaint_after_timeout: std::time::Duration,
|
||||||
|
|
||||||
/// current slider value for current gui scale
|
/// current slider value for current gui scale
|
||||||
#[cfg_attr(feature = "serde", serde(skip))]
|
#[cfg_attr(feature = "serde", serde(skip))]
|
||||||
pixels_per_point: Option<f32>,
|
pixels_per_point: Option<f32>,
|
||||||
|
@ -61,14 +66,32 @@ pub struct BackendPanel {
|
||||||
egui_windows: EguiWindows,
|
egui_windows: EguiWindows,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl Default for BackendPanel {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
open: false,
|
||||||
|
run_mode: Default::default(),
|
||||||
|
repaint_after_timeout: std::time::Duration::from_secs(1),
|
||||||
|
pixels_per_point: None,
|
||||||
|
frame_history: Default::default(),
|
||||||
|
egui_windows: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl BackendPanel {
|
impl BackendPanel {
|
||||||
pub fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
pub fn update(&mut self, ctx: &egui::Context, frame: &mut eframe::Frame) {
|
||||||
self.frame_history
|
self.frame_history
|
||||||
.on_new_frame(ctx.input().time, frame.info().cpu_usage);
|
.on_new_frame(ctx.input().time, frame.info().cpu_usage);
|
||||||
|
|
||||||
if self.run_mode == RunMode::Continuous {
|
match self.run_mode {
|
||||||
// Tell the backend to repaint as soon as possible
|
RunMode::Reactive => {
|
||||||
ctx.request_repaint();
|
ctx.request_repaint_after(self.repaint_after_timeout);
|
||||||
|
}
|
||||||
|
RunMode::Continuous => {
|
||||||
|
// Tell the backend to repaint as soon as possible
|
||||||
|
ctx.request_repaint();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -220,6 +243,16 @@ impl BackendPanel {
|
||||||
));
|
));
|
||||||
} else {
|
} else {
|
||||||
ui.label("Only running UI code when there are animations or input.");
|
ui.label("Only running UI code when there are animations or input.");
|
||||||
|
ui.label("but if there's no input for the repaint_after duration, we force an update");
|
||||||
|
ui.label("repaint_after (in seconds)");
|
||||||
|
let mut seconds = self.repaint_after_timeout.as_secs_f32();
|
||||||
|
if egui::DragValue::new(&mut seconds)
|
||||||
|
.clamp_range(0.1..=10.0)
|
||||||
|
.ui(ui)
|
||||||
|
.changed()
|
||||||
|
{
|
||||||
|
self.repaint_after_timeout = std::time::Duration::from_secs_f32(seconds);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,7 +24,7 @@ fn main() {
|
||||||
let mut redraw = || {
|
let mut redraw = || {
|
||||||
let mut quit = false;
|
let mut quit = false;
|
||||||
|
|
||||||
let needs_repaint = egui_glium.run(&display, |egui_ctx| {
|
let repaint_after = egui_glium.run(&display, |egui_ctx| {
|
||||||
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
|
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
|
||||||
if ui
|
if ui
|
||||||
.add(egui::Button::image_and_text(
|
.add(egui::Button::image_and_text(
|
||||||
|
@ -44,9 +44,13 @@ fn main() {
|
||||||
|
|
||||||
*control_flow = if quit {
|
*control_flow = if quit {
|
||||||
glutin::event_loop::ControlFlow::Exit
|
glutin::event_loop::ControlFlow::Exit
|
||||||
} else if needs_repaint {
|
} else if repaint_after.is_zero() {
|
||||||
display.gl_window().window().request_redraw();
|
display.gl_window().window().request_redraw();
|
||||||
glutin::event_loop::ControlFlow::Poll
|
glutin::event_loop::ControlFlow::Poll
|
||||||
|
} else if let Some(repaint_after_instant) =
|
||||||
|
std::time::Instant::now().checked_add(repaint_after)
|
||||||
|
{
|
||||||
|
glutin::event_loop::ControlFlow::WaitUntil(repaint_after_instant)
|
||||||
} else {
|
} else {
|
||||||
glutin::event_loop::ControlFlow::Wait
|
glutin::event_loop::ControlFlow::Wait
|
||||||
};
|
};
|
||||||
|
@ -85,6 +89,11 @@ fn main() {
|
||||||
|
|
||||||
display.gl_window().window().request_redraw(); // TODO(emilk): ask egui if the events warrants a repaint instead
|
display.gl_window().window().request_redraw(); // TODO(emilk): ask egui if the events warrants a repaint instead
|
||||||
}
|
}
|
||||||
|
glutin::event::Event::NewEvents(glutin::event::StartCause::ResumeTimeReached {
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
display.gl_window().window().request_redraw();
|
||||||
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -14,7 +14,7 @@ fn main() {
|
||||||
let mut redraw = || {
|
let mut redraw = || {
|
||||||
let mut quit = false;
|
let mut quit = false;
|
||||||
|
|
||||||
let needs_repaint = egui_glium.run(&display, |egui_ctx| {
|
let repaint_after = egui_glium.run(&display, |egui_ctx| {
|
||||||
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
|
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
|
||||||
ui.heading("Hello World!");
|
ui.heading("Hello World!");
|
||||||
if ui.button("Quit").clicked() {
|
if ui.button("Quit").clicked() {
|
||||||
|
@ -25,9 +25,13 @@ fn main() {
|
||||||
|
|
||||||
*control_flow = if quit {
|
*control_flow = if quit {
|
||||||
glutin::event_loop::ControlFlow::Exit
|
glutin::event_loop::ControlFlow::Exit
|
||||||
} else if needs_repaint {
|
} else if repaint_after.is_zero() {
|
||||||
display.gl_window().window().request_redraw();
|
display.gl_window().window().request_redraw();
|
||||||
glutin::event_loop::ControlFlow::Poll
|
glutin::event_loop::ControlFlow::Poll
|
||||||
|
} else if let Some(repaint_after_instant) =
|
||||||
|
std::time::Instant::now().checked_add(repaint_after)
|
||||||
|
{
|
||||||
|
glutin::event_loop::ControlFlow::WaitUntil(repaint_after_instant)
|
||||||
} else {
|
} else {
|
||||||
glutin::event_loop::ControlFlow::Wait
|
glutin::event_loop::ControlFlow::Wait
|
||||||
};
|
};
|
||||||
|
@ -66,7 +70,11 @@ fn main() {
|
||||||
|
|
||||||
display.gl_window().window().request_redraw(); // TODO(emilk): ask egui if the events warrants a repaint instead
|
display.gl_window().window().request_redraw(); // TODO(emilk): ask egui if the events warrants a repaint instead
|
||||||
}
|
}
|
||||||
|
glutin::event::Event::NewEvents(glutin::event::StartCause::ResumeTimeReached {
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
display.gl_window().window().request_redraw();
|
||||||
|
}
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
|
@ -60,13 +60,17 @@ impl EguiGlium {
|
||||||
/// Returns `true` if egui requests a repaint.
|
/// Returns `true` if egui requests a repaint.
|
||||||
///
|
///
|
||||||
/// Call [`Self::paint`] later to paint.
|
/// Call [`Self::paint`] later to paint.
|
||||||
pub fn run(&mut self, display: &glium::Display, run_ui: impl FnMut(&egui::Context)) -> bool {
|
pub fn run(
|
||||||
|
&mut self,
|
||||||
|
display: &glium::Display,
|
||||||
|
run_ui: impl FnMut(&egui::Context),
|
||||||
|
) -> std::time::Duration {
|
||||||
let raw_input = self
|
let raw_input = self
|
||||||
.egui_winit
|
.egui_winit
|
||||||
.take_egui_input(display.gl_window().window());
|
.take_egui_input(display.gl_window().window());
|
||||||
let egui::FullOutput {
|
let egui::FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
needs_repaint,
|
repaint_after,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = self.egui_ctx.run(raw_input, run_ui);
|
} = self.egui_ctx.run(raw_input, run_ui);
|
||||||
|
@ -80,7 +84,7 @@ impl EguiGlium {
|
||||||
self.shapes = shapes;
|
self.shapes = shapes;
|
||||||
self.textures_delta.append(textures_delta);
|
self.textures_delta.append(textures_delta);
|
||||||
|
|
||||||
needs_repaint
|
repaint_after
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paint the results of the last call to [`Self::run`].
|
/// Paint the results of the last call to [`Self::run`].
|
||||||
|
|
|
@ -16,7 +16,7 @@ fn main() {
|
||||||
let mut redraw = || {
|
let mut redraw = || {
|
||||||
let mut quit = false;
|
let mut quit = false;
|
||||||
|
|
||||||
let needs_repaint = egui_glow.run(gl_window.window(), |egui_ctx| {
|
let repaint_after = egui_glow.run(gl_window.window(), |egui_ctx| {
|
||||||
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
|
egui::SidePanel::left("my_side_panel").show(egui_ctx, |ui| {
|
||||||
ui.heading("Hello World!");
|
ui.heading("Hello World!");
|
||||||
if ui.button("Quit").clicked() {
|
if ui.button("Quit").clicked() {
|
||||||
|
@ -28,9 +28,13 @@ fn main() {
|
||||||
|
|
||||||
*control_flow = if quit {
|
*control_flow = if quit {
|
||||||
glutin::event_loop::ControlFlow::Exit
|
glutin::event_loop::ControlFlow::Exit
|
||||||
} else if needs_repaint {
|
} else if repaint_after.is_zero() {
|
||||||
gl_window.window().request_redraw();
|
gl_window.window().request_redraw();
|
||||||
glutin::event_loop::ControlFlow::Poll
|
glutin::event_loop::ControlFlow::Poll
|
||||||
|
} else if let Some(repaint_after_instant) =
|
||||||
|
std::time::Instant::now().checked_add(repaint_after)
|
||||||
|
{
|
||||||
|
glutin::event_loop::ControlFlow::WaitUntil(repaint_after_instant)
|
||||||
} else {
|
} else {
|
||||||
glutin::event_loop::ControlFlow::Wait
|
glutin::event_loop::ControlFlow::Wait
|
||||||
};
|
};
|
||||||
|
@ -82,6 +86,11 @@ fn main() {
|
||||||
glutin::event::Event::LoopDestroyed => {
|
glutin::event::Event::LoopDestroyed => {
|
||||||
egui_glow.destroy();
|
egui_glow.destroy();
|
||||||
}
|
}
|
||||||
|
glutin::event::Event::NewEvents(glutin::event::StartCause::ResumeTimeReached {
|
||||||
|
..
|
||||||
|
}) => {
|
||||||
|
gl_window.window().request_redraw();
|
||||||
|
}
|
||||||
|
|
||||||
_ => (),
|
_ => (),
|
||||||
}
|
}
|
||||||
|
|
|
@ -41,18 +41,18 @@ impl EguiGlow {
|
||||||
self.egui_winit.on_event(&self.egui_ctx, event)
|
self.egui_winit.on_event(&self.egui_ctx, event)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns `true` if egui requests a repaint.
|
/// Returns the `Duration` of the timeout after which egui should be repainted even if there's no new events.
|
||||||
///
|
///
|
||||||
/// Call [`Self::paint`] later to paint.
|
/// Call [`Self::paint`] later to paint.
|
||||||
pub fn run(
|
pub fn run(
|
||||||
&mut self,
|
&mut self,
|
||||||
window: &winit::window::Window,
|
window: &winit::window::Window,
|
||||||
run_ui: impl FnMut(&egui::Context),
|
run_ui: impl FnMut(&egui::Context),
|
||||||
) -> bool {
|
) -> std::time::Duration {
|
||||||
let raw_input = self.egui_winit.take_egui_input(window);
|
let raw_input = self.egui_winit.take_egui_input(window);
|
||||||
let egui::FullOutput {
|
let egui::FullOutput {
|
||||||
platform_output,
|
platform_output,
|
||||||
needs_repaint,
|
repaint_after,
|
||||||
textures_delta,
|
textures_delta,
|
||||||
shapes,
|
shapes,
|
||||||
} = self.egui_ctx.run(raw_input, run_ui);
|
} = self.egui_ctx.run(raw_input, run_ui);
|
||||||
|
@ -62,7 +62,7 @@ impl EguiGlow {
|
||||||
|
|
||||||
self.shapes = shapes;
|
self.shapes = shapes;
|
||||||
self.textures_delta.append(textures_delta);
|
self.textures_delta.append(textures_delta);
|
||||||
needs_repaint
|
repaint_after
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Paint the results of the last call to [`Self::run`].
|
/// Paint the results of the last call to [`Self::run`].
|
||||||
|
|
Loading…
Reference in a new issue