fix some corner cases for repaint requests

This commit is contained in:
Emil Ernerfeldt 2020-08-28 16:41:37 +02:00
parent 0755a95c76
commit a2160a5e12
5 changed files with 27 additions and 11 deletions

View file

@ -190,7 +190,6 @@ impl Prepared {
if move_interact.active { if move_interact.active {
state.pos += input.mouse.delta; state.pos += input.mouse.delta;
state.vel = input.mouse.velocity; state.vel = input.mouse.velocity;
ctx.request_repaint();
} else { } else {
let stop_speed = 20.0; // Pixels per second. let stop_speed = 20.0; // Pixels per second.
let friction_coeff = 1000.0; // Pixels per second squared. 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.visible_last_frame(&layer)
{ {
ctx.memory().areas.move_to_top(layer); ctx.memory().areas.move_to_top(layer);
ctx.request_repaint();
} }
ctx.memory().areas.set_state(layer, state); ctx.memory().areas.set_state(layer, state);

View file

@ -104,7 +104,6 @@ impl State {
let openness = self.openness(ui); let openness = self.openness(ui);
let animate = 0.0 < openness && openness < 1.0; let animate = 0.0 < openness && openness < 1.0;
if animate { if animate {
ui.ctx().request_repaint();
Some(ui.add_custom(|child_ui| { Some(ui.add_custom(|child_ui| {
let max_height = if self.open { let max_height = if self.open {
if let Some(full_height) = self.open_height { if let Some(full_height) = self.open_height {

View file

@ -128,6 +128,8 @@ impl Resize {
let id = self.id.unwrap_or_else(|| ui.make_child_id("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(|| { 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); let default_size = self.default_size.max(self.min_size);
State { State {

View file

@ -1,4 +1,7 @@
use std::sync::Arc; use std::sync::{
atomic::{AtomicU32, Ordering::SeqCst},
Arc,
};
use { use {
ahash::AHashMap, ahash::AHashMap,
@ -38,6 +41,9 @@ pub struct Context {
used_ids: Mutex<AHashMap<Id, Pos2>>, used_ids: Mutex<AHashMap<Id, Pos2>>,
paint_stats: Mutex<PaintStats>, paint_stats: Mutex<PaintStats>,
/// While positive, keep requesting repaints. Decrement at the end of each frame.
repaint_requests: AtomicU32,
} }
impl Clone for Context { impl Clone for Context {
@ -53,6 +59,7 @@ impl Clone for Context {
output: Mutex::new(self.output.lock().clone()), output: Mutex::new(self.output.lock().clone()),
used_ids: Mutex::new(self.used_ids.lock().clone()), used_ids: Mutex::new(self.used_ids.lock().clone()),
paint_stats: Mutex::new(*self.paint_stats.lock()), 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. /// 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. /// Call as many times as you wish, only one repaint will be issued.
pub fn request_repaint(&self) { 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 { pub fn input(&self) -> &InputState {
@ -95,7 +104,7 @@ impl Context {
&*self &*self
.fonts .fonts
.as_ref() .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()` /// Not valid until first call to `begin_frame()`
@ -105,7 +114,7 @@ impl Context {
} }
/// Will become active at the start of the next frame. /// 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) { pub fn set_fonts(&self, font_definitions: FontDefinitions) {
*self.font_definitions.lock() = font_definitions; *self.font_definitions.lock() = font_definitions;
} }
@ -180,7 +189,13 @@ impl Context {
} }
self.memory().end_frame(); 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(); let paint_jobs = self.paint();
(output, paint_jobs) (output, paint_jobs)
} }
@ -574,7 +589,7 @@ impl paint::PaintOptions {
impl PaintStats { impl PaintStats {
pub fn ui(&self, ui: &mut Ui) { pub fn ui(&self, ui: &mut Ui) {
ui.add(label!("Jobs: {}", self.num_jobs)) 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)) ui.add(label!("Primitives: {}", self.num_primitives))
.tooltip_text("Boxes, circles, text areas etc"); .tooltip_text("Boxes, circles, text areas etc");
ui.add(label!("Vertices: {}", self.num_vertices)); ui.add(label!("Vertices: {}", self.num_vertices));

View file

@ -18,9 +18,9 @@ pub struct Output {
/// Response to Event::Copy or Event::Cut. Ignore if empty. /// Response to Event::Copy or Event::Cut. Ignore if empty.
pub copied_text: String, pub copied_text: String,
/// Set to `true` to request another repaint right after this one. /// If `true`, Egui or a user is indicating that the UI needs immediate repaint (e.g. on the next frame).
/// This is only used in reactive backends (i.e. backends where we repaint on new input). /// This happens for instance when there is an animation, or if a user has called `Context::request_repaint()`.
/// For instance, you may want to set this to `true` while there is an animation. /// Don't set this manually, but call `Context::request_repaint()` instead.
pub needs_repaint: bool, pub needs_repaint: bool,
} }