From a2160a5e12b3beae62fecadcd779a25afdcee18f Mon Sep 17 00:00:00 2001 From: Emil Ernerfeldt Date: Fri, 28 Aug 2020 16:41:37 +0200 Subject: [PATCH] fix some corner cases for repaint requests --- egui/src/containers/area.rs | 2 +- egui/src/containers/collapsing_header.rs | 1 - egui/src/containers/resize.rs | 2 ++ egui/src/context.rs | 27 ++++++++++++++++++------ egui/src/types.rs | 6 +++--- 5 files changed, 27 insertions(+), 11 deletions(-) diff --git a/egui/src/containers/area.rs b/egui/src/containers/area.rs index 1e13de86..295ca74c 100644 --- a/egui/src/containers/area.rs +++ b/egui/src/containers/area.rs @@ -190,7 +190,6 @@ impl Prepared { if move_interact.active { state.pos += input.mouse.delta; state.vel = input.mouse.velocity; - ctx.request_repaint(); } else { let stop_speed = 20.0; // Pixels per second. let friction_coeff = 1000.0; // Pixels per second squared. @@ -225,6 +224,7 @@ impl Prepared { || !ctx.memory().areas.visible_last_frame(&layer) { ctx.memory().areas.move_to_top(layer); + ctx.request_repaint(); } ctx.memory().areas.set_state(layer, state); diff --git a/egui/src/containers/collapsing_header.rs b/egui/src/containers/collapsing_header.rs index e50dbb38..72ff0958 100644 --- a/egui/src/containers/collapsing_header.rs +++ b/egui/src/containers/collapsing_header.rs @@ -104,7 +104,6 @@ impl State { let openness = self.openness(ui); let animate = 0.0 < openness && openness < 1.0; if animate { - ui.ctx().request_repaint(); Some(ui.add_custom(|child_ui| { let max_height = if self.open { if let Some(full_height) = self.open_height { diff --git a/egui/src/containers/resize.rs b/egui/src/containers/resize.rs index c0facb3a..001ba4a0 100644 --- a/egui/src/containers/resize.rs +++ b/egui/src/containers/resize.rs @@ -128,6 +128,8 @@ impl Resize { let id = self.id.unwrap_or_else(|| ui.make_child_id("resize")); let mut state = ui.memory().resize.get(&id).cloned().unwrap_or_else(|| { + ui.ctx().request_repaint(); // counter frame delay + let default_size = self.default_size.max(self.min_size); State { diff --git a/egui/src/context.rs b/egui/src/context.rs index 1f7b1477..6fa54039 100644 --- a/egui/src/context.rs +++ b/egui/src/context.rs @@ -1,4 +1,7 @@ -use std::sync::Arc; +use std::sync::{ + atomic::{AtomicU32, Ordering::SeqCst}, + Arc, +}; use { ahash::AHashMap, @@ -38,6 +41,9 @@ pub struct Context { used_ids: Mutex>, paint_stats: Mutex, + + /// While positive, keep requesting repaints. Decrement at the end of each frame. + repaint_requests: AtomicU32, } impl Clone for Context { @@ -53,6 +59,7 @@ impl Clone for Context { output: Mutex::new(self.output.lock().clone()), used_ids: Mutex::new(self.used_ids.lock().clone()), paint_stats: Mutex::new(*self.paint_stats.lock()), + repaint_requests: self.repaint_requests.load(SeqCst).into(), } } } @@ -82,7 +89,9 @@ impl Context { /// If this is called at least once in a frame, then there will be another frame right after this. /// Call as many times as you wish, only one repaint will be issued. pub fn request_repaint(&self) { - self.output().needs_repaint = true; + // request two frames of repaint, just to cover some corner cases (frame delays): + let times_to_repaint = 2; + self.repaint_requests.store(times_to_repaint, SeqCst); } pub fn input(&self) -> &InputState { @@ -95,7 +104,7 @@ impl Context { &*self .fonts .as_ref() - .expect("No fonts available until first call to Contex::begin_frame()`") + .expect("No fonts available until first call to Context::begin_frame()`") } /// Not valid until first call to `begin_frame()` @@ -105,7 +114,7 @@ impl Context { } /// Will become active at the start of the next frame. - /// `pixels_per_point` will be ignored (overwitten at start of each frame with the contents of input) + /// `pixels_per_point` will be ignored (overwritten at start of each frame with the contents of input) pub fn set_fonts(&self, font_definitions: FontDefinitions) { *self.font_definitions.lock() = font_definitions; } @@ -180,7 +189,13 @@ impl Context { } self.memory().end_frame(); - let output: Output = std::mem::take(&mut self.output()); + + let mut output: Output = std::mem::take(&mut self.output()); + if self.repaint_requests.load(SeqCst) > 0 { + self.repaint_requests.fetch_sub(1, SeqCst); + output.needs_repaint = true; + } + let paint_jobs = self.paint(); (output, paint_jobs) } @@ -574,7 +589,7 @@ impl paint::PaintOptions { impl PaintStats { pub fn ui(&self, ui: &mut Ui) { ui.add(label!("Jobs: {}", self.num_jobs)) - .tooltip_text("Number of separate clip rectanlges"); + .tooltip_text("Number of separate clip rectangles"); ui.add(label!("Primitives: {}", self.num_primitives)) .tooltip_text("Boxes, circles, text areas etc"); ui.add(label!("Vertices: {}", self.num_vertices)); diff --git a/egui/src/types.rs b/egui/src/types.rs index 0474fca8..bd85fc30 100644 --- a/egui/src/types.rs +++ b/egui/src/types.rs @@ -18,9 +18,9 @@ pub struct Output { /// Response to Event::Copy or Event::Cut. Ignore if empty. pub copied_text: String, - /// Set to `true` to request another repaint right after this one. - /// This is only used in reactive backends (i.e. backends where we repaint on new input). - /// For instance, you may want to set this to `true` while there is an animation. + /// If `true`, Egui or a user is indicating that the UI needs immediate repaint (e.g. on the next frame). + /// This happens for instance when there is an animation, or if a user has called `Context::request_repaint()`. + /// Don't set this manually, but call `Context::request_repaint()` instead. pub needs_repaint: bool, }