Merge branch 'main' into select-on-rename
This commit is contained in:
commit
951fd1ab36
28 changed files with 1063 additions and 257 deletions
|
@ -740,6 +740,7 @@ type ActionCallback =
|
|||
type GlobalActionCallback = dyn FnMut(&dyn AnyAction, &mut MutableAppContext);
|
||||
|
||||
type SubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext) -> bool>;
|
||||
type GlobalSubscriptionCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
||||
type ObservationCallback = Box<dyn FnMut(&mut MutableAppContext) -> bool>;
|
||||
type ReleaseObservationCallback = Box<dyn FnMut(&dyn Any, &mut MutableAppContext)>;
|
||||
|
||||
|
@ -757,6 +758,7 @@ pub struct MutableAppContext {
|
|||
next_subscription_id: usize,
|
||||
frame_count: usize,
|
||||
subscriptions: Arc<Mutex<HashMap<usize, BTreeMap<usize, SubscriptionCallback>>>>,
|
||||
global_subscriptions: Arc<Mutex<HashMap<TypeId, BTreeMap<usize, GlobalSubscriptionCallback>>>>,
|
||||
observations: Arc<Mutex<HashMap<usize, BTreeMap<usize, ObservationCallback>>>>,
|
||||
release_observations: Arc<Mutex<HashMap<usize, BTreeMap<usize, ReleaseObservationCallback>>>>,
|
||||
presenters_and_platform_windows:
|
||||
|
@ -804,6 +806,7 @@ impl MutableAppContext {
|
|||
next_subscription_id: 0,
|
||||
frame_count: 0,
|
||||
subscriptions: Default::default(),
|
||||
global_subscriptions: Default::default(),
|
||||
observations: Default::default(),
|
||||
release_observations: Default::default(),
|
||||
presenters_and_platform_windows: HashMap::new(),
|
||||
|
@ -1062,6 +1065,12 @@ impl MutableAppContext {
|
|||
self.foreground_platform.prompt_for_new_path(directory)
|
||||
}
|
||||
|
||||
pub fn emit_global<E: Any>(&mut self, payload: E) {
|
||||
self.pending_effects.push_back(Effect::GlobalEvent {
|
||||
payload: Box::new(payload),
|
||||
});
|
||||
}
|
||||
|
||||
pub fn subscribe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
|
||||
where
|
||||
E: Entity,
|
||||
|
@ -1075,6 +1084,31 @@ impl MutableAppContext {
|
|||
})
|
||||
}
|
||||
|
||||
pub fn subscribe_global<E, F>(&mut self, mut callback: F) -> Subscription
|
||||
where
|
||||
E: Any,
|
||||
F: 'static + FnMut(&E, &mut Self),
|
||||
{
|
||||
let id = post_inc(&mut self.next_subscription_id);
|
||||
let type_id = TypeId::of::<E>();
|
||||
self.global_subscriptions
|
||||
.lock()
|
||||
.entry(type_id)
|
||||
.or_default()
|
||||
.insert(
|
||||
id,
|
||||
Box::new(move |payload, cx| {
|
||||
let payload = payload.downcast_ref().expect("downcast is type safe");
|
||||
callback(payload, cx)
|
||||
}),
|
||||
);
|
||||
Subscription::GlobalSubscription {
|
||||
id,
|
||||
type_id,
|
||||
subscriptions: Some(Arc::downgrade(&self.global_subscriptions)),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn observe<E, H, F>(&mut self, handle: &H, mut callback: F) -> Subscription
|
||||
where
|
||||
E: Entity,
|
||||
|
@ -1573,6 +1607,7 @@ impl MutableAppContext {
|
|||
if let Some(effect) = self.pending_effects.pop_front() {
|
||||
match effect {
|
||||
Effect::Event { entity_id, payload } => self.emit_event(entity_id, payload),
|
||||
Effect::GlobalEvent { payload } => self.emit_global_event(payload),
|
||||
Effect::ModelNotification { model_id } => {
|
||||
self.notify_model_observers(model_id)
|
||||
}
|
||||
|
@ -1700,6 +1735,16 @@ impl MutableAppContext {
|
|||
}
|
||||
}
|
||||
|
||||
fn emit_global_event(&mut self, payload: Box<dyn Any>) {
|
||||
let type_id = (&*payload).type_id();
|
||||
let callbacks = self.global_subscriptions.lock().remove(&type_id);
|
||||
if let Some(callbacks) = callbacks {
|
||||
for (_, mut callback) in callbacks {
|
||||
callback(payload.as_ref(), self)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn notify_model_observers(&mut self, observed_id: usize) {
|
||||
let callbacks = self.observations.lock().remove(&observed_id);
|
||||
if let Some(callbacks) = callbacks {
|
||||
|
@ -2071,6 +2116,9 @@ pub enum Effect {
|
|||
entity_id: usize,
|
||||
payload: Box<dyn Any>,
|
||||
},
|
||||
GlobalEvent {
|
||||
payload: Box<dyn Any>,
|
||||
},
|
||||
ModelNotification {
|
||||
model_id: usize,
|
||||
},
|
||||
|
@ -2104,6 +2152,10 @@ impl Debug for Effect {
|
|||
.debug_struct("Effect::Event")
|
||||
.field("entity_id", entity_id)
|
||||
.finish(),
|
||||
Effect::GlobalEvent { payload, .. } => f
|
||||
.debug_struct("Effect::GlobalEvent")
|
||||
.field("type_id", &(&*payload).type_id())
|
||||
.finish(),
|
||||
Effect::ModelNotification { model_id } => f
|
||||
.debug_struct("Effect::ModelNotification")
|
||||
.field("model_id", model_id)
|
||||
|
@ -3762,6 +3814,12 @@ pub enum Subscription {
|
|||
entity_id: usize,
|
||||
subscriptions: Option<Weak<Mutex<HashMap<usize, BTreeMap<usize, SubscriptionCallback>>>>>,
|
||||
},
|
||||
GlobalSubscription {
|
||||
id: usize,
|
||||
type_id: TypeId,
|
||||
subscriptions:
|
||||
Option<Weak<Mutex<HashMap<TypeId, BTreeMap<usize, GlobalSubscriptionCallback>>>>>,
|
||||
},
|
||||
Observation {
|
||||
id: usize,
|
||||
entity_id: usize,
|
||||
|
@ -3781,6 +3839,9 @@ impl Subscription {
|
|||
Subscription::Subscription { subscriptions, .. } => {
|
||||
subscriptions.take();
|
||||
}
|
||||
Subscription::GlobalSubscription { subscriptions, .. } => {
|
||||
subscriptions.take();
|
||||
}
|
||||
Subscription::Observation { observations, .. } => {
|
||||
observations.take();
|
||||
}
|
||||
|
@ -3794,6 +3855,28 @@ impl Subscription {
|
|||
impl Drop for Subscription {
|
||||
fn drop(&mut self) {
|
||||
match self {
|
||||
Subscription::Subscription {
|
||||
id,
|
||||
entity_id,
|
||||
subscriptions,
|
||||
} => {
|
||||
if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) {
|
||||
if let Some(subscriptions) = subscriptions.lock().get_mut(entity_id) {
|
||||
subscriptions.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Subscription::GlobalSubscription {
|
||||
id,
|
||||
type_id,
|
||||
subscriptions,
|
||||
} => {
|
||||
if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) {
|
||||
if let Some(subscriptions) = subscriptions.lock().get_mut(type_id) {
|
||||
subscriptions.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
Subscription::Observation {
|
||||
id,
|
||||
entity_id,
|
||||
|
@ -3816,17 +3899,6 @@ impl Drop for Subscription {
|
|||
}
|
||||
}
|
||||
}
|
||||
Subscription::Subscription {
|
||||
id,
|
||||
entity_id,
|
||||
subscriptions,
|
||||
} => {
|
||||
if let Some(subscriptions) = subscriptions.as_ref().and_then(Weak::upgrade) {
|
||||
if let Some(subscriptions) = subscriptions.lock().get_mut(entity_id) {
|
||||
subscriptions.remove(id);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -3,13 +3,15 @@ use serde_json::json;
|
|||
|
||||
use crate::{
|
||||
geometry::vector::Vector2F, DebugContext, Element, ElementBox, Event, EventContext,
|
||||
LayoutContext, PaintContext, SizeConstraint,
|
||||
LayoutContext, NavigationDirection, PaintContext, SizeConstraint,
|
||||
};
|
||||
|
||||
pub struct EventHandler {
|
||||
child: ElementBox,
|
||||
capture: Option<Box<dyn FnMut(&Event, RectF, &mut EventContext) -> bool>>,
|
||||
mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
|
||||
right_mouse_down: Option<Box<dyn FnMut(&mut EventContext) -> bool>>,
|
||||
navigate_mouse_down: Option<Box<dyn FnMut(NavigationDirection, &mut EventContext) -> bool>>,
|
||||
}
|
||||
|
||||
impl EventHandler {
|
||||
|
@ -18,6 +20,8 @@ impl EventHandler {
|
|||
child,
|
||||
capture: None,
|
||||
mouse_down: None,
|
||||
right_mouse_down: None,
|
||||
navigate_mouse_down: None,
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -29,6 +33,22 @@ impl EventHandler {
|
|||
self
|
||||
}
|
||||
|
||||
pub fn on_right_mouse_down<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: 'static + FnMut(&mut EventContext) -> bool,
|
||||
{
|
||||
self.right_mouse_down = Some(Box::new(callback));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn on_navigate_mouse_down<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: 'static + FnMut(NavigationDirection, &mut EventContext) -> bool,
|
||||
{
|
||||
self.navigate_mouse_down = Some(Box::new(callback));
|
||||
self
|
||||
}
|
||||
|
||||
pub fn capture<F>(mut self, callback: F) -> Self
|
||||
where
|
||||
F: 'static + FnMut(&Event, RectF, &mut EventContext) -> bool,
|
||||
|
@ -87,6 +107,26 @@ impl Element for EventHandler {
|
|||
}
|
||||
false
|
||||
}
|
||||
Event::RightMouseDown { position, .. } => {
|
||||
if let Some(callback) = self.right_mouse_down.as_mut() {
|
||||
if bounds.contains_point(*position) {
|
||||
return callback(cx);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
Event::NavigateMouseDown {
|
||||
position,
|
||||
direction,
|
||||
..
|
||||
} => {
|
||||
if let Some(callback) = self.navigate_mouse_down.as_mut() {
|
||||
if bounds.contains_point(*position) {
|
||||
return callback(*direction, cx);
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
_ => false,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -29,7 +29,7 @@ pub mod keymap;
|
|||
pub mod platform;
|
||||
pub use gpui_macros::test;
|
||||
pub use platform::FontSystem;
|
||||
pub use platform::{Event, PathPromptOptions, Platform, PromptLevel};
|
||||
pub use platform::{Event, NavigationDirection, PathPromptOptions, Platform, PromptLevel};
|
||||
pub use presenter::{
|
||||
Axis, DebugContext, EventContext, LayoutContext, PaintContext, SizeConstraint, Vector2FExt,
|
||||
};
|
||||
|
|
|
@ -19,7 +19,7 @@ use crate::{
|
|||
};
|
||||
use anyhow::Result;
|
||||
use async_task::Runnable;
|
||||
pub use event::Event;
|
||||
pub use event::{Event, NavigationDirection};
|
||||
use postage::oneshot;
|
||||
use std::{
|
||||
any::Any,
|
||||
|
|
|
@ -1,5 +1,11 @@
|
|||
use crate::{geometry::vector::Vector2F, keymap::Keystroke};
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum NavigationDirection {
|
||||
Back,
|
||||
Forward,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Event {
|
||||
KeyDown {
|
||||
|
@ -26,6 +32,30 @@ pub enum Event {
|
|||
LeftMouseDragged {
|
||||
position: Vector2F,
|
||||
},
|
||||
RightMouseDown {
|
||||
position: Vector2F,
|
||||
ctrl: bool,
|
||||
alt: bool,
|
||||
shift: bool,
|
||||
cmd: bool,
|
||||
click_count: usize,
|
||||
},
|
||||
RightMouseUp {
|
||||
position: Vector2F,
|
||||
},
|
||||
NavigateMouseDown {
|
||||
position: Vector2F,
|
||||
direction: NavigationDirection,
|
||||
ctrl: bool,
|
||||
alt: bool,
|
||||
shift: bool,
|
||||
cmd: bool,
|
||||
click_count: usize,
|
||||
},
|
||||
NavigateMouseUp {
|
||||
position: Vector2F,
|
||||
direction: NavigationDirection,
|
||||
},
|
||||
MouseMoved {
|
||||
position: Vector2F,
|
||||
left_mouse_down: bool,
|
||||
|
|
|
@ -1,4 +1,8 @@
|
|||
use crate::{geometry::vector::vec2f, keymap::Keystroke, platform::Event};
|
||||
use crate::{
|
||||
geometry::vector::vec2f,
|
||||
keymap::Keystroke,
|
||||
platform::{Event, NavigationDirection},
|
||||
};
|
||||
use cocoa::{
|
||||
appkit::{NSEvent, NSEventModifierFlags, NSEventType},
|
||||
base::{id, nil, YES},
|
||||
|
@ -125,6 +129,64 @@ impl Event {
|
|||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
}),
|
||||
NSEventType::NSRightMouseDown => {
|
||||
let modifiers = native_event.modifierFlags();
|
||||
window_height.map(|window_height| Self::RightMouseDown {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
ctrl: modifiers.contains(NSEventModifierFlags::NSControlKeyMask),
|
||||
alt: modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask),
|
||||
shift: modifiers.contains(NSEventModifierFlags::NSShiftKeyMask),
|
||||
cmd: modifiers.contains(NSEventModifierFlags::NSCommandKeyMask),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
})
|
||||
}
|
||||
NSEventType::NSRightMouseUp => window_height.map(|window_height| Self::RightMouseUp {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
}),
|
||||
NSEventType::NSOtherMouseDown => {
|
||||
let direction = match native_event.buttonNumber() {
|
||||
3 => NavigationDirection::Back,
|
||||
4 => NavigationDirection::Forward,
|
||||
// Other mouse buttons aren't tracked currently
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
let modifiers = native_event.modifierFlags();
|
||||
window_height.map(|window_height| Self::NavigateMouseDown {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
direction,
|
||||
ctrl: modifiers.contains(NSEventModifierFlags::NSControlKeyMask),
|
||||
alt: modifiers.contains(NSEventModifierFlags::NSAlternateKeyMask),
|
||||
shift: modifiers.contains(NSEventModifierFlags::NSShiftKeyMask),
|
||||
cmd: modifiers.contains(NSEventModifierFlags::NSCommandKeyMask),
|
||||
click_count: native_event.clickCount() as usize,
|
||||
})
|
||||
}
|
||||
NSEventType::NSOtherMouseUp => {
|
||||
let direction = match native_event.buttonNumber() {
|
||||
3 => NavigationDirection::Back,
|
||||
4 => NavigationDirection::Forward,
|
||||
// Other mouse buttons aren't tracked currently
|
||||
_ => return None,
|
||||
};
|
||||
|
||||
window_height.map(|window_height| Self::NavigateMouseUp {
|
||||
position: vec2f(
|
||||
native_event.locationInWindow().x as f32,
|
||||
window_height - native_event.locationInWindow().y as f32,
|
||||
),
|
||||
direction,
|
||||
})
|
||||
}
|
||||
NSEventType::NSLeftMouseDragged => {
|
||||
window_height.map(|window_height| Self::LeftMouseDragged {
|
||||
position: vec2f(
|
||||
|
|
|
@ -95,6 +95,22 @@ unsafe fn build_classes() {
|
|||
sel!(mouseUp:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(rightMouseDown:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(rightMouseUp:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(otherMouseDown:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(otherMouseUp:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
);
|
||||
decl.add_method(
|
||||
sel!(mouseMoved:),
|
||||
handle_view_event as extern "C" fn(&Object, Sel, id),
|
||||
|
|
|
@ -186,7 +186,7 @@ pub struct Run {
|
|||
pub glyphs: Vec<Glyph>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Glyph {
|
||||
pub id: GlyphId,
|
||||
pub position: Vector2F,
|
||||
|
@ -210,10 +210,14 @@ impl Line {
|
|||
self.layout.width
|
||||
}
|
||||
|
||||
pub fn font_size(&self) -> f32 {
|
||||
self.layout.font_size
|
||||
}
|
||||
|
||||
pub fn x_for_index(&self, index: usize) -> f32 {
|
||||
for run in &self.layout.runs {
|
||||
for glyph in &run.glyphs {
|
||||
if glyph.index == index {
|
||||
if glyph.index >= index {
|
||||
return glyph.position.x();
|
||||
}
|
||||
}
|
||||
|
@ -221,6 +225,18 @@ impl Line {
|
|||
self.layout.width
|
||||
}
|
||||
|
||||
pub fn font_for_index(&self, index: usize) -> Option<FontId> {
|
||||
for run in &self.layout.runs {
|
||||
for glyph in &run.glyphs {
|
||||
if glyph.index >= index {
|
||||
return Some(run.font_id);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
pub fn index_for_x(&self, x: f32) -> Option<usize> {
|
||||
if x >= self.layout.width {
|
||||
None
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue