zed/crates/gpui3/src/element.rs
Antonio Scandurra c17a4d8453 Checkpoint
2023-10-19 22:05:01 +02:00

304 lines
8.5 KiB
Rust

use crate::{
BorrowWindow, Bounds, ElementId, FocusHandle, FocusListeners, 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;
type ElementState: 'static + Send + Sync;
fn id(&self) -> Option<ElementId>;
fn initialize(
&mut self,
view_state: &mut Self::ViewState,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<Self::ViewState>,
) -> 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>,
view_state: &mut Self::ViewState,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<Self::ViewState>,
);
}
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
pub trait ElementIdentity: 'static + Send + Sync {
fn id(&self) -> Option<ElementId>;
}
pub struct Identified(pub(crate) ElementId);
impl ElementIdentity for Identified {
fn id(&self) -> Option<ElementId> {
Some(self.0.clone())
}
}
pub struct Anonymous;
impl ElementIdentity for Anonymous {
fn id(&self) -> Option<ElementId> {
None
}
}
pub trait ElementFocusability<V: 'static + Send + Sync>: 'static + Send + Sync {
fn focus_handle(&self) -> Option<&FocusHandle>;
fn focus_listeners(&self) -> Option<&FocusListeners<V>>;
fn initialize<R>(
&self,
cx: &mut ViewContext<V>,
f: impl FnOnce(&mut ViewContext<V>) -> R,
) -> R {
if let Some(focus_listeners) = self.focus_listeners() {
for listener in focus_listeners.iter().cloned() {
cx.on_focus_changed(move |view, event, cx| listener(view, event, cx));
}
}
if let Some(focus_handle) = self.focus_handle().cloned() {
cx.with_focus(focus_handle, |cx| f(cx))
} else {
f(cx)
}
}
}
pub struct Focusable<V: 'static + Send + Sync> {
pub focus_handle: FocusHandle,
pub focus_listeners: FocusListeners<V>,
}
impl<V> ElementFocusability<V> for Focusable<V>
where
V: 'static + Send + Sync,
{
fn focus_handle(&self) -> Option<&FocusHandle> {
Some(&self.focus_handle)
}
fn focus_listeners(&self) -> Option<&FocusListeners<V>> {
Some(&self.focus_listeners)
}
}
impl<V> From<FocusHandle> for Focusable<V>
where
V: 'static + Send + Sync,
{
fn from(value: FocusHandle) -> Self {
Self {
focus_handle: value,
focus_listeners: Default::default(),
}
}
}
pub struct NonFocusable;
impl<V> ElementFocusability<V> for NonFocusable
where
V: 'static + Send + Sync,
{
fn focus_handle(&self) -> Option<&FocusHandle> {
None
}
fn focus_listeners(&self) -> Option<&FocusListeners<V>> {
None
}
}
pub trait ParentElement: Element {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::ViewState>; 2]>;
fn child(mut self, child: impl IntoAnyElement<Self::ViewState>) -> Self
where
Self: Sized,
{
self.children_mut().push(child.into_any());
self
}
fn children(
mut self,
iter: impl IntoIterator<Item = impl IntoAnyElement<Self::ViewState>>,
) -> Self
where
Self: Sized,
{
self.children_mut()
.extend(iter.into_iter().map(|item| item.into_any()));
self
}
}
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> {
element: E,
phase: ElementRenderPhase<E::ElementState>,
}
#[derive(Default)]
enum ElementRenderPhase<V> {
#[default]
Start,
Initialized {
frame_state: Option<V>,
},
LayoutRequested {
layout_id: LayoutId,
frame_state: Option<V>,
},
Painted,
}
/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered.
/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
/// improved usability.
impl<E: Element> RenderedElement<E> {
fn new(element: E) -> Self {
RenderedElement {
element,
phase: ElementRenderPhase::Start,
}
}
}
impl<E> ElementObject<E::ViewState> for RenderedElement<E>
where
E: Element,
{
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)
});
None
} else {
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
}
fn paint(
&mut self,
view_state: &mut E::ViewState,
offset: Option<Point<Pixels>>,
cx: &mut ViewContext<E::ViewState>,
) {
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);
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
}
_ => panic!("must call layout before paint"),
};
}
}
pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
impl<V: 'static + Send + Sync> AnyElement<V> {
pub fn new<E: Element<ViewState = V>>(element: E) -> Self {
AnyElement(Box::new(RenderedElement::new(element)))
}
pub fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
self.0.initialize(view_state, 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<V> {
fn into_any(self) -> AnyElement<V>;
}
impl<V> IntoAnyElement<V> for AnyElement<V> {
fn into_any(self) -> AnyElement<V> {
self
}
}