mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-23 18:32:17 +00:00
WIP: Start on rendering scenes via presenter
This commit is contained in:
parent
e809d6119a
commit
605bdd62dd
12 changed files with 495 additions and 388 deletions
34
Cargo.lock
generated
34
Cargo.lock
generated
|
@ -1298,6 +1298,39 @@ dependencies = [
|
|||
"crossbeam-utils 0.8.2",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed"
|
||||
version = "5.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2fe1fe6aac5d6bb9e1ffd81002340363272a7648234ec7bdfac5ee202cb65523"
|
||||
dependencies = [
|
||||
"rust-embed-impl",
|
||||
"rust-embed-utils",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-impl"
|
||||
version = "5.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "3ed91c41c42ef7bf687384439c312e75e0da9c149b0390889b94de3c7d9d9e66"
|
||||
dependencies = [
|
||||
"proc-macro2",
|
||||
"quote",
|
||||
"rust-embed-utils",
|
||||
"syn",
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rust-embed-utils"
|
||||
version = "5.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "2a512219132473ab0a77b52077059f1c47ce4af7fbdc94503e9862a34422876d"
|
||||
dependencies = [
|
||||
"walkdir",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "1.1.0"
|
||||
|
@ -1679,6 +1712,7 @@ dependencies = [
|
|||
"num_cpus",
|
||||
"parking_lot",
|
||||
"rand 0.8.3",
|
||||
"rust-embed",
|
||||
"serde_json",
|
||||
"simplelog",
|
||||
"smallvec",
|
||||
|
|
659
gpui/src/app.rs
659
gpui/src/app.rs
|
@ -2,12 +2,14 @@ use crate::{
|
|||
elements::Element,
|
||||
executor::{self, ForegroundTask},
|
||||
keymap::{self, Keystroke},
|
||||
platform::{self, App as _},
|
||||
platform::{self, App as _, WindowOptions},
|
||||
util::post_inc,
|
||||
AssetCache, AssetSource, FontCache, Presenter,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use keymap::MatchResult;
|
||||
use parking_lot::Mutex;
|
||||
use pathfinder_geometry::{rect::RectF, vector::vec2f};
|
||||
use smol::{channel, prelude::*};
|
||||
use std::{
|
||||
any::{type_name, Any, TypeId},
|
||||
|
@ -66,22 +68,28 @@ pub trait UpdateView {
|
|||
pub struct App(Rc<RefCell<MutableAppContext>>);
|
||||
|
||||
impl App {
|
||||
pub fn test<T, F: Future<Output = T>>(f: impl FnOnce(App) -> F) -> T {
|
||||
pub fn test<T, F: Future<Output = T>>(
|
||||
asset_source: impl AssetSource,
|
||||
f: impl FnOnce(App) -> F,
|
||||
) -> T {
|
||||
let platform = platform::current::app(); // TODO: Make a test platform app
|
||||
let foreground = Rc::new(executor::Foreground::test());
|
||||
let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
|
||||
foreground.clone(),
|
||||
Arc::new(platform),
|
||||
asset_source,
|
||||
))));
|
||||
app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
|
||||
smol::block_on(foreground.run(f(app)))
|
||||
}
|
||||
|
||||
pub fn new() -> Result<Self> {
|
||||
pub fn new(asset_source: impl AssetSource) -> Result<Self> {
|
||||
let platform = Arc::new(platform::current::app());
|
||||
let foreground = Rc::new(executor::Foreground::platform(platform.dispatcher())?);
|
||||
let app = Self(Rc::new(RefCell::new(MutableAppContext::new(
|
||||
foreground, platform,
|
||||
foreground,
|
||||
platform,
|
||||
asset_source,
|
||||
))));
|
||||
app.0.borrow_mut().weak_self = Some(Rc::downgrade(&app.0));
|
||||
Ok(app)
|
||||
|
@ -217,7 +225,7 @@ impl App {
|
|||
}
|
||||
|
||||
pub fn read<T, F: FnOnce(&AppContext) -> T>(&mut self, callback: F) -> T {
|
||||
callback(self.0.borrow().ctx())
|
||||
callback(self.0.borrow().downgrade())
|
||||
}
|
||||
|
||||
pub fn update<T, F: FnOnce(&mut MutableAppContext) -> T>(&mut self, callback: F) -> T {
|
||||
|
@ -234,7 +242,7 @@ impl App {
|
|||
F: FnOnce(&T, &AppContext) -> S,
|
||||
{
|
||||
let state = self.0.borrow();
|
||||
read(state.view(handle), state.ctx())
|
||||
read(state.view(handle), state.downgrade())
|
||||
}
|
||||
|
||||
pub fn finish_pending_tasks(&self) -> impl Future<Output = ()> {
|
||||
|
@ -277,6 +285,8 @@ type GlobalActionCallback = dyn FnMut(&dyn Any, &mut MutableAppContext);
|
|||
|
||||
pub struct MutableAppContext {
|
||||
platform: Arc<dyn platform::App>,
|
||||
fonts: Arc<FontCache>,
|
||||
assets: Arc<AssetCache>,
|
||||
ctx: AppContext,
|
||||
actions: HashMap<TypeId, HashMap<String, Vec<Box<ActionCallback>>>>,
|
||||
global_actions: HashMap<String, Vec<Box<GlobalActionCallback>>>,
|
||||
|
@ -301,9 +311,15 @@ pub struct MutableAppContext {
|
|||
}
|
||||
|
||||
impl MutableAppContext {
|
||||
pub fn new(foreground: Rc<executor::Foreground>, platform: Arc<dyn platform::App>) -> Self {
|
||||
pub fn new(
|
||||
foreground: Rc<executor::Foreground>,
|
||||
platform: Arc<dyn platform::App>,
|
||||
asset_source: impl AssetSource,
|
||||
) -> Self {
|
||||
Self {
|
||||
platform,
|
||||
fonts: Arc::new(FontCache::new()),
|
||||
assets: Arc::new(AssetCache::new(asset_source)),
|
||||
ctx: AppContext {
|
||||
models: HashMap::new(),
|
||||
windows: HashMap::new(),
|
||||
|
@ -331,7 +347,7 @@ impl MutableAppContext {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn ctx(&self) -> &AppContext {
|
||||
pub fn downgrade(&self) -> &AppContext {
|
||||
&self.ctx
|
||||
}
|
||||
|
||||
|
@ -532,7 +548,7 @@ impl MutableAppContext {
|
|||
.get(&window_id)
|
||||
.and_then(|w| w.views.get(view_id))
|
||||
{
|
||||
context.extend(view.keymap_context(self.ctx()));
|
||||
context.extend(view.keymap_context(self.downgrade()));
|
||||
context_chain.push(context.clone());
|
||||
} else {
|
||||
return Err(anyhow!(
|
||||
|
@ -592,11 +608,30 @@ impl MutableAppContext {
|
|||
self.ctx.windows.get_mut(&window_id).unwrap().root_view = Some(root_handle.clone().into());
|
||||
self.focus(window_id, root_handle.id());
|
||||
|
||||
// self.emit_ui_update(UiUpdate::OpenWindow {
|
||||
// window_id,
|
||||
// width: 1024.0,
|
||||
// height: 768.0,
|
||||
// });
|
||||
match self.platform.open_window(
|
||||
WindowOptions {
|
||||
bounds: RectF::new(vec2f(0., 0.), vec2f(1024., 768.)),
|
||||
title: "Zed".into(),
|
||||
},
|
||||
self.foreground.clone(),
|
||||
) {
|
||||
Err(e) => log::error!("error opening window: {}", e),
|
||||
Ok(window) => {
|
||||
let presenter = Rc::new(RefCell::new(Presenter::new(
|
||||
window_id,
|
||||
self.fonts.clone(),
|
||||
self.assets.clone(),
|
||||
self,
|
||||
)));
|
||||
|
||||
self.on_window_invalidated(window_id, move |invalidation, ctx| {
|
||||
let mut presenter = presenter.borrow_mut();
|
||||
presenter.invalidate(invalidation, ctx.downgrade());
|
||||
let scene = presenter.build_scene(window.size(), window.scale_factor(), ctx);
|
||||
window.render_scene(scene);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
(window_id, root_handle)
|
||||
}
|
||||
|
@ -1606,7 +1641,7 @@ impl<'a, T: View> ViewContext<'a, T> {
|
|||
window_id: self.window_id,
|
||||
view_id: self.view_id,
|
||||
callback: Box::new(move |view, payload, app, window_id, view_id| {
|
||||
if let Some(emitter_handle) = emitter_handle.upgrade(app.ctx()) {
|
||||
if let Some(emitter_handle) = emitter_handle.upgrade(app.downgrade()) {
|
||||
let model = view.downcast_mut().expect("downcast is type safe");
|
||||
let payload = payload.downcast_ref().expect("downcast is type safe");
|
||||
let mut ctx = ViewContext::new(app, window_id, view_id);
|
||||
|
@ -1632,7 +1667,7 @@ impl<'a, T: View> ViewContext<'a, T> {
|
|||
window_id: self.window_id,
|
||||
view_id: self.view_id,
|
||||
callback: Box::new(move |view, payload, app, window_id, view_id| {
|
||||
if let Some(emitter_handle) = emitter_handle.upgrade(app.ctx()) {
|
||||
if let Some(emitter_handle) = emitter_handle.upgrade(app.downgrade()) {
|
||||
let model = view.downcast_mut().expect("downcast is type safe");
|
||||
let payload = payload.downcast_ref().expect("downcast is type safe");
|
||||
let mut ctx = ViewContext::new(app, window_id, view_id);
|
||||
|
@ -2261,42 +2296,43 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
|
||||
let handle_1 = app.add_model(|ctx| Model::new(None, ctx));
|
||||
let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx));
|
||||
assert_eq!(app.0.borrow().ctx.models.len(), 2);
|
||||
let handle_1 = app.add_model(|ctx| Model::new(None, ctx));
|
||||
let handle_2 = app.add_model(|ctx| Model::new(Some(handle_1.clone()), ctx));
|
||||
assert_eq!(app.0.borrow().ctx.models.len(), 2);
|
||||
|
||||
handle_1.update(app, |model, ctx| {
|
||||
model.events.push("updated".into());
|
||||
ctx.emit(1);
|
||||
ctx.notify();
|
||||
ctx.emit(2);
|
||||
});
|
||||
handle_1.read(app, |model, _| {
|
||||
assert_eq!(model.events, vec!["updated".to_string()]);
|
||||
});
|
||||
handle_2.read(app, |model, _| {
|
||||
assert_eq!(
|
||||
model.events,
|
||||
vec![
|
||||
"observed event 1".to_string(),
|
||||
"notified".to_string(),
|
||||
"observed event 2".to_string(),
|
||||
]
|
||||
);
|
||||
});
|
||||
handle_1.update(app, |model, ctx| {
|
||||
model.events.push("updated".into());
|
||||
ctx.emit(1);
|
||||
ctx.notify();
|
||||
ctx.emit(2);
|
||||
});
|
||||
handle_1.read(app, |model, _| {
|
||||
assert_eq!(model.events, vec!["updated".to_string()]);
|
||||
});
|
||||
handle_2.read(app, |model, _| {
|
||||
assert_eq!(
|
||||
model.events,
|
||||
vec![
|
||||
"observed event 1".to_string(),
|
||||
"notified".to_string(),
|
||||
"observed event 2".to_string(),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
handle_2.update(app, |model, _| {
|
||||
drop(handle_1);
|
||||
model.other.take();
|
||||
});
|
||||
handle_2.update(app, |model, _| {
|
||||
drop(handle_1);
|
||||
model.other.take();
|
||||
});
|
||||
|
||||
let app_state = app.0.borrow();
|
||||
assert_eq!(app_state.ctx.models.len(), 1);
|
||||
assert!(app_state.subscriptions.is_empty());
|
||||
assert!(app_state.observations.is_empty());
|
||||
let app_state = app.0.borrow();
|
||||
assert_eq!(app_state.ctx.models.len(), 1);
|
||||
assert!(app_state.subscriptions.is_empty());
|
||||
assert!(app_state.observations.is_empty());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2310,28 +2346,28 @@ mod tests {
|
|||
type Event = usize;
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
let handle_1 = app.add_model(|_| Model::default());
|
||||
let handle_2 = app.add_model(|_| Model::default());
|
||||
let handle_2b = handle_2.clone();
|
||||
|
||||
let handle_1 = app.add_model(|_| Model::default());
|
||||
let handle_2 = app.add_model(|_| Model::default());
|
||||
let handle_2b = handle_2.clone();
|
||||
handle_1.update(app, |_, c| {
|
||||
c.subscribe(&handle_2, move |model: &mut Model, event, c| {
|
||||
model.events.push(*event);
|
||||
|
||||
handle_1.update(app, |_, c| {
|
||||
c.subscribe(&handle_2, move |model: &mut Model, event, c| {
|
||||
model.events.push(*event);
|
||||
|
||||
c.subscribe(&handle_2b, |model, event, _| {
|
||||
model.events.push(*event * 2);
|
||||
c.subscribe(&handle_2b, |model, event, _| {
|
||||
model.events.push(*event * 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
handle_2.update(app, |_, c| c.emit(7));
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
|
||||
handle_2.update(app, |_, c| c.emit(7));
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
|
||||
|
||||
handle_2.update(app, |_, c| c.emit(5));
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]));
|
||||
handle_2.update(app, |_, c| c.emit(5));
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2346,33 +2382,33 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
let handle_1 = app.add_model(|_| Model::default());
|
||||
let handle_2 = app.add_model(|_| Model::default());
|
||||
let handle_2b = handle_2.clone();
|
||||
|
||||
let app = &mut app;
|
||||
let handle_1 = app.add_model(|_| Model::default());
|
||||
let handle_2 = app.add_model(|_| Model::default());
|
||||
let handle_2b = handle_2.clone();
|
||||
|
||||
handle_1.update(app, |_, c| {
|
||||
c.observe(&handle_2, move |model, observed, c| {
|
||||
model.events.push(observed.as_ref(c).count);
|
||||
c.observe(&handle_2b, |model, observed, c| {
|
||||
model.events.push(observed.as_ref(c).count * 2);
|
||||
handle_1.update(app, |_, c| {
|
||||
c.observe(&handle_2, move |model, observed, c| {
|
||||
model.events.push(observed.as_ref(c).count);
|
||||
c.observe(&handle_2b, |model, observed, c| {
|
||||
model.events.push(observed.as_ref(c).count * 2);
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
handle_2.update(app, |model, c| {
|
||||
model.count = 7;
|
||||
c.notify()
|
||||
});
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
|
||||
handle_2.update(app, |model, c| {
|
||||
model.count = 7;
|
||||
c.notify()
|
||||
});
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7]));
|
||||
|
||||
handle_2.update(app, |model, c| {
|
||||
model.count = 5;
|
||||
c.notify()
|
||||
});
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]))
|
||||
handle_2.update(app, |model, c| {
|
||||
model.count = 5;
|
||||
c.notify()
|
||||
});
|
||||
handle_1.read(app, |model, _| assert_eq!(model.events, vec![7, 10, 5]))
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2386,7 +2422,7 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
App::test(|mut app| async move {
|
||||
App::test((), |mut app| async move {
|
||||
let handle = app.add_model(|_| Model::default());
|
||||
handle
|
||||
.update(&mut app, |_, c| {
|
||||
|
@ -2419,7 +2455,7 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
App::test(|mut app| async move {
|
||||
App::test((), |mut app| async move {
|
||||
let handle = app.add_model(|_| Model::default());
|
||||
handle
|
||||
.update(&mut app, |_, c| {
|
||||
|
@ -2476,41 +2512,41 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
let (window_id, _) = app.add_window(|ctx| View::new(None, ctx));
|
||||
let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx));
|
||||
let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx));
|
||||
assert_eq!(app.0.borrow().ctx.windows[&window_id].views.len(), 3);
|
||||
|
||||
let (window_id, _) = app.add_window(|ctx| View::new(None, ctx));
|
||||
let handle_1 = app.add_view(window_id, |ctx| View::new(None, ctx));
|
||||
let handle_2 = app.add_view(window_id, |ctx| View::new(Some(handle_1.clone()), ctx));
|
||||
assert_eq!(app.0.borrow().ctx.windows[&window_id].views.len(), 3);
|
||||
handle_1.update(app, |view, ctx| {
|
||||
view.events.push("updated".into());
|
||||
ctx.emit(1);
|
||||
ctx.emit(2);
|
||||
});
|
||||
handle_1.read(app, |view, _| {
|
||||
assert_eq!(view.events, vec!["updated".to_string()]);
|
||||
});
|
||||
handle_2.read(app, |view, _| {
|
||||
assert_eq!(
|
||||
view.events,
|
||||
vec![
|
||||
"observed event 1".to_string(),
|
||||
"observed event 2".to_string(),
|
||||
]
|
||||
);
|
||||
});
|
||||
|
||||
handle_1.update(app, |view, ctx| {
|
||||
view.events.push("updated".into());
|
||||
ctx.emit(1);
|
||||
ctx.emit(2);
|
||||
});
|
||||
handle_1.read(app, |view, _| {
|
||||
assert_eq!(view.events, vec!["updated".to_string()]);
|
||||
});
|
||||
handle_2.read(app, |view, _| {
|
||||
assert_eq!(
|
||||
view.events,
|
||||
vec![
|
||||
"observed event 1".to_string(),
|
||||
"observed event 2".to_string(),
|
||||
]
|
||||
);
|
||||
});
|
||||
handle_2.update(app, |view, _| {
|
||||
drop(handle_1);
|
||||
view.other.take();
|
||||
});
|
||||
|
||||
handle_2.update(app, |view, _| {
|
||||
drop(handle_1);
|
||||
view.other.take();
|
||||
});
|
||||
|
||||
let app_state = app.0.borrow();
|
||||
assert_eq!(app_state.ctx.windows[&window_id].views.len(), 2);
|
||||
assert!(app_state.subscriptions.is_empty());
|
||||
assert!(app_state.observations.is_empty());
|
||||
let app_state = app.0.borrow();
|
||||
assert_eq!(app_state.ctx.windows[&window_id].views.len(), 2);
|
||||
assert!(app_state.subscriptions.is_empty());
|
||||
assert!(app_state.observations.is_empty());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2540,36 +2576,36 @@ mod tests {
|
|||
type Event = usize;
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
let (window_id, handle_1) = app.add_window(|_| View::default());
|
||||
let handle_2 = app.add_view(window_id, |_| View::default());
|
||||
let handle_2b = handle_2.clone();
|
||||
let handle_3 = app.add_model(|_| Model);
|
||||
|
||||
let (window_id, handle_1) = app.add_window(|_| View::default());
|
||||
let handle_2 = app.add_view(window_id, |_| View::default());
|
||||
let handle_2b = handle_2.clone();
|
||||
let handle_3 = app.add_model(|_| Model);
|
||||
handle_1.update(app, |_, c| {
|
||||
c.subscribe_to_view(&handle_2, move |me, _, event, c| {
|
||||
me.events.push(*event);
|
||||
|
||||
handle_1.update(app, |_, c| {
|
||||
c.subscribe_to_view(&handle_2, move |me, _, event, c| {
|
||||
me.events.push(*event);
|
||||
|
||||
c.subscribe_to_view(&handle_2b, |me, _, event, _| {
|
||||
me.events.push(*event * 2);
|
||||
c.subscribe_to_view(&handle_2b, |me, _, event, _| {
|
||||
me.events.push(*event * 2);
|
||||
});
|
||||
});
|
||||
|
||||
c.subscribe_to_model(&handle_3, |me, _, event, _| {
|
||||
me.events.push(*event);
|
||||
})
|
||||
});
|
||||
|
||||
c.subscribe_to_model(&handle_3, |me, _, event, _| {
|
||||
me.events.push(*event);
|
||||
})
|
||||
});
|
||||
handle_2.update(app, |_, c| c.emit(7));
|
||||
handle_1.read(app, |view, _| assert_eq!(view.events, vec![7]));
|
||||
|
||||
handle_2.update(app, |_, c| c.emit(7));
|
||||
handle_1.read(app, |view, _| assert_eq!(view.events, vec![7]));
|
||||
handle_2.update(app, |_, c| c.emit(5));
|
||||
handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5]));
|
||||
|
||||
handle_2.update(app, |_, c| c.emit(5));
|
||||
handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5]));
|
||||
|
||||
handle_3.update(app, |_, c| c.emit(9));
|
||||
handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5, 9]));
|
||||
handle_3.update(app, |_, c| c.emit(9));
|
||||
handle_1.read(app, |view, _| assert_eq!(view.events, vec![7, 10, 5, 9]));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2596,30 +2632,31 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
|
||||
let (window_id, _) = app.add_window(|_| View);
|
||||
let observing_view = app.add_view(window_id, |_| View);
|
||||
let emitting_view = app.add_view(window_id, |_| View);
|
||||
let observing_model = app.add_model(|_| Model);
|
||||
let observed_model = app.add_model(|_| Model);
|
||||
let (window_id, _) = app.add_window(|_| View);
|
||||
let observing_view = app.add_view(window_id, |_| View);
|
||||
let emitting_view = app.add_view(window_id, |_| View);
|
||||
let observing_model = app.add_model(|_| Model);
|
||||
let observed_model = app.add_model(|_| Model);
|
||||
|
||||
observing_view.update(app, |_, ctx| {
|
||||
ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {});
|
||||
ctx.subscribe_to_model(&observed_model, |_, _, _, _| {});
|
||||
});
|
||||
observing_model.update(app, |_, ctx| {
|
||||
ctx.subscribe(&observed_model, |_, _, _| {});
|
||||
});
|
||||
observing_view.update(app, |_, ctx| {
|
||||
ctx.subscribe_to_view(&emitting_view, |_, _, _, _| {});
|
||||
ctx.subscribe_to_model(&observed_model, |_, _, _, _| {});
|
||||
});
|
||||
observing_model.update(app, |_, ctx| {
|
||||
ctx.subscribe(&observed_model, |_, _, _| {});
|
||||
});
|
||||
|
||||
app.update(|_| {
|
||||
drop(observing_view);
|
||||
drop(observing_model);
|
||||
});
|
||||
app.update(|_| {
|
||||
drop(observing_view);
|
||||
drop(observing_model);
|
||||
});
|
||||
|
||||
emitting_view.update(app, |_, ctx| ctx.emit(()));
|
||||
observed_model.update(app, |_, ctx| ctx.emit(()));
|
||||
emitting_view.update(app, |_, ctx| ctx.emit(()));
|
||||
observed_model.update(app, |_, ctx| ctx.emit(()));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2652,22 +2689,23 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
let (_, view) = app.add_window(|_| View::default());
|
||||
let model = app.add_model(|_| Model::default());
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
let (_, view) = app.add_window(|_| View::default());
|
||||
let model = app.add_model(|_| Model::default());
|
||||
|
||||
view.update(app, |_, c| {
|
||||
c.observe(&model, |me, observed, c| {
|
||||
me.events.push(observed.as_ref(c).count)
|
||||
view.update(app, |_, c| {
|
||||
c.observe(&model, |me, observed, c| {
|
||||
me.events.push(observed.as_ref(c).count)
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
model.update(app, |model, c| {
|
||||
model.count = 11;
|
||||
c.notify();
|
||||
});
|
||||
view.read(app, |view, _| assert_eq!(view.events, vec![11]));
|
||||
model.update(app, |model, c| {
|
||||
model.count = 11;
|
||||
c.notify();
|
||||
});
|
||||
view.read(app, |view, _| assert_eq!(view.events, vec![11]));
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2694,27 +2732,28 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
|
||||
let (window_id, _) = app.add_window(|_| View);
|
||||
let observing_view = app.add_view(window_id, |_| View);
|
||||
let observing_model = app.add_model(|_| Model);
|
||||
let observed_model = app.add_model(|_| Model);
|
||||
let (window_id, _) = app.add_window(|_| View);
|
||||
let observing_view = app.add_view(window_id, |_| View);
|
||||
let observing_model = app.add_model(|_| Model);
|
||||
let observed_model = app.add_model(|_| Model);
|
||||
|
||||
observing_view.update(app, |_, ctx| {
|
||||
ctx.observe(&observed_model, |_, _, _| {});
|
||||
});
|
||||
observing_model.update(app, |_, ctx| {
|
||||
ctx.observe(&observed_model, |_, _, _| {});
|
||||
});
|
||||
observing_view.update(app, |_, ctx| {
|
||||
ctx.observe(&observed_model, |_, _, _| {});
|
||||
});
|
||||
observing_model.update(app, |_, ctx| {
|
||||
ctx.observe(&observed_model, |_, _, _| {});
|
||||
});
|
||||
|
||||
app.update(|_| {
|
||||
drop(observing_view);
|
||||
drop(observing_model);
|
||||
});
|
||||
app.update(|_| {
|
||||
drop(observing_view);
|
||||
drop(observing_model);
|
||||
});
|
||||
|
||||
observed_model.update(app, |_, ctx| ctx.notify());
|
||||
observed_model.update(app, |_, ctx| ctx.notify());
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2748,34 +2787,35 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let app = &mut app;
|
||||
let (window_id, view_1) = app.add_window(|_| View::default());
|
||||
let view_2 = app.add_view(window_id, |_| View::default());
|
||||
App::test((), |mut app| async move {
|
||||
let app = &mut app;
|
||||
let (window_id, view_1) = app.add_window(|_| View::default());
|
||||
let view_2 = app.add_view(window_id, |_| View::default());
|
||||
|
||||
view_1.update(app, |_, ctx| {
|
||||
ctx.subscribe_to_view(&view_2, |view_1, _, event, _| {
|
||||
view_1.events.push(format!("view 2 {}", event));
|
||||
view_1.update(app, |_, ctx| {
|
||||
ctx.subscribe_to_view(&view_2, |view_1, _, event, _| {
|
||||
view_1.events.push(format!("view 2 {}", event));
|
||||
});
|
||||
ctx.focus(&view_2);
|
||||
});
|
||||
ctx.focus(&view_2);
|
||||
});
|
||||
|
||||
view_1.update(app, |_, ctx| {
|
||||
ctx.focus(&view_1);
|
||||
});
|
||||
view_1.update(app, |_, ctx| {
|
||||
ctx.focus(&view_1);
|
||||
});
|
||||
|
||||
view_1.read(app, |view_1, _| {
|
||||
assert_eq!(
|
||||
view_1.events,
|
||||
[
|
||||
"self focused".to_string(),
|
||||
"self blurred".to_string(),
|
||||
"view 2 focused".to_string(),
|
||||
"self focused".to_string(),
|
||||
"view 2 blurred".to_string(),
|
||||
],
|
||||
);
|
||||
});
|
||||
view_1.read(app, |view_1, _| {
|
||||
assert_eq!(
|
||||
view_1.events,
|
||||
[
|
||||
"self focused".to_string(),
|
||||
"self blurred".to_string(),
|
||||
"view 2 focused".to_string(),
|
||||
"self focused".to_string(),
|
||||
"view 2 blurred".to_string(),
|
||||
],
|
||||
);
|
||||
});
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -2799,7 +2839,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
App::test(|mut app| async move {
|
||||
App::test((), |mut app| async move {
|
||||
let (_, handle) = app.add_window(|_| View::default());
|
||||
handle
|
||||
.update(&mut app, |_, c| {
|
||||
|
@ -2841,7 +2881,7 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
App::test(|mut app| async move {
|
||||
App::test((), |mut app| async move {
|
||||
let (_, handle) = app.add_window(|_| View::default());
|
||||
handle
|
||||
.update(&mut app, |_, c| {
|
||||
|
@ -2905,76 +2945,77 @@ mod tests {
|
|||
foo: String,
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let actions = Rc::new(RefCell::new(Vec::new()));
|
||||
App::test((), |mut app| async move {
|
||||
let actions = Rc::new(RefCell::new(Vec::new()));
|
||||
|
||||
let actions_clone = actions.clone();
|
||||
app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
|
||||
actions_clone.borrow_mut().push("global a".to_string());
|
||||
});
|
||||
let actions_clone = actions.clone();
|
||||
app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
|
||||
actions_clone.borrow_mut().push("global a".to_string());
|
||||
});
|
||||
|
||||
let actions_clone = actions.clone();
|
||||
app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
|
||||
actions_clone.borrow_mut().push("global b".to_string());
|
||||
});
|
||||
let actions_clone = actions.clone();
|
||||
app.add_global_action("action", move |_: &ActionArg, _: &mut MutableAppContext| {
|
||||
actions_clone.borrow_mut().push("global b".to_string());
|
||||
});
|
||||
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| {
|
||||
assert_eq!(arg.foo, "bar");
|
||||
ctx.propagate_action();
|
||||
actions_clone.borrow_mut().push(format!("{} a", view.id));
|
||||
});
|
||||
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| {
|
||||
if view.id != 1 {
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewA, arg: &ActionArg, ctx| {
|
||||
assert_eq!(arg.foo, "bar");
|
||||
ctx.propagate_action();
|
||||
}
|
||||
actions_clone.borrow_mut().push(format!("{} b", view.id));
|
||||
});
|
||||
actions_clone.borrow_mut().push(format!("{} a", view.id));
|
||||
});
|
||||
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
|
||||
ctx.propagate_action();
|
||||
actions_clone.borrow_mut().push(format!("{} c", view.id));
|
||||
});
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewA, _: &ActionArg, ctx| {
|
||||
if view.id != 1 {
|
||||
ctx.propagate_action();
|
||||
}
|
||||
actions_clone.borrow_mut().push(format!("{} b", view.id));
|
||||
});
|
||||
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
|
||||
ctx.propagate_action();
|
||||
actions_clone.borrow_mut().push(format!("{} d", view.id));
|
||||
});
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
|
||||
ctx.propagate_action();
|
||||
actions_clone.borrow_mut().push(format!("{} c", view.id));
|
||||
});
|
||||
|
||||
let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 });
|
||||
let view_2 = app.add_view(window_id, |_| ViewB { id: 2 });
|
||||
let view_3 = app.add_view(window_id, |_| ViewA { id: 3 });
|
||||
let view_4 = app.add_view(window_id, |_| ViewB { id: 4 });
|
||||
let actions_clone = actions.clone();
|
||||
app.add_action("action", move |view: &mut ViewB, _: &ActionArg, ctx| {
|
||||
ctx.propagate_action();
|
||||
actions_clone.borrow_mut().push(format!("{} d", view.id));
|
||||
});
|
||||
|
||||
app.dispatch_action(
|
||||
window_id,
|
||||
vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
|
||||
"action",
|
||||
ActionArg { foo: "bar".into() },
|
||||
);
|
||||
let (window_id, view_1) = app.add_window(|_| ViewA { id: 1 });
|
||||
let view_2 = app.add_view(window_id, |_| ViewB { id: 2 });
|
||||
let view_3 = app.add_view(window_id, |_| ViewA { id: 3 });
|
||||
let view_4 = app.add_view(window_id, |_| ViewB { id: 4 });
|
||||
|
||||
assert_eq!(
|
||||
*actions.borrow(),
|
||||
vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
|
||||
);
|
||||
app.dispatch_action(
|
||||
window_id,
|
||||
vec![view_1.id(), view_2.id(), view_3.id(), view_4.id()],
|
||||
"action",
|
||||
ActionArg { foo: "bar".into() },
|
||||
);
|
||||
|
||||
// Remove view_1, which doesn't propagate the action
|
||||
actions.borrow_mut().clear();
|
||||
app.dispatch_action(
|
||||
window_id,
|
||||
vec![view_2.id(), view_3.id(), view_4.id()],
|
||||
"action",
|
||||
ActionArg { foo: "bar".into() },
|
||||
);
|
||||
assert_eq!(
|
||||
*actions.borrow(),
|
||||
vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "1 b"]
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
*actions.borrow(),
|
||||
vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
|
||||
);
|
||||
// Remove view_1, which doesn't propagate the action
|
||||
actions.borrow_mut().clear();
|
||||
app.dispatch_action(
|
||||
window_id,
|
||||
vec![view_2.id(), view_3.id(), view_4.id()],
|
||||
"action",
|
||||
ActionArg { foo: "bar".into() },
|
||||
);
|
||||
|
||||
assert_eq!(
|
||||
*actions.borrow(),
|
||||
vec!["4 d", "4 c", "3 b", "3 a", "2 d", "2 c", "global b", "global a"]
|
||||
);
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
@ -3018,41 +3059,41 @@ mod tests {
|
|||
}
|
||||
}
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
App::test((), |mut app| async move {
|
||||
let mut view_1 = View::new(1);
|
||||
let mut view_2 = View::new(2);
|
||||
let mut view_3 = View::new(3);
|
||||
view_1.keymap_context.set.insert("a".into());
|
||||
view_2.keymap_context.set.insert("b".into());
|
||||
view_3.keymap_context.set.insert("c".into());
|
||||
|
||||
let mut view_1 = View::new(1);
|
||||
let mut view_2 = View::new(2);
|
||||
let mut view_3 = View::new(3);
|
||||
view_1.keymap_context.set.insert("a".into());
|
||||
view_2.keymap_context.set.insert("b".into());
|
||||
view_3.keymap_context.set.insert("c".into());
|
||||
let (window_id, view_1) = app.add_window(|_| view_1);
|
||||
let view_2 = app.add_view(window_id, |_| view_2);
|
||||
let view_3 = app.add_view(window_id, |_| view_3);
|
||||
|
||||
let (window_id, view_1) = app.add_window(|_| view_1);
|
||||
let view_2 = app.add_view(window_id, |_| view_2);
|
||||
let view_3 = app.add_view(window_id, |_| view_3);
|
||||
// This keymap's only binding dispatches an action on view 2 because that view will have
|
||||
// "a" and "b" in its context, but not "c".
|
||||
let binding = keymap::Binding::new("a", "action", Some("a && b && !c"))
|
||||
.with_arg(ActionArg { key: "a".into() });
|
||||
app.add_bindings(vec![binding]);
|
||||
|
||||
// This keymap's only binding dispatches an action on view 2 because that view will have
|
||||
// "a" and "b" in its context, but not "c".
|
||||
let binding = keymap::Binding::new("a", "action", Some("a && b && !c"))
|
||||
.with_arg(ActionArg { key: "a".into() });
|
||||
app.add_bindings(vec![binding]);
|
||||
let handled_action = Rc::new(Cell::new(false));
|
||||
let handled_action_clone = handled_action.clone();
|
||||
app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| {
|
||||
handled_action_clone.set(true);
|
||||
assert_eq!(view.id, 2);
|
||||
assert_eq!(arg.key, "a");
|
||||
});
|
||||
|
||||
let handled_action = Rc::new(Cell::new(false));
|
||||
let handled_action_clone = handled_action.clone();
|
||||
app.add_action("action", move |view: &mut View, arg: &ActionArg, _ctx| {
|
||||
handled_action_clone.set(true);
|
||||
assert_eq!(view.id, 2);
|
||||
assert_eq!(arg.key, "a");
|
||||
});
|
||||
app.dispatch_keystroke(
|
||||
window_id,
|
||||
vec![view_1.id(), view_2.id(), view_3.id()],
|
||||
&Keystroke::parse("a")?,
|
||||
)?;
|
||||
|
||||
app.dispatch_keystroke(
|
||||
window_id,
|
||||
vec![view_1.id(), view_2.id(), view_3.id()],
|
||||
&Keystroke::parse("a")?,
|
||||
)?;
|
||||
|
||||
assert!(handled_action.get());
|
||||
Ok(())
|
||||
assert!(handled_action.get());
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
// #[test]
|
||||
|
@ -3160,7 +3201,7 @@ mod tests {
|
|||
type Event = ();
|
||||
}
|
||||
|
||||
App::test(|mut app| async move {
|
||||
App::test((), |mut app| async move {
|
||||
let model = app.add_model(|_| Model);
|
||||
let (_, view) = app.add_window(|_| View);
|
||||
|
||||
|
|
|
@ -2,6 +2,7 @@ use crate::{
|
|||
executor,
|
||||
geometry::vector::Vector2F,
|
||||
platform::{self, Event},
|
||||
Scene,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use cocoa::{
|
||||
|
@ -20,6 +21,7 @@ use objc::{
|
|||
runtime::{Class, Object, Sel, BOOL, NO, YES},
|
||||
sel, sel_impl,
|
||||
};
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
use smol::Timer;
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
|
@ -105,7 +107,7 @@ pub struct Window(Rc<WindowState>);
|
|||
struct WindowState {
|
||||
native_window: id,
|
||||
event_callback: RefCell<Option<Box<dyn FnMut(Event) -> bool>>>,
|
||||
resize_callback: RefCell<Option<Box<dyn FnMut(NSSize, f64)>>>,
|
||||
resize_callback: RefCell<Option<Box<dyn FnMut(Vector2F, f32)>>>,
|
||||
synthetic_drag_counter: Cell<usize>,
|
||||
executor: Rc<executor::Foreground>,
|
||||
}
|
||||
|
@ -207,19 +209,11 @@ impl Window {
|
|||
}
|
||||
}
|
||||
|
||||
pub fn size(&self) -> NSSize {
|
||||
self.0.size()
|
||||
}
|
||||
|
||||
pub fn backing_scale_factor(&self) -> f64 {
|
||||
self.0.backing_scale_factor()
|
||||
}
|
||||
|
||||
pub fn on_event<F: 'static + FnMut(Event) -> bool>(&mut self, callback: F) {
|
||||
*self.0.event_callback.borrow_mut() = Some(Box::new(callback));
|
||||
}
|
||||
|
||||
pub fn on_resize<F: 'static + FnMut(NSSize, f64)>(&mut self, callback: F) {
|
||||
pub fn on_resize<F: 'static + FnMut(Vector2F, f32)>(&mut self, callback: F) {
|
||||
*self.0.resize_callback.borrow_mut() = Some(Box::new(callback));
|
||||
}
|
||||
}
|
||||
|
@ -233,18 +227,31 @@ impl Drop for Window {
|
|||
}
|
||||
}
|
||||
|
||||
impl platform::Window for Window {}
|
||||
|
||||
impl WindowState {
|
||||
fn size(&self) -> NSSize {
|
||||
let view_frame = unsafe { NSView::frame(self.native_window.contentView()) };
|
||||
view_frame.size
|
||||
impl platform::Window for Window {
|
||||
fn size(&self) -> Vector2F {
|
||||
self.0.size()
|
||||
}
|
||||
|
||||
fn backing_scale_factor(&self) -> f64 {
|
||||
fn scale_factor(&self) -> f32 {
|
||||
self.0.scale_factor()
|
||||
}
|
||||
|
||||
fn render_scene(&self, scene: Scene) {
|
||||
log::info!("render scene");
|
||||
}
|
||||
}
|
||||
|
||||
impl WindowState {
|
||||
fn size(&self) -> Vector2F {
|
||||
let NSSize { width, height, .. } =
|
||||
unsafe { NSView::frame(self.native_window.contentView()) }.size;
|
||||
vec2f(width as f32, height as f32)
|
||||
}
|
||||
|
||||
fn scale_factor(&self) -> f32 {
|
||||
unsafe {
|
||||
let screen: id = msg_send![self.native_window, screen];
|
||||
NSScreen::backingScaleFactor(screen)
|
||||
NSScreen::backingScaleFactor(screen) as f32
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -297,7 +304,7 @@ extern "C" fn dealloc_delegate(this: &Object, _: Sel) {
|
|||
extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||
let window = unsafe { window_state(this) };
|
||||
|
||||
let event = unsafe { Event::from_native(native_event, Some(window.size().height as f32)) };
|
||||
let event = unsafe { Event::from_native(native_event, Some(window.size().y())) };
|
||||
|
||||
if let Some(event) = event {
|
||||
match event {
|
||||
|
@ -325,7 +332,7 @@ extern "C" fn send_event(this: &Object, _: Sel, native_event: id) {
|
|||
extern "C" fn window_did_resize(this: &Object, _: Sel, _: id) {
|
||||
let window = unsafe { window_state(this) };
|
||||
let size = window.size();
|
||||
let scale_factor = window.backing_scale_factor();
|
||||
let scale_factor = window.scale_factor();
|
||||
if let Some(callback) = window.resize_callback.borrow_mut().as_mut() {
|
||||
callback(size, scale_factor);
|
||||
}
|
||||
|
|
|
@ -6,7 +6,11 @@ pub mod current {
|
|||
pub use super::mac::*;
|
||||
}
|
||||
|
||||
use crate::{executor, geometry::rect::RectF};
|
||||
use crate::{
|
||||
executor,
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
Scene,
|
||||
};
|
||||
use anyhow::Result;
|
||||
use async_task::Runnable;
|
||||
pub use event::Event;
|
||||
|
@ -36,7 +40,11 @@ pub trait Dispatcher: Send + Sync {
|
|||
fn run_on_main_thread(&self, task: Runnable);
|
||||
}
|
||||
|
||||
pub trait Window {}
|
||||
pub trait Window {
|
||||
fn size(&self) -> Vector2F;
|
||||
fn scale_factor(&self) -> f32;
|
||||
fn render_scene(&self, scene: Scene);
|
||||
}
|
||||
|
||||
pub struct WindowOptions<'a> {
|
||||
pub bounds: RectF,
|
||||
|
|
|
@ -7,22 +7,22 @@ use crate::{
|
|||
AssetCache, Scene,
|
||||
};
|
||||
use pathfinder_geometry::vector::{vec2f, Vector2F};
|
||||
use std::{any::Any, collections::HashMap, rc::Rc};
|
||||
use std::{any::Any, collections::HashMap, sync::Arc};
|
||||
|
||||
pub struct Presenter {
|
||||
window_id: usize,
|
||||
rendered_views: HashMap<usize, Box<dyn Element>>,
|
||||
parents: HashMap<usize, usize>,
|
||||
font_cache: Rc<FontCache>,
|
||||
font_cache: Arc<FontCache>,
|
||||
text_layout_cache: TextLayoutCache,
|
||||
asset_cache: Rc<AssetCache>,
|
||||
asset_cache: Arc<AssetCache>,
|
||||
}
|
||||
|
||||
impl Presenter {
|
||||
pub fn new(
|
||||
window_id: usize,
|
||||
font_cache: Rc<FontCache>,
|
||||
asset_cache: Rc<AssetCache>,
|
||||
font_cache: Arc<FontCache>,
|
||||
asset_cache: Arc<AssetCache>,
|
||||
app: &MutableAppContext,
|
||||
) -> Self {
|
||||
Self {
|
||||
|
@ -35,7 +35,7 @@ impl Presenter {
|
|||
}
|
||||
}
|
||||
|
||||
fn invalidate(&mut self, invalidation: WindowInvalidation, app: &AppContext) {
|
||||
pub fn invalidate(&mut self, invalidation: WindowInvalidation, app: &AppContext) {
|
||||
for view_id in invalidation.updated {
|
||||
self.rendered_views
|
||||
.insert(view_id, app.render_view(self.window_id, view_id).unwrap());
|
||||
|
@ -52,9 +52,9 @@ impl Presenter {
|
|||
scale_factor: f32,
|
||||
app: &mut MutableAppContext,
|
||||
) -> Scene {
|
||||
self.layout(window_size, app.ctx());
|
||||
self.layout(window_size, app.downgrade());
|
||||
self.after_layout(app);
|
||||
let scene = self.paint(window_size, scale_factor, app.ctx());
|
||||
let scene = self.paint(window_size, scale_factor, app.downgrade());
|
||||
self.text_layout_cache.finish_frame();
|
||||
scene
|
||||
}
|
||||
|
|
|
@ -26,6 +26,7 @@ log = "0.4"
|
|||
num_cpus = "1.13.0"
|
||||
parking_lot = "0.11.1"
|
||||
rand = "0.8.3"
|
||||
rust-embed = "5.9.0"
|
||||
simplelog = "0.9"
|
||||
smallvec = "1.6.1"
|
||||
smol = "1.2.5"
|
||||
|
|
13
zed/src/assets.rs
Normal file
13
zed/src/assets.rs
Normal file
|
@ -0,0 +1,13 @@
|
|||
use anyhow::{anyhow, Result};
|
||||
use gpui::AssetSource;
|
||||
use rust_embed::RustEmbed;
|
||||
|
||||
#[derive(RustEmbed)]
|
||||
#[folder = "assets"]
|
||||
struct Assets;
|
||||
|
||||
impl AssetSource for Assets {
|
||||
fn load(&self, path: &str) -> Result<std::borrow::Cow<[u8]>> {
|
||||
Self::get(path).ok_or_else(|| anyhow!("could not find asset at path \"{}\"", path))
|
||||
}
|
||||
}
|
|
@ -1907,46 +1907,46 @@ mod tests {
|
|||
use gpui::App;
|
||||
use std::{cell::RefCell, rc::Rc};
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let mut app = App::test((), |mut app| async move {
|
||||
let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
|
||||
let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
|
||||
|
||||
let buffer_1_events = Rc::new(RefCell::new(Vec::new()));
|
||||
let buffer_2_events = Rc::new(RefCell::new(Vec::new()));
|
||||
let buffer1 = app.add_model(|_| Buffer::new(0, "abcdef"));
|
||||
let buffer2 = app.add_model(|_| Buffer::new(1, "abcdef"));
|
||||
let ops = buffer1.update(&mut app, |buffer, ctx| {
|
||||
let buffer_1_events = buffer_1_events.clone();
|
||||
ctx.subscribe(&buffer1, move |_, event, _| {
|
||||
buffer_1_events.borrow_mut().push(event.clone())
|
||||
});
|
||||
let buffer_2_events = buffer_2_events.clone();
|
||||
ctx.subscribe(&buffer2, move |_, event, _| {
|
||||
buffer_2_events.borrow_mut().push(event.clone())
|
||||
});
|
||||
|
||||
let buffer1 = app.add_model(|_| Buffer::new(0, "abcdef"));
|
||||
let buffer2 = app.add_model(|_| Buffer::new(1, "abcdef"));
|
||||
let ops = buffer1.update(&mut app, |buffer, ctx| {
|
||||
let buffer_1_events = buffer_1_events.clone();
|
||||
ctx.subscribe(&buffer1, move |_, event, _| {
|
||||
buffer_1_events.borrow_mut().push(event.clone())
|
||||
buffer.edit(Some(2..4), "XYZ", Some(ctx)).unwrap()
|
||||
});
|
||||
let buffer_2_events = buffer_2_events.clone();
|
||||
ctx.subscribe(&buffer2, move |_, event, _| {
|
||||
buffer_2_events.borrow_mut().push(event.clone())
|
||||
buffer2.update(&mut app, |buffer, ctx| {
|
||||
buffer.apply_ops(ops, Some(ctx)).unwrap();
|
||||
});
|
||||
|
||||
buffer.edit(Some(2..4), "XYZ", Some(ctx)).unwrap()
|
||||
});
|
||||
buffer2.update(&mut app, |buffer, ctx| {
|
||||
buffer.apply_ops(ops, Some(ctx)).unwrap();
|
||||
});
|
||||
let buffer_1_events = buffer_1_events.borrow();
|
||||
assert_eq!(
|
||||
*buffer_1_events,
|
||||
vec![Event::Edited(vec![Edit {
|
||||
old_range: 2..4,
|
||||
new_range: 2..5
|
||||
}])]
|
||||
);
|
||||
|
||||
let buffer_1_events = buffer_1_events.borrow();
|
||||
assert_eq!(
|
||||
*buffer_1_events,
|
||||
vec![Event::Edited(vec![Edit {
|
||||
old_range: 2..4,
|
||||
new_range: 2..5
|
||||
}])]
|
||||
);
|
||||
|
||||
let buffer_2_events = buffer_2_events.borrow();
|
||||
assert_eq!(
|
||||
*buffer_2_events,
|
||||
vec![Event::Edited(vec![Edit {
|
||||
old_range: 2..4,
|
||||
new_range: 2..5
|
||||
}])]
|
||||
);
|
||||
let buffer_2_events = buffer_2_events.borrow();
|
||||
assert_eq!(
|
||||
*buffer_2_events,
|
||||
vec![Event::Edited(vec![Edit {
|
||||
old_range: 2..4,
|
||||
new_range: 2..5
|
||||
}])]
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -418,7 +418,7 @@ impl Element for BufferElement {
|
|||
let view = self.view.as_ref(app);
|
||||
view.clamp_scroll_left(
|
||||
layout
|
||||
.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app.ctx())
|
||||
.scroll_max(view, ctx.font_cache, ctx.text_layout_cache, app.downgrade())
|
||||
.x(),
|
||||
);
|
||||
|
||||
|
@ -426,10 +426,10 @@ impl Element for BufferElement {
|
|||
view.autoscroll_horizontally(
|
||||
view.scroll_position().y() as u32,
|
||||
layout.text_size.x(),
|
||||
layout.scroll_width(view, ctx.font_cache, ctx.text_layout_cache, app.ctx()),
|
||||
layout.scroll_width(view, ctx.font_cache, ctx.text_layout_cache, app.downgrade()),
|
||||
view.em_width(ctx.font_cache),
|
||||
&layout.line_layouts,
|
||||
app.ctx(),
|
||||
app.downgrade(),
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1269,7 +1269,7 @@ mod tests {
|
|||
|
||||
#[test]
|
||||
fn test_selection_with_mouse() {
|
||||
App::test(|mut app| async move {
|
||||
App::test((), |mut app| async move {
|
||||
let buffer = app.add_model(|_| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n"));
|
||||
let settings = settings::channel(&FontCache::new()).unwrap().1;
|
||||
let (_, buffer_view) =
|
||||
|
@ -1373,19 +1373,21 @@ mod tests {
|
|||
let font_cache = FontCache::new();
|
||||
let layout_cache = TextLayoutCache::new();
|
||||
|
||||
let mut app = App::new().unwrap();
|
||||
let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
|
||||
App::test((), |mut app| async move {
|
||||
let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
|
||||
|
||||
let settings = settings::channel(&font_cache).unwrap().1;
|
||||
let (_, view) = app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
|
||||
let settings = settings::channel(&font_cache).unwrap().1;
|
||||
let (_, view) =
|
||||
app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
|
||||
|
||||
view.read(&app, |view, app| {
|
||||
let layouts = view.layout_line_numbers(1000.0, &font_cache, &layout_cache, app)?;
|
||||
assert_eq!(layouts.len(), 6);
|
||||
Result::<()>::Ok(())
|
||||
})?;
|
||||
view.read(&app, |view, app| {
|
||||
let layouts = view.layout_line_numbers(1000.0, &font_cache, &layout_cache, app)?;
|
||||
assert_eq!(layouts.len(), 6);
|
||||
Result::<()>::Ok(())
|
||||
})?;
|
||||
|
||||
Ok(())
|
||||
Ok(())
|
||||
})
|
||||
}
|
||||
|
||||
#[test]
|
||||
|
|
|
@ -1,3 +1,4 @@
|
|||
pub mod assets;
|
||||
pub mod editor;
|
||||
mod operation_queue;
|
||||
pub mod settings;
|
||||
|
|
|
@ -27,7 +27,7 @@ fn main() {
|
|||
|
||||
let (settings_tx, settings_rx) = settings::channel(&font_cache).unwrap();
|
||||
|
||||
let mut app = gpui::App::new().unwrap();
|
||||
let mut app = gpui::App::new(As).unwrap();
|
||||
|
||||
platform::runner()
|
||||
.on_finish_launching(move || {
|
||||
|
|
Loading…
Reference in a new issue