Checkpoint

This commit is contained in:
Nathan Sobo 2023-09-19 13:09:00 -06:00
parent 89519b1521
commit e762f7f3c0
21 changed files with 29 additions and 2247 deletions

25
Cargo.lock generated
View file

@ -3340,6 +3340,31 @@ dependencies = [
"syn 1.0.109",
]
[[package]]
name = "gpui3"
version = "0.1.0"
dependencies = [
"anyhow",
"bytemuck",
"derive_more",
"font-kit",
"itertools 0.11.0",
"log",
"parking_lot 0.11.2",
"plane-split",
"raw-window-handle",
"refineable",
"rust-embed",
"schemars",
"serde",
"simplelog",
"slotmap",
"smallvec",
"taffy",
"util",
"wgpu",
]
[[package]]
name = "gpui_macros"
version = "0.1.0"

View file

@ -35,6 +35,7 @@ members = [
"crates/gpui_macros",
"crates/gpui2",
"crates/gpui2_macros",
"crates/gpui3",
"crates/install_cli",
"crates/journal",
"crates/language",

View file

@ -8,6 +8,9 @@ publish = false
name = "storybook"
path = "src/storybook.rs"
[features]
test-support = []
[dependencies]
anyhow.workspace = true
bytemuck = "1.14.0"

View file

@ -1,200 +0,0 @@
use anyhow::{anyhow, Result};
use slotmap::SlotMap;
use std::{any::Any, marker::PhantomData, rc::Rc};
use super::{
platform::Platform,
window::{Window, WindowHandle, WindowId},
Context, LayoutId, Reference, View, WindowContext,
};
pub struct AppContext {
platform: Rc<dyn Platform>,
pub(crate) entities: SlotMap<EntityId, Option<Box<dyn Any>>>,
pub(crate) windows: SlotMap<WindowId, Option<Window>>,
// We recycle this memory across layout requests.
pub(crate) layout_id_buffer: Vec<LayoutId>,
}
impl AppContext {
pub fn new(platform: Rc<dyn Platform>) -> Self {
AppContext {
platform,
entities: SlotMap::with_key(),
windows: SlotMap::with_key(),
layout_id_buffer: Default::default(),
}
}
pub fn test() -> Self {
Self::new(TestPlatform::new())
}
pub fn open_window<S: 'static>(
&mut self,
build_root_view: impl FnOnce(&mut WindowContext) -> View<S>,
) -> WindowHandle<S> {
let id = self.windows.insert(None);
let mut window = Window::new(id);
let root_view = build_root_view(&mut WindowContext::mutable(self, &mut window));
window.root_view.replace(Box::new(root_view));
self.windows.get_mut(id).unwrap().replace(window);
WindowHandle::new(id)
}
pub(crate) fn update_window<R>(
&mut self,
window_id: WindowId,
update: impl FnOnce(&mut WindowContext) -> R,
) -> Result<R> {
let mut window = self
.windows
.get_mut(window_id)
.ok_or_else(|| anyhow!("window not found"))?
.take()
.unwrap();
let result = update(&mut WindowContext::mutable(self, &mut window));
self.windows
.get_mut(window_id)
.ok_or_else(|| anyhow!("window not found"))?
.replace(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 id = self.entities.insert(None);
let entity = Box::new(build_entity(&mut ModelContext::mutable(self, id)));
self.entities.get_mut(id).unwrap().replace(entity);
Handle::new(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
.get_mut(handle.id)
.unwrap()
.take()
.unwrap()
.downcast::<T>()
.unwrap();
let result = update(&mut *entity, &mut ModelContext::mutable(self, handle.id));
self.entities.get_mut(handle.id).unwrap().replace(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
.get_mut(self.entity_id)
.unwrap()
.take()
.unwrap();
let result = update(entity.downcast_mut::<T>().unwrap(), self);
self.app
.entities
.get_mut(self.entity_id)
.unwrap()
.replace(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>,
}
slotmap::new_key_type! { pub struct EntityId; }
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

@ -1,190 +0,0 @@
#![allow(dead_code)]
use bytemuck::{Pod, Zeroable};
use serde::de::{self, Deserialize, Deserializer, Visitor};
use std::fmt;
use std::num::ParseIntError;
pub fn rgb<C: From<Rgba>>(hex: u32) -> C {
let r = ((hex >> 16) & 0xFF) as f32 / 255.0;
let g = ((hex >> 8) & 0xFF) as f32 / 255.0;
let b = (hex & 0xFF) as f32 / 255.0;
Rgba { r, g, b, a: 1.0 }.into()
}
#[derive(Clone, Copy, Default, Debug)]
pub struct Rgba {
pub r: f32,
pub g: f32,
pub b: f32,
pub a: f32,
}
struct RgbaVisitor;
impl<'de> Visitor<'de> for RgbaVisitor {
type Value = Rgba;
fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result {
formatter.write_str("a string in the format #rrggbb or #rrggbbaa")
}
fn visit_str<E: de::Error>(self, value: &str) -> Result<Rgba, E> {
if value.len() == 7 || value.len() == 9 {
let r = u8::from_str_radix(&value[1..3], 16).unwrap() as f32 / 255.0;
let g = u8::from_str_radix(&value[3..5], 16).unwrap() as f32 / 255.0;
let b = u8::from_str_radix(&value[5..7], 16).unwrap() as f32 / 255.0;
let a = if value.len() == 9 {
u8::from_str_radix(&value[7..9], 16).unwrap() as f32 / 255.0
} else {
1.0
};
Ok(Rgba { r, g, b, a })
} else {
Err(E::custom(
"Bad format for RGBA. Expected #rrggbb or #rrggbbaa.",
))
}
}
}
impl<'de> Deserialize<'de> for Rgba {
fn deserialize<D: Deserializer<'de>>(deserializer: D) -> Result<Self, D::Error> {
deserializer.deserialize_str(RgbaVisitor)
}
}
impl From<Hsla> for Rgba {
fn from(color: Hsla) -> Self {
let h = color.h;
let s = color.s;
let l = color.l;
let c = (1.0 - (2.0 * l - 1.0).abs()) * s;
let x = c * (1.0 - ((h * 6.0) % 2.0 - 1.0).abs());
let m = l - c / 2.0;
let cm = c + m;
let xm = x + m;
let (r, g, b) = match (h * 6.0).floor() as i32 {
0 | 6 => (cm, xm, m),
1 => (xm, cm, m),
2 => (m, cm, xm),
3 => (m, xm, cm),
4 => (xm, m, cm),
_ => (cm, m, xm),
};
Rgba {
r,
g,
b,
a: color.a,
}
}
}
impl TryFrom<&'_ str> for Rgba {
type Error = ParseIntError;
fn try_from(value: &'_ str) -> Result<Self, Self::Error> {
let r = u8::from_str_radix(&value[1..3], 16)? as f32 / 255.0;
let g = u8::from_str_radix(&value[3..5], 16)? as f32 / 255.0;
let b = u8::from_str_radix(&value[5..7], 16)? as f32 / 255.0;
let a = if value.len() > 7 {
u8::from_str_radix(&value[7..9], 16)? as f32 / 255.0
} else {
1.0
};
Ok(Rgba { r, g, b, a })
}
}
#[derive(Default, Copy, Clone, Debug, PartialEq)]
#[repr(C)]
pub struct Hsla {
pub h: f32,
pub s: f32,
pub l: f32,
pub a: f32,
}
unsafe impl Zeroable for Hsla {}
unsafe impl Pod for Hsla {}
pub fn hsla(h: f32, s: f32, l: f32, a: f32) -> Hsla {
Hsla {
h: h.clamp(0., 1.),
s: s.clamp(0., 1.),
l: l.clamp(0., 1.),
a: a.clamp(0., 1.),
}
}
pub fn black() -> Hsla {
Hsla {
h: 0.,
s: 0.,
l: 0.,
a: 1.,
}
}
impl Hsla {
/// Returns true if the HSLA color is fully transparent, false otherwise.
pub fn is_transparent(&self) -> bool {
self.a == 0.0
}
}
impl From<Rgba> for Hsla {
fn from(color: Rgba) -> Self {
let r = color.r;
let g = color.g;
let b = color.b;
let max = r.max(g.max(b));
let min = r.min(g.min(b));
let delta = max - min;
let l = (max + min) / 2.0;
let s = if l == 0.0 || l == 1.0 {
0.0
} else if l < 0.5 {
delta / (2.0 * l)
} else {
delta / (2.0 - 2.0 * l)
};
let h = if delta == 0.0 {
0.0
} else if max == r {
((g - b) / delta).rem_euclid(6.0) / 6.0
} else if max == g {
((b - r) / delta + 2.0) / 6.0
} else {
((r - g) / delta + 4.0) / 6.0
};
Hsla {
h,
s,
l,
a: color.a,
}
}
}
impl<'de> Deserialize<'de> for Hsla {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
// First, deserialize it into Rgba
let rgba = Rgba::deserialize(deserializer)?;
// Then, use the From<Rgba> for Hsla implementation to convert it
Ok(Hsla::from(rgba))
}
}

View file

@ -1,275 +0,0 @@
use super::{Handle, Layout, LayoutId, Pixels, Point, Result, ViewContext, WindowContext};
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

@ -1,8 +0,0 @@
pub mod div;
pub mod editor;
use super::*;
use std::marker::PhantomData;
pub use div::div;
pub use editor::field;

View file

@ -1,38 +0,0 @@
use super::{
Element, IntoAnyElement, Layout, LayoutId, ParentElement, PhantomData, Result, ViewContext,
};
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!()
}

View file

@ -1,61 +0,0 @@
use super::{Element, Handle, Layout, LayoutId, Result, SharedString, ViewContext};
use std::marker::PhantomData;
pub fn field<S>(editor: Handle<Editor>) -> EditorElement<S> {
EditorElement {
editor,
field: true,
placeholder_text: None,
parent_state: PhantomData,
}
}
pub 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!())
}
}
pub struct Editor {}
impl Editor {
pub fn new(_: &mut ViewContext<Self>) -> Self {
Editor {}
}
}

View file

@ -1,325 +0,0 @@
use bytemuck::{Pod, Zeroable};
use core::fmt::Debug;
use derive_more::{Add, AddAssign, Div, Mul, Sub};
use refineable::Refineable;
use std::ops::Mul;
#[derive(Refineable, Default, Add, AddAssign, Sub, Mul, Div, Copy, Debug, PartialEq, Eq, Hash)]
#[refineable(debug)]
#[repr(C)]
pub struct Point<T: Clone + Debug> {
pub x: T,
pub y: T,
}
impl<T: Clone + Debug> Point<T> {
pub fn new(x: T, y: T) -> Self {
Self { x, y }
}
}
impl<T: Clone + Debug> Clone for Point<T> {
fn clone(&self) -> Self {
Self {
x: self.x.clone(),
y: self.y.clone(),
}
}
}
unsafe impl<T: Clone + Debug + Zeroable + Pod> Zeroable for Point<T> {}
unsafe impl<T: Clone + Debug + Zeroable + Pod> Pod for Point<T> {}
#[derive(Refineable, Default, Clone, Copy, Debug, PartialEq)]
#[refineable(debug)]
pub struct Size<T: Clone + Debug> {
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(Refineable, Clone, Default, Debug, PartialEq)]
#[refineable(debug)]
pub struct Bounds<T: Clone + Debug> {
pub origin: Point<T>,
pub size: Size<T>,
}
impl<T: Clone + Debug + Copy> Copy for Bounds<T> {}
#[derive(Refineable, Clone, Default, Debug)]
#[refineable(debug)]
pub struct Edges<T: Clone + Debug> {
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)]
#[repr(transparent)]
pub struct Pixels(pub(crate) f32);
unsafe impl bytemuck::Pod for Pixels {}
unsafe impl bytemuck::Zeroable for Pixels {}
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

@ -1,101 +0,0 @@
mod app;
mod color;
mod element;
mod elements;
mod geometry;
mod platform;
mod renderer;
mod scene;
mod style;
mod taffy;
mod window;
use self::editor::Editor;
use anyhow::Result;
pub use app::*;
pub use color::*;
pub use element::*;
pub use elements::*;
pub use geometry::*;
pub use gpui2::ArcCow;
use gpui2::Reference;
pub use scene::*;
pub use style::*;
pub use taffy::LayoutId;
use taffy::TaffyLayoutEngine;
pub use window::*;
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;
}
#[derive(Clone, Eq, PartialEq)]
pub struct SharedString(ArcCow<'static, str>);
impl std::fmt::Debug for SharedString {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.0.fmt(f)
}
}
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::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)),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test() {
let mut cx = AppContext::new();
cx.open_window(|cx| workspace(cx));
}
}

View file

@ -1,58 +0,0 @@
mod test;
use super::{AnyWindowHandle, Bounds, Point};
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
pub trait Platform {
fn open_window(
&self,
handle: AnyWindowHandle,
options: WindowOptions,
) -> Box<dyn PlatformWindow>;
}
pub trait PlatformWindow: HasRawWindowHandle + HasRawDisplayHandle {}
#[derive(Debug)]
pub struct WindowOptions<'a> {
pub bounds: WindowBounds,
pub titlebar: Option<TitlebarOptions<'a>>,
pub center: bool,
pub focus: bool,
pub show: bool,
pub kind: WindowKind,
pub is_movable: bool,
}
#[derive(Debug, Default)]
pub struct TitlebarOptions<'a> {
pub title: Option<&'a str>,
pub appears_transparent: bool,
pub traffic_light_position: Option<Point<f32>>,
}
#[derive(Copy, Clone, Debug)]
pub enum Appearance {
Light,
VibrantLight,
Dark,
VibrantDark,
}
impl Default for Appearance {
fn default() -> Self {
Self::Light
}
}
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum WindowKind {
Normal,
PopUp,
}
#[derive(Copy, Clone, Debug, PartialEq)]
pub enum WindowBounds {
Fullscreen,
Maximized,
Fixed(Bounds<f32>),
}

View file

@ -1,164 +0,0 @@
use raw_window_handle::{HasRawDisplayHandle, HasRawWindowHandle};
use super::{Scene, Size};
pub struct Renderer {
device: wgpu::Device,
queue: wgpu::Queue,
surface: wgpu::Surface,
surface_config: wgpu::SurfaceConfiguration,
pipeline: wgpu::RenderPipeline,
vertex_buffer: wgpu::Buffer,
vertex_count: u32,
}
pub trait Window: HasRawWindowHandle + HasRawDisplayHandle {
fn inner_size(&self) -> Size<u32>;
}
impl Renderer {
pub async fn new<W>(window: &W) -> Self
where
W: Window,
{
let instance = wgpu::Instance::new(Default::default());
let surface = unsafe { instance.create_surface(window).unwrap() };
let adapter = instance
.request_adapter(&wgpu::RequestAdapterOptions::default())
.await
.unwrap();
let (device, queue) = adapter
.request_device(&wgpu::DeviceDescriptor::default(), None)
.await
.unwrap();
let surface_config = wgpu::SurfaceConfiguration {
usage: wgpu::TextureUsages::RENDER_ATTACHMENT,
format: wgpu::TextureFormat::Bgra8UnormSrgb,
width: window.inner_size().width,
height: window.inner_size().height,
// "FIFO" mode renders frames in queue synced with the display's refresh rate.
// Avoids screen tearing but may not offer the lowest latency. Ideal when image
// quality takes priority over input latency.
present_mode: wgpu::PresentMode::Fifo,
// Use the Premultiplied alpha mode. With premultiplication, the color components
// are multiplied by the alpha value before storage or blending, meaning calculations
// with colors already factor in the influence of alpha. This typically results
// in better performance and avoids a separate multiplication operation during blending.
alpha_mode: wgpu::CompositeAlphaMode::PreMultiplied,
// Specify the color formats for the views the surface can have.
// In this case, the format is BGRA (blue, green, red, alpha) with unsigned
// normalised integers in the 8-bit range and the color space is sRGB (standard RGB).
// sRGB is the standard color space for displaying images and video on digital displays,
// as it optimises color accuracy and consistency.
view_formats: vec![wgpu::TextureFormat::Bgra8UnormSrgb],
};
surface.configure(&device, &surface_config);
let vs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Vertex Shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shader.vert.wgsl").into()),
});
let fs_module = device.create_shader_module(wgpu::ShaderModuleDescriptor {
label: Some("Fragment Shader"),
source: wgpu::ShaderSource::Wgsl(include_str!("shader.frag.wgsl").into()),
});
let pipeline_layout = device.create_pipeline_layout(&wgpu::PipelineLayoutDescriptor {
label: Some("Render Pipeline Layout"),
bind_group_layouts: &[],
push_constant_ranges: &[],
});
let vertex_buffer = device.create_buffer(&wgpu::BufferDescriptor {
label: Some("Vertex Buffer"),
size: 0,
usage: wgpu::BufferUsages::VERTEX,
mapped_at_creation: false,
});
let pipeline = device.create_render_pipeline(&wgpu::RenderPipelineDescriptor {
label: Some("Render Pipeline"),
layout: Some(&pipeline_layout),
vertex: wgpu::VertexState {
module: &vs_module,
entry_point: "main",
buffers: &[],
},
fragment: Some(wgpu::FragmentState {
module: &fs_module,
entry_point: "main",
targets: &[Some(wgpu::ColorTargetState {
format: surface_config.format,
blend: Some(wgpu::BlendState::REPLACE),
write_mask: wgpu::ColorWrites::ALL,
})],
}),
primitive: wgpu::PrimitiveState {
topology: wgpu::PrimitiveTopology::TriangleStrip,
..Default::default()
},
depth_stencil: None,
multisample: wgpu::MultisampleState::default(),
multiview: None,
});
Self {
device,
queue,
surface,
surface_config,
pipeline,
vertex_buffer,
vertex_count: 0,
}
}
pub fn render(&mut self, scene: &Scene) {
let frame = self.surface.get_current_texture().unwrap();
let view = frame
.texture
.create_view(&wgpu::TextureViewDescriptor::default());
self.queue.write_buffer(
&self.vertex_buffer,
0,
bytemuck::cast_slice(&scene.opaque_primitives().quads),
);
self.vertex_count = scene.opaque_primitives().quads.len() as u32;
let mut encoder = self
.device
.create_command_encoder(&wgpu::CommandEncoderDescriptor {
label: Some("Render Encoder"),
});
{
let mut render_pass = encoder.begin_render_pass(&wgpu::RenderPassDescriptor {
label: Some("Render Pass"),
color_attachments: &[Some(wgpu::RenderPassColorAttachment {
view: &view,
resolve_target: None,
ops: wgpu::Operations {
load: wgpu::LoadOp::Clear(wgpu::Color::BLACK),
store: true,
},
})],
depth_stencil_attachment: None,
});
render_pass.set_pipeline(&self.pipeline);
render_pass.set_vertex_buffer(0, self.vertex_buffer.slice(..));
render_pass.draw(0..self.vertex_count, 0..1);
}
self.queue.submit(std::iter::once(encoder.finish()));
}
}

View file

@ -1,111 +0,0 @@
use super::{Bounds, Hsla, Pixels, Point};
use bytemuck::{Pod, Zeroable};
use plane_split::BspSplitter;
pub struct Scene {
opaque_primitives: PrimitiveBatch,
transparent_primitives: slotmap::SlotMap<slotmap::DefaultKey, Primitive>,
splitter: BspSplitter<slotmap::DefaultKey>,
}
impl Scene {
pub fn new() -> Scene {
Scene {
opaque_primitives: PrimitiveBatch::default(),
transparent_primitives: slotmap::SlotMap::new(),
splitter: BspSplitter::new(),
}
}
pub fn insert(&mut self, primitive: impl Into<Primitive>, is_transparent: bool) {
if is_transparent {
self.transparent_primitives.insert(primitive.into());
} else {
match primitive.into() {
Primitive::Quad(quad) => self.opaque_primitives.quads.push(quad),
Primitive::Glyph(glyph) => self.opaque_primitives.glyphs.push(glyph),
}
}
}
pub fn opaque_primitives(&self) -> &PrimitiveBatch {
&self.opaque_primitives
}
}
#[derive(Clone, Debug)]
pub enum Primitive {
Quad(Quad),
Glyph(Glyph),
}
impl Primitive {
pub fn is_transparent(&self) -> bool {
match self {
Primitive::Quad(quad) => {
quad.background.is_transparent() && quad.border_color.is_transparent()
}
Primitive::Glyph(glyph) => glyph.color.is_transparent(),
}
}
}
#[derive(Default)]
pub struct PrimitiveBatch {
pub quads: Vec<Quad>,
pub glyphs: Vec<Glyph>,
}
#[derive(Debug, Clone, Copy)]
#[repr(C)]
pub struct Quad {
pub order: f32,
pub bounds: Bounds<Pixels>,
pub background: Hsla,
pub border_color: Hsla,
pub corner_radius: Pixels,
pub border_left: Pixels,
pub border_right: Pixels,
pub border_top: Pixels,
pub border_bottom: Pixels,
}
impl Quad {
pub fn vertices(&self) -> impl Iterator<Item = Point<Pixels>> {
let x1 = self.bounds.origin.x;
let y1 = self.bounds.origin.y;
let x2 = x1 + self.bounds.size.width;
let y2 = y1 + self.bounds.size.height;
[
Point::new(x1, y1),
Point::new(x2, y1),
Point::new(x2, y2),
Point::new(x1, y2),
]
.into_iter()
}
}
unsafe impl Zeroable for Quad {}
unsafe impl Pod for Quad {}
#[derive(Debug, Clone)]
pub struct Glyph {
pub order: f32,
pub bounds: Bounds<Pixels>,
pub color: Hsla,
// ...
}
impl From<Quad> for Primitive {
fn from(quad: Quad) -> Self {
Primitive::Quad(quad)
}
}
impl From<Glyph> for Primitive {
fn from(glyph: Glyph) -> Self {
Primitive::Glyph(glyph)
}
}

View file

@ -1,245 +0,0 @@
use refineable::Refineable;
pub use super::taffy::style::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
Overflow, Position,
};
use super::{
rems, AbsoluteLength, Bounds, DefiniteLength, Edges, EdgesRefinement, Hsla, Length, Pixels,
Point, PointRefinement, Rems, SharedString, Size, SizeRefinement, ViewContext, WindowContext,
};
pub use gpui2::style::{FontStyle, FontWeight};
#[derive(Clone, Debug)]
pub struct FontSize(f32);
#[derive(Clone, Refineable, Debug)]
#[refineable(debug)]
pub struct Style {
/// What layout strategy should be used?
pub display: Display,
// Overflow properties
/// How children overflowing their container should affect layout
#[refineable]
pub overflow: Point<Overflow>,
/// How much space (in points) should be reserved for the scrollbars of `Overflow::Scroll` and `Overflow::Auto` nodes.
pub scrollbar_width: f32,
// Position properties
/// What should the `position` value of this struct use as a base offset?
pub position: Position,
/// How should the position of this element be tweaked relative to the layout defined?
#[refineable]
pub inset: Edges<Length>,
// Size properies
/// Sets the initial size of the item
#[refineable]
pub size: Size<Length>,
/// Controls the minimum size of the item
#[refineable]
pub min_size: Size<Length>,
/// Controls the maximum size of the item
#[refineable]
pub max_size: Size<Length>,
/// Sets the preferred aspect ratio for the item. The ratio is calculated as width divided by height.
pub aspect_ratio: Option<f32>,
// Spacing Properties
/// How large should the margin be on each side?
#[refineable]
pub margin: Edges<Length>,
/// How large should the padding be on each side?
#[refineable]
pub padding: Edges<DefiniteLength>,
/// How large should the border be on each side?
#[refineable]
pub border_widths: Edges<AbsoluteLength>,
// Alignment properties
/// How this node's children aligned in the cross/block axis?
pub align_items: Option<AlignItems>,
/// How this node should be aligned in the cross/block axis. Falls back to the parents [`AlignItems`] if not set
pub align_self: Option<AlignSelf>,
/// How should content contained within this item be aligned in the cross/block axis
pub align_content: Option<AlignContent>,
/// How should contained within this item be aligned in the main/inline axis
pub justify_content: Option<JustifyContent>,
/// How large should the gaps between items in a flex container be?
#[refineable]
pub gap: Size<DefiniteLength>,
// Flexbox properies
/// Which direction does the main axis flow in?
pub flex_direction: FlexDirection,
/// Should elements wrap, or stay in a single line?
pub flex_wrap: FlexWrap,
/// Sets the initial main axis size of the item
pub flex_basis: Length,
/// The relative rate at which this item grows when it is expanding to fill space, 0.0 is the default value, and this value must be positive.
pub flex_grow: f32,
/// The relative rate at which this item shrinks when it is contracting to fit into space, 1.0 is the default value, and this value must be positive.
pub flex_shrink: f32,
/// The fill color of this element
pub fill: Option<Fill>,
/// The border color of this element
pub border_color: Option<Hsla>,
/// The radius of the corners of this element
#[refineable]
pub corner_radii: CornerRadii,
/// The color of text within this element. Cascades to children unless overridden.
pub text_color: Option<Hsla>,
/// The font size in rems.
pub font_size: Option<Rems>,
pub font_family: Option<SharedString>,
pub font_weight: Option<FontWeight>,
pub font_style: Option<FontStyle>,
}
#[derive(Refineable, Clone, Debug)]
#[refineable(debug)]
pub struct TextStyle {
pub color: Hsla,
pub font_family: SharedString,
pub font_size: Rems,
pub font_weight: FontWeight,
pub font_style: FontStyle,
pub underline: Underline,
}
#[derive(Refineable, Clone, Default, Debug)]
#[refineable(debug)]
pub struct Underline {
pub origin: Point<Pixels>,
pub width: Pixels,
pub thickness: Pixels,
pub color: Hsla,
pub squiggly: bool,
}
impl Style {
pub fn text_style(&self, cx: &WindowContext) -> Option<TextStyleRefinement> {
if self.text_color.is_none()
&& self.font_size.is_none()
&& self.font_family.is_none()
&& self.font_weight.is_none()
&& self.font_style.is_none()
{
return None;
}
Some(TextStyleRefinement {
color: self.text_color,
font_family: self.font_family.clone(),
font_size: self.font_size,
font_weight: self.font_weight,
font_style: self.font_style,
underline: None,
})
}
/// Paints the background of an element styled with this style.
pub fn paint_background<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
let rem_size = cx.rem_size();
if let Some(color) = self.fill.as_ref().and_then(Fill::color) {
todo!();
}
}
/// Paints the foreground of an element styled with this style.
pub fn paint_foreground<V: 'static>(&self, bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) {
let rem_size = cx.rem_size();
if let Some(color) = self.border_color {
let border = self.border_widths.to_pixels(rem_size);
if !border.is_empty() {
todo!();
}
}
}
}
impl Default for Style {
fn default() -> Self {
Style {
display: Display::Block,
overflow: Point {
x: Overflow::Visible,
y: Overflow::Visible,
},
scrollbar_width: 0.0,
position: Position::Relative,
inset: Edges::auto(),
margin: Edges::<Length>::zero(),
padding: Edges::<DefiniteLength>::zero(),
border_widths: Edges::<AbsoluteLength>::zero(),
size: Size::auto(),
min_size: Size::auto(),
max_size: Size::auto(),
aspect_ratio: None,
gap: Size::zero(),
// Aligment
align_items: None,
align_self: None,
align_content: None,
justify_content: None,
// Flexbox
flex_direction: FlexDirection::Row,
flex_wrap: FlexWrap::NoWrap,
flex_grow: 0.0,
flex_shrink: 1.0,
flex_basis: Length::Auto,
fill: None,
border_color: None,
corner_radii: CornerRadii::default(),
text_color: None,
font_size: Some(rems(1.)),
font_family: None,
font_weight: None,
font_style: None,
}
}
}
#[derive(Clone, Debug)]
pub enum Fill {
Color(Hsla),
}
impl Fill {
pub fn color(&self) -> Option<Hsla> {
match self {
Fill::Color(color) => Some(*color),
}
}
}
impl Default for Fill {
fn default() -> Self {
Self::Color(Hsla::default())
}
}
impl From<Hsla> for Fill {
fn from(color: Hsla) -> Self {
Self::Color(color)
}
}
#[derive(Clone, Refineable, Default, Debug)]
#[refineable(debug)]
pub struct CornerRadii {
top_left: AbsoluteLength,
top_right: AbsoluteLength,
bottom_left: AbsoluteLength,
bottom_right: AbsoluteLength,
}

View file

@ -1,238 +0,0 @@
use super::{
AbsoluteLength, Bounds, DefiniteLength, Edges, Layout, Length, Pixels, Point, Result, Size,
Style,
};
use gpui2::taffy::{self, Taffy};
use std::fmt::Debug;
pub use taffy::*;
pub use gpui2::taffy::tree::NodeId as LayoutId;
pub struct TaffyLayoutEngine(Taffy);
impl TaffyLayoutEngine {
pub fn new() -> Self {
TaffyLayoutEngine(Taffy::new())
}
pub fn request_layout(
&mut self,
style: Style,
rem_size: Pixels,
children: &[LayoutId],
) -> Result<LayoutId> {
let style = style.to_taffy(rem_size);
if children.is_empty() {
Ok(self.0.new_leaf(style)?)
} else {
Ok(self.0.new_with_children(style, children)?)
}
}
pub fn layout(&mut self, id: LayoutId) -> Result<Layout> {
Ok(self.0.layout(id).map(Into::into)?)
}
}
trait ToTaffy<Output> {
fn to_taffy(&self, rem_size: Pixels) -> Output;
}
impl ToTaffy<taffy::style::Style> for Style {
fn to_taffy(&self, rem_size: Pixels) -> taffy::style::Style {
taffy::style::Style {
display: self.display,
overflow: self.overflow.clone().into(),
scrollbar_width: self.scrollbar_width,
position: self.position,
inset: self.inset.to_taffy(rem_size),
size: self.size.to_taffy(rem_size),
min_size: self.min_size.to_taffy(rem_size),
max_size: self.max_size.to_taffy(rem_size),
aspect_ratio: self.aspect_ratio,
margin: self.margin.to_taffy(rem_size),
padding: self.padding.to_taffy(rem_size),
border: self.border_widths.to_taffy(rem_size),
align_items: self.align_items,
align_self: self.align_self,
align_content: self.align_content,
justify_content: self.justify_content,
gap: self.gap.to_taffy(rem_size),
flex_direction: self.flex_direction,
flex_wrap: self.flex_wrap,
flex_basis: self.flex_basis.to_taffy(rem_size),
flex_grow: self.flex_grow,
flex_shrink: self.flex_shrink,
..Default::default() // Ignore grid properties for now
}
}
}
// 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<taffy::style::LengthPercentageAuto> for Length {
fn to_taffy(&self, rem_size: Pixels) -> taffy::prelude::LengthPercentageAuto {
match self {
Length::Definite(length) => length.to_taffy(rem_size),
Length::Auto => taffy::prelude::LengthPercentageAuto::Auto,
}
}
}
impl ToTaffy<taffy::style::Dimension> for Length {
fn to_taffy(&self, rem_size: Pixels) -> taffy::prelude::Dimension {
match self {
Length::Definite(length) => length.to_taffy(rem_size),
Length::Auto => taffy::prelude::Dimension::Auto,
}
}
}
impl ToTaffy<taffy::style::LengthPercentage> for DefiniteLength {
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<taffy::style::LengthPercentageAuto> for DefiniteLength {
fn to_taffy(&self, rem_size: Pixels) -> taffy::style::LengthPercentageAuto {
match self {
DefiniteLength::Absolute(length) => match length {
AbsoluteLength::Pixels(pixels) => {
taffy::style::LengthPercentageAuto::Length(pixels.into())
}
AbsoluteLength::Rems(rems) => {
taffy::style::LengthPercentageAuto::Length((*rems * rem_size).into())
}
},
DefiniteLength::Fraction(fraction) => {
taffy::style::LengthPercentageAuto::Percent(*fraction)
}
}
}
}
impl ToTaffy<taffy::style::Dimension> for DefiniteLength {
fn to_taffy(&self, rem_size: Pixels) -> taffy::style::Dimension {
match self {
DefiniteLength::Absolute(length) => match length {
AbsoluteLength::Pixels(pixels) => taffy::style::Dimension::Length(pixels.into()),
AbsoluteLength::Rems(rems) => {
taffy::style::Dimension::Length((*rems * rem_size).into())
}
},
DefiniteLength::Fraction(fraction) => taffy::style::Dimension::Percent(*fraction),
}
}
}
impl ToTaffy<taffy::style::LengthPercentage> for AbsoluteLength {
fn to_taffy(&self, rem_size: Pixels) -> taffy::style::LengthPercentage {
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: Clone + Debug> 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: Clone + Debug, 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<U> + Clone + Debug, U> ToTaffy<taffy::geometry::Size<U>> for Size<T> {
fn to_taffy(&self, rem_size: Pixels) -> taffy::geometry::Size<U> {
taffy::geometry::Size {
width: self.width.to_taffy(rem_size).into(),
height: self.height.to_taffy(rem_size).into(),
}
}
}
impl<T, U> ToTaffy<taffy::geometry::Rect<U>> for Edges<T>
where
T: ToTaffy<U> + Clone + Debug,
{
fn to_taffy(&self, rem_size: Pixels) -> taffy::geometry::Rect<U> {
taffy::geometry::Rect {
top: self.top.to_taffy(rem_size).into(),
right: self.right.to_taffy(rem_size).into(),
bottom: self.bottom.to_taffy(rem_size).into(),
left: self.left.to_taffy(rem_size).into(),
}
}
}
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 {
Pixels(pixels)
}
}

View file

@ -1,231 +0,0 @@
use super::{
px, taffy::LayoutId, AppContext, Bounds, Context, EntityId, Handle, Pixels, Style,
TaffyLayoutEngine,
};
use anyhow::Result;
use derive_more::{Deref, DerefMut};
use gpui2::Reference;
use std::{
any::{Any, TypeId},
marker::PhantomData,
};
pub struct AnyWindow {}
pub struct Window {
id: WindowId,
rem_size: Pixels,
layout_engine: TaffyLayoutEngine,
pub(crate) root_view: Option<Box<dyn Any>>,
}
impl Window {
pub fn new(id: WindowId) -> Window {
Window {
id,
layout_engine: TaffyLayoutEngine::new(),
rem_size: px(16.),
root_view: None,
}
}
}
#[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.layout_id_buffer.clear();
self.app.layout_id_buffer.extend(children.into_iter());
let rem_size = self.rem_size();
self.window
.layout_engine
.request_layout(style, rem_size, &self.app.layout_id_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 = self.entities.insert(None);
let entity = Box::new(build_entity(&mut ViewContext::mutable(
&mut *self.app,
&mut self.window,
id,
)));
self.entities.get_mut(id).unwrap().replace(entity);
Handle {
id,
entity_type: PhantomData,
}
}
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
.get_mut(handle.id)
.unwrap()
.take()
.unwrap()
.downcast::<T>()
.unwrap();
let result = update(
&mut *entity,
&mut ViewContext::mutable(&mut *self.app, &mut *self.window, handle.id),
);
self.app
.entities
.get_mut(handle.id)
.unwrap()
.replace(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 {
// self.window_cx.update_entity(handle, update)
// 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)]
slotmap::new_key_type! { pub struct WindowId; }
pub struct WindowHandle<S> {
id: WindowId,
state_type: PhantomData<S>,
}
impl<S> WindowHandle<S> {
pub fn new(id: WindowId) -> Self {
WindowHandle {
id,
state_type: PhantomData,
}
}
}
pub struct AnyWindowHandle {
id: WindowId,
state_type: TypeId,
}
#[derive(Clone)]
pub struct Layout {
pub order: u32,
pub bounds: Bounds<Pixels>,
}

View file

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