This commit is contained in:
Nathan Sobo 2023-04-08 06:43:39 -06:00
parent 2186de38ab
commit 9d23a98157
4 changed files with 382 additions and 380 deletions

View file

@ -321,6 +321,17 @@ impl App {
state.pending_notifications.clear(); state.pending_notifications.clear();
result result
} }
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
callback: F,
) -> Option<T> {
let mut state = self.0.borrow_mut();
let result = state.update_window(window_id, callback);
state.pending_notifications.clear();
result
}
} }
impl AsyncAppContext { impl AsyncAppContext {
@ -341,6 +352,14 @@ impl AsyncAppContext {
self.0.borrow_mut().update(callback) self.0.borrow_mut().update(callback)
} }
fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
&mut self,
window_id: usize,
callback: F,
) -> Option<T> {
self.0.borrow_mut().update_window(window_id, callback)
}
pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T> pub fn add_model<T, F>(&mut self, build_model: F) -> ModelHandle<T>
where where
T: Entity, T: Entity,
@ -366,7 +385,7 @@ impl AsyncAppContext {
} }
pub fn activate_window(&mut self, window_id: usize) { pub fn activate_window(&mut self, window_id: usize) {
self.update(|cx| cx.activate_window(window_id)) self.update_window(window_id, |cx| cx.activate_window());
} }
pub fn prompt( pub fn prompt(
@ -375,8 +394,8 @@ impl AsyncAppContext {
level: PromptLevel, level: PromptLevel,
msg: &str, msg: &str,
answers: &[&str], answers: &[&str],
) -> oneshot::Receiver<usize> { ) -> Option<oneshot::Receiver<usize>> {
self.update(|cx| cx.prompt(window_id, level, msg, answers)) self.update_window(window_id, |cx| cx.prompt(level, msg, answers))
} }
pub fn platform(&self) -> Arc<dyn Platform> { pub fn platform(&self) -> Arc<dyn Platform> {
@ -528,9 +547,6 @@ pub struct AppContext {
keystroke_observations: CallbackCollection<usize, KeystrokeCallback>, keystroke_observations: CallbackCollection<usize, KeystrokeCallback>,
active_labeled_task_observations: CallbackCollection<(), ActiveLabeledTasksCallback>, active_labeled_task_observations: CallbackCollection<(), ActiveLabeledTasksCallback>,
#[allow(clippy::type_complexity)]
presenters_and_platform_windows:
HashMap<usize, (Rc<RefCell<Presenter>>, Box<dyn platform::Window>)>,
foreground: Rc<executor::Foreground>, foreground: Rc<executor::Foreground>,
pending_effects: VecDeque<Effect>, pending_effects: VecDeque<Effect>,
pending_notifications: HashSet<usize>, pending_notifications: HashSet<usize>,
@ -588,7 +604,6 @@ impl AppContext {
keystroke_observations: Default::default(), keystroke_observations: Default::default(),
action_dispatch_observations: Default::default(), action_dispatch_observations: Default::default(),
active_labeled_task_observations: Default::default(), active_labeled_task_observations: Default::default(),
presenters_and_platform_windows: Default::default(),
foreground, foreground,
pending_effects: VecDeque::new(), pending_effects: VecDeque::new(),
pending_notifications: Default::default(), pending_notifications: Default::default(),
@ -659,9 +674,7 @@ impl AppContext {
} }
pub fn remove_all_windows(&mut self) { pub fn remove_all_windows(&mut self) {
for (window_id, _) in self.windows.drain() { self.windows.clear();
self.presenters_and_platform_windows.remove(&window_id);
}
self.flush_effects(); self.flush_effects();
} }
@ -782,14 +795,6 @@ impl AppContext {
} }
} }
pub fn is_topmost_window_for_position(&self, window_id: usize, position: Vector2F) -> bool {
self.presenters_and_platform_windows
.get(&window_id)
.map_or(false, |(_, window)| {
window.is_topmost_for_position(position)
})
}
pub fn has_window(&self, window_id: usize) -> bool { pub fn has_window(&self, window_id: usize) -> bool {
self.window_ids() self.window_ids()
.find(|window| window == &window_id) .find(|window| window == &window_id)
@ -800,12 +805,6 @@ impl AppContext {
self.windows.keys().copied() self.windows.keys().copied()
} }
pub fn activate_window(&self, window_id: usize) {
if let Some((_, window)) = self.presenters_and_platform_windows.get(&window_id) {
window.activate()
}
}
pub fn window_is_active(&self, window_id: usize) -> bool { pub fn window_is_active(&self, window_id: usize) -> bool {
self.windows self.windows
.get(&window_id) .get(&window_id)
@ -818,16 +817,6 @@ impl AppContext {
.map_or(false, |window| window.is_fullscreen) .map_or(false, |window| window.is_fullscreen)
} }
pub fn window_bounds(&self, window_id: usize) -> Option<WindowBounds> {
let (_, window) = self.presenters_and_platform_windows.get(&window_id)?;
Some(window.bounds())
}
pub fn window_display_uuid(&self, window_id: usize) -> Option<Uuid> {
let (_, window) = self.presenters_and_platform_windows.get(&window_id)?;
window.screen().display_uuid()
}
pub fn root_view(&self, window_id: usize) -> Option<AnyViewHandle> { pub fn root_view(&self, window_id: usize) -> Option<AnyViewHandle> {
self.windows self.windows
.get(&window_id) .get(&window_id)
@ -891,12 +880,6 @@ impl AppContext {
} }
} }
pub fn debug_elements(&self, window_id: usize) -> Option<crate::json::Value> {
self.presenters_and_platform_windows
.get(&window_id)
.and_then(|(presenter, _)| presenter.borrow().debug_elements(self))
}
pub fn active_labeled_tasks<'a>( pub fn active_labeled_tasks<'a>(
&'a self, &'a self,
) -> impl DoubleEndedIterator<Item = &'static str> + 'a { ) -> impl DoubleEndedIterator<Item = &'static str> + 'a {
@ -966,35 +949,23 @@ impl AppContext {
result result
} }
fn show_character_palette(&self, window_id: usize) { pub fn update_window<T, F: FnOnce(&mut WindowContext) -> T>(
let (_, window) = &self.presenters_and_platform_windows[&window_id]; &mut self,
window.show_character_palette();
}
pub fn minimize_window(&self, window_id: usize) {
let (_, window) = &self.presenters_and_platform_windows[&window_id];
window.minimize();
}
pub fn zoom_window(&self, window_id: usize) {
let (_, window) = &self.presenters_and_platform_windows[&window_id];
window.zoom();
}
pub fn toggle_window_full_screen(&self, window_id: usize) {
let (_, window) = &self.presenters_and_platform_windows[&window_id];
window.toggle_full_screen();
}
pub fn prompt(
&self,
window_id: usize, window_id: usize,
level: PromptLevel, callback: F,
msg: &str, ) -> Option<T> {
answers: &[&str], self.update(|app_context| {
) -> oneshot::Receiver<usize> { let mut window = app_context.windows.remove(&window_id)?;
let (_, window) = &self.presenters_and_platform_windows[&window_id]; let mut window_context = WindowContext {
window.prompt(level, msg, answers) app_context,
window: &mut window,
window_id,
};
let result = callback(&mut window_context);
app_context.windows.insert(window_id, window);
Some(result)
})
} }
pub fn prompt_for_paths( pub fn prompt_for_paths(
@ -1560,54 +1531,6 @@ impl AppContext {
false false
} }
pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: &Keystroke) -> bool {
if let Some(focused_view_id) = self.focused_view_id(window_id) {
let dispatch_path = self
.ancestors(window_id, focused_view_id)
.filter_map(|view_id| {
self.views
.get(&(window_id, view_id))
.map(|view| (view_id, view.keymap_context(self)))
})
.collect();
let match_result = self
.keystroke_matcher
.push_keystroke(keystroke.clone(), dispatch_path);
let mut handled_by = None;
let keystroke_handled = match &match_result {
MatchResult::None => false,
MatchResult::Pending => true,
MatchResult::Matches(matches) => {
for (view_id, action) in matches {
if self.handle_dispatch_action_from_effect(
window_id,
Some(*view_id),
action.as_ref(),
) {
self.keystroke_matcher.clear_pending();
handled_by = Some(action.boxed_clone());
break;
}
}
handled_by.is_some()
}
};
self.keystroke(
window_id,
keystroke.clone(),
handled_by,
match_result.clone(),
);
keystroke_handled
} else {
self.keystroke(window_id, keystroke.clone(), None, MatchResult::None);
false
}
}
pub fn default_global<T: 'static + Default>(&mut self) -> &T { pub fn default_global<T: 'static + Default>(&mut self) -> &T {
let type_id = TypeId::of::<T>(); let type_id = TypeId::of::<T>();
self.update(|this| { self.update(|this| {
@ -1696,6 +1619,16 @@ impl AppContext {
let root_view = this let root_view = this
.build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
.unwrap(); .unwrap();
let platform_window =
this.platform
.open_window(window_id, window_options, this.foreground.clone());
let presenter = self.build_presenter(
window_id,
platform_window.titlebar_height(),
platform_window.appearance(),
);
this.register_platform_window(window_id, &mut presenter, platform_window.as_mut());
this.windows.insert( this.windows.insert(
window_id, window_id,
Window { Window {
@ -1704,15 +1637,12 @@ impl AppContext {
is_active: false, is_active: false,
invalidation: None, invalidation: None,
is_fullscreen: false, is_fullscreen: false,
platform_window,
presenter,
}, },
); );
root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
let window =
this.platform
.open_window(window_id, window_options, this.foreground.clone());
this.register_platform_window(window_id, window);
(window_id, root_view) (window_id, root_view)
}) })
} }
@ -1727,6 +1657,15 @@ impl AppContext {
let root_view = this let root_view = this
.build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx))) .build_and_insert_view(window_id, ParentId::Root, |cx| Some(build_root_view(cx)))
.unwrap(); .unwrap();
let mut platform_window = this.platform.add_status_item();
let mut presenter = self.build_presenter(
window_id,
platform_window.titlebar_height(),
platform_window.appearance(),
);
this.register_platform_window(window_id, &mut presenter, platform_window.as_mut());
let focused_view_id = root_view.id(); let focused_view_id = root_view.id();
this.windows.insert( this.windows.insert(
window_id, window_id,
@ -1736,13 +1675,12 @@ impl AppContext {
is_active: false, is_active: false,
invalidation: None, invalidation: None,
is_fullscreen: false, is_fullscreen: false,
platform_window,
presenter,
}, },
); );
root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx)); root_view.update(this, |view, cx| view.focus_in(cx.handle().into_any(), cx));
let status_item = this.platform.add_status_item();
this.register_platform_window(window_id, status_item);
(window_id, root_view) (window_id, root_view)
}) })
} }
@ -1754,89 +1692,79 @@ impl AppContext {
fn register_platform_window( fn register_platform_window(
&mut self, &mut self,
window_id: usize, window_id: usize,
mut window: Box<dyn platform::Window>, presenter: &mut Presenter,
platform_window: &mut dyn platform::Window,
) { ) {
let presenter = Rc::new(RefCell::new(self.build_presenter(
window_id,
window.titlebar_height(),
window.appearance(),
)));
{ {
let mut app = self.upgrade(); let mut app = self.upgrade();
let presenter = Rc::downgrade(&presenter);
window.on_event(Box::new(move |event| { platform_window.on_event(Box::new(move |event| {
app.update(|cx| { app.update_window(window_id, |cx| {
if let Some(presenter) = presenter.upgrade() { if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event {
if let Event::KeyDown(KeyDownEvent { keystroke, .. }) = &event { if cx.dispatch_keystroke(keystroke) {
if cx.dispatch_keystroke(window_id, keystroke) { return true;
return true;
}
} }
presenter.borrow_mut().dispatch_event(event, false, cx)
} else {
false
} }
cx.dispatch_event(event, false)
}) })
.unwrap_or(false)
})); }));
} }
{ {
let mut app = self.upgrade(); let mut app = self.upgrade();
window.on_active_status_change(Box::new(move |is_active| { platform_window.on_active_status_change(Box::new(move |is_active| {
app.update(|cx| cx.window_changed_active_status(window_id, is_active)) app.update(|cx| cx.window_changed_active_status(window_id, is_active))
})); }));
} }
{ {
let mut app = self.upgrade(); let mut app = self.upgrade();
window.on_resize(Box::new(move || { platform_window.on_resize(Box::new(move || {
app.update(|cx| cx.window_was_resized(window_id)) app.update(|cx| cx.window_was_resized(window_id))
})); }));
} }
{ {
let mut app = self.upgrade(); let mut app = self.upgrade();
window.on_moved(Box::new(move || { platform_window.on_moved(Box::new(move || {
app.update(|cx| cx.window_was_moved(window_id)) app.update(|cx| cx.window_was_moved(window_id))
})); }));
} }
{ {
let mut app = self.upgrade(); let mut app = self.upgrade();
window.on_fullscreen(Box::new(move |is_fullscreen| { platform_window.on_fullscreen(Box::new(move |is_fullscreen| {
app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen)) app.update(|cx| cx.window_was_fullscreen_changed(window_id, is_fullscreen))
})); }));
} }
{ {
let mut app = self.upgrade(); let mut app = self.upgrade();
window.on_close(Box::new(move || { platform_window.on_close(Box::new(move || {
app.update(|cx| cx.remove_window(window_id)); app.update(|cx| cx.remove_window(window_id));
})); }));
} }
{ {
let mut app = self.upgrade(); let mut app = self.upgrade();
window.on_appearance_changed(Box::new(move || app.update(|cx| cx.refresh_windows()))); platform_window
.on_appearance_changed(Box::new(move || app.update(|cx| cx.refresh_windows())));
} }
window.set_input_handler(Box::new(WindowInputHandler { platform_window.set_input_handler(Box::new(WindowInputHandler {
app: self.upgrade().0, app: self.upgrade().0,
window_id, window_id,
})); }));
let scene = presenter.borrow_mut().build_scene( let scene = presenter.build_scene(
window.content_size(), platform_window.content_size(),
window.scale_factor(), platform_window.scale_factor(),
false, false,
self, self,
); );
window.present_scene(scene); platform_window.present_scene(scene);
self.presenters_and_platform_windows
.insert(window_id, (presenter.clone(), window));
} }
pub fn replace_root_view<T, F>(&mut self, window_id: usize, build_root_view: F) -> ViewHandle<T> pub fn replace_root_view<T, F>(&mut self, window_id: usize, build_root_view: F) -> ViewHandle<T>
@ -1857,7 +1785,6 @@ impl AppContext {
pub fn remove_window(&mut self, window_id: usize) { pub fn remove_window(&mut self, window_id: usize) {
self.windows.remove(&window_id); self.windows.remove(&window_id);
self.presenters_and_platform_windows.remove(&window_id);
self.flush_effects(); self.flush_effects();
} }
@ -2217,30 +2144,20 @@ impl AppContext {
} }
fn update_windows(&mut self) { fn update_windows(&mut self) {
let mut invalidations: HashMap<_, _> = Default::default();
for (window_id, window) in &mut self.windows { for (window_id, window) in &mut self.windows {
if let Some(invalidation) = window.invalidation.take() { if let Some(mut invalidation) = window.invalidation.take() {
invalidations.insert(*window_id, invalidation); window.presenter.invalidate(
} &mut invalidation,
} window.platform_window.appearance(),
self,
for (window_id, mut invalidation) in invalidations { );
if let Some((presenter, mut window)) = let scene = window.presenter.build_scene(
self.presenters_and_platform_windows.remove(&window_id) window.platform_window.content_size(),
{ window.platform_window.scale_factor(),
{ false,
let mut presenter = presenter.borrow_mut(); self,
presenter.invalidate(&mut invalidation, window.appearance(), self); );
let scene = presenter.build_scene( window.platform_window.present_scene(scene);
window.content_size(),
window.scale_factor(),
false,
self,
);
window.present_scene(scene);
}
self.presenters_and_platform_windows
.insert(window_id, (presenter, window));
} }
} }
} }
@ -2306,20 +2223,21 @@ impl AppContext {
} }
fn perform_window_refresh(&mut self) { fn perform_window_refresh(&mut self) {
let mut presenters = mem::take(&mut self.presenters_and_platform_windows); for window in self.windows.values_mut() {
for (window_id, (presenter, window)) in &mut presenters { let mut invalidation = window.invalidation.take().unwrap_or_default();
let mut invalidation = self.windows.get_mut(window_id).unwrap().invalidation.take(); window.presenter.invalidate(
let mut presenter = presenter.borrow_mut(); &mut invalidation,
presenter.refresh( window.platform_window.appearance(),
invalidation.as_mut().unwrap_or(&mut Default::default()),
window.appearance(),
self, self,
); );
let scene = let scene = window.presenter.build_scene(
presenter.build_scene(window.content_size(), window.scale_factor(), true, self); window.platform_window.content_size(),
window.present_scene(scene); window.platform_window.scale_factor(),
true,
self,
);
window.platform_window.present_scene(scene);
} }
self.presenters_and_platform_windows = presenters;
} }
fn emit_global_event(&mut self, payload: Box<dyn Any>) { fn emit_global_event(&mut self, payload: Box<dyn Any>) {
@ -2365,33 +2283,19 @@ impl AppContext {
} }
fn handle_fullscreen_effect(&mut self, window_id: usize, is_fullscreen: bool) { fn handle_fullscreen_effect(&mut self, window_id: usize, is_fullscreen: bool) {
//Short circuit evaluation if we're already g2g self.update_window(window_id, |cx| {
if self cx.window.is_fullscreen = is_fullscreen;
.windows
.get(&window_id)
.map(|w| w.is_fullscreen == is_fullscreen)
.unwrap_or(false)
{
return;
}
self.update(|this| { let mut fullscreen_observations = cx.window_fullscreen_observations.clone();
let window = this.windows.get_mut(&window_id)?; fullscreen_observations.emit(window_id, cx, |callback, this| {
window.is_fullscreen = is_fullscreen;
let mut fullscreen_observations = this.window_fullscreen_observations.clone();
fullscreen_observations.emit(window_id, this, |callback, this| {
callback(is_fullscreen, this) callback(is_fullscreen, this)
}); });
if let Some((uuid, bounds)) = this if let Some(uuid) = cx.window_display_uuid() {
.window_display_uuid(window_id) let bounds = cx.window_bounds();
.zip(this.window_bounds(window_id)) let mut bounds_observations = cx.window_bounds_observations.clone();
{ bounds_observations
let mut bounds_observations = this.window_bounds_observations.clone(); .emit(window_id, cx, |callback, this| callback(bounds, uuid, this));
bounds_observations.emit(window_id, this, |callback, this| {
callback(bounds, uuid, this)
});
} }
Some(()) Some(())
@ -2563,23 +2467,27 @@ impl AppContext {
mut callback: WindowShouldCloseSubscriptionCallback, mut callback: WindowShouldCloseSubscriptionCallback,
) { ) {
let mut app = self.upgrade(); let mut app = self.upgrade();
if let Some((_, window)) = self.presenters_and_platform_windows.get_mut(&window_id) { if let Some(window) = self.windows.get_mut(&window_id) {
window.on_should_close(Box::new(move || app.update(|cx| callback(cx)))) window
.platform_window
.on_should_close(Box::new(move || app.update(|cx| callback(cx))))
} }
} }
fn handle_window_moved(&mut self, window_id: usize) { fn handle_window_moved(&mut self, window_id: usize) {
if let Some((display, bounds)) = self self.update_window(window_id, |cx| {
.window_display_uuid(window_id) if let Some(display) = cx.window_display_uuid() {
.zip(self.window_bounds(window_id)) let bounds = cx.window_bounds();
{ cx.window_bounds_observations.clone().emit(
self.window_bounds_observations window_id,
.clone() self,
.emit(window_id, self, move |callback, this| { move |callback, this| {
callback(bounds, display, this); callback(bounds, display, this);
true true
}); },
} );
}
});
} }
fn handle_active_labeled_tasks_changed_effect(&mut self) { fn handle_active_labeled_tasks_changed_effect(&mut self) {
@ -2806,6 +2714,8 @@ pub struct Window {
is_active: bool, is_active: bool,
is_fullscreen: bool, is_fullscreen: bool,
invalidation: Option<WindowInvalidation>, invalidation: Option<WindowInvalidation>,
presenter: Presenter,
platform_window: Box<dyn platform::Window>,
} }
#[derive(Default, Clone)] #[derive(Default, Clone)]
@ -3584,6 +3494,138 @@ impl<M> DerefMut for ModelContext<'_, M> {
} }
} }
pub struct WindowContext<'a: 'b, 'b> {
app_context: &'a mut AppContext,
window: &'b mut Window,
window_id: usize,
}
impl Deref for WindowContext<'_, '_> {
type Target = AppContext;
fn deref(&self) -> &Self::Target {
self.app_context
}
}
impl DerefMut for WindowContext<'_, '_> {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.app_context
}
}
impl WindowContext<'_, '_> {
pub fn dispatch_keystroke(&mut self, keystroke: &Keystroke) -> bool {
let window_id = self.window_id;
if let Some(focused_view_id) = self.focused_view_id(window_id) {
let dispatch_path = self
.ancestors(window_id, focused_view_id)
.filter_map(|view_id| {
self.views
.get(&(window_id, view_id))
.map(|view| (view_id, view.keymap_context(self)))
})
.collect();
let match_result = self
.keystroke_matcher
.push_keystroke(keystroke.clone(), dispatch_path);
let mut handled_by = None;
let keystroke_handled = match &match_result {
MatchResult::None => false,
MatchResult::Pending => true,
MatchResult::Matches(matches) => {
for (view_id, action) in matches {
if self.handle_dispatch_action_from_effect(
window_id,
Some(*view_id),
action.as_ref(),
) {
self.keystroke_matcher.clear_pending();
handled_by = Some(action.boxed_clone());
break;
}
}
handled_by.is_some()
}
};
self.keystroke(
window_id,
keystroke.clone(),
handled_by,
match_result.clone(),
);
keystroke_handled
} else {
self.keystroke(window_id, keystroke.clone(), None, MatchResult::None);
false
}
}
pub fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool {
self.window
.presenter
.dispatch_event(event, event_reused, self)
}
pub fn set_window_title(&mut self, title: &str) {
self.window.platform_window.set_title(title);
}
pub fn set_window_edited(&mut self, edited: bool) {
self.window.platform_window.set_edited(edited);
}
pub fn is_topmost_window_for_position(&self, position: Vector2F) -> bool {
self.window
.platform_window
.is_topmost_for_position(position)
}
pub fn activate_window(&self) {
self.window.platform_window.activate();
}
pub fn window_bounds(&self) -> WindowBounds {
self.window.platform_window.bounds()
}
pub fn window_display_uuid(&self) -> Option<Uuid> {
self.window.platform_window.screen().display_uuid()
}
pub fn debug_elements(&self) -> Option<crate::json::Value> {
self.window.presenter.debug_elements(self)
}
fn show_character_palette(&self) {
self.window.platform_window.show_character_palette();
}
pub fn minimize_window(&self) {
self.window.platform_window.minimize();
}
pub fn zoom_window(&self) {
self.window.platform_window.zoom();
}
pub fn toggle_window_full_screen(&self) {
self.window.platform_window.toggle_full_screen();
}
pub fn prompt(
&self,
level: PromptLevel,
msg: &str,
answers: &[&str],
) -> oneshot::Receiver<usize> {
self.window.platform_window.prompt(level, msg, answers)
}
}
pub struct ViewContext<'a, T: ?Sized> { pub struct ViewContext<'a, T: ?Sized> {
app: &'a mut AppContext, app: &'a mut AppContext,
window_id: usize, window_id: usize,
@ -3633,31 +3675,6 @@ impl<'a, T: View> ViewContext<'a, T> {
self.app.platform() self.app.platform()
} }
pub fn show_character_palette(&self) {
self.app.show_character_palette(self.window_id);
}
pub fn minimize_window(&self) {
self.app.minimize_window(self.window_id)
}
pub fn zoom_window(&self) {
self.app.zoom_window(self.window_id)
}
pub fn toggle_full_screen(&self) {
self.app.toggle_window_full_screen(self.window_id)
}
pub fn prompt(
&self,
level: PromptLevel,
msg: &str,
answers: &[&str],
) -> oneshot::Receiver<usize> {
self.app.prompt(self.window_id, level, msg, answers)
}
pub fn prompt_for_paths( pub fn prompt_for_paths(
&self, &self,
options: PathPromptOptions, options: PathPromptOptions,
@ -3673,10 +3690,6 @@ impl<'a, T: View> ViewContext<'a, T> {
self.app.reveal_path(path) self.app.reveal_path(path)
} }
pub fn debug_elements(&self) -> crate::json::Value {
self.app.debug_elements(self.window_id).unwrap()
}
pub fn focus(&mut self, handle: &AnyViewHandle) { pub fn focus(&mut self, handle: &AnyViewHandle) {
self.app.focus(handle.window_id, Some(handle.view_id)); self.app.focus(handle.window_id, Some(handle.view_id));
} }
@ -3703,20 +3716,6 @@ impl<'a, T: View> ViewContext<'a, T> {
self.app.focus(self.window_id, None); self.app.focus(self.window_id, None);
} }
pub fn set_window_title(&mut self, title: &str) {
let window_id = self.window_id();
if let Some((_, window)) = self.presenters_and_platform_windows.get_mut(&window_id) {
window.set_title(title);
}
}
pub fn set_window_edited(&mut self, edited: bool) {
let window_id = self.window_id();
if let Some((_, window)) = self.presenters_and_platform_windows.get_mut(&window_id) {
window.set_edited(edited);
}
}
pub fn on_window_should_close<F>(&mut self, mut callback: F) pub fn on_window_should_close<F>(&mut self, mut callback: F)
where where
F: 'static + FnMut(&mut T, &mut ViewContext<T>) -> bool, F: 'static + FnMut(&mut T, &mut ViewContext<T>) -> bool,
@ -5492,19 +5491,20 @@ mod tests {
let (window_id, _) = cx.add_window(Default::default(), |_| View { let (window_id, _) = cx.add_window(Default::default(), |_| View {
mouse_down_count: mouse_down_count.clone(), mouse_down_count: mouse_down_count.clone(),
}); });
let presenter = cx.presenters_and_platform_windows[&window_id].0.clone();
// Ensure window's root element is in a valid lifecycle state. cx.update_window(window_id, |cx| {
presenter.borrow_mut().dispatch_event( // Ensure window's root element is in a valid lifecycle state.
Event::MouseDown(MouseButtonEvent { cx.dispatch_event(
position: Default::default(), Event::MouseDown(MouseButtonEvent {
button: MouseButton::Left, position: Default::default(),
modifiers: Default::default(), button: MouseButton::Left,
click_count: 1, modifiers: Default::default(),
}), click_count: 1,
false, }),
cx, false,
); );
assert_eq!(mouse_down_count.load(SeqCst), 1); assert_eq!(mouse_down_count.load(SeqCst), 1);
});
} }
#[crate::test(self)] #[crate::test(self)]
@ -6553,19 +6553,28 @@ mod tests {
} }
}); });
cx.dispatch_keystroke(window_id, &Keystroke::parse("a").unwrap()); cx.update_window(window_id, |cx| {
cx.dispatch_keystroke(&Keystroke::parse("a").unwrap())
});
assert_eq!(&*actions.borrow(), &["2 a"]); assert_eq!(&*actions.borrow(), &["2 a"]);
actions.borrow_mut().clear(); actions.borrow_mut().clear();
cx.dispatch_keystroke(window_id, &Keystroke::parse("b").unwrap()); cx.update_window(window_id, |cx| {
cx.dispatch_keystroke(&Keystroke::parse("b").unwrap());
});
assert_eq!(&*actions.borrow(), &["3 b", "2 b", "1 b", "global b"]); assert_eq!(&*actions.borrow(), &["3 b", "2 b", "1 b", "global b"]);
actions.borrow_mut().clear(); actions.borrow_mut().clear();
cx.dispatch_keystroke(window_id, &Keystroke::parse("c").unwrap()); cx.update_window(window_id, |cx| {
cx.dispatch_keystroke(&Keystroke::parse("c").unwrap());
});
assert_eq!(&*actions.borrow(), &["3 c"]); assert_eq!(&*actions.borrow(), &["3 c"]);
actions.borrow_mut().clear(); actions.borrow_mut().clear();
cx.dispatch_keystroke(window_id, &Keystroke::parse("d").unwrap()); cx.update_window(window_id, |cx| {
cx.dispatch_keystroke(&Keystroke::parse("d").unwrap());
});
assert_eq!(&*actions.borrow(), &["2 d"]); assert_eq!(&*actions.borrow(), &["2 d"]);
actions.borrow_mut().clear(); actions.borrow_mut().clear();
} }
@ -6836,46 +6845,54 @@ mod tests {
} }
let (window_id, root_view) = cx.add_window(Default::default(), |_| View(0)); let (window_id, root_view) = cx.add_window(Default::default(), |_| View(0));
let presenter = cx.presenters_and_platform_windows[&window_id].0.clone(); cx.update_window(window_id, |cx| {
assert_eq!(
assert_eq!( cx.window.presenter.rendered_views[&root_view.id()].name(),
presenter.borrow().rendered_views[&root_view.id()].name(), Some("render count: 0")
Some("render count: 0") );
); });
let view = cx.add_view(&root_view, |cx| { let view = cx.add_view(&root_view, |cx| {
cx.refresh_windows(); cx.refresh_windows();
View(0) View(0)
}); });
assert_eq!( cx.update_window(window_id, |cx| {
presenter.borrow().rendered_views[&root_view.id()].name(), assert_eq!(
Some("render count: 1") cx.window.presenter.rendered_views[&root_view.id()].name(),
); Some("render count: 1")
assert_eq!( );
presenter.borrow().rendered_views[&view.id()].name(), assert_eq!(
Some("render count: 0") cx.window.presenter.rendered_views[&view.id()].name(),
); Some("render count: 0")
);
});
cx.update(|cx| cx.refresh_windows()); cx.update(|cx| cx.refresh_windows());
assert_eq!(
presenter.borrow().rendered_views[&root_view.id()].name(), cx.update_window(window_id, |cx| {
Some("render count: 2") assert_eq!(
); cx.window.presenter.rendered_views[&root_view.id()].name(),
assert_eq!( Some("render count: 2")
presenter.borrow().rendered_views[&view.id()].name(), );
Some("render count: 1") assert_eq!(
); cx.window.presenter.rendered_views[&view.id()].name(),
Some("render count: 1")
);
});
cx.update(|cx| { cx.update(|cx| {
cx.refresh_windows(); cx.refresh_windows();
drop(view); drop(view);
}); });
assert_eq!(
presenter.borrow().rendered_views[&root_view.id()].name(), cx.update_window(window_id, |cx| {
Some("render count: 3") assert_eq!(
); cx.window.presenter.rendered_views[&root_view.id()].name(),
assert_eq!(presenter.borrow().rendered_views.len(), 1); Some("render count: 3")
);
assert_eq!(cx.window.presenter.rendered_views.len(), 1);
});
} }
#[crate::test(self)] #[crate::test(self)]

View file

@ -84,31 +84,28 @@ impl TestAppContext {
} }
pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: Keystroke, is_held: bool) { pub fn dispatch_keystroke(&mut self, window_id: usize, keystroke: Keystroke, is_held: bool) {
let handled = self.cx.borrow_mut().update(|cx| { let handled = self
let presenter = cx .cx
.presenters_and_platform_windows .borrow_mut()
.get(&window_id) .update_window(window_id, |cx| {
.unwrap() if cx.dispatch_keystroke(&keystroke) {
.0 return true;
.clone(); }
if cx.dispatch_keystroke(window_id, &keystroke) { if cx.window.presenter.dispatch_event(
return true; Event::KeyDown(KeyDownEvent {
} keystroke: keystroke.clone(),
is_held,
}),
false,
cx,
) {
return true;
}
if presenter.borrow_mut().dispatch_event( false
Event::KeyDown(KeyDownEvent { })
keystroke: keystroke.clone(), .unwrap_or(false);
is_held,
}),
false,
cx,
) {
return true;
}
false
});
if !handled && !keystroke.cmd && !keystroke.ctrl { if !handled && !keystroke.cmd && !keystroke.ctrl {
WindowInputHandler { WindowInputHandler {
@ -244,7 +241,7 @@ impl TestAppContext {
use postage::prelude::Sink as _; use postage::prelude::Sink as _;
let mut done_tx = self let mut done_tx = self
.window_mut(window_id) .platform_window_mut(window_id)
.pending_prompts .pending_prompts
.borrow_mut() .borrow_mut()
.pop_front() .pop_front()
@ -253,20 +250,23 @@ impl TestAppContext {
} }
pub fn has_pending_prompt(&self, window_id: usize) -> bool { pub fn has_pending_prompt(&self, window_id: usize) -> bool {
let window = self.window_mut(window_id); let window = self.platform_window_mut(window_id);
let prompts = window.pending_prompts.borrow_mut(); let prompts = window.pending_prompts.borrow_mut();
!prompts.is_empty() !prompts.is_empty()
} }
pub fn current_window_title(&self, window_id: usize) -> Option<String> { pub fn current_window_title(&self, window_id: usize) -> Option<String> {
self.window_mut(window_id).title.clone() self.platform_window_mut(window_id).title.clone()
} }
pub fn simulate_window_close(&self, window_id: usize) -> bool { pub fn simulate_window_close(&self, window_id: usize) -> bool {
let handler = self.window_mut(window_id).should_close_handler.take(); let handler = self
.platform_window_mut(window_id)
.should_close_handler
.take();
if let Some(mut handler) = handler { if let Some(mut handler) = handler {
let should_close = handler(); let should_close = handler();
self.window_mut(window_id).should_close_handler = Some(handler); self.platform_window_mut(window_id).should_close_handler = Some(handler);
should_close should_close
} else { } else {
false false
@ -274,47 +274,34 @@ impl TestAppContext {
} }
pub fn simulate_window_resize(&self, window_id: usize, size: Vector2F) { pub fn simulate_window_resize(&self, window_id: usize, size: Vector2F) {
let mut window = self.window_mut(window_id); let mut window = self.platform_window_mut(window_id);
window.size = size; window.size = size;
let mut handlers = mem::take(&mut window.resize_handlers); let mut handlers = mem::take(&mut window.resize_handlers);
drop(window); drop(window);
for handler in &mut handlers { for handler in &mut handlers {
handler(); handler();
} }
self.window_mut(window_id).resize_handlers = handlers; self.platform_window_mut(window_id).resize_handlers = handlers;
} }
pub fn simulate_window_activation(&self, to_activate: Option<usize>) { pub fn simulate_window_activation(&self, to_activate: Option<usize>) {
let mut handlers = BTreeMap::new(); self.cx.borrow_mut().update(|cx| {
{ for window_id in cx
let mut cx = self.cx.borrow_mut(); .windows
for (window_id, (_, window)) in &mut cx.presenters_and_platform_windows { .keys()
let window = window .filter(|window_id| Some(**window_id) != to_activate)
.as_any_mut() {
.downcast_mut::<platform::test::Window>() cx.window_changed_active_status(*window_id, false)
.unwrap();
handlers.insert(
*window_id,
mem::take(&mut window.active_status_change_handlers),
);
}
};
let mut handlers = handlers.into_iter().collect::<Vec<_>>();
handlers.sort_unstable_by_key(|(window_id, _)| Some(*window_id) == to_activate);
for (window_id, mut window_handlers) in handlers {
for window_handler in &mut window_handlers {
window_handler(Some(window_id) == to_activate);
} }
self.window_mut(window_id) if let Some(to_activate) = to_activate {
.active_status_change_handlers cx.window_changed_active_status(to_activate, true)
.extend(window_handlers); }
} });
} }
pub fn is_window_edited(&self, window_id: usize) -> bool { pub fn is_window_edited(&self, window_id: usize) -> bool {
self.window_mut(window_id).edited self.platform_window_mut(window_id).edited
} }
pub fn leak_detector(&self) -> Arc<Mutex<LeakDetector>> { pub fn leak_detector(&self) -> Arc<Mutex<LeakDetector>> {
@ -337,13 +324,11 @@ impl TestAppContext {
self.assert_dropped(weak); self.assert_dropped(weak);
} }
fn window_mut(&self, window_id: usize) -> std::cell::RefMut<platform::test::Window> { fn platform_window_mut(&self, window_id: usize) -> std::cell::RefMut<platform::test::Window> {
std::cell::RefMut::map(self.cx.borrow_mut(), |state| { std::cell::RefMut::map(self.cx.borrow_mut(), |state| {
let (_, window) = state let window = state.windows.get_mut(&window_id).unwrap();
.presenters_and_platform_windows
.get_mut(&window_id)
.unwrap();
let test_window = window let test_window = window
.platform_window
.as_any_mut() .as_any_mut()
.downcast_mut::<platform::test::Window>() .downcast_mut::<platform::test::Window>()
.unwrap(); .unwrap();

View file

@ -91,8 +91,7 @@ impl InputHandler for WindowInputHandler {
fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF> { fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
let app = self.app.borrow(); let app = self.app.borrow();
let (presenter, _) = app.presenters_and_platform_windows.get(&self.window_id)?; let window = app.windows.get(&self.window_id)?;
let presenter = presenter.borrow(); window.presenter.rect_for_text_range(range_utf16, &app)
presenter.rect_for_text_range(range_utf16, &app)
} }
} }

View file

@ -315,9 +315,10 @@ impl Presenter {
} }
} }
if cx.is_topmost_window_for_position(self.window_id, *position) { // TODO!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
cx.platform().set_cursor_style(style_to_assign); // if cx.is_topmost_window_for_position(self.window_id, *position) {
} // cx.platform().set_cursor_style(style_to_assign);
// }
if !event_reused { if !event_reused {
if pressed_button.is_some() { if pressed_button.is_some() {