Position IME input according to where the selection is rendered
This commit is contained in:
parent
3c5d7e001e
commit
97ce3998ec
31 changed files with 563 additions and 27 deletions
|
@ -11,7 +11,7 @@ use gpui::{
|
||||||
fonts::{FontId, HighlightStyle},
|
fonts::{FontId, HighlightStyle},
|
||||||
Entity, ModelContext, ModelHandle,
|
Entity, ModelContext, ModelHandle,
|
||||||
};
|
};
|
||||||
use language::{Point, Subscription as BufferSubscription};
|
use language::{OffsetUtf16, Point, Subscription as BufferSubscription};
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use std::{any::TypeId, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
|
use std::{any::TypeId, fmt::Debug, num::NonZeroU32, ops::Range, sync::Arc};
|
||||||
use sum_tree::{Bias, TreeMap};
|
use sum_tree::{Bias, TreeMap};
|
||||||
|
@ -549,6 +549,12 @@ impl ToDisplayPoint for usize {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl ToDisplayPoint for OffsetUtf16 {
|
||||||
|
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
|
||||||
|
self.to_offset(&map.buffer_snapshot).to_display_point(map)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl ToDisplayPoint for Point {
|
impl ToDisplayPoint for Point {
|
||||||
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
|
fn to_display_point(&self, map: &DisplaySnapshot) -> DisplayPoint {
|
||||||
map.point_to_display_point(*self, Bias::Left)
|
map.point_to_display_point(*self, Bias::Left)
|
||||||
|
|
|
@ -30,7 +30,7 @@ use gpui::{
|
||||||
WeakViewHandle,
|
WeakViewHandle,
|
||||||
};
|
};
|
||||||
use json::json;
|
use json::json;
|
||||||
use language::{Bias, DiagnosticSeverity, Selection};
|
use language::{Bias, DiagnosticSeverity, OffsetUtf16, Selection};
|
||||||
use project::ProjectPath;
|
use project::ProjectPath;
|
||||||
use settings::Settings;
|
use settings::Settings;
|
||||||
use smallvec::SmallVec;
|
use smallvec::SmallVec;
|
||||||
|
@ -1517,6 +1517,43 @@ impl Element for EditorElement {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
bounds: RectF,
|
||||||
|
_: RectF,
|
||||||
|
layout: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &gpui::MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
let text_bounds = RectF::new(
|
||||||
|
bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
|
||||||
|
layout.text_size,
|
||||||
|
);
|
||||||
|
let content_origin = text_bounds.origin() + vec2f(layout.gutter_margin, 0.);
|
||||||
|
let scroll_position = layout.snapshot.scroll_position();
|
||||||
|
let start_row = scroll_position.y() as u32;
|
||||||
|
let scroll_top = scroll_position.y() * layout.line_height;
|
||||||
|
let scroll_left = scroll_position.x() * layout.em_width;
|
||||||
|
|
||||||
|
let range_start =
|
||||||
|
OffsetUtf16(range_utf16.start).to_display_point(&layout.snapshot.display_snapshot);
|
||||||
|
if range_start.row() < start_row {
|
||||||
|
return None;
|
||||||
|
}
|
||||||
|
|
||||||
|
let line = layout
|
||||||
|
.line_layouts
|
||||||
|
.get((range_start.row() - start_row) as usize)?;
|
||||||
|
let range_start_x = line.x_for_index(range_start.column() as usize);
|
||||||
|
let range_start_y = range_start.row() as f32 * layout.line_height;
|
||||||
|
Some(RectF::new(
|
||||||
|
content_origin + vec2f(range_start_x, range_start_y + layout.line_height)
|
||||||
|
- vec2f(scroll_left, scroll_top),
|
||||||
|
vec2f(layout.em_width, layout.line_height),
|
||||||
|
))
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -2,11 +2,12 @@ use gpui::{
|
||||||
color::Color,
|
color::Color,
|
||||||
fonts::{Properties, Weight},
|
fonts::{Properties, Weight},
|
||||||
text_layout::RunStyle,
|
text_layout::RunStyle,
|
||||||
DebugContext, Element as _, Quad,
|
DebugContext, Element as _, MeasurementContext, Quad,
|
||||||
};
|
};
|
||||||
use log::LevelFilter;
|
use log::LevelFilter;
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use simplelog::SimpleLogger;
|
use simplelog::SimpleLogger;
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
SimpleLogger::init(LevelFilter::Info, Default::default()).expect("could not initialize logger");
|
||||||
|
@ -112,6 +113,18 @@ impl gpui::Element for TextElement {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -3,6 +3,7 @@ pub mod action;
|
||||||
use crate::{
|
use crate::{
|
||||||
elements::ElementBox,
|
elements::ElementBox,
|
||||||
executor::{self, Task},
|
executor::{self, Task},
|
||||||
|
geometry::rect::RectF,
|
||||||
keymap::{self, Binding, Keystroke},
|
keymap::{self, Binding, Keystroke},
|
||||||
platform::{self, KeyDownEvent, Platform, PromptLevel, WindowOptions},
|
platform::{self, KeyDownEvent, Platform, PromptLevel, WindowOptions},
|
||||||
presenter::Presenter,
|
presenter::Presenter,
|
||||||
|
@ -445,6 +446,13 @@ impl InputHandler for WindowInputHandler {
|
||||||
);
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF> {
|
||||||
|
let app = self.app.borrow();
|
||||||
|
let (presenter, _) = app.presenters_and_platform_windows.get(&self.window_id)?;
|
||||||
|
let presenter = presenter.borrow();
|
||||||
|
presenter.rect_for_text_range(range_utf16, &app)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(any(test, feature = "test-support"))]
|
#[cfg(any(test, feature = "test-support"))]
|
||||||
|
|
|
@ -31,7 +31,9 @@ use crate::{
|
||||||
rect::RectF,
|
rect::RectF,
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json, Action, DebugContext, Event, EventContext, LayoutContext, PaintContext, RenderContext,
|
json,
|
||||||
|
presenter::MeasurementContext,
|
||||||
|
Action, DebugContext, Event, EventContext, LayoutContext, PaintContext, RenderContext,
|
||||||
SizeConstraint, View,
|
SizeConstraint, View,
|
||||||
};
|
};
|
||||||
use core::panic;
|
use core::panic;
|
||||||
|
@ -41,7 +43,7 @@ use std::{
|
||||||
borrow::Cow,
|
borrow::Cow,
|
||||||
cell::RefCell,
|
cell::RefCell,
|
||||||
mem,
|
mem,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut, Range},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -49,6 +51,11 @@ trait AnyElement {
|
||||||
fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
|
fn layout(&mut self, constraint: SizeConstraint, cx: &mut LayoutContext) -> Vector2F;
|
||||||
fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext);
|
fn paint(&mut self, origin: Vector2F, visible_bounds: RectF, cx: &mut PaintContext);
|
||||||
fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
|
fn dispatch_event(&mut self, event: &Event, cx: &mut EventContext) -> bool;
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF>;
|
||||||
fn debug(&self, cx: &DebugContext) -> serde_json::Value;
|
fn debug(&self, cx: &DebugContext) -> serde_json::Value;
|
||||||
|
|
||||||
fn size(&self) -> Vector2F;
|
fn size(&self) -> Vector2F;
|
||||||
|
@ -83,6 +90,16 @@ pub trait Element {
|
||||||
cx: &mut EventContext,
|
cx: &mut EventContext,
|
||||||
) -> bool;
|
) -> bool;
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
bounds: RectF,
|
||||||
|
visible_bounds: RectF,
|
||||||
|
layout: &Self::LayoutState,
|
||||||
|
paint: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF>;
|
||||||
|
|
||||||
fn metadata(&self) -> Option<&dyn Any> {
|
fn metadata(&self) -> Option<&dyn Any> {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
|
@ -287,6 +304,26 @@ impl<T: Element> AnyElement for Lifecycle<T> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
if let Lifecycle::PostPaint {
|
||||||
|
element,
|
||||||
|
bounds,
|
||||||
|
visible_bounds,
|
||||||
|
layout,
|
||||||
|
paint,
|
||||||
|
..
|
||||||
|
} = self
|
||||||
|
{
|
||||||
|
element.rect_for_text_range(range_utf16, *bounds, *visible_bounds, layout, paint, cx)
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
fn size(&self) -> Vector2F {
|
fn size(&self) -> Vector2F {
|
||||||
match self {
|
match self {
|
||||||
Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
|
Lifecycle::Empty | Lifecycle::Init { .. } => panic!("invalid element lifecycle state"),
|
||||||
|
@ -385,6 +422,14 @@ impl ElementRc {
|
||||||
self.element.borrow_mut().dispatch_event(event, cx)
|
self.element.borrow_mut().dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.element.borrow().rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
pub fn size(&self) -> Vector2F {
|
pub fn size(&self) -> Vector2F {
|
||||||
self.element.borrow().size()
|
self.element.borrow().size()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,8 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
json,
|
||||||
|
presenter::MeasurementContext,
|
||||||
|
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
||||||
SizeConstraint,
|
SizeConstraint,
|
||||||
};
|
};
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
|
@ -94,6 +96,18 @@ impl Element for Align {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: std::ops::Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: pathfinder_geometry::rect::RectF,
|
bounds: pathfinder_geometry::rect::RectF,
|
||||||
|
|
|
@ -1,6 +1,7 @@
|
||||||
use super::Element;
|
use super::Element;
|
||||||
use crate::{
|
use crate::{
|
||||||
json::{self, json},
|
json::{self, json},
|
||||||
|
presenter::MeasurementContext,
|
||||||
DebugContext, PaintContext,
|
DebugContext, PaintContext,
|
||||||
};
|
};
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
|
@ -67,6 +68,18 @@ where
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: std::ops::Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -1,9 +1,13 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
json,
|
||||||
|
presenter::MeasurementContext,
|
||||||
|
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
||||||
SizeConstraint,
|
SizeConstraint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -165,6 +169,18 @@ impl Element for ConstrainedBox {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
color::Color,
|
color::Color,
|
||||||
geometry::{
|
geometry::{
|
||||||
|
@ -7,6 +9,7 @@ use crate::{
|
||||||
},
|
},
|
||||||
json::ToJson,
|
json::ToJson,
|
||||||
platform::CursorStyle,
|
platform::CursorStyle,
|
||||||
|
presenter::MeasurementContext,
|
||||||
scene::{self, Border, CursorRegion, Quad},
|
scene::{self, Border, CursorRegion, Quad},
|
||||||
Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
|
Element, ElementBox, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
@ -271,6 +274,18 @@ impl Element for Container {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -1,9 +1,12 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{
|
geometry::{
|
||||||
rect::RectF,
|
rect::RectF,
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{json, ToJson},
|
json::{json, ToJson},
|
||||||
|
presenter::MeasurementContext,
|
||||||
DebugContext,
|
DebugContext,
|
||||||
};
|
};
|
||||||
use crate::{Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint};
|
use crate::{Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint};
|
||||||
|
@ -67,6 +70,18 @@ impl Element for Empty {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -1,11 +1,11 @@
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::vector::Vector2F, CursorRegion, DebugContext, Element, ElementBox, Event,
|
geometry::vector::Vector2F, presenter::MeasurementContext, CursorRegion, DebugContext, Element,
|
||||||
EventContext, LayoutContext, MouseButton, MouseEvent, MouseRegion, NavigationDirection,
|
ElementBox, Event, EventContext, LayoutContext, MouseButton, MouseEvent, MouseRegion,
|
||||||
PaintContext, SizeConstraint,
|
NavigationDirection, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
use pathfinder_geometry::rect::RectF;
|
use pathfinder_geometry::rect::RectF;
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
use std::{any::TypeId, rc::Rc};
|
use std::{any::TypeId, ops::Range, rc::Rc};
|
||||||
|
|
||||||
pub struct EventHandler {
|
pub struct EventHandler {
|
||||||
child: ElementBox,
|
child: ElementBox,
|
||||||
|
@ -158,6 +158,18 @@ impl Element for EventHandler {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -1,6 +1,10 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json, DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
json,
|
||||||
|
presenter::MeasurementContext,
|
||||||
|
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
||||||
SizeConstraint,
|
SizeConstraint,
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
@ -74,6 +78,18 @@ impl Element for Expanded {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -1,7 +1,8 @@
|
||||||
use std::{any::Any, f32::INFINITY};
|
use std::{any::Any, f32::INFINITY, ops::Range};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
json::{self, ToJson, Value},
|
json::{self, ToJson, Value},
|
||||||
|
presenter::MeasurementContext,
|
||||||
Axis, DebugContext, Element, ElementBox, ElementStateHandle, Event, EventContext,
|
Axis, DebugContext, Element, ElementBox, ElementStateHandle, Event, EventContext,
|
||||||
LayoutContext, MouseMovedEvent, PaintContext, RenderContext, ScrollWheelEvent, SizeConstraint,
|
LayoutContext, MouseMovedEvent, PaintContext, RenderContext, ScrollWheelEvent, SizeConstraint,
|
||||||
Vector2FExt, View,
|
Vector2FExt, View,
|
||||||
|
@ -334,6 +335,20 @@ impl Element for Flex {
|
||||||
handled
|
handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.children
|
||||||
|
.iter()
|
||||||
|
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx))
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
@ -417,6 +432,18 @@ impl Element for FlexItem {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn metadata(&self) -> Option<&dyn Any> {
|
fn metadata(&self) -> Option<&dyn Any> {
|
||||||
Some(&self.metadata)
|
Some(&self.metadata)
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::json,
|
json::json,
|
||||||
|
presenter::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
||||||
SizeConstraint,
|
SizeConstraint,
|
||||||
};
|
};
|
||||||
|
@ -65,6 +68,18 @@ impl Element for Hook {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -5,11 +5,12 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{json, ToJson},
|
json::{json, ToJson},
|
||||||
|
presenter::MeasurementContext,
|
||||||
scene, Border, DebugContext, Element, Event, EventContext, ImageData, LayoutContext,
|
scene, Border, DebugContext, Element, Event, EventContext, ImageData, LayoutContext,
|
||||||
PaintContext, SizeConstraint,
|
PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::sync::Arc;
|
use std::{ops::Range, sync::Arc};
|
||||||
|
|
||||||
pub struct Image {
|
pub struct Image {
|
||||||
data: Arc<ImageData>,
|
data: Arc<ImageData>,
|
||||||
|
@ -89,6 +90,18 @@ impl Element for Image {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -76,6 +76,18 @@ impl Element for KeystrokeLabel {
|
||||||
element.dispatch_event(event, cx)
|
element.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -1,3 +1,5 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
fonts::TextStyle,
|
fonts::TextStyle,
|
||||||
geometry::{
|
geometry::{
|
||||||
|
@ -5,6 +7,7 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{ToJson, Value},
|
json::{ToJson, Value},
|
||||||
|
presenter::MeasurementContext,
|
||||||
text_layout::{Line, RunStyle},
|
text_layout::{Line, RunStyle},
|
||||||
DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
|
DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
@ -174,6 +177,18 @@ impl Element for Label {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -4,6 +4,7 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::json,
|
json::json,
|
||||||
|
presenter::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, ElementRc, Event, EventContext, LayoutContext, PaintContext,
|
DebugContext, Element, ElementBox, ElementRc, Event, EventContext, LayoutContext, PaintContext,
|
||||||
RenderContext, ScrollWheelEvent, SizeConstraint, View, ViewContext,
|
RenderContext, ScrollWheelEvent, SizeConstraint, View, ViewContext,
|
||||||
};
|
};
|
||||||
|
@ -328,6 +329,39 @@ impl Element for List {
|
||||||
handled
|
handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
bounds: RectF,
|
||||||
|
_: RectF,
|
||||||
|
scroll_top: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
let state = self.state.0.borrow();
|
||||||
|
let mut item_origin = bounds.origin() - vec2f(0., scroll_top.offset_in_item);
|
||||||
|
let mut cursor = state.items.cursor::<Count>();
|
||||||
|
cursor.seek(&Count(scroll_top.item_ix), Bias::Right, &());
|
||||||
|
while let Some(item) = cursor.item() {
|
||||||
|
if item_origin.y() > bounds.max_y() {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if let ListItem::Rendered(element) = item {
|
||||||
|
if let Some(rect) = element.rect_for_text_range(range_utf16.clone(), cx) {
|
||||||
|
return Some(rect);
|
||||||
|
}
|
||||||
|
|
||||||
|
item_origin.set_y(item_origin.y() + element.size().y());
|
||||||
|
cursor.next(&());
|
||||||
|
} else {
|
||||||
|
unreachable!();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
@ -939,6 +973,18 @@ mod tests {
|
||||||
todo!()
|
todo!()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(&self, _: RectF, _: &(), _: &(), _: &DebugContext) -> serde_json::Value {
|
fn debug(&self, _: RectF, _: &(), _: &(), _: &DebugContext) -> serde_json::Value {
|
||||||
self.id.into()
|
self.id.into()
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::{any::TypeId, rc::Rc};
|
use std::{any::TypeId, ops::Range, rc::Rc};
|
||||||
|
|
||||||
use super::Padding;
|
use super::Padding;
|
||||||
use crate::{
|
use crate::{
|
||||||
|
@ -8,8 +8,8 @@ use crate::{
|
||||||
},
|
},
|
||||||
platform::CursorStyle,
|
platform::CursorStyle,
|
||||||
scene::CursorRegion,
|
scene::CursorRegion,
|
||||||
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MouseRegion, MouseState,
|
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MouseRegion,
|
||||||
PaintContext, RenderContext, SizeConstraint, View,
|
MouseState, PaintContext, RenderContext, SizeConstraint, View, presenter::MeasurementContext,
|
||||||
};
|
};
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
@ -192,6 +192,18 @@ impl Element for MouseEventHandler {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::ToJson,
|
json::ToJson,
|
||||||
|
presenter::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MouseRegion,
|
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, MouseRegion,
|
||||||
PaintContext, SizeConstraint,
|
PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
@ -126,6 +129,18 @@ impl Element for Overlay {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range_utf16, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -1,6 +1,9 @@
|
||||||
|
use std::ops::Range;
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::{self, json, ToJson},
|
json::{self, json, ToJson},
|
||||||
|
presenter::MeasurementContext,
|
||||||
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
DebugContext, Element, ElementBox, Event, EventContext, LayoutContext, PaintContext,
|
||||||
SizeConstraint,
|
SizeConstraint,
|
||||||
};
|
};
|
||||||
|
@ -64,6 +67,21 @@ impl Element for Stack {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.children
|
||||||
|
.iter()
|
||||||
|
.rev()
|
||||||
|
.find_map(|child| child.rect_for_text_range(range_utf16.clone(), cx))
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
use std::borrow::Cow;
|
use std::{borrow::Cow, ops::Range};
|
||||||
|
|
||||||
use serde_json::json;
|
use serde_json::json;
|
||||||
|
|
||||||
|
@ -8,6 +8,7 @@ use crate::{
|
||||||
rect::RectF,
|
rect::RectF,
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
|
presenter::MeasurementContext,
|
||||||
scene, DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
|
scene, DebugContext, Element, Event, EventContext, LayoutContext, PaintContext, SizeConstraint,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -84,6 +85,18 @@ impl Element for Svg {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -6,6 +6,7 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{ToJson, Value},
|
json::{ToJson, Value},
|
||||||
|
presenter::MeasurementContext,
|
||||||
text_layout::{Line, RunStyle, ShapedBoundary},
|
text_layout::{Line, RunStyle, ShapedBoundary},
|
||||||
DebugContext, Element, Event, EventContext, FontCache, LayoutContext, PaintContext,
|
DebugContext, Element, Event, EventContext, FontCache, LayoutContext, PaintContext,
|
||||||
SizeConstraint, TextLayoutCache,
|
SizeConstraint, TextLayoutCache,
|
||||||
|
@ -63,7 +64,7 @@ impl Element for Text {
|
||||||
cx: &mut LayoutContext,
|
cx: &mut LayoutContext,
|
||||||
) -> (Vector2F, Self::LayoutState) {
|
) -> (Vector2F, Self::LayoutState) {
|
||||||
// Convert the string and highlight ranges into an iterator of highlighted chunks.
|
// Convert the string and highlight ranges into an iterator of highlighted chunks.
|
||||||
|
|
||||||
let mut offset = 0;
|
let mut offset = 0;
|
||||||
let mut highlight_ranges = self.highlights.iter().peekable();
|
let mut highlight_ranges = self.highlights.iter().peekable();
|
||||||
let chunks = std::iter::from_fn(|| {
|
let chunks = std::iter::from_fn(|| {
|
||||||
|
@ -81,7 +82,8 @@ impl Element for Text {
|
||||||
"Highlight out of text range. Text len: {}, Highlight range: {}..{}",
|
"Highlight out of text range. Text len: {}, Highlight range: {}..{}",
|
||||||
self.text.len(),
|
self.text.len(),
|
||||||
range.start,
|
range.start,
|
||||||
range.end);
|
range.end
|
||||||
|
);
|
||||||
result = None;
|
result = None;
|
||||||
}
|
}
|
||||||
} else if offset < self.text.len() {
|
} else if offset < self.text.len() {
|
||||||
|
@ -188,6 +190,18 @@ impl Element for Text {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -6,12 +6,14 @@ use crate::{
|
||||||
fonts::TextStyle,
|
fonts::TextStyle,
|
||||||
geometry::{rect::RectF, vector::Vector2F},
|
geometry::{rect::RectF, vector::Vector2F},
|
||||||
json::json,
|
json::json,
|
||||||
|
presenter::MeasurementContext,
|
||||||
Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint,
|
Action, Axis, ElementStateHandle, LayoutContext, PaintContext, RenderContext, SizeConstraint,
|
||||||
Task, View,
|
Task, View,
|
||||||
};
|
};
|
||||||
use serde::Deserialize;
|
use serde::Deserialize;
|
||||||
use std::{
|
use std::{
|
||||||
cell::{Cell, RefCell},
|
cell::{Cell, RefCell},
|
||||||
|
ops::Range,
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
time::Duration,
|
time::Duration,
|
||||||
};
|
};
|
||||||
|
@ -196,6 +198,18 @@ impl Element for Tooltip {
|
||||||
self.child.dispatch_event(event, cx)
|
self.child.dispatch_event(event, cx)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
self.child.rect_for_text_range(range, cx)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_: RectF,
|
_: RectF,
|
||||||
|
|
|
@ -5,6 +5,7 @@ use crate::{
|
||||||
vector::{vec2f, Vector2F},
|
vector::{vec2f, Vector2F},
|
||||||
},
|
},
|
||||||
json::{self, json},
|
json::{self, json},
|
||||||
|
presenter::MeasurementContext,
|
||||||
ElementBox, RenderContext, ScrollWheelEvent, View,
|
ElementBox, RenderContext, ScrollWheelEvent, View,
|
||||||
};
|
};
|
||||||
use json::ToJson;
|
use json::ToJson;
|
||||||
|
@ -327,6 +328,21 @@ impl Element for UniformList {
|
||||||
handled
|
handled
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
layout: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
layout
|
||||||
|
.items
|
||||||
|
.iter()
|
||||||
|
.find_map(|child| child.rect_for_text_range(range.clone(), cx))
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -30,7 +30,8 @@ pub mod platform;
|
||||||
pub use gpui_macros::test;
|
pub use gpui_macros::test;
|
||||||
pub use platform::*;
|
pub use platform::*;
|
||||||
pub use presenter::{
|
pub use presenter::{
|
||||||
Axis, DebugContext, EventContext, LayoutContext, PaintContext, SizeConstraint, Vector2FExt,
|
Axis, DebugContext, EventContext, LayoutContext, MeasurementContext, PaintContext,
|
||||||
|
SizeConstraint, Vector2FExt,
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use anyhow;
|
pub use anyhow;
|
||||||
|
|
|
@ -91,17 +91,18 @@ pub trait Dispatcher: Send + Sync {
|
||||||
|
|
||||||
pub trait InputHandler {
|
pub trait InputHandler {
|
||||||
fn selected_text_range(&self) -> Option<Range<usize>>;
|
fn selected_text_range(&self) -> Option<Range<usize>>;
|
||||||
fn set_selected_text_range(&mut self, range: Range<usize>);
|
fn set_selected_text_range(&mut self, range_utf16: Range<usize>);
|
||||||
fn text_for_range(&self, range: Range<usize>) -> Option<String>;
|
fn text_for_range(&self, range_utf16: Range<usize>) -> Option<String>;
|
||||||
fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str);
|
fn replace_text_in_range(&mut self, replacement_range: Option<Range<usize>>, text: &str);
|
||||||
fn replace_and_mark_text_in_range(
|
fn replace_and_mark_text_in_range(
|
||||||
&mut self,
|
&mut self,
|
||||||
range: Option<Range<usize>>,
|
range_utf16: Option<Range<usize>>,
|
||||||
new_text: &str,
|
new_text: &str,
|
||||||
new_selected_range: Option<Range<usize>>,
|
new_selected_range: Option<Range<usize>>,
|
||||||
);
|
);
|
||||||
fn marked_text_range(&self) -> Option<Range<usize>>;
|
fn marked_text_range(&self) -> Option<Range<usize>>;
|
||||||
fn unmark_text(&mut self);
|
fn unmark_text(&mut self);
|
||||||
|
fn rect_for_range(&self, range_utf16: Range<usize>) -> Option<RectF>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait Window: WindowContext {
|
pub trait Window: WindowContext {
|
||||||
|
|
|
@ -1003,8 +1003,33 @@ extern "C" fn selected_range(this: &Object, _: Sel) -> NSRange {
|
||||||
.map_or(NSRange::invalid(), |range| range.into())
|
.map_or(NSRange::invalid(), |range| range.into())
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn first_rect_for_character_range(_: &Object, _: Sel, _: NSRange, _: id) -> NSRect {
|
extern "C" fn first_rect_for_character_range(
|
||||||
NSRect::new(NSPoint::new(0., 0.), NSSize::new(20., 20.))
|
this: &Object,
|
||||||
|
_: Sel,
|
||||||
|
range: NSRange,
|
||||||
|
_: id,
|
||||||
|
) -> NSRect {
|
||||||
|
let frame = unsafe {
|
||||||
|
let window = get_window_state(this).borrow().native_window;
|
||||||
|
NSView::frame(window)
|
||||||
|
};
|
||||||
|
|
||||||
|
with_input_handler(this, |input_handler| {
|
||||||
|
input_handler.rect_for_range(range.to_range()?)
|
||||||
|
})
|
||||||
|
.flatten()
|
||||||
|
.map_or(
|
||||||
|
NSRect::new(NSPoint::new(0., 0.), NSSize::new(0., 0.)),
|
||||||
|
|rect| {
|
||||||
|
NSRect::new(
|
||||||
|
NSPoint::new(
|
||||||
|
frame.origin.x + rect.origin_x() as f64,
|
||||||
|
frame.origin.y + frame.size.height - rect.origin_y() as f64,
|
||||||
|
),
|
||||||
|
NSSize::new(rect.width() as f64, rect.height() as f64),
|
||||||
|
)
|
||||||
|
},
|
||||||
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) {
|
extern "C" fn insert_text(this: &Object, _: Sel, text: id, replacement_range: NSRange) {
|
||||||
|
|
|
@ -19,7 +19,7 @@ use smallvec::SmallVec;
|
||||||
use std::{
|
use std::{
|
||||||
collections::{HashMap, HashSet},
|
collections::{HashMap, HashSet},
|
||||||
marker::PhantomData,
|
marker::PhantomData,
|
||||||
ops::{Deref, DerefMut},
|
ops::{Deref, DerefMut, Range},
|
||||||
sync::Arc,
|
sync::Arc,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -224,6 +224,17 @@ impl Presenter {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn rect_for_text_range(&self, range_utf16: Range<usize>, cx: &AppContext) -> Option<RectF> {
|
||||||
|
cx.focused_view_id(self.window_id).and_then(|view_id| {
|
||||||
|
let cx = MeasurementContext {
|
||||||
|
app: cx,
|
||||||
|
rendered_views: &self.rendered_views,
|
||||||
|
window_id: self.window_id,
|
||||||
|
};
|
||||||
|
cx.rect_for_text_range(view_id, range_utf16)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) -> bool {
|
pub fn dispatch_event(&mut self, event: Event, cx: &mut MutableAppContext) -> bool {
|
||||||
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
|
if let Some(root_view_id) = cx.root_view_id(self.window_id) {
|
||||||
let mut invalidated_views = Vec::new();
|
let mut invalidated_views = Vec::new();
|
||||||
|
@ -777,6 +788,27 @@ impl<'a> DerefMut for EventContext<'a> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct MeasurementContext<'a> {
|
||||||
|
app: &'a AppContext,
|
||||||
|
rendered_views: &'a HashMap<usize, ElementBox>,
|
||||||
|
pub window_id: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> Deref for MeasurementContext<'a> {
|
||||||
|
type Target = AppContext;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
self.app
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> MeasurementContext<'a> {
|
||||||
|
fn rect_for_text_range(&self, view_id: usize, range_utf16: Range<usize>) -> Option<RectF> {
|
||||||
|
let element = self.rendered_views.get(&view_id)?;
|
||||||
|
element.rect_for_text_range(range_utf16, self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DebugContext<'a> {
|
pub struct DebugContext<'a> {
|
||||||
rendered_views: &'a HashMap<usize, ElementBox>,
|
rendered_views: &'a HashMap<usize, ElementBox>,
|
||||||
pub font_cache: &'a FontCache,
|
pub font_cache: &'a FontCache,
|
||||||
|
@ -936,6 +968,18 @@ impl Element for ChildView {
|
||||||
cx.dispatch_event(self.view.id(), event)
|
cx.dispatch_event(self.view.id(), event)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
range_utf16: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
cx: &MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
cx.rect_for_text_range(self.view.id(), range_utf16)
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: RectF,
|
bounds: RectF,
|
||||||
|
|
|
@ -395,6 +395,18 @@ impl Element for TerminalEl {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &gpui::MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
_bounds: gpui::geometry::rect::RectF,
|
_bounds: gpui::geometry::rect::RectF,
|
||||||
|
|
|
@ -43,6 +43,7 @@ use std::{
|
||||||
fmt,
|
fmt,
|
||||||
future::Future,
|
future::Future,
|
||||||
mem,
|
mem,
|
||||||
|
ops::Range,
|
||||||
path::{Path, PathBuf},
|
path::{Path, PathBuf},
|
||||||
rc::Rc,
|
rc::Rc,
|
||||||
sync::{
|
sync::{
|
||||||
|
@ -2538,6 +2539,18 @@ impl Element for AvatarRibbon {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn rect_for_text_range(
|
||||||
|
&self,
|
||||||
|
_: Range<usize>,
|
||||||
|
_: RectF,
|
||||||
|
_: RectF,
|
||||||
|
_: &Self::LayoutState,
|
||||||
|
_: &Self::PaintState,
|
||||||
|
_: &gpui::MeasurementContext,
|
||||||
|
) -> Option<RectF> {
|
||||||
|
None
|
||||||
|
}
|
||||||
|
|
||||||
fn debug(
|
fn debug(
|
||||||
&self,
|
&self,
|
||||||
bounds: gpui::geometry::rect::RectF,
|
bounds: gpui::geometry::rect::RectF,
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue