Merge branch 'main' into picker

This commit is contained in:
Max Brunsfeld 2023-11-07 16:57:47 -08:00
commit bdec1c8202
7 changed files with 672 additions and 540 deletions

File diff suppressed because it is too large Load diff

View file

@ -2622,6 +2622,10 @@ impl Element<Editor> for EditorElement {
} }
}); });
if editor.focus_handle.is_focused(cx) {
cx.handle_text_input();
}
cx.with_content_mask(ContentMask { bounds }, |cx| { cx.with_content_mask(ContentMask { bounds }, |cx| {
let gutter_bounds = Bounds { let gutter_bounds = Bounds {
origin: bounds.origin, origin: bounds.origin,

View file

@ -154,7 +154,7 @@ type ReleaseListener = Box<dyn FnOnce(&mut dyn Any, &mut AppContext) + 'static>;
// } // }
pub struct AppContext { pub struct AppContext {
this: Weak<AppCell>, pub(crate) this: Weak<AppCell>,
pub(crate) platform: Rc<dyn Platform>, pub(crate) platform: Rc<dyn Platform>,
app_metadata: AppMetadata, app_metadata: AppMetadata,
text_system: Arc<TextSystem>, text_system: Arc<TextSystem>,

View file

@ -24,6 +24,7 @@ mod text_system;
mod util; mod util;
mod view; mod view;
mod window; mod window;
mod window_input_handler;
mod private { mod private {
/// A mechanism for restricting implementations of a trait to only those in GPUI. /// A mechanism for restricting implementations of a trait to only those in GPUI.
@ -64,6 +65,7 @@ pub use text_system::*;
pub use util::arc_cow::ArcCow; pub use util::arc_cow::ArcCow;
pub use view::*; pub use view::*;
pub use window::*; pub use window::*;
pub use window_input_handler::*;
use derive_more::{Deref, DerefMut}; use derive_more::{Deref, DerefMut};
use std::{ use std::{

View file

@ -2,13 +2,14 @@ use crate::{
px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext, AsyncWindowContext, AvailableSpace,
Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId, Bounds, BoxShadow, Context, Corners, CursorStyle, DevicePixels, DispatchContext, DisplayId,
Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId, Edges, Effect, Entity, EntityId, EventEmitter, FileDropEvent, FocusEvent, FontId,
GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyListener, KeyMatch, GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, InputHandler, IsZero, KeyListener,
KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton, KeyMatch, KeyMatcher, Keystroke, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas,
PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel,
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Quad, Render, RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels,
Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet, Subscription,
VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext, WeakView,
WindowBounds, WindowInputHandler, WindowOptions, SUBPIXEL_VARIANTS,
}; };
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use collections::HashMap; use collections::HashMap;
@ -191,6 +192,7 @@ pub struct Window {
default_prevented: bool, default_prevented: bool,
mouse_position: Point<Pixels>, mouse_position: Point<Pixels>,
requested_cursor_style: Option<CursorStyle>, requested_cursor_style: Option<CursorStyle>,
requested_input_handler: Option<Box<dyn PlatformInputHandler>>,
scale_factor: f32, scale_factor: f32,
bounds: WindowBounds, bounds: WindowBounds,
bounds_observers: SubscriberSet<(), AnyObserver>, bounds_observers: SubscriberSet<(), AnyObserver>,
@ -253,7 +255,7 @@ impl Window {
handle handle
.update(&mut cx, |_, cx| cx.dispatch_event(event)) .update(&mut cx, |_, cx| cx.dispatch_event(event))
.log_err() .log_err()
.unwrap_or(true) .unwrap_or(false)
}) })
}); });
@ -285,6 +287,7 @@ impl Window {
default_prevented: true, default_prevented: true,
mouse_position, mouse_position,
requested_cursor_style: None, requested_cursor_style: None,
requested_input_handler: None,
scale_factor, scale_factor,
bounds, bounds,
bounds_observers: SubscriberSet::new(), bounds_observers: SubscriberSet::new(),
@ -1016,6 +1019,9 @@ impl<'a> WindowContext<'a> {
.take() .take()
.unwrap_or(CursorStyle::Arrow); .unwrap_or(CursorStyle::Arrow);
self.platform.set_cursor_style(cursor_style); self.platform.set_cursor_style(cursor_style);
if let Some(handler) = self.window.requested_input_handler.take() {
self.window.platform_window.set_input_handler(handler);
}
self.window.dirty = false; self.window.dirty = false;
} }
@ -1160,6 +1166,7 @@ impl<'a> WindowContext<'a> {
.insert(any_mouse_event.type_id(), handlers); .insert(any_mouse_event.type_id(), handlers);
} }
} else if let Some(any_key_event) = event.keyboard_event() { } else if let Some(any_key_event) = event.keyboard_event() {
let mut did_handle_action = false;
let key_dispatch_stack = mem::take(&mut self.window.key_dispatch_stack); let key_dispatch_stack = mem::take(&mut self.window.key_dispatch_stack);
let key_event_type = any_key_event.type_id(); let key_event_type = any_key_event.type_id();
let mut context_stack = SmallVec::<[&DispatchContext; 16]>::new(); let mut context_stack = SmallVec::<[&DispatchContext; 16]>::new();
@ -1180,6 +1187,7 @@ impl<'a> WindowContext<'a> {
self.dispatch_action(action, &key_dispatch_stack[..ix]); self.dispatch_action(action, &key_dispatch_stack[..ix]);
} }
if !self.app.propagate_event { if !self.app.propagate_event {
did_handle_action = true;
break; break;
} }
} }
@ -1208,6 +1216,7 @@ impl<'a> WindowContext<'a> {
} }
if !self.app.propagate_event { if !self.app.propagate_event {
did_handle_action = true;
break; break;
} }
} }
@ -1221,6 +1230,7 @@ impl<'a> WindowContext<'a> {
drop(context_stack); drop(context_stack);
self.window.key_dispatch_stack = key_dispatch_stack; self.window.key_dispatch_stack = key_dispatch_stack;
return did_handle_action;
} }
true true
@ -2003,6 +2013,19 @@ impl<'a, V: 'static> ViewContext<'a, V> {
} }
} }
impl<V> ViewContext<'_, V>
where
V: InputHandler + 'static,
{
pub fn handle_text_input(&mut self) {
self.window.requested_input_handler = Some(Box::new(WindowInputHandler {
cx: self.app.this.clone(),
window: self.window_handle(),
handler: self.view().downgrade(),
}));
}
}
impl<V> ViewContext<'_, V> impl<V> ViewContext<'_, V>
where where
V: EventEmitter, V: EventEmitter,

View file

@ -0,0 +1,89 @@
use crate::{AnyWindowHandle, AppCell, Context, PlatformInputHandler, ViewContext, WeakView};
use std::{ops::Range, rc::Weak};
pub struct WindowInputHandler<V>
where
V: InputHandler,
{
pub cx: Weak<AppCell>,
pub window: AnyWindowHandle,
pub handler: WeakView<V>,
}
impl<V: InputHandler + 'static> PlatformInputHandler for WindowInputHandler<V> {
fn selected_text_range(&self) -> Option<std::ops::Range<usize>> {
self.update(|view, cx| view.selected_text_range(cx))
.flatten()
}
fn marked_text_range(&self) -> Option<std::ops::Range<usize>> {
self.update(|view, cx| view.marked_text_range(cx)).flatten()
}
fn text_for_range(&self, range_utf16: std::ops::Range<usize>) -> Option<String> {
self.update(|view, cx| view.text_for_range(range_utf16, cx))
.flatten()
}
fn replace_text_in_range(
&mut self,
replacement_range: Option<std::ops::Range<usize>>,
text: &str,
) {
self.update(|view, cx| view.replace_text_in_range(replacement_range, text, cx));
}
fn replace_and_mark_text_in_range(
&mut self,
range_utf16: Option<std::ops::Range<usize>>,
new_text: &str,
new_selected_range: Option<std::ops::Range<usize>>,
) {
self.update(|view, cx| {
view.replace_and_mark_text_in_range(range_utf16, new_text, new_selected_range, cx)
});
}
fn unmark_text(&mut self) {
self.update(|view, cx| view.unmark_text(cx));
}
fn bounds_for_range(&self, range_utf16: std::ops::Range<usize>) -> Option<crate::Bounds<f32>> {
self.update(|view, cx| view.bounds_for_range(range_utf16, cx))
.flatten()
}
}
impl<V: InputHandler + 'static> WindowInputHandler<V> {
fn update<T>(&self, f: impl FnOnce(&mut V, &mut ViewContext<V>) -> T) -> Option<T> {
let cx = self.cx.upgrade()?;
let mut cx = cx.borrow_mut();
cx.update_window(self.window, |_, cx| self.handler.update(cx, f).ok())
.ok()?
}
}
pub trait InputHandler: Sized {
fn text_for_range(&self, range: Range<usize>, cx: &mut ViewContext<Self>) -> Option<String>;
fn selected_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>;
fn marked_text_range(&self, cx: &mut ViewContext<Self>) -> Option<Range<usize>>;
fn unmark_text(&mut self, cx: &mut ViewContext<Self>);
fn replace_text_in_range(
&mut self,
range: Option<Range<usize>>,
text: &str,
cx: &mut ViewContext<Self>,
);
fn replace_and_mark_text_in_range(
&mut self,
range: Option<Range<usize>>,
new_text: &str,
new_selected_range: Option<Range<usize>>,
cx: &mut ViewContext<Self>,
);
fn bounds_for_range(
&self,
range_utf16: std::ops::Range<usize>,
cx: &mut ViewContext<Self>,
) -> Option<crate::Bounds<f32>>;
}

View file

@ -2694,7 +2694,7 @@ impl Workspace {
.any(|item| item.has_conflict(cx) || item.is_dirty(cx)); .any(|item| item.has_conflict(cx) || item.is_dirty(cx));
if is_edited != self.window_edited { if is_edited != self.window_edited {
self.window_edited = is_edited; self.window_edited = is_edited;
todo!() // todo!()
// cx.set_window_edited(self.window_edited) // cx.set_window_edited(self.window_edited)
} }
} }