Detailed changes
@@ -23,12 +23,11 @@
//!
use crate::{
- point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
- Bounds, ClickEvent, DispatchPhase, Element, ElementContext, ElementId, FocusHandle,
- IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton,
- MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render,
- ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task,
- View, Visibility, WindowContext,
+ point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds, ClickEvent,
+ DispatchPhase, Element, ElementContext, ElementId, FocusHandle, IntoElement, IsZero,
+ KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
+ MouseUpEvent, ParentElement, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size,
+ StackingOrder, Style, StyleRefinement, Styled, Task, View, Visibility, WindowContext,
};
use collections::HashMap;
@@ -7,8 +7,8 @@
//! If all of your elements are the same height, see [`UniformList`] for a simpler API
use crate::{
- point, px, AnyElement, AvailableSpace, BorrowAppContext, Bounds, ContentMask, DispatchPhase,
- Element, IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, StyleRefinement, Styled,
+ point, px, AnyElement, AvailableSpace, Bounds, ContentMask, DispatchPhase, Element,
+ IntoElement, Pixels, Point, ScrollWheelEvent, Size, Style, StyleRefinement, Styled,
WindowContext,
};
use collections::VecDeque;
@@ -220,11 +220,6 @@ pub trait EventEmitter<E: Any>: 'static {}
/// A helper trait for auto-implementing certain methods on contexts that
/// can be used interchangeably.
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.
fn set_global<T: 'static>(&mut self, global: T);
}
@@ -233,20 +228,6 @@ impl<C> BorrowAppContext for C
where
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) {
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.
pub fn paint(
&self,
@@ -1,16 +1,15 @@
use crate::{
- px, size, transparent_black, Action, AnyDrag, AnyTooltip, AnyView, AppContext, Arena,
- AsyncWindowContext, AvailableSpace, Bounds, Context, Corners, CursorStyle,
- DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity,
- EntityId, EventEmitter, FileDropEvent, Flatten, GlobalElementId, Hsla, KeyBinding, KeyContext,
- KeyDownEvent, KeystrokeEvent, Model, ModelContext, Modifiers, MouseButton, MouseMoveEvent,
- MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler,
- PlatformWindow, Point, PromptLevel, Render, ScaledPixels, Scene, SharedString, Size,
- SubscriberSet, Subscription, TaffyLayoutEngine, Task, View, VisualContext, WeakView,
- WindowBounds, WindowOptions,
+ px, size, transparent_black, Action, AnyDrag, AnyView, AppContext, Arena, AsyncWindowContext,
+ AvailableSpace, Bounds, Context, Corners, CursorStyle, DispatchActionListener, DispatchNodeId,
+ DispatchTree, DisplayId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten,
+ GlobalElementId, Hsla, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, Model,
+ ModelContext, Modifiers, MouseButton, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas,
+ PlatformDisplay, PlatformInput, PlatformWindow, Point, PromptLevel, Render, ScaledPixels,
+ SharedString, Size, SubscriberSet, Subscription, TaffyLayoutEngine, Task, View, VisualContext,
+ WeakView, WindowBounds, WindowOptions,
};
use anyhow::{anyhow, Context as _, Result};
-use collections::{FxHashMap, FxHashSet};
+use collections::FxHashSet;
use derive_more::{Deref, DerefMut};
use futures::{
channel::{mpsc, oneshot},
@@ -97,7 +96,7 @@ impl DispatchPhase {
}
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>;
struct FocusEvent {
@@ -286,16 +285,6 @@ pub struct Window {
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) inner: Box<dyn Any>,
pub(crate) parent_view_id: EntityId,
@@ -303,116 +292,6 @@ pub(crate) struct ElementStateBox {
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 {
pub(crate) fn new(
handle: AnyWindowHandle,
@@ -925,19 +804,6 @@ impl<'a> WindowContext<'a> {
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
/// 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.
@@ -979,48 +845,6 @@ impl<'a> WindowContext<'a> {
&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.
pub(crate) fn draw(&mut self) {
self.window.dirty = false;
@@ -7,21 +7,144 @@ use std::{
};
use anyhow::Result;
+use collections::{FxHashMap, FxHashSet};
use derive_more::{Deref, DerefMut};
use media::core_video::CVImageBuffer;
+use smallvec::SmallVec;
use util::post_inc;
use crate::{
- prelude::*, size, AppContext, AvailableSpace, Bounds, BoxShadow, ContentMask, Corners,
- DevicePixels, DispatchPhase, ElementId, ElementStateBox, EntityId, FocusHandle, FontId,
- GlyphId, Hsla, ImageData, InputHandler, IsZero, KeyContext, KeyEvent, LayoutId,
- MonochromeSprite, MouseEvent, PaintQuad, Path, Pixels, PlatformInputHandler, Point,
- PolychromeSprite, Quad, RenderGlyphParams, RenderImageParams, RenderSvgParams, Shadow,
- SharedString, Size, Style, Surface, Underline, UnderlineStyle, Window, WindowContext,
+ prelude::*, size, AnyTooltip, AppContext, AvailableSpace, Bounds, BoxShadow, ContentMask,
+ Corners, CursorStyle, DevicePixels, DispatchPhase, DispatchTree, ElementId, ElementStateBox,
+ EntityId, FocusHandle, FocusId, FontId, GlobalElementId, GlyphId, Hsla, ImageData,
+ InputHandler, IsZero, KeyContext, KeyEvent, LayoutId, MonochromeSprite, MouseEvent, PaintQuad,
+ Path, Pixels, PlatformInputHandler, Point, PolychromeSprite, Quad, RenderGlyphParams,
+ RenderImageParams, RenderSvgParams, Scene, Shadow, SharedString, Size, StackingOrder, Style,
+ Surface, TextStyleRefinement, Underline, UnderlineStyle, Window, WindowContext,
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
#[derive(Deref, DerefMut)]
@@ -169,6 +292,76 @@ impl<'a> VisualContext for 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
/// 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
@@ -365,7 +365,7 @@ impl TerminalElement {
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 buffer_font_size = settings.buffer_font_size(cx);