Remove V parameter on elements

This commit is contained in:
Mikayla 2023-11-19 18:32:31 -08:00
parent c0d85dc1dd
commit 88024ca7c9
No known key found for this signature in database
13 changed files with 578 additions and 665 deletions

View file

@ -631,7 +631,7 @@ impl AnyWindowHandle {
pub struct EmptyView {}
impl Render for EmptyView {
type Element = Div<Self>;
type Element = Div;
fn render(&mut self, _cx: &mut crate::ViewContext<Self>) -> Self::Element {
div()

View file

@ -1,37 +1,34 @@
use crate::{
AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, ViewContext,
AvailableSpace, BorrowWindow, Bounds, ElementId, LayoutId, Pixels, Point, Size, WindowContext,
};
use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec;
use std::{any::Any, fmt::Debug, mem};
pub trait Element<V: 'static> {
pub trait Element {
type ElementState: 'static;
fn element_id(&self) -> Option<ElementId>;
fn layout(
&mut self,
view_state: &mut V,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState);
fn paint(
&mut self,
bounds: Bounds<Pixels>,
view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
);
fn draw<T, R>(
self,
origin: Point<Pixels>,
available_space: Size<T>,
view_state: &mut V,
cx: &mut ViewContext<V>,
f: impl FnOnce(&Self::ElementState, &mut ViewContext<V>) -> R,
cx: &mut WindowContext,
f: impl FnOnce(&Self::ElementState, &mut WindowContext) -> R,
) -> R
where
Self: Sized,
@ -41,7 +38,7 @@ pub trait Element<V: 'static> {
element: self,
phase: ElementRenderPhase::Start,
};
element.draw(origin, available_space.map(Into::into), view_state, cx);
element.draw(origin, available_space.map(Into::into), cx);
if let ElementRenderPhase::Painted { frame_state } = &element.phase {
if let Some(frame_state) = frame_state.as_ref() {
f(&frame_state, cx)
@ -65,10 +62,10 @@ pub trait Element<V: 'static> {
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
pub trait ParentComponent<V: 'static> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
pub trait ParentComponent {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]>;
fn child(mut self, child: impl Component<V>) -> Self
fn child(mut self, child: impl Component) -> Self
where
Self: Sized,
{
@ -76,7 +73,7 @@ pub trait ParentComponent<V: 'static> {
self
}
fn children(mut self, iter: impl IntoIterator<Item = impl Component<V>>) -> Self
fn children(mut self, iter: impl IntoIterator<Item = impl Component>) -> Self
where
Self: Sized,
{
@ -86,26 +83,24 @@ pub trait ParentComponent<V: 'static> {
}
}
trait ElementObject<V> {
trait ElementObject {
fn element_id(&self) -> Option<ElementId>;
fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId;
fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>);
fn layout(&mut self, cx: &mut WindowContext) -> LayoutId;
fn paint(&mut self, cx: &mut WindowContext);
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
view_state: &mut V,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> Size<Pixels>;
fn draw(
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
view_state: &mut V,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
);
}
struct RenderedElement<V: 'static, E: Element<V>> {
struct RenderedElement<E: Element> {
element: E,
phase: ElementRenderPhase<E::ElementState>,
}
@ -131,7 +126,7 @@ enum ElementRenderPhase<V> {
/// 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<V, E: Element<V>> RenderedElement<V, E> {
impl<E: Element> RenderedElement<E> {
fn new(element: E) -> Self {
RenderedElement {
element,
@ -140,25 +135,25 @@ impl<V, E: Element<V>> RenderedElement<V, E> {
}
}
impl<V, E> ElementObject<V> for RenderedElement<V, E>
impl<E> ElementObject for RenderedElement<E>
where
E: Element<V>,
E: Element,
E::ElementState: 'static,
{
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout(&mut self, state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
let (layout_id, frame_state) = match mem::take(&mut self.phase) {
ElementRenderPhase::Start => {
if let Some(id) = self.element.element_id() {
let layout_id = cx.with_element_state(id, |element_state, cx| {
self.element.layout(state, element_state, cx)
self.element.layout(element_state, cx)
});
(layout_id, None)
} else {
let (layout_id, frame_state) = self.element.layout(state, None, cx);
let (layout_id, frame_state) = self.element.layout(None, cx);
(layout_id, Some(frame_state))
}
}
@ -176,7 +171,7 @@ where
layout_id
}
fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
fn paint(&mut self, cx: &mut WindowContext) {
self.phase = match mem::take(&mut self.phase) {
ElementRenderPhase::LayoutRequested {
layout_id,
@ -191,13 +186,12 @@ where
if let Some(id) = self.element.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);
self.element.paint(bounds, &mut element_state, cx);
((), element_state)
});
} else {
self.element
.paint(bounds, view_state, frame_state.as_mut().unwrap(), cx);
.paint(bounds, frame_state.as_mut().unwrap(), cx);
}
ElementRenderPhase::Painted { frame_state }
}
@ -209,11 +203,10 @@ where
fn measure(
&mut self,
available_space: Size<AvailableSpace>,
view_state: &mut V,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> Size<Pixels> {
if matches!(&self.phase, ElementRenderPhase::Start) {
self.layout(view_state, cx);
self.layout(cx);
}
let layout_id = match &mut self.phase {
@ -251,21 +244,19 @@ where
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
view_state: &mut V,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) {
self.measure(available_space, view_state, cx);
cx.with_absolute_element_offset(origin, |cx| self.paint(view_state, cx))
self.measure(available_space, cx);
cx.with_absolute_element_offset(origin, |cx| self.paint(cx))
}
}
pub struct AnyElement<V>(Box<dyn ElementObject<V>>);
pub struct AnyElement(Box<dyn ElementObject>);
impl<V> AnyElement<V> {
impl AnyElement {
pub fn new<E>(element: E) -> Self
where
V: 'static,
E: 'static + Element<V>,
E: 'static + Element,
E::ElementState: Any,
{
AnyElement(Box::new(RenderedElement::new(element)))
@ -275,22 +266,21 @@ impl<V> AnyElement<V> {
self.0.element_id()
}
pub fn layout(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) -> LayoutId {
self.0.layout(view_state, cx)
pub fn layout(&mut self, cx: &mut WindowContext) -> LayoutId {
self.0.layout(cx)
}
pub fn paint(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
self.0.paint(view_state, cx)
pub fn paint(&mut self, cx: &mut WindowContext) {
self.0.paint(cx)
}
/// Initializes this element and performs layout within the given available space to determine its size.
pub fn measure(
&mut self,
available_space: Size<AvailableSpace>,
view_state: &mut V,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> Size<Pixels> {
self.0.measure(available_space, view_state, cx)
self.0.measure(available_space, cx)
}
/// Initializes this element and performs layout in the available space, then paints it at the given origin.
@ -298,20 +288,19 @@ impl<V> AnyElement<V> {
&mut self,
origin: Point<Pixels>,
available_space: Size<AvailableSpace>,
view_state: &mut V,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) {
self.0.draw(origin, available_space, view_state, cx)
self.0.draw(origin, available_space, cx)
}
}
pub trait Component<V> {
fn render(self) -> AnyElement<V>;
pub trait Component {
fn render(self) -> AnyElement;
fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
where
Self: Sized,
U: Component<V>,
U: Component,
{
f(self)
}
@ -337,19 +326,18 @@ pub trait Component<V> {
}
}
impl<V> Component<V> for AnyElement<V> {
fn render(self) -> AnyElement<V> {
impl Component for AnyElement {
fn render(self) -> AnyElement {
self
}
}
impl<V, E, F> Element<V> for Option<F>
impl<E, F> Element for Option<F>
where
V: 'static,
E: 'static + Component<V>,
F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
E: 'static + Component,
F: FnOnce(&mut WindowContext) -> E + 'static,
{
type ElementState = AnyElement<V>;
type ElementState = AnyElement;
fn element_id(&self) -> Option<ElementId> {
None
@ -357,45 +345,41 @@ where
fn layout(
&mut self,
view_state: &mut V,
_: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
let render = self.take().unwrap();
let mut rendered_element = (render)(view_state, cx).render();
let layout_id = rendered_element.layout(view_state, cx);
let mut rendered_element = (render)(cx).render();
let layout_id = rendered_element.layout(cx);
(layout_id, rendered_element)
}
fn paint(
&mut self,
_bounds: Bounds<Pixels>,
view_state: &mut V,
rendered_element: &mut Self::ElementState,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) {
rendered_element.paint(view_state, cx)
rendered_element.paint(cx)
}
}
impl<V, E, F> Component<V> for Option<F>
impl<E, F> Component for Option<F>
where
V: 'static,
E: 'static + Component<V>,
F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
E: 'static + Component,
F: FnOnce(&mut WindowContext) -> E + 'static,
{
fn render(self) -> AnyElement<V> {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<V, E, F> Component<V> for F
impl<E, F> Component for F
where
V: 'static,
E: 'static + Component<V>,
F: FnOnce(&mut V, &mut ViewContext<'_, V>) -> E + 'static,
E: 'static + Component,
F: FnOnce(&mut WindowContext) -> E + 'static,
{
fn render(self) -> AnyElement<V> {
fn render(self) -> AnyElement {
AnyElement::new(Some(self))
}
}

File diff suppressed because it is too large Load diff

View file

@ -1,18 +1,17 @@
use crate::{
AnyElement, BorrowWindow, Bounds, Component, Element, InteractiveComponent,
InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement,
Styled, ViewContext,
AnyElement, Bounds, Component, Element, InteractiveComponent, InteractiveElementState,
Interactivity, LayoutId, Pixels, SharedString, StyleRefinement, Styled, WindowContext,
};
use futures::FutureExt;
use util::ResultExt;
pub struct Img<V: 'static> {
interactivity: Interactivity<V>,
pub struct Img {
interactivity: Interactivity,
uri: Option<SharedString>,
grayscale: bool,
}
pub fn img<V: 'static>() -> Img<V> {
pub fn img() -> Img {
Img {
interactivity: Interactivity::default(),
uri: None,
@ -20,10 +19,7 @@ pub fn img<V: 'static>() -> Img<V> {
}
}
impl<V> Img<V>
where
V: 'static,
{
impl Img {
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
self.uri = Some(uri.into());
self
@ -35,13 +31,13 @@ where
}
}
impl<V> Component<V> for Img<V> {
fn render(self) -> AnyElement<V> {
impl Component for Img {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<V> Element<V> for Img<V> {
impl Element for Img {
type ElementState = InteractiveElementState;
fn element_id(&self) -> Option<crate::ElementId> {
@ -50,9 +46,8 @@ impl<V> Element<V> for Img<V> {
fn layout(
&mut self,
_view_state: &mut V,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None)
@ -62,9 +57,8 @@ impl<V> Element<V> for Img<V> {
fn paint(
&mut self,
bounds: Bounds<Pixels>,
_view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) {
self.interactivity.paint(
bounds,
@ -89,7 +83,7 @@ impl<V> Element<V> for Img<V> {
.log_err()
});
} else {
cx.spawn(|_, mut cx| async move {
cx.spawn(|mut cx| async move {
if image_future.await.ok().is_some() {
cx.on_next_frame(|cx| cx.notify());
}
@ -102,14 +96,14 @@ impl<V> Element<V> for Img<V> {
}
}
impl<V> Styled for Img<V> {
impl Styled for Img {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.interactivity.base_style
}
}
impl<V> InteractiveComponent<V> for Img<V> {
fn interactivity(&mut self) -> &mut Interactivity<V> {
impl InteractiveComponent for Img {
fn interactivity(&mut self) -> &mut Interactivity {
&mut self.interactivity
}
}

View file

@ -3,15 +3,15 @@ use taffy::style::{Display, Position};
use crate::{
point, AnyElement, BorrowWindow, Bounds, Component, Element, LayoutId, ParentComponent, Pixels,
Point, Size, Style,
Point, Size, Style, WindowContext,
};
pub struct OverlayState {
child_layout_ids: SmallVec<[LayoutId; 4]>,
}
pub struct Overlay<V> {
children: SmallVec<[AnyElement<V>; 2]>,
pub struct Overlay {
children: SmallVec<[AnyElement; 2]>,
anchor_corner: AnchorCorner,
fit_mode: OverlayFitMode,
// todo!();
@ -21,7 +21,7 @@ pub struct Overlay<V> {
/// overlay gives you a floating element that will avoid overflowing the window bounds.
/// Its children should have no margin to avoid measurement issues.
pub fn overlay<V: 'static>() -> Overlay<V> {
pub fn overlay() -> Overlay {
Overlay {
children: SmallVec::new(),
anchor_corner: AnchorCorner::TopLeft,
@ -30,7 +30,7 @@ pub fn overlay<V: 'static>() -> Overlay<V> {
}
}
impl<V> Overlay<V> {
impl Overlay {
/// Sets which corner of the overlay should be anchored to the current position.
pub fn anchor(mut self, anchor: AnchorCorner) -> Self {
self.anchor_corner = anchor;
@ -51,19 +51,19 @@ impl<V> Overlay<V> {
}
}
impl<V: 'static> ParentComponent<V> for Overlay<V> {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
impl ParentComponent for Overlay {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children
}
}
impl<V: 'static> Component<V> for Overlay<V> {
fn render(self) -> AnyElement<V> {
impl Component for Overlay {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<V: 'static> Element<V> for Overlay<V> {
impl Element for Overlay {
type ElementState = OverlayState;
fn element_id(&self) -> Option<crate::ElementId> {
@ -72,14 +72,13 @@ impl<V: 'static> Element<V> for Overlay<V> {
fn layout(
&mut self,
view_state: &mut V,
_: Option<Self::ElementState>,
cx: &mut crate::ViewContext<V>,
cx: &mut WindowContext,
) -> (crate::LayoutId, Self::ElementState) {
let child_layout_ids = self
.children
.iter_mut()
.map(|child| child.layout(view_state, cx))
.map(|child| child.layout(cx))
.collect::<SmallVec<_>>();
let mut overlay_style = Style::default();
@ -94,9 +93,8 @@ impl<V: 'static> Element<V> for Overlay<V> {
fn paint(
&mut self,
bounds: crate::Bounds<crate::Pixels>,
view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut crate::ViewContext<V>,
cx: &mut WindowContext,
) {
if element_state.child_layout_ids.is_empty() {
return;
@ -157,7 +155,7 @@ impl<V: 'static> Element<V> for Overlay<V> {
cx.with_element_offset(desired.origin - bounds.origin, |cx| {
for child in &mut self.children {
child.paint(view_state, cx);
child.paint(cx);
}
})
}

View file

@ -1,36 +1,36 @@
use crate::{
AnyElement, Bounds, Component, Element, ElementId, InteractiveComponent,
InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement,
Styled, ViewContext,
Styled, WindowContext,
};
use util::ResultExt;
pub struct Svg<V: 'static> {
interactivity: Interactivity<V>,
pub struct Svg {
interactivity: Interactivity,
path: Option<SharedString>,
}
pub fn svg<V: 'static>() -> Svg<V> {
pub fn svg() -> Svg {
Svg {
interactivity: Interactivity::default(),
path: None,
}
}
impl<V> Svg<V> {
impl Svg {
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
self.path = Some(path.into());
self
}
}
impl<V> Component<V> for Svg<V> {
fn render(self) -> AnyElement<V> {
impl Component for Svg {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<V> Element<V> for Svg<V> {
impl Element for Svg {
type ElementState = InteractiveElementState;
fn element_id(&self) -> Option<ElementId> {
@ -39,9 +39,8 @@ impl<V> Element<V> for Svg<V> {
fn layout(
&mut self,
_view_state: &mut V,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
self.interactivity.layout(element_state, cx, |style, cx| {
cx.request_layout(&style, None)
@ -51,9 +50,8 @@ impl<V> Element<V> for Svg<V> {
fn paint(
&mut self,
bounds: Bounds<Pixels>,
_view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) where
Self: Sized,
{
@ -66,14 +64,14 @@ impl<V> Element<V> for Svg<V> {
}
}
impl<V> Styled for Svg<V> {
impl Styled for Svg {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.interactivity.base_style
}
}
impl<V> InteractiveComponent<V> for Svg<V> {
fn interactivity(&mut self) -> &mut Interactivity<V> {
impl InteractiveComponent for Svg {
fn interactivity(&mut self) -> &mut Interactivity {
&mut self.interactivity
}
}

View file

@ -1,6 +1,6 @@
use crate::{
AnyElement, BorrowWindow, Bounds, Component, Element, ElementId, LayoutId, Pixels,
SharedString, Size, TextRun, ViewContext, WrappedLine,
AnyElement, Bounds, Component, Element, ElementId, LayoutId, Pixels, SharedString, Size,
TextRun, WindowContext, WrappedLine,
};
use parking_lot::{Mutex, MutexGuard};
use smallvec::SmallVec;
@ -26,13 +26,13 @@ impl Text {
}
}
impl<V: 'static> Component<V> for Text {
fn render(self) -> AnyElement<V> {
impl Component for Text {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<V: 'static> Element<V> for Text {
impl Element for Text {
type ElementState = TextState;
fn element_id(&self) -> Option<crate::ElementId> {
@ -41,9 +41,8 @@ impl<V: 'static> Element<V> for Text {
fn layout(
&mut self,
_view: &mut V,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
let element_state = element_state.unwrap_or_default();
let text_system = cx.text_system().clone();
@ -120,9 +119,8 @@ impl<V: 'static> Element<V> for Text {
fn paint(
&mut self,
bounds: Bounds<Pixels>,
_: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) {
let element_state = element_state.lock();
let element_state = element_state
@ -165,7 +163,7 @@ struct InteractiveTextState {
clicked_range_ixs: Rc<Cell<SmallVec<[usize; 1]>>>,
}
impl<V: 'static> Element<V> for InteractiveText {
impl Element for InteractiveText {
type ElementState = InteractiveTextState;
fn element_id(&self) -> Option<ElementId> {
@ -174,23 +172,22 @@ impl<V: 'static> Element<V> for InteractiveText {
fn layout(
&mut self,
view_state: &mut V,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
if let Some(InteractiveTextState {
text_state,
clicked_range_ixs,
}) = element_state
{
let (layout_id, text_state) = self.text.layout(view_state, Some(text_state), cx);
let (layout_id, text_state) = self.text.layout(Some(text_state), cx);
let element_state = InteractiveTextState {
text_state,
clicked_range_ixs,
};
(layout_id, element_state)
} else {
let (layout_id, text_state) = self.text.layout(view_state, None, cx);
let (layout_id, text_state) = self.text.layout(None, cx);
let element_state = InteractiveTextState {
text_state,
clicked_range_ixs: Rc::default(),
@ -202,17 +199,15 @@ impl<V: 'static> Element<V> for InteractiveText {
fn paint(
&mut self,
bounds: Bounds<Pixels>,
view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) {
self.text
.paint(bounds, view_state, &mut element_state.text_state, cx)
self.text.paint(bounds, &mut element_state.text_state, cx)
}
}
impl<V: 'static> Component<V> for SharedString {
fn render(self) -> AnyElement<V> {
impl Component for SharedString {
fn render(self) -> AnyElement {
Text {
text: self,
runs: None,
@ -221,8 +216,8 @@ impl<V: 'static> Component<V> for SharedString {
}
}
impl<V: 'static> Component<V> for &'static str {
fn render(self) -> AnyElement<V> {
impl Component for &'static str {
fn render(self) -> AnyElement {
Text {
text: self.into(),
runs: None,
@ -233,8 +228,8 @@ impl<V: 'static> Component<V> for &'static str {
// TODO: Figure out how to pass `String` to `child` without this.
// This impl doesn't exist in the `gpui2` crate.
impl<V: 'static> Component<V> for String {
fn render(self) -> AnyElement<V> {
impl Component for String {
fn render(self) -> AnyElement {
Text {
text: self.into(),
runs: None,

View file

@ -1,7 +1,7 @@
use crate::{
point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element,
ElementId, InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels,
Point, Size, StyleRefinement, Styled, ViewContext,
point, px, size, AnyElement, AvailableSpace, Bounds, Component, Element, ElementId,
InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels, Point, Size,
StyleRefinement, Styled, WindowContext,
};
use smallvec::SmallVec;
use std::{cell::RefCell, cmp, mem, ops::Range, rc::Rc};
@ -10,15 +10,14 @@ use taffy::style::Overflow;
/// uniform_list provides lazy rendering for a set of items that are of uniform height.
/// When rendered into a container with overflow-y: hidden and a fixed (or max) height,
/// uniform_list will only render the visibile subset of items.
pub fn uniform_list<I, V, C>(
pub fn uniform_list<I, C>(
id: I,
item_count: usize,
f: impl 'static + Fn(&mut V, Range<usize>, &mut ViewContext<V>) -> Vec<C>,
) -> UniformList<V>
f: impl 'static + Fn(Range<usize>, &mut WindowContext) -> Vec<C>,
) -> UniformList
where
I: Into<ElementId>,
V: 'static,
C: Component<V>,
C: Component,
{
let id = id.into();
let mut style = StyleRefinement::default();
@ -29,8 +28,8 @@ where
style,
item_count,
item_to_measure_index: 0,
render_items: Box::new(move |view, visible_range, cx| {
f(view, visible_range, cx)
render_items: Box::new(move |visible_range, cx| {
f(visible_range, cx)
.into_iter()
.map(|component| component.render())
.collect()
@ -43,19 +42,14 @@ where
}
}
pub struct UniformList<V: 'static> {
pub struct UniformList {
id: ElementId,
style: StyleRefinement,
item_count: usize,
item_to_measure_index: usize,
render_items: Box<
dyn for<'a> Fn(
&'a mut V,
Range<usize>,
&'a mut ViewContext<V>,
) -> SmallVec<[AnyElement<V>; 64]>,
>,
interactivity: Interactivity<V>,
render_items:
Box<dyn for<'a> Fn(Range<usize>, &'a mut WindowContext) -> SmallVec<[AnyElement; 64]>>,
interactivity: Interactivity,
scroll_handle: Option<UniformListScrollHandle>,
}
@ -89,7 +83,7 @@ impl UniformListScrollHandle {
}
}
impl<V: 'static> Styled for UniformList<V> {
impl Styled for UniformList {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.style
}
@ -101,7 +95,7 @@ pub struct UniformListState {
item_size: Size<Pixels>,
}
impl<V: 'static> Element<V> for UniformList<V> {
impl Element for UniformList {
type ElementState = UniformListState;
fn element_id(&self) -> Option<crate::ElementId> {
@ -110,16 +104,15 @@ impl<V: 'static> Element<V> for UniformList<V> {
fn layout(
&mut self,
view_state: &mut V,
element_state: Option<Self::ElementState>,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
let max_items = self.item_count;
let rem_size = cx.rem_size();
let item_size = element_state
.as_ref()
.map(|s| s.item_size)
.unwrap_or_else(|| self.measure_item(view_state, None, cx));
.unwrap_or_else(|| self.measure_item(None, cx));
let (layout_id, interactive) =
self.interactivity
@ -161,9 +154,8 @@ impl<V: 'static> Element<V> for UniformList<V> {
fn paint(
&mut self,
bounds: Bounds<crate::Pixels>,
view_state: &mut V,
element_state: &mut Self::ElementState,
cx: &mut ViewContext<V>,
cx: &mut WindowContext,
) {
let style =
self.interactivity
@ -209,9 +201,8 @@ impl<V: 'static> Element<V> for UniformList<V> {
style.paint(bounds, cx);
if self.item_count > 0 {
let item_height = self
.measure_item(view_state, Some(padded_bounds.size.width), cx)
.height;
let item_height =
self.measure_item(Some(padded_bounds.size.width), cx).height;
if let Some(scroll_handle) = self.scroll_handle.clone() {
scroll_handle.0.borrow_mut().replace(ScrollHandleState {
item_height,
@ -233,7 +224,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
self.item_count,
);
let mut items = (self.render_items)(view_state, visible_range.clone(), cx);
let mut items = (self.render_items)(visible_range.clone(), cx);
cx.with_z_index(1, |cx| {
for (item, ix) in items.iter_mut().zip(visible_range) {
let item_origin = padded_bounds.origin
@ -242,7 +233,7 @@ impl<V: 'static> Element<V> for UniformList<V> {
AvailableSpace::Definite(padded_bounds.size.width),
AvailableSpace::Definite(item_height),
);
item.draw(item_origin, available_space, view_state, cx);
item.draw(item_origin, available_space, cx);
}
});
}
@ -253,24 +244,19 @@ impl<V: 'static> Element<V> for UniformList<V> {
}
}
impl<V> UniformList<V> {
impl UniformList {
pub fn with_width_from_item(mut self, item_index: Option<usize>) -> Self {
self.item_to_measure_index = item_index.unwrap_or(0);
self
}
fn measure_item(
&self,
view_state: &mut V,
list_width: Option<Pixels>,
cx: &mut ViewContext<V>,
) -> Size<Pixels> {
fn measure_item(&self, list_width: Option<Pixels>, cx: &mut WindowContext) -> Size<Pixels> {
if self.item_count == 0 {
return Size::default();
}
let item_ix = cmp::min(self.item_to_measure_index, self.item_count - 1);
let mut items = (self.render_items)(view_state, item_ix..item_ix + 1, cx);
let mut items = (self.render_items)(item_ix..item_ix + 1, cx);
let mut item_to_measure = items.pop().unwrap();
let available_space = size(
list_width.map_or(AvailableSpace::MinContent, |width| {
@ -278,7 +264,7 @@ impl<V> UniformList<V> {
}),
AvailableSpace::MinContent,
);
item_to_measure.measure(available_space, view_state, cx)
item_to_measure.measure(available_space, cx)
}
pub fn track_scroll(mut self, handle: UniformListScrollHandle) -> Self {
@ -287,14 +273,14 @@ impl<V> UniformList<V> {
}
}
impl<V> InteractiveComponent<V> for UniformList<V> {
fn interactivity(&mut self) -> &mut crate::Interactivity<V> {
impl InteractiveComponent for UniformList {
fn interactivity(&mut self) -> &mut crate::Interactivity {
&mut self.interactivity
}
}
impl<V: 'static> Component<V> for UniformList<V> {
fn render(self) -> AnyElement<V> {
impl Component for UniformList {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}

View file

@ -196,6 +196,30 @@ where
}
}
pub struct CallbackHandle<E> {
callback: Box<dyn Fn(&E, &mut WindowContext) + 'static>,
}
impl<E, F: Fn(&E, &mut WindowContext) + 'static> From<F> for CallbackHandle<E> {
fn from(value: F) -> Self {
CallbackHandle {
callback: Box::new(value),
}
}
}
pub struct ConstructorHandle<R> {
callback: Box<dyn Fn(&mut WindowContext) -> R + 'static>,
}
impl<R, F: Fn(&mut WindowContext) -> R + 'static> From<F> for ConstructorHandle<R> {
fn from(value: F) -> Self {
ConstructorHandle {
callback: Box::new(value),
}
}
}
pub trait Flatten<T> {
fn flatten(self) -> Result<T>;
}

View file

@ -1,9 +1,8 @@
use crate::{
div, point, Component, Div, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render,
ViewContext,
div, point, Div, FocusHandle, Keystroke, Modifiers, Pixels, Point, Render, ViewContext,
};
use smallvec::SmallVec;
use std::{any::Any, fmt::Debug, marker::PhantomData, ops::Deref, path::PathBuf};
use std::{any::Any, fmt::Debug, ops::Deref, path::PathBuf};
#[derive(Clone, Debug, Eq, PartialEq)]
pub struct KeyDownEvent {
@ -60,32 +59,6 @@ pub struct ClickEvent {
pub up: MouseUpEvent,
}
pub struct Drag<S, R, V, E>
where
R: Fn(&mut V, &mut ViewContext<V>) -> E,
V: 'static,
E: Component<()>,
{
pub state: S,
pub render_drag_handle: R,
view_type: PhantomData<V>,
}
impl<S, R, V, E> Drag<S, R, V, E>
where
R: Fn(&mut V, &mut ViewContext<V>) -> E,
V: 'static,
E: Component<()>,
{
pub fn new(state: S, render_drag_handle: R) -> Self {
Drag {
state,
render_drag_handle,
view_type: PhantomData,
}
}
}
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
pub enum MouseButton {
Left,
@ -194,7 +167,7 @@ impl Deref for MouseExitEvent {
pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>);
impl Render for ExternalPaths {
type Element = Div<Self>;
type Element = Div;
fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
div() // Intentionally left empty because the platform will render icons for the dragged files
@ -287,7 +260,7 @@ pub struct FocusEvent {
mod test {
use crate::{
self as gpui, div, Component, Div, FocusHandle, InteractiveComponent, KeyBinding,
Keystroke, ParentComponent, Render, Stateful, TestAppContext, ViewContext, VisualContext,
Keystroke, ParentComponent, Render, Stateful, TestAppContext, VisualContext,
};
struct TestView {
@ -299,20 +272,24 @@ mod test {
actions!(TestAction);
impl Render for TestView {
type Element = Stateful<Self, Div<Self>>;
type Element = Stateful<Div>;
fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> Self::Element {
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
div().id("testview").child(
div()
.key_context("parent")
.on_key_down(|this: &mut TestView, _, _, _| this.saw_key_down = true)
.on_action(|this: &mut TestView, _: &TestAction, _| this.saw_action = true)
.child(|this: &mut Self, _cx: &mut ViewContext<Self>| {
.on_key_down(cx.callback(|this, _, _| this.saw_key_down = true))
.on_action(
cx.callback(|this: &mut TestView, _: &TestAction, _| {
this.saw_action = true
}),
)
.child(
div()
.key_context("nested")
.track_focus(&this.focus_handle)
.render()
}),
.track_focus(&self.focus_handle)
.render(),
),
)
}
}

View file

@ -2,7 +2,7 @@ use crate::{
black, phi, point, rems, AbsoluteLength, BorrowAppContext, BorrowWindow, Bounds, ContentMask,
Corners, CornersRefinement, CursorStyle, DefiniteLength, Edges, EdgesRefinement, Font,
FontFeatures, FontStyle, FontWeight, Hsla, Length, Pixels, Point, PointRefinement, Rgba,
SharedString, Size, SizeRefinement, Styled, TextRun, ViewContext,
SharedString, Size, SizeRefinement, Styled, TextRun, WindowContext,
};
use refineable::{Cascade, Refineable};
use smallvec::SmallVec;
@ -313,7 +313,7 @@ impl Style {
}
/// Paints the background of an element styled with this style.
pub fn paint<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
let rem_size = cx.rem_size();
cx.with_z_index(0, |cx| {

View file

@ -11,7 +11,7 @@ use std::{
};
pub trait Render: 'static + Sized {
type Element: Element<Self> + 'static;
type Element: Element + 'static;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element;
}
@ -67,7 +67,7 @@ impl<V: 'static> View<V> {
pub fn render_with<C>(&self, component: C) -> RenderViewWith<C, V>
where
C: 'static + Component<V>,
C: 'static + Component,
{
RenderViewWith {
view: self.clone(),
@ -105,8 +105,8 @@ impl<V> PartialEq for View<V> {
impl<V> Eq for View<V> {}
impl<V: Render, ParentViewState: 'static> Component<ParentViewState> for View<V> {
fn render(self) -> AnyElement<ParentViewState> {
impl<V: Render> Component for View<V> {
fn render(self) -> AnyElement {
AnyElement::new(AnyView::from(self))
}
}
@ -211,8 +211,8 @@ impl AnyView {
}
}
impl<V: 'static> Component<V> for AnyView {
fn render(self) -> AnyElement<V> {
impl Component for AnyView {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
@ -227,7 +227,7 @@ impl<V: Render> From<View<V>> for AnyView {
}
}
impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
impl Element for AnyView {
type ElementState = Box<dyn Any>;
fn element_id(&self) -> Option<ElementId> {
@ -236,9 +236,8 @@ impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
fn layout(
&mut self,
_view_state: &mut ParentViewState,
_element_state: Option<Self::ElementState>,
cx: &mut ViewContext<ParentViewState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
(self.layout)(self, cx)
}
@ -246,9 +245,8 @@ impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
fn paint(
&mut self,
_bounds: Bounds<Pixels>,
_view_state: &mut ParentViewState,
rendered_element: &mut Self::ElementState,
cx: &mut ViewContext<ParentViewState>,
cx: &mut WindowContext,
) {
(self.paint)(self, rendered_element, cx)
}
@ -281,41 +279,39 @@ impl<V: Render> From<WeakView<V>> for AnyWeakView {
}
}
// impl<T, E> Render for T
// where
// T: 'static + FnMut(&mut WindowContext) -> E,
// E: 'static + Send + Element<T>,
// {
// type Element = E;
impl<T, E> Render for T
where
T: 'static + FnMut(&mut WindowContext) -> E,
E: 'static + Send + Element,
{
type Element = E;
// fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
// (self)(cx)
// }
// }
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
(self)(cx)
}
}
pub struct RenderViewWith<C, V> {
view: View<V>,
component: Option<C>,
}
impl<C, ParentViewState, ViewState> Component<ParentViewState> for RenderViewWith<C, ViewState>
impl<C, V> Component for RenderViewWith<C, V>
where
C: 'static + Component<ViewState>,
ParentViewState: 'static,
ViewState: 'static,
V: 'static + Render,
C: 'static + Component,
{
fn render(self) -> AnyElement<ParentViewState> {
fn render(self) -> AnyElement {
AnyElement::new(self)
}
}
impl<C, ParentViewState, ViewState> Element<ParentViewState> for RenderViewWith<C, ViewState>
impl<C, V> Element for RenderViewWith<C, V>
where
C: 'static + Component<ViewState>,
ParentViewState: 'static,
ViewState: 'static,
V: 'static + Render,
C: 'static + Component,
{
type ElementState = AnyElement<ViewState>;
type ElementState = AnyElement;
fn element_id(&self) -> Option<ElementId> {
Some(self.view.entity_id().into())
@ -323,25 +319,21 @@ where
fn layout(
&mut self,
_: &mut ParentViewState,
_: Option<Self::ElementState>,
cx: &mut ViewContext<ParentViewState>,
cx: &mut WindowContext,
) -> (LayoutId, Self::ElementState) {
self.view.update(cx, |view, cx| {
let mut element = self.component.take().unwrap().render();
let layout_id = element.layout(view, cx);
(layout_id, element)
})
let mut element = self.component.take().unwrap().render();
let layout_id = element.layout(cx);
(layout_id, element)
}
fn paint(
&mut self,
_: Bounds<Pixels>,
_: &mut ParentViewState,
element: &mut Self::ElementState,
cx: &mut ViewContext<ParentViewState>,
cx: &mut WindowContext,
) {
self.view.update(cx, |view, cx| element.paint(view, cx))
element.paint(cx)
}
}
@ -357,7 +349,7 @@ mod any_view {
let view = view.clone().downcast::<V>().unwrap();
view.update(cx, |view, cx| {
let mut element = AnyElement::new(view.render(cx));
let layout_id = element.layout(view, cx);
let layout_id = element.layout(cx);
(layout_id, Box::new(element) as Box<dyn Any>)
})
})
@ -369,9 +361,8 @@ mod any_view {
cx: &mut WindowContext,
) {
cx.with_element_id(Some(view.model.entity_id), |cx| {
let view = view.clone().downcast::<V>().unwrap();
let element = element.downcast_mut::<AnyElement<V>>().unwrap();
view.update(cx, |view, cx| element.paint(view, cx))
let element = element.downcast_mut::<AnyElement>().unwrap();
element.paint(cx);
})
}
}

View file

@ -1,15 +1,15 @@
use crate::{
key_dispatch::DispatchActionListener, px, size, Action, AnyBox, AnyDrag, AnyView, AppContext,
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, Context, Corners, CursorStyle,
DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId,
EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla,
ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, LayoutId, Model,
ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent,
MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler,
PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams,
RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View,
VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
AsyncWindowContext, AvailableSpace, Bounds, BoxShadow, CallbackHandle, ConstructorHandle,
Context, Corners, CursorStyle, DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges,
Effect, Entity, EntityId, EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId,
GlobalElementId, GlyphId, Hsla, ImageData, InputEvent, IsZero, KeyBinding, KeyContext,
KeyDownEvent, LayoutId, Model, ModelContext, Modifiers, MonochromeSprite, MouseButton,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay,
PlatformInputHandler, PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render,
RenderGlyphParams, RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow,
SharedString, Size, Style, SubscriberSet, Subscription, TaffyLayoutEngine, Task, Underline,
UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::{anyhow, Context as _, Result};
use collections::HashMap;
@ -1436,6 +1436,47 @@ impl<'a> WindowContext<'a> {
.dispatch_tree
.bindings_for_action(action)
}
///========== ELEMENT RELATED FUNCTIONS ===========
pub fn with_key_dispatch<R>(
&mut self,
context: KeyContext,
focus_handle: Option<FocusHandle>,
f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
) -> R {
let window = &mut self.window;
window
.current_frame
.dispatch_tree
.push_node(context.clone());
if let Some(focus_handle) = focus_handle.as_ref() {
window
.current_frame
.dispatch_tree
.make_focusable(focus_handle.id);
}
let result = f(focus_handle, self);
self.window.current_frame.dispatch_tree.pop_node();
result
}
/// Register a focus listener for the current frame only. It will be cleared
/// on the next frame render. You should use this method only from within elements,
/// and we may want to enforce that better via a different context type.
// todo!() Move this to `FrameContext` to emphasize its individuality?
pub fn on_focus_changed(
&mut self,
listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static,
) {
self.window
.current_frame
.focus_listeners
.push(Box::new(move |event, cx| {
listener(event, cx);
}));
}
}
impl Context for WindowContext<'_> {
@ -2124,49 +2165,6 @@ impl<'a, V: 'static> ViewContext<'a, V> {
)
}
/// Register a focus listener for the current frame only. It will be cleared
/// on the next frame render. You should use this method only from within elements,
/// and we may want to enforce that better via a different context type.
// todo!() Move this to `FrameContext` to emphasize its individuality?
pub fn on_focus_changed(
&mut self,
listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
) {
let handle = self.view().downgrade();
self.window
.current_frame
.focus_listeners
.push(Box::new(move |event, cx| {
handle
.update(cx, |view, cx| listener(view, event, cx))
.log_err();
}));
}
pub fn with_key_dispatch<R>(
&mut self,
context: KeyContext,
focus_handle: Option<FocusHandle>,
f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
) -> R {
let window = &mut self.window;
window
.current_frame
.dispatch_tree
.push_node(context.clone());
if let Some(focus_handle) = focus_handle.as_ref() {
window
.current_frame
.dispatch_tree
.make_focusable(focus_handle.id);
}
let result = f(focus_handle, self);
self.window.current_frame.dispatch_tree.pop_node();
result
}
pub fn spawn<Fut, R>(
&mut self,
f: impl FnOnce(WeakView<V>, AsyncWindowContext) -> Fut,
@ -2284,6 +2282,25 @@ impl<'a, V: 'static> ViewContext<'a, V> {
{
self.defer(|_, cx| cx.emit(Manager::Dismiss))
}
pub fn callback<E>(
&self,
f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
) -> CallbackHandle<E> {
let view = self.view().clone();
(move |e: &E, cx: &mut WindowContext| {
view.update(cx, |view, cx| f(view, e, cx));
})
.into()
}
pub fn constructor<R>(
&self,
f: impl Fn(&mut V, &mut ViewContext<V>) -> R + 'static,
) -> ConstructorHandle<R> {
let view = self.view().clone();
(move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))).into()
}
}
impl<V> Context for ViewContext<'_, V> {