-
Notifications
You must be signed in to change notification settings - Fork 1.9k
Description
Describe the bug
This is a bit of an odd case and took me a long time to track down.
Use case:
Two windows - a primary and a secondary.
Primary window requires re-painting at 60fps (rendering animations/frames/etc)
Secondary window only requires re-painting in response to user interaction (e.g. a preferences window)
Trying to select text in the secondary window works fine only when it's the one being repainted. If the primary window repaints after selection has started, selection is cleared.
The relevant lines of code are from the label_text_selection.rs module:
if !state.has_reached_primary || !state.has_reached_secondary {
// We didn't see both cursors this frame,
// maybe because they are outside the visible area (scrolling),
// or one disappeared. In either case we will have horrible glitches, so let's just deselect.
let prev_selection = state.selection.take();I suspect the reason this happens is because the store/load happening for the temporary selection state is not keyed at all by viewport, and because deferred viewports require their own begin/end frame cycle it ends up clearing the selection since the primary window was repainted and no widgets matched the current selection state.
pub fn load(ctx: &Context) -> Self {
ctx.data(|data| data.get_temp::<Self>(Id::NULL))
.unwrap_or_default()
}
pub fn store(self, ctx: &Context) {
ctx.data_mut(|data| {
data.insert_temp(Id::NULL, self);
});
}To Reproduce
- Modify the test_viewports example to add a
ctx.request_repaint_of(ViewportId::ROOT);to the mainupdatemethod - Open a deferred viewport and try to select a label - it gets immediately cleared
- Open an immediate viewport and try to select a label - works as expected
Expected behavior
I'd expect selecting labels to work correctly
Desktop (please complete the following information):
- OS: Linux
Additional context
I was able to get a working version with the following. If it's acceptable, I can create a PR:
pub fn load(ctx: &Context) -> Self {
let id = Id::new(ctx.viewport_id());
ctx.data(|data| data.get_temp::<Self>(id))
.unwrap_or_default()
}
pub fn store(self, ctx: &Context) {
let id = Id::new(ctx.viewport_id());
ctx.data_mut(|data| {
data.insert_temp(id, self);
});
}