Call methods on the focused view during input events
This commit is contained in:
parent
1b0e93b153
commit
0b81a4dfae
3 changed files with 281 additions and 38 deletions
|
@ -7,8 +7,8 @@ use crate::{
|
|||
platform::{self, KeyDownEvent, Platform, PromptLevel, WindowOptions},
|
||||
presenter::Presenter,
|
||||
util::post_inc,
|
||||
AssetCache, AssetSource, ClipboardItem, FontCache, MouseRegionId, PathPromptOptions,
|
||||
TextLayoutCache,
|
||||
AssetCache, AssetSource, ClipboardItem, FontCache, InputHandler, MouseRegionId,
|
||||
PathPromptOptions, TextLayoutCache,
|
||||
};
|
||||
pub use action::*;
|
||||
use anyhow::{anyhow, Context, Result};
|
||||
|
@ -28,7 +28,7 @@ use std::{
|
|||
hash::{Hash, Hasher},
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::{Deref, DerefMut},
|
||||
ops::{Deref, DerefMut, Range},
|
||||
path::{Path, PathBuf},
|
||||
pin::Pin,
|
||||
rc::{self, Rc},
|
||||
|
@ -64,6 +64,33 @@ pub trait View: Entity + Sized {
|
|||
fn debug_json(&self, _: &AppContext) -> serde_json::Value {
|
||||
serde_json::Value::Null
|
||||
}
|
||||
|
||||
fn text_for_range(&self, _: Range<usize>, _: &AppContext) -> Option<String> {
|
||||
None
|
||||
}
|
||||
fn selected_text_range(&self, _: &AppContext) -> Option<Range<usize>> {
|
||||
None
|
||||
}
|
||||
fn set_selected_text_range(&mut self, _: Range<usize>, _: &mut ViewContext<Self>) {}
|
||||
fn marked_text_range(&self, _: &AppContext) -> Option<Range<usize>> {
|
||||
None
|
||||
}
|
||||
fn unmark_text(&mut self, _: &mut ViewContext<Self>) {}
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
_: Option<Range<usize>>,
|
||||
_: &str,
|
||||
_: &mut ViewContext<Self>,
|
||||
) {
|
||||
}
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
_: Option<Range<usize>>,
|
||||
_: &str,
|
||||
_: Option<Range<usize>>,
|
||||
_: &mut ViewContext<Self>,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ReadModel {
|
||||
|
@ -154,6 +181,11 @@ pub struct TestAppContext {
|
|||
condition_duration: Option<Duration>,
|
||||
}
|
||||
|
||||
pub struct WindowInputHandler {
|
||||
app: Rc<RefCell<MutableAppContext>>,
|
||||
window_id: usize,
|
||||
}
|
||||
|
||||
impl App {
|
||||
pub fn new(asset_source: impl AssetSource) -> Result<Self> {
|
||||
let platform = platform::current::platform();
|
||||
|
@ -310,6 +342,121 @@ impl App {
|
|||
}
|
||||
}
|
||||
|
||||
impl WindowInputHandler {
|
||||
fn read_focused_view<T, F>(&self, f: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce(&dyn AnyView, &AppContext) -> T,
|
||||
{
|
||||
let app = self.app.borrow();
|
||||
let view_id = app.focused_view_id(self.window_id)?;
|
||||
let view = app.cx.views.get(&(self.window_id, view_id))?;
|
||||
let result = f(view.as_ref(), &app);
|
||||
Some(result)
|
||||
}
|
||||
|
||||
fn update_focused_view<T, F>(&mut self, f: F) -> Option<T>
|
||||
where
|
||||
F: FnOnce(usize, usize, &mut dyn AnyView, &mut MutableAppContext) -> T,
|
||||
{
|
||||
let mut app = self.app.borrow_mut();
|
||||
app.update(|app| {
|
||||
let view_id = app.focused_view_id(self.window_id)?;
|
||||
let mut view = app.cx.views.remove(&(self.window_id, view_id))?;
|
||||
let result = f(self.window_id, view_id, view.as_mut(), &mut *app);
|
||||
app.cx.views.insert((self.window_id, view_id), view);
|
||||
Some(result)
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl InputHandler for WindowInputHandler {
|
||||
fn text_for_range(&self, range: Range<usize>) -> Option<String> {
|
||||
let result = self
|
||||
.read_focused_view(|view, cx| view.text_for_range(range.clone(), cx))
|
||||
.flatten();
|
||||
|
||||
eprintln!("text_for_range({range:?}) -> {result:?}");
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn selected_text_range(&self) -> Option<Range<usize>> {
|
||||
let result = self
|
||||
.read_focused_view(|view, cx| view.selected_text_range(cx))
|
||||
.flatten();
|
||||
|
||||
eprintln!("selected_text_range() -> {result:?}");
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn set_selected_text_range(&mut self, range: Range<usize>) {
|
||||
eprintln!("set_selected_text_range({range:?})");
|
||||
|
||||
self.update_focused_view(|window_id, view_id, view, cx| {
|
||||
view.set_selected_text_range(range, cx, window_id, view_id);
|
||||
});
|
||||
}
|
||||
|
||||
fn replace_text_in_range(&mut self, range: Option<Range<usize>>, text: &str) {
|
||||
eprintln!("replace_text_in_range({range:?}, {text:?})");
|
||||
|
||||
self.update_focused_view(|window_id, view_id, view, cx| {
|
||||
view.replace_text_in_range(range, text, cx, window_id, view_id);
|
||||
});
|
||||
}
|
||||
|
||||
fn marked_text_range(&self) -> Option<Range<usize>> {
|
||||
let result = self
|
||||
.read_focused_view(|view, cx| view.marked_text_range(cx))
|
||||
.flatten();
|
||||
|
||||
eprintln!("marked_text_range() -> {result:?}");
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
fn unmark_text(&mut self) {
|
||||
eprintln!("unmark_text()");
|
||||
|
||||
self.update_focused_view(|window_id, view_id, view, cx| {
|
||||
view.unmark_text(cx, window_id, view_id);
|
||||
});
|
||||
}
|
||||
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
range: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
) {
|
||||
eprintln!(
|
||||
"replace_and_mark_text_in_range({range:?}, {new_text:?}, {new_selected_range:?})"
|
||||
);
|
||||
|
||||
self.update_focused_view(|window_id, view_id, view, cx| {
|
||||
view.replace_and_mark_text_in_range(
|
||||
range,
|
||||
new_text,
|
||||
new_selected_range,
|
||||
cx,
|
||||
window_id,
|
||||
view_id,
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
// TODO - do these need to be handled separately?
|
||||
|
||||
fn cancel_composition(&mut self) {
|
||||
self.unmark_text();
|
||||
}
|
||||
|
||||
fn finish_composition(&mut self) {
|
||||
self.unmark_text();
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
impl TestAppContext {
|
||||
pub fn new(
|
||||
|
@ -1888,6 +2035,11 @@ impl MutableAppContext {
|
|||
}));
|
||||
}
|
||||
|
||||
window.set_input_handler(Box::new(WindowInputHandler {
|
||||
app: self.upgrade().0,
|
||||
window_id,
|
||||
}));
|
||||
|
||||
let scene =
|
||||
presenter
|
||||
.borrow_mut()
|
||||
|
@ -3179,6 +3331,35 @@ pub trait AnyView {
|
|||
fn on_blur(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
|
||||
fn keymap_context(&self, cx: &AppContext) -> keymap::Context;
|
||||
fn debug_json(&self, cx: &AppContext) -> serde_json::Value;
|
||||
|
||||
fn text_for_range(&self, range: Range<usize>, cx: &AppContext) -> Option<String>;
|
||||
fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>>;
|
||||
fn set_selected_text_range(
|
||||
&mut self,
|
||||
range: Range<usize>,
|
||||
cx: &mut MutableAppContext,
|
||||
window_id: usize,
|
||||
view_id: usize,
|
||||
);
|
||||
fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>>;
|
||||
fn unmark_text(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize);
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
range: Option<Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut MutableAppContext,
|
||||
window_id: usize,
|
||||
view_id: usize,
|
||||
);
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
range: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
cx: &mut MutableAppContext,
|
||||
window_id: usize,
|
||||
view_id: usize,
|
||||
);
|
||||
}
|
||||
|
||||
impl<T> AnyView for T
|
||||
|
@ -3229,6 +3410,59 @@ where
|
|||
fn debug_json(&self, cx: &AppContext) -> serde_json::Value {
|
||||
View::debug_json(self, cx)
|
||||
}
|
||||
|
||||
fn text_for_range(&self, range: Range<usize>, cx: &AppContext) -> Option<String> {
|
||||
View::text_for_range(self, range, cx)
|
||||
}
|
||||
|
||||
fn selected_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
|
||||
View::selected_text_range(self, cx)
|
||||
}
|
||||
|
||||
fn set_selected_text_range(
|
||||
&mut self,
|
||||
range: Range<usize>,
|
||||
cx: &mut MutableAppContext,
|
||||
window_id: usize,
|
||||
view_id: usize,
|
||||
) {
|
||||
let mut cx = ViewContext::new(cx, window_id, view_id);
|
||||
View::set_selected_text_range(self, range, &mut cx)
|
||||
}
|
||||
|
||||
fn marked_text_range(&self, cx: &AppContext) -> Option<Range<usize>> {
|
||||
View::marked_text_range(self, cx)
|
||||
}
|
||||
|
||||
fn unmark_text(&mut self, cx: &mut MutableAppContext, window_id: usize, view_id: usize) {
|
||||
let mut cx = ViewContext::new(cx, window_id, view_id);
|
||||
View::unmark_text(self, &mut cx)
|
||||
}
|
||||
|
||||
fn replace_text_in_range(
|
||||
&mut self,
|
||||
range: Option<Range<usize>>,
|
||||
text: &str,
|
||||
cx: &mut MutableAppContext,
|
||||
window_id: usize,
|
||||
view_id: usize,
|
||||
) {
|
||||
let mut cx = ViewContext::new(cx, window_id, view_id);
|
||||
View::replace_text_in_range(self, range, text, &mut cx)
|
||||
}
|
||||
|
||||
fn replace_and_mark_text_in_range(
|
||||
&mut self,
|
||||
range: Option<Range<usize>>,
|
||||
new_text: &str,
|
||||
new_selected_range: Option<Range<usize>>,
|
||||
cx: &mut MutableAppContext,
|
||||
window_id: usize,
|
||||
view_id: usize,
|
||||
) {
|
||||
let mut cx = ViewContext::new(cx, window_id, view_id);
|
||||
View::replace_and_mark_text_in_range(self, range, new_text, new_selected_range, &mut cx)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ModelContext<'a, T: ?Sized> {
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue