mirror of
https://github.com/zed-industries/zed.git
synced 2024-12-28 06:03:35 +03:00
Get basic mouse_down and mouse_up working
This commit is contained in:
parent
187d78011c
commit
812d3f6af6
@ -4,7 +4,7 @@ use crate::{
|
||||
text::ArcCow,
|
||||
themes::rose_pine,
|
||||
};
|
||||
use gpui::ViewContext;
|
||||
use gpui::{platform::MouseButton, ViewContext};
|
||||
use playground_macros::Element;
|
||||
use std::{marker::PhantomData, rc::Rc};
|
||||
|
||||
@ -69,7 +69,7 @@ impl<V: 'static, D: 'static> Button<V, D> {
|
||||
|
||||
pub fn click(self, handler: impl Fn(&mut V, &D, &mut ViewContext<V>) + 'static) -> Self {
|
||||
let data = self.data.clone();
|
||||
Element::left_click(self, move |view, _, cx| {
|
||||
Element::click(self, MouseButton::Left, move |view, _, cx| {
|
||||
handler(view, data.as_ref(), cx);
|
||||
})
|
||||
}
|
||||
@ -89,7 +89,9 @@ impl<V: 'static, D: 'static> Button<V, D> {
|
||||
|
||||
if let Some(handler) = self.handlers.click.clone() {
|
||||
let data = self.data.clone();
|
||||
button.left_click(move |view, event, cx| handler(view, data.as_ref(), cx))
|
||||
button.mouse_down(MouseButton::Left, move |view, event, cx| {
|
||||
handler(view, data.as_ref(), cx)
|
||||
})
|
||||
} else {
|
||||
button
|
||||
}
|
||||
|
@ -7,12 +7,12 @@ use anyhow::Result;
|
||||
pub use gpui::LayoutContext;
|
||||
use gpui::{
|
||||
geometry::{DefinedLength, Length},
|
||||
platform::MouseButton,
|
||||
scene::MouseClick,
|
||||
EngineLayout, RenderContext, ViewContext, WindowContext,
|
||||
platform::{MouseButton, MouseButtonEvent},
|
||||
EngineLayout, EventContext, RenderContext, ViewContext,
|
||||
};
|
||||
use playground_macros::tailwind_lengths;
|
||||
use std::{any::Any, rc::Rc};
|
||||
use smallvec::SmallVec;
|
||||
use std::{any::Any, cell::Cell, rc::Rc};
|
||||
|
||||
pub use crate::paint_context::PaintContext;
|
||||
pub use taffy::tree::NodeId;
|
||||
@ -23,7 +23,7 @@ pub struct Layout<'a, E: ?Sized> {
|
||||
}
|
||||
|
||||
pub struct ElementHandlers<V> {
|
||||
click: Option<Rc<dyn Fn(&mut V, MouseClick, &mut WindowContext, usize)>>,
|
||||
mouse_button: SmallVec<[Rc<dyn Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>)>; 2]>,
|
||||
}
|
||||
|
||||
pub struct ElementMetadata<V> {
|
||||
@ -42,7 +42,9 @@ impl<V> Default for ElementMetadata<V> {
|
||||
|
||||
impl<V> Default for ElementHandlers<V> {
|
||||
fn default() -> Self {
|
||||
ElementHandlers { click: None }
|
||||
ElementHandlers {
|
||||
mouse_button: Default::default(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -79,36 +81,62 @@ pub trait Element<V: 'static>: 'static {
|
||||
Adapter(self.into_any())
|
||||
}
|
||||
|
||||
fn left_click(self, handler: impl Fn(&mut V, MouseClick, &mut ViewContext<V>) + 'static) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.click(MouseButton::Left, handler)
|
||||
}
|
||||
|
||||
fn right_click(
|
||||
fn click(
|
||||
self,
|
||||
handler: impl Fn(&mut V, MouseClick, &mut ViewContext<V>) + 'static,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseButtonEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.click(MouseButton::Right, handler)
|
||||
let pressed: Rc<Cell<bool>> = Default::default();
|
||||
self.mouse_down(button, {
|
||||
let pressed = pressed.clone();
|
||||
move |_, _, _| {
|
||||
pressed.set(true);
|
||||
}
|
||||
})
|
||||
.mouse_up(button, move |view, event, event_cx| {
|
||||
if pressed.get() {
|
||||
pressed.set(false);
|
||||
handler(view, event, event_cx);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn click(
|
||||
fn mouse_down(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, MouseClick, &mut ViewContext<V>) + 'static,
|
||||
handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.handlers_mut().click = Some(Rc::new(move |view, event, window_cx, view_id| {
|
||||
if event.button == button {
|
||||
handler(view, event, &mut ViewContext::mutable(window_cx, view_id));
|
||||
}
|
||||
}));
|
||||
self.handlers_mut()
|
||||
.mouse_button
|
||||
.push(Rc::new(move |view, event, event_cx| {
|
||||
if event.button == button && event.is_down {
|
||||
handler(view, event, event_cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn mouse_up(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseButtonEvent, &mut EventContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.handlers_mut()
|
||||
.mouse_button
|
||||
.push(Rc::new(move |view, event, event_cx| {
|
||||
if event.button == button && !event.is_down {
|
||||
handler(view, event, event_cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
@ -385,7 +413,7 @@ pub struct AnyElement<V> {
|
||||
layout: Option<(NodeId, Box<dyn Any>)>,
|
||||
}
|
||||
|
||||
impl<V> AnyElement<V> {
|
||||
impl<V: 'static> AnyElement<V> {
|
||||
pub fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<NodeId> {
|
||||
let pushed_text_style = self.push_text_style(cx);
|
||||
|
||||
@ -426,7 +454,20 @@ impl<V> AnyElement<V> {
|
||||
from_element: element_layout.as_mut(),
|
||||
};
|
||||
|
||||
if let Some(click_handler) = self.element.handlers_mut().click.clone() {}
|
||||
for handler in self.element.handlers_mut().mouse_button.iter().cloned() {
|
||||
let EngineLayout { order, bounds } = layout.from_engine;
|
||||
|
||||
let view_id = cx.view_id();
|
||||
cx.draw_interactive_region(
|
||||
order,
|
||||
bounds,
|
||||
move |view, event: &MouseButtonEvent, window_cx| {
|
||||
let mut view_cx = ViewContext::mutable(window_cx, view_id);
|
||||
let mut event_cx = EventContext::new(&mut view_cx);
|
||||
(handler)(view, event, &mut event_cx);
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
self.element.paint(layout, view, cx)?;
|
||||
if pushed_text_style {
|
||||
|
@ -1,11 +1,9 @@
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
collections::BTreeSet,
|
||||
rc::Rc,
|
||||
};
|
||||
use std::{any::TypeId, rc::Rc};
|
||||
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use gpui::{geometry::rect::RectF, EventContext, RenderContext, ViewContext, WindowContext};
|
||||
use gpui::{
|
||||
geometry::rect::RectF, scene::InteractiveRegion, EventContext, RenderContext, ViewContext,
|
||||
};
|
||||
pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext};
|
||||
pub use taffy::tree::NodeId;
|
||||
|
||||
@ -15,7 +13,6 @@ pub struct PaintContext<'a, 'b, 'c, 'd, V> {
|
||||
#[deref_mut]
|
||||
pub(crate) legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
|
||||
pub(crate) scene: &'d mut gpui::SceneBuilder,
|
||||
regions: BTreeSet<InteractiveRegion>,
|
||||
}
|
||||
|
||||
impl<V> RenderContext for PaintContext<'_, '_, '_, '_, V> {
|
||||
@ -37,20 +34,17 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
|
||||
legacy_cx: &'d mut LegacyPaintContext<'a, 'b, 'c, V>,
|
||||
scene: &'d mut gpui::SceneBuilder,
|
||||
) -> Self {
|
||||
Self {
|
||||
legacy_cx,
|
||||
scene,
|
||||
regions: BTreeSet::new(),
|
||||
}
|
||||
Self { legacy_cx, scene }
|
||||
}
|
||||
|
||||
pub fn paint_interactive<E: 'static>(
|
||||
pub fn draw_interactive_region<E: 'static>(
|
||||
&mut self,
|
||||
order: u32,
|
||||
bounds: RectF,
|
||||
handler: impl Fn(&mut V, E, &mut EventContext<V>) + 'static,
|
||||
handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
|
||||
) {
|
||||
self.regions.insert(InteractiveRegion {
|
||||
// We'll sort these by their order in `take_interactive_regions`.
|
||||
self.scene.interactive_regions.push(InteractiveRegion {
|
||||
order,
|
||||
bounds,
|
||||
event_handler: Rc::new(move |view, event, window_cx, view_id| {
|
||||
@ -58,38 +52,12 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
|
||||
let mut cx = EventContext::new(&mut cx);
|
||||
handler(
|
||||
view.downcast_mut().unwrap(),
|
||||
*event.downcast().unwrap(),
|
||||
event.downcast_ref().unwrap(),
|
||||
&mut cx,
|
||||
)
|
||||
}),
|
||||
event_type: TypeId::of::<E>(),
|
||||
view_id: self.view_id(),
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
struct InteractiveRegion {
|
||||
order: u32,
|
||||
bounds: RectF,
|
||||
event_handler: Rc<dyn Fn(&mut dyn Any, Box<dyn Any>, &mut WindowContext, usize)>,
|
||||
event_type: TypeId,
|
||||
}
|
||||
|
||||
impl Eq for InteractiveRegion {}
|
||||
|
||||
impl PartialEq for InteractiveRegion {
|
||||
fn eq(&self, other: &Self) -> bool {
|
||||
self.order == other.order
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd for InteractiveRegion {
|
||||
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
|
||||
todo!()
|
||||
}
|
||||
}
|
||||
|
||||
impl Ord for InteractiveRegion {
|
||||
fn cmp(&self, other: &Self) -> std::cmp::Ordering {
|
||||
self.order.cmp(&other.order)
|
||||
}
|
||||
}
|
||||
|
@ -5,7 +5,7 @@ use element::Element;
|
||||
use frame::frame;
|
||||
use gpui::{
|
||||
geometry::{rect::RectF, vector::vec2f},
|
||||
platform::WindowOptions,
|
||||
platform::{MouseButton, WindowOptions},
|
||||
};
|
||||
use log::LevelFilter;
|
||||
use simplelog::SimpleLogger;
|
||||
@ -49,7 +49,12 @@ fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
||||
.h_full()
|
||||
.w_half()
|
||||
.fill(theme.success(0.5))
|
||||
.child(button().label("Hello").click(|_, _, _| (println!("hey!"))))
|
||||
.child(
|
||||
button()
|
||||
.label("Hello")
|
||||
.mouse_up(MouseButton::Left, |_, _, _| (println!("up!")))
|
||||
.mouse_down(MouseButton::Left, |_, _, _| (println!("down!"))),
|
||||
)
|
||||
}
|
||||
|
||||
// todo!()
|
||||
|
@ -5216,6 +5216,7 @@ mod tests {
|
||||
button: MouseButton::Left,
|
||||
modifiers: Default::default(),
|
||||
click_count: 1,
|
||||
is_down: true,
|
||||
}),
|
||||
false,
|
||||
);
|
||||
|
@ -8,8 +8,9 @@ use crate::{
|
||||
MouseButton, MouseMovedEvent, PromptLevel, WindowBounds,
|
||||
},
|
||||
scene::{
|
||||
CursorRegion, MouseClick, MouseClickOut, MouseDown, MouseDownOut, MouseDrag, MouseEvent,
|
||||
MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp, MouseUpOut, Scene,
|
||||
CursorRegion, InteractiveRegion, MouseClick, MouseClickOut, MouseDown, MouseDownOut,
|
||||
MouseDrag, MouseEvent, MouseHover, MouseMove, MouseMoveOut, MouseScrollWheel, MouseUp,
|
||||
MouseUpOut, Scene,
|
||||
},
|
||||
text_layout::TextLayoutCache,
|
||||
util::post_inc,
|
||||
@ -56,6 +57,7 @@ pub struct Window {
|
||||
appearance: Appearance,
|
||||
cursor_regions: Vec<CursorRegion>,
|
||||
mouse_regions: Vec<(MouseRegion, usize)>,
|
||||
interactive_regions: Vec<InteractiveRegion>,
|
||||
last_mouse_moved_event: Option<Event>,
|
||||
pub(crate) hovered_region_ids: Vec<MouseRegionId>,
|
||||
pub(crate) clicked_region_ids: Vec<MouseRegionId>,
|
||||
@ -89,6 +91,7 @@ impl Window {
|
||||
rendered_views: Default::default(),
|
||||
cursor_regions: Default::default(),
|
||||
mouse_regions: Default::default(),
|
||||
interactive_regions: Vec::new(),
|
||||
text_layout_cache: TextLayoutCache::new(cx.font_system.clone()),
|
||||
last_mouse_moved_event: None,
|
||||
hovered_region_ids: Default::default(),
|
||||
@ -490,6 +493,8 @@ impl<'a> WindowContext<'a> {
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_event(&mut self, event: Event, event_reused: bool) -> bool {
|
||||
self.dispatch_to_interactive_regions(&event);
|
||||
|
||||
let mut mouse_events = SmallVec::<[_; 2]>::new();
|
||||
let mut notified_views: HashSet<usize> = Default::default();
|
||||
let handle = self.window_handle;
|
||||
@ -867,6 +872,30 @@ impl<'a> WindowContext<'a> {
|
||||
any_event_handled
|
||||
}
|
||||
|
||||
fn dispatch_to_interactive_regions(&mut self, event: &Event) {
|
||||
if let Some(mouse_event) = event.mouse_event() {
|
||||
let mouse_position = event.position().expect("mouse events must have a position");
|
||||
let interactive_regions = std::mem::take(&mut self.window.interactive_regions);
|
||||
|
||||
for region in interactive_regions.iter().rev() {
|
||||
if region.event_type == mouse_event.type_id() {
|
||||
if region.bounds.contains_point(mouse_position) {
|
||||
self.update_any_view(region.view_id, |view, window_cx| {
|
||||
(region.event_handler)(
|
||||
view.as_any_mut(),
|
||||
mouse_event,
|
||||
window_cx,
|
||||
region.view_id,
|
||||
)
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.window.interactive_regions = interactive_regions;
|
||||
}
|
||||
}
|
||||
|
||||
pub(crate) fn dispatch_key_down(&mut self, event: &KeyDownEvent) -> bool {
|
||||
let handle = self.window_handle;
|
||||
if let Some(focused_view_id) = self.window.focused_view_id {
|
||||
@ -1018,9 +1047,10 @@ impl<'a> WindowContext<'a> {
|
||||
.insert(root_view_id, rendered_root);
|
||||
|
||||
self.window.text_layout_cache.finish_frame();
|
||||
let scene = scene_builder.build();
|
||||
let mut scene = scene_builder.build();
|
||||
self.window.cursor_regions = scene.cursor_regions();
|
||||
self.window.mouse_regions = scene.mouse_regions();
|
||||
self.window.interactive_regions = scene.take_interactive_regions();
|
||||
|
||||
if self.window_is_active() {
|
||||
if let Some(event) = self.window.last_mouse_moved_event.clone() {
|
||||
|
@ -1,4 +1,4 @@
|
||||
use std::ops::Deref;
|
||||
use std::{any::Any, ops::Deref};
|
||||
|
||||
use pathfinder_geometry::vector::vec2f;
|
||||
|
||||
@ -142,6 +142,7 @@ pub struct MouseButtonEvent {
|
||||
pub position: Vector2F,
|
||||
pub modifiers: Modifiers,
|
||||
pub click_count: usize,
|
||||
pub is_down: bool,
|
||||
}
|
||||
|
||||
impl Deref for MouseButtonEvent {
|
||||
@ -174,6 +175,7 @@ impl MouseMovedEvent {
|
||||
button: self.pressed_button.unwrap_or(button),
|
||||
modifiers: self.modifiers,
|
||||
click_count: 0,
|
||||
is_down: self.pressed_button.is_some(),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -211,10 +213,25 @@ impl Event {
|
||||
Event::KeyDown { .. } => None,
|
||||
Event::KeyUp { .. } => None,
|
||||
Event::ModifiersChanged { .. } => None,
|
||||
Event::MouseDown(event) | Event::MouseUp(event) => Some(event.position),
|
||||
Event::MouseDown(event) => Some(event.position),
|
||||
Event::MouseUp(event) => Some(event.position),
|
||||
Event::MouseMoved(event) => Some(event.position),
|
||||
Event::MouseExited(event) => Some(event.position),
|
||||
Event::ScrollWheel(event) => Some(event.position),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mouse_event<'a>(&'a self) -> Option<&'a dyn Any> {
|
||||
match self {
|
||||
Event::KeyDown { .. } => None,
|
||||
Event::KeyUp { .. } => None,
|
||||
Event::ModifiersChanged { .. } => None,
|
||||
Event::MouseDown(event) => Some(event),
|
||||
Event::MouseUp(event) => Some(event),
|
||||
_ => None,
|
||||
// Event::MouseMoved(event) => Some(event),
|
||||
// Event::MouseExited(event) => Some(event),
|
||||
// Event::ScrollWheel(event) => Some(event),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,6 +132,7 @@ impl Event {
|
||||
),
|
||||
modifiers: read_modifiers(native_event),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
is_down: true,
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -158,6 +159,7 @@ impl Event {
|
||||
),
|
||||
modifiers: read_modifiers(native_event),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
is_down: false,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
@ -9,7 +9,12 @@ use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
use serde_derive::Serialize;
|
||||
use serde_json::json;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
borrow::Cow,
|
||||
rc::Rc,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
color::Color,
|
||||
@ -17,7 +22,7 @@ use crate::{
|
||||
geometry::{rect::RectF, vector::Vector2F},
|
||||
json::ToJson,
|
||||
platform::{current::Surface, CursorStyle},
|
||||
ImageData,
|
||||
ImageData, WindowContext,
|
||||
};
|
||||
pub use mouse_event::*;
|
||||
pub use mouse_region::*;
|
||||
@ -26,6 +31,8 @@ pub struct SceneBuilder {
|
||||
scale_factor: f32,
|
||||
stacking_contexts: Vec<StackingContext>,
|
||||
active_stacking_context_stack: Vec<usize>,
|
||||
/// Used by the playground crate.
|
||||
pub interactive_regions: Vec<InteractiveRegion>,
|
||||
#[cfg(debug_assertions)]
|
||||
mouse_region_ids: HashSet<MouseRegionId>,
|
||||
}
|
||||
@ -33,6 +40,7 @@ pub struct SceneBuilder {
|
||||
pub struct Scene {
|
||||
scale_factor: f32,
|
||||
stacking_contexts: Vec<StackingContext>,
|
||||
interactive_regions: Vec<InteractiveRegion>,
|
||||
}
|
||||
|
||||
struct StackingContext {
|
||||
@ -273,6 +281,12 @@ impl Scene {
|
||||
})
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn take_interactive_regions(&mut self) -> Vec<InteractiveRegion> {
|
||||
self.interactive_regions
|
||||
.sort_by(|a, b| a.order.cmp(&b.order));
|
||||
std::mem::take(&mut self.interactive_regions)
|
||||
}
|
||||
}
|
||||
|
||||
impl SceneBuilder {
|
||||
@ -284,6 +298,7 @@ impl SceneBuilder {
|
||||
active_stacking_context_stack: vec![0],
|
||||
#[cfg(debug_assertions)]
|
||||
mouse_region_ids: Default::default(),
|
||||
interactive_regions: Vec::new(),
|
||||
}
|
||||
}
|
||||
|
||||
@ -293,6 +308,7 @@ impl SceneBuilder {
|
||||
Scene {
|
||||
scale_factor: self.scale_factor,
|
||||
stacking_contexts: self.stacking_contexts,
|
||||
interactive_regions: self.interactive_regions,
|
||||
}
|
||||
}
|
||||
|
||||
@ -689,6 +705,17 @@ impl MouseRegion {
|
||||
}
|
||||
}
|
||||
|
||||
/// This is currently only used in the playground crate. It represents a region
|
||||
/// with which the user can interact via a pointing device. It aims to replace
|
||||
/// MouseRegion and CursorRegion.
|
||||
pub struct InteractiveRegion {
|
||||
pub order: u32,
|
||||
pub bounds: RectF,
|
||||
pub event_handler: Rc<dyn Fn(&mut dyn Any, &dyn Any, &mut WindowContext, usize)>,
|
||||
pub event_type: TypeId,
|
||||
pub view_id: usize,
|
||||
}
|
||||
|
||||
fn can_draw(bounds: RectF) -> bool {
|
||||
let size = bounds.size();
|
||||
size.x() > 0. && size.y() > 0.
|
||||
|
@ -364,13 +364,13 @@ impl Line {
|
||||
origin: glyph_origin,
|
||||
});
|
||||
} else {
|
||||
scene.push_glyph(dbg!(scene::Glyph {
|
||||
scene.push_glyph(scene::Glyph {
|
||||
font_id: run.font_id,
|
||||
font_size: self.layout.font_size,
|
||||
id: glyph.id,
|
||||
origin: glyph_origin,
|
||||
color,
|
||||
}));
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user