Flesh out gpui2 test support
This commit is contained in:
parent
eb325fb387
commit
8e799b6e22
7 changed files with 271 additions and 13 deletions
|
@ -1,7 +1,7 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext, BackgroundExecutor, Context,
|
AnyView, AnyWindowHandle, AppCell, AppContext, AsyncAppContext, BackgroundExecutor, Context,
|
||||||
EventEmitter, ForegroundExecutor, Model, ModelContext, Result, Task, TestDispatcher,
|
EventEmitter, ForegroundExecutor, InputEvent, KeyDownEvent, Keystroke, Model, ModelContext,
|
||||||
TestPlatform, WindowContext,
|
Result, Task, TestDispatcher, TestPlatform, WindowContext,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, bail};
|
use anyhow::{anyhow, bail};
|
||||||
use futures::{Stream, StreamExt};
|
use futures::{Stream, StreamExt};
|
||||||
|
@ -129,6 +129,23 @@ impl TestAppContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn dispatch_keystroke(
|
||||||
|
&mut self,
|
||||||
|
window: AnyWindowHandle,
|
||||||
|
keystroke: Keystroke,
|
||||||
|
is_held: bool,
|
||||||
|
) {
|
||||||
|
let handled = window
|
||||||
|
.update(self, |_, cx| {
|
||||||
|
cx.dispatch_event(InputEvent::KeyDown(KeyDownEvent { keystroke, is_held }))
|
||||||
|
})
|
||||||
|
.is_ok_and(|handled| handled);
|
||||||
|
|
||||||
|
if !handled {
|
||||||
|
// todo!() simluate input here
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn notifications<T: 'static>(&mut self, entity: &Model<T>) -> impl Stream<Item = ()> {
|
pub fn notifications<T: 'static>(&mut self, entity: &Model<T>) -> impl Stream<Item = ()> {
|
||||||
let (tx, rx) = futures::channel::mpsc::unbounded();
|
let (tx, rx) = futures::channel::mpsc::unbounded();
|
||||||
|
|
||||||
|
|
|
@ -25,6 +25,10 @@ impl<T: Clone + Debug + Default> Point<T> {
|
||||||
Self { x, y }
|
Self { x, y }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn zero() -> Self {
|
||||||
|
Self::new(T::default(), T::default())
|
||||||
|
}
|
||||||
|
|
||||||
pub fn map<U: Clone + Default + Debug>(&self, f: impl Fn(T) -> U) -> Point<U> {
|
pub fn map<U: Clone + Default + Debug>(&self, f: impl Fn(T) -> U) -> Point<U> {
|
||||||
Point {
|
Point {
|
||||||
x: f(self.x.clone()),
|
x: f(self.x.clone()),
|
||||||
|
|
|
@ -1,5 +1,9 @@
|
||||||
mod dispatcher;
|
mod dispatcher;
|
||||||
|
mod display;
|
||||||
mod platform;
|
mod platform;
|
||||||
|
mod window;
|
||||||
|
|
||||||
pub use dispatcher::*;
|
pub use dispatcher::*;
|
||||||
|
pub use display::*;
|
||||||
pub use platform::*;
|
pub use platform::*;
|
||||||
|
pub use window::*;
|
||||||
|
|
41
crates/gpui2/src/platform/test/display.rs
Normal file
41
crates/gpui2/src/platform/test/display.rs
Normal file
|
@ -0,0 +1,41 @@
|
||||||
|
use anyhow::{Ok, Result};
|
||||||
|
|
||||||
|
use crate::{Bounds, DisplayId, GlobalPixels, PlatformDisplay, Point};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TestDisplay {
|
||||||
|
id: DisplayId,
|
||||||
|
uuid: uuid::Uuid,
|
||||||
|
bounds: Bounds<GlobalPixels>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl TestDisplay {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
TestDisplay {
|
||||||
|
id: DisplayId(1),
|
||||||
|
uuid: uuid::Uuid::new_v4(),
|
||||||
|
bounds: Bounds::from_corners(
|
||||||
|
Point::zero(),
|
||||||
|
Point::new(GlobalPixels(1920.), GlobalPixels(1080.)),
|
||||||
|
),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlatformDisplay for TestDisplay {
|
||||||
|
fn id(&self) -> crate::DisplayId {
|
||||||
|
self.id
|
||||||
|
}
|
||||||
|
|
||||||
|
fn uuid(&self) -> Result<uuid::Uuid> {
|
||||||
|
Ok(self.uuid)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn std::any::Any {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bounds(&self) -> crate::Bounds<crate::GlobalPixels> {
|
||||||
|
self.bounds
|
||||||
|
}
|
||||||
|
}
|
|
@ -1,10 +1,18 @@
|
||||||
use crate::{BackgroundExecutor, DisplayId, ForegroundExecutor, Platform, PlatformTextSystem};
|
use crate::{
|
||||||
|
AnyWindowHandle, BackgroundExecutor, CursorStyle, DisplayId, ForegroundExecutor, Platform,
|
||||||
|
PlatformDisplay, PlatformTextSystem, TestDisplay, TestWindow, WindowOptions,
|
||||||
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use std::sync::Arc;
|
use parking_lot::Mutex;
|
||||||
|
use std::{rc::Rc, sync::Arc};
|
||||||
|
|
||||||
pub struct TestPlatform {
|
pub struct TestPlatform {
|
||||||
background_executor: BackgroundExecutor,
|
background_executor: BackgroundExecutor,
|
||||||
foreground_executor: ForegroundExecutor,
|
foreground_executor: ForegroundExecutor,
|
||||||
|
|
||||||
|
active_window: Arc<Mutex<Option<AnyWindowHandle>>>,
|
||||||
|
active_display: Rc<dyn PlatformDisplay>,
|
||||||
|
active_cursor: Mutex<CursorStyle>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl TestPlatform {
|
impl TestPlatform {
|
||||||
|
@ -12,6 +20,10 @@ impl TestPlatform {
|
||||||
TestPlatform {
|
TestPlatform {
|
||||||
background_executor: executor,
|
background_executor: executor,
|
||||||
foreground_executor,
|
foreground_executor,
|
||||||
|
|
||||||
|
active_cursor: Default::default(),
|
||||||
|
active_display: Rc::new(TestDisplay::new()),
|
||||||
|
active_window: Default::default(),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -59,11 +71,11 @@ impl Platform for TestPlatform {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn displays(&self) -> Vec<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
fn displays(&self) -> Vec<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
||||||
unimplemented!()
|
vec![self.active_display.clone()]
|
||||||
}
|
}
|
||||||
|
|
||||||
fn display(&self, _id: DisplayId) -> Option<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
fn display(&self, id: DisplayId) -> Option<std::rc::Rc<dyn crate::PlatformDisplay>> {
|
||||||
unimplemented!()
|
self.displays().iter().find(|d| d.id() == id).cloned()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main_window(&self) -> Option<crate::AnyWindowHandle> {
|
fn main_window(&self) -> Option<crate::AnyWindowHandle> {
|
||||||
|
@ -72,10 +84,11 @@ impl Platform for TestPlatform {
|
||||||
|
|
||||||
fn open_window(
|
fn open_window(
|
||||||
&self,
|
&self,
|
||||||
_handle: crate::AnyWindowHandle,
|
handle: AnyWindowHandle,
|
||||||
_options: crate::WindowOptions,
|
options: WindowOptions,
|
||||||
) -> Box<dyn crate::PlatformWindow> {
|
) -> Box<dyn crate::PlatformWindow> {
|
||||||
unimplemented!()
|
*self.active_window.lock() = Some(handle);
|
||||||
|
Box::new(TestWindow::new(options, self.active_display.clone()))
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_display_link_output_callback(
|
fn set_display_link_output_callback(
|
||||||
|
@ -164,8 +177,8 @@ impl Platform for TestPlatform {
|
||||||
unimplemented!()
|
unimplemented!()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn set_cursor_style(&self, _style: crate::CursorStyle) {
|
fn set_cursor_style(&self, style: crate::CursorStyle) {
|
||||||
unimplemented!()
|
*self.active_cursor.lock() = style;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn should_auto_hide_scrollbars(&self) -> bool {
|
fn should_auto_hide_scrollbars(&self) -> bool {
|
||||||
|
|
179
crates/gpui2/src/platform/test/window.rs
Normal file
179
crates/gpui2/src/platform/test/window.rs
Normal file
|
@ -0,0 +1,179 @@
|
||||||
|
use std::{rc::Rc, sync::Arc};
|
||||||
|
|
||||||
|
use parking_lot::Mutex;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
px, Pixels, PlatformAtlas, PlatformDisplay, PlatformWindow, Point, Scene, Size,
|
||||||
|
WindowAppearance, WindowBounds, WindowOptions,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Default)]
|
||||||
|
struct Handlers {
|
||||||
|
active_status_change: Vec<Box<dyn FnMut(bool)>>,
|
||||||
|
input: Vec<Box<dyn FnMut(crate::InputEvent) -> bool>>,
|
||||||
|
moved: Vec<Box<dyn FnMut()>>,
|
||||||
|
resize: Vec<Box<dyn FnMut(Size<Pixels>, f32)>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TestWindow {
|
||||||
|
bounds: WindowBounds,
|
||||||
|
current_scene: Mutex<Option<Scene>>,
|
||||||
|
display: Rc<dyn PlatformDisplay>,
|
||||||
|
|
||||||
|
handlers: Mutex<Handlers>,
|
||||||
|
sprite_atlas: Arc<dyn PlatformAtlas>,
|
||||||
|
}
|
||||||
|
impl TestWindow {
|
||||||
|
pub fn new(options: WindowOptions, display: Rc<dyn PlatformDisplay>) -> Self {
|
||||||
|
Self {
|
||||||
|
bounds: options.bounds,
|
||||||
|
current_scene: Default::default(),
|
||||||
|
display,
|
||||||
|
|
||||||
|
sprite_atlas: Arc::new(TestAtlas),
|
||||||
|
handlers: Default::default(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl PlatformWindow for TestWindow {
|
||||||
|
fn bounds(&self) -> WindowBounds {
|
||||||
|
self.bounds
|
||||||
|
}
|
||||||
|
|
||||||
|
fn content_size(&self) -> Size<Pixels> {
|
||||||
|
let bounds = match self.bounds {
|
||||||
|
WindowBounds::Fixed(bounds) => bounds,
|
||||||
|
WindowBounds::Maximized | WindowBounds::Fullscreen => self.display().bounds(),
|
||||||
|
};
|
||||||
|
bounds.size.map(|p| px(p.0))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn scale_factor(&self) -> f32 {
|
||||||
|
2.0
|
||||||
|
}
|
||||||
|
|
||||||
|
fn titlebar_height(&self) -> Pixels {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn appearance(&self) -> WindowAppearance {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(&self) -> std::rc::Rc<dyn crate::PlatformDisplay> {
|
||||||
|
self.display.clone()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn mouse_position(&self) -> Point<Pixels> {
|
||||||
|
Point::zero()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn as_any_mut(&mut self) -> &mut dyn std::any::Any {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_input_handler(&mut self, _input_handler: Box<dyn crate::PlatformInputHandler>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn prompt(
|
||||||
|
&self,
|
||||||
|
_level: crate::PromptLevel,
|
||||||
|
_msg: &str,
|
||||||
|
_answers: &[&str],
|
||||||
|
) -> futures::channel::oneshot::Receiver<usize> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn activate(&self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_title(&mut self, _title: &str) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn set_edited(&mut self, _edited: bool) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn show_character_palette(&self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn minimize(&self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn zoom(&self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn toggle_full_screen(&self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_input(&self, callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
|
||||||
|
self.handlers.lock().input.push(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>) {
|
||||||
|
self.handlers.lock().active_status_change.push(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>) {
|
||||||
|
self.handlers.lock().resize.push(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_fullscreen(&self, _callback: Box<dyn FnMut(bool)>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_moved(&self, callback: Box<dyn FnMut()>) {
|
||||||
|
self.handlers.lock().moved.push(callback)
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_should_close(&self, _callback: Box<dyn FnMut() -> bool>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_close(&self, _callback: Box<dyn FnOnce()>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_appearance_changed(&self, _callback: Box<dyn FnMut()>) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn is_topmost_for_position(&self, _position: crate::Point<Pixels>) -> bool {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn draw(&self, scene: crate::Scene) {
|
||||||
|
self.current_scene.lock().replace(scene);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn sprite_atlas(&self) -> std::sync::Arc<dyn crate::PlatformAtlas> {
|
||||||
|
self.sprite_atlas.clone()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct TestAtlas;
|
||||||
|
|
||||||
|
impl PlatformAtlas for TestAtlas {
|
||||||
|
fn get_or_insert_with<'a>(
|
||||||
|
&self,
|
||||||
|
_key: &crate::AtlasKey,
|
||||||
|
_build: &mut dyn FnMut() -> anyhow::Result<(
|
||||||
|
Size<crate::DevicePixels>,
|
||||||
|
std::borrow::Cow<'a, [u8]>,
|
||||||
|
)>,
|
||||||
|
) -> anyhow::Result<crate::AtlasTile> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear(&self) {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
}
|
|
@ -1047,7 +1047,7 @@ impl<'a> WindowContext<'a> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Dispatch a mouse or keyboard event on the window.
|
/// Dispatch a mouse or keyboard event on the window.
|
||||||
fn dispatch_event(&mut self, event: InputEvent) -> bool {
|
pub fn dispatch_event(&mut self, event: InputEvent) -> bool {
|
||||||
let event = match event {
|
let event = match event {
|
||||||
// Track the mouse position with our own state, since accessing the platform
|
// Track the mouse position with our own state, since accessing the platform
|
||||||
// API for the mouse position can only occur on the main thread.
|
// API for the mouse position can only occur on the main thread.
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue