Checkpoint
This commit is contained in:
parent
7b610f8dd8
commit
f763ed9a7e
7 changed files with 309 additions and 22 deletions
|
@ -1,11 +1,13 @@
|
||||||
mod div;
|
mod div;
|
||||||
mod img;
|
mod img;
|
||||||
|
mod interactive;
|
||||||
mod stateless;
|
mod stateless;
|
||||||
mod svg;
|
mod svg;
|
||||||
mod text;
|
mod text;
|
||||||
|
|
||||||
pub use div::*;
|
pub use div::*;
|
||||||
pub use img::*;
|
pub use img::*;
|
||||||
|
pub use interactive::*;
|
||||||
pub use stateless::*;
|
pub use stateless::*;
|
||||||
pub use svg::*;
|
pub use svg::*;
|
||||||
pub use text::*;
|
pub use text::*;
|
||||||
|
|
152
crates/gpui3/src/elements/interactive.rs
Normal file
152
crates/gpui3/src/elements/interactive.rs
Normal file
|
@ -0,0 +1,152 @@
|
||||||
|
use crate::{
|
||||||
|
Bounds, DispatchPhase, MouseButton, MouseDownEvent, MouseUpEvent, Pixels, ViewContext,
|
||||||
|
};
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
use smallvec::SmallVec;
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
pub trait Interactive<S: 'static + Send + Sync> {
|
||||||
|
fn interaction_listeners(&mut self) -> &mut InteractionHandlers<S>;
|
||||||
|
|
||||||
|
fn on_mouse_down(
|
||||||
|
mut self,
|
||||||
|
button: MouseButton,
|
||||||
|
handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.interaction_listeners()
|
||||||
|
.mouse_down
|
||||||
|
.push(Arc::new(move |view, event, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Bubble && event.button == button {
|
||||||
|
handler(view, event, cx)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_mouse_up(
|
||||||
|
mut self,
|
||||||
|
button: MouseButton,
|
||||||
|
handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.interaction_listeners()
|
||||||
|
.mouse_up
|
||||||
|
.push(Arc::new(move |view, event, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Bubble && event.button == button {
|
||||||
|
handler(view, event, cx)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_mouse_down_out(
|
||||||
|
mut self,
|
||||||
|
button: MouseButton,
|
||||||
|
handler: impl Fn(&mut S, &MouseDownEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.interaction_listeners()
|
||||||
|
.mouse_down
|
||||||
|
.push(Arc::new(move |view, event, phase, cx| {
|
||||||
|
if phase == DispatchPhase::Capture && event.button == button {
|
||||||
|
handler(view, event, cx)
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_mouse_up_out(
|
||||||
|
mut self,
|
||||||
|
button: MouseButton,
|
||||||
|
handler: impl Fn(&mut S, &MouseUpEvent, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
self.interaction_listeners()
|
||||||
|
.mouse_up
|
||||||
|
.push(Arc::new(move |view, event, phase, cx| {
|
||||||
|
if event.button == button && phase == DispatchPhase::Capture {
|
||||||
|
handler(view, event, cx);
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
self
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_click(
|
||||||
|
self,
|
||||||
|
button: MouseButton,
|
||||||
|
handler: impl Fn(&mut S, &MouseDownEvent, &MouseUpEvent, &mut ViewContext<S>)
|
||||||
|
+ Send
|
||||||
|
+ Sync
|
||||||
|
+ 'static,
|
||||||
|
) -> Self
|
||||||
|
where
|
||||||
|
Self: Sized,
|
||||||
|
{
|
||||||
|
let down_event = Arc::new(Mutex::new(None));
|
||||||
|
self.on_mouse_down(button, {
|
||||||
|
let down_event = down_event.clone();
|
||||||
|
move |_, event, _| {
|
||||||
|
down_event.lock().replace(event.clone());
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_mouse_up_out(button, {
|
||||||
|
let down_event = down_event.clone();
|
||||||
|
move |_, _, _| {
|
||||||
|
down_event.lock().take();
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.on_mouse_up(button, move |view, event, cx| {
|
||||||
|
if let Some(down_event) = down_event.lock().take() {
|
||||||
|
handler(view, &down_event, event, cx);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type MouseDownHandler<V> = Arc<
|
||||||
|
dyn Fn(&mut V, &MouseDownEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||||
|
>;
|
||||||
|
type MouseUpHandler<V> =
|
||||||
|
Arc<dyn Fn(&mut V, &MouseUpEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||||
|
|
||||||
|
pub struct InteractionHandlers<V: 'static> {
|
||||||
|
mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
|
||||||
|
mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Send + Sync + 'static> InteractionHandlers<S> {
|
||||||
|
pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<S>) {
|
||||||
|
for handler in self.mouse_down.iter().cloned() {
|
||||||
|
cx.on_mouse_event(move |view, event: &MouseDownEvent, phase, cx| {
|
||||||
|
if bounds.contains_point(event.position) {
|
||||||
|
handler(view, event, phase, cx);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
for handler in self.mouse_up.iter().cloned() {
|
||||||
|
cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
|
||||||
|
if bounds.contains_point(event.position) {
|
||||||
|
handler(view, event, phase, cx);
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<V> Default for InteractionHandlers<V> {
|
||||||
|
fn default() -> Self {
|
||||||
|
Self {
|
||||||
|
mouse_down: Default::default(),
|
||||||
|
mouse_up: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -27,6 +27,7 @@ impl MetalAtlas {
|
||||||
self.0.lock().texture(id).metal_texture.clone()
|
self.0.lock().texture(id).metal_texture.clone()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
pub(crate) fn allocate(
|
pub(crate) fn allocate(
|
||||||
&self,
|
&self,
|
||||||
size: Size<DevicePixels>,
|
size: Size<DevicePixels>,
|
||||||
|
|
|
@ -172,7 +172,7 @@ impl MetalRenderer {
|
||||||
let command_buffer = command_queue.new_command_buffer();
|
let command_buffer = command_queue.new_command_buffer();
|
||||||
let mut instance_offset = 0;
|
let mut instance_offset = 0;
|
||||||
|
|
||||||
let path_tiles = self.rasterize_paths(scene.paths(), &mut instance_offset, &command_buffer);
|
// let path_tiles = self.rasterize_paths(scene.paths(), &mut instance_offset, &command_buffer);
|
||||||
|
|
||||||
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
let render_pass_descriptor = metal::RenderPassDescriptor::new();
|
||||||
let color_attachment = render_pass_descriptor
|
let color_attachment = render_pass_descriptor
|
||||||
|
@ -208,7 +208,7 @@ impl MetalRenderer {
|
||||||
PrimitiveBatch::Quads(quads) => {
|
PrimitiveBatch::Quads(quads) => {
|
||||||
self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder);
|
self.draw_quads(quads, &mut instance_offset, viewport_size, command_encoder);
|
||||||
}
|
}
|
||||||
PrimitiveBatch::Paths(paths) => {
|
PrimitiveBatch::Paths(_paths) => {
|
||||||
// self.draw_paths(paths, &mut instance_offset, viewport_size, command_encoder);
|
// self.draw_paths(paths, &mut instance_offset, viewport_size, command_encoder);
|
||||||
}
|
}
|
||||||
PrimitiveBatch::Underlines(underlines) => {
|
PrimitiveBatch::Underlines(underlines) => {
|
||||||
|
@ -258,11 +258,12 @@ impl MetalRenderer {
|
||||||
drawable.present();
|
drawable.present();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
fn rasterize_paths(
|
fn rasterize_paths(
|
||||||
&mut self,
|
&mut self,
|
||||||
paths: &[Path<ScaledPixels>],
|
paths: &[Path<ScaledPixels>],
|
||||||
offset: &mut usize,
|
_offset: &mut usize,
|
||||||
command_buffer: &metal::CommandBufferRef,
|
_command_buffer: &metal::CommandBufferRef,
|
||||||
) -> HashMap<PathId, AtlasTile> {
|
) -> HashMap<PathId, AtlasTile> {
|
||||||
let mut tiles = HashMap::default();
|
let mut tiles = HashMap::default();
|
||||||
let mut vertices_by_texture_id = HashMap::default();
|
let mut vertices_by_texture_id = HashMap::default();
|
||||||
|
@ -288,7 +289,7 @@ impl MetalRenderer {
|
||||||
tiles.insert(path.id, tile);
|
tiles.insert(path.id, tile);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (texture_id, vertices) in vertices_by_texture_id {
|
for (_texture_id, _vertices) in vertices_by_texture_id {
|
||||||
todo!();
|
todo!();
|
||||||
// align_offset(offset);
|
// align_offset(offset);
|
||||||
// let next_offset = *offset + vertices.len() * mem::size_of::<PathVertex<ScaledPixels>>();
|
// let next_offset = *offset + vertices.len() * mem::size_of::<PathVertex<ScaledPixels>>();
|
||||||
|
|
|
@ -923,7 +923,7 @@ extern "C" fn send_event(this: &mut Object, _sel: Sel, native_event: id) {
|
||||||
if let Some(event) = Event::from_native(native_event, None) {
|
if let Some(event) = Event::from_native(native_event, None) {
|
||||||
let platform = get_foreground_platform(this);
|
let platform = get_foreground_platform(this);
|
||||||
if let Some(callback) = platform.0.lock().event.as_mut() {
|
if let Some(callback) = platform.0.lock().event.as_mut() {
|
||||||
if callback(event) {
|
if !callback(event) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,17 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, Hsla, Pixels, Point,
|
point, AtlasTextureId, AtlasTile, Bounds, ContentMask, Corners, Edges, Hsla, Pixels, Point,
|
||||||
ScaledPixels,
|
ScaledPixels, StackingOrder,
|
||||||
};
|
};
|
||||||
use collections::BTreeMap;
|
use collections::BTreeMap;
|
||||||
use etagere::euclid::{Point3D, Vector3D};
|
use etagere::euclid::{Point3D, Vector3D};
|
||||||
use plane_split::{BspSplitter, Polygon as BspPolygon};
|
use plane_split::{BspSplitter, Polygon as BspPolygon};
|
||||||
use smallvec::SmallVec;
|
|
||||||
use std::{fmt::Debug, iter::Peekable, mem, slice};
|
use std::{fmt::Debug, iter::Peekable, mem, slice};
|
||||||
|
|
||||||
// Exported to metal
|
// Exported to metal
|
||||||
pub type PointF = Point<f32>;
|
pub type PointF = Point<f32>;
|
||||||
pub type StackingOrder = SmallVec<[u32; 16]>;
|
|
||||||
pub type LayerId = u32;
|
pub type LayerId = u32;
|
||||||
|
|
||||||
pub type DrawOrder = u32;
|
pub type DrawOrder = u32;
|
||||||
|
|
||||||
pub(crate) struct SceneBuilder {
|
pub(crate) struct SceneBuilder {
|
||||||
|
@ -180,6 +180,7 @@ pub(crate) struct Scene {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Scene {
|
impl Scene {
|
||||||
|
#[allow(dead_code)]
|
||||||
pub fn paths(&self) -> &[Path<ScaledPixels>] {
|
pub fn paths(&self) -> &[Path<ScaledPixels>] {
|
||||||
&self.paths
|
&self.paths
|
||||||
}
|
}
|
||||||
|
@ -731,9 +732,9 @@ mod tests {
|
||||||
let mut scene = SceneBuilder::new();
|
let mut scene = SceneBuilder::new();
|
||||||
assert_eq!(scene.layers_by_order.len(), 0);
|
assert_eq!(scene.layers_by_order.len(), 0);
|
||||||
|
|
||||||
scene.insert(&smallvec![1], quad());
|
scene.insert(&smallvec![1].into(), quad());
|
||||||
scene.insert(&smallvec![2], shadow());
|
scene.insert(&smallvec![2].into(), shadow());
|
||||||
scene.insert(&smallvec![3], quad());
|
scene.insert(&smallvec![3].into(), quad());
|
||||||
|
|
||||||
let mut batches_count = 0;
|
let mut batches_count = 0;
|
||||||
for _ in scene.build().batches() {
|
for _ in scene.build().batches() {
|
||||||
|
|
|
@ -1,20 +1,45 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext,
|
image_cache::RenderImageParams, px, size, AnyView, AppContext, AsyncWindowContext,
|
||||||
AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId,
|
AvailableSpace, BorrowAppContext, Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId,
|
||||||
Edges, Effect, Element, EntityId, FontId, GlyphId, Handle, Hsla, ImageData, IsZero, LayoutId,
|
Edges, Effect, Element, EntityId, Event, FontId, GlyphId, Handle, Hsla, ImageData, IsZero,
|
||||||
MainThread, MainThreadOnly, MonochromeSprite, Path, Pixels, PlatformAtlas, PlatformWindow,
|
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, Path, Pixels, PlatformAtlas,
|
||||||
Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderSvgParams, ScaledPixels,
|
PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams, RenderSvgParams,
|
||||||
SceneBuilder, Shadow, SharedString, Size, StackingOrder, Style, TaffyLayoutEngine, Task,
|
ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, TaffyLayoutEngine, Task,
|
||||||
Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
Underline, UnderlineStyle, WeakHandle, WindowOptions, SUBPIXEL_VARIANTS,
|
||||||
};
|
};
|
||||||
use anyhow::Result;
|
use anyhow::Result;
|
||||||
|
use collections::HashMap;
|
||||||
|
use derive_more::{Deref, DerefMut};
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
any::TypeId, borrow::Cow, fmt::Debug, future::Future, marker::PhantomData, mem, sync::Arc,
|
any::{Any, TypeId},
|
||||||
|
borrow::Cow,
|
||||||
|
fmt::Debug,
|
||||||
|
future::Future,
|
||||||
|
marker::PhantomData,
|
||||||
|
mem,
|
||||||
|
sync::Arc,
|
||||||
};
|
};
|
||||||
use util::ResultExt;
|
use util::ResultExt;
|
||||||
|
|
||||||
pub struct AnyWindow {}
|
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
|
||||||
|
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
|
||||||
|
|
||||||
|
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
|
||||||
|
pub enum DispatchPhase {
|
||||||
|
/// After the capture phase comes the bubble phase, in which event handlers are
|
||||||
|
/// invoked front to back. This is the phase you'll usually want to use for event handlers.
|
||||||
|
#[default]
|
||||||
|
Bubble,
|
||||||
|
/// During the initial capture phase, event handlers are invoked back to front. This phase
|
||||||
|
/// is used for special purposes such as clearing the "pressed" state for click events. If
|
||||||
|
/// you stop event propagation during this phase, you need to know what you're doing. Handlers
|
||||||
|
/// outside of the immediate region may rely on detecting non-local events during this phase.
|
||||||
|
Capture,
|
||||||
|
}
|
||||||
|
|
||||||
|
type MouseEventHandler =
|
||||||
|
Arc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||||
|
|
||||||
pub struct Window {
|
pub struct Window {
|
||||||
handle: AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
|
@ -25,9 +50,11 @@ pub struct Window {
|
||||||
content_size: Size<Pixels>,
|
content_size: Size<Pixels>,
|
||||||
layout_engine: TaffyLayoutEngine,
|
layout_engine: TaffyLayoutEngine,
|
||||||
pub(crate) root_view: Option<AnyView<()>>,
|
pub(crate) root_view: Option<AnyView<()>>,
|
||||||
mouse_position: Point<Pixels>,
|
|
||||||
current_stacking_order: StackingOrder,
|
current_stacking_order: StackingOrder,
|
||||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||||
|
mouse_event_handlers: HashMap<TypeId, Vec<(StackingOrder, MouseEventHandler)>>,
|
||||||
|
propagate_event: bool,
|
||||||
|
mouse_position: Point<Pixels>,
|
||||||
scale_factor: f32,
|
scale_factor: f32,
|
||||||
pub(crate) scene_builder: SceneBuilder,
|
pub(crate) scene_builder: SceneBuilder,
|
||||||
pub(crate) dirty: bool,
|
pub(crate) dirty: bool,
|
||||||
|
@ -46,7 +73,6 @@ impl Window {
|
||||||
let content_size = platform_window.content_size();
|
let content_size = platform_window.content_size();
|
||||||
let scale_factor = platform_window.scale_factor();
|
let scale_factor = platform_window.scale_factor();
|
||||||
platform_window.on_resize(Box::new({
|
platform_window.on_resize(Box::new({
|
||||||
let handle = handle;
|
|
||||||
let cx = cx.to_async();
|
let cx = cx.to_async();
|
||||||
move |content_size, scale_factor| {
|
move |content_size, scale_factor| {
|
||||||
cx.update_window(handle, |cx| {
|
cx.update_window(handle, |cx| {
|
||||||
|
@ -65,6 +91,15 @@ impl Window {
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
|
|
||||||
|
platform_window.on_event({
|
||||||
|
let cx = cx.to_async();
|
||||||
|
Box::new(move |event| {
|
||||||
|
cx.update_window(handle, |cx| cx.dispatch_event(event))
|
||||||
|
.log_err()
|
||||||
|
.unwrap_or(true)
|
||||||
|
})
|
||||||
|
});
|
||||||
|
|
||||||
let platform_window = MainThreadOnly::new(Arc::new(platform_window), cx.executor.clone());
|
let platform_window = MainThreadOnly::new(Arc::new(platform_window), cx.executor.clone());
|
||||||
|
|
||||||
Window {
|
Window {
|
||||||
|
@ -76,9 +111,11 @@ impl Window {
|
||||||
content_size,
|
content_size,
|
||||||
layout_engine: TaffyLayoutEngine::new(),
|
layout_engine: TaffyLayoutEngine::new(),
|
||||||
root_view: None,
|
root_view: None,
|
||||||
mouse_position,
|
current_stacking_order: StackingOrder(SmallVec::new()),
|
||||||
current_stacking_order: SmallVec::new(),
|
|
||||||
content_mask_stack: Vec::new(),
|
content_mask_stack: Vec::new(),
|
||||||
|
mouse_event_handlers: HashMap::default(),
|
||||||
|
propagate_event: true,
|
||||||
|
mouse_position,
|
||||||
scale_factor,
|
scale_factor,
|
||||||
scene_builder: SceneBuilder::new(),
|
scene_builder: SceneBuilder::new(),
|
||||||
dirty: true,
|
dirty: true,
|
||||||
|
@ -241,6 +278,27 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
self.window.rem_size
|
self.window.rem_size
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn stop_event_propagation(&mut self) {
|
||||||
|
self.window.propagate_event = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn on_mouse_event<Event: 'static>(
|
||||||
|
&mut self,
|
||||||
|
handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + Sync + 'static,
|
||||||
|
) {
|
||||||
|
let order = self.window.current_stacking_order.clone();
|
||||||
|
self.window
|
||||||
|
.mouse_event_handlers
|
||||||
|
.entry(TypeId::of::<Event>())
|
||||||
|
.or_default()
|
||||||
|
.push((
|
||||||
|
order,
|
||||||
|
Arc::new(move |event: &dyn Any, phase, cx| {
|
||||||
|
handler(event.downcast_ref().unwrap(), phase, cx)
|
||||||
|
}),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
pub fn mouse_position(&self) -> Point<Pixels> {
|
pub fn mouse_position(&self) -> Point<Pixels> {
|
||||||
self.window.mouse_position
|
self.window.mouse_position
|
||||||
}
|
}
|
||||||
|
@ -529,6 +587,11 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
pub(crate) fn draw(&mut self) -> Result<()> {
|
pub(crate) fn draw(&mut self) -> Result<()> {
|
||||||
let unit_entity = self.unit_entity.clone();
|
let unit_entity = self.unit_entity.clone();
|
||||||
self.update_entity(&unit_entity, |view, cx| {
|
self.update_entity(&unit_entity, |view, cx| {
|
||||||
|
cx.window
|
||||||
|
.mouse_event_handlers
|
||||||
|
.values_mut()
|
||||||
|
.for_each(Vec::clear);
|
||||||
|
|
||||||
let mut root_view = cx.window.root_view.take().unwrap();
|
let mut root_view = cx.window.root_view.take().unwrap();
|
||||||
let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
|
let (root_layout_id, mut frame_state) = root_view.layout(&mut (), cx)?;
|
||||||
let available_space = cx.window.content_size.map(Into::into);
|
let available_space = cx.window.content_size.map(Into::into);
|
||||||
|
@ -554,6 +617,54 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
Ok(())
|
Ok(())
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn dispatch_event(&mut self, event: Event) -> bool {
|
||||||
|
if let Some(any_mouse_event) = event.mouse_event() {
|
||||||
|
if let Some(mut handlers) = self
|
||||||
|
.window
|
||||||
|
.mouse_event_handlers
|
||||||
|
.remove(&any_mouse_event.type_id())
|
||||||
|
{
|
||||||
|
// We sort these every time, because handlers may add handlers. Probably fast enough.
|
||||||
|
handlers.sort_by(|(a, _), (b, _)| a.cmp(b));
|
||||||
|
|
||||||
|
// Handlers may set this to false by calling `stop_propagation`;
|
||||||
|
self.window.propagate_event = true;
|
||||||
|
|
||||||
|
// 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 &handlers {
|
||||||
|
handler(any_mouse_event, DispatchPhase::Capture, self);
|
||||||
|
if !self.window.propagate_event {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bubble phase
|
||||||
|
if self.window.propagate_event {
|
||||||
|
for (_, handler) in handlers.iter().rev() {
|
||||||
|
handler(any_mouse_event, DispatchPhase::Bubble, self);
|
||||||
|
if !self.window.propagate_event {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
handlers.extend(
|
||||||
|
self.window
|
||||||
|
.mouse_event_handlers
|
||||||
|
.get_mut(&any_mouse_event.type_id())
|
||||||
|
.into_iter()
|
||||||
|
.flat_map(|handlers| handlers.drain(..)),
|
||||||
|
);
|
||||||
|
self.window
|
||||||
|
.mouse_event_handlers
|
||||||
|
.insert(any_mouse_event.type_id(), handlers);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
true
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Context for WindowContext<'_, '_> {
|
impl Context for WindowContext<'_, '_> {
|
||||||
|
@ -786,6 +897,18 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn on_mouse_event<Event: 'static>(
|
||||||
|
&mut self,
|
||||||
|
handler: impl Fn(&mut S, &Event, DispatchPhase, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||||
|
) {
|
||||||
|
let handle = self.handle().upgrade(self).unwrap();
|
||||||
|
self.window_cx.on_mouse_event(move |event, phase, cx| {
|
||||||
|
handle.update(cx, |view, cx| {
|
||||||
|
handler(view, event, phase, cx);
|
||||||
|
})
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
|
pub(crate) fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
|
||||||
let entity_id = self.unit_entity.id;
|
let entity_id = self.unit_entity.id;
|
||||||
let mut cx = ViewContext::mutable(
|
let mut cx = ViewContext::mutable(
|
||||||
|
@ -874,3 +997,10 @@ pub struct AnyWindowHandle {
|
||||||
pub(crate) id: WindowId,
|
pub(crate) id: WindowId,
|
||||||
state_type: TypeId,
|
state_type: TypeId,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(any(test, feature = "test"))]
|
||||||
|
impl From<SmallVec<[u32; 16]>> for StackingOrder {
|
||||||
|
fn from(small_vec: SmallVec<[u32; 16]>) -> Self {
|
||||||
|
StackingOrder(small_vec)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue