Detailed changes
@@ -185,31 +185,27 @@ async fn test_newline_above_or_below_does_not_move_guest_cursor(
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
.await
.unwrap();
- let window_a = cx_a.add_empty_window();
- let editor_a =
- window_a.build_view(cx_a, |cx| Editor::for_buffer(buffer_a, Some(project_a), cx));
+ let cx_a = cx_a.add_empty_window();
+ let editor_a = cx_a.new_view(|cx| Editor::for_buffer(buffer_a, Some(project_a), cx));
let mut editor_cx_a = EditorTestContext {
- cx: VisualTestContext::from_window(window_a, cx_a),
- window: window_a.into(),
+ cx: cx_a.clone(),
+ window: cx_a.handle(),
editor: editor_a,
assertion_cx: AssertionContextManager::new(),
};
- let window_b = cx_b.add_empty_window();
- let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
-
+ let cx_b = cx_b.add_empty_window();
// Open a buffer as client B
let buffer_b = project_b
- .update(&mut cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
+ .update(cx_b, |p, cx| p.open_buffer((worktree_id, "a.txt"), cx))
.await
.unwrap();
- let editor_b = window_b.build_view(&mut cx_b, |cx| {
- Editor::for_buffer(buffer_b, Some(project_b), cx)
- });
+ let editor_b = cx_b.new_view(|cx| Editor::for_buffer(buffer_b, Some(project_b), cx));
+
let mut editor_cx_b = EditorTestContext {
- cx: cx_b,
- window: window_b.into(),
+ cx: cx_b.clone(),
+ window: cx_b.handle(),
editor: editor_b,
assertion_cx: AssertionContextManager::new(),
};
@@ -311,10 +307,9 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
.await
.unwrap();
- let window_b = cx_b.add_empty_window();
- let editor_b = window_b.build_view(cx_b, |cx| {
- Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx)
- });
+ let cx_b = cx_b.add_empty_window();
+ let editor_b =
+ cx_b.new_view(|cx| Editor::for_buffer(buffer_b.clone(), Some(project_b.clone()), cx));
let fake_language_server = fake_language_servers.next().await.unwrap();
cx_a.background_executor.run_until_parked();
@@ -323,10 +318,8 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
assert!(!buffer.completion_triggers().is_empty())
});
- let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
-
// Type a completion trigger character as the guest.
- editor_b.update(&mut cx_b, |editor, cx| {
+ editor_b.update(cx_b, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input(".", cx);
});
@@ -392,8 +385,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
});
// Confirm a completion on the guest.
-
- editor_b.update(&mut cx_b, |editor, cx| {
+ editor_b.update(cx_b, |editor, cx| {
assert!(editor.context_menu_visible());
editor.confirm_completion(&ConfirmCompletion { item_ix: Some(0) }, cx);
assert_eq!(editor.text(cx), "fn main() { a.first_method() }");
@@ -431,7 +423,7 @@ async fn test_collaborating_with_completion(cx_a: &mut TestAppContext, cx_b: &mu
);
});
- buffer_b.read_with(&mut cx_b, |buffer, _| {
+ buffer_b.read_with(cx_b, |buffer, _| {
assert_eq!(
buffer.text(),
"use d::SomeTrait;\nfn main() { a.first_method() }"
@@ -960,7 +952,7 @@ async fn test_share_project(
cx_c: &mut TestAppContext,
) {
let executor = cx_a.executor();
- let window_b = cx_b.add_empty_window();
+ let cx_b = cx_b.add_empty_window();
let mut server = TestServer::start(executor.clone()).await;
let client_a = server.create_client(cx_a, "user_a").await;
let client_b = server.create_client(cx_b, "user_b").await;
@@ -1075,7 +1067,7 @@ async fn test_share_project(
.await
.unwrap();
- let editor_b = window_b.build_view(cx_b, |cx| Editor::for_buffer(buffer_b, None, cx));
+ let editor_b = cx_b.new_view(|cx| Editor::for_buffer(buffer_b, None, cx));
// Client A sees client B's selection
executor.run_until_parked();
@@ -1089,8 +1081,7 @@ async fn test_share_project(
});
// Edit the buffer as client B and see that edit as client A.
- let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
- editor_b.update(&mut cx_b, |editor, cx| editor.handle_input("ok, ", cx));
+ editor_b.update(cx_b, |editor, cx| editor.handle_input("ok, ", cx));
executor.run_until_parked();
buffer_a.read_with(cx_a, |buffer, _| {
@@ -1099,7 +1090,7 @@ async fn test_share_project(
// Client B can invite client C on a project shared by client A.
active_call_b
- .update(&mut cx_b, |call, cx| {
+ .update(cx_b, |call, cx| {
call.invite(client_c.user_id().unwrap(), Some(project_b.clone()), cx)
})
.await
@@ -1190,12 +1181,8 @@ async fn test_on_input_format_from_host_to_guest(
.update(cx_a, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
.await
.unwrap();
- let window_a = cx_a.add_empty_window();
- let editor_a = window_a
- .update(cx_a, |_, cx| {
- cx.new_view(|cx| Editor::for_buffer(buffer_a, Some(project_a.clone()), cx))
- })
- .unwrap();
+ let cx_a = cx_a.add_empty_window();
+ let editor_a = cx_a.new_view(|cx| Editor::for_buffer(buffer_a, Some(project_a.clone()), cx));
let fake_language_server = fake_language_servers.next().await.unwrap();
executor.run_until_parked();
@@ -1226,10 +1213,9 @@ async fn test_on_input_format_from_host_to_guest(
.await
.unwrap();
- let mut cx_a = VisualTestContext::from_window(window_a, cx_a);
// Type a on type formatting trigger character as the guest.
cx_a.focus_view(&editor_a);
- editor_a.update(&mut cx_a, |editor, cx| {
+ editor_a.update(cx_a, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input(">", cx);
});
@@ -1241,7 +1227,7 @@ async fn test_on_input_format_from_host_to_guest(
});
// Undo should remove LSP edits first
- editor_a.update(&mut cx_a, |editor, cx| {
+ editor_a.update(cx_a, |editor, cx| {
assert_eq!(editor.text(cx), "fn main() { a>~< }");
editor.undo(&Undo, cx);
assert_eq!(editor.text(cx), "fn main() { a> }");
@@ -1252,7 +1238,7 @@ async fn test_on_input_format_from_host_to_guest(
assert_eq!(buffer.text(), "fn main() { a> }")
});
- editor_a.update(&mut cx_a, |editor, cx| {
+ editor_a.update(cx_a, |editor, cx| {
assert_eq!(editor.text(cx), "fn main() { a> }");
editor.undo(&Undo, cx);
assert_eq!(editor.text(cx), "fn main() { a }");
@@ -1323,17 +1309,15 @@ async fn test_on_input_format_from_guest_to_host(
.update(cx_b, |p, cx| p.open_buffer((worktree_id, "main.rs"), cx))
.await
.unwrap();
- let window_b = cx_b.add_empty_window();
- let editor_b = window_b.build_view(cx_b, |cx| {
- Editor::for_buffer(buffer_b, Some(project_b.clone()), cx)
- });
+ let cx_b = cx_b.add_empty_window();
+ let editor_b = cx_b.new_view(|cx| Editor::for_buffer(buffer_b, Some(project_b.clone()), cx));
let fake_language_server = fake_language_servers.next().await.unwrap();
executor.run_until_parked();
- let mut cx_b = VisualTestContext::from_window(window_b, cx_b);
+
// Type a on type formatting trigger character as the guest.
cx_b.focus_view(&editor_b);
- editor_b.update(&mut cx_b, |editor, cx| {
+ editor_b.update(cx_b, |editor, cx| {
editor.change_selections(None, cx, |s| s.select_ranges([13..13]));
editor.handle_input(":", cx);
});
@@ -1374,7 +1358,7 @@ async fn test_on_input_format_from_guest_to_host(
});
// Undo should remove LSP edits first
- editor_b.update(&mut cx_b, |editor, cx| {
+ editor_b.update(cx_b, |editor, cx| {
assert_eq!(editor.text(cx), "fn main() { a:~: }");
editor.undo(&Undo, cx);
assert_eq!(editor.text(cx), "fn main() { a: }");
@@ -1385,7 +1369,7 @@ async fn test_on_input_format_from_guest_to_host(
assert_eq!(buffer.text(), "fn main() { a: }")
});
- editor_b.update(&mut cx_b, |editor, cx| {
+ editor_b.update(cx_b, |editor, cx| {
assert_eq!(editor.text(cx), "fn main() { a: }");
editor.undo(&Undo, cx);
assert_eq!(editor.text(cx), "fn main() { a }");
@@ -1,11 +1,11 @@
#![deny(missing_docs)]
use crate::{
- div, Action, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext,
- BackgroundExecutor, ClipboardItem, Context, Entity, EventEmitter, ForegroundExecutor,
- IntoElement, Keystroke, Model, ModelContext, Pixels, Platform, Render, Result, Size, Task,
- TestDispatcher, TestPlatform, TestWindow, TextSystem, View, ViewContext, VisualContext,
- WindowContext, WindowHandle, WindowOptions,
+ Action, AnyElement, AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext,
+ AvailableSpace, BackgroundExecutor, ClipboardItem, Context, Entity, EventEmitter,
+ ForegroundExecutor, InputEvent, Keystroke, Model, ModelContext, Pixels, Platform, Point,
+ Render, Result, Size, Task, TestDispatcher, TestPlatform, TestWindow, TextSystem, View,
+ ViewContext, VisualContext, WindowContext, WindowHandle, WindowOptions,
};
use anyhow::{anyhow, bail};
use futures::{Stream, StreamExt};
@@ -167,10 +167,14 @@ impl TestAppContext {
}
/// Adds a new window with no content.
- pub fn add_empty_window(&mut self) -> AnyWindowHandle {
+ pub fn add_empty_window(&mut self) -> &mut VisualTestContext {
let mut cx = self.app.borrow_mut();
- cx.open_window(WindowOptions::default(), |cx| cx.new_view(|_| EmptyView {}))
- .any_handle
+ let window = cx.open_window(WindowOptions::default(), |cx| cx.new_view(|_| ()));
+ drop(cx);
+ let cx = Box::new(VisualTestContext::from_window(*window.deref(), self));
+ cx.run_until_parked();
+ // it might be nice to try and cleanup these at the end of each test.
+ Box::leak(cx)
}
/// Adds a new window, and returns its root view and a `VisualTestContext` which can be used
@@ -564,6 +568,11 @@ pub struct VisualTestContext {
}
impl<'a> VisualTestContext {
+ /// Get the underlying window handle underlying this context.
+ pub fn handle(&self) -> AnyWindowHandle {
+ self.window
+ }
+
/// Provides the `WindowContext` for the duration of the closure.
pub fn update<R>(&mut self, f: impl FnOnce(&mut WindowContext) -> R) -> R {
self.cx.update_window(self.window, |_, cx| f(cx)).unwrap()
@@ -609,6 +618,36 @@ impl<'a> VisualTestContext {
self.cx.simulate_input(self.window, input)
}
+ /// Draw an element to the window. Useful for simulating events or actions
+ pub fn draw(
+ &mut self,
+ origin: Point<Pixels>,
+ space: Size<AvailableSpace>,
+ f: impl FnOnce(&mut WindowContext) -> AnyElement,
+ ) {
+ self.update(|cx| {
+ let entity_id = cx
+ .window
+ .root_view
+ .as_ref()
+ .expect("Can't draw to this window without a root view")
+ .entity_id();
+ cx.with_view_id(entity_id, |cx| {
+ f(cx).draw(origin, space, cx);
+ });
+
+ cx.refresh();
+ })
+ }
+
+ /// Simulate an event from the platform, e.g. a SrollWheelEvent
+ /// Make sure you've called [VisualTestContext::draw] first!
+ pub fn simulate_event<E: InputEvent>(&mut self, event: E) {
+ self.test_window(self.window)
+ .simulate_input(event.to_platform_input());
+ self.background_executor.run_until_parked();
+ }
+
/// Simulates the user blurring the window.
pub fn deactivate_window(&mut self) {
if Some(self.window) == self.test_platform.active_window() {
@@ -763,12 +802,3 @@ impl AnyWindowHandle {
self.update(cx, |_, cx| cx.new_view(build_view)).unwrap()
}
}
-
-/// An EmptyView for testing.
-pub struct EmptyView {}
-
-impl Render for EmptyView {
- fn render(&mut self, _cx: &mut crate::ViewContext<Self>) -> impl IntoElement {
- div()
- }
-}
@@ -115,6 +115,12 @@ pub trait Render: 'static + Sized {
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl IntoElement;
}
+impl Render for () {
+ fn render(&mut self, _cx: &mut ViewContext<Self>) -> impl IntoElement {
+ ()
+ }
+}
+
/// You can derive [`IntoElement`] on any type that implements this trait.
/// It is used to allow views to be expressed in terms of abstract data.
pub trait RenderOnce: 'static {
@@ -30,6 +30,7 @@ struct StateInner {
logical_scroll_top: Option<ListOffset>,
alignment: ListAlignment,
overdraw: Pixels,
+ reset: bool,
#[allow(clippy::type_complexity)]
scroll_handler: Option<Box<dyn FnMut(&ListScrollEvent, &mut WindowContext)>>,
}
@@ -92,11 +93,17 @@ impl ListState {
alignment: orientation,
overdraw,
scroll_handler: None,
+ reset: false,
})))
}
+ /// Reset this instantiation of the list state.
+ ///
+ /// Note that this will cause scroll events to be dropped until the next paint.
pub fn reset(&self, element_count: usize) {
let state = &mut *self.0.borrow_mut();
+ state.reset = true;
+
state.logical_scroll_top = None;
state.items = SumTree::new();
state
@@ -152,11 +159,13 @@ impl ListState {
scroll_top.item_ix = item_count;
scroll_top.offset_in_item = px(0.);
}
+
state.logical_scroll_top = Some(scroll_top);
}
pub fn scroll_to_reveal_item(&self, ix: usize) {
let state = &mut *self.0.borrow_mut();
+
let mut scroll_top = state.logical_scroll_top();
let height = state
.last_layout_bounds
@@ -187,9 +196,9 @@ impl ListState {
/// Get the bounds for the given item in window coordinates.
pub fn bounds_for_item(&self, ix: usize) -> Option<Bounds<Pixels>> {
let state = &*self.0.borrow();
+
let bounds = state.last_layout_bounds.unwrap_or_default();
let scroll_top = state.logical_scroll_top();
-
if ix < scroll_top.item_ix {
return None;
}
@@ -230,6 +239,12 @@ impl StateInner {
delta: Point<Pixels>,
cx: &mut WindowContext,
) {
+ // Drop scroll events after a reset, since we can't calculate
+ // the new logical scroll top without the item heights
+ if self.reset {
+ return;
+ }
+
let scroll_max = (self.items.summary().height - height).max(px(0.));
let new_scroll_top = (self.scroll_top(scroll_top) - delta.y)
.max(px(0.))
@@ -325,6 +340,8 @@ impl Element for List {
) {
let state = &mut *self.state.0.borrow_mut();
+ state.reset = false;
+
// If the width of the list has changed, invalidate all cached item heights
if state.last_layout_bounds.map_or(true, |last_bounds| {
last_bounds.size.width != bounds.size.width
@@ -346,8 +363,9 @@ impl Element for List {
height: AvailableSpace::MinContent,
};
- // Render items after the scroll top, including those in the trailing overdraw
let mut cursor = old_items.cursor::<Count>();
+
+ // Render items after the scroll top, including those in the trailing overdraw
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
for (ix, item) in cursor.by_ref().enumerate() {
let visible_height = rendered_height - scroll_top.offset_in_item;
@@ -461,6 +479,7 @@ impl Element for List {
let list_state = self.state.clone();
let height = bounds.size.height;
+
cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
if phase == DispatchPhase::Bubble
&& bounds.contains(&event.position)
@@ -562,3 +581,49 @@ impl<'a> sum_tree::SeekTarget<'a, ListItemSummary, ListItemSummary> for Height {
self.0.partial_cmp(&other.height).unwrap()
}
}
+
+#[cfg(test)]
+mod test {
+
+ use gpui::{ScrollDelta, ScrollWheelEvent};
+
+ use crate::{self as gpui, TestAppContext};
+
+ #[gpui::test]
+ fn test_reset_after_paint_before_scroll(cx: &mut TestAppContext) {
+ use crate::{div, list, point, px, size, Element, ListState, Styled};
+
+ let cx = cx.add_empty_window();
+
+ let state = ListState::new(5, crate::ListAlignment::Top, px(10.), |_, _| {
+ div().h(px(10.)).w_full().into_any()
+ });
+
+ // Ensure that the list is scrolled to the top
+ state.scroll_to(gpui::ListOffset {
+ item_ix: 0,
+ offset_in_item: px(0.0),
+ });
+
+ // Paint
+ cx.draw(
+ point(px(0.), px(0.)),
+ size(px(100.), px(20.)).into(),
+ |_| list(state.clone()).w_full().h_full().z_index(10).into_any(),
+ );
+
+ // Reset
+ state.reset(5);
+
+ // And then recieve a scroll event _before_ the next paint
+ cx.simulate_event(ScrollWheelEvent {
+ position: point(px(1.), px(1.)),
+ delta: ScrollDelta::Pixels(point(px(0.), px(-500.))),
+ ..Default::default()
+ });
+
+ // Scroll position should stay at the top of the list
+ assert_eq!(state.logical_scroll_top().item_ix, 0);
+ assert_eq!(state.logical_scroll_top().offset_in_item, px(0.));
+ }
+}
@@ -1,8 +1,14 @@
use crate::{
- div, point, Element, IntoElement, Keystroke, Modifiers, Pixels, Point, Render, ViewContext,
+ point, seal::Sealed, IntoElement, Keystroke, Modifiers, Pixels, Point, Render, ViewContext,
};
use smallvec::SmallVec;
-use std::{any::Any, fmt::Debug, marker::PhantomData, ops::Deref, path::PathBuf};
+use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf};
+
+pub trait InputEvent: Sealed + 'static {
+ fn to_platform_input(self) -> PlatformInput;
+}
+pub trait KeyEvent: InputEvent {}
+pub trait MouseEvent: InputEvent {}
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KeyDownEvent {
@@ -10,16 +16,40 @@ pub struct KeyDownEvent {
pub is_held: bool,
}
+impl Sealed for KeyDownEvent {}
+impl InputEvent for KeyDownEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::KeyDown(self)
+ }
+}
+impl KeyEvent for KeyDownEvent {}
+
#[derive(Clone, Debug)]
pub struct KeyUpEvent {
pub keystroke: Keystroke,
}
+impl Sealed for KeyUpEvent {}
+impl InputEvent for KeyUpEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::KeyUp(self)
+ }
+}
+impl KeyEvent for KeyUpEvent {}
+
#[derive(Clone, Debug, Default)]
pub struct ModifiersChangedEvent {
pub modifiers: Modifiers,
}
+impl Sealed for ModifiersChangedEvent {}
+impl InputEvent for ModifiersChangedEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::ModifiersChanged(self)
+ }
+}
+impl KeyEvent for ModifiersChangedEvent {}
+
impl Deref for ModifiersChangedEvent {
type Target = Modifiers;
@@ -30,9 +60,10 @@ impl Deref for ModifiersChangedEvent {
/// The phase of a touch motion event.
/// Based on the winit enum of the same name.
-#[derive(Clone, Copy, Debug)]
+#[derive(Clone, Copy, Debug, Default)]
pub enum TouchPhase {
Started,
+ #[default]
Moved,
Ended,
}
@@ -45,6 +76,14 @@ pub struct MouseDownEvent {
pub click_count: usize,
}
+impl Sealed for MouseDownEvent {}
+impl InputEvent for MouseDownEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::MouseDown(self)
+ }
+}
+impl MouseEvent for MouseDownEvent {}
+
#[derive(Clone, Debug, Default)]
pub struct MouseUpEvent {
pub button: MouseButton,
@@ -53,38 +92,20 @@ pub struct MouseUpEvent {
pub click_count: usize,
}
+impl Sealed for MouseUpEvent {}
+impl InputEvent for MouseUpEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::MouseUp(self)
+ }
+}
+impl MouseEvent for MouseUpEvent {}
+
#[derive(Clone, Debug, Default)]
pub struct ClickEvent {
pub down: MouseDownEvent,
pub up: MouseUpEvent,
}
-pub struct Drag<S, R, V, E>
-where
- R: Fn(&mut V, &mut ViewContext<V>) -> E,
- V: 'static,
- E: IntoElement,
-{
- pub state: S,
- pub render_drag_handle: R,
- view_element_types: PhantomData<(V, E)>,
-}
-
-impl<S, R, V, E> Drag<S, R, V, E>
-where
- R: Fn(&mut V, &mut ViewContext<V>) -> E,
- V: 'static,
- E: Element,
-{
- pub fn new(state: S, render_drag_handle: R) -> Self {
- Drag {
- state,
- render_drag_handle,
- view_element_types: Default::default(),
- }
- }
-}
-
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
pub enum MouseButton {
Left,
@@ -130,13 +151,21 @@ pub struct MouseMoveEvent {
pub modifiers: Modifiers,
}
+impl Sealed for MouseMoveEvent {}
+impl InputEvent for MouseMoveEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::MouseMove(self)
+ }
+}
+impl MouseEvent for MouseMoveEvent {}
+
impl MouseMoveEvent {
pub fn dragging(&self) -> bool {
self.pressed_button == Some(MouseButton::Left)
}
}
-#[derive(Clone, Debug)]
+#[derive(Clone, Debug, Default)]
pub struct ScrollWheelEvent {
pub position: Point<Pixels>,
pub delta: ScrollDelta,
@@ -144,6 +173,14 @@ pub struct ScrollWheelEvent {
pub touch_phase: TouchPhase,
}
+impl Sealed for ScrollWheelEvent {}
+impl InputEvent for ScrollWheelEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::ScrollWheel(self)
+ }
+}
+impl MouseEvent for ScrollWheelEvent {}
+
impl Deref for ScrollWheelEvent {
type Target = Modifiers;
@@ -201,6 +238,14 @@ pub struct MouseExitEvent {
pub modifiers: Modifiers,
}
+impl Sealed for MouseExitEvent {}
+impl InputEvent for MouseExitEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::MouseExited(self)
+ }
+}
+impl MouseEvent for MouseExitEvent {}
+
impl Deref for MouseExitEvent {
type Target = Modifiers;
@@ -220,7 +265,7 @@ impl ExternalPaths {
impl Render for ExternalPaths {
fn render(&mut self, _: &mut ViewContext<Self>) -> impl IntoElement {
- div() // Intentionally left empty because the platform will render icons for the dragged files
+ () // Intentionally left empty because the platform will render icons for the dragged files
}
}
@@ -239,8 +284,16 @@ pub enum FileDropEvent {
Exited,
}
+impl Sealed for FileDropEvent {}
+impl InputEvent for FileDropEvent {
+ fn to_platform_input(self) -> PlatformInput {
+ PlatformInput::FileDrop(self)
+ }
+}
+impl MouseEvent for FileDropEvent {}
+
#[derive(Clone, Debug)]
-pub enum InputEvent {
+pub enum PlatformInput {
KeyDown(KeyDownEvent),
KeyUp(KeyUpEvent),
ModifiersChanged(ModifiersChangedEvent),
@@ -252,19 +305,19 @@ pub enum InputEvent {
FileDrop(FileDropEvent),
}
-impl InputEvent {
+impl PlatformInput {
pub fn position(&self) -> Option<Point<Pixels>> {
match self {
- InputEvent::KeyDown { .. } => None,
- InputEvent::KeyUp { .. } => None,
- InputEvent::ModifiersChanged { .. } => None,
- InputEvent::MouseDown(event) => Some(event.position),
- InputEvent::MouseUp(event) => Some(event.position),
- InputEvent::MouseMove(event) => Some(event.position),
- InputEvent::MouseExited(event) => Some(event.position),
- InputEvent::ScrollWheel(event) => Some(event.position),
- InputEvent::FileDrop(FileDropEvent::Exited) => None,
- InputEvent::FileDrop(
+ PlatformInput::KeyDown { .. } => None,
+ PlatformInput::KeyUp { .. } => None,
+ PlatformInput::ModifiersChanged { .. } => None,
+ PlatformInput::MouseDown(event) => Some(event.position),
+ PlatformInput::MouseUp(event) => Some(event.position),
+ PlatformInput::MouseMove(event) => Some(event.position),
+ PlatformInput::MouseExited(event) => Some(event.position),
+ PlatformInput::ScrollWheel(event) => Some(event.position),
+ PlatformInput::FileDrop(FileDropEvent::Exited) => None,
+ PlatformInput::FileDrop(
FileDropEvent::Entered { position, .. }
| FileDropEvent::Pending { position, .. }
| FileDropEvent::Submit { position, .. },
@@ -274,29 +327,29 @@ impl InputEvent {
pub fn mouse_event(&self) -> Option<&dyn Any> {
match self {
- InputEvent::KeyDown { .. } => None,
- InputEvent::KeyUp { .. } => None,
- InputEvent::ModifiersChanged { .. } => None,
- InputEvent::MouseDown(event) => Some(event),
- InputEvent::MouseUp(event) => Some(event),
- InputEvent::MouseMove(event) => Some(event),
- InputEvent::MouseExited(event) => Some(event),
- InputEvent::ScrollWheel(event) => Some(event),
- InputEvent::FileDrop(event) => Some(event),
+ PlatformInput::KeyDown { .. } => None,
+ PlatformInput::KeyUp { .. } => None,
+ PlatformInput::ModifiersChanged { .. } => None,
+ PlatformInput::MouseDown(event) => Some(event),
+ PlatformInput::MouseUp(event) => Some(event),
+ PlatformInput::MouseMove(event) => Some(event),
+ PlatformInput::MouseExited(event) => Some(event),
+ PlatformInput::ScrollWheel(event) => Some(event),
+ PlatformInput::FileDrop(event) => Some(event),
}
}
pub fn keyboard_event(&self) -> Option<&dyn Any> {
match self {
- InputEvent::KeyDown(event) => Some(event),
- InputEvent::KeyUp(event) => Some(event),
- InputEvent::ModifiersChanged(event) => Some(event),
- InputEvent::MouseDown(_) => None,
- InputEvent::MouseUp(_) => None,
- InputEvent::MouseMove(_) => None,
- InputEvent::MouseExited(_) => None,
- InputEvent::ScrollWheel(_) => None,
- InputEvent::FileDrop(_) => None,
+ PlatformInput::KeyDown(event) => Some(event),
+ PlatformInput::KeyUp(event) => Some(event),
+ PlatformInput::ModifiersChanged(event) => Some(event),
+ PlatformInput::MouseDown(_) => None,
+ PlatformInput::MouseUp(_) => None,
+ PlatformInput::MouseMove(_) => None,
+ PlatformInput::MouseExited(_) => None,
+ PlatformInput::ScrollWheel(_) => None,
+ PlatformInput::FileDrop(_) => None,
}
}
}
@@ -209,7 +209,6 @@ mod tests {
);
assert!(!matcher.has_pending_keystrokes());
- eprintln!("PROBLEM AREA");
// If a is prefixed, C will not be dispatched because there
// was a pending binding for it
assert_eq!(
@@ -7,7 +7,7 @@ mod test;
use crate::{
Action, AnyWindowHandle, BackgroundExecutor, Bounds, DevicePixels, Font, FontId, FontMetrics,
- FontRun, ForegroundExecutor, GlobalPixels, GlyphId, InputEvent, Keymap, LineLayout, Pixels,
+ FontRun, ForegroundExecutor, GlobalPixels, GlyphId, Keymap, LineLayout, Pixels, PlatformInput,
Point, RenderGlyphParams, RenderImageParams, RenderSvgParams, Result, Scene, SharedString,
Size, TaskLabel,
};
@@ -88,7 +88,7 @@ pub(crate) trait Platform: 'static {
fn on_resign_active(&self, callback: Box<dyn FnMut()>);
fn on_quit(&self, callback: Box<dyn FnMut()>);
fn on_reopen(&self, callback: Box<dyn FnMut()>);
- fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>);
+ fn on_event(&self, callback: Box<dyn FnMut(PlatformInput) -> bool>);
fn set_menus(&self, menus: Vec<Menu>, keymap: &Keymap);
fn on_app_menu_action(&self, callback: Box<dyn FnMut(&dyn Action)>);
@@ -155,7 +155,7 @@ pub trait PlatformWindow {
fn zoom(&self);
fn toggle_full_screen(&self);
fn on_request_frame(&self, callback: Box<dyn FnMut()>);
- fn on_input(&self, callback: Box<dyn FnMut(InputEvent) -> bool>);
+ fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> bool>);
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>);
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>);
fn on_fullscreen(&self, callback: Box<dyn FnMut(bool)>);
@@ -1,7 +1,7 @@
use crate::{
- point, px, InputEvent, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent,
- MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection,
- Pixels, ScrollDelta, ScrollWheelEvent, TouchPhase,
+ point, px, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,
+ MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection, Pixels,
+ PlatformInput, ScrollDelta, ScrollWheelEvent, TouchPhase,
};
use cocoa::{
appkit::{NSEvent, NSEventModifierFlags, NSEventPhase, NSEventType},
@@ -82,7 +82,7 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers {
}
}
-impl InputEvent {
+impl PlatformInput {
pub unsafe fn from_native(native_event: id, window_height: Option<Pixels>) -> Option<Self> {
let event_type = native_event.eventType();
@@ -1,8 +1,8 @@
use super::{events::key_to_native, BoolExt};
use crate::{
Action, AnyWindowHandle, BackgroundExecutor, ClipboardItem, CursorStyle, DisplayId,
- ForegroundExecutor, InputEvent, Keymap, MacDispatcher, MacDisplay, MacDisplayLinker,
- MacTextSystem, MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay,
+ ForegroundExecutor, Keymap, MacDispatcher, MacDisplay, MacDisplayLinker, MacTextSystem,
+ MacWindow, Menu, MenuItem, PathPromptOptions, Platform, PlatformDisplay, PlatformInput,
PlatformTextSystem, PlatformWindow, Result, SemanticVersion, VideoTimestamp, WindowOptions,
};
use anyhow::anyhow;
@@ -153,7 +153,7 @@ pub struct MacPlatformState {
resign_active: Option<Box<dyn FnMut()>>,
reopen: Option<Box<dyn FnMut()>>,
quit: Option<Box<dyn FnMut()>>,
- event: Option<Box<dyn FnMut(InputEvent) -> bool>>,
+ event: Option<Box<dyn FnMut(PlatformInput) -> bool>>,
menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
will_open_menu: Option<Box<dyn FnMut()>>,
@@ -637,7 +637,7 @@ impl Platform for MacPlatform {
self.0.lock().reopen = Some(callback);
}
- fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>) {
+ fn on_event(&self, callback: Box<dyn FnMut(PlatformInput) -> bool>) {
self.0.lock().event = Some(callback);
}
@@ -976,7 +976,7 @@ unsafe fn get_mac_platform(object: &mut Object) -> &MacPlatform {
extern "C" fn send_event(this: &mut Object, _sel: Sel, native_event: id) {
unsafe {
- if let Some(event) = InputEvent::from_native(native_event, None) {
+ if let Some(event) = PlatformInput::from_native(native_event, None) {
let platform = get_mac_platform(this);
let mut lock = platform.0.lock();
if let Some(mut callback) = lock.event.take() {
@@ -1,9 +1,9 @@
use super::{display_bounds_from_native, ns_string, MacDisplay, MetalRenderer, NSRange};
use crate::{
display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, ExternalPaths,
- FileDropEvent, ForegroundExecutor, GlobalPixels, InputEvent, KeyDownEvent, Keystroke,
- Modifiers, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
- Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
+ FileDropEvent, ForegroundExecutor, GlobalPixels, KeyDownEvent, Keystroke, Modifiers,
+ ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
+ PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow, Point,
PromptLevel, Size, Timer, WindowAppearance, WindowBounds, WindowKind, WindowOptions,
};
use block::ConcreteBlock;
@@ -319,7 +319,7 @@ struct MacWindowState {
renderer: MetalRenderer,
kind: WindowKind,
request_frame_callback: Option<Box<dyn FnMut()>>,
- event_callback: Option<Box<dyn FnMut(InputEvent) -> bool>>,
+ event_callback: Option<Box<dyn FnMut(PlatformInput) -> bool>>,
activate_callback: Option<Box<dyn FnMut(bool)>>,
resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
fullscreen_callback: Option<Box<dyn FnMut(bool)>>,
@@ -333,7 +333,7 @@ struct MacWindowState {
synthetic_drag_counter: usize,
last_fresh_keydown: Option<Keystroke>,
traffic_light_position: Option<Point<Pixels>>,
- previous_modifiers_changed_event: Option<InputEvent>,
+ previous_modifiers_changed_event: Option<PlatformInput>,
// State tracking what the IME did after the last request
ime_state: ImeState,
// Retains the last IME Text
@@ -928,7 +928,7 @@ impl PlatformWindow for MacWindow {
self.0.as_ref().lock().request_frame_callback = Some(callback);
}
- fn on_input(&self, callback: Box<dyn FnMut(InputEvent) -> bool>) {
+ fn on_input(&self, callback: Box<dyn FnMut(PlatformInput) -> bool>) {
self.0.as_ref().lock().event_callback = Some(callback);
}
@@ -1053,9 +1053,9 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
let mut lock = window_state.as_ref().lock();
let window_height = lock.content_size().height;
- let event = unsafe { InputEvent::from_native(native_event, Some(window_height)) };
+ let event = unsafe { PlatformInput::from_native(native_event, Some(window_height)) };
- if let Some(InputEvent::KeyDown(event)) = event {
+ if let Some(PlatformInput::KeyDown(event)) = event {
// For certain keystrokes, macOS will first dispatch a "key equivalent" event.
// If that event isn't handled, it will then dispatch a "key down" event. GPUI
// makes no distinction between these two types of events, so we need to ignore
@@ -1102,7 +1102,7 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
.flatten()
.is_some();
if !is_composing {
- handled = callback(InputEvent::KeyDown(event));
+ handled = callback(PlatformInput::KeyDown(event));
}
if !handled {
@@ -1146,11 +1146,11 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
let is_active = unsafe { lock.native_window.isKeyWindow() == YES };
let window_height = lock.content_size().height;
- let event = unsafe { InputEvent::from_native(native_event, Some(window_height)) };
+ let event = unsafe { PlatformInput::from_native(native_event, Some(window_height)) };
if let Some(mut event) = event {
match &mut event {
- InputEvent::MouseDown(
+ PlatformInput::MouseDown(
event @ MouseDownEvent {
button: MouseButton::Left,
modifiers: Modifiers { control: true, .. },
@@ -1172,7 +1172,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
// Because we map a ctrl-left_down to a right_down -> right_up let's ignore
// the ctrl-left_up to avoid having a mismatch in button down/up events if the
// user is still holding ctrl when releasing the left mouse button
- InputEvent::MouseUp(
+ PlatformInput::MouseUp(
event @ MouseUpEvent {
button: MouseButton::Left,
modifiers: Modifiers { control: true, .. },
@@ -1194,7 +1194,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
};
match &event {
- InputEvent::MouseMove(
+ PlatformInput::MouseMove(
event @ MouseMoveEvent {
pressed_button: Some(_),
..
@@ -1216,15 +1216,15 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
}
}
- InputEvent::MouseMove(_) if !(is_active || lock.kind == WindowKind::PopUp) => return,
+ PlatformInput::MouseMove(_) if !(is_active || lock.kind == WindowKind::PopUp) => return,
- InputEvent::MouseUp(MouseUpEvent { .. }) => {
+ PlatformInput::MouseUp(MouseUpEvent { .. }) => {
lock.synthetic_drag_counter += 1;
}
- InputEvent::ModifiersChanged(ModifiersChangedEvent { modifiers }) => {
+ PlatformInput::ModifiersChanged(ModifiersChangedEvent { modifiers }) => {
// Only raise modifiers changed event when they have actually changed
- if let Some(InputEvent::ModifiersChanged(ModifiersChangedEvent {
+ if let Some(PlatformInput::ModifiersChanged(ModifiersChangedEvent {
modifiers: prev_modifiers,
})) = &lock.previous_modifiers_changed_event
{
@@ -1258,7 +1258,7 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
key: ".".into(),
ime_key: None,
};
- let event = InputEvent::KeyDown(KeyDownEvent {
+ let event = PlatformInput::KeyDown(KeyDownEvent {
keystroke: keystroke.clone(),
is_held: false,
});
@@ -1655,7 +1655,7 @@ extern "C" fn dragging_entered(this: &Object, _: Sel, dragging_info: id) -> NSDr
if send_new_event(&window_state, {
let position = drag_event_position(&window_state, dragging_info);
let paths = external_paths_from_event(dragging_info);
- InputEvent::FileDrop(FileDropEvent::Entered { position, paths })
+ PlatformInput::FileDrop(FileDropEvent::Entered { position, paths })
}) {
window_state.lock().external_files_dragged = true;
NSDragOperationCopy
@@ -1669,7 +1669,7 @@ extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDr
let position = drag_event_position(&window_state, dragging_info);
if send_new_event(
&window_state,
- InputEvent::FileDrop(FileDropEvent::Pending { position }),
+ PlatformInput::FileDrop(FileDropEvent::Pending { position }),
) {
NSDragOperationCopy
} else {
@@ -1679,7 +1679,10 @@ extern "C" fn dragging_updated(this: &Object, _: Sel, dragging_info: id) -> NSDr
extern "C" fn dragging_exited(this: &Object, _: Sel, _: id) {
let window_state = unsafe { get_window_state(this) };
- send_new_event(&window_state, InputEvent::FileDrop(FileDropEvent::Exited));
+ send_new_event(
+ &window_state,
+ PlatformInput::FileDrop(FileDropEvent::Exited),
+ );
window_state.lock().external_files_dragged = false;
}
@@ -1688,7 +1691,7 @@ extern "C" fn perform_drag_operation(this: &Object, _: Sel, dragging_info: id) -
let position = drag_event_position(&window_state, dragging_info);
if send_new_event(
&window_state,
- InputEvent::FileDrop(FileDropEvent::Submit { position }),
+ PlatformInput::FileDrop(FileDropEvent::Submit { position }),
) {
YES
} else {
@@ -1712,7 +1715,10 @@ fn external_paths_from_event(dragging_info: *mut Object) -> ExternalPaths {
extern "C" fn conclude_drag_operation(this: &Object, _: Sel, _: id) {
let window_state = unsafe { get_window_state(this) };
- send_new_event(&window_state, InputEvent::FileDrop(FileDropEvent::Exited));
+ send_new_event(
+ &window_state,
+ PlatformInput::FileDrop(FileDropEvent::Exited),
+ );
}
async fn synthetic_drag(
@@ -1727,7 +1733,7 @@ async fn synthetic_drag(
if lock.synthetic_drag_counter == drag_id {
if let Some(mut callback) = lock.event_callback.take() {
drop(lock);
- callback(InputEvent::MouseMove(event.clone()));
+ callback(PlatformInput::MouseMove(event.clone()));
window_state.lock().event_callback = Some(callback);
}
} else {
@@ -1737,7 +1743,7 @@ async fn synthetic_drag(
}
}
-fn send_new_event(window_state_lock: &Mutex<MacWindowState>, e: InputEvent) -> bool {
+fn send_new_event(window_state_lock: &Mutex<MacWindowState>, e: PlatformInput) -> bool {
let window_state = window_state_lock.lock().event_callback.take();
if let Some(mut callback) = window_state {
callback(e);
@@ -239,7 +239,7 @@ impl Platform for TestPlatform {
unimplemented!()
}
- fn on_event(&self, _callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
+ fn on_event(&self, _callback: Box<dyn FnMut(crate::PlatformInput) -> bool>) {
unimplemented!()
}
@@ -1,7 +1,7 @@
use crate::{
- px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, InputEvent, KeyDownEvent,
- Keystroke, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
- Size, TestPlatform, TileId, WindowAppearance, WindowBounds, WindowOptions,
+ px, AnyWindowHandle, AtlasKey, AtlasTextureId, AtlasTile, Bounds, KeyDownEvent, Keystroke,
+ Pixels, PlatformAtlas, PlatformDisplay, PlatformInput, PlatformInputHandler, PlatformWindow,
+ Point, Size, TestPlatform, TileId, WindowAppearance, WindowBounds, WindowOptions,
};
use collections::HashMap;
use parking_lot::Mutex;
@@ -19,7 +19,7 @@ pub struct TestWindowState {
platform: Weak<TestPlatform>,
sprite_atlas: Arc<dyn PlatformAtlas>,
pub(crate) should_close_handler: Option<Box<dyn FnMut() -> bool>>,
- input_callback: Option<Box<dyn FnMut(InputEvent) -> bool>>,
+ input_callback: Option<Box<dyn FnMut(PlatformInput) -> bool>>,
active_status_change_callback: Option<Box<dyn FnMut(bool)>>,
resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
moved_callback: Option<Box<dyn FnMut()>>,
@@ -85,7 +85,7 @@ impl TestWindow {
self.0.lock().active_status_change_callback = Some(callback);
}
- pub fn simulate_input(&mut self, event: InputEvent) -> bool {
+ pub fn simulate_input(&mut self, event: PlatformInput) -> bool {
let mut lock = self.0.lock();
let Some(mut callback) = lock.input_callback.take() else {
return false;
@@ -97,7 +97,7 @@ impl TestWindow {
}
pub fn simulate_keystroke(&mut self, keystroke: Keystroke, is_held: bool) {
- if self.simulate_input(InputEvent::KeyDown(KeyDownEvent {
+ if self.simulate_input(PlatformInput::KeyDown(KeyDownEvent {
keystroke: keystroke.clone(),
is_held,
})) {
@@ -220,7 +220,7 @@ impl PlatformWindow for TestWindow {
fn on_request_frame(&self, _callback: Box<dyn FnMut()>) {}
- fn on_input(&self, callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
+ fn on_input(&self, callback: Box<dyn FnMut(crate::PlatformInput) -> bool>) {
self.0.lock().input_callback = Some(callback)
}
@@ -5,13 +5,14 @@ use crate::{
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
DevicePixels, DispatchActionListener, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect,
Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FontId, GlobalElementId, GlyphId, Hsla,
- ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeystrokeEvent, LayoutId,
- Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent,
- Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
- PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams,
- RenderSvgParams, ScaledPixels, Scene, Shadow, SharedString, Size, Style, SubscriberSet,
- Subscription, Surface, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext,
- WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
+ ImageData, IsZero, KeyBinding, KeyContext, KeyDownEvent, KeyEvent, KeystrokeEvent, LayoutId,
+ Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseEvent, MouseMoveEvent,
+ MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInput,
+ PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
+ RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, Scene, Shadow,
+ SharedString, Size, Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task,
+ Underline, UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions,
+ SUBPIXEL_VARIANTS,
};
use anyhow::{anyhow, Context as _, Result};
use collections::{FxHashMap, FxHashSet};
@@ -971,7 +972,7 @@ impl<'a> WindowContext<'a> {
/// Register a mouse event listener on the window for the next frame. The type of event
/// is determined by the first parameter of the given listener. When the next frame is rendered
/// the listener will be cleared.
- pub fn on_mouse_event<Event: 'static>(
+ pub fn on_mouse_event<Event: MouseEvent>(
&mut self,
mut handler: impl FnMut(&Event, DispatchPhase, &mut WindowContext) + 'static,
) {
@@ -999,7 +1000,7 @@ impl<'a> WindowContext<'a> {
///
/// This is a fairly low-level method, so prefer using event handlers on elements unless you have
/// a specific need to register a global listener.
- pub fn on_key_event<Event: 'static>(
+ pub fn on_key_event<Event: KeyEvent>(
&mut self,
listener: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static,
) {
@@ -1620,7 +1621,7 @@ impl<'a> WindowContext<'a> {
}
/// Dispatch a mouse or keyboard event on the window.
- pub fn dispatch_event(&mut self, event: InputEvent) -> bool {
+ pub fn dispatch_event(&mut self, event: PlatformInput) -> bool {
// Handlers may set this to false by calling `stop_propagation`.
self.app.propagate_event = true;
// Handlers may set this to true by calling `prevent_default`.
@@ -1629,37 +1630,37 @@ impl<'a> WindowContext<'a> {
let event = match event {
// Track the mouse position with our own state, since accessing the platform
// API for the mouse position can only occur on the main thread.
- InputEvent::MouseMove(mouse_move) => {
+ PlatformInput::MouseMove(mouse_move) => {
self.window.mouse_position = mouse_move.position;
self.window.modifiers = mouse_move.modifiers;
- InputEvent::MouseMove(mouse_move)
+ PlatformInput::MouseMove(mouse_move)
}
- InputEvent::MouseDown(mouse_down) => {
+ PlatformInput::MouseDown(mouse_down) => {
self.window.mouse_position = mouse_down.position;
self.window.modifiers = mouse_down.modifiers;
- InputEvent::MouseDown(mouse_down)
+ PlatformInput::MouseDown(mouse_down)
}
- InputEvent::MouseUp(mouse_up) => {
+ PlatformInput::MouseUp(mouse_up) => {
self.window.mouse_position = mouse_up.position;
self.window.modifiers = mouse_up.modifiers;
- InputEvent::MouseUp(mouse_up)
+ PlatformInput::MouseUp(mouse_up)
}
- InputEvent::MouseExited(mouse_exited) => {
+ PlatformInput::MouseExited(mouse_exited) => {
self.window.modifiers = mouse_exited.modifiers;
- InputEvent::MouseExited(mouse_exited)
+ PlatformInput::MouseExited(mouse_exited)
}
- InputEvent::ModifiersChanged(modifiers_changed) => {
+ PlatformInput::ModifiersChanged(modifiers_changed) => {
self.window.modifiers = modifiers_changed.modifiers;
- InputEvent::ModifiersChanged(modifiers_changed)
+ PlatformInput::ModifiersChanged(modifiers_changed)
}
- InputEvent::ScrollWheel(scroll_wheel) => {
+ PlatformInput::ScrollWheel(scroll_wheel) => {
self.window.mouse_position = scroll_wheel.position;
self.window.modifiers = scroll_wheel.modifiers;
- InputEvent::ScrollWheel(scroll_wheel)
+ PlatformInput::ScrollWheel(scroll_wheel)
}
// Translate dragging and dropping of external files from the operating system
// to internal drag and drop events.
- InputEvent::FileDrop(file_drop) => match file_drop {
+ PlatformInput::FileDrop(file_drop) => match file_drop {
FileDropEvent::Entered { position, paths } => {
self.window.mouse_position = position;
if self.active_drag.is_none() {
@@ -1669,7 +1670,7 @@ impl<'a> WindowContext<'a> {
cursor_offset: position,
});
}
- InputEvent::MouseMove(MouseMoveEvent {
+ PlatformInput::MouseMove(MouseMoveEvent {
position,
pressed_button: Some(MouseButton::Left),
modifiers: Modifiers::default(),
@@ -1677,7 +1678,7 @@ impl<'a> WindowContext<'a> {
}
FileDropEvent::Pending { position } => {
self.window.mouse_position = position;
- InputEvent::MouseMove(MouseMoveEvent {
+ PlatformInput::MouseMove(MouseMoveEvent {
position,
pressed_button: Some(MouseButton::Left),
modifiers: Modifiers::default(),
@@ -1686,21 +1687,21 @@ impl<'a> WindowContext<'a> {
FileDropEvent::Submit { position } => {
self.activate(true);
self.window.mouse_position = position;
- InputEvent::MouseUp(MouseUpEvent {
+ PlatformInput::MouseUp(MouseUpEvent {
button: MouseButton::Left,
position,
modifiers: Modifiers::default(),
click_count: 1,
})
}
- FileDropEvent::Exited => InputEvent::MouseUp(MouseUpEvent {
+ FileDropEvent::Exited => PlatformInput::MouseUp(MouseUpEvent {
button: MouseButton::Left,
position: Point::default(),
modifiers: Modifiers::default(),
click_count: 1,
}),
},
- InputEvent::KeyDown(_) | InputEvent::KeyUp(_) => event,
+ PlatformInput::KeyDown(_) | PlatformInput::KeyUp(_) => event,
};
if let Some(any_mouse_event) = event.mouse_event() {
@@ -2983,7 +2984,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
/// Add a listener for any mouse event that occurs in the window.
/// This is a fairly low level method.
/// Typically, you'll want to use methods on UI elements, which perform bounds checking etc.
- pub fn on_mouse_event<Event: 'static>(
+ pub fn on_mouse_event<Event: MouseEvent>(
&mut self,
handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext<V>) + 'static,
) {
@@ -2996,7 +2997,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
}
/// Register a callback to be invoked when the given Key Event is dispatched to the window.
- pub fn on_key_event<Event: 'static>(
+ pub fn on_key_event<Event: KeyEvent>(
&mut self,
handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext<V>) + 'static,
) {
@@ -1167,7 +1167,7 @@ mod tests {
use super::*;
use editor::{DisplayPoint, Editor};
- use gpui::{Context, EmptyView, Hsla, TestAppContext, VisualTestContext};
+ use gpui::{Context, Hsla, TestAppContext, VisualTestContext};
use language::Buffer;
use smol::stream::StreamExt as _;
use unindent::Unindent as _;
@@ -1200,7 +1200,7 @@ mod tests {
.unindent(),
)
});
- let (_, cx) = cx.add_window_view(|_| EmptyView {});
+ let cx = cx.add_empty_window();
let editor = cx.new_view(|cx| Editor::for_buffer(buffer.clone(), None, cx));
let search_bar = cx.new_view(|cx| {
@@ -1547,7 +1547,7 @@ mod tests {
"Should pick a query with multiple results"
);
let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), buffer_text));
- let window = cx.add_window(|_| EmptyView {});
+ let window = cx.add_window(|_| ());
let editor = window.build_view(cx, |cx| Editor::for_buffer(buffer.clone(), None, cx));
@@ -1743,7 +1743,7 @@ mod tests {
"#
.unindent();
let buffer = cx.new_model(|cx| Buffer::new(0, cx.entity_id().as_u64(), buffer_text));
- let (_, cx) = cx.add_window_view(|_| EmptyView {});
+ let cx = cx.add_empty_window();
let editor = cx.new_view(|cx| Editor::for_buffer(buffer.clone(), None, cx));