Moved Frame struct into element context, to be close to it's associated methods
This commit is contained in:
parent
c05edee2b5
commit
b65cae5874
7 changed files with 218 additions and 233 deletions
|
@ -23,12 +23,11 @@
|
||||||
//!
|
//!
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
|
point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds, ClickEvent,
|
||||||
Bounds, ClickEvent, DispatchPhase, Element, ElementContext, ElementId, FocusHandle,
|
DispatchPhase, Element, ElementContext, ElementId, FocusHandle, IntoElement, IsZero,
|
||||||
IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton,
|
KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
|
||||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render,
|
MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size,
|
||||||
ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task,
|
StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility, WindowContext,
|
||||||
View, Visibility, WindowContext,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
use collections::HashMap;
|
use collections::HashMap;
|
||||||
|
|
|
@ -7,8 +7,8 @@
|
||||||
//! If all of your elements are the same height, see [`UniformList`] for a simpler API
|
//! If all of your elements are the same height, see [`UniformList`] for a simpler API
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
point, px, AnyElement, AvailableSpace, BorrowAppContext, Bounds, ContentMask, DispatchPhase,
|
point, px, AnyElement, AvailableSpace, Bounds, ContentMask, DispatchPhase, Element,
|
||||||
Element, IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, StyleRefinement, Styled,
|
IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, StyleRefinement, Styled,
|
||||||
WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
use collections::VecDeque;
|
use collections::VecDeque;
|
||||||
|
|
|
@ -220,11 +220,6 @@ pub trait EventEmitter<E: Any>: 'static {}
|
||||||
/// A helper trait for auto-implementing certain methods on contexts that
|
/// A helper trait for auto-implementing certain methods on contexts that
|
||||||
/// can be used interchangeably.
|
/// can be used interchangeably.
|
||||||
pub trait BorrowAppContext {
|
pub trait BorrowAppContext {
|
||||||
/// Run a closure with a text style pushed onto the context.
|
|
||||||
fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self) -> R;
|
|
||||||
|
|
||||||
/// Set a global value on the context.
|
/// Set a global value on the context.
|
||||||
fn set_global<T: 'static>(&mut self, global: T);
|
fn set_global<T: 'static>(&mut self, global: T);
|
||||||
}
|
}
|
||||||
|
@ -233,20 +228,6 @@ impl<C> BorrowAppContext for C
|
||||||
where
|
where
|
||||||
C: BorrowMut<AppContext>,
|
C: BorrowMut<AppContext>,
|
||||||
{
|
{
|
||||||
fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
|
|
||||||
where
|
|
||||||
F: FnOnce(&mut Self) -> R,
|
|
||||||
{
|
|
||||||
if let Some(style) = style {
|
|
||||||
self.borrow_mut().push_text_style(style);
|
|
||||||
let result = f(self);
|
|
||||||
self.borrow_mut().pop_text_style();
|
|
||||||
result
|
|
||||||
} else {
|
|
||||||
f(self)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn set_global<G: 'static>(&mut self, global: G) {
|
fn set_global<G: 'static>(&mut self, global: G) {
|
||||||
self.borrow_mut().set_global(global)
|
self.borrow_mut().set_global(global)
|
||||||
}
|
}
|
||||||
|
|
|
@ -308,18 +308,6 @@ impl Style {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn apply_text_style<C, F, R>(&self, cx: &mut C, f: F) -> R
|
|
||||||
where
|
|
||||||
C: BorrowAppContext,
|
|
||||||
F: FnOnce(&mut C) -> R,
|
|
||||||
{
|
|
||||||
if self.text.is_some() {
|
|
||||||
cx.with_text_style(Some(self.text.clone()), f)
|
|
||||||
} else {
|
|
||||||
f(cx)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Paints the background of an element styled with this style.
|
/// Paints the background of an element styled with this style.
|
||||||
pub fn paint(
|
pub fn paint(
|
||||||
&self,
|
&self,
|
||||||
|
|
|
@ -1,16 +1,15 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
px, size, transparent_black, Action, AnyDrag, AnyTooltip, AnyView, AppContext, Arena,
|
px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, AsyncWindowContext,
|
||||||
AsyncWindowContext, AvailableSpace, Bounds, Context, Corners, CursorStyle,
|
AvailableSpace, Bounds, Context, Corners, CursorStyle, DispatchActionListener, DispatchNodeId,
|
||||||
DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
|
DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten,
|
||||||
EntityId, EventEmitter, FileDropEvent, Flatten, GlobalElementId, Hsla, KeyBinding, KeyContext,
|
GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, Model,
|
||||||
KeyDownEvent, KeystrokeEvent, Model, ModelContext, Modifiers, MouseButton, MouseMoveEvent,
|
ModelContext, Modifiers, MouseButton, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas,
|
||||||
MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
|
PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptLevel, Render, ScaledPixels,
|
||||||
PlatformWindow, Point, PromptLevel, Render, ScaledPixels, Scene, SharedString, Size,
|
SharedString, Size, SubscriberSet, Subscription, TaffyLayoutEngine, Task, View, VisualContext,
|
||||||
SubscriberSet, Subscription, TaffyLayoutEngine, Task, View, VisualContext, WeakView,
|
WeakView, WindowBounds, WindowOptions,
|
||||||
WindowBounds, WindowOptions,
|
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Context as _, Result};
|
use anyhow::{anyhow, Context as _, Result};
|
||||||
use collections::{FxHashMap, FxHashSet};
|
use collections::FxHashSet;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use futures::{
|
use futures::{
|
||||||
channel::{mpsc, oneshot},
|
channel::{mpsc, oneshot},
|
||||||
|
@ -97,7 +96,7 @@ impl DispatchPhase {
|
||||||
}
|
}
|
||||||
|
|
||||||
type AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
|
type AnyObserver = Box<dyn FnMut(&mut WindowContext) -> bool + 'static>;
|
||||||
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
|
|
||||||
type AnyWindowFocusListener = Box<dyn FnMut(&FocusEvent, &mut WindowContext) -> bool + 'static>;
|
type AnyWindowFocusListener = Box<dyn FnMut(&FocusEvent, &mut WindowContext) -> bool + 'static>;
|
||||||
|
|
||||||
struct FocusEvent {
|
struct FocusEvent {
|
||||||
|
@ -286,16 +285,6 @@ pub struct Window {
|
||||||
pub(crate) focus_invalidated: bool,
|
pub(crate) focus_invalidated: bool,
|
||||||
}
|
}
|
||||||
|
|
||||||
struct RequestedInputHandler {
|
|
||||||
view_id: EntityId,
|
|
||||||
handler: Option<PlatformInputHandler>,
|
|
||||||
}
|
|
||||||
|
|
||||||
struct TooltipRequest {
|
|
||||||
view_id: EntityId,
|
|
||||||
tooltip: AnyTooltip,
|
|
||||||
}
|
|
||||||
|
|
||||||
pub(crate) struct ElementStateBox {
|
pub(crate) struct ElementStateBox {
|
||||||
pub(crate) inner: Box<dyn Any>,
|
pub(crate) inner: Box<dyn Any>,
|
||||||
pub(crate) parent_view_id: EntityId,
|
pub(crate) parent_view_id: EntityId,
|
||||||
|
@ -303,116 +292,6 @@ pub(crate) struct ElementStateBox {
|
||||||
pub(crate) type_name: &'static str,
|
pub(crate) type_name: &'static str,
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) struct Frame {
|
|
||||||
focus: Option<FocusId>,
|
|
||||||
window_active: bool,
|
|
||||||
pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
|
|
||||||
mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
|
|
||||||
pub(crate) dispatch_tree: DispatchTree,
|
|
||||||
pub(crate) scene: Scene,
|
|
||||||
pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
|
|
||||||
pub(crate) z_index_stack: StackingOrder,
|
|
||||||
pub(crate) next_stacking_order_id: u32,
|
|
||||||
pub(crate) next_root_z_index: u8,
|
|
||||||
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
|
|
||||||
pub(crate) element_offset_stack: Vec<Point<Pixels>>,
|
|
||||||
requested_input_handler: Option<RequestedInputHandler>,
|
|
||||||
tooltip_request: Option<TooltipRequest>,
|
|
||||||
cursor_styles: FxHashMap<EntityId, CursorStyle>,
|
|
||||||
requested_cursor_style: Option<CursorStyle>,
|
|
||||||
pub(crate) view_stack: Vec<EntityId>,
|
|
||||||
pub(crate) reused_views: FxHashSet<EntityId>,
|
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
|
||||||
pub(crate) debug_bounds: collections::FxHashMap<String, Bounds<Pixels>>,
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Frame {
|
|
||||||
fn new(dispatch_tree: DispatchTree) -> Self {
|
|
||||||
Frame {
|
|
||||||
focus: None,
|
|
||||||
window_active: false,
|
|
||||||
element_states: FxHashMap::default(),
|
|
||||||
mouse_listeners: FxHashMap::default(),
|
|
||||||
dispatch_tree,
|
|
||||||
scene: Scene::default(),
|
|
||||||
depth_map: Vec::new(),
|
|
||||||
z_index_stack: StackingOrder::default(),
|
|
||||||
next_stacking_order_id: 0,
|
|
||||||
next_root_z_index: 0,
|
|
||||||
content_mask_stack: Vec::new(),
|
|
||||||
element_offset_stack: Vec::new(),
|
|
||||||
requested_input_handler: None,
|
|
||||||
tooltip_request: None,
|
|
||||||
cursor_styles: FxHashMap::default(),
|
|
||||||
requested_cursor_style: None,
|
|
||||||
view_stack: Vec::new(),
|
|
||||||
reused_views: FxHashSet::default(),
|
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
|
||||||
debug_bounds: FxHashMap::default(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn clear(&mut self) {
|
|
||||||
self.element_states.clear();
|
|
||||||
self.mouse_listeners.values_mut().for_each(Vec::clear);
|
|
||||||
self.dispatch_tree.clear();
|
|
||||||
self.depth_map.clear();
|
|
||||||
self.next_stacking_order_id = 0;
|
|
||||||
self.next_root_z_index = 0;
|
|
||||||
self.reused_views.clear();
|
|
||||||
self.scene.clear();
|
|
||||||
self.requested_input_handler.take();
|
|
||||||
self.tooltip_request.take();
|
|
||||||
self.cursor_styles.clear();
|
|
||||||
self.requested_cursor_style.take();
|
|
||||||
debug_assert_eq!(self.view_stack.len(), 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
|
|
||||||
self.focus
|
|
||||||
.map(|focus_id| self.dispatch_tree.focus_path(focus_id))
|
|
||||||
.unwrap_or_default()
|
|
||||||
}
|
|
||||||
|
|
||||||
fn finish(&mut self, prev_frame: &mut Self) {
|
|
||||||
// Reuse mouse listeners that didn't change since the last frame.
|
|
||||||
for (type_id, listeners) in &mut prev_frame.mouse_listeners {
|
|
||||||
let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
|
|
||||||
for (order, view_id, listener) in listeners.drain(..) {
|
|
||||||
if self.reused_views.contains(&view_id) {
|
|
||||||
next_listeners.push((order, view_id, listener));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reuse entries in the depth map that didn't change since the last frame.
|
|
||||||
for (order, view_id, bounds) in prev_frame.depth_map.drain(..) {
|
|
||||||
if self.reused_views.contains(&view_id) {
|
|
||||||
match self
|
|
||||||
.depth_map
|
|
||||||
.binary_search_by(|(level, _, _)| order.cmp(level))
|
|
||||||
{
|
|
||||||
Ok(i) | Err(i) => self.depth_map.insert(i, (order, view_id, bounds)),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Retain element states for views that didn't change since the last frame.
|
|
||||||
for (element_id, state) in prev_frame.element_states.drain() {
|
|
||||||
if self.reused_views.contains(&state.parent_view_id) {
|
|
||||||
self.element_states.entry(element_id).or_insert(state);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reuse geometry that didn't change since the last frame.
|
|
||||||
self.scene
|
|
||||||
.reuse_views(&self.reused_views, &mut prev_frame.scene);
|
|
||||||
self.scene.finish();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Window {
|
impl Window {
|
||||||
pub(crate) fn new(
|
pub(crate) fn new(
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
|
@ -925,19 +804,6 @@ impl<'a> WindowContext<'a> {
|
||||||
self.window.modifiers
|
self.window.modifiers
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Updates the cursor style at the platform level.
|
|
||||||
pub fn set_cursor_style(&mut self, style: CursorStyle) {
|
|
||||||
let view_id = self.parent_view_id();
|
|
||||||
self.window.next_frame.cursor_styles.insert(view_id, style);
|
|
||||||
self.window.next_frame.requested_cursor_style = Some(style);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Sets 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 });
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns true if there is no opaque layer containing the given point
|
/// Returns true if there is no opaque layer containing the given point
|
||||||
/// on top of the given level. Layers whose level is an extension of the
|
/// on top of the given level. Layers whose level is an extension of the
|
||||||
/// level are not considered to be on top of the level.
|
/// level are not considered to be on top of the level.
|
||||||
|
@ -979,48 +845,6 @@ impl<'a> WindowContext<'a> {
|
||||||
&self.window.next_frame.z_index_stack
|
&self.window.next_frame.z_index_stack
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn reuse_view(&mut self) {
|
|
||||||
let view_id = self.parent_view_id();
|
|
||||||
let grafted_view_ids = self
|
|
||||||
.window
|
|
||||||
.next_frame
|
|
||||||
.dispatch_tree
|
|
||||||
.reuse_view(view_id, &mut self.window.rendered_frame.dispatch_tree);
|
|
||||||
for view_id in grafted_view_ids {
|
|
||||||
assert!(self.window.next_frame.reused_views.insert(view_id));
|
|
||||||
|
|
||||||
// Reuse the previous input handler requested during painting of the reused view.
|
|
||||||
if self
|
|
||||||
.window
|
|
||||||
.rendered_frame
|
|
||||||
.requested_input_handler
|
|
||||||
.as_ref()
|
|
||||||
.map_or(false, |requested| requested.view_id == view_id)
|
|
||||||
{
|
|
||||||
self.window.next_frame.requested_input_handler =
|
|
||||||
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) {
|
|
||||||
self.window.next_frame.cursor_styles.insert(view_id, style);
|
|
||||||
self.window.next_frame.requested_cursor_style = Some(style);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Draw pixels to the display for this window based on the contents of its scene.
|
/// Draw pixels to the display for this window based on the contents of its scene.
|
||||||
pub(crate) fn draw(&mut self) {
|
pub(crate) fn draw(&mut self) {
|
||||||
self.window.dirty = false;
|
self.window.dirty = false;
|
||||||
|
|
|
@ -7,21 +7,144 @@ use std::{
|
||||||
};
|
};
|
||||||
|
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use collections::{FxHashMap, FxHashSet};
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
use media::core_video::CVImageBuffer;
|
use media::core_video::CVImageBuffer;
|
||||||
|
use smallvec::SmallVec;
|
||||||
use util::post_inc;
|
use util::post_inc;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
prelude::*, size, AppContext, AvailableSpace, Bounds, BoxShadow, ContentMask, Corners,
|
prelude::*, size, AnyTooltip, AppContext, AvailableSpace, Bounds, BoxShadow, ContentMask,
|
||||||
DevicePixels, DispatchPhase, ElementId, ElementStateBox, EntityId, FocusHandle, FontId,
|
Corners, CursorStyle, DevicePixels, DispatchPhase, DispatchTree, ElementId, ElementStateBox,
|
||||||
GlyphId, Hsla, ImageData, InputHandler, IsZero, KeyContext, KeyEvent, LayoutId,
|
EntityId, FocusHandle, FocusId, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
|
||||||
MonochromeSprite, MouseEvent, PaintQuad, Path, Pixels, PlatformInputHandler, Point,
|
InputHandler, IsZero, KeyContext, KeyEvent, LayoutId, MonochromeSprite, MouseEvent, PaintQuad,
|
||||||
PolychromeSprite, Quad, RenderGlyphParams, RenderImageParams, RenderSvgParams, Shadow,
|
Path, Pixels, PlatformInputHandler, Point, PolychromeSprite, Quad, RenderGlyphParams,
|
||||||
SharedString, Size, Style, Surface, Underline, UnderlineStyle, Window, WindowContext,
|
RenderImageParams, RenderSvgParams, Scene, Shadow, SharedString, Size, StackingOrder, Style,
|
||||||
|
Surface, TextStyleRefinement, Underline, UnderlineStyle, Window, WindowContext,
|
||||||
SUBPIXEL_VARIANTS,
|
SUBPIXEL_VARIANTS,
|
||||||
};
|
};
|
||||||
|
|
||||||
use super::RequestedInputHandler;
|
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
|
||||||
|
|
||||||
|
pub(crate) struct RequestedInputHandler {
|
||||||
|
pub(crate) view_id: EntityId,
|
||||||
|
pub(crate) handler: Option<PlatformInputHandler>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct TooltipRequest {
|
||||||
|
pub(crate) view_id: EntityId,
|
||||||
|
pub(crate) tooltip: AnyTooltip,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) struct Frame {
|
||||||
|
pub(crate) focus: Option<FocusId>,
|
||||||
|
pub(crate) window_active: bool,
|
||||||
|
pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
|
||||||
|
pub(crate) mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, EntityId, AnyMouseListener)>>,
|
||||||
|
pub(crate) dispatch_tree: DispatchTree,
|
||||||
|
pub(crate) scene: Scene,
|
||||||
|
pub(crate) depth_map: Vec<(StackingOrder, EntityId, Bounds<Pixels>)>,
|
||||||
|
pub(crate) z_index_stack: StackingOrder,
|
||||||
|
pub(crate) next_stacking_order_id: u32,
|
||||||
|
pub(crate) next_root_z_index: u8,
|
||||||
|
pub(crate) content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||||
|
pub(crate) element_offset_stack: Vec<Point<Pixels>>,
|
||||||
|
pub(crate) requested_input_handler: Option<RequestedInputHandler>,
|
||||||
|
pub(crate) tooltip_request: Option<TooltipRequest>,
|
||||||
|
pub(crate) cursor_styles: FxHashMap<EntityId, CursorStyle>,
|
||||||
|
pub(crate) requested_cursor_style: Option<CursorStyle>,
|
||||||
|
pub(crate) view_stack: Vec<EntityId>,
|
||||||
|
pub(crate) reused_views: FxHashSet<EntityId>,
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
pub(crate) debug_bounds: collections::FxHashMap<String, Bounds<Pixels>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Frame {
|
||||||
|
pub(crate) fn new(dispatch_tree: DispatchTree) -> Self {
|
||||||
|
Frame {
|
||||||
|
focus: None,
|
||||||
|
window_active: false,
|
||||||
|
element_states: FxHashMap::default(),
|
||||||
|
mouse_listeners: FxHashMap::default(),
|
||||||
|
dispatch_tree,
|
||||||
|
scene: Scene::default(),
|
||||||
|
depth_map: Vec::new(),
|
||||||
|
z_index_stack: StackingOrder::default(),
|
||||||
|
next_stacking_order_id: 0,
|
||||||
|
next_root_z_index: 0,
|
||||||
|
content_mask_stack: Vec::new(),
|
||||||
|
element_offset_stack: Vec::new(),
|
||||||
|
requested_input_handler: None,
|
||||||
|
tooltip_request: None,
|
||||||
|
cursor_styles: FxHashMap::default(),
|
||||||
|
requested_cursor_style: None,
|
||||||
|
view_stack: Vec::new(),
|
||||||
|
reused_views: FxHashSet::default(),
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
debug_bounds: FxHashMap::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn clear(&mut self) {
|
||||||
|
self.element_states.clear();
|
||||||
|
self.mouse_listeners.values_mut().for_each(Vec::clear);
|
||||||
|
self.dispatch_tree.clear();
|
||||||
|
self.depth_map.clear();
|
||||||
|
self.next_stacking_order_id = 0;
|
||||||
|
self.next_root_z_index = 0;
|
||||||
|
self.reused_views.clear();
|
||||||
|
self.scene.clear();
|
||||||
|
self.requested_input_handler.take();
|
||||||
|
self.tooltip_request.take();
|
||||||
|
self.cursor_styles.clear();
|
||||||
|
self.requested_cursor_style.take();
|
||||||
|
debug_assert_eq!(self.view_stack.len(), 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn focus_path(&self) -> SmallVec<[FocusId; 8]> {
|
||||||
|
self.focus
|
||||||
|
.map(|focus_id| self.dispatch_tree.focus_path(focus_id))
|
||||||
|
.unwrap_or_default()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(crate) fn finish(&mut self, prev_frame: &mut Self) {
|
||||||
|
// Reuse mouse listeners that didn't change since the last frame.
|
||||||
|
for (type_id, listeners) in &mut prev_frame.mouse_listeners {
|
||||||
|
let next_listeners = self.mouse_listeners.entry(*type_id).or_default();
|
||||||
|
for (order, view_id, listener) in listeners.drain(..) {
|
||||||
|
if self.reused_views.contains(&view_id) {
|
||||||
|
next_listeners.push((order, view_id, listener));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reuse entries in the depth map that didn't change since the last frame.
|
||||||
|
for (order, view_id, bounds) in prev_frame.depth_map.drain(..) {
|
||||||
|
if self.reused_views.contains(&view_id) {
|
||||||
|
match self
|
||||||
|
.depth_map
|
||||||
|
.binary_search_by(|(level, _, _)| order.cmp(level))
|
||||||
|
{
|
||||||
|
Ok(i) | Err(i) => self.depth_map.insert(i, (order, view_id, bounds)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Retain element states for views that didn't change since the last frame.
|
||||||
|
for (element_id, state) in prev_frame.element_states.drain() {
|
||||||
|
if self.reused_views.contains(&state.parent_view_id) {
|
||||||
|
self.element_states.entry(element_id).or_insert(state);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reuse geometry that didn't change since the last frame.
|
||||||
|
self.scene
|
||||||
|
.reuse_views(&self.reused_views, &mut prev_frame.scene);
|
||||||
|
self.scene.finish();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// This context is used for assisting in the implementation of the element trait
|
/// This context is used for assisting in the implementation of the element trait
|
||||||
#[derive(Deref, DerefMut)]
|
#[derive(Deref, DerefMut)]
|
||||||
|
@ -169,6 +292,76 @@ impl<'a> VisualContext for ElementContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> ElementContext<'a> {
|
impl<'a> ElementContext<'a> {
|
||||||
|
pub(crate) fn reuse_view(&mut self) {
|
||||||
|
let view_id = self.parent_view_id();
|
||||||
|
let grafted_view_ids = self
|
||||||
|
.cx
|
||||||
|
.window
|
||||||
|
.next_frame
|
||||||
|
.dispatch_tree
|
||||||
|
.reuse_view(view_id, &mut self.cx.window.rendered_frame.dispatch_tree);
|
||||||
|
for view_id in grafted_view_ids {
|
||||||
|
assert!(self.window.next_frame.reused_views.insert(view_id));
|
||||||
|
|
||||||
|
// Reuse the previous input handler requested during painting of the reused view.
|
||||||
|
if self
|
||||||
|
.window
|
||||||
|
.rendered_frame
|
||||||
|
.requested_input_handler
|
||||||
|
.as_ref()
|
||||||
|
.map_or(false, |requested| requested.view_id == view_id)
|
||||||
|
{
|
||||||
|
self.window.next_frame.requested_input_handler =
|
||||||
|
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) {
|
||||||
|
self.window.next_frame.cursor_styles.insert(view_id, style);
|
||||||
|
self.window.next_frame.requested_cursor_style = Some(style);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn with_text_style<F, R>(&mut self, style: Option<TextStyleRefinement>, f: F) -> R
|
||||||
|
where
|
||||||
|
F: FnOnce(&mut Self) -> R,
|
||||||
|
{
|
||||||
|
if let Some(style) = style {
|
||||||
|
self.push_text_style(style);
|
||||||
|
let result = f(self);
|
||||||
|
self.pop_text_style();
|
||||||
|
result
|
||||||
|
} else {
|
||||||
|
f(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Updates the cursor style at the platform level.
|
||||||
|
pub fn set_cursor_style(&mut self, style: CursorStyle) {
|
||||||
|
let view_id = self.parent_view_id();
|
||||||
|
self.window.next_frame.cursor_styles.insert(view_id, style);
|
||||||
|
self.window.next_frame.requested_cursor_style = Some(style);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets 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 });
|
||||||
|
}
|
||||||
|
|
||||||
/// Pushes the given element id onto the global stack and invokes the given closure
|
/// Pushes the given element id onto the global stack and invokes the given closure
|
||||||
/// with a `GlobalElementId`, which disambiguates the given id in the context of its ancestor
|
/// with a `GlobalElementId`, which disambiguates the given id in the context of its ancestor
|
||||||
/// ids. Because elements are discarded and recreated on each frame, the `GlobalElementId` is
|
/// ids. Because elements are discarded and recreated on each frame, the `GlobalElementId` is
|
||||||
|
|
|
@ -365,7 +365,7 @@ impl TerminalElement {
|
||||||
result
|
result
|
||||||
}
|
}
|
||||||
|
|
||||||
fn compute_layout(&self, bounds: Bounds<gpui::Pixels>, cx: &mut WindowContext) -> LayoutState {
|
fn compute_layout(&self, bounds: Bounds<gpui::Pixels>, cx: &mut ElementContext) -> LayoutState {
|
||||||
let settings = ThemeSettings::get_global(cx).clone();
|
let settings = ThemeSettings::get_global(cx).clone();
|
||||||
|
|
||||||
let buffer_font_size = settings.buffer_font_size(cx);
|
let buffer_font_size = settings.buffer_font_size(cx);
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue