Implement activate_workspace_for_project
This commit is contained in:
parent
bd750fbbe2
commit
e2ee9a28bf
5 changed files with 146 additions and 49 deletions
|
@ -17,8 +17,8 @@ use crate::{
|
||||||
AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Executor,
|
AppMetadata, AssetSource, ClipboardItem, Context, DispatchPhase, DisplayId, Executor,
|
||||||
FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly,
|
FocusEvent, FocusHandle, FocusId, KeyBinding, Keymap, LayoutId, MainThread, MainThreadOnly,
|
||||||
Pixels, Platform, Point, SharedString, SubscriberSet, Subscription, SvgRenderer, Task,
|
Pixels, Platform, Point, SharedString, SubscriberSet, Subscription, SvgRenderer, Task,
|
||||||
TextStyle, TextStyleRefinement, TextSystem, View, Window, WindowContext, WindowHandle,
|
TextStyle, TextStyleRefinement, TextSystem, View, ViewContext, Window, WindowContext,
|
||||||
WindowId,
|
WindowHandle, WindowId,
|
||||||
};
|
};
|
||||||
use anyhow::{anyhow, Result};
|
use anyhow::{anyhow, Result};
|
||||||
use collections::{HashMap, HashSet, VecDeque};
|
use collections::{HashMap, HashSet, VecDeque};
|
||||||
|
@ -303,6 +303,20 @@ impl AppContext {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_window_root<V, R>(
|
||||||
|
&mut self,
|
||||||
|
handle: &WindowHandle<V>,
|
||||||
|
update: impl FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> R,
|
||||||
|
) -> Result<R>
|
||||||
|
where
|
||||||
|
V: 'static,
|
||||||
|
{
|
||||||
|
self.update_window(handle.any_handle, |cx| {
|
||||||
|
let root_view = cx.window.root_view.as_ref().unwrap().downcast().unwrap();
|
||||||
|
root_view.update(cx, update)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn push_effect(&mut self, effect: Effect) {
|
pub(crate) fn push_effect(&mut self, effect: Effect) {
|
||||||
match &effect {
|
match &effect {
|
||||||
Effect::Notify { emitter } => {
|
Effect::Notify { emitter } => {
|
||||||
|
@ -841,6 +855,20 @@ impl MainThread<AppContext> {
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_window_root<V, R>(
|
||||||
|
&mut self,
|
||||||
|
handle: &WindowHandle<V>,
|
||||||
|
update: impl FnOnce(&mut V, &mut MainThread<ViewContext<'_, '_, V>>) -> R,
|
||||||
|
) -> Result<R>
|
||||||
|
where
|
||||||
|
V: 'static,
|
||||||
|
{
|
||||||
|
self.update_window(handle.any_handle, |cx| {
|
||||||
|
let root_view = cx.window.root_view.as_ref().unwrap().downcast().unwrap();
|
||||||
|
root_view.update(cx, update)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
/// Opens a new window with the given option and the root view returned by the given function.
|
/// Opens a new window with the given option and the root view returned by the given function.
|
||||||
/// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
|
/// The function is invoked with a `WindowContext`, which can be used to interact with window-specific
|
||||||
/// functionality.
|
/// functionality.
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyWindowHandle, AppContext, Context, Executor, Handle, MainThread, ModelContext, Result, Task,
|
AnyWindowHandle, AppContext, Component, Context, Executor, Handle, MainThread, ModelContext,
|
||||||
WindowContext,
|
Result, Task, View, ViewContext, VisualContext, WindowContext, WindowHandle,
|
||||||
};
|
};
|
||||||
use anyhow::Context as _;
|
use anyhow::Context as _;
|
||||||
use derive_more::{Deref, DerefMut};
|
use derive_more::{Deref, DerefMut};
|
||||||
|
@ -78,6 +78,19 @@ impl AsyncAppContext {
|
||||||
app_context.update_window(handle, update)
|
app_context.update_window(handle, update)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn update_window_root<V, R>(
|
||||||
|
&mut self,
|
||||||
|
handle: &WindowHandle<V>,
|
||||||
|
update: impl FnOnce(&mut V, &mut ViewContext<'_, '_, V>) -> R,
|
||||||
|
) -> Result<R>
|
||||||
|
where
|
||||||
|
V: 'static,
|
||||||
|
{
|
||||||
|
let app = self.app.upgrade().context("app was released")?;
|
||||||
|
let mut app_context = app.lock();
|
||||||
|
app_context.update_window_root(handle, update)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
|
pub fn spawn<Fut, R>(&self, f: impl FnOnce(AsyncAppContext) -> Fut + Send + 'static) -> Task<R>
|
||||||
where
|
where
|
||||||
Fut: Future<Output = R> + Send + 'static,
|
Fut: Future<Output = R> + Send + 'static,
|
||||||
|
@ -245,6 +258,32 @@ impl Context for AsyncWindowContext {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl VisualContext for AsyncWindowContext {
|
||||||
|
type ViewContext<'a, 'w, V> = ViewContext<'a, 'w, V>;
|
||||||
|
|
||||||
|
fn build_view<E, V>(
|
||||||
|
&mut self,
|
||||||
|
build_entity: impl FnOnce(&mut Self::ViewContext<'_, '_, V>) -> V,
|
||||||
|
render: impl Fn(&mut V, &mut ViewContext<'_, '_, V>) -> E + Send + 'static,
|
||||||
|
) -> Self::Result<View<V>>
|
||||||
|
where
|
||||||
|
E: Component<V>,
|
||||||
|
V: 'static + Send,
|
||||||
|
{
|
||||||
|
self.app
|
||||||
|
.update_window(self.window, |cx| cx.build_view(build_entity, render))
|
||||||
|
}
|
||||||
|
|
||||||
|
fn update_view<V: 'static, R>(
|
||||||
|
&mut self,
|
||||||
|
view: &View<V>,
|
||||||
|
update: impl FnOnce(&mut V, &mut Self::ViewContext<'_, '_, V>) -> R,
|
||||||
|
) -> Self::Result<R> {
|
||||||
|
self.app
|
||||||
|
.update_window(self.window, |cx| cx.update_view(view, update))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
|
@ -1,11 +1,12 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
|
AnyBox, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element, ElementId,
|
||||||
EntityId, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle,
|
EntityId, Flatten, Handle, LayoutId, Pixels, Size, ViewContext, VisualContext, WeakHandle,
|
||||||
WindowContext,
|
WindowContext,
|
||||||
};
|
};
|
||||||
use anyhow::{Context, Result};
|
use anyhow::{Context, Result};
|
||||||
use parking_lot::Mutex;
|
use parking_lot::Mutex;
|
||||||
use std::{
|
use std::{
|
||||||
|
any::Any,
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
sync::{Arc, Weak},
|
sync::{Arc, Weak},
|
||||||
};
|
};
|
||||||
|
@ -128,13 +129,17 @@ impl<V: 'static> WeakView<V> {
|
||||||
Some(View { state, render })
|
Some(View { state, render })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn update<R>(
|
pub fn update<C, R>(
|
||||||
&self,
|
&self,
|
||||||
cx: &mut WindowContext,
|
cx: &mut C,
|
||||||
f: impl FnOnce(&mut V, &mut ViewContext<V>) -> R,
|
f: impl FnOnce(&mut V, &mut C::ViewContext<'_, '_, V>) -> R,
|
||||||
) -> Result<R> {
|
) -> Result<R>
|
||||||
|
where
|
||||||
|
C: VisualContext,
|
||||||
|
Result<C::Result<R>>: Flatten<R>,
|
||||||
|
{
|
||||||
let view = self.upgrade().context("error upgrading view")?;
|
let view = self.upgrade().context("error upgrading view")?;
|
||||||
Ok(view.update(cx, f))
|
Ok(view.update(cx, f)).flatten()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -201,15 +206,16 @@ trait ViewObject: Send + Sync {
|
||||||
fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
|
fn initialize(&self, cx: &mut WindowContext) -> AnyBox;
|
||||||
fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
|
fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
|
||||||
fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
|
fn paint(&self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
|
||||||
|
fn as_any(&self) -> &dyn Any;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<V: 'static> ViewObject for View<V> {
|
impl<V: 'static> ViewObject for View<V> {
|
||||||
fn entity_id(&self) -> EntityId {
|
fn entity_id(&self) -> EntityId {
|
||||||
self.state.entity_id()
|
self.state.entity_id
|
||||||
}
|
}
|
||||||
|
|
||||||
fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
|
fn initialize(&self, cx: &mut WindowContext) -> AnyBox {
|
||||||
cx.with_element_id(self.entity_id(), |_global_id, cx| {
|
cx.with_element_id(self.state.entity_id, |_global_id, cx| {
|
||||||
self.update(cx, |state, cx| {
|
self.update(cx, |state, cx| {
|
||||||
let mut any_element = Box::new((self.render.lock())(state, cx));
|
let mut any_element = Box::new((self.render.lock())(state, cx));
|
||||||
any_element.initialize(state, cx);
|
any_element.initialize(state, cx);
|
||||||
|
@ -219,7 +225,7 @@ impl<V: 'static> ViewObject for View<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
|
fn layout(&self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
|
||||||
cx.with_element_id(self.entity_id(), |_global_id, cx| {
|
cx.with_element_id(self.state.entity_id, |_global_id, cx| {
|
||||||
self.update(cx, |state, cx| {
|
self.update(cx, |state, cx| {
|
||||||
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
|
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
|
||||||
element.layout(state, cx)
|
element.layout(state, cx)
|
||||||
|
@ -228,19 +234,27 @@ impl<V: 'static> ViewObject for View<V> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
|
fn paint(&self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
|
||||||
cx.with_element_id(self.entity_id(), |_global_id, cx| {
|
cx.with_element_id(self.state.entity_id, |_global_id, cx| {
|
||||||
self.update(cx, |state, cx| {
|
self.update(cx, |state, cx| {
|
||||||
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
|
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
|
||||||
element.paint(state, cx);
|
element.paint(state, cx);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn as_any(&self) -> &dyn Any {
|
||||||
|
self
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct AnyView(Arc<dyn ViewObject>);
|
pub struct AnyView(Arc<dyn ViewObject>);
|
||||||
|
|
||||||
impl AnyView {
|
impl AnyView {
|
||||||
|
pub fn downcast<V: 'static>(&self) -> Option<View<V>> {
|
||||||
|
self.0.as_any().downcast_ref().cloned()
|
||||||
|
}
|
||||||
|
|
||||||
pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
|
pub(crate) fn draw(&self, available_space: Size<AvailableSpace>, cx: &mut WindowContext) {
|
||||||
let mut rendered_element = self.0.initialize(cx);
|
let mut rendered_element = self.0.initialize(cx);
|
||||||
let layout_id = self.0.layout(&mut rendered_element, cx);
|
let layout_id = self.0.layout(&mut rendered_element, cx);
|
||||||
|
|
|
@ -1237,16 +1237,6 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, 'w> MainThread<WindowContext<'a, 'w>> {
|
|
||||||
fn platform_window(&self) -> &dyn PlatformWindow {
|
|
||||||
self.window.platform_window.borrow_on_main_thread().as_ref()
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn activate_window(&self) {
|
|
||||||
self.platform_window().activate();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Context for WindowContext<'_, '_> {
|
impl Context for WindowContext<'_, '_> {
|
||||||
type EntityContext<'a, T> = ModelContext<'a, T>;
|
type EntityContext<'a, T> = ModelContext<'a, T>;
|
||||||
type Result<T> = T;
|
type Result<T> = T;
|
||||||
|
@ -1864,6 +1854,16 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<'a, 'w, V: 'static> MainThread<ViewContext<'a, 'w, V>> {
|
||||||
|
fn platform_window(&self) -> &dyn PlatformWindow {
|
||||||
|
self.window.platform_window.borrow_on_main_thread().as_ref()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn activate_window(&self) {
|
||||||
|
self.platform_window().activate();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
|
impl<'a, 'w, V> Context for ViewContext<'a, 'w, V> {
|
||||||
type EntityContext<'b, U> = ModelContext<'b, U>;
|
type EntityContext<'b, U> = ModelContext<'b, U>;
|
||||||
type Result<U> = U;
|
type Result<U> = U;
|
||||||
|
@ -1934,38 +1934,40 @@ impl WindowId {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(PartialEq, Eq)]
|
#[derive(PartialEq, Eq, Deref, DerefMut)]
|
||||||
pub struct WindowHandle<V> {
|
pub struct WindowHandle<V> {
|
||||||
id: WindowId,
|
#[deref]
|
||||||
|
#[deref_mut]
|
||||||
|
pub(crate) any_handle: AnyWindowHandle,
|
||||||
state_type: PhantomData<V>,
|
state_type: PhantomData<V>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> Copy for WindowHandle<S> {}
|
impl<V> Copy for WindowHandle<V> {}
|
||||||
|
|
||||||
impl<S> Clone for WindowHandle<S> {
|
impl<V> Clone for WindowHandle<V> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
WindowHandle {
|
WindowHandle {
|
||||||
id: self.id,
|
any_handle: self.any_handle,
|
||||||
state_type: PhantomData,
|
state_type: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S> WindowHandle<S> {
|
impl<V: 'static> WindowHandle<V> {
|
||||||
pub fn new(id: WindowId) -> Self {
|
pub fn new(id: WindowId) -> Self {
|
||||||
WindowHandle {
|
WindowHandle {
|
||||||
id,
|
any_handle: AnyWindowHandle {
|
||||||
|
id,
|
||||||
|
state_type: TypeId::of::<V>(),
|
||||||
|
},
|
||||||
state_type: PhantomData,
|
state_type: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<S: 'static> Into<AnyWindowHandle> for WindowHandle<S> {
|
impl<V: 'static> Into<AnyWindowHandle> for WindowHandle<V> {
|
||||||
fn into(self) -> AnyWindowHandle {
|
fn into(self) -> AnyWindowHandle {
|
||||||
AnyWindowHandle {
|
self.any_handle
|
||||||
id: self.id,
|
|
||||||
state_type: TypeId::of::<S>(),
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1979,6 +1981,17 @@ impl AnyWindowHandle {
|
||||||
pub fn window_id(&self) -> WindowId {
|
pub fn window_id(&self) -> WindowId {
|
||||||
self.id
|
self.id
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn downcast<T: 'static>(&self) -> Option<WindowHandle<T>> {
|
||||||
|
if TypeId::of::<T>() == self.state_type {
|
||||||
|
Some(WindowHandle {
|
||||||
|
any_handle: *self,
|
||||||
|
state_type: PhantomData,
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
|
|
@ -4103,25 +4103,28 @@ pub struct Workspace {
|
||||||
pub async fn activate_workspace_for_project(
|
pub async fn activate_workspace_for_project(
|
||||||
cx: &mut AsyncAppContext,
|
cx: &mut AsyncAppContext,
|
||||||
predicate: impl Fn(&Project, &AppContext) -> bool + Send + 'static,
|
predicate: impl Fn(&Project, &AppContext) -> bool + Send + 'static,
|
||||||
) -> Option<WeakHandle<Workspace>> {
|
) -> Option<WindowHandle<Workspace>> {
|
||||||
cx.run_on_main(move |cx| {
|
cx.run_on_main(move |cx| {
|
||||||
for window in cx.windows() {
|
for window in cx.windows() {
|
||||||
let handle = cx
|
let Some(workspace) = window.downcast::<Workspace>() else {
|
||||||
.update_window(window, |cx| {
|
continue;
|
||||||
if let Some(workspace_handle) = cx.root_view()?.downcast::<Workspace>() {
|
};
|
||||||
let project = workspace_handle.read(cx).project.clone();
|
|
||||||
if project.update(cx, |project, cx| predicate(project, cx)) {
|
let predicate = cx
|
||||||
cx.activate_window();
|
.update_window_root(&workspace, |workspace, cx| {
|
||||||
return Some(workspace_handle.clone());
|
let project = workspace.project.read(cx);
|
||||||
}
|
if predicate(project, cx) {
|
||||||
|
cx.activate_window();
|
||||||
|
true
|
||||||
|
} else {
|
||||||
|
false
|
||||||
}
|
}
|
||||||
None
|
|
||||||
})
|
})
|
||||||
.log_err()
|
.log_err()
|
||||||
.flatten();
|
.unwrap_or(false);
|
||||||
|
|
||||||
if let Some(handle) = handle {
|
if predicate {
|
||||||
return Some(handle.downgrade());
|
return Some(workspace);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue