WIP
This commit is contained in:
parent
0fde56909c
commit
542fb5c89a
9 changed files with 410 additions and 112 deletions
|
@ -19,9 +19,9 @@ use crate::{
|
|||
point, px, size, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, Bounds,
|
||||
ClickEvent, DispatchPhase, Element, ElementContext, ElementId, FocusHandle, Global,
|
||||
IntoElement, IsZero, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, OcclusionId, ParentElement, Pixels, Point,
|
||||
Render, ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled,
|
||||
Task, View, Visibility, WindowContext,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, Point, Render,
|
||||
ScrollWheelEvent, SharedString, Size, StackingOrder, Style, StyleRefinement, Styled, Task,
|
||||
View, Visibility, WindowContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
|
@ -1312,7 +1312,7 @@ impl Interactivity {
|
|||
})
|
||||
{
|
||||
let clipped_bounds = bounds.intersect(&cx.content_mask().bounds);
|
||||
cx.insert_occlusion(clipped_bounds);
|
||||
cx.occlude(clipped_bounds);
|
||||
}
|
||||
|
||||
let scroll_offset = self.clamp_scroll_position(bounds, &style, cx);
|
||||
|
|
|
@ -117,6 +117,10 @@ impl DispatchTree {
|
|||
self.keystroke_matchers.clear();
|
||||
}
|
||||
|
||||
pub fn len(&self) -> usize {
|
||||
self.nodes.len()
|
||||
}
|
||||
|
||||
pub fn push_node(
|
||||
&mut self,
|
||||
context: Option<KeyContext>,
|
||||
|
|
|
@ -294,8 +294,7 @@ impl MetalRenderer {
|
|||
zfar: 1.0,
|
||||
});
|
||||
|
||||
let mut batches = scene.batches();
|
||||
while let Some(batch) = batches.next() {
|
||||
for batch in scene.batches() {
|
||||
let ok = match batch {
|
||||
PrimitiveBatch::Shadows(shadows) => self.draw_shadows(
|
||||
shadows,
|
||||
|
@ -358,7 +357,15 @@ impl MetalRenderer {
|
|||
};
|
||||
|
||||
if !ok {
|
||||
log::error!("scene too large: {} primitives", scene.primitives.len());
|
||||
log::error!("scene too large: {} paths, {} shadows, {} quads, {} underlines, {} mono, {} poly, {} surfaces",
|
||||
scene.paths.len(),
|
||||
scene.shadows.len(),
|
||||
scene.quads.len(),
|
||||
scene.underlines.len(),
|
||||
scene.monochrome_sprites.len(),
|
||||
scene.polychrome_sprites.len(),
|
||||
scene.surfaces.len(),
|
||||
);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -5,7 +5,11 @@ use crate::{
|
|||
bounds_tree::BoundsTree, point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges,
|
||||
Hsla, Pixels, Point, ScaledPixels,
|
||||
};
|
||||
use std::{fmt::Debug, iter, slice};
|
||||
use std::{
|
||||
fmt::Debug,
|
||||
iter::{self, Peekable},
|
||||
slice,
|
||||
};
|
||||
|
||||
#[allow(non_camel_case_types, unused)]
|
||||
pub(crate) type PathVertex_ScaledPixels = PathVertex<ScaledPixels>;
|
||||
|
@ -14,9 +18,15 @@ pub(crate) type DrawOrder = u32;
|
|||
|
||||
#[derive(Default)]
|
||||
pub(crate) struct Scene {
|
||||
pub(crate) primitives: Vec<Primitive>,
|
||||
primitives: Vec<Primitive>,
|
||||
primitive_bounds: BoundsTree<ScaledPixels, ()>,
|
||||
paths: Vec<Path<ScaledPixels>>,
|
||||
pub(crate) shadows: Vec<Shadow>,
|
||||
pub(crate) quads: Vec<Quad>,
|
||||
pub(crate) paths: Vec<Path<ScaledPixels>>,
|
||||
pub(crate) underlines: Vec<Underline>,
|
||||
pub(crate) monochrome_sprites: Vec<MonochromeSprite>,
|
||||
pub(crate) polychrome_sprites: Vec<PolychromeSprite>,
|
||||
pub(crate) surfaces: Vec<Surface>,
|
||||
}
|
||||
|
||||
impl Scene {
|
||||
|
@ -24,6 +34,12 @@ impl Scene {
|
|||
self.primitives.clear();
|
||||
self.primitive_bounds.clear();
|
||||
self.paths.clear();
|
||||
self.shadows.clear();
|
||||
self.quads.clear();
|
||||
self.underlines.clear();
|
||||
self.monochrome_sprites.clear();
|
||||
self.polychrome_sprites.clear();
|
||||
self.surfaces.clear();
|
||||
}
|
||||
|
||||
pub fn paths(&self) -> &[Path<ScaledPixels>] {
|
||||
|
@ -47,39 +63,88 @@ impl Scene {
|
|||
|
||||
let order = self.primitive_bounds.insert(clipped_bounds, ());
|
||||
match &mut primitive {
|
||||
Primitive::Shadow(shadow) => shadow.order = order,
|
||||
Primitive::Quad(quad) => quad.order = order,
|
||||
Primitive::Shadow(shadow) => {
|
||||
shadow.order = order;
|
||||
self.shadows.push(shadow.clone());
|
||||
}
|
||||
Primitive::Quad(quad) => {
|
||||
quad.order = order;
|
||||
self.quads.push(quad.clone());
|
||||
}
|
||||
Primitive::Path(path) => {
|
||||
path.order = order;
|
||||
path.id = PathId(self.paths.len());
|
||||
self.paths.push(path.clone());
|
||||
}
|
||||
Primitive::Underline(underline) => underline.order = order,
|
||||
Primitive::MonochromeSprite(sprite) => sprite.order = order,
|
||||
Primitive::PolychromeSprite(sprite) => sprite.order = order,
|
||||
Primitive::Surface(surface) => surface.order = order,
|
||||
Primitive::Underline(underline) => {
|
||||
underline.order = order;
|
||||
self.underlines.push(underline.clone());
|
||||
}
|
||||
Primitive::MonochromeSprite(sprite) => {
|
||||
sprite.order = order;
|
||||
self.monochrome_sprites.push(sprite.clone());
|
||||
}
|
||||
Primitive::PolychromeSprite(sprite) => {
|
||||
sprite.order = order;
|
||||
self.polychrome_sprites.push(sprite.clone());
|
||||
}
|
||||
Primitive::Surface(surface) => {
|
||||
surface.order = order;
|
||||
self.surfaces.push(surface.clone());
|
||||
}
|
||||
}
|
||||
self.primitives.push(primitive);
|
||||
}
|
||||
|
||||
pub fn finish(&mut self) {
|
||||
self.primitives.sort_unstable();
|
||||
self.shadows.sort_unstable();
|
||||
self.quads.sort_unstable();
|
||||
self.paths.sort_unstable();
|
||||
self.underlines.sort_unstable();
|
||||
self.monochrome_sprites.sort_unstable();
|
||||
self.polychrome_sprites.sort_unstable();
|
||||
self.surfaces.sort_unstable();
|
||||
}
|
||||
|
||||
pub(crate) fn batches(&self) -> PrimitiveBatches {
|
||||
PrimitiveBatches {
|
||||
primitives: self.primitives.iter().peekable(),
|
||||
shadows: Vec::new(),
|
||||
quads: Vec::new(),
|
||||
paths: Vec::new(),
|
||||
underlines: Vec::new(),
|
||||
monochrome_sprites: Vec::new(),
|
||||
polychrome_sprites: Vec::new(),
|
||||
surfaces: Vec::new(),
|
||||
pub(crate) fn batches(&self) -> impl Iterator<Item = PrimitiveBatch> {
|
||||
BatchIterator {
|
||||
shadows: &self.shadows,
|
||||
shadows_start: 0,
|
||||
shadows_iter: self.shadows.iter().peekable(),
|
||||
quads: &self.quads,
|
||||
quads_start: 0,
|
||||
quads_iter: self.quads.iter().peekable(),
|
||||
paths: &self.paths,
|
||||
paths_start: 0,
|
||||
paths_iter: self.paths.iter().peekable(),
|
||||
underlines: &self.underlines,
|
||||
underlines_start: 0,
|
||||
underlines_iter: self.underlines.iter().peekable(),
|
||||
monochrome_sprites: &self.monochrome_sprites,
|
||||
monochrome_sprites_start: 0,
|
||||
monochrome_sprites_iter: self.monochrome_sprites.iter().peekable(),
|
||||
polychrome_sprites: &self.polychrome_sprites,
|
||||
polychrome_sprites_start: 0,
|
||||
polychrome_sprites_iter: self.polychrome_sprites.iter().peekable(),
|
||||
surfaces: &self.surfaces,
|
||||
surfaces_start: 0,
|
||||
surfaces_iter: self.surfaces.iter().peekable(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Eq, PartialEq, Ord, PartialOrd, Default)]
|
||||
pub(crate) enum PrimitiveKind {
|
||||
Shadow,
|
||||
#[default]
|
||||
Quad,
|
||||
Path,
|
||||
Underline,
|
||||
MonochromeSprite,
|
||||
PolychromeSprite,
|
||||
Surface,
|
||||
}
|
||||
|
||||
#[derive(Ord, PartialOrd, Eq, PartialEq)]
|
||||
pub(crate) enum Primitive {
|
||||
Shadow(Shadow),
|
||||
|
@ -117,6 +182,191 @@ impl Primitive {
|
|||
}
|
||||
}
|
||||
|
||||
struct BatchIterator<'a> {
|
||||
shadows: &'a [Shadow],
|
||||
shadows_start: usize,
|
||||
shadows_iter: Peekable<slice::Iter<'a, Shadow>>,
|
||||
quads: &'a [Quad],
|
||||
quads_start: usize,
|
||||
quads_iter: Peekable<slice::Iter<'a, Quad>>,
|
||||
paths: &'a [Path<ScaledPixels>],
|
||||
paths_start: usize,
|
||||
paths_iter: Peekable<slice::Iter<'a, Path<ScaledPixels>>>,
|
||||
underlines: &'a [Underline],
|
||||
underlines_start: usize,
|
||||
underlines_iter: Peekable<slice::Iter<'a, Underline>>,
|
||||
monochrome_sprites: &'a [MonochromeSprite],
|
||||
monochrome_sprites_start: usize,
|
||||
monochrome_sprites_iter: Peekable<slice::Iter<'a, MonochromeSprite>>,
|
||||
polychrome_sprites: &'a [PolychromeSprite],
|
||||
polychrome_sprites_start: usize,
|
||||
polychrome_sprites_iter: Peekable<slice::Iter<'a, PolychromeSprite>>,
|
||||
surfaces: &'a [Surface],
|
||||
surfaces_start: usize,
|
||||
surfaces_iter: Peekable<slice::Iter<'a, Surface>>,
|
||||
}
|
||||
|
||||
impl<'a> Iterator for BatchIterator<'a> {
|
||||
type Item = PrimitiveBatch<'a>;
|
||||
|
||||
fn next(&mut self) -> Option<Self::Item> {
|
||||
let mut orders_and_kinds = [
|
||||
(
|
||||
self.shadows_iter.peek().map(|s| s.order),
|
||||
PrimitiveKind::Shadow,
|
||||
),
|
||||
(self.quads_iter.peek().map(|q| q.order), PrimitiveKind::Quad),
|
||||
(self.paths_iter.peek().map(|q| q.order), PrimitiveKind::Path),
|
||||
(
|
||||
self.underlines_iter.peek().map(|u| u.order),
|
||||
PrimitiveKind::Underline,
|
||||
),
|
||||
(
|
||||
self.monochrome_sprites_iter.peek().map(|s| s.order),
|
||||
PrimitiveKind::MonochromeSprite,
|
||||
),
|
||||
(
|
||||
self.polychrome_sprites_iter.peek().map(|s| s.order),
|
||||
PrimitiveKind::PolychromeSprite,
|
||||
),
|
||||
(
|
||||
self.surfaces_iter.peek().map(|s| s.order),
|
||||
PrimitiveKind::Surface,
|
||||
),
|
||||
];
|
||||
orders_and_kinds.sort_by_key(|(order, kind)| (order.unwrap_or(u32::MAX), *kind));
|
||||
|
||||
let first = orders_and_kinds[0];
|
||||
let second = orders_and_kinds[1];
|
||||
let (batch_kind, max_order_and_kind) = if first.0.is_some() {
|
||||
(first.1, (second.0.unwrap_or(u32::MAX), second.1))
|
||||
} else {
|
||||
return None;
|
||||
};
|
||||
|
||||
match batch_kind {
|
||||
PrimitiveKind::Shadow => {
|
||||
let shadows_start = self.shadows_start;
|
||||
let mut shadows_end = shadows_start + 1;
|
||||
self.shadows_iter.next();
|
||||
while self
|
||||
.shadows_iter
|
||||
.next_if(|shadow| (shadow.order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
shadows_end += 1;
|
||||
}
|
||||
self.shadows_start = shadows_end;
|
||||
Some(PrimitiveBatch::Shadows(
|
||||
&self.shadows[shadows_start..shadows_end],
|
||||
))
|
||||
}
|
||||
PrimitiveKind::Quad => {
|
||||
let quads_start = self.quads_start;
|
||||
let mut quads_end = quads_start + 1;
|
||||
self.quads_iter.next();
|
||||
while self
|
||||
.quads_iter
|
||||
.next_if(|quad| (quad.order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
quads_end += 1;
|
||||
}
|
||||
self.quads_start = quads_end;
|
||||
Some(PrimitiveBatch::Quads(&self.quads[quads_start..quads_end]))
|
||||
}
|
||||
PrimitiveKind::Path => {
|
||||
let paths_start = self.paths_start;
|
||||
let mut paths_end = paths_start + 1;
|
||||
self.paths_iter.next();
|
||||
while self
|
||||
.paths_iter
|
||||
.next_if(|path| (path.order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
paths_end += 1;
|
||||
}
|
||||
self.paths_start = paths_end;
|
||||
Some(PrimitiveBatch::Paths(&self.paths[paths_start..paths_end]))
|
||||
}
|
||||
PrimitiveKind::Underline => {
|
||||
let underlines_start = self.underlines_start;
|
||||
let mut underlines_end = underlines_start + 1;
|
||||
self.underlines_iter.next();
|
||||
while self
|
||||
.underlines_iter
|
||||
.next_if(|underline| (underline.order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
underlines_end += 1;
|
||||
}
|
||||
self.underlines_start = underlines_end;
|
||||
Some(PrimitiveBatch::Underlines(
|
||||
&self.underlines[underlines_start..underlines_end],
|
||||
))
|
||||
}
|
||||
PrimitiveKind::MonochromeSprite => {
|
||||
let texture_id = self.monochrome_sprites_iter.peek().unwrap().tile.texture_id;
|
||||
let sprites_start = self.monochrome_sprites_start;
|
||||
let mut sprites_end = sprites_start + 1;
|
||||
self.monochrome_sprites_iter.next();
|
||||
while self
|
||||
.monochrome_sprites_iter
|
||||
.next_if(|sprite| {
|
||||
(sprite.order, batch_kind) < max_order_and_kind
|
||||
&& sprite.tile.texture_id == texture_id
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
sprites_end += 1;
|
||||
}
|
||||
self.monochrome_sprites_start = sprites_end;
|
||||
Some(PrimitiveBatch::MonochromeSprites {
|
||||
texture_id,
|
||||
sprites: &self.monochrome_sprites[sprites_start..sprites_end],
|
||||
})
|
||||
}
|
||||
PrimitiveKind::PolychromeSprite => {
|
||||
let texture_id = self.polychrome_sprites_iter.peek().unwrap().tile.texture_id;
|
||||
let sprites_start = self.polychrome_sprites_start;
|
||||
let mut sprites_end = self.polychrome_sprites_start + 1;
|
||||
self.polychrome_sprites_iter.next();
|
||||
while self
|
||||
.polychrome_sprites_iter
|
||||
.next_if(|sprite| {
|
||||
(sprite.order, batch_kind) < max_order_and_kind
|
||||
&& sprite.tile.texture_id == texture_id
|
||||
})
|
||||
.is_some()
|
||||
{
|
||||
sprites_end += 1;
|
||||
}
|
||||
self.polychrome_sprites_start = sprites_end;
|
||||
Some(PrimitiveBatch::PolychromeSprites {
|
||||
texture_id,
|
||||
sprites: &self.polychrome_sprites[sprites_start..sprites_end],
|
||||
})
|
||||
}
|
||||
PrimitiveKind::Surface => {
|
||||
let surfaces_start = self.surfaces_start;
|
||||
let mut surfaces_end = surfaces_start + 1;
|
||||
self.surfaces_iter.next();
|
||||
while self
|
||||
.surfaces_iter
|
||||
.next_if(|surface| (surface.order, batch_kind) < max_order_and_kind)
|
||||
.is_some()
|
||||
{
|
||||
surfaces_end += 1;
|
||||
}
|
||||
self.surfaces_start = surfaces_end;
|
||||
Some(PrimitiveBatch::Surfaces(
|
||||
&self.surfaces[surfaces_start..surfaces_end],
|
||||
))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) struct PrimitiveBatches<'a> {
|
||||
primitives: iter::Peekable<slice::Iter<'a, Primitive>>,
|
||||
shadows: Vec<Shadow>,
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{
|
||||
seal::Sealed, AnyElement, AnyModel, AnyWeakModel, AppContext, Bounds, ContentMask, Element,
|
||||
ElementContext, ElementId, Entity, EntityId, Flatten, FocusHandle, FocusableView, IntoElement,
|
||||
LayoutId, Model, Pixels, Render, Style, TextStyle, ViewContext, VisualContext, WeakModel,
|
||||
LayoutId, Model, PaintIndex, Pixels, Render, Style, TextStyle, ViewContext, VisualContext,
|
||||
WeakModel,
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use std::{
|
||||
|
@ -23,6 +24,7 @@ impl<V> Sealed for View<V> {}
|
|||
struct AnyViewState {
|
||||
root_style: Style,
|
||||
occlusion_range: Range<usize>,
|
||||
paint_range: Range<PaintIndex>,
|
||||
cache_key: ViewCacheKey,
|
||||
}
|
||||
|
||||
|
@ -285,10 +287,6 @@ impl Element for AnyView {
|
|||
fn before_layout(&mut self, cx: &mut ElementContext) -> (LayoutId, Self::BeforeLayout) {
|
||||
cx.with_view_id(self.entity_id(), |cx| {
|
||||
if self.cache {
|
||||
let mut element = (self.render)(self, cx);
|
||||
let layout_id = element.before_layout(cx);
|
||||
(layout_id, Some(element))
|
||||
} else {
|
||||
cx.with_element_state::<AnyViewState, _>(
|
||||
Some(ElementId::View(self.entity_id())),
|
||||
|element_state, cx| {
|
||||
|
@ -312,10 +310,15 @@ impl Element for AnyView {
|
|||
root_style: cx.layout_style(layout_id).unwrap().clone(),
|
||||
cache_key: ViewCacheKey::default(),
|
||||
occlusion_range: 0..0,
|
||||
paint_range: PaintIndex::default()..PaintIndex::default(),
|
||||
});
|
||||
((layout_id, Some(element)), element_state)
|
||||
},
|
||||
)
|
||||
} else {
|
||||
let mut element = (self.render)(self, cx);
|
||||
let layout_id = element.before_layout(cx);
|
||||
(layout_id, Some(element))
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -328,12 +331,6 @@ impl Element for AnyView {
|
|||
) -> Option<AnyElement> {
|
||||
cx.with_view_id(self.entity_id(), |cx| {
|
||||
if self.cache {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
let mut element = element.take().unwrap();
|
||||
element.after_layout(cx);
|
||||
Some(element)
|
||||
})
|
||||
} else {
|
||||
cx.with_element_state::<AnyViewState, _>(
|
||||
Some(ElementId::View(self.entity_id())),
|
||||
|element_state, cx| {
|
||||
|
@ -373,6 +370,12 @@ impl Element for AnyView {
|
|||
}
|
||||
},
|
||||
)
|
||||
} else {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
let mut element = element.take().unwrap();
|
||||
element.after_layout(cx);
|
||||
Some(element)
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
|
@ -385,13 +388,28 @@ impl Element for AnyView {
|
|||
cx: &mut ElementContext,
|
||||
) {
|
||||
cx.paint_view(self.entity_id(), |cx| {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
if let Some(element) = element.as_mut() {
|
||||
element.paint(cx);
|
||||
} else {
|
||||
cx.reuse_paint();
|
||||
}
|
||||
})
|
||||
if self.cache {
|
||||
cx.with_element_state::<AnyViewState, _>(
|
||||
Some(ElementId::View(self.entity_id())),
|
||||
|element_state, cx| {
|
||||
let mut element_state = element_state.unwrap().unwrap();
|
||||
|
||||
if let Some(element) = element {
|
||||
element_state.paint_range.start = cx.window.next_frame.paint_index();
|
||||
element.paint(cx);
|
||||
element_state.paint_range.end = cx.window.next_frame.paint_index();
|
||||
} else {
|
||||
cx.reuse_paint(element_state.paint_range.clone());
|
||||
}
|
||||
|
||||
((), Some(element_state))
|
||||
},
|
||||
)
|
||||
} else {
|
||||
cx.with_element_id(Some(ElementId::View(self.entity_id())), |cx| {
|
||||
element.as_mut().unwrap().paint(cx);
|
||||
})
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -855,6 +855,17 @@ impl<'a> WindowContext<'a> {
|
|||
self.window.mouse_position
|
||||
}
|
||||
|
||||
/// Finds the topmost [Occlusion] in the upcoming frame containing the given position.
|
||||
pub fn topmost_occlusion(&self, position: Point<Pixels>) -> Option<Occlusion> {
|
||||
self.window
|
||||
.next_frame
|
||||
.occlusions
|
||||
.iter()
|
||||
.rev()
|
||||
.find(|occlusion| occlusion.bounds.contains(&position))
|
||||
.cloned()
|
||||
}
|
||||
|
||||
/// The current state of the keyboard's modifiers
|
||||
pub fn modifiers(&self) -> Modifiers {
|
||||
self.window.modifiers
|
||||
|
@ -908,7 +919,8 @@ impl<'a> WindowContext<'a> {
|
|||
|
||||
// Set the cursor only if we're the active window.
|
||||
if self.is_window_active() {
|
||||
self.compute_cursor_style();
|
||||
let cursor_style = self.compute_cursor_style().unwrap_or(CursorStyle::Arrow);
|
||||
self.platform.set_cursor_style(cursor_style);
|
||||
}
|
||||
|
||||
// Register requested input handler with the platform window.
|
||||
|
@ -982,15 +994,15 @@ impl<'a> WindowContext<'a> {
|
|||
|
||||
fn compute_cursor_style(&mut self) -> Option<CursorStyle> {
|
||||
let mouse_position = self.mouse_position();
|
||||
|
||||
let occlusion = self.topmost_occlusion(mouse_position)?;
|
||||
// TODO: maybe we should have a HashMap keyed by OcclusionId.
|
||||
let cursor_style = self
|
||||
let request = self
|
||||
.window
|
||||
.next_frame
|
||||
.cursor_styles
|
||||
.iter()
|
||||
.take()
|
||||
.unwrap_or(CursorStyle::Arrow);
|
||||
.find(|request| request.occlusion_id == occlusion.id)?;
|
||||
Some(request.style)
|
||||
}
|
||||
|
||||
/// Dispatch a given keystroke as though the user had typed it.
|
||||
|
@ -1127,44 +1139,38 @@ impl<'a> WindowContext<'a> {
|
|||
}
|
||||
|
||||
fn dispatch_mouse_event(&mut self, event: &dyn Any) {
|
||||
if let Some(mut handlers) = self
|
||||
.window
|
||||
.rendered_frame
|
||||
.mouse_listeners
|
||||
.remove(&event.type_id())
|
||||
{
|
||||
// Because handlers may add other handlers, we sort every time.
|
||||
handlers.sort_by(|(a, _, _), (b, _, _)| a.cmp(b));
|
||||
let Some(mouse_occlusion) = self.topmost_occlusion(self.mouse_position()) else {
|
||||
return;
|
||||
};
|
||||
|
||||
// Capture phase, events bubble from back to front. Handlers for this phase are used for
|
||||
// special purposes, such as detecting events outside of a given Bounds.
|
||||
for (_, _, handler) in &mut handlers {
|
||||
// Capture phase, events bubble from back to front. Handlers for this phase are used for
|
||||
// special purposes, such as detecting events outside of a given Bounds.
|
||||
for listener in &mut self.window.rendered_frame.mouse_listeners {
|
||||
self.with_element_context(|cx| {
|
||||
handler(event, DispatchPhase::Capture, cx);
|
||||
});
|
||||
if !self.app.propagate_event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble phase, where most normal handlers do their work.
|
||||
if self.app.propagate_event {
|
||||
for (_, _, handler) in handlers.iter_mut().rev() {
|
||||
self.with_element_context(|cx| {
|
||||
handler(event, DispatchPhase::Capture, cx);
|
||||
handler(event, DispatchPhase::Bubble, cx);
|
||||
});
|
||||
if !self.app.propagate_event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Bubble phase, where most normal handlers do their work.
|
||||
if self.app.propagate_event {
|
||||
for (_, _, handler) in handlers.iter_mut().rev() {
|
||||
self.with_element_context(|cx| {
|
||||
handler(event, DispatchPhase::Bubble, cx);
|
||||
});
|
||||
if !self.app.propagate_event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.window
|
||||
.rendered_frame
|
||||
.mouse_listeners
|
||||
.insert(event.type_id(), handlers);
|
||||
}
|
||||
|
||||
self.window
|
||||
.rendered_frame
|
||||
.mouse_listeners
|
||||
.insert(event.type_id(), handlers);
|
||||
|
||||
if self.app.propagate_event && self.has_active_drag() {
|
||||
if event.is::<MouseMoveEvent>() {
|
||||
// If this was a mouse move event, redraw the window so that the
|
||||
|
|
|
@ -38,7 +38,11 @@ use crate::{
|
|||
SUBPIXEL_VARIANTS,
|
||||
};
|
||||
|
||||
type AnyMouseListener = Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>;
|
||||
struct MouseListener {
|
||||
occlusion_id: OcclusionId,
|
||||
invert_occlusion: bool,
|
||||
callback: Box<dyn FnMut(&dyn Any, DispatchPhase, &mut ElementContext) + 'static>,
|
||||
}
|
||||
|
||||
pub(crate) struct RequestedInputHandler {
|
||||
pub(crate) view_id: EntityId,
|
||||
|
@ -50,13 +54,19 @@ pub(crate) struct TooltipRequest {
|
|||
pub(crate) tooltip: AnyTooltip,
|
||||
}
|
||||
|
||||
/// Identifies an occlusion, see [ElementContext::insert_occlusion] for more details.
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
pub struct OcclusionId(usize);
|
||||
struct CursorStyleRequest {
|
||||
pub(crate) occlusion_id: OcclusionId,
|
||||
pub(crate) style: CursorStyle,
|
||||
}
|
||||
|
||||
#[derive(Clone)]
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
pub(crate) struct OcclusionId(usize);
|
||||
|
||||
/// Identifies an occlusion, see [ElementContext::insert_occlusion] for more details.
|
||||
#[derive(Clone, Deref)]
|
||||
pub(crate) struct Occlusion {
|
||||
pub(crate) id: OcclusionId,
|
||||
#[deref]
|
||||
pub(crate) bounds: Bounds<Pixels>,
|
||||
}
|
||||
|
||||
|
@ -64,7 +74,7 @@ pub(crate) struct Frame {
|
|||
pub(crate) focus: Option<FocusId>,
|
||||
pub(crate) window_active: bool,
|
||||
pub(crate) element_states: FxHashMap<(GlobalElementId, TypeId), ElementStateBox>,
|
||||
pub(crate) mouse_listeners: Vec<AnyMouseListener>,
|
||||
pub(crate) mouse_listeners: Vec<MouseListener>,
|
||||
pub(crate) dispatch_tree: DispatchTree,
|
||||
pub(crate) scene: Scene,
|
||||
pub(crate) occlusions: Vec<Occlusion>,
|
||||
|
@ -72,17 +82,14 @@ pub(crate) struct Frame {
|
|||
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: Vec<(OcclusionId, CursorStyle)>,
|
||||
pub(crate) cursor_styles: Vec<CursorStyleRequest>,
|
||||
pub(crate) view_stack: Vec<EntityId>,
|
||||
pub(crate) reused_views: FxHashSet<EntityId>,
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub(crate) debug_bounds: FxHashMap<String, Bounds<Pixels>>,
|
||||
}
|
||||
|
||||
pub(crate) struct LayoutIndex {
|
||||
occlusion_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Default)]
|
||||
pub(crate) struct PaintIndex {
|
||||
scene_index: usize,
|
||||
mouse_listeners_index: usize,
|
||||
|
@ -126,10 +133,8 @@ impl Frame {
|
|||
debug_assert_eq!(self.view_stack.len(), 0);
|
||||
}
|
||||
|
||||
pub(crate) fn layout_index(&self) -> LayoutIndex {
|
||||
LayoutIndex {
|
||||
occlusion_index: self.occlusions.len(),
|
||||
}
|
||||
pub(crate) fn occlusion_index(&self) -> usize {
|
||||
self.occlusions.len()
|
||||
}
|
||||
|
||||
pub(crate) fn paint_index(&self) -> PaintIndex {
|
||||
|
@ -137,6 +142,7 @@ impl Frame {
|
|||
scene_index: self.scene.len(),
|
||||
mouse_listeners_index: self.mouse_listeners.len(),
|
||||
cursor_styles_index: self.cursor_styles.len(),
|
||||
dispatch_tree_index: self.dispatch_tree.len(),
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -353,12 +359,9 @@ impl<'a> ElementContext<'a> {
|
|||
}
|
||||
}
|
||||
|
||||
pub(crate) fn reuse_layout(&mut self, range: Range<LayoutIndex>) {
|
||||
pub(crate) fn reuse_occlusions(&mut self, range: Range<usize>) {
|
||||
let window = &mut self.window;
|
||||
|
||||
for occlusion in &window.rendered_frame.occlusions
|
||||
[range.start.occlusion_index..range.end.occlusion_index]
|
||||
{
|
||||
for occlusion in &window.rendered_frame.occlusions[range] {
|
||||
window.next_frame.occlusions.push(occlusion.clone());
|
||||
}
|
||||
}
|
||||
|
@ -429,7 +432,10 @@ impl<'a> ElementContext<'a> {
|
|||
self.window
|
||||
.next_frame
|
||||
.cursor_styles
|
||||
.push((occlusion_id, style));
|
||||
.push(CursorStyleRequest {
|
||||
occlusion_id,
|
||||
style,
|
||||
});
|
||||
}
|
||||
|
||||
/// Sets a tooltip to be rendered for the upcoming frame
|
||||
|
@ -1048,12 +1054,13 @@ impl<'a> ElementContext<'a> {
|
|||
/// This method should be called during `after_layout`. You can use
|
||||
/// the returned [OcclusionId] during `paint` or in an event handler
|
||||
/// to determine whether the inserted occlusion was the topmost.
|
||||
pub fn insert_occlusion(&mut self, bounds: Bounds<Pixels>) -> OcclusionId {
|
||||
pub fn occlude(&mut self, bounds: Bounds<Pixels>) -> Occlusion {
|
||||
let window = &mut self.window;
|
||||
let id = window.next_occlusion_id;
|
||||
window.next_occlusion_id.0 += 1;
|
||||
window.next_frame.occlusions.push(Occlusion { id, bounds });
|
||||
id
|
||||
let occlusion = Occlusion { id, bounds };
|
||||
window.next_frame.occlusions.push(occlusion.clone());
|
||||
occlusion
|
||||
}
|
||||
|
||||
/// Invoke the given function with the given focus handle present on the key dispatch stack.
|
||||
|
@ -1139,15 +1146,21 @@ impl<'a> ElementContext<'a> {
|
|||
/// the listener will be cleared.
|
||||
pub fn on_mouse_event<Event: MouseEvent>(
|
||||
&mut self,
|
||||
// occlusion: Occlusion,
|
||||
mut handler: impl FnMut(&Event, DispatchPhase, &mut ElementContext) + 'static,
|
||||
) {
|
||||
self.window.next_frame.mouse_listeners.push(Box::new(
|
||||
move |event: &dyn Any, phase: DispatchPhase, cx: &mut ElementContext<'_>| {
|
||||
if let Some(event) = event.downcast_ref() {
|
||||
handler(event, phase, cx)
|
||||
}
|
||||
},
|
||||
));
|
||||
let occlusion: Occlusion = todo!();
|
||||
self.window.next_frame.mouse_listeners.push(MouseListener {
|
||||
occlusion_id: occlusion.id,
|
||||
invert_occlusion: false,
|
||||
callback: Box::new(
|
||||
move |event: &dyn Any, phase: DispatchPhase, cx: &mut ElementContext<'_>| {
|
||||
if let Some(event) = event.downcast_ref() {
|
||||
handler(event, phase, cx)
|
||||
}
|
||||
},
|
||||
),
|
||||
});
|
||||
}
|
||||
|
||||
/// Register a key event listener on the window for the next frame. The type of event
|
||||
|
|
|
@ -763,7 +763,7 @@ mod element {
|
|||
})
|
||||
}
|
||||
|
||||
cx.insert_occlusion(handle_bounds);
|
||||
cx.occlude(handle_bounds);
|
||||
cx.paint_quad(gpui::fill(divider_bounds, cx.theme().colors().border));
|
||||
|
||||
cx.on_mouse_event({
|
||||
|
|
|
@ -4629,7 +4629,7 @@ impl Element for DisconnectedOverlay {
|
|||
overlay: &mut Self::BeforeLayout,
|
||||
cx: &mut ElementContext,
|
||||
) {
|
||||
cx.insert_occlusion(bounds);
|
||||
cx.occlude(bounds);
|
||||
overlay.after_layout(cx);
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue