Detailed changes
@@ -408,7 +408,15 @@ pub trait Element<V: 'static>: 'static {
where
Self: Sized,
{
- self.style_mut().fill = fill.into();
+ self.style_mut().fill = Some(fill.into());
+ self
+ }
+
+ fn hover_fill(mut self, fill: impl Into<Fill>) -> Self
+ where
+ Self: Sized,
+ {
+ self.style_mut().hover_fill = Some(fill.into());
self
}
@@ -2,7 +2,7 @@ use crate::{
element::{
AnyElement, Element, EventHandler, IntoElement, Layout, LayoutContext, NodeId, PaintContext,
},
- style::ElementStyle,
+ style::{ElementStyle, Fill},
};
use anyhow::{anyhow, Result};
use gpui::LayoutNodeId;
@@ -58,7 +58,12 @@ 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
+ .style
+ .fill
+ .as_ref()
+ .and_then(Fill::color)
+ .map(Into::into),
border: Default::default(),
corner_radii: Default::default(),
});
@@ -1,9 +1,7 @@
use std::{any::TypeId, rc::Rc};
use derive_more::{Deref, DerefMut};
-use gpui::{
- geometry::rect::RectF, scene::InteractiveRegion, EventContext, RenderContext, ViewContext,
-};
+use gpui::{geometry::rect::RectF, EventContext, RenderContext, ViewContext};
pub use gpui::{LayoutContext, PaintContext as LegacyPaintContext};
pub use taffy::tree::NodeId;
@@ -42,24 +40,26 @@ impl<'a, 'b, 'c, 'd, V: 'static> PaintContext<'a, 'b, 'c, 'd, V> {
order: u32,
bounds: RectF,
outside_bounds: bool,
- handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
+ event_handler: impl Fn(&mut V, &E, &mut EventContext<V>) + 'static,
) {
- // We'll sort these by their order in `take_interactive_regions`.
- self.scene.interactive_regions.push(InteractiveRegion {
- order,
- bounds,
- outside_bounds,
- event_handler: Rc::new(move |view, event, window_cx, view_id| {
- let mut cx = ViewContext::mutable(window_cx, view_id);
- let mut cx = EventContext::new(&mut cx);
- handler(
- view.downcast_mut().unwrap(),
- event.downcast_ref().unwrap(),
- &mut cx,
- )
- }),
- event_type: TypeId::of::<E>(),
- view_id: self.view_id(),
- });
+ // We'll sort these later when `take_interactive_regions` is called.
+ self.scene
+ .interactive_regions
+ .push(gpui::scene::InteractiveRegion {
+ order,
+ bounds,
+ outside_bounds,
+ event_handler: Rc::new(move |view, event, window_cx, view_id| {
+ let mut view_context = ViewContext::mutable(window_cx, view_id);
+ let mut event_context = EventContext::new(&mut view_context);
+ event_handler(
+ view.downcast_mut().unwrap(),
+ event.downcast_ref().unwrap(),
+ &mut event_context,
+ );
+ }),
+ event_type: TypeId::of::<E>(),
+ view_id: self.view_id(),
+ });
}
}
@@ -5,7 +5,7 @@ use element::Element;
use frame::frame;
use gpui::{
geometry::{rect::RectF, vector::vec2f},
- platform::{MouseButton, WindowOptions},
+ platform::WindowOptions,
};
use log::LevelFilter;
use simplelog::SimpleLogger;
@@ -65,7 +65,9 @@ pub struct ElementStyle {
pub flex_shrink: f32,
/// The fill color of this element
- pub fill: Fill,
+ pub fill: Option<Fill>,
+ /// The fill color of this element when hovered
+ pub hover_fill: Option<Fill>,
/// The color of text within this element. Cascades to children unless overridden.
pub text_color: Option<Hsla>,
}
@@ -99,12 +101,8 @@ impl ElementStyle {
flex_grow: 0.0,
flex_shrink: 1.0,
flex_basis: Length::Auto,
- fill: Fill::Color(Hsla {
- h: 0.,
- s: 0.,
- l: 0.,
- a: 0.,
- }),
+ fill: None,
+ hover_fill: None,
text_color: None,
};
@@ -0,0 +1,95 @@
+use proc_macro::TokenStream;
+use quote::{quote, ToTokens};
+use syn::{parse_macro_input, Expr, Ident, Token};
+
+struct Args {
+ method_name: Ident,
+ method_suffix: Option<Ident>,
+ field_name: Ident,
+ value: Expr,
+}
+
+impl syn::parse::Parse for Args {
+ fn parse(input: syn::parse::ParseStream) -> syn::Result<Self> {
+ let method_name = input.parse()?;
+ let method_suffix = if input.peek(Token![::]) {
+ input.parse::<Token![::]>()?;
+ Some(input.parse()?)
+ } else {
+ None
+ };
+ input.parse::<Token![,]>()?;
+ let field_name = input.parse()?;
+ input.parse::<Token![,]>()?;
+ let value = input.parse()?;
+
+ Ok(Self {
+ method_name,
+ method_suffix,
+ field_name,
+ value,
+ })
+ }
+}
+
+fn fixed_lengths() -> Vec<(&'static str, proc_macro2::TokenStream)> {
+ vec![
+ ("0", quote! { DefinedLength::Pixels(0.) }),
+ ("px", quote! { DefinedLength::Pixels(1.) }),
+ ("0_5", quote! { DefinedLength::Rems(0.125) }),
+ // ...
+ ]
+}
+
+pub fn style_methods(input: TokenStream) -> TokenStream {
+ let Args {
+ method_name,
+ method_suffix,
+ field_name,
+ value,
+ } = parse_macro_input!(input as Args);
+
+ let hover_method_name = format!("hover_{}", method_name);
+ let hover_method_ident = syn::Ident::new(&hover_method_name, method_name.span());
+
+ let mut result = quote! {
+ fn #method_name(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.metadata().style.#field_name = #value;
+ self
+ }
+
+ fn #hover_method_ident(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.metadata().hover_style.#field_name = Some(#value);
+ self
+ }
+ };
+
+ if let Some(suffix_ident) = method_suffix {
+ if suffix_ident == "_" {
+ let fixed_lengths = fixed_lengths();
+
+ for (suffix, value) in fixed_lengths {
+ let method_ident =
+ syn::Ident::new(&format!("{}_{}", method_name, suffix), method_name.span());
+ let method = quote! {
+ fn #method_ident(mut self) -> Self
+ where
+ Self: Sized,
+ {
+ self.metadata().style.#field_name = #value;
+ self
+ }
+ };
+ result.extend(method);
+ }
+ }
+ }
+
+ result.into()
+}