Detailed changes
@@ -1,6 +1,6 @@
use crate::{
+ div,
element::{Element, ElementMetadata},
- frame,
text::ArcCow,
themes::rose_pine,
};
@@ -82,8 +82,9 @@ pub fn button<V>() -> Button<V, ()> {
impl<V: 'static, D: 'static> Button<V, D> {
fn render(&mut self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> {
// TODO: Drive theme from the context
- let button = frame()
+ let button = div()
.fill(rose_pine::dawn().error(0.5))
+ // .hover_fill(rose_pine::dawn().error(0.6))
.h_4()
.children(self.label.clone());
@@ -1,8 +1,5 @@
-use crate::{
- element::{
- AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId, PaintContext,
- },
- style::ElementStyle,
+use crate::element::{
+ AnyElement, Element, ElementMetadata, IntoElement, Layout, LayoutContext, NodeId, PaintContext,
};
use anyhow::{anyhow, Result};
use gpui::LayoutNodeId;
@@ -10,29 +7,23 @@ use playground_macros::IntoElement;
#[derive(IntoElement)]
#[element_crate = "crate"]
-pub struct Frame<V: 'static> {
- style: ElementStyle,
- handlers: Vec<EventHandler<V>>,
+pub struct Div<V: 'static> {
+ metadata: ElementMetadata<V>,
children: Vec<AnyElement<V>>,
}
-pub fn frame<V>() -> Frame<V> {
- Frame {
- style: ElementStyle::default(),
- handlers: Vec::new(),
+pub fn div<V>() -> Div<V> {
+ Div {
+ metadata: ElementMetadata::default(),
children: Vec::new(),
}
}
-impl<V: 'static> Element<V> for Frame<V> {
+impl<V: 'static> Element<V> for Div<V> {
type Layout = ();
- fn style_mut(&mut self) -> &mut ElementStyle {
- &mut self.style
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- &mut self.handlers
+ fn metadata(&mut self) -> &mut ElementMetadata<V> {
+ &mut self.metadata
}
fn layout(
@@ -50,7 +41,10 @@ impl<V: 'static> Element<V> for Frame<V> {
let node_id = cx
.layout_engine()
.ok_or_else(|| anyhow!("no layout engine"))?
- .add_node(self.style.to_taffy(rem_size), child_layout_node_ids)?;
+ .add_node(
+ self.metadata.style.to_taffy(rem_size),
+ child_layout_node_ids,
+ )?;
Ok((node_id, ()))
}
@@ -58,7 +52,7 @@ impl<V: 'static> Element<V> for Frame<V> {
fn paint(&mut self, layout: Layout<()>, view: &mut V, cx: &mut PaintContext<V>) -> Result<()> {
cx.scene.push_quad(gpui::scene::Quad {
bounds: layout.from_engine.bounds,
- background: self.style.fill.color().map(Into::into),
+ background: self.metadata.style.fill.color().map(Into::into),
border: Default::default(),
corner_radii: Default::default(),
});
@@ -70,7 +64,7 @@ impl<V: 'static> Element<V> for Frame<V> {
}
}
-impl<V: 'static> Frame<V> {
+impl<V: 'static> Div<V> {
pub fn child(mut self, child: impl IntoElement<V>) -> Self {
self.children.push(child.into_any_element());
self
@@ -1,7 +1,7 @@
use crate::{
adapter::Adapter,
color::Hsla,
- style::{Display, ElementStyle, Fill, Overflow, Position},
+ style::{Display, ElementStyle, ElementStyleOverrides, Fill, Overflow, Position},
};
use anyhow::Result;
pub use gpui::LayoutContext;
@@ -27,6 +27,7 @@ pub struct Layout<'a, E: ?Sized> {
pub struct ElementMetadata<V> {
pub style: ElementStyle,
+ pub hover_style: ElementStyleOverrides,
pub handlers: Vec<EventHandler<V>>,
}
@@ -50,6 +51,7 @@ impl<V> Default for ElementMetadata<V> {
fn default() -> Self {
Self {
style: ElementStyle::default(),
+ hover_style: ElementStyleOverrides::default(),
handlers: Vec::new(),
}
}
@@ -58,8 +60,7 @@ impl<V> Default for ElementMetadata<V> {
pub trait Element<V: 'static>: 'static {
type Layout: 'static;
- fn style_mut(&mut self) -> &mut ElementStyle;
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
+ fn metadata(&mut self) -> &mut ElementMetadata<V>;
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
-> Result<(NodeId, Self::Layout)>;
@@ -126,7 +127,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.handlers_mut().push(EventHandler {
+ self.metadata().handlers.push(EventHandler {
handler: Rc::new(move |view, event, event_cx| {
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
if event.button == button && event.is_down {
@@ -147,7 +148,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.handlers_mut().push(EventHandler {
+ self.metadata().handlers.push(EventHandler {
handler: Rc::new(move |view, event, event_cx| {
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
if event.button == button && event.is_down {
@@ -168,7 +169,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.handlers_mut().push(EventHandler {
+ self.metadata().handlers.push(EventHandler {
handler: Rc::new(move |view, event, event_cx| {
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
if event.button == button && !event.is_down {
@@ -189,7 +190,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.handlers_mut().push(EventHandler {
+ self.metadata().handlers.push(EventHandler {
handler: Rc::new(move |view, event, event_cx| {
let event = event.downcast_ref::<MouseButtonEvent>().unwrap();
if event.button == button && !event.is_down {
@@ -208,7 +209,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().display = Display::Block;
+ self.metadata().style.display = Display::Block;
self
}
@@ -216,7 +217,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().display = Display::Flex;
+ self.metadata().style.display = Display::Flex;
self
}
@@ -224,7 +225,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().display = Display::Grid;
+ self.metadata().style.display = Display::Grid;
self
}
@@ -234,8 +235,8 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.x = Overflow::Visible;
- self.style_mut().overflow.y = Overflow::Visible;
+ self.metadata().style.overflow.x = Overflow::Visible;
+ self.metadata().style.overflow.y = Overflow::Visible;
self
}
@@ -243,8 +244,8 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.x = Overflow::Hidden;
- self.style_mut().overflow.y = Overflow::Hidden;
+ self.metadata().style.overflow.x = Overflow::Hidden;
+ self.metadata().style.overflow.y = Overflow::Hidden;
self
}
@@ -252,8 +253,8 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.x = Overflow::Scroll;
- self.style_mut().overflow.y = Overflow::Scroll;
+ self.metadata().style.overflow.x = Overflow::Scroll;
+ self.metadata().style.overflow.y = Overflow::Scroll;
self
}
@@ -261,7 +262,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.x = Overflow::Visible;
+ self.metadata().style.overflow.x = Overflow::Visible;
self
}
@@ -269,7 +270,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.x = Overflow::Hidden;
+ self.metadata().style.overflow.x = Overflow::Hidden;
self
}
@@ -277,7 +278,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.x = Overflow::Scroll;
+ self.metadata().style.overflow.x = Overflow::Scroll;
self
}
@@ -285,7 +286,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.y = Overflow::Visible;
+ self.metadata().style.overflow.y = Overflow::Visible;
self
}
@@ -293,7 +294,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.y = Overflow::Hidden;
+ self.metadata().style.overflow.y = Overflow::Hidden;
self
}
@@ -301,7 +302,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().overflow.y = Overflow::Scroll;
+ self.metadata().style.overflow.y = Overflow::Scroll;
self
}
@@ -311,7 +312,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().position = Position::Relative;
+ self.metadata().style.position = Position::Relative;
self
}
@@ -319,7 +320,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().position = Position::Absolute;
+ self.metadata().style.position = Position::Absolute;
self
}
@@ -329,10 +330,10 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().inset.top = length;
- self.style_mut().inset.right = length;
- self.style_mut().inset.bottom = length;
- self.style_mut().inset.left = length;
+ self.metadata().style.inset.top = length;
+ self.metadata().style.inset.right = length;
+ self.metadata().style.inset.bottom = length;
+ self.metadata().style.inset.left = length;
self
}
@@ -340,7 +341,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().size.width = width.into();
+ self.metadata().style.size.width = width.into();
self
}
@@ -348,7 +349,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().size.width = Length::Auto;
+ self.metadata().style.size.width = Length::Auto;
self
}
@@ -357,7 +358,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().size.width = length;
+ self.metadata().style.size.width = length;
self
}
@@ -366,7 +367,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().min_size.width = length;
+ self.metadata().style.min_size.width = length;
self
}
@@ -374,7 +375,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().size.height = height.into();
+ self.metadata().style.size.height = height.into();
self
}
@@ -382,7 +383,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().size.height = Length::Auto;
+ self.metadata().style.size.height = Length::Auto;
self
}
@@ -391,7 +392,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().size.height = height;
+ self.metadata().style.size.height = height;
self
}
@@ -400,7 +401,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().min_size.height = length;
+ self.metadata().style.min_size.height = length;
self
}
@@ -408,7 +409,7 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().fill = fill.into();
+ self.metadata().style.fill = fill.into();
self
}
@@ -416,15 +417,14 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().text_color = Some(color.into());
+ self.metadata().style.text_color = Some(color.into());
self
}
}
// Object-safe counterpart of Element used by AnyElement to store elements as trait objects.
trait ElementObject<V> {
- fn style_mut(&mut self) -> &mut ElementStyle;
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>>;
+ fn metadata(&mut self) -> &mut ElementMetadata<V>;
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>)
-> Result<(NodeId, Box<dyn Any>)>;
fn paint(
@@ -436,12 +436,8 @@ trait ElementObject<V> {
}
impl<V: 'static, E: Element<V>> ElementObject<V> for E {
- fn style_mut(&mut self) -> &mut ElementStyle {
- Element::style_mut(self)
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- Element::handlers_mut(self)
+ fn metadata(&mut self) -> &mut ElementMetadata<V> {
+ Element::metadata(self)
}
fn layout(
@@ -490,7 +486,7 @@ impl<V: 'static> AnyElement<V> {
}
pub fn push_text_style(&mut self, cx: &mut impl RenderContext) -> bool {
- let text_style = self.element.style_mut().text_style();
+ let text_style = self.element.metadata().style.text_style();
if let Some(text_style) = text_style {
let mut current_text_style = cx.text_style();
text_style.apply(&mut current_text_style);
@@ -516,7 +512,7 @@ impl<V: 'static> AnyElement<V> {
from_element: element_layout.as_mut(),
};
- for event_handler in self.element.handlers_mut().iter().cloned() {
+ for event_handler in self.element.metadata().handlers.iter().cloned() {
let EngineLayout { order, bounds } = layout.from_engine;
let view_id = cx.view_id();
@@ -551,12 +547,8 @@ impl<V: 'static> AnyElement<V> {
impl<V: 'static> Element<V> for AnyElement<V> {
type Layout = ();
- fn style_mut(&mut self) -> &mut ElementStyle {
- self.element.style_mut()
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- self.element.handlers_mut()
+ fn metadata(&mut self) -> &mut ElementMetadata<V> {
+ self.element.metadata()
}
fn layout(
@@ -1,11 +1,11 @@
#![allow(dead_code, unused_variables)]
use color::black;
use components::button;
+use div::div;
use element::Element;
-use frame::frame;
use gpui::{
geometry::{rect::RectF, vector::vec2f},
- platform::{MouseButton, WindowOptions},
+ platform::WindowOptions,
};
use log::LevelFilter;
use simplelog::SimpleLogger;
@@ -16,8 +16,8 @@ use view::view;
mod adapter;
mod color;
mod components;
+mod div;
mod element;
-mod frame;
mod paint_context;
mod style;
mod text;
@@ -44,7 +44,7 @@ fn main() {
}
fn playground<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
- frame()
+ div()
.text_color(black())
.h_full()
.w_half()
@@ -1,11 +1,20 @@
use crate::color::Hsla;
use gpui::geometry::{DefinedLength, Edges, Length, Point, Size};
+use playground_macros::Overrides;
pub use taffy::style::{
AlignContent, AlignItems, AlignSelf, Display, FlexDirection, FlexWrap, JustifyContent,
Overflow, Position,
};
-#[derive(Clone)]
+pub trait Overrides {
+ type Base;
+
+ fn is_some(&self) -> bool;
+ fn apply(&self, base: &mut Self::Base);
+}
+
+#[derive(Clone, Overrides)]
+#[overrides_crate = "crate"]
pub struct ElementStyle {
/// What layout strategy should be used?
pub display: Display,
@@ -1,4 +1,4 @@
-use crate::element::{Element, ElementMetadata, EventHandler, IntoElement};
+use crate::element::{Element, ElementMetadata, IntoElement};
use gpui::{geometry::Size, text_layout::LineLayout, RenderContext};
use parking_lot::Mutex;
use std::sync::Arc;
@@ -22,8 +22,8 @@ pub struct Text<V> {
impl<V: 'static> Element<V> for Text<V> {
type Layout = Arc<Mutex<Option<TextLayout>>>;
- fn style_mut(&mut self) -> &mut crate::style::ElementStyle {
- &mut self.metadata.style
+ fn metadata(&mut self) -> &mut crate::element::ElementMetadata<V> {
+ &mut self.metadata
}
fn layout(
@@ -91,10 +91,6 @@ impl<V: 'static> Element<V> for Text<V> {
);
Ok(())
}
-
- fn handlers_mut(&mut self) -> &mut Vec<EventHandler<V>> {
- &mut self.metadata.handlers
- }
}
pub struct TextLayout {
@@ -79,12 +79,8 @@ pub fn derive_element(input: TokenStream) -> TokenStream {
{
type Layout = #crate_name::element::AnyElement<V>;
- fn style_mut(&mut self) -> &mut #crate_name::style::ElementStyle {
- &mut self.metadata.style
- }
-
- fn handlers_mut(&mut self) -> &mut Vec<#crate_name::element::EventHandler<V>> {
- &mut self.metadata.handlers
+ fn metadata(&mut self) -> &mut #crate_name::element::ElementMetadata<V> {
+ &mut self.metadata
}
fn layout(
@@ -0,0 +1,119 @@
+extern crate proc_macro;
+use proc_macro::TokenStream;
+use quote::{format_ident, quote};
+use syn::{parse_macro_input, Data, DeriveInput, Fields, Lit, Meta};
+
+/// When deriving Overrides on a struct Foo, builds a new struct FooOverrides
+/// that implements the Overrides trait so it can be applied to Foo.
+pub fn derive_overrides(input: TokenStream) -> TokenStream {
+ let input = parse_macro_input!(input as DeriveInput);
+
+ let crate_name: String = input
+ .attrs
+ .iter()
+ .find_map(|attr| {
+ if attr.path.is_ident("overrides_crate") {
+ match attr.parse_meta() {
+ Ok(Meta::NameValue(nv)) => {
+ if let Lit::Str(s) = nv.lit {
+ Some(s.value())
+ } else {
+ None
+ }
+ }
+ _ => None,
+ }
+ } else {
+ None
+ }
+ })
+ .unwrap_or_else(|| String::from("playground"));
+ let crate_name = format_ident!("{}", crate_name);
+
+ let ident = input.ident;
+ let new_ident = syn::Ident::new(&format!("{}Overrides", ident), ident.span());
+ let data = match input.data {
+ Data::Struct(s) => s,
+ _ => panic!("Override can only be derived for structs"),
+ };
+
+ let fields = match data.fields {
+ Fields::Named(fields) => fields.named,
+ _ => panic!("Override can only be derived for structs with named fields"),
+ };
+
+ let new_fields = fields
+ .iter()
+ .map(|f| {
+ let name = &f.ident;
+ let ty = &f.ty;
+
+ if let syn::Type::Path(typepath) = ty {
+ if typepath.path.segments.last().unwrap().ident == "Option" {
+ return quote! { #name: #ty };
+ }
+ }
+ quote! { #name: Option<#ty> }
+ })
+ .collect::<Vec<_>>();
+
+ let names = fields.iter().map(|f| &f.ident);
+ let is_some_implementation = names.clone().map(|name| {
+ quote! {
+ self.#name.is_some()
+ }
+ });
+
+ let apply_implementation = fields.iter().map(|f| {
+ let name = &f.ident;
+ let ty = &f.ty;
+
+ if let syn::Type::Path(typepath) = ty {
+ if typepath.path.segments.last().unwrap().ident == "Option" {
+ return quote! {
+ base.#name = self.#name.clone();
+ };
+ }
+ }
+
+ quote! {
+ if let Some(value) = &self.#name {
+ base.#name = value.clone();
+ }
+ }
+ });
+
+ let default_implementation = names.map(|name| {
+ quote! {
+ #name: None,
+ }
+ });
+
+ let expanded = quote! {
+ pub struct #new_ident {
+ #(#new_fields,)*
+ }
+
+ impl #crate_name::style::Overrides for #new_ident {
+ type Base = #ident;
+
+ fn is_some(&self) -> bool {
+ #(#is_some_implementation)||*
+ }
+
+ fn apply(&self, base: &mut Self::Base) {
+ #(#apply_implementation)*
+ }
+ }
+
+ impl Default for #new_ident {
+ fn default() -> Self {
+ Self {
+ #(#default_implementation)*
+ }
+ }
+ }
+ };
+
+ TokenStream::from(expanded)
+}
@@ -2,6 +2,7 @@ use proc_macro::TokenStream;
mod derive_element;
mod derive_into_element;
+mod derive_overrides;
mod tailwind_lengths;
#[proc_macro_derive(Element, attributes(element_crate))]
@@ -14,6 +15,11 @@ pub fn derive_into_element(input: TokenStream) -> TokenStream {
derive_into_element::derive_into_element(input)
}
+#[proc_macro_derive(Overrides, attributes(overrides_crate))]
+pub fn derive_overrides(input: TokenStream) -> TokenStream {
+ derive_overrides::derive_overrides(input)
+}
+
#[proc_macro_attribute]
pub fn tailwind_lengths(attr: TokenStream, item: TokenStream) -> TokenStream {
tailwind_lengths::tailwind_lengths(attr, item)