Merge branch 'gpui2' of github.com:zed-industries/zed into gpui2

This commit is contained in:
Marshall Bowers 2023-10-18 10:44:43 -04:00
commit 1a156c1060
20 changed files with 1247 additions and 440 deletions

View File

@ -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)]

View File

@ -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()?;

View File

@ -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
}
}

View File

@ -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) {

View File

@ -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()
}
}

View File

@ -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()
}
}

View File

@ -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

View File

@ -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
View 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
}
}

View File

@ -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::*;

View File

@ -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,
}

View File

@ -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)>);

View File

@ -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();

View File

@ -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) {

View File

@ -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 {

View File

@ -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!()
}

View File

@ -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(

View File

@ -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> {

View File

@ -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)
}
}
};

View File

@ -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);
});
}
}