mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-16 15:11:25 +00:00
Don't move in paint
This commit is contained in:
parent
fb3382bcc5
commit
d13a21c238
15 changed files with 537 additions and 393 deletions
|
@ -933,7 +933,7 @@ impl EditorElement {
|
|||
cx.stop_propagation();
|
||||
},
|
||||
))
|
||||
.draw(
|
||||
.draw2(
|
||||
fold_bounds.origin,
|
||||
fold_bounds.size,
|
||||
cx,
|
||||
|
@ -1199,11 +1199,10 @@ impl EditorElement {
|
|||
.child(mouse_context_menu.context_menu.clone())
|
||||
.anchor(AnchorCorner::TopLeft)
|
||||
.snap_to_window();
|
||||
element.draw(
|
||||
element.into_any().draw(
|
||||
gpui::Point::default(),
|
||||
size(AvailableSpace::MinContent, AvailableSpace::MinContent),
|
||||
cx,
|
||||
|_, _| {},
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1496,7 +1495,7 @@ impl EditorElement {
|
|||
let scroll_left = scroll_position.x * layout.position_map.em_width;
|
||||
let scroll_top = scroll_position.y * layout.position_map.line_height;
|
||||
|
||||
for block in layout.blocks.drain(..) {
|
||||
for mut block in layout.blocks.drain(..) {
|
||||
let mut origin = bounds.origin
|
||||
+ point(
|
||||
Pixels::ZERO,
|
||||
|
@ -2781,7 +2780,7 @@ impl Element for EditorElement {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
mut self,
|
||||
&mut self,
|
||||
bounds: Bounds<gpui::Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut gpui::WindowContext,
|
||||
|
|
|
@ -23,7 +23,7 @@ pub trait IntoElement: Sized {
|
|||
self.into_element().into_any()
|
||||
}
|
||||
|
||||
fn draw<T, R>(
|
||||
fn draw2<T, R>(
|
||||
self,
|
||||
origin: Point<Pixels>,
|
||||
available_space: Size<T>,
|
||||
|
@ -92,7 +92,7 @@ pub trait Element: 'static + IntoElement {
|
|||
cx: &mut WindowContext,
|
||||
) -> (LayoutId, Self::State);
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext);
|
||||
|
||||
fn into_any(self) -> AnyElement {
|
||||
AnyElement::new(self)
|
||||
|
@ -150,8 +150,8 @@ impl<C: RenderOnce> Element for Component<C> {
|
|||
}
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
let element = state.rendered_element.take().unwrap();
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
let mut element = state.rendered_element.take().unwrap();
|
||||
if let Some(element_id) = element.element_id() {
|
||||
cx.with_element_state(element_id, |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
|
@ -420,7 +420,7 @@ impl AnyElement {
|
|||
self.0.layout(cx)
|
||||
}
|
||||
|
||||
pub fn paint(mut self, cx: &mut WindowContext) {
|
||||
pub fn paint(&mut self, cx: &mut WindowContext) {
|
||||
self.0.paint(cx)
|
||||
}
|
||||
|
||||
|
@ -435,7 +435,7 @@ impl AnyElement {
|
|||
|
||||
/// Initializes this element and performs layout in the available space, then paints it at the given origin.
|
||||
pub fn draw(
|
||||
mut self,
|
||||
&mut self,
|
||||
origin: Point<Pixels>,
|
||||
available_space: Size<AvailableSpace>,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -465,8 +465,8 @@ impl Element for AnyElement {
|
|||
(layout_id, ())
|
||||
}
|
||||
|
||||
fn paint(self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
|
||||
self.paint(cx);
|
||||
fn paint(&mut self, _: Bounds<Pixels>, _: &mut Self::State, cx: &mut WindowContext) {
|
||||
self.paint(cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -508,5 +508,11 @@ impl Element for () {
|
|||
(cx.request_layout(&crate::Style::default(), None), ())
|
||||
}
|
||||
|
||||
fn paint(self, _bounds: Bounds<Pixels>, _state: &mut Self::State, _cx: &mut WindowContext) {}
|
||||
fn paint(
|
||||
&mut self,
|
||||
_bounds: Bounds<Pixels>,
|
||||
_state: &mut Self::State,
|
||||
_cx: &mut WindowContext,
|
||||
) {
|
||||
}
|
||||
}
|
||||
|
|
|
@ -4,13 +4,13 @@ use crate::{Bounds, Element, IntoElement, Pixels, Style, StyleRefinement, Styled
|
|||
|
||||
pub fn canvas(callback: impl 'static + FnOnce(&Bounds<Pixels>, &mut WindowContext)) -> Canvas {
|
||||
Canvas {
|
||||
paint_callback: Box::new(callback),
|
||||
paint_callback: Some(Box::new(callback)),
|
||||
style: StyleRefinement::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Canvas {
|
||||
paint_callback: Box<dyn FnOnce(&Bounds<Pixels>, &mut WindowContext)>,
|
||||
paint_callback: Option<Box<dyn FnOnce(&Bounds<Pixels>, &mut WindowContext)>>,
|
||||
style: StyleRefinement,
|
||||
}
|
||||
|
||||
|
@ -40,8 +40,8 @@ impl Element for Canvas {
|
|||
(layout_id, ())
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, _: &mut (), cx: &mut WindowContext) {
|
||||
(self.paint_callback)(&bounds, cx)
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, _: &mut (), cx: &mut WindowContext) {
|
||||
(self.paint_callback.take().unwrap())(&bounds, cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -35,6 +35,281 @@ pub struct DragMoveEvent<W: Render> {
|
|||
pub drag: View<W>,
|
||||
}
|
||||
|
||||
impl Interactivity {
|
||||
pub fn on_mouse_down(
|
||||
&mut self,
|
||||
button: MouseButton,
|
||||
listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.mouse_down_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_any_mouse_down(
|
||||
&mut self,
|
||||
listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.mouse_down_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_mouse_up(
|
||||
&mut self,
|
||||
button: MouseButton,
|
||||
listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.mouse_up_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_any_mouse_up(
|
||||
&mut self,
|
||||
listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.mouse_up_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_mouse_down_out(
|
||||
&mut self,
|
||||
listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.mouse_down_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture && !bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_mouse_up_out(
|
||||
&mut self,
|
||||
button: MouseButton,
|
||||
listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.mouse_up_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_mouse_move(
|
||||
&mut self,
|
||||
listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.mouse_move_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_drag_move<W>(
|
||||
&mut self,
|
||||
listener: impl Fn(&DragMoveEvent<W>, &mut WindowContext) + 'static,
|
||||
) where
|
||||
W: Render,
|
||||
{
|
||||
self.mouse_move_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& bounds.drag_target_contains(&event.position, cx)
|
||||
{
|
||||
if let Some(view) = cx.active_drag().and_then(|view| view.downcast::<W>().ok())
|
||||
{
|
||||
(listener)(
|
||||
&DragMoveEvent {
|
||||
event: event.clone(),
|
||||
drag: view,
|
||||
},
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_scroll_wheel(
|
||||
&mut self,
|
||||
listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.scroll_wheel_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn capture_action<A: Action>(
|
||||
&mut self,
|
||||
listener: impl Fn(&A, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.action_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Capture {
|
||||
(listener)(action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn on_action<A: Action>(&mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) {
|
||||
self.action_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Bubble {
|
||||
(listener)(action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn on_boxed_action(
|
||||
&mut self,
|
||||
action: &Box<dyn Action>,
|
||||
listener: impl Fn(&Box<dyn Action>, &mut WindowContext) + 'static,
|
||||
) {
|
||||
let action = action.boxed_clone();
|
||||
self.action_listeners.push((
|
||||
(*action).type_id(),
|
||||
Box::new(move |_, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
(listener)(&action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn on_key_down(&mut self, listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static) {
|
||||
self.key_down_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn capture_key_down(
|
||||
&mut self,
|
||||
listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.key_down_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
listener(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
|
||||
self.key_up_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
listener(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn capture_key_up(&mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) {
|
||||
self.key_up_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
listener(event, cx)
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_drop<W: 'static>(
|
||||
&mut self,
|
||||
listener: impl Fn(&View<W>, &mut WindowContext) + 'static,
|
||||
) {
|
||||
self.drop_listeners.push((
|
||||
TypeId::of::<W>(),
|
||||
Box::new(move |dragged_view, cx| {
|
||||
listener(&dragged_view.downcast().unwrap(), cx);
|
||||
}),
|
||||
));
|
||||
}
|
||||
|
||||
pub fn on_click(&mut self, listener: impl Fn(&ClickEvent, &mut WindowContext) + 'static)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.click_listeners
|
||||
.push(Box::new(move |event, cx| listener(event, cx)));
|
||||
}
|
||||
|
||||
pub fn on_drag<W>(&mut self, constructor: impl Fn(&mut WindowContext) -> View<W> + 'static)
|
||||
where
|
||||
Self: Sized,
|
||||
W: 'static + Render,
|
||||
{
|
||||
debug_assert!(
|
||||
self.drag_listener.is_none(),
|
||||
"calling on_drag more than once on the same element is not supported"
|
||||
);
|
||||
self.drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag {
|
||||
view: constructor(cx).into(),
|
||||
cursor_offset,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn on_hover(&mut self, listener: impl Fn(&bool, &mut WindowContext) + 'static)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
debug_assert!(
|
||||
self.hover_listener.is_none(),
|
||||
"calling on_hover more than once on the same element is not supported"
|
||||
);
|
||||
self.hover_listener = Some(Box::new(listener));
|
||||
}
|
||||
|
||||
pub fn tooltip(&mut self, build_tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
debug_assert!(
|
||||
self.tooltip_builder.is_none(),
|
||||
"calling tooltip more than once on the same element is not supported"
|
||||
);
|
||||
self.tooltip_builder = Some(Rc::new(build_tooltip));
|
||||
}
|
||||
}
|
||||
|
||||
pub trait InteractiveElement: Sized {
|
||||
fn interactivity(&mut self) -> &mut Interactivity;
|
||||
|
||||
|
@ -92,16 +367,7 @@ pub trait InteractiveElement: Sized {
|
|||
button: MouseButton,
|
||||
listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().mouse_down_listeners.push(Box::new(
|
||||
move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx)
|
||||
}
|
||||
},
|
||||
));
|
||||
self.interactivity().on_mouse_down(button, listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -109,13 +375,7 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().mouse_down_listeners.push(Box::new(
|
||||
move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx)
|
||||
}
|
||||
},
|
||||
));
|
||||
self.interactivity().on_any_mouse_down(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -124,30 +384,7 @@ pub trait InteractiveElement: Sized {
|
|||
button: MouseButton,
|
||||
listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_any_mouse_up(
|
||||
mut self,
|
||||
listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
self.interactivity().on_mouse_up(button, listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -155,14 +392,7 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().mouse_down_listeners.push(Box::new(
|
||||
move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture && !bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx)
|
||||
}
|
||||
},
|
||||
));
|
||||
self.interactivity().on_mouse_down_out(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -171,16 +401,7 @@ pub trait InteractiveElement: Sized {
|
|||
button: MouseButton,
|
||||
listener: impl Fn(&MouseUpEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.visibly_contains(&event.position, cx)
|
||||
{
|
||||
(listener)(event, cx);
|
||||
}
|
||||
}));
|
||||
self.interactivity().on_mouse_up_out(button, listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -188,13 +409,7 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&MouseMoveEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().mouse_move_listeners.push(Box::new(
|
||||
move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx);
|
||||
}
|
||||
},
|
||||
));
|
||||
self.interactivity().on_mouse_move(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -205,24 +420,7 @@ pub trait InteractiveElement: Sized {
|
|||
where
|
||||
W: Render,
|
||||
{
|
||||
self.interactivity().mouse_move_listeners.push(Box::new(
|
||||
move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& bounds.drag_target_contains(&event.position, cx)
|
||||
{
|
||||
if let Some(view) = cx.active_drag().and_then(|view| view.downcast::<W>().ok())
|
||||
{
|
||||
(listener)(
|
||||
&DragMoveEvent {
|
||||
event: event.clone(),
|
||||
drag: view,
|
||||
},
|
||||
cx,
|
||||
);
|
||||
}
|
||||
}
|
||||
},
|
||||
));
|
||||
self.interactivity().on_drag_move(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -230,13 +428,7 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&ScrollWheelEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().scroll_wheel_listeners.push(Box::new(
|
||||
move |event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.visibly_contains(&event.position, cx) {
|
||||
(listener)(event, cx);
|
||||
}
|
||||
},
|
||||
));
|
||||
self.interactivity().on_scroll_wheel(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -245,29 +437,13 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&A, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().action_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Capture {
|
||||
(listener)(action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
self.interactivity().capture_action(listener);
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a listener for the given action, fires during the bubble event phase
|
||||
fn on_action<A: Action>(mut self, listener: impl Fn(&A, &mut WindowContext) + 'static) -> Self {
|
||||
self.interactivity().action_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Bubble {
|
||||
(listener)(action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
self.interactivity().on_action(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -276,15 +452,7 @@ pub trait InteractiveElement: Sized {
|
|||
action: &Box<dyn Action>,
|
||||
listener: impl Fn(&Box<dyn Action>, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
let action = action.boxed_clone();
|
||||
self.interactivity().action_listeners.push((
|
||||
(*action).type_id(),
|
||||
Box::new(move |_, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
(listener)(&action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
self.interactivity().on_boxed_action(action, listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -292,13 +460,7 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity()
|
||||
.key_down_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
(listener)(event, cx)
|
||||
}
|
||||
}));
|
||||
self.interactivity().on_key_down(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -306,24 +468,12 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&KeyDownEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity()
|
||||
.key_down_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
listener(event, cx)
|
||||
}
|
||||
}));
|
||||
self.interactivity().capture_key_down(listener);
|
||||
self
|
||||
}
|
||||
|
||||
fn on_key_up(mut self, listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static) -> Self {
|
||||
self.interactivity()
|
||||
.key_up_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
listener(event, cx)
|
||||
}
|
||||
}));
|
||||
self.interactivity().on_key_up(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -331,13 +481,15 @@ pub trait InteractiveElement: Sized {
|
|||
mut self,
|
||||
listener: impl Fn(&KeyUpEvent, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity()
|
||||
.key_up_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
listener(event, cx)
|
||||
}
|
||||
}));
|
||||
self.interactivity().capture_key_up(listener);
|
||||
self
|
||||
}
|
||||
|
||||
fn on_drop<W: 'static>(
|
||||
mut self,
|
||||
listener: impl Fn(&View<W>, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().on_drop(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -362,19 +514,6 @@ pub trait InteractiveElement: Sized {
|
|||
));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_drop<W: 'static>(
|
||||
mut self,
|
||||
listener: impl Fn(&View<W>, &mut WindowContext) + 'static,
|
||||
) -> Self {
|
||||
self.interactivity().drop_listeners.push((
|
||||
TypeId::of::<W>(),
|
||||
Box::new(move |dragged_view, cx| {
|
||||
listener(&dragged_view.downcast().unwrap(), cx);
|
||||
}),
|
||||
));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StatefulInteractiveElement: InteractiveElement {
|
||||
|
@ -431,9 +570,7 @@ pub trait StatefulInteractiveElement: InteractiveElement {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.interactivity()
|
||||
.click_listeners
|
||||
.push(Box::new(move |event, cx| listener(event, cx)));
|
||||
self.interactivity().on_click(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -442,14 +579,7 @@ pub trait StatefulInteractiveElement: InteractiveElement {
|
|||
Self: Sized,
|
||||
W: 'static + Render,
|
||||
{
|
||||
debug_assert!(
|
||||
self.interactivity().drag_listener.is_none(),
|
||||
"calling on_drag more than once on the same element is not supported"
|
||||
);
|
||||
self.interactivity().drag_listener = Some(Box::new(move |cursor_offset, cx| AnyDrag {
|
||||
view: constructor(cx).into(),
|
||||
cursor_offset,
|
||||
}));
|
||||
self.interactivity().on_drag(constructor);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -457,11 +587,7 @@ pub trait StatefulInteractiveElement: InteractiveElement {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
debug_assert!(
|
||||
self.interactivity().hover_listener.is_none(),
|
||||
"calling on_hover more than once on the same element is not supported"
|
||||
);
|
||||
self.interactivity().hover_listener = Some(Box::new(listener));
|
||||
self.interactivity().on_hover(listener);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -469,11 +595,7 @@ pub trait StatefulInteractiveElement: InteractiveElement {
|
|||
where
|
||||
Self: Sized,
|
||||
{
|
||||
debug_assert!(
|
||||
self.interactivity().tooltip_builder.is_none(),
|
||||
"calling tooltip more than once on the same element is not supported"
|
||||
);
|
||||
self.interactivity().tooltip_builder = Some(Rc::new(build_tooltip));
|
||||
self.interactivity().tooltip(build_tooltip);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -529,6 +651,7 @@ pub type ActionListener = Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext
|
|||
|
||||
#[track_caller]
|
||||
pub fn div() -> Div {
|
||||
#[allow(unused_mut)]
|
||||
let mut div = Div {
|
||||
interactivity: Interactivity::default(),
|
||||
children: SmallVec::default(),
|
||||
|
@ -598,7 +721,7 @@ impl Element for Div {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -649,7 +772,7 @@ impl Element for Div {
|
|||
cx.with_text_style(style.text_style().cloned(), |cx| {
|
||||
cx.with_content_mask(style.overflow_mask(bounds), |cx| {
|
||||
cx.with_element_offset(scroll_offset, |cx| {
|
||||
for child in self.children {
|
||||
for child in &mut self.children {
|
||||
child.paint(cx);
|
||||
}
|
||||
})
|
||||
|
@ -769,7 +892,7 @@ impl Interactivity {
|
|||
}
|
||||
|
||||
pub fn paint(
|
||||
mut self,
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
content_size: Size<Pixels>,
|
||||
element_state: &mut InteractiveElementState,
|
||||
|
@ -788,7 +911,7 @@ impl Interactivity {
|
|||
&& bounds.contains(&cx.mouse_position())
|
||||
{
|
||||
const FONT_SIZE: crate::Pixels = crate::Pixels(10.);
|
||||
let element_id = format!("{:?}", self.element_id.unwrap());
|
||||
let element_id = format!("{:?}", self.element_id.as_ref().unwrap());
|
||||
let str_len = element_id.len();
|
||||
|
||||
let render_debug_text = |cx: &mut WindowContext| {
|
||||
|
@ -934,28 +1057,28 @@ impl Interactivity {
|
|||
});
|
||||
}
|
||||
|
||||
for listener in self.mouse_down_listeners {
|
||||
for listener in self.mouse_down_listeners.drain(..) {
|
||||
let interactive_bounds = interactive_bounds.clone();
|
||||
cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
|
||||
listener(event, &interactive_bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.mouse_up_listeners {
|
||||
for listener in self.mouse_up_listeners.drain(..) {
|
||||
let interactive_bounds = interactive_bounds.clone();
|
||||
cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
|
||||
listener(event, &interactive_bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.mouse_move_listeners {
|
||||
for listener in self.mouse_move_listeners.drain(..) {
|
||||
let interactive_bounds = interactive_bounds.clone();
|
||||
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
|
||||
listener(event, &interactive_bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.scroll_wheel_listeners {
|
||||
for listener in self.scroll_wheel_listeners.drain(..) {
|
||||
let interactive_bounds = interactive_bounds.clone();
|
||||
cx.on_mouse_event(move |event: &ScrollWheelEvent, phase, cx| {
|
||||
listener(event, &interactive_bounds, phase, cx);
|
||||
|
@ -1024,8 +1147,8 @@ impl Interactivity {
|
|||
}
|
||||
}
|
||||
|
||||
let click_listeners = self.click_listeners;
|
||||
let drag_listener = self.drag_listener;
|
||||
let click_listeners = mem::take(&mut self.click_listeners);
|
||||
let drag_listener = mem::take(&mut self.drag_listener);
|
||||
|
||||
if !click_listeners.is_empty() || drag_listener.is_some() {
|
||||
let pending_mouse_down = element_state
|
||||
|
@ -1267,23 +1390,26 @@ impl Interactivity {
|
|||
.as_ref()
|
||||
.map(|scroll_offset| *scroll_offset.borrow());
|
||||
|
||||
let key_down_listeners = mem::take(&mut self.key_down_listeners);
|
||||
let key_up_listeners = mem::take(&mut self.key_up_listeners);
|
||||
let action_listeners = mem::take(&mut self.action_listeners);
|
||||
cx.with_key_dispatch(
|
||||
self.key_context.clone(),
|
||||
element_state.focus_handle.clone(),
|
||||
|_, cx| {
|
||||
for listener in self.key_down_listeners {
|
||||
for listener in key_down_listeners {
|
||||
cx.on_key_event(move |event: &KeyDownEvent, phase, cx| {
|
||||
listener(event, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.key_up_listeners {
|
||||
for listener in key_up_listeners {
|
||||
cx.on_key_event(move |event: &KeyUpEvent, phase, cx| {
|
||||
listener(event, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for (action_type, listener) in self.action_listeners {
|
||||
for (action_type, listener) in action_listeners {
|
||||
cx.on_action(action_type, listener)
|
||||
}
|
||||
|
||||
|
@ -1522,7 +1648,7 @@ where
|
|||
self.element.layout(state, cx)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
self.element.paint(bounds, state, cx)
|
||||
}
|
||||
}
|
||||
|
@ -1596,7 +1722,7 @@ where
|
|||
self.element.layout(state, cx)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
self.element.paint(bounds, state, cx)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -81,11 +81,12 @@ impl Element for Img {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
let source = self.source.clone();
|
||||
self.interactivity.paint(
|
||||
bounds,
|
||||
bounds.size,
|
||||
|
@ -94,7 +95,7 @@ impl Element for Img {
|
|||
|style, _scroll_offset, cx| {
|
||||
let corner_radii = style.corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||
cx.with_z_index(1, |cx| {
|
||||
match self.source {
|
||||
match source {
|
||||
ImageSource::Uri(uri) => {
|
||||
let image_future = cx.image_cache.get(uri.clone());
|
||||
if let Some(data) = image_future
|
||||
|
|
|
@ -257,7 +257,7 @@ impl Element for List {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: crate::Bounds<crate::Pixels>,
|
||||
_state: &mut Self::State,
|
||||
cx: &mut crate::WindowContext,
|
||||
|
@ -385,7 +385,7 @@ impl Element for List {
|
|||
// Paint the visible items
|
||||
let mut item_origin = bounds.origin;
|
||||
item_origin.y -= scroll_top.offset_in_item;
|
||||
for mut item_element in item_elements {
|
||||
for item_element in &mut item_elements {
|
||||
let item_height = item_element.measure(available_item_space, cx).height;
|
||||
item_element.draw(item_origin, available_item_space, cx);
|
||||
item_origin.y += item_height;
|
||||
|
|
|
@ -81,7 +81,7 @@ impl Element for Overlay {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: crate::Bounds<crate::Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -149,7 +149,7 @@ impl Element for Overlay {
|
|||
|
||||
cx.with_element_offset(desired.origin - bounds.origin, |cx| {
|
||||
cx.break_content_mask(|cx| {
|
||||
for child in self.children {
|
||||
for child in &mut self.children {
|
||||
child.paint(cx);
|
||||
}
|
||||
})
|
||||
|
|
|
@ -36,8 +36,12 @@ impl Element for Svg {
|
|||
})
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, element_state: &mut Self::State, cx: &mut WindowContext)
|
||||
where
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
self.interactivity
|
||||
|
|
|
@ -6,7 +6,7 @@ use crate::{
|
|||
use anyhow::anyhow;
|
||||
use parking_lot::{Mutex, MutexGuard};
|
||||
use smallvec::SmallVec;
|
||||
use std::{cell::Cell, ops::Range, rc::Rc, sync::Arc};
|
||||
use std::{cell::Cell, mem, ops::Range, rc::Rc, sync::Arc};
|
||||
use util::ResultExt;
|
||||
|
||||
impl Element for &'static str {
|
||||
|
@ -22,7 +22,7 @@ impl Element for &'static str {
|
|||
(layout_id, state)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
state.paint(bounds, self, cx)
|
||||
}
|
||||
}
|
||||
|
@ -52,7 +52,7 @@ impl Element for SharedString {
|
|||
(layout_id, state)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut TextState, cx: &mut WindowContext) {
|
||||
let text_str: &str = self.as_ref();
|
||||
state.paint(bounds, text_str, cx)
|
||||
}
|
||||
|
@ -128,7 +128,7 @@ impl Element for StyledText {
|
|||
(layout_id, state)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
state.paint(bounds, &self.text, cx)
|
||||
}
|
||||
}
|
||||
|
@ -356,8 +356,8 @@ impl Element for InteractiveText {
|
|||
}
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
if let Some(click_listener) = self.click_listener {
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
if let Some(click_listener) = self.click_listener.take() {
|
||||
if let Some(ix) = state
|
||||
.text_state
|
||||
.index_for_position(bounds, cx.mouse_position())
|
||||
|
@ -374,13 +374,14 @@ impl Element for InteractiveText {
|
|||
let text_state = state.text_state.clone();
|
||||
let mouse_down = state.mouse_down_index.clone();
|
||||
if let Some(mouse_down_index) = mouse_down.get() {
|
||||
let clickable_ranges = mem::take(&mut self.clickable_ranges);
|
||||
cx.on_mouse_event(move |event: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
if let Some(mouse_up_index) =
|
||||
text_state.index_for_position(bounds, event.position)
|
||||
{
|
||||
click_listener(
|
||||
&self.clickable_ranges,
|
||||
&clickable_ranges,
|
||||
InteractiveTextClickEvent {
|
||||
mouse_down_index,
|
||||
mouse_up_index,
|
||||
|
|
|
@ -155,7 +155,7 @@ impl Element for UniformList {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: Bounds<crate::Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
|
@ -220,11 +220,11 @@ impl Element for UniformList {
|
|||
let visible_range = first_visible_element_ix
|
||||
..cmp::min(last_visible_element_ix, self.item_count);
|
||||
|
||||
let items = (self.render_items)(visible_range.clone(), cx);
|
||||
let mut items = (self.render_items)(visible_range.clone(), cx);
|
||||
cx.with_z_index(1, |cx| {
|
||||
let content_mask = ContentMask { bounds };
|
||||
cx.with_content_mask(Some(content_mask), |cx| {
|
||||
for (item, ix) in items.into_iter().zip(visible_range) {
|
||||
for (item, ix) in items.iter_mut().zip(visible_range) {
|
||||
let item_origin = padded_bounds.origin
|
||||
+ point(px(0.), item_height * ix + scroll_offset.y);
|
||||
let available_space = size(
|
||||
|
|
|
@ -90,7 +90,7 @@ impl<V: Render> Element for View<V> {
|
|||
(layout_id, Some(element))
|
||||
}
|
||||
|
||||
fn paint(self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, _: Bounds<Pixels>, element: &mut Self::State, cx: &mut WindowContext) {
|
||||
element.take().unwrap().paint(cx);
|
||||
}
|
||||
}
|
||||
|
@ -170,7 +170,7 @@ impl<V> Eq for WeakView<V> {}
|
|||
pub struct AnyView {
|
||||
model: AnyModel,
|
||||
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
|
||||
paint: fn(&AnyView, AnyElement, &mut WindowContext),
|
||||
paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
|
||||
}
|
||||
|
||||
impl AnyView {
|
||||
|
@ -209,7 +209,7 @@ impl AnyView {
|
|||
) {
|
||||
cx.with_absolute_element_offset(origin, |cx| {
|
||||
let start_time = std::time::Instant::now();
|
||||
let (layout_id, rendered_element) = (self.layout)(self, cx);
|
||||
let (layout_id, mut rendered_element) = (self.layout)(self, cx);
|
||||
let duration = start_time.elapsed();
|
||||
println!("request layout: {:?}", duration);
|
||||
|
||||
|
@ -219,7 +219,7 @@ impl AnyView {
|
|||
println!("compute layout: {:?}", duration);
|
||||
|
||||
let start_time = std::time::Instant::now();
|
||||
(self.paint)(self, rendered_element, cx);
|
||||
(self.paint)(self, &mut rendered_element, cx);
|
||||
let duration = start_time.elapsed();
|
||||
println!("paint: {:?}", duration);
|
||||
})
|
||||
|
@ -248,12 +248,12 @@ impl Element for AnyView {
|
|||
(layout_id, Some(state))
|
||||
}
|
||||
|
||||
fn paint(self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
fn paint(&mut self, _: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext) {
|
||||
debug_assert!(
|
||||
state.is_some(),
|
||||
"state is None. Did you include an AnyView twice in the tree?"
|
||||
);
|
||||
(self.paint)(&self, state.take().unwrap(), cx)
|
||||
(self.paint)(&self, state.as_mut().unwrap(), cx)
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,7 @@ impl IntoElement for AnyView {
|
|||
pub struct AnyWeakView {
|
||||
model: AnyWeakModel,
|
||||
layout: fn(&AnyView, &mut WindowContext) -> (LayoutId, AnyElement),
|
||||
paint: fn(&AnyView, AnyElement, &mut WindowContext),
|
||||
paint: fn(&AnyView, &mut AnyElement, &mut WindowContext),
|
||||
}
|
||||
|
||||
impl AnyWeakView {
|
||||
|
@ -335,7 +335,7 @@ mod any_view {
|
|||
|
||||
pub(crate) fn paint<V: 'static + Render>(
|
||||
_view: &AnyView,
|
||||
element: AnyElement,
|
||||
element: &mut AnyElement,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
element.paint(cx);
|
||||
|
|
|
@ -2,8 +2,8 @@ use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
|
|||
use gpui::{
|
||||
black, div, fill, point, px, red, relative, AnyElement, AsyncWindowContext, AvailableSpace,
|
||||
Bounds, DispatchPhase, Element, ElementId, ExternalPaths, FocusHandle, Font, FontStyle,
|
||||
FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState, IntoElement,
|
||||
LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels,
|
||||
FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState, Interactivity,
|
||||
IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels,
|
||||
PlatformInputHandler, Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled,
|
||||
TextRun, TextStyle, TextSystem, UnderlineStyle, WhiteSpace, WindowContext,
|
||||
};
|
||||
|
@ -145,11 +145,11 @@ pub struct TerminalElement {
|
|||
focused: bool,
|
||||
cursor_visible: bool,
|
||||
can_navigate_to_selected_word: bool,
|
||||
interactivity: gpui::Interactivity,
|
||||
interactivity: Interactivity,
|
||||
}
|
||||
|
||||
impl InteractiveElement for TerminalElement {
|
||||
fn interactivity(&mut self) -> &mut gpui::Interactivity {
|
||||
fn interactivity(&mut self) -> &mut Interactivity {
|
||||
&mut self.interactivity
|
||||
}
|
||||
}
|
||||
|
@ -605,141 +605,157 @@ impl TerminalElement {
|
|||
}
|
||||
|
||||
fn register_mouse_listeners(
|
||||
self,
|
||||
&mut self,
|
||||
origin: Point<Pixels>,
|
||||
mode: TermMode,
|
||||
bounds: Bounds<Pixels>,
|
||||
cx: &mut WindowContext,
|
||||
) -> Self {
|
||||
) {
|
||||
let focus = self.focus.clone();
|
||||
let connection = self.terminal.clone();
|
||||
let terminal = self.terminal.clone();
|
||||
|
||||
let mut this = self
|
||||
.on_mouse_down(MouseButton::Left, {
|
||||
let connection = connection.clone();
|
||||
let focus = focus.clone();
|
||||
move |e, cx| {
|
||||
cx.focus(&focus);
|
||||
//todo!(context menu)
|
||||
// v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
|
||||
connection.update(cx, |terminal, cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
self.interactivity.on_mouse_down(MouseButton::Left, {
|
||||
let terminal = terminal.clone();
|
||||
let focus = focus.clone();
|
||||
move |e, cx| {
|
||||
cx.focus(&focus);
|
||||
//todo!(context menu)
|
||||
// v.context_menu.update(cx, |menu, _cx| menu.delay_cancel());
|
||||
terminal.update(cx, |terminal, cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
});
|
||||
self.interactivity.on_mouse_move({
|
||||
let terminal = terminal.clone();
|
||||
let focus = focus.clone();
|
||||
move |e, cx| {
|
||||
if e.pressed_button.is_some() && focus.is_focused(cx) && !cx.has_active_drag() {
|
||||
terminal.update(cx, |terminal, cx| {
|
||||
terminal.mouse_drag(e, origin, bounds);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
})
|
||||
.on_mouse_move({
|
||||
let connection = connection.clone();
|
||||
let focus = focus.clone();
|
||||
move |e, cx| {
|
||||
if e.pressed_button.is_some() && focus.is_focused(cx) && !cx.has_active_drag() {
|
||||
connection.update(cx, |terminal, cx| {
|
||||
terminal.mouse_drag(e, origin, bounds);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
});
|
||||
self.interactivity.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
TerminalElement::generic_button_handler(
|
||||
terminal.clone(),
|
||||
origin,
|
||||
focus.clone(),
|
||||
move |terminal, origin, e, cx| {
|
||||
terminal.mouse_up(&e, origin, cx);
|
||||
},
|
||||
),
|
||||
);
|
||||
self.interactivity.on_click({
|
||||
let terminal = terminal.clone();
|
||||
move |e, cx| {
|
||||
if e.down.button == MouseButton::Right {
|
||||
let mouse_mode = terminal.update(cx, |terminal, _cx| {
|
||||
terminal.mouse_mode(e.down.modifiers.shift)
|
||||
});
|
||||
|
||||
if !mouse_mode {
|
||||
//todo!(context menu)
|
||||
// view.deploy_context_menu(e.position, cx);
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_mouse_up(
|
||||
MouseButton::Left,
|
||||
}
|
||||
});
|
||||
|
||||
self.interactivity.on_mouse_move({
|
||||
let terminal = terminal.clone();
|
||||
let focus = focus.clone();
|
||||
move |e, cx| {
|
||||
if focus.is_focused(cx) {
|
||||
terminal.update(cx, |terminal, cx| {
|
||||
terminal.mouse_move(&e, origin);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
}
|
||||
});
|
||||
self.interactivity.on_scroll_wheel({
|
||||
let terminal = terminal.clone();
|
||||
move |e, cx| {
|
||||
terminal.update(cx, |terminal, cx| {
|
||||
terminal.scroll_wheel(e, origin);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
self.interactivity.on_drop::<ExternalPaths>({
|
||||
let focus = focus.clone();
|
||||
let terminal = terminal.clone();
|
||||
move |external_paths, cx| {
|
||||
cx.focus(&focus);
|
||||
let mut new_text = external_paths
|
||||
.read(cx)
|
||||
.paths()
|
||||
.iter()
|
||||
.map(|path| format!(" {path:?}"))
|
||||
.join("");
|
||||
new_text.push(' ');
|
||||
terminal.update(cx, |terminal, _| {
|
||||
// todo!() long paths are not displayed properly albeit the text is there
|
||||
terminal.paste(&new_text);
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// Mouse mode handlers:
|
||||
// All mouse modes need the extra click handlers
|
||||
if mode.intersects(TermMode::MOUSE_MODE) {
|
||||
self.interactivity.on_mouse_down(
|
||||
MouseButton::Right,
|
||||
TerminalElement::generic_button_handler(
|
||||
connection.clone(),
|
||||
terminal.clone(),
|
||||
origin,
|
||||
focus.clone(),
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
},
|
||||
),
|
||||
);
|
||||
self.interactivity.on_mouse_down(
|
||||
MouseButton::Middle,
|
||||
TerminalElement::generic_button_handler(
|
||||
terminal.clone(),
|
||||
origin,
|
||||
focus.clone(),
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
},
|
||||
),
|
||||
);
|
||||
self.interactivity.on_mouse_up(
|
||||
MouseButton::Right,
|
||||
TerminalElement::generic_button_handler(
|
||||
terminal.clone(),
|
||||
origin,
|
||||
focus.clone(),
|
||||
move |terminal, origin, e, cx| {
|
||||
terminal.mouse_up(&e, origin, cx);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_click({
|
||||
let connection = connection.clone();
|
||||
move |e, cx| {
|
||||
if e.down.button == MouseButton::Right {
|
||||
let mouse_mode = connection.update(cx, |terminal, _cx| {
|
||||
terminal.mouse_mode(e.down.modifiers.shift)
|
||||
});
|
||||
|
||||
if !mouse_mode {
|
||||
//todo!(context menu)
|
||||
// view.deploy_context_menu(e.position, cx);
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_mouse_move({
|
||||
let connection = connection.clone();
|
||||
let focus = focus.clone();
|
||||
move |e, cx| {
|
||||
if focus.is_focused(cx) {
|
||||
connection.update(cx, |terminal, cx| {
|
||||
terminal.mouse_move(&e, origin);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
.on_scroll_wheel({
|
||||
let connection = connection.clone();
|
||||
move |e, cx| {
|
||||
connection.update(cx, |terminal, cx| {
|
||||
terminal.scroll_wheel(e, origin);
|
||||
cx.notify();
|
||||
})
|
||||
}
|
||||
});
|
||||
|
||||
// Mouse mode handlers:
|
||||
// All mouse modes need the extra click handlers
|
||||
if mode.intersects(TermMode::MOUSE_MODE) {
|
||||
this = this
|
||||
.on_mouse_down(
|
||||
MouseButton::Right,
|
||||
TerminalElement::generic_button_handler(
|
||||
connection.clone(),
|
||||
origin,
|
||||
focus.clone(),
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_mouse_down(
|
||||
MouseButton::Middle,
|
||||
TerminalElement::generic_button_handler(
|
||||
connection.clone(),
|
||||
origin,
|
||||
focus.clone(),
|
||||
move |terminal, origin, e, _cx| {
|
||||
terminal.mouse_down(&e, origin);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_mouse_up(
|
||||
MouseButton::Right,
|
||||
TerminalElement::generic_button_handler(
|
||||
connection.clone(),
|
||||
origin,
|
||||
focus.clone(),
|
||||
move |terminal, origin, e, cx| {
|
||||
terminal.mouse_up(&e, origin, cx);
|
||||
},
|
||||
),
|
||||
)
|
||||
.on_mouse_up(
|
||||
MouseButton::Middle,
|
||||
TerminalElement::generic_button_handler(
|
||||
connection,
|
||||
origin,
|
||||
focus,
|
||||
move |terminal, origin, e, cx| {
|
||||
terminal.mouse_up(&e, origin, cx);
|
||||
},
|
||||
),
|
||||
)
|
||||
);
|
||||
self.interactivity.on_mouse_up(
|
||||
MouseButton::Middle,
|
||||
TerminalElement::generic_button_handler(
|
||||
terminal,
|
||||
origin,
|
||||
focus,
|
||||
move |terminal, origin, e, cx| {
|
||||
terminal.mouse_up(&e, origin, cx);
|
||||
},
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
this
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -764,7 +780,12 @@ impl Element for TerminalElement {
|
|||
(layout_id, interactive_state)
|
||||
}
|
||||
|
||||
fn paint(self, bounds: Bounds<Pixels>, state: &mut Self::State, cx: &mut WindowContext<'_>) {
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
state: &mut Self::State,
|
||||
cx: &mut WindowContext<'_>,
|
||||
) {
|
||||
let mut layout = self.compute_layout(bounds, cx);
|
||||
|
||||
let theme = cx.theme();
|
||||
|
@ -783,33 +804,19 @@ impl Element for TerminalElement {
|
|||
|
||||
let terminal_focus_handle = self.focus.clone();
|
||||
let terminal_handle = self.terminal.clone();
|
||||
let mut this: TerminalElement = self
|
||||
.register_mouse_listeners(origin, layout.mode, bounds, cx)
|
||||
.drag_over::<ExternalPaths>(|style| {
|
||||
// todo!() why does not it work? z-index of elements?
|
||||
style.bg(cx.theme().colors().ghost_element_hover)
|
||||
})
|
||||
.on_drop::<ExternalPaths>(move |external_paths, cx| {
|
||||
cx.focus(&terminal_focus_handle);
|
||||
let mut new_text = external_paths
|
||||
.read(cx)
|
||||
.paths()
|
||||
.iter()
|
||||
.map(|path| format!(" {path:?}"))
|
||||
.join("");
|
||||
new_text.push(' ');
|
||||
terminal_handle.update(cx, |terminal, _| {
|
||||
// todo!() long paths are not displayed properly albeit the text is there
|
||||
terminal.paste(&new_text);
|
||||
});
|
||||
});
|
||||
self.register_mouse_listeners(origin, layout.mode, bounds, cx);
|
||||
|
||||
let interactivity = mem::take(&mut this.interactivity);
|
||||
// todo!(change this to work in terms of on_drag_move or some such)
|
||||
// .drag_over::<ExternalPaths>(|style| {
|
||||
// // todo!() why does not it work? z-index of elements?
|
||||
// style.bg(cx.theme().colors().ghost_element_hover)
|
||||
// })
|
||||
|
||||
let mut interactivity = mem::take(&mut self.interactivity);
|
||||
interactivity.paint(bounds, bounds.size, state, cx, |_, _, cx| {
|
||||
cx.handle_input(&this.focus, terminal_input_handler);
|
||||
cx.handle_input(&self.focus, terminal_input_handler);
|
||||
|
||||
this.register_key_listeners(cx);
|
||||
self.register_key_listeners(cx);
|
||||
|
||||
for rect in &layout.rects {
|
||||
rect.paint(origin, &layout, cx);
|
||||
|
@ -840,7 +847,7 @@ impl Element for TerminalElement {
|
|||
}
|
||||
});
|
||||
|
||||
if this.cursor_visible {
|
||||
if self.cursor_visible {
|
||||
cx.with_z_index(3, |cx| {
|
||||
if let Some(cursor) = &layout.cursor {
|
||||
cursor.paint(origin, cx);
|
||||
|
@ -848,7 +855,7 @@ impl Element for TerminalElement {
|
|||
});
|
||||
}
|
||||
|
||||
if let Some(element) = layout.hyperlink_tooltip.take() {
|
||||
if let Some(mut element) = layout.hyperlink_tooltip.take() {
|
||||
let width: AvailableSpace = bounds.size.width.into();
|
||||
let height: AvailableSpace = bounds.size.height.into();
|
||||
element.draw(origin, Size { width, height }, cx)
|
||||
|
|
|
@ -182,12 +182,12 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
_: Bounds<gpui::Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
if let Some(child) = element_state.child_element.take() {
|
||||
if let Some(mut child) = element_state.child_element.take() {
|
||||
child.paint(cx);
|
||||
}
|
||||
|
||||
|
@ -195,7 +195,7 @@ impl<M: ManagedView> Element for PopoverMenu<M> {
|
|||
element_state.child_bounds = Some(cx.layout_bounds(child_layout_id));
|
||||
}
|
||||
|
||||
if let Some(menu) = element_state.menu_element.take() {
|
||||
if let Some(mut menu) = element_state.menu_element.take() {
|
||||
menu.paint(cx);
|
||||
|
||||
if let Some(child_bounds) = element_state.child_bounds {
|
||||
|
|
|
@ -112,21 +112,21 @@ impl<M: ManagedView> Element for RightClickMenu<M> {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: Bounds<gpui::Pixels>,
|
||||
element_state: &mut Self::State,
|
||||
cx: &mut WindowContext,
|
||||
) {
|
||||
if let Some(child) = element_state.child_element.take() {
|
||||
if let Some(mut child) = element_state.child_element.take() {
|
||||
child.paint(cx);
|
||||
}
|
||||
|
||||
if let Some(menu) = element_state.menu_element.take() {
|
||||
if let Some(mut menu) = element_state.menu_element.take() {
|
||||
menu.paint(cx);
|
||||
return;
|
||||
}
|
||||
|
||||
let Some(builder) = self.menu_builder else {
|
||||
let Some(builder) = self.menu_builder.take() else {
|
||||
return;
|
||||
};
|
||||
let menu = element_state.menu.clone();
|
||||
|
|
|
@ -896,7 +896,7 @@ mod element {
|
|||
}
|
||||
|
||||
fn paint(
|
||||
self,
|
||||
&mut self,
|
||||
bounds: gpui::Bounds<ui::prelude::Pixels>,
|
||||
state: &mut Self::State,
|
||||
cx: &mut ui::prelude::WindowContext,
|
||||
|
@ -912,7 +912,7 @@ mod element {
|
|||
let mut bounding_boxes = self.bounding_boxes.lock();
|
||||
bounding_boxes.clear();
|
||||
|
||||
for (ix, child) in self.children.into_iter().enumerate() {
|
||||
for (ix, mut child) in self.children.iter_mut().enumerate() {
|
||||
//todo!(active_pane_magnification)
|
||||
// If usign active pane magnification, need to switch to using
|
||||
// 1 for all non-active panes, and then the magnification for the
|
||||
|
|
Loading…
Reference in a new issue