This commit is contained in:
Nathan Sobo 2023-09-21 13:39:43 -06:00
parent 8573c6e8c6
commit a53c0b9472
7 changed files with 88 additions and 43 deletions

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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