Checkpoint

This commit is contained in:
Nathan Sobo 2023-09-14 14:42:04 -06:00
parent 1c20a8cd31
commit b9e1ca1385
12 changed files with 1353 additions and 747 deletions

1
Cargo.lock generated
View file

@ -7384,6 +7384,7 @@ dependencies = [
"serde",
"settings",
"simplelog",
"slotmap",
"theme",
"util",
]

View file

@ -35,7 +35,7 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
let field_visibilities: Vec<_> = fields.iter().map(|f| &f.vis).collect();
let wrapped_types: Vec<_> = fields.iter().map(|f| get_wrapper_type(f, &f.ty)).collect();
// Create trait bound that each wrapped type must implement Clone & Default
// Create trait bound that each wrapped type must implement Clone // & Default
let type_param_bounds: Vec<_> = wrapped_types
.iter()
.map(|ty| {
@ -51,13 +51,14 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
lifetimes: None,
path: parse_quote!(Clone),
}));
punctuated.push_punct(syn::token::Add::default());
punctuated.push_value(TypeParamBound::Trait(TraitBound {
paren_token: None,
modifier: syn::TraitBoundModifier::None,
lifetimes: None,
path: parse_quote!(Default),
}));
// punctuated.push_punct(syn::token::Add::default());
// punctuated.push_value(TypeParamBound::Trait(TraitBound {
// paren_token: None,
// modifier: syn::TraitBoundModifier::None,
// lifetimes: None,
// path: parse_quote!(Default),
// }));
punctuated
},
})
@ -161,7 +162,7 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
};
let gen = quote! {
#[derive(Default, Clone)]
#[derive(Clone)]
pub struct #refinement_ident #impl_generics {
#( #field_visibilities #field_names: #wrapped_types ),*
}
@ -186,6 +187,16 @@ pub fn derive_refineable(input: TokenStream) -> TokenStream {
}
}
impl #impl_generics ::core::default::Default for #refinement_ident #ty_generics
#where_clause
{
fn default() -> Self {
#refinement_ident {
#( #field_names: Default::default() ),*
}
}
}
impl #impl_generics #refinement_ident #ty_generics
#where_clause
{

View file

@ -18,6 +18,7 @@ rust-embed.workspace = true
serde.workspace = true
settings = { path = "../settings" }
simplelog = "0.9"
slotmap = "1.0.6"
theme = { path = "../theme" }
util = { path = "../util" }

View file

@ -0,0 +1,167 @@
use anyhow::{anyhow, Result};
use std::{any::Any, collections::HashMap, marker::PhantomData};
use super::{
window::{Window, WindowHandle, WindowId},
Context, EntityId, LayoutId, Reference, View, WindowContext,
};
pub struct AppContext {
pub(crate) entity_count: usize,
pub(crate) entities: HashMap<EntityId, Box<dyn Any>>,
pub(crate) window_count: usize,
pub(crate) windows: HashMap<WindowId, Window>,
// We recycle this memory across layout requests.
pub(crate) child_layout_buffer: Vec<LayoutId>,
}
impl AppContext {
pub fn new() -> Self {
AppContext {
entity_count: 0,
entities: HashMap::new(),
window_count: 0,
windows: HashMap::new(),
child_layout_buffer: Default::default(),
}
}
pub fn open_window<S>(
&mut self,
build_root_view: impl FnOnce(&mut WindowContext) -> View<S>,
) -> WindowHandle<S> {
let window = Window::new(&mut self.window_count);
unimplemented!()
}
pub(crate) fn update_window<R>(
&mut self,
window_id: WindowId,
update: impl FnOnce(&mut WindowContext) -> R,
) -> Result<R> {
let mut window = self
.windows
.remove(&window_id)
.ok_or_else(|| anyhow!("window not found"))?;
let result = update(&mut WindowContext::mutable(self, &mut window));
self.windows.insert(window_id, window);
Ok(result)
}
}
impl Context for AppContext {
type EntityContext<'a, 'w, T: 'static> = ModelContext<'a, T>;
fn entity<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
) -> Handle<T> {
let entity_id = EntityId::new(&mut self.entity_count);
let entity = build_entity(&mut ModelContext::mutable(self, entity_id));
self.entities.insert(entity_id, Box::new(entity));
Handle::new(entity_id)
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
) -> R {
let mut entity = self
.entities
.remove(&handle.id)
.unwrap()
.downcast::<T>()
.unwrap();
let result = update(&mut *entity, &mut ModelContext::mutable(self, handle.id));
self.entities.insert(handle.id, Box::new(entity));
result
}
}
pub struct ModelContext<'a, T> {
app: Reference<'a, AppContext>,
entity_type: PhantomData<T>,
entity_id: EntityId,
}
impl<'a, T: 'static> ModelContext<'a, T> {
pub(crate) fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
Self {
app: Reference::Mutable(app),
entity_type: PhantomData,
entity_id,
}
}
fn immutable(app: &'a AppContext, entity_id: EntityId) -> Self {
Self {
app: Reference::Immutable(app),
entity_type: PhantomData,
entity_id,
}
}
fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
let mut entity = self.app.entities.remove(&self.entity_id).unwrap();
let result = update(entity.downcast_mut::<T>().unwrap(), self);
self.app.entities.insert(self.entity_id, Box::new(entity));
result
}
}
impl<'a, T: 'static> Context for ModelContext<'a, T> {
type EntityContext<'b, 'c, U: 'static> = ModelContext<'b, U>;
fn entity<U: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, U>) -> U,
) -> Handle<U> {
self.app.entity(build_entity)
}
fn update_entity<U: 'static, R>(
&mut self,
handle: &Handle<U>,
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
) -> R {
self.app.update_entity(handle, update)
}
}
pub struct Handle<T> {
pub(crate) id: EntityId,
pub(crate) entity_type: PhantomData<T>,
}
impl<T: 'static> Handle<T> {
fn new(id: EntityId) -> Self {
Self {
id,
entity_type: PhantomData,
}
}
/// Update the entity referenced by this handle with the given function.
///
/// The update function receives a context appropriate for its environment.
/// When updating in an `AppContext`, it receives a `ModelContext`.
/// When updating an a `WindowContext`, it receives a `ViewContext`.
pub fn update<C: Context, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
) -> R {
cx.update_entity(self, update)
}
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
entity_type: PhantomData,
}
}
}

View file

@ -0,0 +1,276 @@
use super::{Handle, Layout, LayoutId, Pixels, Point, ViewContext, WindowContext};
use anyhow::Result;
use std::{any::Any, cell::RefCell, marker::PhantomData, rc::Rc};
pub trait Element: 'static {
type State;
type FrameState;
fn layout(
&mut self,
state: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)>;
fn paint(
&mut self,
layout: Layout,
state: &mut Self::State,
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()>;
}
pub trait ParentElement<S> {
fn child(self, child: impl IntoAnyElement<S>) -> Self;
}
trait ElementObject<S> {
fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
fn paint(
&mut self,
parent_origin: super::Point<Pixels>,
state: &mut S,
cx: &mut ViewContext<S>,
) -> Result<()>;
}
struct RenderedElement<E: Element> {
element: E,
phase: ElementRenderPhase<E::FrameState>,
}
#[derive(Default)]
enum ElementRenderPhase<S> {
#[default]
Rendered,
LayoutRequested {
layout_id: LayoutId,
frame_state: S,
},
Painted {
layout: Layout,
frame_state: S,
},
}
/// Internal struct that wraps an element to store Layout and FrameState 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::Rendered,
}
}
}
impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
let (layout_id, frame_state) = self.element.layout(state, cx)?;
self.phase = ElementRenderPhase::LayoutRequested {
layout_id,
frame_state,
};
Ok(layout_id)
}
fn paint(
&mut self,
parent_origin: Point<Pixels>,
state: &mut E::State,
cx: &mut ViewContext<E::State>,
) -> Result<()> {
self.phase = match std::mem::take(&mut self.phase) {
ElementRenderPhase::Rendered => panic!("must call layout before paint"),
ElementRenderPhase::LayoutRequested {
layout_id,
mut frame_state,
} => {
let mut layout = cx.layout(layout_id)?;
layout.bounds.origin += parent_origin;
self.element
.paint(layout.clone(), state, &mut frame_state, cx)?;
ElementRenderPhase::Painted {
layout,
frame_state,
}
}
ElementRenderPhase::Painted {
layout,
mut frame_state,
} => {
self.element
.paint(layout.clone(), state, &mut frame_state, cx)?;
ElementRenderPhase::Painted {
layout,
frame_state,
}
}
};
Ok(())
}
}
pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
impl<S> AnyElement<S> {
pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
self.0.layout(state, cx)
}
pub fn paint(
&mut self,
parent_origin: Point<Pixels>,
state: &mut S,
cx: &mut ViewContext<S>,
) -> Result<()> {
self.0.paint(parent_origin, state, cx)
}
}
pub trait IntoAnyElement<S> {
fn into_any(self) -> AnyElement<S>;
}
impl<E: Element> IntoAnyElement<E::State> for E {
fn into_any(self) -> AnyElement<E::State> {
AnyElement(Box::new(RenderedElement::new(self)))
}
}
impl<S> IntoAnyElement<S> for AnyElement<S> {
fn into_any(self) -> AnyElement<S> {
self
}
}
#[derive(Clone)]
pub struct View<S> {
state: Handle<S>,
render: Rc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S>>,
}
pub fn view<S: 'static, E: Element<State = S>>(
state: Handle<S>,
render: impl 'static + Fn(&mut S, &mut ViewContext<S>) -> E,
) -> View<S> {
View {
state,
render: Rc::new(move |state, cx| render(state, cx).into_any()),
}
}
impl<S: 'static> View<S> {
pub fn into_any<ParentState>(self) -> AnyView<ParentState> {
AnyView {
view: Rc::new(RefCell::new(self)),
parent_state_type: PhantomData,
}
}
}
impl<S: 'static> Element for View<S> {
type State = ();
type FrameState = AnyElement<S>;
fn layout(
&mut self,
_: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
self.state.update(cx, |state, cx| {
let mut element = (self.render)(state, cx);
let layout_id = element.layout(state, cx)?;
Ok((layout_id, element))
})
}
fn paint(
&mut self,
layout: Layout,
_: &mut Self::State,
element: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
self.state.update(cx, |state, cx| {
element.paint(layout.bounds.origin, state, cx)
})
}
}
trait ViewObject {
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
fn paint(
&mut self,
layout: Layout,
element: &mut dyn Any,
cx: &mut WindowContext,
) -> Result<()>;
}
impl<S: 'static> ViewObject for View<S> {
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
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 Box<dyn Any>;
Ok((layout_id, element))
})
}
fn paint(
&mut self,
layout: Layout,
element: &mut dyn Any,
cx: &mut WindowContext,
) -> Result<()> {
self.state.update(cx, |state, cx| {
element
.downcast_mut::<AnyElement<S>>()
.unwrap()
.paint(layout.bounds.origin, state, cx)
})
}
}
pub struct AnyView<S> {
view: Rc<RefCell<dyn ViewObject>>,
parent_state_type: PhantomData<S>,
}
impl<S: 'static> Element for AnyView<S> {
type State = S;
type FrameState = Box<dyn Any>;
fn layout(
&mut self,
_: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
self.view.borrow_mut().layout(cx)
}
fn paint(
&mut self,
layout: Layout,
_: &mut Self::State,
element: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
self.view.borrow_mut().paint(layout, element, cx)
}
}
impl<S> Clone for AnyView<S> {
fn clone(&self) -> Self {
Self {
view: self.view.clone(),
parent_state_type: PhantomData,
}
}
}

View file

@ -0,0 +1,303 @@
use core::fmt::Debug;
use derive_more::{Add, AddAssign, Div, Mul, Sub};
use refineable::Refineable;
use std::ops::Mul;
#[derive(Default, Add, AddAssign, Sub, Mul, Div, Copy, Debug, PartialEq, Eq, Hash)]
pub struct Point<T> {
pub x: T,
pub y: T,
}
impl<T: Clone> Clone for Point<T> {
fn clone(&self) -> Self {
Self {
x: self.x.clone(),
y: self.y.clone(),
}
}
}
#[derive(Default, Clone, Refineable, Debug)]
pub struct Size<T: Clone> {
pub width: T,
pub height: T,
}
impl Size<Length> {
pub fn full() -> Self {
Self {
width: relative(1.),
height: relative(1.),
}
}
}
impl Size<DefiniteLength> {
pub fn zero() -> Self {
Self {
width: px(0.),
height: px(0.),
}
}
}
impl Size<Length> {
pub fn auto() -> Self {
Self {
width: Length::Auto,
height: Length::Auto,
}
}
}
#[derive(Clone, Default, Debug)]
pub struct Bounds<F: Clone> {
pub origin: Point<F>,
pub size: Size<F>,
}
#[derive(Clone, Default, Refineable, Debug)]
pub struct Edges<T: Clone> {
pub top: T,
pub right: T,
pub bottom: T,
pub left: T,
}
impl Edges<Length> {
pub fn auto() -> Self {
Self {
top: Length::Auto,
right: Length::Auto,
bottom: Length::Auto,
left: Length::Auto,
}
}
pub fn zero() -> Self {
Self {
top: px(0.),
right: px(0.),
bottom: px(0.),
left: px(0.),
}
}
}
impl Edges<DefiniteLength> {
pub fn zero() -> Self {
Self {
top: px(0.),
right: px(0.),
bottom: px(0.),
left: px(0.),
}
}
}
impl Edges<AbsoluteLength> {
pub fn zero() -> Self {
Self {
top: px(0.),
right: px(0.),
bottom: px(0.),
left: px(0.),
}
}
pub fn to_pixels(&self, rem_size: Pixels) -> Edges<Pixels> {
Edges {
top: self.top.to_pixels(rem_size),
right: self.right.to_pixels(rem_size),
bottom: self.bottom.to_pixels(rem_size),
left: self.left.to_pixels(rem_size),
}
}
}
impl Edges<Pixels> {
pub fn is_empty(&self) -> bool {
self.top == px(0.) && self.right == px(0.) && self.bottom == px(0.) && self.left == px(0.)
}
}
#[derive(Clone, Copy, Default, Add, AddAssign, Sub, Mul, Div, PartialEq)]
pub struct Pixels(pub(crate) f32);
impl Debug for Pixels {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} px", self.0)
}
}
impl From<Pixels> for f32 {
fn from(pixels: Pixels) -> Self {
pixels.0
}
}
impl From<&Pixels> for f32 {
fn from(pixels: &Pixels) -> Self {
pixels.0
}
}
#[derive(Clone, Copy, Default, Add, Sub, Mul, Div)]
pub struct Rems(f32);
impl Mul<Pixels> for Rems {
type Output = Pixels;
fn mul(self, other: Pixels) -> Pixels {
Pixels(self.0 * other.0)
}
}
impl Debug for Rems {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
write!(f, "{} rem", self.0)
}
}
#[derive(Clone, Copy, Debug)]
pub enum AbsoluteLength {
Pixels(Pixels),
Rems(Rems),
}
impl From<Pixels> for AbsoluteLength {
fn from(pixels: Pixels) -> Self {
AbsoluteLength::Pixels(pixels)
}
}
impl From<Rems> for AbsoluteLength {
fn from(rems: Rems) -> Self {
AbsoluteLength::Rems(rems)
}
}
impl AbsoluteLength {
pub fn to_pixels(&self, rem_size: Pixels) -> Pixels {
match self {
AbsoluteLength::Pixels(pixels) => *pixels,
AbsoluteLength::Rems(rems) => *rems * rem_size,
}
}
}
impl Default for AbsoluteLength {
fn default() -> Self {
px(0.)
}
}
/// A non-auto length that can be defined in pixels, rems, or percent of parent.
#[derive(Clone, Copy)]
pub enum DefiniteLength {
Absolute(AbsoluteLength),
/// A fraction of the parent's size between 0 and 1.
Fraction(f32),
}
impl Debug for DefiniteLength {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
DefiniteLength::Absolute(length) => Debug::fmt(length, f),
DefiniteLength::Fraction(fract) => write!(f, "{}%", (fract * 100.0) as i32),
}
}
}
impl From<Pixels> for DefiniteLength {
fn from(pixels: Pixels) -> Self {
Self::Absolute(pixels.into())
}
}
impl From<Rems> for DefiniteLength {
fn from(rems: Rems) -> Self {
Self::Absolute(rems.into())
}
}
impl From<AbsoluteLength> for DefiniteLength {
fn from(length: AbsoluteLength) -> Self {
Self::Absolute(length)
}
}
impl Default for DefiniteLength {
fn default() -> Self {
Self::Absolute(AbsoluteLength::default())
}
}
/// A length that can be defined in pixels, rems, percent of parent, or auto.
#[derive(Clone, Copy)]
pub enum Length {
Definite(DefiniteLength),
Auto,
}
impl Debug for Length {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
Length::Definite(definite_length) => write!(f, "{:?}", definite_length),
Length::Auto => write!(f, "auto"),
}
}
}
pub fn relative<T: From<DefiniteLength>>(fraction: f32) -> T {
DefiniteLength::Fraction(fraction).into()
}
pub fn rems<T: From<Rems>>(rems: f32) -> T {
Rems(rems).into()
}
pub fn px<T: From<Pixels>>(pixels: f32) -> T {
Pixels(pixels).into()
}
pub fn auto() -> Length {
Length::Auto
}
impl From<Pixels> for Length {
fn from(pixels: Pixels) -> Self {
Self::Definite(pixels.into())
}
}
impl From<Rems> for Length {
fn from(rems: Rems) -> Self {
Self::Definite(rems.into())
}
}
impl From<DefiniteLength> for Length {
fn from(length: DefiniteLength) -> Self {
Self::Definite(length)
}
}
impl From<AbsoluteLength> for Length {
fn from(length: AbsoluteLength) -> Self {
Self::Definite(length.into())
}
}
impl Default for Length {
fn default() -> Self {
Self::Definite(DefiniteLength::default())
}
}
impl From<()> for Length {
fn from(_: ()) -> Self {
Self::Definite(DefiniteLength::default())
}
}

View file

@ -0,0 +1,191 @@
mod app;
mod element;
mod geometry;
mod style;
mod taffy;
mod window;
use anyhow::Result;
pub use gpui2::ArcCow;
use gpui2::Reference;
use std::marker::PhantomData;
pub use app::*;
pub use element::*;
pub use geometry::*;
pub use style::*;
use taffy::TaffyLayoutEngine;
pub use window::*;
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct EntityId(usize);
impl EntityId {
fn new(entity_count: &mut usize) -> EntityId {
let id = *entity_count;
*entity_count += 1;
Self(id)
}
}
pub trait Context {
type EntityContext<'a, 'w, T: 'static>;
fn entity<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
) -> Handle<T>;
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
) -> R;
}
pub struct Div<S>(PhantomData<S>);
impl<S: 'static> Element for Div<S> {
type State = S;
type FrameState = ();
fn layout(
&mut self,
state: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
todo!()
}
fn paint(
&mut self,
layout: Layout,
state: &mut Self::State,
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
todo!()
}
}
impl<S> ParentElement<S> for Div<S> {
fn child(self, child: impl IntoAnyElement<S>) -> Self {
todo!()
}
}
pub fn div<S>() -> Div<S> {
todo!()
}
pub struct SharedString(ArcCow<'static, str>);
impl<T: Into<ArcCow<'static, str>>> From<T> for SharedString {
fn from(value: T) -> Self {
Self(value.into())
}
}
struct Workspace {
left_panel: AnyView<Self>,
}
fn workspace(cx: &mut WindowContext) -> View<Workspace> {
let workspace = cx.entity(|cx| Workspace {
left_panel: collab_panel(cx).into_any(),
});
view(workspace, |workspace, cx| {
div().child(workspace.left_panel.clone())
})
}
struct CollabPanel {
filter_editor: Handle<Editor>,
}
fn collab_panel(cx: &mut WindowContext) -> View<CollabPanel> {
let panel = cx.entity(|cx| CollabPanel::new(cx));
view(panel, |panel, cx| {
div()
.child(div())
.child(field(panel.filter_editor.clone()).placeholder_text("Search channels, contacts"))
})
}
impl CollabPanel {
fn new(cx: &mut ViewContext<Self>) -> Self {
Self {
filter_editor: cx.entity(|cx| Editor::new(cx)),
}
}
}
fn field<S>(editor: Handle<Editor>) -> EditorElement<S> {
EditorElement {
editor,
field: true,
placeholder_text: None,
parent_state: PhantomData,
}
}
struct EditorElement<S> {
editor: Handle<Editor>,
field: bool,
placeholder_text: Option<SharedString>,
parent_state: PhantomData<S>,
}
impl<S> EditorElement<S> {
pub fn field(mut self) -> Self {
self.field = true;
self
}
pub fn placeholder_text(mut self, text: impl Into<SharedString>) -> Self {
self.placeholder_text = Some(text.into());
self
}
}
impl<S: 'static> Element for EditorElement<S> {
type State = S;
type FrameState = ();
fn layout(
&mut self,
_: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
self.editor.update(cx, |editor, cx| todo!())
}
fn paint(
&mut self,
layout: Layout,
state: &mut Self::State,
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
self.editor.update(cx, |editor, cx| todo!())
}
}
struct Editor {}
impl Editor {
pub fn new(_: &mut ViewContext<Self>) -> Self {
Editor {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let mut cx = AppContext::new();
cx.open_window(|cx| workspace(cx));
}
}

View file

@ -0,0 +1 @@
pub struct Style;

View file

@ -0,0 +1,177 @@
use super::{
AbsoluteLength, Bounds, DefiniteLength, Edges, Layout, LayoutEngine, LayoutId, Length, Pixels,
Point, Size, Style,
};
use anyhow::Result;
use gpui2::taffy::{self, Taffy};
use std::fmt::Debug;
pub use gpui2::taffy::tree::NodeId;
pub struct TaffyLayoutEngine(Taffy);
impl TaffyLayoutEngine {
pub fn new() -> Self {
TaffyLayoutEngine(Taffy::new())
}
}
impl LayoutEngine for TaffyLayoutEngine {
fn request_layout(&mut self, style: Style, children: &[LayoutId]) -> Result<LayoutId> {
todo!()
}
fn layout(&mut self, id: LayoutId) -> Result<Layout> {
todo!()
}
}
trait ToTaffy {
type Output;
fn to_taffy(&self, rem_size: Pixels) -> Self::Output;
}
impl ToTaffy for Style {
type Output = taffy::style::Style;
fn to_taffy(&self, rem_size: Pixels) -> Self::Output {
todo!()
}
}
// impl ToTaffy for Bounds<Length> {
// type Output = taffy::prelude::Bounds<taffy::prelude::LengthPercentageAuto>;
// fn to_taffy(
// &self,
// rem_size: Pixels,
// ) -> taffy::prelude::Bounds<taffy::prelude::LengthPercentageAuto> {
// taffy::prelude::Bounds {
// origin: self.origin.to_taffy(rem_size),
// size: self.size.to_taffy(rem_size),
// }
// }
// }
impl ToTaffy for Length {
type Output = taffy::style::LengthPercentageAuto;
fn to_taffy(&self, rem_size: Pixels) -> taffy::prelude::LengthPercentageAuto {
match self {
Length::Definite(length) => length.to_taffy(rem_size).into(),
Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
}
}
}
impl ToTaffy for DefiniteLength {
type Output = taffy::style::LengthPercentage;
fn to_taffy(&self, rem_size: Pixels) -> taffy::style::LengthPercentage {
match self {
DefiniteLength::Absolute(length) => match length {
AbsoluteLength::Pixels(pixels) => {
taffy::style::LengthPercentage::Length(pixels.into())
}
AbsoluteLength::Rems(rems) => {
taffy::style::LengthPercentage::Length((*rems * rem_size).into())
}
},
DefiniteLength::Fraction(fraction) => {
taffy::style::LengthPercentage::Percent(*fraction)
}
}
}
}
impl ToTaffy for AbsoluteLength {
type Output = taffy::style::LengthPercentage;
fn to_taffy(&self, rem_size: Pixels) -> Self::Output {
match self {
AbsoluteLength::Pixels(pixels) => taffy::style::LengthPercentage::Length(pixels.into()),
AbsoluteLength::Rems(rems) => {
taffy::style::LengthPercentage::Length((*rems * rem_size).into())
}
}
}
}
impl<T, T2> From<taffy::geometry::Point<T>> for Point<T2>
where
T: Into<T2>,
{
fn from(point: taffy::geometry::Point<T>) -> Point<T2> {
Point {
x: point.x.into(),
y: point.y.into(),
}
}
}
impl<T, T2> Into<taffy::geometry::Point<T2>> for Point<T>
where
T: Into<T2>,
{
fn into(self) -> taffy::geometry::Point<T2> {
taffy::geometry::Point {
x: self.x.into(),
y: self.y.into(),
}
}
}
impl<T: ToTaffy + Clone> ToTaffy for Size<T> {
type Output = taffy::geometry::Size<T::Output>;
fn to_taffy(&self, rem_size: Pixels) -> Self::Output {
taffy::geometry::Size {
width: self.width.to_taffy(rem_size).into(),
height: self.height.to_taffy(rem_size).into(),
}
}
}
impl<T: ToTaffy + Clone> ToTaffy for Edges<T> {
type Output = taffy::geometry::Rect<T::Output>;
fn to_taffy(&self, rem_size: Pixels) -> Self::Output {
taffy::geometry::Rect {
top: self.top.to_taffy(rem_size),
right: self.right.to_taffy(rem_size),
bottom: self.bottom.to_taffy(rem_size),
left: self.left.to_taffy(rem_size),
}
}
}
impl<S, T: Clone + Default + Debug> From<taffy::geometry::Size<S>> for Size<T>
where
S: Into<T>,
{
fn from(value: taffy::geometry::Size<S>) -> Self {
Self {
width: value.width.into(),
height: value.height.into(),
}
}
}
impl From<&taffy::tree::Layout> for Layout {
fn from(layout: &taffy::tree::Layout) -> Self {
Layout {
order: layout.order,
bounds: Bounds {
origin: layout.location.into(),
size: layout.size.into(),
},
}
}
}
impl From<f32> for Pixels {
fn from(pixels: f32) -> Self {
Self(pixels)
}
}

View file

@ -0,0 +1,215 @@
use super::{px, AppContext, Bounds, Context, EntityId, Handle, Pixels, Style, TaffyLayoutEngine};
use anyhow::Result;
use derive_more::{Deref, DerefMut};
use gpui2::Reference;
use std::marker::PhantomData;
pub struct Window {
id: WindowId,
rem_size: Pixels,
layout_engine: Box<dyn LayoutEngine>,
}
impl Window {
pub fn new(window_count: &mut usize) -> Window {
let id = WindowId::new(window_count);
Window {
id,
layout_engine: Box::new(TaffyLayoutEngine::new()),
rem_size: px(16.),
}
}
}
#[derive(Deref, DerefMut)]
pub struct WindowContext<'a, 'b> {
#[deref]
#[deref_mut]
app: Reference<'a, AppContext>,
window: Reference<'b, Window>,
}
impl<'a, 'w> WindowContext<'a, 'w> {
pub(crate) fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
Self {
app: Reference::Mutable(app),
window: Reference::Mutable(window),
}
}
pub(crate) fn immutable(app: &'a AppContext, window: &'w Window) -> Self {
Self {
app: Reference::Immutable(app),
window: Reference::Immutable(window),
}
}
pub fn request_layout(
&mut self,
style: Style,
children: impl IntoIterator<Item = LayoutId>,
) -> Result<LayoutId> {
self.app.child_layout_buffer.clear();
self.app.child_layout_buffer.extend(children.into_iter());
self.window
.layout_engine
.request_layout(style, &self.app.child_layout_buffer)
}
pub fn layout(&mut self, layout_id: LayoutId) -> Result<Layout> {
Ok(self
.window
.layout_engine
.layout(layout_id)
.map(Into::into)?)
}
pub fn rem_size(&self) -> Pixels {
self.window.rem_size
}
fn update_window<R>(
&mut self,
window_id: WindowId,
update: impl FnOnce(&mut WindowContext) -> R,
) -> Result<R> {
if window_id == self.window.id {
Ok(update(self))
} else {
self.app.update_window(window_id, update)
}
}
}
impl Context for WindowContext<'_, '_> {
type EntityContext<'a, 'w, T: 'static> = ViewContext<'a, 'w, T>;
fn entity<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T>) -> T,
) -> Handle<T> {
{
let id = EntityId::new(&mut self.app.entity_count);
let entity = build_entity(&mut ViewContext::mutable(
&mut *self.app,
&mut self.window,
id,
));
let handle = Handle {
id,
entity_type: PhantomData,
};
self.app.entities.insert(handle.id, Box::new(entity));
handle
}
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
) -> R {
let mut entity = self
.app
.entities
.remove(&handle.id)
.unwrap()
.downcast::<T>()
.unwrap();
let result = update(
&mut *entity,
&mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
);
self.entities.insert(handle.id, Box::new(entity));
result
}
}
#[derive(Deref, DerefMut)]
pub struct ViewContext<'a, 'w, T> {
#[deref]
#[deref_mut]
window_cx: WindowContext<'a, 'w>,
entity_type: PhantomData<T>,
entity_id: EntityId,
}
impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> {
fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
let mut entity = self.window_cx.app.entities.remove(&self.entity_id).unwrap();
let result = update(entity.downcast_mut::<T>().unwrap(), self);
self.window_cx
.app
.entities
.insert(self.entity_id, Box::new(entity));
result
}
fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
Self {
window_cx: WindowContext::mutable(app, window),
entity_id,
entity_type: PhantomData,
}
}
fn immutable(app: &'a AppContext, window: &'w Window, entity_id: EntityId) -> Self {
Self {
window_cx: WindowContext::immutable(app, window),
entity_id,
entity_type: PhantomData,
}
}
}
impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> {
type EntityContext<'b, 'c, U: 'static> = ViewContext<'b, 'c, U>;
fn entity<T2: 'static>(
&mut self,
build_entity: impl FnOnce(&mut Self::EntityContext<'_, '_, T2>) -> T2,
) -> Handle<T2> {
self.window_cx.entity(build_entity)
}
fn update_entity<U: 'static, R>(
&mut self,
handle: &Handle<U>,
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
) -> R {
self.window_cx.update_entity(handle, update)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct WindowId(usize);
impl WindowId {
fn new(window_count: &mut usize) -> Self {
let id = *window_count;
*window_count += 1;
Self(id)
}
}
pub struct WindowHandle<S> {
id: WindowId,
state_type: PhantomData<S>,
}
#[derive(Clone)]
pub struct Layout {
pub order: u32,
pub bounds: Bounds<Pixels>,
}
#[derive(Copy, Clone)]
pub struct LayoutId(slotmap::DefaultKey);
pub trait LayoutEngine {
/// Register a new node on which to perform layout.
fn request_layout(&mut self, style: Style, children: &[LayoutId]) -> Result<LayoutId>;
/// Get the layout for the given id.
fn layout(&mut self, id: LayoutId) -> Result<Layout>;
}

View file

@ -1,737 +0,0 @@
use anyhow::{anyhow, Result};
use derive_more::{Deref, DerefMut};
use gpui2::{taffy::Taffy, ArcCow, Layout, LayoutId, Reference, Vector2F};
use std::{any::Any, cell::RefCell, collections::HashMap, marker::PhantomData, rc::Rc};
pub struct AppContext {
entity_count: usize,
entities: HashMap<EntityId, Box<dyn Any>>,
window_count: usize,
windows: HashMap<WindowId, Window>,
}
impl AppContext {
pub fn new() -> Self {
AppContext {
entity_count: 0,
entities: HashMap::new(),
window_count: 0,
windows: HashMap::new(),
}
}
pub fn open_window<S>(
&mut self,
build_root_view: impl FnOnce(&mut WindowContext) -> View<S>,
) -> WindowHandle<S> {
let window = Window::new(&mut self.window_count);
unimplemented!()
}
fn add_entity<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut ModelContext<T>) -> T,
) -> Handle<T> {
let id = EntityId::new(&mut self.entity_count);
let entity = build_entity(&mut ModelContext::mutable(self, id));
self.entities.insert(id, Box::new(entity));
Handle {
id,
entity_type: PhantomData,
}
}
fn update_window<R>(
&mut self,
window_id: WindowId,
update: impl FnOnce(&mut WindowContext) -> R,
) -> Result<R> {
let mut window = self
.windows
.remove(&window_id)
.ok_or_else(|| anyhow!("window not found"))?;
let result = update(&mut WindowContext::mutable(self, &mut window));
self.windows.insert(window_id, window);
Ok(result)
}
}
pub struct ModelContext<'a, T> {
app: Reference<'a, AppContext>,
entity_type: PhantomData<T>,
entity_id: EntityId,
}
impl<'a, T: 'static> ModelContext<'a, T> {
fn mutable(app: &'a mut AppContext, entity_id: EntityId) -> Self {
Self {
app: Reference::Mutable(app),
entity_type: PhantomData,
entity_id,
}
}
fn immutable(app: &'a AppContext, entity_id: EntityId) -> Self {
Self {
app: Reference::Immutable(app),
entity_type: PhantomData,
entity_id,
}
}
fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
let mut entity = self.app.entities.remove(&self.entity_id).unwrap();
let result = update(entity.downcast_mut::<T>().unwrap(), self);
self.app.entities.insert(self.entity_id, Box::new(entity));
result
}
}
pub struct Window {
id: WindowId,
layout_engine: Taffy,
}
impl Window {
pub fn new(window_count: &mut usize) -> Window {
let id = WindowId::new(window_count);
Window {
id,
layout_engine: Taffy::new(),
}
}
}
#[derive(Deref, DerefMut)]
pub struct WindowContext<'a, 'b> {
#[deref]
#[deref_mut]
app: Reference<'a, AppContext>,
window: Reference<'b, Window>,
}
impl<'a, 'w> WindowContext<'a, 'w> {
fn mutable(app: &'a mut AppContext, window: &'w mut Window) -> Self {
Self {
app: Reference::Mutable(app),
window: Reference::Mutable(window),
}
}
fn immutable(app: &'a AppContext, window: &'w Window) -> Self {
Self {
app: Reference::Immutable(app),
window: Reference::Immutable(window),
}
}
fn app_context(&mut self) -> &mut AppContext {
&mut *self.app
}
}
impl<'a, 'w> WindowContext<'a, 'w> {
fn entity<T: 'static>(
&mut self,
build_entity: impl FnOnce(&mut ViewContext<'_, '_, T>) -> T,
) -> Handle<T> {
let id = EntityId::new(&mut self.app_context().entity_count);
let entity = build_entity(&mut ViewContext::mutable(
&mut *self.app,
&mut *self.window,
id,
));
self.app.entities.insert(id, Box::new(entity));
Handle {
id,
entity_type: PhantomData,
}
}
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut ViewContext<T>) -> R,
) -> R {
let mut entity = self.app.entities.remove(&handle.id).unwrap();
let result = update(
entity.downcast_mut().unwrap(),
&mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
);
self.app.entities.insert(handle.id, entity);
result
}
fn update_window<R>(
&mut self,
window_id: WindowId,
update: impl FnOnce(&mut WindowContext) -> R,
) -> Result<R> {
if window_id == self.window.id {
Ok(update(self))
} else {
self.app.update_window(window_id, update)
}
}
}
#[derive(Deref, DerefMut)]
pub struct ViewContext<'a, 'w, T> {
#[deref]
#[deref_mut]
window_cx: WindowContext<'a, 'w>,
entity_type: PhantomData<T>,
entity_id: EntityId,
}
impl<'a, 'w, T: 'static> ViewContext<'a, 'w, T> {
fn update<R>(&mut self, update: impl FnOnce(&mut T, &mut Self) -> R) -> R {
let mut entity = self.window_cx.app.entities.remove(&self.entity_id).unwrap();
let result = update(entity.downcast_mut::<T>().unwrap(), self);
self.window_cx
.app
.entities
.insert(self.entity_id, Box::new(entity));
result
}
fn mutable(app: &'a mut AppContext, window: &'w mut Window, entity_id: EntityId) -> Self {
Self {
window_cx: WindowContext::mutable(app, window),
entity_id,
entity_type: PhantomData,
}
}
fn immutable(app: &'a AppContext, window: &'w Window, entity_id: EntityId) -> Self {
Self {
window_cx: WindowContext::immutable(app, window),
entity_id,
entity_type: PhantomData,
}
}
}
impl<'a, 'w, T: 'static> Context for ViewContext<'a, 'w, T> {
type EntityContext<'b, 'c, U: 'static> = ViewContext<'b, 'c, U>;
fn update_entity<U: 'static, R>(
&mut self,
handle: &Handle<U>,
update: impl FnOnce(&mut U, &mut Self::EntityContext<'_, '_, U>) -> R,
) -> R {
ViewContext::mutable(
&mut *self.window_cx.app,
&mut *self.window_cx.window,
handle.id,
)
.update(update)
}
}
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct WindowId(usize);
impl WindowId {
fn new(window_count: &mut usize) -> Self {
let id = *window_count;
*window_count += 1;
Self(id)
}
}
pub struct WindowHandle<S> {
id: WindowId,
state_type: PhantomData<S>,
}
#[derive(Clone, Copy, Eq, PartialEq, Hash)]
pub struct EntityId(usize);
impl EntityId {
fn new(entity_count: &mut usize) -> EntityId {
let id = *entity_count;
*entity_count += 1;
Self(id)
}
}
trait Context {
type EntityContext<'a, 'w, T: 'static>;
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
) -> R;
}
impl Context for AppContext {
type EntityContext<'a, 'w, T: 'static> = ModelContext<'a, T>;
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
) -> R {
let mut entity = self
.entities
.remove(&handle.id)
.unwrap()
.downcast::<T>()
.unwrap();
let result = update(&mut *entity, &mut ModelContext::mutable(self, handle.id));
self.entities.insert(handle.id, Box::new(entity));
result
}
}
impl Context for WindowContext<'_, '_> {
type EntityContext<'a, 'w, T: 'static> = ViewContext<'a, 'w, T>;
fn update_entity<T: 'static, R>(
&mut self,
handle: &Handle<T>,
update: impl FnOnce(&mut T, &mut Self::EntityContext<'_, '_, T>) -> R,
) -> R {
let mut entity = self
.app
.entities
.remove(&handle.id)
.unwrap()
.downcast::<T>()
.unwrap();
let result = update(
&mut *entity,
&mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
);
self.entities.insert(handle.id, Box::new(entity));
result
}
}
pub struct Handle<T> {
id: EntityId,
entity_type: PhantomData<T>,
}
impl<T: 'static> Handle<T> {
fn update<C: Context, R>(
&self,
cx: &mut C,
update: impl FnOnce(&mut T, &mut C::EntityContext<'_, '_, T>) -> R,
) -> R {
cx.update_entity(self, update)
}
}
impl<T> Clone for Handle<T> {
fn clone(&self) -> Self {
Self {
id: self.id,
entity_type: PhantomData,
}
}
}
pub trait Element: 'static {
type State;
type FrameState;
fn layout(
&mut self,
state: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)>;
fn paint(
&mut self,
layout: Layout,
state: &mut Self::State,
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()>;
}
pub trait ParentElement<S> {
fn child(self, child: impl IntoAnyElement<S>) -> Self;
}
trait ElementObject<S> {
fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId>;
fn paint(
&mut self,
parent_origin: Vector2F,
state: &mut S,
cx: &mut ViewContext<S>,
) -> Result<()>;
}
struct RenderedElement<E: Element> {
element: E,
phase: ElementRenderPhase<E::FrameState>,
}
#[derive(Default)]
enum ElementRenderPhase<S> {
#[default]
Rendered,
LayoutRequested {
layout_id: LayoutId,
frame_state: S,
},
Painted {
layout: Layout,
frame_state: S,
},
}
impl<E: Element> RenderedElement<E> {
fn new(element: E) -> Self {
RenderedElement {
element,
phase: ElementRenderPhase::Rendered,
}
}
}
impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
fn layout(&mut self, state: &mut E::State, cx: &mut ViewContext<E::State>) -> Result<LayoutId> {
let (layout_id, frame_state) = self.element.layout(state, cx)?;
self.phase = ElementRenderPhase::LayoutRequested {
layout_id,
frame_state,
};
Ok(layout_id)
}
fn paint(
&mut self,
parent_origin: Vector2F,
state: &mut E::State,
cx: &mut ViewContext<E::State>,
) -> Result<()> {
self.phase = match std::mem::take(&mut self.phase) {
ElementRenderPhase::Rendered => panic!("must call layout before paint"),
ElementRenderPhase::LayoutRequested {
layout_id,
frame_state,
} => {
todo!()
}
ElementRenderPhase::Painted {
layout,
frame_state,
} => todo!(),
};
Ok(())
}
}
pub struct AnyElement<S>(Box<dyn ElementObject<S>>);
impl<S> AnyElement<S> {
pub fn layout(&mut self, state: &mut S, cx: &mut ViewContext<S>) -> Result<LayoutId> {
self.0.layout(state, cx)
}
pub fn paint(
&mut self,
parent_origin: Vector2F,
state: &mut S,
cx: &mut ViewContext<S>,
) -> Result<()> {
self.0.paint(parent_origin, state, cx)
}
}
pub trait IntoAnyElement<S> {
fn into_any(self) -> AnyElement<S>;
}
impl<E: Element> IntoAnyElement<E::State> for E {
fn into_any(self) -> AnyElement<E::State> {
AnyElement(Box::new(RenderedElement::new(self)))
}
}
impl<S> IntoAnyElement<S> for AnyElement<S> {
fn into_any(self) -> AnyElement<S> {
self
}
}
#[derive(Clone)]
pub struct View<S> {
state: Handle<S>,
render: Rc<dyn Fn(&mut S, &mut ViewContext<S>) -> AnyElement<S>>,
}
pub fn view<S: 'static, E: Element<State = S>>(
state: Handle<S>,
render: impl 'static + Fn(&mut S, &mut ViewContext<S>) -> E,
) -> View<S> {
View {
state,
render: Rc::new(move |state, cx| render(state, cx).into_any()),
}
}
impl<S: 'static> View<S> {
pub fn into_any<ParentState>(self) -> AnyView<ParentState> {
AnyView {
view: Rc::new(RefCell::new(self)),
parent_state_type: PhantomData,
}
}
}
impl<S: 'static> Element for View<S> {
type State = ();
type FrameState = AnyElement<S>;
fn layout(
&mut self,
_: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
self.state.update(cx, |state, cx| {
let mut element = (self.render)(state, cx);
let layout_id = element.layout(state, cx)?;
Ok((layout_id, element))
})
}
fn paint(
&mut self,
layout: Layout,
_: &mut Self::State,
element: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
self.state.update(cx, |state, cx| {
element.paint(layout.bounds.origin(), state, cx)
})
}
}
trait ViewObject {
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)>;
fn paint(
&mut self,
layout: Layout,
element: &mut dyn Any,
cx: &mut WindowContext,
) -> Result<()>;
}
impl<S: 'static> ViewObject for View<S> {
fn layout(&mut self, cx: &mut WindowContext) -> Result<(LayoutId, Box<dyn Any>)> {
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 Box<dyn Any>;
Ok((layout_id, element))
})
}
fn paint(
&mut self,
layout: Layout,
element: &mut dyn Any,
cx: &mut WindowContext,
) -> Result<()> {
self.state.update(cx, |state, cx| {
element.downcast_mut::<AnyElement<S>>().unwrap().paint(
layout.bounds.origin(),
state,
cx,
)
})
}
}
pub struct AnyView<S> {
view: Rc<RefCell<dyn ViewObject>>,
parent_state_type: PhantomData<S>,
}
impl<S: 'static> Element for AnyView<S> {
type State = S;
type FrameState = Box<dyn Any>;
fn layout(
&mut self,
_: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
self.view.borrow_mut().layout(cx)
}
fn paint(
&mut self,
layout: Layout,
_: &mut Self::State,
element: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
self.view.borrow_mut().paint(layout, element, cx)
}
}
impl<S> Clone for AnyView<S> {
fn clone(&self) -> Self {
Self {
view: self.view.clone(),
parent_state_type: PhantomData,
}
}
}
pub struct Div<S>(PhantomData<S>);
impl<S: 'static> Element for Div<S> {
type State = S;
type FrameState = ();
fn layout(
&mut self,
state: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
todo!()
}
fn paint(
&mut self,
layout: Layout,
state: &mut Self::State,
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
todo!()
}
}
impl<S> ParentElement<S> for Div<S> {
fn child(self, child: impl IntoAnyElement<S>) -> Self {
todo!()
}
}
pub fn div<S>() -> Div<S> {
todo!()
}
pub struct SharedString(ArcCow<'static, str>);
impl<T: Into<ArcCow<'static, str>>> From<T> for SharedString {
fn from(value: T) -> Self {
Self(value.into())
}
}
struct Workspace {
left_panel: AnyView<Self>,
}
fn workspace(cx: &mut WindowContext) -> View<Workspace> {
let workspace = cx.entity(|cx| Workspace {
left_panel: collab_panel(cx).into_any(),
});
view(workspace, |workspace, cx| {
div().child(workspace.left_panel.clone())
})
}
struct CollabPanel {
filter_editor: Handle<Editor>,
}
fn collab_panel(cx: &mut WindowContext) -> View<CollabPanel> {
let panel = cx.entity(|cx| CollabPanel::new(cx));
view(panel, |panel, cx| {
div()
.child(div())
.child(field(panel.filter_editor.clone()).placeholder_text("Search channels, contacts"))
})
}
impl CollabPanel {
fn new(cx: &mut ViewContext<Self>) -> Self {
Self {
filter_editor: cx.entity(|cx| Editor::new(cx)),
}
}
}
fn field<S>(editor: Handle<Editor>) -> EditorElement<S> {
EditorElement {
editor,
field: true,
placeholder_text: None,
parent_state: PhantomData,
}
}
struct EditorElement<S> {
editor: Handle<Editor>,
field: bool,
placeholder_text: Option<SharedString>,
parent_state: PhantomData<S>,
}
impl<S> EditorElement<S> {
pub fn field(mut self) -> Self {
self.field = true;
self
}
pub fn placeholder_text(mut self, text: impl Into<SharedString>) -> Self {
self.placeholder_text = Some(text.into());
self
}
}
impl<S: 'static> Element for EditorElement<S> {
type State = S;
type FrameState = ();
fn layout(
&mut self,
_: &mut Self::State,
cx: &mut ViewContext<Self::State>,
) -> Result<(LayoutId, Self::FrameState)> {
self.editor.update(cx, |editor, cx| todo!())
}
fn paint(
&mut self,
layout: Layout,
state: &mut Self::State,
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
self.editor.update(cx, |editor, cx| todo!())
}
}
struct Editor {}
impl Editor {
pub fn new(_: &mut ViewContext<Self>) -> Self {
Editor {}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let mut cx = AppContext::new();
cx.open_window(|cx| workspace(cx));
}
}

View file

@ -12,7 +12,7 @@ use simplelog::SimpleLogger;
mod collab_panel;
mod components;
mod element_ext;
mod sketch;
mod gpui3;
mod theme;
mod workspace;