From 569d99a5a1cbdb89c0a87c90940237b33fc91274 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 23 Aug 2023 09:08:05 -0600 Subject: [PATCH 001/109] Add hover styling support --- crates/gpui/playground/src/hoverable.rs | 33 ++++++++++++------------ crates/gpui/playground/src/playground.rs | 9 ++++--- crates/gpui/playground/src/style.rs | 8 ++++++ crates/gpui/src/app.rs | 9 ++++++- crates/gpui/src/app/window.rs | 3 ++- crates/gpui/src/platform.rs | 1 + crates/gpui/src/platform/mac/platform.rs | 8 +++++- crates/gpui/src/platform/test.rs | 4 +++ 8 files changed, 53 insertions(+), 22 deletions(-) diff --git a/crates/gpui/playground/src/hoverable.rs b/crates/gpui/playground/src/hoverable.rs index 5545155a60c4e55e15bc534843c76a0e6f543d36..d2c87506c4931f37fbeec8e70103596f2e96b0df 100644 --- a/crates/gpui/playground/src/hoverable.rs +++ b/crates/gpui/playground/src/hoverable.rs @@ -2,40 +2,38 @@ use crate::{ element::{Element, Layout}, layout_context::LayoutContext, paint_context::PaintContext, - style::{StyleRefinement, Styleable}, + style::{Style, StyleHelpers, StyleRefinement, Styleable}, }; use anyhow::Result; use gpui::platform::MouseMovedEvent; use refineable::Refineable; -use std::{cell::Cell, marker::PhantomData}; +use std::cell::Cell; -pub struct Hoverable + Styleable> { +pub struct Hoverable { hovered: Cell, child_style: StyleRefinement, hovered_style: StyleRefinement, child: E, - view_type: PhantomData, } -pub fn hoverable + Styleable>(mut child: E) -> Hoverable { +pub fn hoverable(mut child: E) -> Hoverable { Hoverable { hovered: Cell::new(false), child_style: child.declared_style().clone(), hovered_style: Default::default(), child, - view_type: PhantomData, } } -impl + Styleable> Styleable for Hoverable { +impl Styleable for Hoverable { type Style = E::Style; fn declared_style(&mut self) -> &mut crate::style::StyleRefinement { - self.child.declared_style() + &mut self.hovered_style } } -impl + Styleable> Element for Hoverable { +impl + Styleable> Element for Hoverable { type Layout = E::Layout; fn layout(&mut self, view: &mut V, cx: &mut LayoutContext) -> Result> @@ -53,6 +51,10 @@ impl + Styleable> Element for Hoverable { ) where Self: Sized, { + let bounds = layout.bounds(cx); + let order = layout.order(cx); + + self.hovered.set(bounds.contains_point(cx.mouse_position())); if self.hovered.get() { // If hovered, refine the child's style with this element's style. self.child.declared_style().refine(&self.hovered_style); @@ -61,16 +63,15 @@ impl + Styleable> Element for Hoverable { *self.child.declared_style() = self.child_style.clone(); } - let bounds = layout.bounds(cx); - let order = layout.order(cx); - self.hovered.set(bounds.contains_point(cx.mouse_position())); - let was_hovered = self.hovered.clone(); + let hovered = self.hovered.clone(); cx.on_event(order, move |view, event: &MouseMovedEvent, cx| { - let is_hovered = bounds.contains_point(event.position); - if is_hovered != was_hovered.get() { - was_hovered.set(is_hovered); + if bounds.contains_point(event.position) != hovered.get() { cx.repaint(); } }); + + self.child.paint(view, layout, cx); } } + +impl> StyleHelpers for Hoverable {} diff --git a/crates/gpui/playground/src/playground.rs b/crates/gpui/playground/src/playground.rs index 2462ac99f59e412cdbd16d3b616503dcb7810660..00f0ebdc8007aaf2017a3a45b4b3dbc547634713 100644 --- a/crates/gpui/playground/src/playground.rs +++ b/crates/gpui/playground/src/playground.rs @@ -1,5 +1,8 @@ #![allow(dead_code, unused_variables)] -use crate::{color::black, style::StyleHelpers}; +use crate::{ + color::black, + style::{StyleHelpers, Styleable}, +}; use element::Element; use gpui::{ geometry::{rect::RectF, vector::vec2f}, @@ -51,8 +54,8 @@ fn playground(theme: &ThemeColors) -> impl Element { .h_full() .w_1_2() .fill(theme.success(0.5)) - // .hover() - // .fill(theme.error(0.5)) + .hoverable() + .fill(theme.error(0.5)) // .child(button().label("Hello").click(|_, _, _| println!("click!"))) } diff --git a/crates/gpui/playground/src/style.rs b/crates/gpui/playground/src/style.rs index 9216702f7fab3a50cc4a27502ebd3a383db5134f..9d58c583f5a9d6f0e289fe8691d0fe3f3d007268 100644 --- a/crates/gpui/playground/src/style.rs +++ b/crates/gpui/playground/src/style.rs @@ -1,6 +1,7 @@ use crate::{ color::Hsla, element::{Element, Layout}, + hoverable::{hoverable, Hoverable}, paint_context::PaintContext, }; use gpui::{ @@ -255,6 +256,13 @@ pub trait Styleable { style.refine(self.declared_style()); style } + + fn hoverable(self) -> Hoverable + where + Self: Sized, + { + hoverable(self) + } } // Helpers methods that take and return mut self. This includes tailwind style methods for standard sizes etc. diff --git a/crates/gpui/src/app.rs b/crates/gpui/src/app.rs index 076a3fdde32ac008a05869004a859a9a002a8f80..55ed812f994f663f66e6aea11664895ec0627b41 100644 --- a/crates/gpui/src/app.rs +++ b/crates/gpui/src/app.rs @@ -1363,7 +1363,14 @@ impl AppContext { window: handle, })); - let mut window = Window::new(handle, platform_window, self, build_root_view); + let mouse_position = self.platform.mouse_position(); + let mut window = Window::new( + handle, + platform_window, + mouse_position, + self, + build_root_view, + ); let mut cx = WindowContext::mutable(self, &mut window, handle); cx.layout(false).expect("initial layout should not error"); let scene = cx.paint().expect("initial paint should not error"); diff --git a/crates/gpui/src/app/window.rs b/crates/gpui/src/app/window.rs index 5638699565fbbb8c725bf3e119b3ffa0f1e07ce4..e0d53401a8b37915fcd48b602d005a5351dc81c0 100644 --- a/crates/gpui/src/app/window.rs +++ b/crates/gpui/src/app/window.rs @@ -70,6 +70,7 @@ impl Window { pub fn new( handle: AnyWindowHandle, platform_window: Box, + mouse_position: Vector2F, cx: &mut AppContext, build_view: F, ) -> Self @@ -97,7 +98,7 @@ impl Window { hovered_region_ids: Default::default(), clicked_region_ids: Default::default(), clicked_region: None, - mouse_position: vec2f(0., 0.), + mouse_position, titlebar_height, appearance, }; diff --git a/crates/gpui/src/platform.rs b/crates/gpui/src/platform.rs index 824e6b61e5342923f8cb6c21a6e4590bb5b240a2..2ac7ec54c704c17779d81e3237c3375a7c5789e7 100644 --- a/crates/gpui/src/platform.rs +++ b/crates/gpui/src/platform.rs @@ -75,6 +75,7 @@ pub trait Platform: Send + Sync { fn read_credentials(&self, url: &str) -> Result)>>; fn delete_credentials(&self, url: &str) -> Result<()>; + fn mouse_position(&self) -> Vector2F; fn set_cursor_style(&self, style: CursorStyle); fn should_auto_hide_scrollbars(&self) -> bool; diff --git a/crates/gpui/src/platform/mac/platform.rs b/crates/gpui/src/platform/mac/platform.rs index 9a799c3a3a17767bb1be4fcdd9d7a7a217f52e11..af4eaa2a4092b1a4a29adcc447356f5b5e379f3d 100644 --- a/crates/gpui/src/platform/mac/platform.rs +++ b/crates/gpui/src/platform/mac/platform.rs @@ -18,7 +18,7 @@ use cocoa::{ }, base::{id, nil, selector, BOOL, YES}, foundation::{ - NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSProcessInfo, NSString, + NSArray, NSAutoreleasePool, NSBundle, NSData, NSInteger, NSPoint, NSProcessInfo, NSString, NSUInteger, NSURL, }, }; @@ -37,6 +37,7 @@ use objc::{ runtime::{Class, Object, Sel}, sel, sel_impl, }; +use pathfinder_geometry::vector::{vec2f, Vector2F}; use postage::oneshot; use ptr::null_mut; use std::{ @@ -784,6 +785,11 @@ impl platform::Platform for MacPlatform { Ok(()) } + fn mouse_position(&self) -> Vector2F { + let position: NSPoint = unsafe { msg_send![class!(NSEvent), mouseLocation] }; + vec2f(position.x as f32, position.y as f32) + } + fn set_cursor_style(&self, style: CursorStyle) { unsafe { let new_cursor: id = match style { diff --git a/crates/gpui/src/platform/test.rs b/crates/gpui/src/platform/test.rs index ee3a26c6fd887dc9d3215476d29045376bc2c087..5b6f299f9c0b1b4167ae44b42d07c30bf3f6ad50 100644 --- a/crates/gpui/src/platform/test.rs +++ b/crates/gpui/src/platform/test.rs @@ -195,6 +195,10 @@ impl super::Platform for Platform { Ok(()) } + fn mouse_position(&self) -> Vector2F { + Vector2F::zero() + } + fn set_cursor_style(&self, style: CursorStyle) { *self.cursor.lock() = style; } From 5996b6b46bd3bd69703a8ebf3c68f13c2faf9f30 Mon Sep 17 00:00:00 2001 From: Nathan Sobo Date: Wed, 23 Aug 2023 12:18:12 -0600 Subject: [PATCH 002/109] Use RefinementCascade to compose pressability and hoverability Co-Authored-By: Conrad Irwin --- crates/gpui/playground/src/div.rs | 23 +++--- crates/gpui/playground/src/element.rs | 32 ++++---- crates/gpui/playground/src/hoverable.rs | 33 ++++---- crates/gpui/playground/src/playground.rs | 5 +- crates/gpui/playground/src/pressable.rs | 81 +++++++++++++++++++ crates/gpui/playground/src/style.rs | 38 ++++----- .../playground_macros/src/derive_element.rs | 10 +-- .../src/styleable_helpers.rs | 1 + crates/gpui/src/app.rs | 1 - crates/refineable/src/refineable.rs | 46 ++++++++++- 10 files changed, 202 insertions(+), 68 deletions(-) create mode 100644 crates/gpui/playground/src/pressable.rs diff --git a/crates/gpui/playground/src/div.rs b/crates/gpui/playground/src/div.rs index 8efe3590258a4249abd9bb69a359f95692b6a6a0..73f196b4f07088cd3d007b071759a18eb373b164 100644 --- a/crates/gpui/playground/src/div.rs +++ b/crates/gpui/playground/src/div.rs @@ -3,21 +3,22 @@ use crate::{ interactive::{InteractionHandlers, Interactive}, layout_context::LayoutContext, paint_context::PaintContext, - style::{Style, StyleHelpers, StyleRefinement, Styleable}, + style::{Style, StyleHelpers, Styleable}, }; use anyhow::Result; use gpui::LayoutId; +use refineable::{Refineable, RefinementCascade}; use smallvec::SmallVec; pub struct Div { - style: StyleRefinement, + styles: RefinementCascade