Detailed changes
@@ -47,8 +47,8 @@ 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,
+ offset: Option<Point<Pixels>>,
cx: &mut ViewContext<S>,
) -> Result<()>;
}
@@ -96,8 +96,8 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
fn paint(
&mut self,
- parent_origin: Point<Pixels>,
state: &mut E::State,
+ offset: Option<Point<Pixels>>,
cx: &mut ViewContext<E::State>,
) -> Result<()> {
self.phase = match std::mem::take(&mut self.phase) {
@@ -107,8 +107,8 @@ impl<E: Element> ElementObject<E::State> for RenderedElement<E> {
layout_id,
mut frame_state,
} => {
- let mut layout = cx.layout(layout_id)?;
- layout.bounds.origin += parent_origin;
+ let mut layout = cx.layout(layout_id)?.clone();
+ offset.map(|offset| layout.bounds.origin += offset);
self.element
.paint(layout.clone(), state, &mut frame_state, cx)?;
ElementRenderPhase::Painted {
@@ -143,11 +143,11 @@ impl<S> AnyElement<S> {
pub fn paint(
&mut self,
- parent_origin: Point<Pixels>,
state: &mut S,
+ offset: Option<Point<Pixels>>,
cx: &mut ViewContext<S>,
) -> Result<()> {
- self.0.paint(parent_origin, state, cx)
+ self.0.paint(state, offset, cx)
}
}
@@ -215,9 +215,8 @@ impl<S: 'static> Element for View<S> {
element: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
) -> Result<()> {
- self.state.update(cx, |state, cx| {
- element.paint(layout.bounds.origin, state, cx)
- })
+ self.state
+ .update(cx, |state, cx| element.paint(state, None, cx))
}
}
@@ -251,7 +250,7 @@ impl<S: 'static> ViewObject for View<S> {
element
.downcast_mut::<AnyElement<S>>()
.unwrap()
- .paint(layout.bounds.origin, state, cx)
+ .paint(state, None, cx)
})
}
}
@@ -67,8 +67,6 @@ impl<S: 'static> Element for Div<S> {
style.paint_background(bounds, cx);
// self.interaction_handlers().paint(order, bounds, cx);
- let scrolled_origin = bounds.origin - self.scroll_offset(&style.overflow);
-
// // TODO: Support only one dimension being hidden
// let mut pop_layer = false;
// if style.overflow.y != Overflow::Visible || style.overflow.x != Overflow::Visible {
@@ -76,8 +74,9 @@ impl<S: 'static> Element for Div<S> {
// pop_layer = true;
// }
+ let scroll_offset = self.scroll_offset(&style.overflow);
for child in &mut self.children {
- child.paint(scrolled_origin, state, cx)?;
+ child.paint(state, Some(scroll_offset), cx)?;
}
// if pop_layer {
@@ -2,7 +2,7 @@ use bytemuck::{Pod, Zeroable};
use core::fmt::Debug;
use derive_more::{Add, AddAssign, Div, Mul, Sub, SubAssign};
use refineable::Refineable;
-use std::ops::{Add, Mul, Sub, SubAssign};
+use std::ops::{Add, AddAssign, Mul, Sub, SubAssign};
#[derive(
Refineable, Default, Add, AddAssign, Sub, SubAssign, Mul, Div, Copy, Debug, PartialEq, Eq, Hash,
@@ -38,6 +38,13 @@ impl<T: Clone + Debug + Sub<Output = T>> SubAssign<Size<T>> for Point<T> {
}
}
+impl<T: Clone + Debug + Add<Output = T> + Copy> AddAssign<T> for Point<T> {
+ fn add_assign(&mut self, rhs: T) {
+ self.x = self.x.clone() + rhs;
+ self.y = self.y.clone() + rhs;
+ }
+}
+
impl<T: Clone + Debug + std::cmp::PartialOrd> Point<T> {
pub fn max(&self, other: &Self) -> Self {
Point {
@@ -15,13 +15,14 @@ mod text_system;
mod util;
mod window;
-use anyhow::Result;
+pub use anyhow::Result;
pub use app::*;
pub use color::*;
pub use element::*;
pub use elements::*;
pub use executor::*;
pub use geometry::*;
+pub use gpui3_macros::*;
pub use platform::*;
pub use refineable::*;
pub use scene::*;
@@ -996,7 +996,7 @@ extern "C" fn open_urls(this: &mut Object, _: Sel, _: id, urls: id) {
}
}
-extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) {
+extern "C" fn handle_menu_item(__this: &mut Object, _: Sel, __item: id) {
todo!()
// unsafe {
// let platform = get_foreground_platform(this);
@@ -1012,7 +1012,7 @@ extern "C" fn handle_menu_item(this: &mut Object, _: Sel, item: id) {
// }
}
-extern "C" fn validate_menu_item(this: &mut Object, _: Sel, item: id) -> bool {
+extern "C" fn validate_menu_item(__this: &mut Object, _: Sel, __item: id) -> bool {
todo!()
// unsafe {
// let mut result = false;
@@ -1378,7 +1378,7 @@ extern "C" fn set_frame_size(this: &Object, _: Sel, size: NSSize) {
};
}
-extern "C" fn display_layer(this: &Object, _: Sel, _: id) {
+extern "C" fn display_layer(_this: &Object, _: Sel, _: id) {
// unsafe {
// let window_state = get_window_state(this);
// let mut window_state = window_state.as_ref().borrow_mut();
@@ -17,7 +17,7 @@ impl Platform for TestPlatform {
todo!()
}
- fn run(&self, on_finish_launching: Box<dyn FnOnce()>) {
+ fn run(&self, _on_finish_launching: Box<dyn FnOnce()>) {
todo!()
}
@@ -29,7 +29,7 @@ impl Platform for TestPlatform {
todo!()
}
- fn activate(&self, ignoring_other_apps: bool) {
+ fn activate(&self, _ignoring_other_apps: bool) {
todo!()
}
@@ -49,7 +49,7 @@ impl Platform for TestPlatform {
todo!()
}
- fn screen_by_id(&self, id: uuid::Uuid) -> Option<std::rc::Rc<dyn crate::PlatformScreen>> {
+ fn screen_by_id(&self, _id: uuid::Uuid) -> Option<std::rc::Rc<dyn crate::PlatformScreen>> {
todo!()
}
@@ -59,55 +59,55 @@ impl Platform for TestPlatform {
fn open_window(
&self,
- handle: crate::AnyWindowHandle,
- options: crate::WindowOptions,
+ _handle: crate::AnyWindowHandle,
+ _options: crate::WindowOptions,
) -> Box<dyn crate::PlatformWindow> {
todo!()
}
- fn open_url(&self, url: &str) {
+ fn open_url(&self, _url: &str) {
todo!()
}
- fn on_open_urls(&self, callback: Box<dyn FnMut(Vec<String>)>) {
+ fn on_open_urls(&self, _callback: Box<dyn FnMut(Vec<String>)>) {
todo!()
}
fn prompt_for_paths(
&self,
- options: crate::PathPromptOptions,
+ _options: crate::PathPromptOptions,
) -> futures::channel::oneshot::Receiver<Option<Vec<std::path::PathBuf>>> {
todo!()
}
fn prompt_for_new_path(
&self,
- directory: &std::path::Path,
+ _directory: &std::path::Path,
) -> futures::channel::oneshot::Receiver<Option<std::path::PathBuf>> {
todo!()
}
- fn reveal_path(&self, path: &std::path::Path) {
+ fn reveal_path(&self, _path: &std::path::Path) {
todo!()
}
- fn on_become_active(&self, callback: Box<dyn FnMut()>) {
+ fn on_become_active(&self, _callback: Box<dyn FnMut()>) {
todo!()
}
- fn on_resign_active(&self, callback: Box<dyn FnMut()>) {
+ fn on_resign_active(&self, _callback: Box<dyn FnMut()>) {
todo!()
}
- fn on_quit(&self, callback: Box<dyn FnMut()>) {
+ fn on_quit(&self, _callback: Box<dyn FnMut()>) {
todo!()
}
- fn on_reopen(&self, callback: Box<dyn FnMut()>) {
+ fn on_reopen(&self, _callback: Box<dyn FnMut()>) {
todo!()
}
- fn on_event(&self, callback: Box<dyn FnMut(crate::Event) -> bool>) {
+ fn on_event(&self, _callback: Box<dyn FnMut(crate::Event) -> bool>) {
todo!()
}
@@ -131,11 +131,11 @@ impl Platform for TestPlatform {
todo!()
}
- fn path_for_auxiliary_executable(&self, name: &str) -> anyhow::Result<std::path::PathBuf> {
+ fn path_for_auxiliary_executable(&self, _name: &str) -> anyhow::Result<std::path::PathBuf> {
todo!()
}
- fn set_cursor_style(&self, style: crate::CursorStyle) {
+ fn set_cursor_style(&self, _style: crate::CursorStyle) {
todo!()
}
@@ -143,7 +143,7 @@ impl Platform for TestPlatform {
todo!()
}
- fn write_to_clipboard(&self, item: crate::ClipboardItem) {
+ fn write_to_clipboard(&self, _item: crate::ClipboardItem) {
todo!()
}
@@ -151,15 +151,20 @@ impl Platform for TestPlatform {
todo!()
}
- fn write_credentials(&self, url: &str, username: &str, password: &[u8]) -> anyhow::Result<()> {
+ fn write_credentials(
+ &self,
+ _url: &str,
+ _username: &str,
+ _password: &[u8],
+ ) -> anyhow::Result<()> {
todo!()
}
- fn read_credentials(&self, url: &str) -> anyhow::Result<Option<(String, Vec<u8>)>> {
+ fn read_credentials(&self, _url: &str) -> anyhow::Result<Option<(String, Vec<u8>)>> {
todo!()
}
- fn delete_credentials(&self, url: &str) -> anyhow::Result<()> {
+ fn delete_credentials(&self, _url: &str) -> anyhow::Result<()> {
todo!()
}
}
@@ -1,5 +1,5 @@
use crate::{
- self as gpui2, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, JustifyContent,
+ self as gpui3, relative, rems, AlignItems, Display, Fill, FlexDirection, Hsla, JustifyContent,
Length, Position, SharedString, Style, Styled,
};
@@ -2,29 +2,28 @@ use super::{
AbsoluteLength, Bounds, DefiniteLength, Edges, Layout, Length, Pixels, Point, Result, Size,
Style,
};
+use collections::HashMap;
use std::fmt::Debug;
-pub use taffy::tree::NodeId as LayoutId;
use taffy::{
geometry::Size as TaffySize,
style::AvailableSpace as TaffyAvailableSpace,
- tree::{Measurable, MeasureFunc},
+ tree::{Measurable, MeasureFunc, NodeId},
Taffy,
};
-pub struct TaffyLayoutEngine(Taffy);
-#[derive(Copy, Clone, Debug)]
-pub enum AvailableSpace {
- /// The amount of space available is the specified number of pixels
- Definite(Pixels),
- /// The amount of space available is indefinite and the node should be laid out under a min-content constraint
- MinContent,
- /// The amount of space available is indefinite and the node should be laid out under a max-content constraint
- MaxContent,
+pub struct TaffyLayoutEngine {
+ taffy: Taffy,
+ children_to_parents: HashMap<LayoutId, LayoutId>,
+ absolute_layouts: HashMap<LayoutId, Layout>,
}
impl TaffyLayoutEngine {
pub fn new() -> Self {
- TaffyLayoutEngine(Taffy::new())
+ TaffyLayoutEngine {
+ taffy: Taffy::new(),
+ children_to_parents: HashMap::default(),
+ absolute_layouts: HashMap::default(),
+ }
}
pub fn request_layout(
@@ -35,9 +34,17 @@ impl TaffyLayoutEngine {
) -> Result<LayoutId> {
let style = style.to_taffy(rem_size);
if children.is_empty() {
- Ok(self.0.new_leaf(style)?)
+ Ok(self.taffy.new_leaf(style)?.into())
} else {
- Ok(self.0.new_with_children(style, children)?)
+ let parent_id = self
+ .taffy
+ // This is safe because LayoutId is repr(transparent) to taffy::tree::NodeId.
+ .new_with_children(style, unsafe { std::mem::transmute(children) })?
+ .into();
+ for child_id in children {
+ self.children_to_parents.insert(*child_id, parent_id);
+ }
+ Ok(parent_id)
}
}
@@ -54,15 +61,59 @@ impl TaffyLayoutEngine {
let measurable = Box::new(Measureable(measure)) as Box<dyn Measurable>;
Ok(self
- .0
- .new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))?)
+ .taffy
+ .new_leaf_with_measure(style, MeasureFunc::Boxed(measurable))?
+ .into())
}
pub fn layout(&mut self, id: LayoutId) -> Result<Layout> {
- Ok(self.0.layout(id).map(Into::into)?)
+ if let Some(layout) = self.absolute_layouts.get(&id).cloned() {
+ return Ok(layout);
+ }
+
+ let mut relative_layout: Layout = self.taffy.layout(id.into()).map(Into::into)?;
+ if let Some(parent_id) = self.children_to_parents.get(&id).copied() {
+ let parent_layout = self.layout(parent_id)?;
+ relative_layout.bounds.origin += parent_layout.bounds.origin;
+ }
+ self.absolute_layouts.insert(id, relative_layout.clone());
+
+ Ok(relative_layout)
+ }
+}
+
+#[derive(Copy, Clone, Eq, PartialEq, Debug)]
+#[repr(transparent)]
+pub struct LayoutId(NodeId);
+
+impl std::hash::Hash for LayoutId {
+ fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
+ u64::from(self.0).hash(state);
}
}
+impl From<NodeId> for LayoutId {
+ fn from(node_id: NodeId) -> Self {
+ Self(node_id)
+ }
+}
+
+impl From<LayoutId> for NodeId {
+ fn from(layout_id: LayoutId) -> NodeId {
+ layout_id.0
+ }
+}
+
+#[derive(Copy, Clone, Debug)]
+pub enum AvailableSpace {
+ /// The amount of space available is the specified number of pixels
+ Definite(Pixels),
+ /// The amount of space available is indefinite and the node should be laid out under a min-content constraint
+ MinContent,
+ /// The amount of space available is indefinite and the node should be laid out under a max-content constraint
+ MaxContent,
+}
+
struct Measureable<F>(F);
impl<F> taffy::tree::Measurable for Measureable<F>
@@ -1,92 +1,49 @@
use proc_macro::TokenStream;
use proc_macro2::Ident;
use quote::quote;
-use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam, Generics};
-
-use crate::derive_into_element::impl_into_element;
+use syn::{parse_macro_input, parse_quote, DeriveInput, GenericParam};
pub fn derive_element(input: TokenStream) -> TokenStream {
let ast = parse_macro_input!(input as DeriveInput);
let type_name = ast.ident;
- let placeholder_view_generics: Generics = parse_quote! { <V: 'static> };
-
- let (impl_generics, type_generics, where_clause, view_type_name, lifetimes) =
- if let Some(first_type_param) = ast.generics.params.iter().find_map(|param| {
- if let GenericParam::Type(type_param) = param {
- Some(type_param.ident.clone())
- } else {
- None
- }
- }) {
- let mut lifetimes = vec![];
- for param in ast.generics.params.iter() {
- if let GenericParam::Lifetime(lifetime_def) = param {
- lifetimes.push(lifetime_def.lifetime.clone());
- }
- }
- let generics = ast.generics.split_for_impl();
- (
- generics.0,
- Some(generics.1),
- generics.2,
- first_type_param,
- lifetimes,
- )
- } else {
- let generics = placeholder_view_generics.split_for_impl();
- let placeholder_view_type_name: Ident = parse_quote! { V };
- (
- generics.0,
- None,
- generics.2,
- placeholder_view_type_name,
- vec![],
- )
- };
+ let mut state_type: Option<Ident> = None;
- let lifetimes = if !lifetimes.is_empty() {
- quote! { <#(#lifetimes),*> }
- } else {
- quote! {}
- };
+ for param in ast.generics.params.iter() {
+ if let GenericParam::Type(type_param) = param {
+ state_type = Some(type_param.ident.clone())
+ }
+ }
- let impl_into_element = impl_into_element(
- &impl_generics,
- &view_type_name,
- &type_name,
- &type_generics,
- &where_clause,
- );
+ let state_type_name = state_type.unwrap_or_else(|| parse_quote! { () });
+ let (impl_generics, ty_generics, where_clause) = ast.generics.split_for_impl();
let gen = quote! {
- impl #impl_generics gpui2::element::Element<#view_type_name> for #type_name #type_generics
+ impl #impl_generics gpui3::Element for #type_name #ty_generics
#where_clause
{
- type PaintState = gpui2::element::AnyElement<#view_type_name #lifetimes>;
+ type State = #state_type_name;
+ type FrameState = gpui3::AnyElement<#state_type_name>;
fn layout(
&mut self,
- view: &mut V,
- cx: &mut gpui2::ViewContext<V>,
- ) -> anyhow::Result<(gpui2::element::LayoutId, Self::PaintState)> {
- let mut rendered_element = self.render(view, cx).into_element().into_any();
- let layout_id = rendered_element.layout(view, cx)?;
+ state: &mut #state_type_name,
+ cx: &mut gpui3::ViewContext<V>,
+ ) -> anyhow::Result<(gpui3::LayoutId, Self::FrameState)> {
+ let mut rendered_element = self.render(state, cx).into_element().into_any();
+ let layout_id = rendered_element.layout(state, cx)?;
Ok((layout_id, rendered_element))
}
fn paint(
&mut self,
- view: &mut V,
- parent_origin: gpui2::Vector2F,
- _: &gpui2::element::Layout,
- rendered_element: &mut Self::PaintState,
- cx: &mut gpui2::ViewContext<V>,
+ layout: &gpui3::Layout,
+ state: &mut #state_type_name,
+ rendered_element: &mut Self::FrameState,
+ cx: &mut gpui3::ViewContext<V>,
) {
- rendered_element.paint(view, parent_origin, cx);
+ rendered_element.paint(layout.origin, state, cx);
}
}
-
- #impl_into_element
};
gen.into()
@@ -1,69 +0,0 @@
-use proc_macro::TokenStream;
-use quote::quote;
-use syn::{
- parse_macro_input, parse_quote, DeriveInput, GenericParam, Generics, Ident, WhereClause,
-};
-
-pub fn derive_into_element(input: TokenStream) -> TokenStream {
- let ast = parse_macro_input!(input as DeriveInput);
- let type_name = ast.ident;
-
- let placeholder_view_generics: Generics = parse_quote! { <V: 'static> };
- let placeholder_view_type_name: Ident = parse_quote! { V };
- let view_type_name: Ident;
- let impl_generics: syn::ImplGenerics<'_>;
- let type_generics: Option<syn::TypeGenerics<'_>>;
- let where_clause: Option<&'_ WhereClause>;
-
- match ast.generics.params.iter().find_map(|param| {
- if let GenericParam::Type(type_param) = param {
- Some(type_param.ident.clone())
- } else {
- None
- }
- }) {
- Some(type_name) => {
- view_type_name = type_name;
- let generics = ast.generics.split_for_impl();
- impl_generics = generics.0;
- type_generics = Some(generics.1);
- where_clause = generics.2;
- }
- _ => {
- view_type_name = placeholder_view_type_name;
- let generics = placeholder_view_generics.split_for_impl();
- impl_generics = generics.0;
- type_generics = None;
- where_clause = generics.2;
- }
- }
-
- impl_into_element(
- &impl_generics,
- &view_type_name,
- &type_name,
- &type_generics,
- &where_clause,
- )
- .into()
-}
-
-pub fn impl_into_element(
- impl_generics: &syn::ImplGenerics<'_>,
- view_type_name: &Ident,
- type_name: &Ident,
- type_generics: &Option<syn::TypeGenerics<'_>>,
- where_clause: &Option<&WhereClause>,
-) -> proc_macro2::TokenStream {
- quote! {
- impl #impl_generics gpui2::element::IntoElement<#view_type_name> for #type_name #type_generics
- #where_clause
- {
- type Element = Self;
-
- fn into_element(self) -> Self {
- self
- }
- }
- }
-}
@@ -1,7 +1,6 @@
use proc_macro::TokenStream;
mod derive_element;
-mod derive_into_element;
mod style_helpers;
#[proc_macro]
@@ -13,8 +12,3 @@ pub fn style_helpers(args: TokenStream) -> TokenStream {
pub fn derive_element(input: TokenStream) -> TokenStream {
derive_element::derive_element(input)
}
-
-#[proc_macro_derive(IntoElement, attributes(element_crate))]
-pub fn derive_into_element(input: TokenStream) -> TokenStream {
- derive_into_element::derive_into_element(input)
-}
@@ -17,15 +17,9 @@ impl Parse for StyleableMacroInput {
pub fn style_helpers(input: TokenStream) -> TokenStream {
let _ = parse_macro_input!(input as StyleableMacroInput);
let methods = generate_methods();
-
- for method in &methods {
- println!("method: {}", method);
- }
-
let output = quote! {
#(#methods)*
};
-
output.into()
}
@@ -74,7 +68,7 @@ fn generate_method(
.iter()
.map(|field_tokens| {
quote! {
- style.#field_tokens = Some(gpui2::#length_tokens.into());
+ style.#field_tokens = Some(gpui3::#length_tokens.into());
}
})
.collect::<Vec<_>>();
@@ -1,4 +1,4 @@
-use gpui3::{Element, Hsla, Layout, LayoutId, ViewContext, WindowContext};
+use gpui3::{Element, Hsla, Layout, LayoutId, Result, ViewContext, WindowContext};
use serde::{de::Visitor, Deserialize, Deserializer};
use std::{collections::HashMap, fmt};
@@ -156,13 +156,15 @@ impl<E: Element> Element for Themed<E> {
state: &mut Self::State,
frame_state: &mut Self::FrameState,
cx: &mut ViewContext<Self::State>,
- ) where
+ ) -> Result<()>
+ where
Self: Sized,
{
// todo!
// cx.push_theme(self.theme.clone());
self.child.paint(layout, state, frame_state, cx);
// cx.pop_theme();
+ Ok(())
}
}
@@ -1,7 +1,7 @@
use crate::{collab_panel::collab_panel, theme::theme};
use gpui3::{div, img, svg, Element, ParentElement, ScrollState, StyleHelpers, ViewContext};
-#[derive(Default)]
+#[derive(Element, Default)]
struct WorkspaceElement {
left_scroll_state: ScrollState,
right_scroll_state: ScrollState,