This commit is contained in:
Nathan Sobo
2023-09-21 12:18:09 -06:00
parent dfeb702544
commit 8573c6e8c6
15 changed files with 147 additions and 207 deletions
+9 -10
View File
@@ -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)
})
}
}
+2 -3
View File
@@ -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 {
+8 -1
View File
@@ -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 {
+2 -1
View File
@@ -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::*;
+2 -2
View File
@@ -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;
+1 -1
View File
@@ -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();
+26 -21
View File
@@ -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 -1
View File
@@ -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,
};
+68 -17
View File
@@ -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>
+22 -65
View File
@@ -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 mut state_type: Option<Ident> = None;
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![],
)
};
for param in ast.generics.params.iter() {
if let GenericParam::Type(type_param) = param {
state_type = Some(type_param.ident.clone())
}
}
let lifetimes = if !lifetimes.is_empty() {
quote! { <#(#lifetimes),*> }
} else {
quote! {}
};
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
}
}
}
}
-6
View File
@@ -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)
}
+1 -7
View File
@@ -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<_>>();
+4 -2
View File
@@ -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 -1
View File
@@ -1,7 +1,7 @@
use crate::{collab_panel::collab_panel, theme::theme};
use gpui3::{div, img, svg, Element, ParentElement, ScrollState, StyleHelpers, ViewContext};
#[derive(Default)]
#[derive(Element, Default)]
struct WorkspaceElement {
left_scroll_state: ScrollState,
right_scroll_state: ScrollState,