Detailed changes
@@ -29,6 +29,7 @@ impl App {
pub struct AppContext {
platform: Rc<dyn Platform>,
text_system: Arc<TextSystem>,
+ pub(crate) unit_entity_id: EntityId,
pub(crate) entities: SlotMap<EntityId, Option<Box<dyn Any>>>,
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
// We recycle this memory across layout requests.
@@ -38,10 +39,14 @@ pub struct AppContext {
impl AppContext {
pub fn new(platform: Rc<dyn Platform>) -> Self {
let text_system = Arc::new(TextSystem::new(platform.text_system()));
+ let mut entities = SlotMap::with_key();
+ let unit_entity_id = entities.insert(Some(Box::new(()) as Box<dyn Any>));
+
AppContext {
platform,
text_system,
- entities: SlotMap::with_key(),
+ unit_entity_id,
+ entities,
windows: SlotMap::with_key(),
layout_id_buffer: Default::default(),
}
@@ -1,9 +1,11 @@
mod div;
mod img;
+mod stateless;
mod svg;
mod text;
pub use div::*;
pub use img::*;
+pub use stateless::*;
pub use svg::*;
pub use text::*;
@@ -0,0 +1,31 @@
+use std::marker::PhantomData;
+
+use crate::Element;
+
+pub struct Stateless<E: Element<State = ()>, S> {
+ element: E,
+ parent_state_type: PhantomData<S>,
+}
+
+impl<E: Element<State = ()>, S: 'static> Element for Stateless<E, S> {
+ type State = S;
+ type FrameState = E::FrameState;
+
+ fn layout(
+ &mut self,
+ _: &mut Self::State,
+ cx: &mut crate::ViewContext<Self::State>,
+ ) -> anyhow::Result<(crate::LayoutId, Self::FrameState)> {
+ cx.erase_state(|cx| self.element.layout(&mut (), cx))
+ }
+
+ fn paint(
+ &mut self,
+ layout: crate::Layout,
+ _: &mut Self::State,
+ frame_state: &mut Self::FrameState,
+ cx: &mut crate::ViewContext<Self::State>,
+ ) -> anyhow::Result<()> {
+ cx.erase_state(|cx| self.element.paint(layout, &mut (), frame_state, cx))
+ }
+}
@@ -220,6 +220,16 @@ impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> {
entity_type: PhantomData,
}
}
+
+ pub fn erase_state<R>(&mut self, f: impl FnOnce(&mut ViewContext<()>) -> R) -> R {
+ let unit_entity_id = self.unit_entity_id;
+ let mut cx = ViewContext::mutable(
+ &mut *self.window_cx.app,
+ &mut *self.window_cx.window,
+ unit_entity_id,
+ );
+ f(&mut cx)
+ }
}
impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> {
@@ -1,32 +1,32 @@
use proc_macro::TokenStream;
-use proc_macro2::Ident;
use quote::quote;
-use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam};
+use syn::{parse_macro_input, DeriveInput, GenericParam};
pub fn derive_element(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let type_name = ast.ident;
- let mut state_type: Option<Ident> = None;
- for param in ast.generics.params.iter() {
+ let mut state_type = quote! { () };
+
+ for param in &ast.generics.params {
if let GenericParam::Type(type_param) = param {
- state_type = Some(type_param.ident.clone())
+ let type_ident = &type_param.ident;
+ state_type = quote! {#type_ident};
}
}
- let state_type_name = state_type.unwrap_or_else(|| parse_quote! { () });
let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let gen = quote! {
impl #impl_generics gpui3::Element for #type_name #ty_generics
#where_clause
{
- type State = #state_type_name;
- type FrameState = gpui3::AnyElement<#state_type_name>;
+ type State = #state_type;
+ type FrameState = gpui3::AnyElement<#state_type>;
fn layout(
&mut self,
- state: &mut #state_type_name,
+ state: &mut #state_type,
cx: &mut gpui3::ViewContext<V>,
) -> anyhow::Result<(gpui3::LayoutId, Self::FrameState)> {
let mut rendered_element = self.render(state, cx).into_element().into_any();
@@ -37,7 +37,7 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
fn paint(
&mut self,
layout: &gpui3::Layout,
- state: &mut #state_type_name,
+ state: &mut #state_type,
rendered_element: &mut Self::FrameState,
cx: &mut gpui3::ViewContext<V>,
) {
@@ -1,26 +1,29 @@
use crate::theme::{theme, Theme};
use gpui3::{
- div, img, svg, ArcCow, Element, IntoAnyElement, ParentElement, ScrollState, StyleHelpers,
- ViewContext,
+ div, img, svg, view, AppContext, ArcCow, Context, Element, IntoAnyElement, ParentElement,
+ ScrollState, StyleHelpers, View, ViewContext, WindowContext,
};
-use std::marker::PhantomData;
-pub struct CollabPanelElement<V: 'static> {
- view_type: PhantomData<V>,
+struct CollabPanel {
scroll_state: ScrollState,
}
-// When I improve child view rendering, I'd like to have V implement a trait that
-// provides the scroll state, among other things.
-pub fn collab_panel<V: 'static>(scroll_state: ScrollState) -> CollabPanelElement<V> {
- CollabPanelElement {
- view_type: PhantomData,
- scroll_state,
+pub fn collab_panel(cx: &mut WindowContext) -> View<CollabPanel> {
+ view(cx.entity(|cx| CollabPanel::new(cx)), |panel, cx| {
+ panel.render(cx)
+ })
+}
+
+impl CollabPanel {
+ fn new(_: &mut AppContext) -> Self {
+ CollabPanel {
+ scroll_state: ScrollState::default(),
+ }
}
}
-impl<V: 'static> CollabPanelElement<V> {
- fn render(&mut self, _: &mut V, cx: &mut ViewContext<V>) -> impl Element {
+impl CollabPanel {
+ fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<State = Self> {
let theme = theme(cx);
// Panel
@@ -115,10 +118,10 @@ impl<V: 'static> CollabPanelElement<V> {
fn list_section_header(
&self,
- label: impl IntoAnyElement<V>,
+ label: impl IntoAnyElement<Self>,
expanded: bool,
theme: &Theme,
- ) -> impl Element<State = V> {
+ ) -> impl Element<State = Self> {
div()
.h_7()
.px_2()
@@ -144,9 +147,9 @@ impl<V: 'static> CollabPanelElement<V> {
fn list_item(
&self,
avatar_uri: impl Into<ArcCow<'static, str>>,
- label: impl IntoAnyElement<V>,
+ label: impl IntoAnyElement<Self>,
theme: &Theme,
- ) -> impl Element<State = V> {
+ ) -> impl Element<State = Self> {
div()
.h_7()
.px_2()
@@ -1,7 +1,7 @@
use crate::{collab_panel::collab_panel, theme::theme};
use gpui3::{div, img, svg, Element, ParentElement, ScrollState, StyleHelpers, ViewContext};
-#[derive(Element, Default)]
+#[derive(Default)]
struct WorkspaceElement {
left_scroll_state: ScrollState,
right_scroll_state: ScrollState,
@@ -271,18 +271,12 @@ impl TitleBar {
// ================================================================================ //
-struct StatusBar;
+mod statusbar {
+ use gpui3::WindowContext;
-pub fn statusbar<V: 'static>() -> impl Element<State = V> {
- StatusBar
-}
+ use super::*;
-impl StatusBar {
- fn render<V: 'static>(
- &mut self,
- _: &mut V,
- cx: &mut ViewContext<V>,
- ) -> impl Element<State = V> {
+ pub fn statusbar<V: 'static>(_: &mut V, cx: &mut ViewContext<V>) -> impl Element<State = V> {
let theme = theme(cx);
div()
.flex()
@@ -291,11 +285,11 @@ impl StatusBar {
.w_full()
.h_8()
.fill(theme.lowest.base.default.background)
- .child(self.left_group(cx))
- .child(self.right_group(cx))
+ .child(left_group(cx))
+ .child(right_group(cx))
}
- fn left_group<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl Element<State = V> {
+ fn left_group<V: 'static>(cx: &mut ViewContext<V>) -> impl Element<State = V> {
let theme = theme(cx);
div()
.flex()
@@ -392,7 +386,7 @@ impl StatusBar {
)
}
- fn right_group<V: 'static>(&mut self, cx: &mut ViewContext<V>) -> impl Element<State = V> {
+ fn right_group<S: 'static>(cx: &mut ViewContext<S>) -> impl Element<State = S> {
let theme = theme(cx);
div()
.flex()