parent
143119943d
commit
977d83a08f
|
@ -1442,6 +1442,16 @@ impl Context {
|
|||
self.request_repaint_after_for(duration, self.viewport_id());
|
||||
}
|
||||
|
||||
/// Repaint after this many seconds.
|
||||
///
|
||||
/// See [`Self::request_repaint_after`] for details.
|
||||
#[track_caller]
|
||||
pub fn request_repaint_after_secs(&self, seconds: f32) {
|
||||
if let Ok(duration) = std::time::Duration::try_from_secs_f32(seconds) {
|
||||
self.request_repaint_after(duration);
|
||||
}
|
||||
}
|
||||
|
||||
/// Request repaint after at most the specified duration elapses.
|
||||
///
|
||||
/// The backend can chose to repaint sooner, for instance if some other code called
|
||||
|
|
|
@ -44,6 +44,12 @@ pub struct InputState {
|
|||
/// (We keep a separate [`TouchState`] for each encountered touch device.)
|
||||
touch_states: BTreeMap<TouchDeviceId, TouchState>,
|
||||
|
||||
// ----------------------------------------------
|
||||
// Scrolling:
|
||||
//
|
||||
/// Time of the last scroll event.
|
||||
last_scroll_time: f64,
|
||||
|
||||
/// Used for smoothing the scroll delta.
|
||||
unprocessed_scroll_delta: Vec2,
|
||||
|
||||
|
@ -87,6 +93,7 @@ pub struct InputState {
|
|||
/// * `zoom > 1`: pinch spread
|
||||
zoom_factor_delta: f32,
|
||||
|
||||
// ----------------------------------------------
|
||||
/// Position and size of the egui area.
|
||||
pub screen_rect: Rect,
|
||||
|
||||
|
@ -161,11 +168,14 @@ impl Default for InputState {
|
|||
raw: Default::default(),
|
||||
pointer: Default::default(),
|
||||
touch_states: Default::default(),
|
||||
|
||||
last_scroll_time: f64::NEG_INFINITY,
|
||||
unprocessed_scroll_delta: Vec2::ZERO,
|
||||
unprocessed_scroll_delta_for_zoom: 0.0,
|
||||
raw_scroll_delta: Vec2::ZERO,
|
||||
smooth_scroll_delta: Vec2::ZERO,
|
||||
zoom_factor_delta: 1.0,
|
||||
|
||||
screen_rect: Rect::from_min_size(Default::default(), vec2(10_000.0, 10_000.0)),
|
||||
pixels_per_point: 1.0,
|
||||
max_texture_side: 2048,
|
||||
|
@ -320,14 +330,24 @@ impl InputState {
|
|||
}
|
||||
}
|
||||
|
||||
let is_scrolling = raw_scroll_delta != Vec2::ZERO || smooth_scroll_delta != Vec2::ZERO;
|
||||
let last_scroll_time = if is_scrolling {
|
||||
time
|
||||
} else {
|
||||
self.last_scroll_time
|
||||
};
|
||||
|
||||
Self {
|
||||
pointer,
|
||||
touch_states: self.touch_states,
|
||||
|
||||
last_scroll_time,
|
||||
unprocessed_scroll_delta,
|
||||
unprocessed_scroll_delta_for_zoom,
|
||||
raw_scroll_delta,
|
||||
smooth_scroll_delta,
|
||||
zoom_factor_delta,
|
||||
|
||||
screen_rect,
|
||||
pixels_per_point,
|
||||
max_texture_side: new.max_texture_side.unwrap_or(self.max_texture_side),
|
||||
|
@ -393,6 +413,12 @@ impl InputState {
|
|||
)
|
||||
}
|
||||
|
||||
/// How long has it been (in seconds) since the use last scrolled?
|
||||
#[inline(always)]
|
||||
pub fn time_since_last_scroll(&self) -> f32 {
|
||||
(self.time - self.last_scroll_time) as f32
|
||||
}
|
||||
|
||||
/// The [`crate::Context`] will call this at the end of each frame to see if we need a repaint.
|
||||
///
|
||||
/// Returns how long to wait for a repaint.
|
||||
|
@ -1218,6 +1244,7 @@ impl InputState {
|
|||
pointer,
|
||||
touch_states,
|
||||
|
||||
last_scroll_time,
|
||||
unprocessed_scroll_delta,
|
||||
unprocessed_scroll_delta_for_zoom,
|
||||
raw_scroll_delta,
|
||||
|
@ -1257,6 +1284,10 @@ impl InputState {
|
|||
});
|
||||
}
|
||||
|
||||
ui.label(format!(
|
||||
"Time since last scroll: {:.1} s",
|
||||
time - last_scroll_time
|
||||
));
|
||||
if cfg!(debug_assertions) {
|
||||
ui.label(format!(
|
||||
"unprocessed_scroll_delta: {unprocessed_scroll_delta:?} points"
|
||||
|
@ -1270,6 +1301,7 @@ impl InputState {
|
|||
"smooth_scroll_delta: {smooth_scroll_delta:?} points"
|
||||
));
|
||||
ui.label(format!("zoom_factor_delta: {zoom_factor_delta:4.2}x"));
|
||||
|
||||
ui.label(format!("screen_rect: {screen_rect:?} points"));
|
||||
ui.label(format!(
|
||||
"{pixels_per_point} physical pixels for each logical point"
|
||||
|
|
|
@ -611,6 +611,21 @@ impl Response {
|
|||
return false;
|
||||
}
|
||||
|
||||
let style = self.ctx.style();
|
||||
|
||||
let tooltip_delay = style.interaction.tooltip_delay;
|
||||
let tooltip_grace_time = style.interaction.tooltip_grace_time;
|
||||
|
||||
let time_since_last_scroll = self.ctx.input(|i| i.time_since_last_scroll());
|
||||
|
||||
if time_since_last_scroll < tooltip_delay {
|
||||
// See https://github.com/emilk/egui/issues/4781
|
||||
// Note that this means we cannot have `ScrollArea`s in a tooltip.
|
||||
self.ctx
|
||||
.request_repaint_after_secs(tooltip_delay - time_since_last_scroll);
|
||||
return false;
|
||||
}
|
||||
|
||||
let is_our_tooltip_open = self.is_tooltip_open();
|
||||
|
||||
if is_our_tooltip_open {
|
||||
|
@ -680,9 +695,6 @@ impl Response {
|
|||
return false;
|
||||
}
|
||||
|
||||
let tooltip_delay = self.ctx.style().interaction.tooltip_delay;
|
||||
let tooltip_grace_time = self.ctx.style().interaction.tooltip_grace_time;
|
||||
|
||||
// There is a tooltip_delay before showing the first tooltip,
|
||||
// but once one tooltips is show, moving the mouse cursor to
|
||||
// another widget should show the tooltip for that widget right away.
|
||||
|
@ -692,23 +704,27 @@ impl Response {
|
|||
crate::popup::seconds_since_last_tooltip(&self.ctx) < tooltip_grace_time;
|
||||
|
||||
if !tooltip_was_recently_shown && !is_our_tooltip_open {
|
||||
if self.ctx.style().interaction.show_tooltips_only_when_still {
|
||||
if style.interaction.show_tooltips_only_when_still {
|
||||
// We only show the tooltip when the mouse pointer is still.
|
||||
if !self.ctx.input(|i| i.pointer.is_still()) {
|
||||
if !self
|
||||
.ctx
|
||||
.input(|i| i.pointer.is_still() && i.smooth_scroll_delta == Vec2::ZERO)
|
||||
{
|
||||
// wait for mouse to stop
|
||||
self.ctx.request_repaint();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
let time_til_tooltip =
|
||||
tooltip_delay - self.ctx.input(|i| i.pointer.time_since_last_movement());
|
||||
let time_since_last_interaction = self.ctx.input(|i| {
|
||||
i.time_since_last_scroll()
|
||||
.max(i.pointer.time_since_last_movement())
|
||||
});
|
||||
let time_til_tooltip = tooltip_delay - time_since_last_interaction;
|
||||
|
||||
if 0.0 < time_til_tooltip {
|
||||
// Wait until the mouse has been still for a while
|
||||
if let Ok(duration) = std::time::Duration::try_from_secs_f32(time_til_tooltip) {
|
||||
self.ctx.request_repaint_after(duration);
|
||||
}
|
||||
self.ctx.request_repaint_after_secs(time_til_tooltip);
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -99,8 +99,7 @@ pub fn paint_text_cursor(
|
|||
total_duration - time_in_cycle
|
||||
};
|
||||
|
||||
ui.ctx()
|
||||
.request_repaint_after(std::time::Duration::from_secs_f32(wake_in));
|
||||
ui.ctx().request_repaint_after_secs(wake_in);
|
||||
} else {
|
||||
paint_cursor_end(painter, ui.visuals(), primary_cursor_rect);
|
||||
}
|
||||
|
|
|
@ -19,7 +19,8 @@ impl crate::Demo for Tooltips {
|
|||
use crate::View as _;
|
||||
let window = egui::Window::new("Tooltips")
|
||||
.constrain(false) // So we can test how tooltips behave close to the screen edge
|
||||
.resizable(false)
|
||||
.resizable(true)
|
||||
.default_size([450.0, 300.0])
|
||||
.scroll(false)
|
||||
.open(open);
|
||||
window.show(ctx, |ui| self.ui(ui));
|
||||
|
@ -34,6 +35,34 @@ impl crate::View for Tooltips {
|
|||
ui.add(crate::egui_github_link_file_line!());
|
||||
});
|
||||
|
||||
egui::SidePanel::right("scroll_test").show_inside(ui, |ui| {
|
||||
ui.label(
|
||||
"The scroll area below has many labels with interactive tooltips. \
|
||||
The purpose is to test that the tooltips close when you scroll.",
|
||||
)
|
||||
.on_hover_text("Try hovering a label below, then scroll!");
|
||||
egui::ScrollArea::vertical()
|
||||
.auto_shrink(false)
|
||||
.show(ui, |ui| {
|
||||
for i in 0..1000 {
|
||||
ui.label(format!("This is line {i}")).on_hover_ui(|ui| {
|
||||
ui.style_mut().interaction.selectable_labels = true;
|
||||
ui.label(
|
||||
"This tooltip is interactive, because the text in it is selectable.",
|
||||
);
|
||||
});
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
egui::CentralPanel::default().show_inside(ui, |ui| {
|
||||
self.misc_tests(ui);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl Tooltips {
|
||||
fn misc_tests(&mut self, ui: &mut egui::Ui) {
|
||||
ui.label("All labels in this demo have tooltips.")
|
||||
.on_hover_text("Yes, even this one.");
|
||||
|
||||
|
|
Loading…
Reference in New Issue