mirror of
https://github.com/zed-industries/zed.git
synced 2024-11-10 14:06:11 +03:00
Merge branch 'gpui2' of github.com:zed-industries/zed into gpui2
This commit is contained in:
commit
1a156c1060
@ -8,9 +8,10 @@ pub use model_context::*;
|
||||
use refineable::Refineable;
|
||||
|
||||
use crate::{
|
||||
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor, LayoutId,
|
||||
MainThread, MainThreadOnly, Platform, SubscriberSet, SvgRenderer, Task, TextStyle,
|
||||
TextStyleRefinement, TextSystem, View, Window, WindowContext, WindowHandle, WindowId,
|
||||
current_platform, image_cache::ImageCache, AssetSource, Context, DisplayId, Executor,
|
||||
FocusEvent, FocusHandle, FocusId, LayoutId, MainThread, MainThreadOnly, Platform,
|
||||
SubscriberSet, SvgRenderer, Task, TextStyle, TextStyleRefinement, TextSystem, View, Window,
|
||||
WindowContext, WindowHandle, WindowId,
|
||||
};
|
||||
use anyhow::{anyhow, Result};
|
||||
use collections::{HashMap, HashSet, VecDeque};
|
||||
@ -54,6 +55,7 @@ impl App {
|
||||
this: this.clone(),
|
||||
text_system: Arc::new(TextSystem::new(platform.text_system())),
|
||||
pending_updates: 0,
|
||||
flushing_effects: false,
|
||||
next_frame_callbacks: Default::default(),
|
||||
platform: MainThreadOnly::new(platform, executor.clone()),
|
||||
executor,
|
||||
@ -97,6 +99,7 @@ pub struct AppContext {
|
||||
this: Weak<Mutex<AppContext>>,
|
||||
pub(crate) platform: MainThreadOnly<dyn Platform>,
|
||||
text_system: Arc<TextSystem>,
|
||||
flushing_effects: bool,
|
||||
pending_updates: usize,
|
||||
pub(crate) next_frame_callbacks: HashMap<DisplayId, Vec<FrameCallback>>,
|
||||
pub(crate) executor: Executor,
|
||||
@ -119,8 +122,10 @@ impl AppContext {
|
||||
pub(crate) fn update<R>(&mut self, update: impl FnOnce(&mut Self) -> R) -> R {
|
||||
self.pending_updates += 1;
|
||||
let result = update(self);
|
||||
if self.pending_updates == 1 {
|
||||
if !self.flushing_effects && self.pending_updates == 1 {
|
||||
self.flushing_effects = true;
|
||||
self.flush_effects();
|
||||
self.flushing_effects = false;
|
||||
}
|
||||
self.pending_updates -= 1;
|
||||
result
|
||||
@ -158,6 +163,7 @@ impl AppContext {
|
||||
}
|
||||
}
|
||||
Effect::Emit { .. } => self.pending_effects.push_back(effect),
|
||||
Effect::FocusChanged { .. } => self.pending_effects.push_back(effect),
|
||||
}
|
||||
}
|
||||
|
||||
@ -168,6 +174,9 @@ impl AppContext {
|
||||
match effect {
|
||||
Effect::Notify { emitter } => self.apply_notify_effect(emitter),
|
||||
Effect::Emit { emitter, event } => self.apply_emit_effect(emitter, event),
|
||||
Effect::FocusChanged { window_id, focused } => {
|
||||
self.apply_focus_changed(window_id, focused)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
@ -222,6 +231,24 @@ impl AppContext {
|
||||
.retain(&emitter, |handler| handler(&event, self));
|
||||
}
|
||||
|
||||
fn apply_focus_changed(&mut self, window_id: WindowId, focused: Option<FocusId>) {
|
||||
self.update_window(window_id, |cx| {
|
||||
if cx.window.focus == focused {
|
||||
let mut listeners = mem::take(&mut cx.window.focus_listeners);
|
||||
let focused = focused.map(FocusHandle::new);
|
||||
let blurred = cx.window.last_blur.unwrap().map(FocusHandle::new);
|
||||
let event = FocusEvent { focused, blurred };
|
||||
for listener in &listeners {
|
||||
listener(&event, cx);
|
||||
}
|
||||
|
||||
listeners.extend(cx.window.focus_listeners.drain(..));
|
||||
cx.window.focus_listeners = listeners;
|
||||
}
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
|
||||
pub fn to_async(&self) -> AsyncAppContext {
|
||||
AsyncAppContext(unsafe { mem::transmute(self.this.clone()) })
|
||||
}
|
||||
@ -426,6 +453,10 @@ pub(crate) enum Effect {
|
||||
emitter: EntityId,
|
||||
event: Box<dyn Any + Send + Sync + 'static>,
|
||||
},
|
||||
FocusChanged {
|
||||
window_id: WindowId,
|
||||
focused: Option<FocusId>,
|
||||
},
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
|
@ -199,6 +199,16 @@ pub struct WeakHandle<T> {
|
||||
entity_map: Weak<RwLock<EntityMapState>>,
|
||||
}
|
||||
|
||||
impl<T: 'static + Send + Sync> Clone for WeakHandle<T> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
id: self.id,
|
||||
entity_type: self.entity_type,
|
||||
entity_map: self.entity_map.clone(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: Send + Sync + 'static> WeakHandle<T> {
|
||||
pub fn upgrade(&self, _: &impl Context) -> Option<Handle<T>> {
|
||||
let entity_map = &self.entity_map.upgrade()?;
|
||||
|
@ -1,6 +1,7 @@
|
||||
use crate::{BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, ViewContext};
|
||||
use crate::{BorrowWindow, Bounds, ElementId, FocusHandle, LayoutId, Pixels, Point, ViewContext};
|
||||
use derive_more::{Deref, DerefMut};
|
||||
pub(crate) use smallvec::SmallVec;
|
||||
use std::mem;
|
||||
|
||||
pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
|
||||
type ViewState: 'static + Send + Sync;
|
||||
@ -8,17 +9,24 @@ pub trait Element: 'static + Send + Sync + IntoAnyElement<Self::ViewState> {
|
||||
|
||||
fn id(&self) -> Option<ElementId>;
|
||||
|
||||
fn layout(
|
||||
fn initialize(
|
||||
&mut self,
|
||||
state: &mut Self::ViewState,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState);
|
||||
) -> Self::ElementState;
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> LayoutId;
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
state: &mut Self::ViewState,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
);
|
||||
@ -31,21 +39,54 @@ pub trait ElementIdentity: 'static + Send + Sync {
|
||||
fn id(&self) -> Option<ElementId>;
|
||||
}
|
||||
|
||||
pub struct IdentifiedElement(pub(crate) ElementId);
|
||||
pub struct AnonymousElement;
|
||||
pub struct Identified(pub(crate) ElementId);
|
||||
|
||||
impl ElementIdentity for IdentifiedElement {
|
||||
impl ElementIdentity for Identified {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
Some(self.0.clone())
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementIdentity for AnonymousElement {
|
||||
pub struct Anonymous;
|
||||
|
||||
impl ElementIdentity for Anonymous {
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ElementFocusability: 'static + Send + Sync {
|
||||
fn focus_handle(&self) -> Option<&FocusHandle>;
|
||||
}
|
||||
|
||||
pub struct Focusable(FocusHandle);
|
||||
|
||||
impl AsRef<FocusHandle> for Focusable {
|
||||
fn as_ref(&self) -> &FocusHandle {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
|
||||
impl ElementFocusability for Focusable {
|
||||
fn focus_handle(&self) -> Option<&FocusHandle> {
|
||||
Some(&self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<FocusHandle> for Focusable {
|
||||
fn from(value: FocusHandle) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NonFocusable;
|
||||
|
||||
impl ElementFocusability for NonFocusable {
|
||||
fn focus_handle(&self) -> Option<&FocusHandle> {
|
||||
None
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ParentElement: Element {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
|
||||
|
||||
@ -70,9 +111,10 @@ pub trait ParentElement: Element {
|
||||
}
|
||||
}
|
||||
|
||||
trait ElementObject<S>: 'static + Send + Sync {
|
||||
fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId;
|
||||
fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>);
|
||||
trait ElementObject<V>: 'static + Send + Sync {
|
||||
fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
|
||||
fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
|
||||
fn paint(&mut self, view_state: &mut V, offset: Option<Point<Pixels>>, cx: &mut ViewContext<V>);
|
||||
}
|
||||
|
||||
struct RenderedElement<E: Element> {
|
||||
@ -81,17 +123,17 @@ struct RenderedElement<E: Element> {
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
enum ElementRenderPhase<S> {
|
||||
enum ElementRenderPhase<V> {
|
||||
#[default]
|
||||
Rendered,
|
||||
Start,
|
||||
Initialized {
|
||||
frame_state: Option<V>,
|
||||
},
|
||||
LayoutRequested {
|
||||
layout_id: LayoutId,
|
||||
frame_state: Option<S>,
|
||||
},
|
||||
Painted {
|
||||
bounds: Bounds<Pixels>,
|
||||
frame_state: Option<S>,
|
||||
frame_state: Option<V>,
|
||||
},
|
||||
Painted,
|
||||
}
|
||||
|
||||
/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
|
||||
@ -101,52 +143,57 @@ impl<E: Element> RenderedElement<E> {
|
||||
fn new(element: E) -> Self {
|
||||
RenderedElement {
|
||||
element,
|
||||
phase: ElementRenderPhase::Rendered,
|
||||
}
|
||||
}
|
||||
|
||||
fn paint_with_element_state(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
view_state: &mut E::ViewState,
|
||||
frame_state: &mut Option<E::ElementState>,
|
||||
cx: &mut ViewContext<E::ViewState>,
|
||||
) {
|
||||
if let Some(id) = self.element.id() {
|
||||
cx.with_element_state(id, |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
self.element
|
||||
.paint(bounds, view_state, &mut element_state, cx);
|
||||
((), element_state)
|
||||
});
|
||||
} else {
|
||||
self.element
|
||||
.paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
|
||||
phase: ElementRenderPhase::Start,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, S> ElementObject<E::ViewState> for RenderedElement<E>
|
||||
impl<E> ElementObject<E::ViewState> for RenderedElement<E>
|
||||
where
|
||||
E: Element<ElementState = S>,
|
||||
S: 'static + Send + Sync,
|
||||
E: Element,
|
||||
{
|
||||
fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
|
||||
let (layout_id, frame_state) = if let Some(id) = self.element.id() {
|
||||
let layout_id = cx.with_element_state(id, |element_state, cx| {
|
||||
self.element.layout(state, element_state, cx)
|
||||
fn initialize(&mut self, view_state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) {
|
||||
let frame_state = if let Some(id) = self.element.id() {
|
||||
cx.with_element_state(id, |element_state, cx| {
|
||||
let element_state = self.element.initialize(view_state, element_state, cx);
|
||||
((), element_state)
|
||||
});
|
||||
(layout_id, None)
|
||||
None
|
||||
} else {
|
||||
let (layout_id, frame_state) = self.element.layout(state, None, cx);
|
||||
(layout_id, Some(frame_state))
|
||||
let frame_state = self.element.initialize(view_state, None, cx);
|
||||
Some(frame_state)
|
||||
};
|
||||
|
||||
self.phase = ElementRenderPhase::Initialized { frame_state };
|
||||
}
|
||||
|
||||
fn layout(&mut self, state: &mut E::ViewState, cx: &mut ViewContext<E::ViewState>) -> LayoutId {
|
||||
let layout_id;
|
||||
let mut frame_state;
|
||||
match mem::take(&mut self.phase) {
|
||||
ElementRenderPhase::Initialized {
|
||||
frame_state: initial_frame_state,
|
||||
} => {
|
||||
frame_state = initial_frame_state;
|
||||
if let Some(id) = self.element.id() {
|
||||
layout_id = cx.with_element_state(id, |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
let layout_id = self.element.layout(state, &mut element_state, cx);
|
||||
(layout_id, element_state)
|
||||
});
|
||||
} else {
|
||||
layout_id = self
|
||||
.element
|
||||
.layout(state, frame_state.as_mut().unwrap(), cx);
|
||||
}
|
||||
}
|
||||
_ => panic!("must call initialize before layout"),
|
||||
};
|
||||
|
||||
self.phase = ElementRenderPhase::LayoutRequested {
|
||||
layout_id,
|
||||
frame_state,
|
||||
};
|
||||
|
||||
layout_id
|
||||
}
|
||||
|
||||
@ -156,60 +203,63 @@ where
|
||||
offset: Option<Point<Pixels>>,
|
||||
cx: &mut ViewContext<E::ViewState>,
|
||||
) {
|
||||
self.phase = match std::mem::take(&mut self.phase) {
|
||||
ElementRenderPhase::Rendered => panic!("must call layout before paint"),
|
||||
|
||||
self.phase = match mem::take(&mut self.phase) {
|
||||
ElementRenderPhase::LayoutRequested {
|
||||
layout_id,
|
||||
mut frame_state,
|
||||
} => {
|
||||
let mut bounds = cx.layout_bounds(layout_id);
|
||||
offset.map(|offset| bounds.origin += offset);
|
||||
self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
|
||||
ElementRenderPhase::Painted {
|
||||
bounds,
|
||||
frame_state,
|
||||
if let Some(id) = self.element.id() {
|
||||
cx.with_element_state(id, |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
self.element
|
||||
.paint(bounds, view_state, &mut element_state, cx);
|
||||
((), element_state)
|
||||
});
|
||||
} else {
|
||||
self.element
|
||||
.paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
|
||||
}
|
||||
ElementRenderPhase::Painted
|
||||
}
|
||||
|
||||
ElementRenderPhase::Painted {
|
||||
bounds,
|
||||
mut frame_state,
|
||||
} => {
|
||||
self.paint_with_element_state(bounds, view_state, &mut frame_state, cx);
|
||||
ElementRenderPhase::Painted {
|
||||
bounds,
|
||||
frame_state,
|
||||
}
|
||||
}
|
||||
_ => panic!("must call layout before paint"),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
|
||||
pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
|
||||
|
||||
impl<S: 'static + Send + Sync> AnyElement<S> {
|
||||
pub fn new<E: Element<ViewState = S>>(element: E) -> Self {
|
||||
impl<V: 'static + Send + Sync> AnyElement<V> {
|
||||
pub fn new<E: Element<ViewState = V>>(element: E) -> Self {
|
||||
AnyElement(Box::new(RenderedElement::new(element)))
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: 'static + Send + Sync> AnyElement<S> {
|
||||
pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> LayoutId {
|
||||
self.0.layout(state, cx)
|
||||
pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
|
||||
self.0.initialize(view_state, cx);
|
||||
}
|
||||
|
||||
pub fn paint(&mut self, state: &mut S, offset: Option<Point<Pixels>>, cx: &mut ViewContext<S>) {
|
||||
self.0.paint(state, offset, cx)
|
||||
pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
|
||||
self.0.layout(view_state, cx)
|
||||
}
|
||||
|
||||
pub fn paint(
|
||||
&mut self,
|
||||
view_state: &mut V,
|
||||
offset: Option<Point<Pixels>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
self.0.paint(view_state, offset, cx)
|
||||
}
|
||||
}
|
||||
|
||||
pub trait IntoAnyElement<S> {
|
||||
fn into_any(self) -> AnyElement<S>;
|
||||
pub trait IntoAnyElement<V> {
|
||||
fn into_any(self) -> AnyElement<V>;
|
||||
}
|
||||
|
||||
impl<S> IntoAnyElement<S> for AnyElement<S> {
|
||||
fn into_any(self) -> AnyElement<S> {
|
||||
impl<V> IntoAnyElement<V> for AnyElement<V> {
|
||||
fn into_any(self) -> AnyElement<V> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -1,15 +1,15 @@
|
||||
use crate::{
|
||||
Active, AnonymousElement, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase,
|
||||
Element, ElementId, ElementIdentity, Hover, IdentifiedElement, Interactive, IntoAnyElement,
|
||||
LayoutId, MouseClickEvent, MouseDownEvent, MouseEventListeners, MouseMoveEvent, MouseUpEvent,
|
||||
Overflow, ParentElement, Pixels, Point, ScrollWheelEvent, SharedString, Style, StyleRefinement,
|
||||
Styled, ViewContext,
|
||||
Active, Anonymous, AnyElement, AppContext, BorrowWindow, Bounds, Click, DispatchPhase, Element,
|
||||
ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, FocusHandle, Focusable,
|
||||
Hover, Identified, Interactive, IntoAnyElement, LayoutId, MouseClickEvent, MouseDownEvent,
|
||||
MouseMoveEvent, MouseUpEvent, NonFocusable, Overflow, ParentElement, Pixels, Point,
|
||||
ScrollWheelEvent, SharedString, Style, StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
use std::sync::Arc;
|
||||
use std::{mem, sync::Arc};
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct DivState {
|
||||
@ -60,12 +60,13 @@ impl ScrollState {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn div<S>() -> Div<S, AnonymousElement>
|
||||
pub fn div<V>() -> Div<V, Anonymous, NonFocusable>
|
||||
where
|
||||
S: 'static + Send + Sync,
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
Div {
|
||||
kind: AnonymousElement,
|
||||
identity: Anonymous,
|
||||
focusability: NonFocusable,
|
||||
children: SmallVec::new(),
|
||||
group: None,
|
||||
base_style: StyleRefinement::default(),
|
||||
@ -73,12 +74,20 @@ where
|
||||
group_hover: None,
|
||||
active_style: StyleRefinement::default(),
|
||||
group_active: None,
|
||||
listeners: MouseEventListeners::default(),
|
||||
focus_style: StyleRefinement::default(),
|
||||
focus_in_style: StyleRefinement::default(),
|
||||
in_focus_style: StyleRefinement::default(),
|
||||
listeners: EventListeners::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Div<V: 'static + Send + Sync, K: ElementIdentity = AnonymousElement> {
|
||||
kind: K,
|
||||
pub struct Div<
|
||||
V: 'static + Send + Sync,
|
||||
I: ElementIdentity = Anonymous,
|
||||
F: ElementFocusability = NonFocusable,
|
||||
> {
|
||||
identity: I,
|
||||
focusability: F,
|
||||
children: SmallVec<[AnyElement<V>; 2]>,
|
||||
group: Option<SharedString>,
|
||||
base_style: StyleRefinement,
|
||||
@ -86,7 +95,10 @@ pub struct Div<V: 'static + Send + Sync, K: ElementIdentity = AnonymousElement>
|
||||
group_hover: Option<GroupStyle>,
|
||||
active_style: StyleRefinement,
|
||||
group_active: Option<GroupStyle>,
|
||||
listeners: MouseEventListeners<V>,
|
||||
focus_style: StyleRefinement,
|
||||
focus_in_style: StyleRefinement,
|
||||
in_focus_style: StyleRefinement,
|
||||
listeners: EventListeners<V>,
|
||||
}
|
||||
|
||||
struct GroupStyle {
|
||||
@ -94,13 +106,15 @@ struct GroupStyle {
|
||||
style: StyleRefinement,
|
||||
}
|
||||
|
||||
impl<V> Div<V, AnonymousElement>
|
||||
impl<V, F> Div<V, Anonymous, F>
|
||||
where
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, IdentifiedElement> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Div<V, Identified, F> {
|
||||
Div {
|
||||
kind: IdentifiedElement(id.into()),
|
||||
identity: Identified(id.into()),
|
||||
focusability: self.focusability,
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
base_style: self.base_style,
|
||||
@ -108,15 +122,19 @@ where
|
||||
group_hover: self.group_hover,
|
||||
active_style: self.active_style,
|
||||
group_active: self.group_active,
|
||||
focus_style: self.focus_style,
|
||||
focus_in_style: self.focus_in_style,
|
||||
in_focus_style: self.in_focus_style,
|
||||
listeners: self.listeners,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Div<V, K>
|
||||
impl<V, I, F> Div<V, I, F>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
{
|
||||
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||
self.group = Some(group.into());
|
||||
@ -187,6 +205,20 @@ where
|
||||
let mut computed_style = Style::default();
|
||||
computed_style.refine(&self.base_style);
|
||||
|
||||
if let Some(handle) = self.focusability.focus_handle() {
|
||||
if handle.contains_focused(cx) {
|
||||
computed_style.refine(&self.focus_in_style);
|
||||
}
|
||||
|
||||
if handle.within_focused(cx) {
|
||||
computed_style.refine(&self.in_focus_style);
|
||||
}
|
||||
|
||||
if handle.is_focused(cx) {
|
||||
computed_style.refine(&self.focus_style);
|
||||
}
|
||||
}
|
||||
|
||||
let mouse_position = cx.mouse_position();
|
||||
|
||||
if let Some(group_hover) = self.group_hover.as_ref() {
|
||||
@ -258,12 +290,12 @@ where
|
||||
}
|
||||
|
||||
fn paint_event_listeners(
|
||||
&self,
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
pending_click: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let click_listeners = self.listeners.mouse_click.clone();
|
||||
let click_listeners = mem::take(&mut self.listeners.mouse_click);
|
||||
let mouse_down = pending_click.lock().clone();
|
||||
if let Some(mouse_down) = mouse_down {
|
||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||
@ -287,25 +319,25 @@ where
|
||||
});
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_down.iter().cloned() {
|
||||
for listener in mem::take(&mut self.listeners.mouse_down) {
|
||||
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_up.iter().cloned() {
|
||||
for listener in mem::take(&mut self.listeners.mouse_up) {
|
||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.mouse_move.iter().cloned() {
|
||||
for listener in mem::take(&mut self.listeners.mouse_move) {
|
||||
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in self.listeners.scroll_wheel.iter().cloned() {
|
||||
for listener in mem::take(&mut self.listeners.scroll_wheel) {
|
||||
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
@ -313,26 +345,92 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Element for Div<V, K>
|
||||
impl<V, I> Div<V, I, NonFocusable>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
pub fn focusable(self, handle: &FocusHandle) -> Div<V, I, Focusable> {
|
||||
Div {
|
||||
identity: self.identity,
|
||||
focusability: handle.clone().into(),
|
||||
children: self.children,
|
||||
group: self.group,
|
||||
base_style: self.base_style,
|
||||
hover_style: self.hover_style,
|
||||
group_hover: self.group_hover,
|
||||
active_style: self.active_style,
|
||||
group_active: self.group_active,
|
||||
focus_style: self.focus_style,
|
||||
focus_in_style: self.focus_in_style,
|
||||
in_focus_style: self.in_focus_style,
|
||||
listeners: self.listeners,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I> Focus for Div<V, I, Focusable>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
fn handle(&self) -> &FocusHandle {
|
||||
self.focusability.as_ref()
|
||||
}
|
||||
|
||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.focus_style = style;
|
||||
}
|
||||
|
||||
fn set_focus_in_style(&mut self, style: StyleRefinement) {
|
||||
self.focus_in_style = style;
|
||||
}
|
||||
|
||||
fn set_in_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.in_focus_style = style;
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Element for Div<V, I, F>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
{
|
||||
type ViewState = V;
|
||||
type ElementState = DivState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.kind.id()
|
||||
self.identity.id()
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> Self::ElementState {
|
||||
cx.with_focus(
|
||||
self.focusability.focus_handle().cloned(),
|
||||
mem::take(&mut self.listeners.key_down),
|
||||
mem::take(&mut self.listeners.key_up),
|
||||
mem::take(&mut self.listeners.focus),
|
||||
|cx| {
|
||||
for child in &mut self.children {
|
||||
child.initialize(view_state, cx);
|
||||
}
|
||||
element_state.unwrap_or_default()
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
let element_state = element_state.unwrap_or_default();
|
||||
let style = self.compute_style(Bounds::default(), &element_state, cx);
|
||||
) -> LayoutId {
|
||||
let style = self.compute_style(Bounds::default(), element_state, cx);
|
||||
style.apply_text_style(cx, |cx| {
|
||||
self.with_element_id(cx, |this, cx| {
|
||||
let layout_ids = this
|
||||
@ -340,9 +438,7 @@ where
|
||||
.iter_mut()
|
||||
.map(|child| child.layout(view_state, cx))
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
let layout_id = cx.request_layout(&style, layout_ids);
|
||||
(layout_id, element_state)
|
||||
cx.request_layout(&style, layout_ids)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -410,50 +506,55 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> IntoAnyElement<V> for Div<V, K>
|
||||
impl<V, I, F> IntoAnyElement<V> for Div<V, I, F>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> ParentElement for Div<V, K>
|
||||
impl<V, I, F> ParentElement for Div<V, I, F>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
{
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]> {
|
||||
&mut self.children
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Styled for Div<V, K>
|
||||
impl<V, I, F> Styled for Div<V, I, F>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
&mut self.base_style
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Interactive for Div<V, K>
|
||||
impl<V, I, F> Interactive for Div<V, I, F>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
{
|
||||
fn listeners(&mut self) -> &mut MouseEventListeners<V> {
|
||||
fn listeners(&mut self) -> &mut EventListeners<V> {
|
||||
&mut self.listeners
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Hover for Div<V, K>
|
||||
impl<V, I, F> Hover for Div<V, I, F>
|
||||
where
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
{
|
||||
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||
if let Some(group) = group {
|
||||
@ -464,10 +565,16 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Click for Div<V, IdentifiedElement> where V: 'static + Send + Sync {}
|
||||
|
||||
impl<V> Active for Div<V, IdentifiedElement>
|
||||
impl<V, F> Click for Div<V, Identified, F>
|
||||
where
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
}
|
||||
|
||||
impl<V, F> Active for Div<V, Identified, F>
|
||||
where
|
||||
F: ElementFocusability,
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||
|
@ -1,18 +1,23 @@
|
||||
use crate::{
|
||||
div, Active, AnonymousElement, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,
|
||||
ElementId, ElementIdentity, Hover, IdentifiedElement, Interactive, IntoAnyElement, LayoutId,
|
||||
MouseEventListeners, Pixels, SharedString, StyleRefinement, Styled, ViewContext,
|
||||
div, Active, Anonymous, AnyElement, BorrowWindow, Bounds, Click, Div, DivState, Element,
|
||||
ElementFocusability, ElementId, ElementIdentity, EventListeners, Focus, Focusable, Hover,
|
||||
Identified, Interactive, IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString,
|
||||
StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Img<V: 'static + Send + Sync, K: ElementIdentity = AnonymousElement> {
|
||||
base: Div<V, K>,
|
||||
pub struct Img<
|
||||
V: 'static + Send + Sync,
|
||||
I: ElementIdentity = Anonymous,
|
||||
F: ElementFocusability = NonFocusable,
|
||||
> {
|
||||
base: Div<V, I, F>,
|
||||
uri: Option<SharedString>,
|
||||
grayscale: bool,
|
||||
}
|
||||
|
||||
pub fn img<V>() -> Img<V, AnonymousElement>
|
||||
pub fn img<V>() -> Img<V, Anonymous, NonFocusable>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
@ -23,10 +28,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Img<V, K>
|
||||
impl<V, I, F> Img<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
|
||||
self.uri = Some(uri.into());
|
||||
@ -39,8 +45,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> Img<V, AnonymousElement> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, IdentifiedElement> {
|
||||
impl<V, F> Img<V, Anonymous, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, Identified, F> {
|
||||
Img {
|
||||
base: self.base.id(id),
|
||||
uri: self.uri,
|
||||
@ -49,20 +59,22 @@ impl<V: 'static + Send + Sync> Img<V, AnonymousElement> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> IntoAnyElement<V> for Img<V, K>
|
||||
impl<V, I, F> IntoAnyElement<V> for Img<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Element for Img<V, K>
|
||||
impl<V, I, F> Element for Img<V, I, F>
|
||||
where
|
||||
V: Send + Sync + 'static,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
type ViewState = V;
|
||||
type ElementState = DivState;
|
||||
@ -71,24 +83,30 @@ where
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
view_state: &mut V,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
self.base.initialize(view_state, element_state, cx)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
view_state: &mut V,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
) -> LayoutId {
|
||||
self.base.layout(view_state, element_state, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
view: &mut Self::ViewState,
|
||||
view: &mut V,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
cx.stack(0, |cx| {
|
||||
self.base.paint(bounds, view, element_state, cx);
|
||||
@ -121,43 +139,74 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Styled for Img<V, K>
|
||||
impl<V, I, F> Styled for Img<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.base.style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Interactive for Img<V, K>
|
||||
impl<V, I, F> Interactive for Img<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn listeners(&mut self) -> &mut MouseEventListeners<V> {
|
||||
fn listeners(&mut self) -> &mut EventListeners<V> {
|
||||
self.base.listeners()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Hover for Img<V, K>
|
||||
impl<V, I, F> Hover for Img<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||
self.base.set_hover_style(group, style);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Click for Img<V, IdentifiedElement> where V: 'static + Send + Sync {}
|
||||
|
||||
impl<V> Active for Img<V, IdentifiedElement>
|
||||
impl<V, F> Click for Img<V, Identified, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
}
|
||||
|
||||
impl<V, F> Active for Img<V, Identified, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||
self.base.set_active_style(group, style)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I> Focus for Img<V, I, Focusable>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
I: ElementIdentity,
|
||||
{
|
||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_style(style)
|
||||
}
|
||||
|
||||
fn set_focus_in_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_in_style(style)
|
||||
}
|
||||
|
||||
fn set_in_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_in_focus_style(style)
|
||||
}
|
||||
|
||||
fn handle(&self) -> &crate::FocusHandle {
|
||||
self.base.handle()
|
||||
}
|
||||
}
|
||||
|
@ -1,16 +1,21 @@
|
||||
use crate::{
|
||||
div, Active, AnonymousElement, AnyElement, Bounds, Click, Div, DivState, Element, ElementId,
|
||||
ElementIdentity, Hover, IdentifiedElement, Interactive, IntoAnyElement, LayoutId,
|
||||
MouseEventListeners, Pixels, SharedString, StyleRefinement, Styled,
|
||||
div, Active, Anonymous, AnyElement, Bounds, Click, Div, DivState, Element, ElementFocusability,
|
||||
ElementId, ElementIdentity, EventListeners, Focus, Focusable, Hover, Identified, Interactive,
|
||||
IntoAnyElement, LayoutId, NonFocusable, Pixels, SharedString, StyleRefinement, Styled,
|
||||
ViewContext,
|
||||
};
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Svg<V: 'static + Send + Sync, K: ElementIdentity = AnonymousElement> {
|
||||
base: Div<V, K>,
|
||||
pub struct Svg<
|
||||
V: 'static + Send + Sync,
|
||||
I: ElementIdentity = Anonymous,
|
||||
F: ElementFocusability = NonFocusable,
|
||||
> {
|
||||
base: Div<V, I, F>,
|
||||
path: Option<SharedString>,
|
||||
}
|
||||
|
||||
pub fn svg<V>() -> Svg<V, AnonymousElement>
|
||||
pub fn svg<V>() -> Svg<V, Anonymous, NonFocusable>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
@ -20,10 +25,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Svg<V, K>
|
||||
impl<V, I, F> Svg<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
||||
self.path = Some(path.into());
|
||||
@ -31,8 +37,12 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static + Send + Sync> Svg<V, AnonymousElement> {
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, IdentifiedElement> {
|
||||
impl<V, F> Svg<V, Anonymous, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, Identified, F> {
|
||||
Svg {
|
||||
base: self.base.id(id),
|
||||
path: self.path,
|
||||
@ -40,20 +50,22 @@ impl<V: 'static + Send + Sync> Svg<V, AnonymousElement> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> IntoAnyElement<V> for Svg<V, K>
|
||||
impl<V, I, F> IntoAnyElement<V> for Svg<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Element for Svg<V, K>
|
||||
impl<V, I, F> Element for Svg<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
type ViewState = V;
|
||||
type ElementState = DivState;
|
||||
@ -62,16 +74,22 @@ where
|
||||
self.base.id()
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
view_state: &mut V,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
self.base.initialize(view_state, element_state, cx)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view: &mut V,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut crate::ViewContext<V>,
|
||||
) -> (LayoutId, Self::ElementState)
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base.layout(view, element_state, cx)
|
||||
view_state: &mut V,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> LayoutId {
|
||||
self.base.layout(view_state, element_state, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
@ -79,7 +97,7 @@ where
|
||||
bounds: Bounds<Pixels>,
|
||||
view: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut crate::ViewContext<V>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
@ -95,43 +113,74 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Styled for Svg<V, K>
|
||||
impl<V, I, F> Styled for Svg<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.base.style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Interactive for Svg<V, K>
|
||||
impl<V, I, F> Interactive for Svg<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn listeners(&mut self) -> &mut MouseEventListeners<V> {
|
||||
fn listeners(&mut self) -> &mut EventListeners<V> {
|
||||
self.base.listeners()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, K> Hover for Svg<V, K>
|
||||
impl<V, I, F> Hover for Svg<V, I, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
K: ElementIdentity,
|
||||
I: ElementIdentity,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn set_hover_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||
self.base.set_hover_style(group, style);
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Click for Svg<V, IdentifiedElement> where V: 'static + Send + Sync {}
|
||||
|
||||
impl<V> Active for Svg<V, IdentifiedElement>
|
||||
impl<V, F> Click for Svg<V, Identified, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
}
|
||||
|
||||
impl<V, F> Active for Svg<V, Identified, F>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
F: ElementFocusability,
|
||||
{
|
||||
fn set_active_style(&mut self, group: Option<SharedString>, style: StyleRefinement) {
|
||||
self.base.set_active_style(group, style)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I> Focus for Svg<V, I, Focusable>
|
||||
where
|
||||
V: 'static + Send + Sync,
|
||||
I: ElementIdentity,
|
||||
{
|
||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_style(style)
|
||||
}
|
||||
|
||||
fn set_focus_in_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_in_style(style)
|
||||
}
|
||||
|
||||
fn set_in_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_in_focus_style(style)
|
||||
}
|
||||
|
||||
fn handle(&self) -> &crate::FocusHandle {
|
||||
self.base.handle()
|
||||
}
|
||||
}
|
||||
|
@ -39,31 +39,40 @@ impl<S: 'static + Send + Sync> IntoAnyElement<S> for String {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Text<S> {
|
||||
pub struct Text<V> {
|
||||
text: SharedString,
|
||||
state_type: PhantomData<S>,
|
||||
state_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<S: 'static + Send + Sync> IntoAnyElement<S> for Text<S> {
|
||||
fn into_any(self) -> AnyElement<S> {
|
||||
impl<V: 'static + Send + Sync> IntoAnyElement<V> for Text<V> {
|
||||
fn into_any(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: 'static + Send + Sync> Element for Text<S> {
|
||||
type ViewState = S;
|
||||
impl<V: 'static + Send + Sync> Element for Text<V> {
|
||||
type ViewState = V;
|
||||
type ElementState = Arc<Mutex<Option<TextElementState>>>;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
None
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
_view_state: &mut V,
|
||||
element_state: Option<Self::ElementState>,
|
||||
_cx: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
element_state.unwrap_or_default()
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_view: &mut S,
|
||||
_element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<S>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
_view: &mut V,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> LayoutId {
|
||||
let text_system = cx.text_system().clone();
|
||||
let text_style = cx.text_style();
|
||||
let font_size = text_style.font_size * cx.rem_size();
|
||||
@ -71,7 +80,6 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
|
||||
.line_height
|
||||
.to_pixels(font_size.into(), cx.rem_size());
|
||||
let text = self.text.clone();
|
||||
let element_state = Arc::new(Mutex::new(None));
|
||||
|
||||
let rem_size = cx.rem_size();
|
||||
let layout_id = cx.request_measured_layout(Default::default(), rem_size, {
|
||||
@ -102,15 +110,15 @@ impl<S: 'static + Send + Sync> Element for Text<S> {
|
||||
}
|
||||
});
|
||||
|
||||
(layout_id, element_state)
|
||||
layout_id
|
||||
}
|
||||
|
||||
fn paint<'a>(
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
_: &mut Self::ViewState,
|
||||
_: &mut V,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<S>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let element_state = element_state.lock();
|
||||
let element_state = element_state
|
||||
|
@ -1,4 +1,7 @@
|
||||
use crate::{point, Keystroke, Modifiers, Pixels, Point};
|
||||
use crate::{
|
||||
point, Bounds, DispatchPhase, FocusHandle, Keystroke, Modifiers, Pixels, Point, ViewContext,
|
||||
};
|
||||
use smallvec::SmallVec;
|
||||
use std::{any::Any, ops::Deref};
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
@ -26,7 +29,7 @@ impl Deref for ModifiersChangedEvent {
|
||||
}
|
||||
|
||||
/// The phase of a touch motion event.
|
||||
/// Based on the winit enum of the same name,
|
||||
/// Based on the winit enum of the same name.
|
||||
#[derive(Clone, Copy, Debug)]
|
||||
pub enum TouchPhase {
|
||||
Started,
|
||||
@ -50,6 +53,12 @@ pub struct MouseUpEvent {
|
||||
pub click_count: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Default)]
|
||||
pub struct MouseClickEvent {
|
||||
pub down: MouseDownEvent,
|
||||
pub up: MouseUpEvent,
|
||||
}
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub enum MouseButton {
|
||||
Left,
|
||||
@ -155,7 +164,7 @@ impl Deref for MouseExitEvent {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum Event {
|
||||
pub enum InputEvent {
|
||||
KeyDown(KeyDownEvent),
|
||||
KeyUp(KeyUpEvent),
|
||||
ModifiersChanged(ModifiersChangedEvent),
|
||||
@ -166,30 +175,112 @@ pub enum Event {
|
||||
ScrollWheel(ScrollWheelEvent),
|
||||
}
|
||||
|
||||
impl Event {
|
||||
impl InputEvent {
|
||||
pub fn position(&self) -> Option<Point<Pixels>> {
|
||||
match self {
|
||||
Event::KeyDown { .. } => None,
|
||||
Event::KeyUp { .. } => None,
|
||||
Event::ModifiersChanged { .. } => None,
|
||||
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),
|
||||
InputEvent::KeyDown { .. } => None,
|
||||
InputEvent::KeyUp { .. } => None,
|
||||
InputEvent::ModifiersChanged { .. } => None,
|
||||
InputEvent::MouseDown(event) => Some(event.position),
|
||||
InputEvent::MouseUp(event) => Some(event.position),
|
||||
InputEvent::MouseMoved(event) => Some(event.position),
|
||||
InputEvent::MouseExited(event) => Some(event.position),
|
||||
InputEvent::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),
|
||||
Event::MouseMoved(event) => Some(event),
|
||||
Event::MouseExited(event) => Some(event),
|
||||
Event::ScrollWheel(event) => Some(event),
|
||||
InputEvent::KeyDown { .. } => None,
|
||||
InputEvent::KeyUp { .. } => None,
|
||||
InputEvent::ModifiersChanged { .. } => None,
|
||||
InputEvent::MouseDown(event) => Some(event),
|
||||
InputEvent::MouseUp(event) => Some(event),
|
||||
InputEvent::MouseMoved(event) => Some(event),
|
||||
InputEvent::MouseExited(event) => Some(event),
|
||||
InputEvent::ScrollWheel(event) => Some(event),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn keyboard_event<'a>(&'a self) -> Option<&'a dyn Any> {
|
||||
match self {
|
||||
InputEvent::KeyDown(event) => Some(event),
|
||||
InputEvent::KeyUp(event) => Some(event),
|
||||
InputEvent::ModifiersChanged(event) => Some(event),
|
||||
InputEvent::MouseDown(_) => None,
|
||||
InputEvent::MouseUp(_) => None,
|
||||
InputEvent::MouseMoved(_) => None,
|
||||
InputEvent::MouseExited(_) => None,
|
||||
InputEvent::ScrollWheel(_) => None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct FocusEvent {
|
||||
pub blurred: Option<FocusHandle>,
|
||||
pub focused: Option<FocusHandle>,
|
||||
}
|
||||
|
||||
pub type MouseDownListener<V> = Box<
|
||||
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
pub type MouseUpListener<V> = Box<
|
||||
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
pub type MouseClickListener<V> =
|
||||
Box<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub type MouseMoveListener<V> = Box<
|
||||
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub type ScrollWheelListener<V> = Box<
|
||||
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub type KeyDownListener<V> =
|
||||
Box<dyn Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub type KeyUpListener<V> =
|
||||
Box<dyn Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub type FocusListener<V> =
|
||||
Box<dyn Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
pub struct EventListeners<V: 'static> {
|
||||
pub mouse_down: SmallVec<[MouseDownListener<V>; 2]>,
|
||||
pub mouse_up: SmallVec<[MouseUpListener<V>; 2]>,
|
||||
pub mouse_click: SmallVec<[MouseClickListener<V>; 2]>,
|
||||
pub mouse_move: SmallVec<[MouseMoveListener<V>; 2]>,
|
||||
pub scroll_wheel: SmallVec<[ScrollWheelListener<V>; 2]>,
|
||||
pub key_down: SmallVec<[KeyDownListener<V>; 2]>,
|
||||
pub key_up: SmallVec<[KeyUpListener<V>; 2]>,
|
||||
pub focus: SmallVec<[FocusListener<V>; 2]>,
|
||||
}
|
||||
|
||||
impl<V> Default for EventListeners<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mouse_down: SmallVec::new(),
|
||||
mouse_up: SmallVec::new(),
|
||||
mouse_click: SmallVec::new(),
|
||||
mouse_move: SmallVec::new(),
|
||||
scroll_wheel: SmallVec::new(),
|
||||
key_down: SmallVec::new(),
|
||||
key_up: SmallVec::new(),
|
||||
focus: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
159
crates/gpui3/src/focus.rs
Normal file
159
crates/gpui3/src/focus.rs
Normal file
@ -0,0 +1,159 @@
|
||||
use crate::{
|
||||
DispatchPhase, FocusEvent, FocusHandle, Interactive, KeyDownEvent, KeyUpEvent, StyleRefinement,
|
||||
ViewContext,
|
||||
};
|
||||
|
||||
pub trait Focus: Interactive {
|
||||
fn set_focus_style(&mut self, style: StyleRefinement);
|
||||
fn set_focus_in_style(&mut self, style: StyleRefinement);
|
||||
fn set_in_focus_style(&mut self, style: StyleRefinement);
|
||||
fn handle(&self) -> &FocusHandle;
|
||||
|
||||
fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_focus_style(f(StyleRefinement::default()));
|
||||
self
|
||||
}
|
||||
|
||||
fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_focus_in_style(f(StyleRefinement::default()));
|
||||
self
|
||||
}
|
||||
|
||||
fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_in_focus_style(f(StyleRefinement::default()));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event.focused.as_ref() == Some(&handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_blur(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event.blurred.as_ref() == Some(&handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus_in(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event
|
||||
.focused
|
||||
.as_ref()
|
||||
.map_or(false, |focused| focused.contains(&handle, cx))
|
||||
{
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus_out(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &FocusEvent, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
let handle = self.handle().clone();
|
||||
self.listeners()
|
||||
.focus
|
||||
.push(Box::new(move |view, event, cx| {
|
||||
if event
|
||||
.blurred
|
||||
.as_ref()
|
||||
.map_or(false, |blurred| handle.contains(&blurred, cx))
|
||||
{
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_key_down(
|
||||
mut self,
|
||||
listener: impl Fn(
|
||||
&mut Self::ViewState,
|
||||
&KeyDownEvent,
|
||||
DispatchPhase,
|
||||
&mut ViewContext<Self::ViewState>,
|
||||
) + Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners().key_down.push(Box::new(listener));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_key_up(
|
||||
mut self,
|
||||
listener: impl Fn(&mut Self::ViewState, &KeyUpEvent, DispatchPhase, &mut ViewContext<Self::ViewState>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.listeners().key_up.push(Box::new(listener));
|
||||
self
|
||||
}
|
||||
}
|
@ -6,6 +6,7 @@ mod element;
|
||||
mod elements;
|
||||
mod events;
|
||||
mod executor;
|
||||
mod focus;
|
||||
mod geometry;
|
||||
mod hover;
|
||||
mod image_cache;
|
||||
@ -31,6 +32,7 @@ pub use element::*;
|
||||
pub use elements::*;
|
||||
pub use events::*;
|
||||
pub use executor::*;
|
||||
pub use focus::*;
|
||||
pub use geometry::*;
|
||||
pub use gpui3_macros::*;
|
||||
pub use hover::*;
|
||||
|
@ -1,13 +1,10 @@
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::{
|
||||
Bounds, DispatchPhase, Element, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent,
|
||||
Pixels, ScrollWheelEvent, ViewContext,
|
||||
DispatchPhase, Element, EventListeners, MouseButton, MouseClickEvent, MouseDownEvent,
|
||||
MouseMoveEvent, MouseUpEvent, ScrollWheelEvent, ViewContext,
|
||||
};
|
||||
use std::sync::Arc;
|
||||
|
||||
pub trait Interactive: Element {
|
||||
fn listeners(&mut self) -> &mut MouseEventListeners<Self::ViewState>;
|
||||
fn listeners(&mut self) -> &mut EventListeners<Self::ViewState>;
|
||||
|
||||
fn on_mouse_down(
|
||||
mut self,
|
||||
@ -22,7 +19,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_down
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
@ -46,7 +43,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_up
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
@ -70,7 +67,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_down
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
@ -94,7 +91,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_up
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
@ -117,7 +114,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_move
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
@ -137,7 +134,7 @@ pub trait Interactive: Element {
|
||||
{
|
||||
self.listeners()
|
||||
.scroll_wheel
|
||||
.push(Arc::new(move |view, event, bounds, phase, cx| {
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
@ -159,60 +156,7 @@ pub trait Click: Interactive {
|
||||
{
|
||||
self.listeners()
|
||||
.mouse_click
|
||||
.push(Arc::new(move |view, event, cx| handler(view, event, cx)));
|
||||
.push(Box::new(move |view, event, cx| handler(view, event, cx)));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
type MouseDownHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseDownEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type MouseUpHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseUpEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type MouseClickHandler<V> =
|
||||
Arc<dyn Fn(&mut V, &MouseClickEvent, &mut ViewContext<V>) + Send + Sync + 'static>;
|
||||
|
||||
type MouseMoveHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &MouseMoveEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
type ScrollWheelHandler<V> = Arc<
|
||||
dyn Fn(&mut V, &ScrollWheelEvent, &Bounds<Pixels>, DispatchPhase, &mut ViewContext<V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
>;
|
||||
|
||||
pub struct MouseEventListeners<V: 'static> {
|
||||
pub mouse_down: SmallVec<[MouseDownHandler<V>; 2]>,
|
||||
pub mouse_up: SmallVec<[MouseUpHandler<V>; 2]>,
|
||||
pub mouse_click: SmallVec<[MouseClickHandler<V>; 2]>,
|
||||
pub mouse_move: SmallVec<[MouseMoveHandler<V>; 2]>,
|
||||
pub scroll_wheel: SmallVec<[ScrollWheelHandler<V>; 2]>,
|
||||
}
|
||||
|
||||
impl<V> Default for MouseEventListeners<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
mouse_down: SmallVec::new(),
|
||||
mouse_up: SmallVec::new(),
|
||||
mouse_click: SmallVec::new(),
|
||||
mouse_move: SmallVec::new(),
|
||||
scroll_wheel: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct MouseClickEvent {
|
||||
pub down: MouseDownEvent,
|
||||
pub up: MouseUpEvent,
|
||||
}
|
||||
|
@ -5,9 +5,9 @@ mod mac;
|
||||
mod test;
|
||||
|
||||
use crate::{
|
||||
AnyWindowHandle, Bounds, DevicePixels, Event, Executor, Font, FontId, FontMetrics, FontRun,
|
||||
GlobalPixels, GlyphId, LineLayout, Pixels, Point, RenderGlyphParams, RenderImageParams,
|
||||
RenderSvgParams, Result, Scene, SharedString, Size,
|
||||
AnyWindowHandle, Bounds, DevicePixels, Executor, Font, FontId, FontMetrics, FontRun,
|
||||
GlobalPixels, GlyphId, InputEvent, LineLayout, Pixels, Point, RenderGlyphParams,
|
||||
RenderImageParams, RenderSvgParams, Result, Scene, SharedString, Size,
|
||||
};
|
||||
use anyhow::anyhow;
|
||||
use async_task::Runnable;
|
||||
@ -81,7 +81,7 @@ pub(crate) trait Platform: 'static {
|
||||
fn on_resign_active(&self, callback: Box<dyn FnMut()>);
|
||||
fn on_quit(&self, callback: Box<dyn FnMut()>);
|
||||
fn on_reopen(&self, callback: Box<dyn FnMut()>);
|
||||
fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>);
|
||||
fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>);
|
||||
|
||||
fn os_name(&self) -> &'static str;
|
||||
fn os_version(&self) -> Result<SemanticVersion>;
|
||||
@ -141,7 +141,7 @@ pub(crate) trait PlatformWindow {
|
||||
fn minimize(&self);
|
||||
fn zoom(&self);
|
||||
fn toggle_full_screen(&self);
|
||||
fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>);
|
||||
fn on_input(&self, callback: Box<dyn FnMut(InputEvent) -> bool>);
|
||||
fn on_active_status_change(&self, callback: Box<dyn FnMut(bool)>);
|
||||
fn on_resize(&self, callback: Box<dyn FnMut(Size<Pixels>, f32)>);
|
||||
fn on_fullscreen(&self, callback: Box<dyn FnMut(bool)>);
|
||||
|
@ -1,5 +1,5 @@
|
||||
use crate::{
|
||||
point, px, Event, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent,
|
||||
point, px, InputEvent, KeyDownEvent, KeyUpEvent, Keystroke, Modifiers, ModifiersChangedEvent,
|
||||
MouseButton, MouseDownEvent, MouseExitEvent, MouseMoveEvent, MouseUpEvent, NavigationDirection,
|
||||
Pixels, ScrollDelta, ScrollWheelEvent, TouchPhase,
|
||||
};
|
||||
@ -84,7 +84,7 @@ unsafe fn read_modifiers(native_event: id) -> Modifiers {
|
||||
}
|
||||
}
|
||||
|
||||
impl Event {
|
||||
impl InputEvent {
|
||||
pub unsafe fn from_native(native_event: id, window_height: Option<Pixels>) -> Option<Self> {
|
||||
let event_type = native_event.eventType();
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
use super::BoolExt;
|
||||
use crate::{
|
||||
AnyWindowHandle, ClipboardItem, CursorStyle, DisplayId, Event, Executor, MacDispatcher,
|
||||
AnyWindowHandle, ClipboardItem, CursorStyle, DisplayId, Executor, InputEvent, MacDispatcher,
|
||||
MacDisplay, MacDisplayLinker, MacTextSystem, MacWindow, PathPromptOptions, Platform,
|
||||
PlatformDisplay, PlatformTextSystem, PlatformWindow, Result, SemanticVersion, VideoTimestamp,
|
||||
WindowOptions,
|
||||
@ -153,7 +153,7 @@ pub struct MacPlatformState {
|
||||
resign_active: Option<Box<dyn FnMut()>>,
|
||||
reopen: Option<Box<dyn FnMut()>>,
|
||||
quit: Option<Box<dyn FnMut()>>,
|
||||
event: Option<Box<dyn FnMut(Event) -> bool>>,
|
||||
event: Option<Box<dyn FnMut(InputEvent) -> bool>>,
|
||||
// menu_command: Option<Box<dyn FnMut(&dyn Action)>>,
|
||||
// validate_menu_command: Option<Box<dyn FnMut(&dyn Action) -> bool>>,
|
||||
will_open_menu: Option<Box<dyn FnMut()>>,
|
||||
@ -621,7 +621,7 @@ impl Platform for MacPlatform {
|
||||
self.0.lock().reopen = Some(callback);
|
||||
}
|
||||
|
||||
fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>) {
|
||||
fn on_event(&self, callback: Box<dyn FnMut(InputEvent) -> bool>) {
|
||||
self.0.lock().event = Some(callback);
|
||||
}
|
||||
|
||||
@ -937,7 +937,7 @@ unsafe fn get_foreground_platform(object: &mut Object) -> &MacPlatform {
|
||||
|
||||
extern "C" fn send_event(this: &mut Object, _sel: Sel, native_event: id) {
|
||||
unsafe {
|
||||
if let Some(event) = Event::from_native(native_event, None) {
|
||||
if let Some(event) = InputEvent::from_native(native_event, None) {
|
||||
let platform = get_foreground_platform(this);
|
||||
if let Some(callback) = platform.0.lock().event.as_mut() {
|
||||
if !callback(event) {
|
||||
|
@ -1,7 +1,7 @@
|
||||
use super::{display_bounds_from_native, ns_string, MacDisplay, MetalRenderer, NSRange};
|
||||
use crate::{
|
||||
display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, Event, Executor,
|
||||
GlobalPixels, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,
|
||||
display_bounds_to_native, point, px, size, AnyWindowHandle, Bounds, Executor, GlobalPixels,
|
||||
InputEvent, KeyDownEvent, Keystroke, Modifiers, ModifiersChangedEvent, MouseButton,
|
||||
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels, PlatformAtlas, PlatformDisplay,
|
||||
PlatformInputHandler, PlatformWindow, Point, Scene, Size, Timer, WindowAppearance,
|
||||
WindowBounds, WindowKind, WindowOptions, WindowPromptLevel,
|
||||
@ -286,7 +286,7 @@ struct MacWindowState {
|
||||
renderer: MetalRenderer,
|
||||
scene_to_render: Option<Scene>,
|
||||
kind: WindowKind,
|
||||
event_callback: Option<Box<dyn FnMut(Event) -> bool>>,
|
||||
event_callback: Option<Box<dyn FnMut(InputEvent) -> bool>>,
|
||||
activate_callback: Option<Box<dyn FnMut(bool)>>,
|
||||
resize_callback: Option<Box<dyn FnMut(Size<Pixels>, f32)>>,
|
||||
fullscreen_callback: Option<Box<dyn FnMut(bool)>>,
|
||||
@ -300,7 +300,7 @@ struct MacWindowState {
|
||||
synthetic_drag_counter: usize,
|
||||
last_fresh_keydown: Option<Keystroke>,
|
||||
traffic_light_position: Option<Point<Pixels>>,
|
||||
previous_modifiers_changed_event: Option<Event>,
|
||||
previous_modifiers_changed_event: Option<InputEvent>,
|
||||
// State tracking what the IME did after the last request
|
||||
ime_state: ImeState,
|
||||
// Retains the last IME Text
|
||||
@ -854,7 +854,7 @@ impl PlatformWindow for MacWindow {
|
||||
.detach();
|
||||
}
|
||||
|
||||
fn on_event(&self, callback: Box<dyn FnMut(Event) -> bool>) {
|
||||
fn on_input(&self, callback: Box<dyn FnMut(InputEvent) -> bool>) {
|
||||
self.0.as_ref().lock().event_callback = Some(callback);
|
||||
}
|
||||
|
||||
@ -975,9 +975,9 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
|
||||
let mut lock = window_state.as_ref().lock();
|
||||
|
||||
let window_height = lock.content_size().height;
|
||||
let event = unsafe { Event::from_native(native_event, Some(window_height)) };
|
||||
let event = unsafe { InputEvent::from_native(native_event, Some(window_height)) };
|
||||
|
||||
if let Some(Event::KeyDown(event)) = event {
|
||||
if let Some(InputEvent::KeyDown(event)) = event {
|
||||
// For certain keystrokes, macOS will first dispatch a "key equivalent" event.
|
||||
// If that event isn't handled, it will then dispatch a "key down" event. GPUI
|
||||
// makes no distinction between these two types of events, so we need to ignore
|
||||
@ -1045,13 +1045,13 @@ extern "C" fn handle_key_event(this: &Object, native_event: id, key_equivalent:
|
||||
key: ime_text.clone().unwrap(),
|
||||
},
|
||||
};
|
||||
handled = callback(Event::KeyDown(event_with_ime_text));
|
||||
handled = callback(InputEvent::KeyDown(event_with_ime_text));
|
||||
}
|
||||
if !handled {
|
||||
// empty key happens when you type a deadkey in input composition.
|
||||
// (e.g. on a brazillian keyboard typing quote is a deadkey)
|
||||
if !event.keystroke.key.is_empty() {
|
||||
handled = callback(Event::KeyDown(event));
|
||||
handled = callback(InputEvent::KeyDown(event));
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1097,11 +1097,11 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||
let is_active = unsafe { lock.native_window.isKeyWindow() == YES };
|
||||
|
||||
let window_height = lock.content_size().height;
|
||||
let event = unsafe { Event::from_native(native_event, Some(window_height)) };
|
||||
let event = unsafe { InputEvent::from_native(native_event, Some(window_height)) };
|
||||
|
||||
if let Some(mut event) = event {
|
||||
let synthesized_second_event = match &mut event {
|
||||
Event::MouseDown(
|
||||
InputEvent::MouseDown(
|
||||
event @ MouseDownEvent {
|
||||
button: MouseButton::Left,
|
||||
modifiers: Modifiers { control: true, .. },
|
||||
@ -1118,7 +1118,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||
..*event
|
||||
};
|
||||
|
||||
Some(Event::MouseDown(MouseDownEvent {
|
||||
Some(InputEvent::MouseDown(MouseDownEvent {
|
||||
button: MouseButton::Right,
|
||||
..*event
|
||||
}))
|
||||
@ -1127,7 +1127,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||
// Because we map a ctrl-left_down to a right_down -> right_up let's ignore
|
||||
// the ctrl-left_up to avoid having a mismatch in button down/up events if the
|
||||
// user is still holding ctrl when releasing the left mouse button
|
||||
Event::MouseUp(MouseUpEvent {
|
||||
InputEvent::MouseUp(MouseUpEvent {
|
||||
button: MouseButton::Left,
|
||||
modifiers: Modifiers { control: true, .. },
|
||||
..
|
||||
@ -1140,7 +1140,7 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||
};
|
||||
|
||||
match &event {
|
||||
Event::MouseMoved(
|
||||
InputEvent::MouseMoved(
|
||||
event @ MouseMoveEvent {
|
||||
pressed_button: Some(_),
|
||||
..
|
||||
@ -1157,18 +1157,18 @@ extern "C" fn handle_view_event(this: &Object, _: Sel, native_event: id) {
|
||||
.detach();
|
||||
}
|
||||
|
||||
Event::MouseMoved(_) if !(is_active || lock.kind == WindowKind::PopUp) => return,
|
||||
InputEvent::MouseMoved(_) if !(is_active || lock.kind == WindowKind::PopUp) => return,
|
||||
|
||||
Event::MouseUp(MouseUpEvent {
|
||||
InputEvent::MouseUp(MouseUpEvent {
|
||||
button: MouseButton::Left,
|
||||
..
|
||||
}) => {
|
||||
lock.synthetic_drag_counter += 1;
|
||||
}
|
||||
|
||||
Event::ModifiersChanged(ModifiersChangedEvent { modifiers }) => {
|
||||
InputEvent::ModifiersChanged(ModifiersChangedEvent { modifiers }) => {
|
||||
// Only raise modifiers changed event when they have actually changed
|
||||
if let Some(Event::ModifiersChanged(ModifiersChangedEvent {
|
||||
if let Some(InputEvent::ModifiersChanged(ModifiersChangedEvent {
|
||||
modifiers: prev_modifiers,
|
||||
})) = &lock.previous_modifiers_changed_event
|
||||
{
|
||||
@ -1204,7 +1204,7 @@ extern "C" fn cancel_operation(this: &Object, _sel: Sel, _sender: id) {
|
||||
modifiers: Default::default(),
|
||||
key: ".".into(),
|
||||
};
|
||||
let event = Event::KeyDown(KeyDownEvent {
|
||||
let event = InputEvent::KeyDown(KeyDownEvent {
|
||||
keystroke: keystroke.clone(),
|
||||
is_held: false,
|
||||
});
|
||||
@ -1605,7 +1605,7 @@ async fn synthetic_drag(
|
||||
if lock.synthetic_drag_counter == drag_id {
|
||||
if let Some(mut callback) = lock.event_callback.take() {
|
||||
drop(lock);
|
||||
callback(Event::MouseMoved(event.clone()));
|
||||
callback(InputEvent::MouseMoved(event.clone()));
|
||||
window_state.lock().event_callback = Some(callback);
|
||||
}
|
||||
} else {
|
||||
|
@ -125,7 +125,7 @@ impl Platform for TestPlatform {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
fn on_event(&self, _callback: Box<dyn FnMut(crate::Event) -> bool>) {
|
||||
fn on_event(&self, _callback: Box<dyn FnMut(crate::InputEvent) -> bool>) {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
|
@ -6,12 +6,12 @@ use crate::{
|
||||
};
|
||||
use std::{marker::PhantomData, sync::Arc};
|
||||
|
||||
pub struct View<S: Send + Sync> {
|
||||
state: Handle<S>,
|
||||
render: Arc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S> + Send + Sync + 'static>,
|
||||
pub struct View<V: Send + Sync> {
|
||||
state: Handle<V>,
|
||||
render: Arc<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyElement<V> + Send + Sync + 'static>,
|
||||
}
|
||||
|
||||
impl<S: 'static + Send + Sync> View<S> {
|
||||
impl<V: 'static + Send + Sync> View<V> {
|
||||
pub fn into_any(self) -> AnyView {
|
||||
AnyView {
|
||||
view: Arc::new(Mutex::new(self)),
|
||||
@ -19,7 +19,7 @@ impl<S: 'static + Send + Sync> View<S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: Send + Sync> Clone for View<S> {
|
||||
impl<V: Send + Sync> Clone for View<V> {
|
||||
fn clone(&self) -> Self {
|
||||
Self {
|
||||
state: self.state.clone(),
|
||||
@ -28,13 +28,13 @@ impl<S: Send + Sync> Clone for View<S> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn view<S, E>(
|
||||
state: Handle<S>,
|
||||
render: impl Fn(&mut S, &mut ViewContext<S>) -> E + Send + Sync + 'static,
|
||||
) -> View<S>
|
||||
pub fn view<V, E>(
|
||||
state: Handle<V>,
|
||||
render: impl Fn(&mut V, &mut ViewContext<V>) -> E + Send + Sync + 'static,
|
||||
) -> View<V>
|
||||
where
|
||||
E: IntoAnyElement<S>,
|
||||
S: 'static + Send + Sync,
|
||||
E: IntoAnyElement<V>,
|
||||
V: 'static + Send + Sync,
|
||||
{
|
||||
View {
|
||||
state,
|
||||
@ -42,8 +42,8 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: 'static + Send + Sync, ParentViewState: 'static + Send + Sync>
|
||||
IntoAnyElement<ParentViewState> for View<S>
|
||||
impl<V: 'static + Send + Sync, ParentViewState: 'static + Send + Sync>
|
||||
IntoAnyElement<ParentViewState> for View<V>
|
||||
{
|
||||
fn into_any(self) -> AnyElement<ParentViewState> {
|
||||
AnyElement::new(EraseViewState {
|
||||
@ -53,74 +53,91 @@ impl<S: 'static + Send + Sync, ParentViewState: 'static + Send + Sync>
|
||||
}
|
||||
}
|
||||
|
||||
impl<S: 'static + Send + Sync> Element for View<S> {
|
||||
impl<V: 'static + Send + Sync> Element for View<V> {
|
||||
type ViewState = ();
|
||||
type ElementState = AnyElement<S>;
|
||||
type ElementState = AnyElement<V>;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
Some(ElementId::View(self.state.id))
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
_: &mut (),
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<()>,
|
||||
) -> Self::ElementState {
|
||||
self.state.update(cx, |state, cx| {
|
||||
let mut any_element = (self.render)(state, cx);
|
||||
any_element.initialize(state, cx);
|
||||
any_element
|
||||
})
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_: &mut Self::ViewState,
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
self.state.update(cx, |state, cx| {
|
||||
let mut element = (self.render)(state, cx);
|
||||
let layout_id = element.layout(state, cx);
|
||||
(layout_id, element)
|
||||
})
|
||||
_: &mut (),
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<()>,
|
||||
) -> LayoutId {
|
||||
self.state.update(cx, |state, cx| element.layout(state, cx))
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
_: Bounds<Pixels>,
|
||||
_: &mut Self::ViewState,
|
||||
_: &mut (),
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
cx: &mut ViewContext<()>,
|
||||
) {
|
||||
self.state
|
||||
.update(cx, |state, cx| element.paint(state, None, cx))
|
||||
}
|
||||
}
|
||||
|
||||
struct EraseViewState<ViewState: 'static + Send + Sync, ParentViewState> {
|
||||
view: View<ViewState>,
|
||||
parent_view_state_type: PhantomData<ParentViewState>,
|
||||
struct EraseViewState<V: 'static + Send + Sync, ParentV> {
|
||||
view: View<V>,
|
||||
parent_view_state_type: PhantomData<ParentV>,
|
||||
}
|
||||
|
||||
impl<ViewState, ParentViewState> IntoAnyElement<ParentViewState>
|
||||
for EraseViewState<ViewState, ParentViewState>
|
||||
impl<V, ParentV> IntoAnyElement<ParentV> for EraseViewState<V, ParentV>
|
||||
where
|
||||
ViewState: 'static + Send + Sync,
|
||||
ParentViewState: 'static + Send + Sync,
|
||||
V: 'static + Send + Sync,
|
||||
ParentV: 'static + Send + Sync,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<ParentViewState> {
|
||||
fn into_any(self) -> AnyElement<ParentV> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<ViewState, ParentViewState> Element for EraseViewState<ViewState, ParentViewState>
|
||||
impl<V, ParentV> Element for EraseViewState<V, ParentV>
|
||||
where
|
||||
ViewState: 'static + Send + Sync,
|
||||
ParentViewState: 'static + Send + Sync,
|
||||
V: 'static + Send + Sync,
|
||||
ParentV: 'static + Send + Sync,
|
||||
{
|
||||
type ViewState = ParentViewState;
|
||||
type ViewState = ParentV;
|
||||
type ElementState = AnyBox;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
Element::id(&self.view)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
fn initialize(
|
||||
&mut self,
|
||||
_: &mut Self::ViewState,
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
ViewObject::layout(&mut self.view, cx)
|
||||
) -> Self::ElementState {
|
||||
ViewObject::initialize(&mut self.view, cx)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_: &mut Self::ViewState,
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> LayoutId {
|
||||
ViewObject::layout(&mut self.view, element, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
@ -136,22 +153,31 @@ where
|
||||
|
||||
trait ViewObject: 'static + Send + Sync {
|
||||
fn entity_id(&self) -> EntityId;
|
||||
fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox);
|
||||
fn initialize(&mut self, cx: &mut WindowContext) -> AnyBox;
|
||||
fn layout(&mut self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId;
|
||||
fn paint(&mut self, bounds: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext);
|
||||
}
|
||||
|
||||
impl<S: Send + Sync + 'static> ViewObject for View<S> {
|
||||
impl<V: Send + Sync + 'static> ViewObject for View<V> {
|
||||
fn entity_id(&self) -> EntityId {
|
||||
self.state.id
|
||||
}
|
||||
|
||||
fn layout(&mut self, cx: &mut WindowContext) -> (LayoutId, AnyBox) {
|
||||
fn initialize(&mut self, cx: &mut WindowContext) -> AnyBox {
|
||||
cx.with_element_id(self.entity_id(), |cx| {
|
||||
self.state.update(cx, |state, cx| {
|
||||
let mut element = (self.render)(state, cx);
|
||||
let layout_id = element.layout(state, cx);
|
||||
let element = Box::new(element) as AnyBox;
|
||||
(layout_id, element)
|
||||
let mut any_element = Box::new((self.render)(state, cx));
|
||||
any_element.initialize(state, cx);
|
||||
any_element as AnyBox
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
fn layout(&mut self, element: &mut AnyBox, cx: &mut WindowContext) -> LayoutId {
|
||||
cx.with_element_id(self.entity_id(), |cx| {
|
||||
self.state.update(cx, |state, cx| {
|
||||
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
|
||||
element.layout(state, cx)
|
||||
})
|
||||
})
|
||||
}
|
||||
@ -159,7 +185,7 @@ impl<S: Send + Sync + 'static> ViewObject for View<S> {
|
||||
fn paint(&mut self, _: Bounds<Pixels>, element: &mut AnyBox, cx: &mut WindowContext) {
|
||||
cx.with_element_id(self.entity_id(), |cx| {
|
||||
self.state.update(cx, |state, cx| {
|
||||
let element = element.downcast_mut::<AnyElement<S>>().unwrap();
|
||||
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
|
||||
element.paint(state, None, cx);
|
||||
});
|
||||
});
|
||||
@ -170,11 +196,11 @@ pub struct AnyView {
|
||||
view: Arc<Mutex<dyn ViewObject>>,
|
||||
}
|
||||
|
||||
impl<ParentViewState> IntoAnyElement<ParentViewState> for AnyView
|
||||
impl<ParentV> IntoAnyElement<ParentV> for AnyView
|
||||
where
|
||||
ParentViewState: 'static + Send + Sync,
|
||||
ParentV: 'static + Send + Sync,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<ParentViewState> {
|
||||
fn into_any(self) -> AnyElement<ParentV> {
|
||||
AnyElement::new(EraseAnyViewState {
|
||||
view: self,
|
||||
parent_view_state_type: PhantomData,
|
||||
@ -190,13 +216,22 @@ impl Element for AnyView {
|
||||
Some(ElementId::View(self.view.lock().entity_id()))
|
||||
}
|
||||
|
||||
fn layout(
|
||||
fn initialize(
|
||||
&mut self,
|
||||
_: &mut Self::ViewState,
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
self.view.lock().layout(cx)
|
||||
) -> Self::ElementState {
|
||||
self.view.lock().initialize(cx)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_: &mut Self::ViewState,
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> LayoutId {
|
||||
self.view.lock().layout(element, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
@ -215,33 +250,42 @@ struct EraseAnyViewState<ParentViewState> {
|
||||
parent_view_state_type: PhantomData<ParentViewState>,
|
||||
}
|
||||
|
||||
impl<ParentViewState> IntoAnyElement<ParentViewState> for EraseAnyViewState<ParentViewState>
|
||||
impl<ParentV> IntoAnyElement<ParentV> for EraseAnyViewState<ParentV>
|
||||
where
|
||||
ParentViewState: 'static + Send + Sync,
|
||||
ParentV: 'static + Send + Sync,
|
||||
{
|
||||
fn into_any(self) -> AnyElement<ParentViewState> {
|
||||
fn into_any(self) -> AnyElement<ParentV> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<ParentViewState> Element for EraseAnyViewState<ParentViewState>
|
||||
impl<ParentV> Element for EraseAnyViewState<ParentV>
|
||||
where
|
||||
ParentViewState: 'static + Send + Sync,
|
||||
ParentV: 'static + Send + Sync,
|
||||
{
|
||||
type ViewState = ParentViewState;
|
||||
type ViewState = ParentV;
|
||||
type ElementState = AnyBox;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
Element::id(&self.view)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
fn initialize(
|
||||
&mut self,
|
||||
_: &mut Self::ViewState,
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState) {
|
||||
self.view.view.lock().layout(cx)
|
||||
) -> Self::ElementState {
|
||||
self.view.view.lock().initialize(cx)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
_: &mut Self::ViewState,
|
||||
element: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> LayoutId {
|
||||
self.view.view.lock().layout(element, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
@ -1,7 +1,8 @@
|
||||
use crate::{
|
||||
px, size, AnyBox, AnyView, AppContext, AsyncWindowContext, AvailableSpace, BorrowAppContext,
|
||||
Bounds, BoxShadow, Context, Corners, DevicePixels, DisplayId, Edges, Effect, Element, EntityId,
|
||||
Event, EventEmitter, FontId, GlobalElementId, GlyphId, Handle, Hsla, ImageData, IsZero,
|
||||
EventEmitter, FocusEvent, FocusListener, FontId, GlobalElementId, GlyphId, Handle, Hsla,
|
||||
ImageData, InputEvent, IsZero, KeyDownEvent, KeyDownListener, KeyUpEvent, KeyUpListener,
|
||||
LayoutId, MainThread, MainThreadOnly, MonochromeSprite, MouseMoveEvent, Path, Pixels, Platform,
|
||||
PlatformAtlas, PlatformWindow, Point, PolychromeSprite, Quad, Reference, RenderGlyphParams,
|
||||
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
|
||||
@ -21,7 +22,7 @@ use std::{
|
||||
mem,
|
||||
sync::Arc,
|
||||
};
|
||||
use util::ResultExt;
|
||||
use util::{post_inc, ResultExt};
|
||||
|
||||
#[derive(Deref, DerefMut, Ord, PartialOrd, Eq, PartialEq, Clone, Default)]
|
||||
pub struct StackingOrder(pub(crate) SmallVec<[u32; 16]>);
|
||||
@ -39,8 +40,55 @@ pub enum DispatchPhase {
|
||||
Capture,
|
||||
}
|
||||
|
||||
type MouseEventHandler =
|
||||
Arc<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyMouseEventListener =
|
||||
Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyboardEventListener =
|
||||
Box<dyn Fn(&dyn Any, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyFocusListener = Box<dyn Fn(&FocusEvent, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyDownListener =
|
||||
Box<dyn Fn(&KeyDownEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
type AnyKeyUpListener =
|
||||
Box<dyn Fn(&KeyUpEvent, DispatchPhase, &mut WindowContext) + Send + Sync + 'static>;
|
||||
|
||||
#[derive(Copy, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct FocusId(usize);
|
||||
|
||||
#[derive(Clone, PartialEq, Eq)]
|
||||
pub struct FocusHandle {
|
||||
pub(crate) id: FocusId,
|
||||
}
|
||||
|
||||
impl FocusHandle {
|
||||
pub(crate) fn new(id: FocusId) -> Self {
|
||||
Self { id }
|
||||
}
|
||||
|
||||
pub fn is_focused(&self, cx: &WindowContext) -> bool {
|
||||
cx.window.focus == Some(self.id)
|
||||
}
|
||||
|
||||
pub fn contains_focused(&self, cx: &WindowContext) -> bool {
|
||||
cx.focused()
|
||||
.map_or(false, |focused| self.contains(&focused, cx))
|
||||
}
|
||||
|
||||
pub fn within_focused(&self, cx: &WindowContext) -> bool {
|
||||
let focused = cx.focused();
|
||||
focused.map_or(false, |focused| focused.contains(self, cx))
|
||||
}
|
||||
|
||||
pub(crate) fn contains(&self, other: &Self, cx: &WindowContext) -> bool {
|
||||
let mut ancestor = Some(other.id);
|
||||
while let Some(ancestor_id) = ancestor {
|
||||
if self.id == ancestor_id {
|
||||
return true;
|
||||
} else {
|
||||
ancestor = cx.window.focus_parents_by_child.get(&ancestor_id).copied();
|
||||
}
|
||||
}
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Window {
|
||||
handle: AnyWindowHandle,
|
||||
@ -56,12 +104,19 @@ pub struct Window {
|
||||
element_states: HashMap<GlobalElementId, AnyBox>,
|
||||
z_index_stack: StackingOrder,
|
||||
content_mask_stack: Vec<ContentMask<Pixels>>,
|
||||
mouse_event_handlers: HashMap<TypeId, Vec<(StackingOrder, MouseEventHandler)>>,
|
||||
mouse_listeners: HashMap<TypeId, Vec<(StackingOrder, AnyMouseEventListener)>>,
|
||||
keyboard_listeners: HashMap<TypeId, Vec<AnyKeyboardEventListener>>,
|
||||
focus_stack: Vec<FocusStackFrame>,
|
||||
focus_parents_by_child: HashMap<FocusId, FocusId>,
|
||||
pub(crate) focus_listeners: Vec<AnyFocusListener>,
|
||||
propagate_event: bool,
|
||||
mouse_position: Point<Pixels>,
|
||||
scale_factor: f32,
|
||||
pub(crate) scene_builder: SceneBuilder,
|
||||
pub(crate) dirty: bool,
|
||||
pub(crate) last_blur: Option<Option<FocusId>>,
|
||||
pub(crate) focus: Option<FocusId>,
|
||||
next_focus_id: FocusId,
|
||||
}
|
||||
|
||||
impl Window {
|
||||
@ -95,7 +150,7 @@ impl Window {
|
||||
}
|
||||
}));
|
||||
|
||||
platform_window.on_event({
|
||||
platform_window.on_input({
|
||||
let cx = cx.to_async();
|
||||
Box::new(move |event| {
|
||||
cx.update_window(handle, |cx| cx.dispatch_event(event))
|
||||
@ -120,12 +175,19 @@ impl Window {
|
||||
element_states: HashMap::default(),
|
||||
z_index_stack: StackingOrder(SmallVec::new()),
|
||||
content_mask_stack: Vec::new(),
|
||||
mouse_event_handlers: HashMap::default(),
|
||||
mouse_listeners: HashMap::default(),
|
||||
keyboard_listeners: HashMap::default(),
|
||||
focus_stack: Vec::new(),
|
||||
focus_parents_by_child: HashMap::default(),
|
||||
focus_listeners: Vec::new(),
|
||||
propagate_event: true,
|
||||
mouse_position,
|
||||
scale_factor,
|
||||
scene_builder: SceneBuilder::new(),
|
||||
dirty: true,
|
||||
last_blur: None,
|
||||
focus: None,
|
||||
next_focus_id: FocusId(0),
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -149,6 +211,12 @@ impl ContentMask<Pixels> {
|
||||
}
|
||||
}
|
||||
|
||||
struct FocusStackFrame {
|
||||
handle: FocusHandle,
|
||||
key_down_listeners: SmallVec<[AnyKeyDownListener; 2]>,
|
||||
key_up_listeners: SmallVec<[AnyKeyUpListener; 2]>,
|
||||
}
|
||||
|
||||
pub struct WindowContext<'a, 'w> {
|
||||
app: Reference<'a, AppContext>,
|
||||
pub(crate) window: Reference<'w, Window>,
|
||||
@ -166,6 +234,43 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
self.window.dirty = true;
|
||||
}
|
||||
|
||||
pub fn focus_handle(&mut self) -> FocusHandle {
|
||||
let id = FocusId(post_inc(&mut self.window.next_focus_id.0));
|
||||
FocusHandle { id }
|
||||
}
|
||||
|
||||
pub fn focused(&self) -> Option<FocusHandle> {
|
||||
self.window.focus.map(|id| FocusHandle::new(id))
|
||||
}
|
||||
|
||||
pub fn focus(&mut self, handle: &FocusHandle) {
|
||||
if self.window.last_blur.is_none() {
|
||||
self.window.last_blur = Some(self.window.focus);
|
||||
}
|
||||
|
||||
let window_id = self.window.handle.id;
|
||||
self.window.focus = Some(handle.id);
|
||||
self.push_effect(Effect::FocusChanged {
|
||||
window_id,
|
||||
focused: Some(handle.id),
|
||||
});
|
||||
self.notify();
|
||||
}
|
||||
|
||||
pub fn blur(&mut self) {
|
||||
if self.window.last_blur.is_none() {
|
||||
self.window.last_blur = Some(self.window.focus);
|
||||
}
|
||||
|
||||
let window_id = self.window.handle.id;
|
||||
self.window.focus = None;
|
||||
self.push_effect(Effect::FocusChanged {
|
||||
window_id,
|
||||
focused: None,
|
||||
});
|
||||
self.notify();
|
||||
}
|
||||
|
||||
pub fn run_on_main<R>(
|
||||
&mut self,
|
||||
f: impl FnOnce(&mut MainThread<WindowContext<'_, '_>>) -> R + Send + 'static,
|
||||
@ -298,17 +403,30 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
) {
|
||||
let order = self.window.z_index_stack.clone();
|
||||
self.window
|
||||
.mouse_event_handlers
|
||||
.mouse_listeners
|
||||
.entry(TypeId::of::<Event>())
|
||||
.or_default()
|
||||
.push((
|
||||
order,
|
||||
Arc::new(move |event: &dyn Any, phase, cx| {
|
||||
Box::new(move |event: &dyn Any, phase, cx| {
|
||||
handler(event.downcast_ref().unwrap(), phase, cx)
|
||||
}),
|
||||
))
|
||||
}
|
||||
|
||||
pub fn on_keyboard_event<Event: 'static>(
|
||||
&mut self,
|
||||
handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + Send + Sync + 'static,
|
||||
) {
|
||||
self.window
|
||||
.keyboard_listeners
|
||||
.entry(TypeId::of::<Event>())
|
||||
.or_default()
|
||||
.push(Box::new(move |event: &dyn Any, phase, cx| {
|
||||
handler(event.downcast_ref().unwrap(), phase, cx)
|
||||
}))
|
||||
}
|
||||
|
||||
pub fn mouse_position(&self) -> Point<Pixels> {
|
||||
self.window.mouse_position
|
||||
}
|
||||
@ -628,7 +746,8 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
element_state: Option<AnyBox>,
|
||||
cx: &mut ViewContext<()>,
|
||||
) -> AnyBox {
|
||||
let (layout_id, mut element_state) = root_view.layout(&mut (), element_state, cx);
|
||||
let mut element_state = root_view.initialize(&mut (), element_state, cx);
|
||||
let layout_id = root_view.layout(&mut (), &mut element_state, cx);
|
||||
let available_space = cx.window.content_size.map(Into::into);
|
||||
cx.window
|
||||
.layout_engine
|
||||
@ -645,21 +764,24 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
// reference during the upcoming frame.
|
||||
let window = &mut *self.window;
|
||||
mem::swap(&mut window.element_states, &mut window.prev_element_states);
|
||||
self.window.element_states.clear();
|
||||
window.element_states.clear();
|
||||
|
||||
// Clear mouse event listeners, because elements add new element listeners
|
||||
// when the upcoming frame is painted.
|
||||
self.window
|
||||
.mouse_event_handlers
|
||||
.values_mut()
|
||||
.for_each(Vec::clear);
|
||||
window.mouse_listeners.values_mut().for_each(Vec::clear);
|
||||
|
||||
// Clear focus state, because we determine what is focused when the new elements
|
||||
// in the upcoming frame are initialized.
|
||||
window.focus_listeners.clear();
|
||||
window.keyboard_listeners.values_mut().for_each(Vec::clear);
|
||||
window.focus_parents_by_child.clear();
|
||||
}
|
||||
|
||||
fn end_frame(&mut self) {
|
||||
self.text_system().end_frame();
|
||||
}
|
||||
|
||||
fn dispatch_event(&mut self, event: Event) -> bool {
|
||||
fn dispatch_event(&mut self, event: InputEvent) -> bool {
|
||||
if let Some(any_mouse_event) = event.mouse_event() {
|
||||
if let Some(MouseMoveEvent { position, .. }) = any_mouse_event.downcast_ref() {
|
||||
self.window.mouse_position = *position;
|
||||
@ -667,7 +789,7 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
|
||||
if let Some(mut handlers) = self
|
||||
.window
|
||||
.mouse_event_handlers
|
||||
.mouse_listeners
|
||||
.remove(&any_mouse_event.type_id())
|
||||
{
|
||||
// Because handlers may add other handlers, we sort every time.
|
||||
@ -698,15 +820,48 @@ impl<'a, 'w> WindowContext<'a, 'w> {
|
||||
// Just in case any handlers added new handlers, which is weird, but possible.
|
||||
handlers.extend(
|
||||
self.window
|
||||
.mouse_event_handlers
|
||||
.mouse_listeners
|
||||
.get_mut(&any_mouse_event.type_id())
|
||||
.into_iter()
|
||||
.flat_map(|handlers| handlers.drain(..)),
|
||||
);
|
||||
self.window
|
||||
.mouse_event_handlers
|
||||
.mouse_listeners
|
||||
.insert(any_mouse_event.type_id(), handlers);
|
||||
}
|
||||
} else if let Some(any_keyboard_event) = event.keyboard_event() {
|
||||
if let Some(mut handlers) = self
|
||||
.window
|
||||
.keyboard_listeners
|
||||
.remove(&any_keyboard_event.type_id())
|
||||
{
|
||||
for handler in &handlers {
|
||||
handler(any_keyboard_event, DispatchPhase::Capture, self);
|
||||
if !self.window.propagate_event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if self.window.propagate_event {
|
||||
for handler in handlers.iter().rev() {
|
||||
handler(any_keyboard_event, DispatchPhase::Bubble, self);
|
||||
if !self.window.propagate_event {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
handlers.extend(
|
||||
self.window
|
||||
.keyboard_listeners
|
||||
.get_mut(&any_keyboard_event.type_id())
|
||||
.into_iter()
|
||||
.flat_map(|handlers| handlers.drain(..)),
|
||||
);
|
||||
self.window
|
||||
.keyboard_listeners
|
||||
.insert(any_keyboard_event.type_id(), handlers);
|
||||
}
|
||||
}
|
||||
|
||||
true
|
||||
@ -882,7 +1037,7 @@ impl<S> BorrowWindow for ViewContext<'_, '_, S> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
impl<'a, 'w, V: Send + Sync + 'static> ViewContext<'a, 'w, V> {
|
||||
fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
|
||||
Self {
|
||||
window_cx: WindowContext::mutable(app, window),
|
||||
@ -891,7 +1046,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn handle(&self) -> WeakHandle<S> {
|
||||
pub fn handle(&self) -> WeakHandle<V> {
|
||||
self.entities.weak_handle(self.entity_id)
|
||||
}
|
||||
|
||||
@ -902,7 +1057,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
result
|
||||
}
|
||||
|
||||
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut S, &mut ViewContext<S>) + Send + 'static) {
|
||||
pub fn on_next_frame(&mut self, f: impl FnOnce(&mut V, &mut ViewContext<V>) + Send + 'static) {
|
||||
let entity = self.handle();
|
||||
self.window_cx.on_next_frame(move |cx| {
|
||||
entity.update(cx, f).ok();
|
||||
@ -912,7 +1067,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
pub fn observe<E: Send + Sync + 'static>(
|
||||
&mut self,
|
||||
handle: &Handle<E>,
|
||||
on_notify: impl Fn(&mut S, Handle<E>, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
|
||||
on_notify: impl Fn(&mut V, Handle<E>, &mut ViewContext<'_, '_, V>) + Send + Sync + 'static,
|
||||
) -> Subscription {
|
||||
let this = self.handle();
|
||||
let handle = handle.downgrade();
|
||||
@ -936,7 +1091,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
pub fn subscribe<E: EventEmitter + Send + Sync + 'static>(
|
||||
&mut self,
|
||||
handle: &Handle<E>,
|
||||
on_event: impl Fn(&mut S, Handle<E>, &E::Event, &mut ViewContext<'_, '_, S>)
|
||||
on_event: impl Fn(&mut V, Handle<E>, &E::Event, &mut ViewContext<'_, '_, V>)
|
||||
+ Send
|
||||
+ Sync
|
||||
+ 'static,
|
||||
@ -963,7 +1118,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
|
||||
pub fn on_release(
|
||||
&mut self,
|
||||
on_release: impl Fn(&mut S, &mut WindowContext) + Send + Sync + 'static,
|
||||
on_release: impl Fn(&mut V, &mut WindowContext) + Send + Sync + 'static,
|
||||
) -> Subscription {
|
||||
let window_handle = self.window.handle;
|
||||
self.app.release_handlers.insert(
|
||||
@ -979,7 +1134,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
pub fn observe_release<E: Send + Sync + 'static>(
|
||||
&mut self,
|
||||
handle: &Handle<E>,
|
||||
on_release: impl Fn(&mut S, &mut E, &mut ViewContext<'_, '_, S>) + Send + Sync + 'static,
|
||||
on_release: impl Fn(&mut V, &mut E, &mut ViewContext<'_, '_, V>) + Send + Sync + 'static,
|
||||
) -> Subscription {
|
||||
let this = self.handle();
|
||||
let window_handle = self.window.handle;
|
||||
@ -1002,10 +1157,86 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
});
|
||||
}
|
||||
|
||||
pub fn with_focus<R>(
|
||||
&mut self,
|
||||
focus_handle: Option<FocusHandle>,
|
||||
key_down: impl IntoIterator<Item = KeyDownListener<V>>,
|
||||
key_up: impl IntoIterator<Item = KeyUpListener<V>>,
|
||||
focus: impl IntoIterator<Item = FocusListener<V>>,
|
||||
f: impl FnOnce(&mut Self) -> R,
|
||||
) -> R {
|
||||
let Some(focus_handle) = focus_handle else {
|
||||
return f(self);
|
||||
};
|
||||
|
||||
let handle = self.handle();
|
||||
let window = &mut *self.window;
|
||||
|
||||
for listener in focus {
|
||||
let handle = handle.clone();
|
||||
window.focus_listeners.push(Box::new(move |event, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
|
||||
let mut focus_stack = mem::take(&mut window.focus_stack);
|
||||
if let Some(parent_frame) = focus_stack.last() {
|
||||
window
|
||||
.focus_parents_by_child
|
||||
.insert(focus_handle.id, parent_frame.handle.id);
|
||||
}
|
||||
|
||||
let mut frame = FocusStackFrame {
|
||||
handle: focus_handle.clone(),
|
||||
key_down_listeners: SmallVec::new(),
|
||||
key_up_listeners: SmallVec::new(),
|
||||
};
|
||||
|
||||
for listener in key_down {
|
||||
let handle = handle.clone();
|
||||
frame
|
||||
.key_down_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, phase, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
for listener in key_up {
|
||||
let handle = handle.clone();
|
||||
frame
|
||||
.key_up_listeners
|
||||
.push(Box::new(move |event, phase, cx| {
|
||||
handle
|
||||
.update(cx, |view, cx| listener(view, event, phase, cx))
|
||||
.log_err();
|
||||
}));
|
||||
}
|
||||
focus_stack.push(frame);
|
||||
|
||||
if Some(focus_handle.id) == window.focus {
|
||||
for focus_frame in &mut focus_stack {
|
||||
for listener in focus_frame.key_down_listeners.drain(..) {
|
||||
self.window_cx.on_keyboard_event(listener);
|
||||
}
|
||||
for listener in focus_frame.key_up_listeners.drain(..) {
|
||||
self.window_cx.on_keyboard_event(listener);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
self.window.focus_stack = focus_stack;
|
||||
let result = f(self);
|
||||
self.window.focus_stack.pop();
|
||||
result
|
||||
}
|
||||
|
||||
pub fn run_on_main<R>(
|
||||
&mut self,
|
||||
view: &mut S,
|
||||
f: impl FnOnce(&mut S, &mut MainThread<ViewContext<'_, '_, S>>) -> R + Send + 'static,
|
||||
view: &mut V,
|
||||
f: impl FnOnce(&mut V, &mut MainThread<ViewContext<'_, '_, V>>) -> R + Send + 'static,
|
||||
) -> Task<Result<R>>
|
||||
where
|
||||
R: Send + 'static,
|
||||
@ -1021,7 +1252,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
|
||||
pub fn spawn<Fut, R>(
|
||||
&mut self,
|
||||
f: impl FnOnce(WeakHandle<S>, AsyncWindowContext) -> Fut + Send + 'static,
|
||||
f: impl FnOnce(WeakHandle<V>, AsyncWindowContext) -> Fut + Send + 'static,
|
||||
) -> Task<R>
|
||||
where
|
||||
R: Send + 'static,
|
||||
@ -1036,7 +1267,7 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
|
||||
pub fn on_mouse_event<Event: 'static>(
|
||||
&mut self,
|
||||
handler: impl Fn(&mut S, &Event, DispatchPhase, &mut ViewContext<S>) + Send + Sync + 'static,
|
||||
handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) {
|
||||
let handle = self.handle().upgrade(self).unwrap();
|
||||
self.window_cx.on_mouse_event(move |event, phase, cx| {
|
||||
@ -1045,6 +1276,18 @@ impl<'a, 'w, S: Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
pub fn on_keyboard_event<Event: 'static>(
|
||||
&mut self,
|
||||
handler: impl Fn(&mut V, &Event, DispatchPhase, &mut ViewContext<V>) + Send + Sync + 'static,
|
||||
) {
|
||||
let handle = self.handle().upgrade(self).unwrap();
|
||||
self.window_cx.on_keyboard_event(move |event, phase, cx| {
|
||||
handle.update(cx, |view, cx| {
|
||||
handler(view, event, phase, cx);
|
||||
})
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, 'w, S: EventEmitter + Send + Sync + 'static> ViewContext<'a, 'w, S> {
|
||||
|
@ -57,27 +57,36 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
|
||||
None
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
_: Option<Self::ElementState>,
|
||||
cx: &mut gpui3::ViewContext<Self::ViewState>
|
||||
) -> Self::ElementState {
|
||||
use gpui3::IntoAnyElement;
|
||||
|
||||
let mut element = self.render(view_state, cx).into_any();
|
||||
element.initialize(view_state, cx);
|
||||
element
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
rendered_element: &mut Self::ElementState,
|
||||
cx: &mut gpui3::ViewContext<Self::ViewState>,
|
||||
) -> (gpui3::LayoutId, Self::ElementState) {
|
||||
use gpui3::IntoAnyElement;
|
||||
|
||||
let mut rendered_element = self.render(view_state, cx).into_any();
|
||||
let layout_id = rendered_element.layout(view_state, cx);
|
||||
(layout_id, rendered_element)
|
||||
) -> gpui3::LayoutId {
|
||||
rendered_element.layout(view_state, cx)
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: gpui3::Bounds<gpui3::Pixels>,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
rendered_element: &mut Self::ElementState,
|
||||
cx: &mut gpui3::ViewContext<Self::ViewState>,
|
||||
) {
|
||||
element_state.paint(view_state, None, cx)
|
||||
rendered_element.paint(view_state, None, cx)
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -164,31 +164,42 @@ impl<E: Element> Element for Themed<E> {
|
||||
None
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
&mut self,
|
||||
view_state: &mut Self::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) -> Self::ElementState {
|
||||
cx.with_global(self.theme.clone(), |cx| {
|
||||
self.child.initialize(view_state, element_state, cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn layout(
|
||||
&mut self,
|
||||
state: &mut E::ViewState,
|
||||
element_state: Option<Self::ElementState>,
|
||||
view_state: &mut E::ViewState,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<E::ViewState>,
|
||||
) -> (LayoutId, Self::ElementState)
|
||||
) -> LayoutId
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
cx.with_global(self.theme.clone(), |cx| {
|
||||
self.child.layout(state, element_state, cx)
|
||||
self.child.layout(view_state, element_state, cx)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
state: &mut Self::ViewState,
|
||||
view_state: &mut Self::ViewState,
|
||||
frame_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<Self::ViewState>,
|
||||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
cx.with_global(self.theme.clone(), |cx| {
|
||||
self.child.paint(bounds, state, frame_state, cx);
|
||||
self.child.paint(bounds, view_state, frame_state, cx);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user