Merge branch 'main' into picker
This commit is contained in:
commit
bdec1c8202
7 changed files with 672 additions and 540 deletions
File diff suppressed because it is too large
Load diff
|
@ -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,
|
||||||
|
|
|
@ -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>,
|
||||||
|
|
|
@ -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::{
|
||||||
|
|
|
@ -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,
|
||||||
|
|
89
crates/gpui2/src/window_input_handler.rs
Normal file
89
crates/gpui2/src/window_input_handler.rs
Normal 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>>;
|
||||||
|
}
|
|
@ -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)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue