Preserve tooltips requested by cached views
Co-Authored-By: Nathan <nathan@zed.dev> Co-Authored-By: Max <max@zed.dev>
This commit is contained in:
parent
90f4c70a82
commit
69bbcba99a
4 changed files with 49 additions and 19 deletions
|
@ -196,7 +196,6 @@ pub struct AppContext {
|
||||||
pending_updates: usize,
|
pending_updates: usize,
|
||||||
pub(crate) actions: Rc<ActionRegistry>,
|
pub(crate) actions: Rc<ActionRegistry>,
|
||||||
pub(crate) active_drag: Option<AnyDrag>,
|
pub(crate) active_drag: Option<AnyDrag>,
|
||||||
pub(crate) active_tooltip: Option<AnyTooltip>,
|
|
||||||
pub(crate) next_frame_callbacks: FxHashMap<DisplayId, Vec<FrameCallback>>,
|
pub(crate) next_frame_callbacks: FxHashMap<DisplayId, Vec<FrameCallback>>,
|
||||||
pub(crate) frame_consumers: FxHashMap<DisplayId, Task<()>>,
|
pub(crate) frame_consumers: FxHashMap<DisplayId, Task<()>>,
|
||||||
pub(crate) background_executor: BackgroundExecutor,
|
pub(crate) background_executor: BackgroundExecutor,
|
||||||
|
@ -258,7 +257,6 @@ impl AppContext {
|
||||||
flushing_effects: false,
|
flushing_effects: false,
|
||||||
pending_updates: 0,
|
pending_updates: 0,
|
||||||
active_drag: None,
|
active_drag: None,
|
||||||
active_tooltip: None,
|
|
||||||
next_frame_callbacks: FxHashMap::default(),
|
next_frame_callbacks: FxHashMap::default(),
|
||||||
frame_consumers: FxHashMap::default(),
|
frame_consumers: FxHashMap::default(),
|
||||||
background_executor: executor,
|
background_executor: executor,
|
||||||
|
@ -1268,8 +1266,10 @@ pub struct AnyDrag {
|
||||||
pub cursor_offset: Point<Pixels>,
|
pub cursor_offset: Point<Pixels>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Contains state associated with a tooltip. You'll only need this struct if you're implementing
|
||||||
|
/// tooltip behavior on a custom element. Otherwise, use [Div::tooltip].
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub(crate) struct AnyTooltip {
|
pub struct AnyTooltip {
|
||||||
pub view: AnyView,
|
pub view: AnyView,
|
||||||
pub cursor_offset: Point<Pixels>,
|
pub cursor_offset: Point<Pixels>,
|
||||||
}
|
}
|
||||||
|
|
|
@ -1433,8 +1433,8 @@ impl Interactivity {
|
||||||
.borrow()
|
.borrow()
|
||||||
.as_ref()
|
.as_ref()
|
||||||
{
|
{
|
||||||
if active_tooltip.tooltip.is_some() {
|
if let Some(tooltip) = active_tooltip.tooltip.clone() {
|
||||||
cx.active_tooltip = active_tooltip.tooltip.clone()
|
cx.set_tooltip(tooltip);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -112,7 +112,7 @@ impl DispatchTree {
|
||||||
target.action_listeners = mem::take(&mut source.action_listeners);
|
target.action_listeners = mem::take(&mut source.action_listeners);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn graft(&mut self, view_id: EntityId, source: &mut Self) -> SmallVec<[EntityId; 8]> {
|
pub fn reuse_view(&mut self, view_id: EntityId, source: &mut Self) -> SmallVec<[EntityId; 8]> {
|
||||||
let view_source_node_id = source
|
let view_source_node_id = source
|
||||||
.view_node_ids
|
.view_node_ids
|
||||||
.get(&view_id)
|
.get(&view_id)
|
||||||
|
|
|
@ -1,10 +1,10 @@
|
||||||
#![deny(missing_docs)]
|
#![deny(missing_docs)]
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, AsyncWindowContext,
|
px, size, transparent_black, Action, AnyDrag, AnyTooltip, AnyView, AppContext, Arena,
|
||||||
AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels,
|
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
|
||||||
DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
|
DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
|
||||||
EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
|
Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
|
||||||
ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId,
|
ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId,
|
||||||
Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent,
|
Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent,
|
||||||
Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
|
||||||
|
@ -300,6 +300,11 @@ struct RequestedInputHandler {
|
||||||
handler: Option<Box<dyn PlatformInputHandler>>,
|
handler: Option<Box<dyn PlatformInputHandler>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct TooltipRequest {
|
||||||
|
view_id: EntityId,
|
||||||
|
tooltip: AnyTooltip,
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) struct Frame {
|
pub(crate) struct Frame {
|
||||||
focus: Option<FocusId>,
|
focus: Option<FocusId>,
|
||||||
window_active: bool,
|
window_active: bool,
|
||||||
|
@ -313,6 +318,7 @@ pub(crate) struct Frame {
|
||||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||||
element_offset_stack: Vec<Point<Pixels>>,
|
element_offset_stack: Vec<Point<Pixels>>,
|
||||||
requested_input_handler: Option<RequestedInputHandler>,
|
requested_input_handler: Option<RequestedInputHandler>,
|
||||||
|
tooltip_request: Option<TooltipRequest>,
|
||||||
cursor_styles: FxHashMap<EntityId, CursorStyle>,
|
cursor_styles: FxHashMap<EntityId, CursorStyle>,
|
||||||
requested_cursor_style: Option<CursorStyle>,
|
requested_cursor_style: Option<CursorStyle>,
|
||||||
pub(crate) view_stack: Vec<EntityId>,
|
pub(crate) view_stack: Vec<EntityId>,
|
||||||
|
@ -328,12 +334,13 @@ impl Frame {
|
||||||
mouse_listeners: FxHashMap::default(),
|
mouse_listeners: FxHashMap::default(),
|
||||||
dispatch_tree,
|
dispatch_tree,
|
||||||
scene: Scene::default(),
|
scene: Scene::default(),
|
||||||
|
depth_map: Vec::new(),
|
||||||
z_index_stack: StackingOrder::default(),
|
z_index_stack: StackingOrder::default(),
|
||||||
next_stacking_order_id: 0,
|
next_stacking_order_id: 0,
|
||||||
depth_map: Vec::new(),
|
|
||||||
content_mask_stack: Vec::new(),
|
content_mask_stack: Vec::new(),
|
||||||
element_offset_stack: Vec::new(),
|
element_offset_stack: Vec::new(),
|
||||||
requested_input_handler: None,
|
requested_input_handler: None,
|
||||||
|
tooltip_request: None,
|
||||||
cursor_styles: FxHashMap::default(),
|
cursor_styles: FxHashMap::default(),
|
||||||
requested_cursor_style: None,
|
requested_cursor_style: None,
|
||||||
view_stack: Vec::new(),
|
view_stack: Vec::new(),
|
||||||
|
@ -350,6 +357,7 @@ impl Frame {
|
||||||
self.reused_views.clear();
|
self.reused_views.clear();
|
||||||
self.scene.clear();
|
self.scene.clear();
|
||||||
self.requested_input_handler.take();
|
self.requested_input_handler.take();
|
||||||
|
self.tooltip_request.take();
|
||||||
self.cursor_styles.clear();
|
self.cursor_styles.clear();
|
||||||
self.requested_cursor_style.take();
|
self.requested_cursor_style.take();
|
||||||
debug_assert_eq!(self.view_stack.len(), 0);
|
debug_assert_eq!(self.view_stack.len(), 0);
|
||||||
|
@ -1052,6 +1060,12 @@ impl<'a> WindowContext<'a> {
|
||||||
self.window.next_frame.requested_cursor_style = Some(style);
|
self.window.next_frame.requested_cursor_style = Some(style);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Set a tooltip to be rendered for the upcoming frame
|
||||||
|
pub fn set_tooltip(&mut self, tooltip: AnyTooltip) {
|
||||||
|
let view_id = self.parent_view_id();
|
||||||
|
self.window.next_frame.tooltip_request = Some(TooltipRequest { view_id, tooltip });
|
||||||
|
}
|
||||||
|
|
||||||
/// Called during painting to track which z-index is on top at each pixel position
|
/// Called during painting to track which z-index is on top at each pixel position
|
||||||
pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
|
pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
|
||||||
let stacking_order = self.window.next_frame.z_index_stack.clone();
|
let stacking_order = self.window.next_frame.z_index_stack.clone();
|
||||||
|
@ -1432,12 +1446,11 @@ impl<'a> WindowContext<'a> {
|
||||||
.window
|
.window
|
||||||
.next_frame
|
.next_frame
|
||||||
.dispatch_tree
|
.dispatch_tree
|
||||||
.graft(view_id, &mut self.window.rendered_frame.dispatch_tree);
|
.reuse_view(view_id, &mut self.window.rendered_frame.dispatch_tree);
|
||||||
for view_id in grafted_view_ids {
|
for view_id in grafted_view_ids {
|
||||||
assert!(self.window.next_frame.reused_views.insert(view_id));
|
assert!(self.window.next_frame.reused_views.insert(view_id));
|
||||||
|
|
||||||
// Reuse the previous input handler if it was associated with one of
|
// Reuse the previous input handler requested during painting of the reused view.
|
||||||
// the views grafted from the tree in the previous frame.
|
|
||||||
if self
|
if self
|
||||||
.window
|
.window
|
||||||
.rendered_frame
|
.rendered_frame
|
||||||
|
@ -1449,6 +1462,19 @@ impl<'a> WindowContext<'a> {
|
||||||
self.window.rendered_frame.requested_input_handler.take();
|
self.window.rendered_frame.requested_input_handler.take();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Reuse the tooltip previously requested during painting of the reused view.
|
||||||
|
if self
|
||||||
|
.window
|
||||||
|
.rendered_frame
|
||||||
|
.tooltip_request
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |requested| requested.view_id == view_id)
|
||||||
|
{
|
||||||
|
self.window.next_frame.tooltip_request =
|
||||||
|
self.window.rendered_frame.tooltip_request.take();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reuse the cursor styles previously requested during painting of the reused view.
|
||||||
if let Some(style) = self.window.rendered_frame.cursor_styles.remove(&view_id) {
|
if let Some(style) = self.window.rendered_frame.cursor_styles.remove(&view_id) {
|
||||||
self.window.next_frame.cursor_styles.insert(view_id, style);
|
self.window.next_frame.cursor_styles.insert(view_id, style);
|
||||||
self.window.next_frame.requested_cursor_style = Some(style);
|
self.window.next_frame.requested_cursor_style = Some(style);
|
||||||
|
@ -1498,13 +1524,16 @@ impl<'a> WindowContext<'a> {
|
||||||
active_drag.view.draw(offset, available_space, cx);
|
active_drag.view.draw(offset, available_space, cx);
|
||||||
});
|
});
|
||||||
self.active_drag = Some(active_drag);
|
self.active_drag = Some(active_drag);
|
||||||
} else if let Some(active_tooltip) = self.app.active_tooltip.take() {
|
} else if let Some(tooltip_request) = self.window.next_frame.tooltip_request.take() {
|
||||||
self.with_z_index(1, |cx| {
|
self.with_z_index(1, |cx| {
|
||||||
let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
let available_space = size(AvailableSpace::MinContent, AvailableSpace::MinContent);
|
||||||
active_tooltip
|
tooltip_request.tooltip.view.draw(
|
||||||
.view
|
tooltip_request.tooltip.cursor_offset,
|
||||||
.draw(active_tooltip.cursor_offset, available_space, cx);
|
available_space,
|
||||||
|
cx,
|
||||||
|
);
|
||||||
});
|
});
|
||||||
|
self.window.next_frame.tooltip_request = Some(tooltip_request);
|
||||||
}
|
}
|
||||||
self.window.dirty_views.clear();
|
self.window.dirty_views.clear();
|
||||||
|
|
||||||
|
@ -2145,7 +2174,8 @@ impl<'a> WindowContext<'a> {
|
||||||
|
|
||||||
/// Set an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
|
/// Set an input handler, such as [`ElementInputHandler`][element_input_handler], which interfaces with the
|
||||||
/// platform to receive textual input with proper integration with concerns such
|
/// platform to receive textual input with proper integration with concerns such
|
||||||
/// as IME interactions.
|
/// as IME interactions. This handler will be active for the upcoming frame until the following frame is
|
||||||
|
/// rendered.
|
||||||
///
|
///
|
||||||
/// [element_input_handler]: crate::ElementInputHandler
|
/// [element_input_handler]: crate::ElementInputHandler
|
||||||
pub fn handle_input(
|
pub fn handle_input(
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue