Detailed changes
@@ -17,7 +17,7 @@ impl RenderOnce for FacePile {
let isnt_last = ix < player_count - 1;
div()
- .z_index((player_count - ix) as u32)
+ .z_index((player_count - ix) as u8)
.when(isnt_last, |div| div.neg_mr_1())
.child(player)
});
@@ -933,7 +933,7 @@ impl EditorElement {
cx.stop_propagation();
},
))
- .draw(
+ .draw_and_update_state(
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 draw_and_update_state<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,10 @@ impl Element for Canvas {
(layout_id, style)
}
- fn paint(self, bounds: Bounds<Pixels>, style: &mut Style, cx: &mut WindowContext) {
- style.paint(bounds, cx, |cx| (self.paint_callback)(&bounds, cx));
+ fn paint(&mut self, bounds: Bounds<Pixels>, style: &mut Style, cx: &mut WindowContext) {
+ style.paint(bounds, cx, |cx| {
+ (self.paint_callback.take().unwrap())(&bounds, cx)
+ });
}
}
@@ -46,6 +46,286 @@ impl<T: 'static> DragMoveEvent<T> {
}
}
+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<T>(
+ &mut self,
+ listener: impl Fn(&DragMoveEvent<T>, &mut WindowContext) + 'static,
+ ) where
+ T: 'static,
+ {
+ self.mouse_move_listeners
+ .push(Box::new(move |event, bounds, phase, cx| {
+ if phase == DispatchPhase::Capture
+ && bounds.drag_target_contains(&event.position, cx)
+ {
+ if cx
+ .active_drag
+ .as_ref()
+ .is_some_and(|drag| drag.value.as_ref().type_id() == TypeId::of::<T>())
+ {
+ (listener)(
+ &DragMoveEvent {
+ event: event.clone(),
+ bounds: bounds.bounds,
+ drag: PhantomData,
+ },
+ 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<T: 'static>(&mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) {
+ self.drop_listeners.push((
+ TypeId::of::<T>(),
+ Box::new(move |dragged_value, cx| {
+ listener(dragged_value.downcast_ref().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<T, W>(
+ &mut self,
+ value: T,
+ constructor: impl Fn(&T, &mut WindowContext) -> View<W> + 'static,
+ ) where
+ Self: Sized,
+ T: 'static,
+ 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(value),
+ Box::new(move |value, cx| constructor(value.downcast_ref().unwrap(), cx).into()),
+ ));
+ }
+
+ 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;
@@ -103,16 +383,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
}
@@ -120,13 +391,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
}
@@ -135,30 +400,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
}
@@ -166,14 +408,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
}
@@ -182,16 +417,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
}
@@ -199,13 +425,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
}
@@ -216,28 +436,7 @@ pub trait InteractiveElement: Sized {
where
T: 'static,
{
- 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 cx
- .active_drag
- .as_ref()
- .is_some_and(|drag| drag.value.as_ref().type_id() == TypeId::of::<T>())
- {
- (listener)(
- &DragMoveEvent {
- event: event.clone(),
- bounds: bounds.bounds,
- drag: PhantomData,
- },
- cx,
- );
- }
- }
- },
- ));
+ self.interactivity().on_drag_move(listener);
self
}
@@ -245,13 +444,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
}
@@ -260,29 +453,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
}
@@ -291,15 +468,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
}
@@ -307,13 +476,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
}
@@ -321,24 +484,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
}
@@ -346,13 +497,7 @@ 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
}
@@ -379,12 +524,7 @@ pub trait InteractiveElement: Sized {
}
fn on_drop<T: 'static>(mut self, listener: impl Fn(&T, &mut WindowContext) + 'static) -> Self {
- self.interactivity().drop_listeners.push((
- TypeId::of::<T>(),
- Box::new(move |dragged_value, cx| {
- listener(dragged_value.downcast_ref().unwrap(), cx);
- }),
- ));
+ self.interactivity().on_drop(listener);
self
}
}
@@ -443,9 +583,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
}
@@ -459,14 +597,7 @@ pub trait StatefulInteractiveElement: InteractiveElement {
T: 'static,
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(value),
- Box::new(move |value, cx| constructor(value.downcast_ref().unwrap(), cx).into()),
- ));
+ self.interactivity().on_drag(value, constructor);
self
}
@@ -474,11 +605,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
}
@@ -486,11 +613,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
}
}
@@ -618,7 +741,7 @@ impl Element for Div {
}
fn paint(
- self,
+ &mut self,
bounds: Bounds<Pixels>,
element_state: &mut Self::State,
cx: &mut WindowContext,
@@ -669,7 +792,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);
}
})
@@ -701,7 +824,10 @@ pub struct DivState {
impl DivState {
pub fn is_active(&self) -> bool {
- self.interactive_state.pending_mouse_down.borrow().is_some()
+ self.interactive_state
+ .pending_mouse_down
+ .as_ref()
+ .map_or(false, |pending| pending.borrow().is_some())
}
}
@@ -786,7 +912,7 @@ impl Interactivity {
}
pub fn paint(
- mut self,
+ &mut self,
bounds: Bounds<Pixels>,
content_size: Size<Pixels>,
element_state: &mut InteractiveElementState,
@@ -805,7 +931,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| {
@@ -918,10 +1044,10 @@ impl Interactivity {
cx.with_z_index(style.z_index.unwrap_or(0), |cx| cx.add_opaque_layer(bounds))
}
- let interactive_bounds = Rc::new(InteractiveBounds {
+ let interactive_bounds = InteractiveBounds {
bounds: bounds.intersect(&cx.content_mask().bounds),
stacking_order: cx.stacking_order().clone(),
- });
+ };
if let Some(mouse_cursor) = style.mouse_cursor {
let mouse_position = &cx.mouse_position();
@@ -954,28 +1080,28 @@ impl Interactivity {
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);
+ listener(event, &interactive_bounds, phase, cx);
})
}
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);
+ listener(event, &interactive_bounds, phase, cx);
})
}
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);
+ listener(event, &interactive_bounds, phase, cx);
})
}
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);
+ listener(event, &interactive_bounds, phase, cx);
})
}
@@ -1047,11 +1173,17 @@ impl Interactivity {
let mut drag_listener = mem::take(&mut self.drag_listener);
if !click_listeners.is_empty() || drag_listener.is_some() {
- let pending_mouse_down = element_state.pending_mouse_down.clone();
+ let pending_mouse_down = element_state
+ .pending_mouse_down
+ .get_or_insert_with(Default::default)
+ .clone();
let mouse_down = pending_mouse_down.borrow().clone();
if let Some(mouse_down) = mouse_down {
if drag_listener.is_some() {
- let active_state = element_state.clicked_state.clone();
+ let active_state = element_state
+ .clicked_state
+ .get_or_insert_with(Default::default)
+ .clone();
let interactive_bounds = interactive_bounds.clone();
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
@@ -1112,8 +1244,14 @@ impl Interactivity {
}
if let Some(hover_listener) = self.hover_listener.take() {
- let was_hovered = element_state.hover_state.clone();
- let has_mouse_down = element_state.pending_mouse_down.clone();
+ let was_hovered = element_state
+ .hover_state
+ .get_or_insert_with(Default::default)
+ .clone();
+ let has_mouse_down = element_state
+ .pending_mouse_down
+ .get_or_insert_with(Default::default)
+ .clone();
let interactive_bounds = interactive_bounds.clone();
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
@@ -1134,8 +1272,14 @@ impl Interactivity {
}
if let Some(tooltip_builder) = self.tooltip_builder.take() {
- let active_tooltip = element_state.active_tooltip.clone();
- let pending_mouse_down = element_state.pending_mouse_down.clone();
+ let active_tooltip = element_state
+ .active_tooltip
+ .get_or_insert_with(Default::default)
+ .clone();
+ let pending_mouse_down = element_state
+ .pending_mouse_down
+ .get_or_insert_with(Default::default)
+ .clone();
let interactive_bounds = interactive_bounds.clone();
cx.on_mouse_event(move |event: &MouseMoveEvent, phase, cx| {
@@ -1177,19 +1321,30 @@ impl Interactivity {
}
});
- let active_tooltip = element_state.active_tooltip.clone();
+ let active_tooltip = element_state
+ .active_tooltip
+ .get_or_insert_with(Default::default)
+ .clone();
cx.on_mouse_event(move |_: &MouseDownEvent, _, _| {
active_tooltip.borrow_mut().take();
});
- if let Some(active_tooltip) = element_state.active_tooltip.borrow().as_ref() {
+ if let Some(active_tooltip) = element_state
+ .active_tooltip
+ .get_or_insert_with(Default::default)
+ .borrow()
+ .as_ref()
+ {
if active_tooltip.tooltip.is_some() {
cx.active_tooltip = active_tooltip.tooltip.clone()
}
}
}
- let active_state = element_state.clicked_state.clone();
+ let active_state = element_state
+ .clicked_state
+ .get_or_insert_with(Default::default)
+ .clone();
if active_state.borrow().is_clicked() {
cx.on_mouse_event(move |_: &MouseUpEvent, phase, cx| {
if phase == DispatchPhase::Capture {
@@ -1265,23 +1420,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.drain(..) {
+ 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.drain(..) {
+ 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)
}
@@ -1368,7 +1526,10 @@ impl Interactivity {
}
}
- let clicked_state = element_state.clicked_state.borrow();
+ let clicked_state = element_state
+ .clicked_state
+ .get_or_insert_with(Default::default)
+ .borrow();
if clicked_state.group {
if let Some(group) = self.group_active_style.as_ref() {
style.refine(&group.style)
@@ -1427,11 +1588,11 @@ impl Default for Interactivity {
#[derive(Default)]
pub struct InteractiveElementState {
pub focus_handle: Option<FocusHandle>,
- pub clicked_state: Rc<RefCell<ElementClickedState>>,
- pub hover_state: Rc<RefCell<bool>>,
- pub pending_mouse_down: Rc<RefCell<Option<MouseDownEvent>>>,
+ pub clicked_state: Option<Rc<RefCell<ElementClickedState>>>,
+ pub hover_state: Option<Rc<RefCell<bool>>>,
+ pub pending_mouse_down: Option<Rc<RefCell<Option<MouseDownEvent>>>>,
pub scroll_offset: Option<Rc<RefCell<Point<Pixels>>>>,
- pub active_tooltip: Rc<RefCell<Option<ActiveTooltip>>>,
+ pub active_tooltip: Option<Rc<RefCell<Option<ActiveTooltip>>>>,
}
pub struct ActiveTooltip {
@@ -1517,7 +1678,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)
}
}
@@ -1591,7 +1752,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(
@@ -187,6 +187,8 @@ impl MetalRenderer {
}
pub fn draw(&mut self, scene: &Scene) {
+ let start = std::time::Instant::now();
+
let layer = self.layer.clone();
let viewport_size = layer.drawable_size();
let viewport_size: Size<DevicePixels> = size(
@@ -303,6 +305,10 @@ impl MetalRenderer {
command_buffer.commit();
self.sprite_atlas.clear_textures(AtlasTextureKind::Path);
+
+ let duration_since_start = start.elapsed();
+ println!("renderer draw: {:?}", duration_since_start);
+
command_buffer.wait_until_completed();
drawable.present();
}
@@ -110,7 +110,7 @@ pub struct Style {
/// The mouse cursor style shown when the mouse pointer is over an element.
pub mouse_cursor: Option<CursorStyle>,
- pub z_index: Option<u32>,
+ pub z_index: Option<u8>,
#[cfg(debug_assertions)]
pub debug: bool,
@@ -12,7 +12,7 @@ pub trait Styled: Sized {
gpui2_macros::style_helpers!();
- fn z_index(mut self, z_index: u32) -> Self {
+ fn z_index(mut self, z_index: u8) -> Self {
self.style().z_index = Some(z_index);
self
}
@@ -91,7 +91,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);
}
}
@@ -171,7 +171,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,9 +209,20 @@ impl AnyView {
cx: &mut WindowContext,
) {
cx.with_absolute_element_offset(origin, |cx| {
- let (layout_id, rendered_element) = (self.layout)(self, cx);
+ let start_time = std::time::Instant::now();
+ let (layout_id, mut rendered_element) = (self.layout)(self, cx);
+ let duration = start_time.elapsed();
+ println!("request layout: {:?}", duration);
+
+ let start_time = std::time::Instant::now();
cx.compute_layout(layout_id, available_space);
- (self.paint)(self, rendered_element, cx);
+ let duration = start_time.elapsed();
+ println!("compute layout: {:?}", duration);
+
+ let start_time = std::time::Instant::now();
+ (self.paint)(self, &mut rendered_element, cx);
+ let duration = start_time.elapsed();
+ println!("paint: {:?}", duration);
})
}
}
@@ -238,12 +249,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)
}
}
@@ -274,7 +285,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 {
@@ -339,7 +350,7 @@ mod any_view {
pub(crate) fn paint<V: 'static + Render>(
_view: &AnyView,
- element: AnyElement,
+ element: &mut AnyElement,
cx: &mut WindowContext,
) {
element.paint(cx);
@@ -12,7 +12,7 @@ use crate::{
UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::{anyhow, Context as _, Result};
-use collections::HashMap;
+use collections::FxHashMap;
use derive_more::{Deref, DerefMut};
use futures::{
channel::{mpsc, oneshot},
@@ -38,12 +38,24 @@ use std::{
};
use util::ResultExt;
-const ACTIVE_DRAG_Z_INDEX: u32 = 1;
+const ACTIVE_DRAG_Z_INDEX: u8 = 1;
/// A global stacking order, which is created by stacking successive z-index values.
/// Each z-index will always be interpreted in the context of its parent z-index.
-#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default, Debug)]
-pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
+#[derive(Deref, DerefMut, Clone, Debug, Ord, PartialOrd, PartialEq, Eq)]
+pub struct StackingOrder {
+ #[deref]
+ #[deref_mut]
+ z_indices: SmallVec<[u8; 64]>,
+}
+
+impl Default for StackingOrder {
+ fn default() -> Self {
+ StackingOrder {
+ z_indices: SmallVec::new(),
+ }
+ }
+}
/// Represents the two different phases when dispatching events.
#[derive(Default, Copy, Clone, Debug, Eq, PartialEq)]
@@ -238,6 +250,7 @@ pub struct Window {
bounds_observers: SubscriberSet<(), AnyObserver>,
active: bool,
pub(crate) dirty: bool,
+ pub(crate) drawing: bool,
activation_observers: SubscriberSet<(), AnyObserver>,
pub(crate) last_blur: Option<Option<FocusId>>,
pub(crate) focus: Option<FocusId>,
@@ -251,8 +264,8 @@ pub(crate) struct ElementStateBox {
// #[derive(Default)]
pub(crate) struct Frame {
- pub(crate) element_states: HashMap<GlobalElementId, ElementStateBox>,
- mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>,
+ pub(crate) element_states: FxHashMap<GlobalElementId, ElementStateBox>,
+ mouse_listeners: FxHashMap<TypeId, Vec<(StackingOrder, AnyMouseListener)>>,
pub(crate) dispatch_tree: DispatchTree,
pub(crate) focus_listeners: Vec<AnyFocusListener>,
pub(crate) scene_builder: SceneBuilder,
@@ -265,8 +278,8 @@ pub(crate) struct Frame {
impl Frame {
fn new(dispatch_tree: DispatchTree) -> Self {
Frame {
- element_states: HashMap::default(),
- mouse_listeners: HashMap::default(),
+ element_states: FxHashMap::default(),
+ mouse_listeners: FxHashMap::default(),
dispatch_tree,
focus_listeners: Vec::new(),
scene_builder: SceneBuilder::default(),
@@ -374,6 +387,7 @@ impl Window {
bounds_observers: SubscriberSet::new(),
active: false,
dirty: false,
+ drawing: false,
activation_observers: SubscriberSet::new(),
last_blur: None,
focus: None,
@@ -425,7 +439,9 @@ impl<'a> WindowContext<'a> {
/// Mark the window as dirty, scheduling it to be redrawn on the next frame.
pub fn notify(&mut self) {
- self.window.dirty = true;
+ if !self.window.drawing {
+ self.window.dirty = true;
+ }
}
/// Close this window.
@@ -891,7 +907,7 @@ impl<'a> WindowContext<'a> {
/// Called during painting to invoke the given closure in a new stacking context. The given
/// z-index is interpreted relative to the previous call to `stack`.
- pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
+ pub fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
self.window.next_frame.z_index_stack.push(z_index);
let result = f(self);
self.window.next_frame.z_index_stack.pop();
@@ -1238,6 +1254,10 @@ impl<'a> WindowContext<'a> {
/// Draw pixels to the display for this window based on the contents of its scene.
pub(crate) fn draw(&mut self) -> Scene {
+ let t0 = std::time::Instant::now();
+ self.window.dirty = false;
+ self.window.drawing = true;
+
let window_was_focused = self
.window
.focus
@@ -1327,7 +1347,8 @@ impl<'a> WindowContext<'a> {
self.platform.set_cursor_style(cursor_style);
}
- self.window.dirty = false;
+ self.window.drawing = false;
+ eprintln!("window draw: {:?}", t0.elapsed());
scene
}
@@ -2227,7 +2248,7 @@ impl<'a, V: 'static> ViewContext<'a, V> {
&mut self.window_cx
}
- pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
+ pub fn with_z_index<R>(&mut self, z_index: u8, f: impl FnOnce(&mut Self) -> R) -> R {
self.window.next_frame.z_index_stack.push(z_index);
let result = f(self);
self.window.next_frame.z_index_stack.pop();
@@ -2364,10 +2385,12 @@ impl<'a, V: 'static> ViewContext<'a, V> {
}
pub fn notify(&mut self) {
- self.window_cx.notify();
- self.window_cx.app.push_effect(Effect::Notify {
- emitter: self.view.model.entity_id,
- });
+ if !self.window.drawing {
+ self.window_cx.notify();
+ self.window_cx.app.push_effect(Effect::Notify {
+ emitter: self.view.model.entity_id,
+ });
+ }
}
pub fn observe_window_bounds(
@@ -2902,12 +2925,12 @@ impl AnyWindowHandle {
}
}
-#[cfg(any(test, feature = "test-support"))]
-impl From<SmallVec<[u32; 16]>> for StackingOrder {
- fn from(small_vec: SmallVec<[u32; 16]>) -> Self {
- StackingOrder(small_vec)
- }
-}
+// #[cfg(any(test, feature = "test-support"))]
+// impl From<SmallVec<[u32; 16]>> for StackingOrder {
+// fn from(small_vec: SmallVec<[u32; 16]>) -> Self {
+// StackingOrder(small_vec)
+// }
+// }
#[derive(Clone, Debug, Eq, PartialEq, Hash)]
pub enum ElementId {
@@ -1524,33 +1524,17 @@ impl Render for ProjectSearchBar {
cx,
)
})
- .selected(self.is_option_enabled(SearchOptions::CASE_SENSITIVE, cx))
+ .selected(self.is_option_enabled(SearchOptions::WHOLE_WORD, cx))
.on_click(cx.listener(
|this, _, cx| {
- this.toggle_search_option(
- SearchOptions::CASE_SENSITIVE,
- cx,
- );
+ this.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
},
)),
)
- .child(
- IconButton::new("project-search-whole-word", Icon::WholeWord)
- .tooltip(|cx| {
- Tooltip::for_action(
- "Toggle whole word",
- &ToggleWholeWord,
- cx,
- )
- })
- .selected(self.is_option_enabled(SearchOptions::WHOLE_WORD, cx))
- .on_click(cx.listener(|this, _, cx| {
- this.toggle_search_option(SearchOptions::WHOLE_WORD, cx);
- })),
- )
}),
),
);
+
let mode_column = v_stack().items_start().justify_start().child(
h_stack()
.child(
@@ -78,7 +78,7 @@ impl Styles for Div {}
#[derive(IntoElement)]
struct ZIndexExample {
- z_index: u32,
+ z_index: u8,
}
impl RenderOnce for ZIndexExample {
@@ -170,7 +170,7 @@ impl RenderOnce for ZIndexExample {
}
impl ZIndexExample {
- pub fn new(z_index: u32) -> Self {
+ pub fn new(z_index: u8) -> Self {
Self { z_index }
}
}
@@ -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,156 @@ 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 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);
+ let terminal = self.terminal.clone();
+
+ 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();
- })
- }
- }
- })
- .on_mouse_up(
- MouseButton::Left,
- TerminalElement::generic_button_handler(
- connection.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();
- })
+ }
+ });
+ 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_scroll_wheel({
- let connection = connection.clone();
- move |e, cx| {
- connection.update(cx, |terminal, cx| {
- terminal.scroll_wheel(e, origin);
+ }
+ });
+
+ 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
+ .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) {
- 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_down(
+ MouseButton::Right,
+ TerminalElement::generic_button_handler(
+ 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);
+ },
+ ),
+ );
+ 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 +779,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,32 +803,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
- .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);
@@ -839,7 +846,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);
@@ -847,7 +854,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();
@@ -20,14 +20,14 @@ pub enum ElevationIndex {
}
impl ElevationIndex {
- pub fn z_index(self) -> u32 {
+ pub fn z_index(self) -> u8 {
match self {
ElevationIndex::Background => 0,
- ElevationIndex::Surface => 100,
- ElevationIndex::ElevatedSurface => 200,
- ElevationIndex::Wash => 250,
- ElevationIndex::ModalSurface => 300,
- ElevationIndex::DraggedElement => 900,
+ ElevationIndex::Surface => 42,
+ ElevationIndex::ElevatedSurface => 84,
+ ElevationIndex::Wash => 126,
+ ElevationIndex::ModalSurface => 168,
+ ElevationIndex::DraggedElement => 210,
}
}
@@ -116,7 +116,7 @@ impl Render for ModalLayer {
.size_full()
.top_0()
.left_0()
- .z_index(400)
+ .z_index(169)
.child(
v_stack()
.h(px(0.0))
@@ -890,7 +890,7 @@ mod element {
}
fn paint(
- self,
+ &mut self,
bounds: gpui::Bounds<ui::prelude::Pixels>,
state: &mut Self::State,
cx: &mut ui::prelude::WindowContext,
@@ -906,7 +906,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, 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
@@ -0,0 +1,8 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "https://www.apple.com/DTDs/PropertyList-1.0.dtd">
+<plist version="1.0">
+ <dict>
+ <key>com.apple.security.get-task-allow</key>
+ <true/>
+ </dict>
+</plist>