From 9b9894d8083df4a895a0a123fb534d2c9574e7b1 Mon Sep 17 00:00:00 2001 From: Vladyslav Batyrenko Date: Tue, 30 Jul 2024 23:36:33 +0300 Subject: [PATCH] Fix redraws (#293) * Attempt to reproduce #292 * Fix repaint corner cases --- examples/side_panel.rs | 16 +++++++++++++++- src/systems.rs | 21 +++++++++++++++++++-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/examples/side_panel.rs b/examples/side_panel.rs index 5989f27fc..14e9c56ef 100644 --- a/examples/side_panel.rs +++ b/examples/side_panel.rs @@ -1,4 +1,4 @@ -use bevy::{prelude::*, window::PrimaryWindow}; +use bevy::{prelude::*, window::PrimaryWindow, winit::WinitSettings}; use bevy_egui::{EguiContexts, EguiPlugin}; #[derive(Default, Resource)] @@ -16,6 +16,7 @@ struct OriginalCameraTransform(Transform); fn main() { App::new() + .insert_resource(WinitSettings::desktop_app()) .add_plugins(DefaultPlugins) .add_plugins(EguiPlugin) .init_resource::() @@ -26,6 +27,7 @@ fn main() { } fn ui_example_system( + mut is_last_selected: Local, mut contexts: EguiContexts, mut occupied_screen_space: ResMut, ) { @@ -35,6 +37,18 @@ fn ui_example_system( .resizable(true) .show(ctx, |ui| { ui.label("Left resizeable panel"); + if ui + .add(egui::widgets::Button::new("A button").selected(!*is_last_selected)) + .clicked() + { + *is_last_selected = false; + } + if ui + .add(egui::widgets::Button::new("Another button").selected(*is_last_selected)) + .clicked() + { + *is_last_selected = true; + } ui.allocate_rect(ui.available_rect_before_wrap(), egui::Sense::hover()); }) .response diff --git a/src/systems.rs b/src/systems.rs index d03f64534..abd500e1e 100644 --- a/src/systems.rs +++ b/src/systems.rs @@ -14,11 +14,12 @@ use bevy::{ ButtonState, }, log, - prelude::{Entity, EventReader, Query, Resource, Time}, + prelude::{Entity, EventReader, NonSend, Query, Resource, Time}, time::Real, window::{CursorMoved, RequestRedraw}, + winit::{EventLoopProxy, WakeUp}, }; -use std::marker::PhantomData; +use std::{marker::PhantomData, time::Duration}; #[allow(missing_docs)] #[derive(SystemParam)] @@ -482,6 +483,7 @@ pub fn process_output_system( mut egui_clipboard: bevy::ecs::system::ResMut, mut event: EventWriter, #[cfg(windows)] mut last_cursor_icon: Local>, + event_loop_proxy: Option>>, ) { let mut should_request_redraw = false; @@ -530,6 +532,21 @@ pub fn process_output_system( let needs_repaint = !context.render_output.is_empty(); should_request_redraw |= ctx.has_requested_repaint() && needs_repaint; + // The resource doesn't exist in the headless mode. + if let Some(event_loop_proxy) = &event_loop_proxy { + // A zero duration indicates that it's an outstanding redraw request, which gives Egui an + // opportunity to settle the effects of interactions with widgets. Such repaint requests + // are processed not immediately but on a next frame. In this case, we need to indicate to + // winit, that it needs to wake up next frame as well even if there are no inputs. + // + // TLDR: this solves repaint corner cases of `WinitSettings::desktop_app()`. + if let Some(Duration::ZERO) = + ctx.viewport(|viewport| viewport.input.wants_repaint_after()) + { + let _ = event_loop_proxy.send_event(WakeUp); + } + } + #[cfg(feature = "open_url")] if let Some(egui::output::OpenUrl { url, new_tab }) = platform_output.open_url { let target = if new_tab {