Add group hovers

This commit is contained in:
Nathan Sobo 2023-10-11 21:34:08 -06:00
parent f37b83a0ea
commit d920f7edc1
21 changed files with 157 additions and 103 deletions

View File

@ -13,12 +13,12 @@ use gpui::{
scene::{self},
LayoutId,
};
use refineable::{Refineable, RefinementCascade};
use refineable::{Cascade, Refineable};
use smallvec::SmallVec;
use util::ResultExt;
pub struct Div<V: 'static> {
styles: RefinementCascade<Style>,
styles: Cascade<Style>,
handlers: InteractionHandlers<V>,
children: SmallVec<[AnyElement<V>; 2]>,
scroll_state: Option<ScrollState>,
@ -263,7 +263,7 @@ impl<V: 'static> Div<V> {
impl<V> Styleable for Div<V> {
type Style = Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
&mut self.styles
}

View File

@ -6,7 +6,7 @@ use crate::{
};
use anyhow::Result;
use gpui::{geometry::vector::Vector2F, platform::MouseMovedEvent, LayoutId};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use refineable::{Cascade, CascadeSlot, Refineable};
use smallvec::SmallVec;
use std::{cell::Cell, rc::Rc};
@ -29,7 +29,7 @@ pub fn hoverable<E: Styleable>(mut child: E) -> Hoverable<E> {
impl<E: Styleable> Styleable for Hoverable<E> {
type Style = E::Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
self.child.style_cascade()
}

View File

@ -7,19 +7,19 @@ use futures::FutureExt;
use gpui::geometry::vector::Vector2F;
use gpui::scene;
use gpui2_macros::IntoElement;
use refineable::RefinementCascade;
use refineable::Cascade;
use util::arc_cow::ArcCow;
use util::ResultExt;
#[derive(IntoElement)]
pub struct Img {
style: RefinementCascade<Style>,
style: Cascade<Style>,
uri: Option<ArcCow<'static, str>>,
}
pub fn img() -> Img {
Img {
style: RefinementCascade::default(),
style: Cascade::default(),
uri: None,
}
}
@ -98,7 +98,7 @@ impl<V: 'static> Element<V> for Img {
impl Styleable for Img {
type Style = Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
&mut self.style
}

View File

@ -6,7 +6,7 @@ use crate::{
};
use anyhow::Result;
use gpui::{geometry::vector::Vector2F, platform::MouseButtonEvent, LayoutId};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use refineable::{Cascade, CascadeSlot, Refineable};
use smallvec::SmallVec;
use std::{cell::Cell, rc::Rc};
@ -33,7 +33,7 @@ impl<E: Styleable> Styleable for Pressable<E> {
&mut self.pressed_style
}
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
self.child.style_cascade()
}
}

View File

@ -4,20 +4,20 @@ use crate::{
Element, IntoElement, Layout, LayoutId, Rgba,
};
use gpui::geometry::vector::Vector2F;
use refineable::RefinementCascade;
use refineable::Cascade;
use std::borrow::Cow;
use util::ResultExt;
#[derive(IntoElement)]
pub struct Svg {
path: Option<Cow<'static, str>>,
style: RefinementCascade<Style>,
style: Cascade<Style>,
}
pub fn svg() -> Svg {
Svg {
path: None,
style: RefinementCascade::<Style>::default(),
style: Cascade::<Style>::default(),
}
}
@ -72,7 +72,7 @@ impl<V: 'static> Element<V> for Svg {
impl Styleable for Svg {
type Style = Style;
fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut refineable::Cascade<Self::Style> {
&mut self.style
}

View File

@ -19,7 +19,7 @@ use gpui::{
scene, taffy, WindowContext,
};
use gpui2_macros::styleable_helpers;
use refineable::{Refineable, RefinementCascade};
use refineable::{Cascade, Refineable};
use std::sync::Arc;
#[derive(Clone, Refineable, Debug)]
@ -292,7 +292,7 @@ impl CornerRadii {
pub trait Styleable {
type Style: Refineable + Default;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
fn style_cascade(&mut self) -> &mut Cascade<Self::Style>;
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
fn computed_style(&mut self) -> Self::Style {

View File

@ -1,8 +1,8 @@
use std::sync::Arc;
use crate::{
BorrowWindow, Bounds, Clickable, ElementGroup, ElementId, LayoutId, MouseDownEvent,
MouseUpEvent, Pixels, Point, SharedString, ViewContext,
BorrowWindow, Bounds, Clickable, ElementId, Group, LayoutId, MouseDownEvent, MouseUpEvent,
Pixels, Point, SharedString, ViewContext,
};
use derive_more::{Deref, DerefMut};
pub(crate) use smallvec::SmallVec;
@ -28,11 +28,11 @@ pub trait Element: 'static + Send + Sync {
cx: &mut ViewContext<Self::ViewState>,
);
fn group(self, name: impl Into<SharedString>) -> ElementGroup<Self>
fn group(self, name: impl Into<SharedString>) -> Group<Self>
where
Self: Sized,
{
ElementGroup::new(name.into(), self)
Group::new(name.into(), self)
}
}

View File

@ -3,7 +3,7 @@ use crate::{
MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
};
use parking_lot::Mutex;
use refineable::RefinementCascade;
use refineable::Cascade;
use smallvec::SmallVec;
use std::sync::Arc;
@ -32,7 +32,7 @@ where
{
type Style = E::Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
self.child.style_cascade()
}

View File

@ -1,7 +1,7 @@
use crate::{
AnyElement, BorrowWindow, Bounds, Element, ElementId, IdentifiedElement, Interactive, LayoutId,
MouseEventListeners, Overflow, ParentElement, Pixels, Point, Refineable, RefinementCascade,
Style, Styled, ViewContext,
AnyElement, BorrowWindow, Bounds, Cascade, Element, ElementId, IdentifiedElement, Interactive,
LayoutId, MouseEventListeners, Overflow, ParentElement, Pixels, Point, Refineable, Style,
Styled, ViewContext,
};
use parking_lot::Mutex;
use smallvec::SmallVec;
@ -10,7 +10,7 @@ use std::{marker::PhantomData, sync::Arc};
pub enum HasId {}
pub struct Div<S: 'static, I = ()> {
styles: RefinementCascade<Style>,
styles: Cascade<Style>,
id: Option<ElementId>,
listeners: MouseEventListeners<S>,
children: SmallVec<[AnyElement<S>; 2]>,
@ -179,7 +179,7 @@ where
impl<V: 'static + Send + Sync, Marker: 'static + Send + Sync> Styled for Div<V, Marker> {
type Style = Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
&mut self.styles
}

View File

@ -1,8 +1,9 @@
use crate::{
AnyElement, AppContext, Bounds, Element, ElementId, IdentifiedElement, ParentElement, Pixels,
SharedString, ViewContext,
AnyElement, AppContext, Bounds, Element, ElementId, IdentifiedElement, Interactive,
MouseEventListeners, ParentElement, Pixels, SharedString, Styled, ViewContext,
};
use collections::HashMap;
use refineable::Cascade;
use smallvec::SmallVec;
#[derive(Default)]
@ -15,18 +16,18 @@ pub fn element_group_bounds(name: &SharedString, cx: &mut AppContext) -> Option<
.and_then(|bounds_stack| bounds_stack.last().cloned())
}
pub struct ElementGroup<E> {
pub struct Group<E> {
name: SharedString,
child: E,
}
impl<E> ElementGroup<E> {
impl<E> Group<E> {
pub fn new(name: SharedString, child: E) -> Self {
ElementGroup { name, child }
Group { name, child }
}
}
impl<E: Element> Element for ElementGroup<E> {
impl<E: Element> Element for Group<E> {
type ViewState = E::ViewState;
type ElementState = E::ElementState;
@ -64,7 +65,7 @@ impl<E: Element> Element for ElementGroup<E> {
}
}
impl<E: ParentElement> ParentElement for ElementGroup<E> {
impl<E: ParentElement> ParentElement for Group<E> {
type State = E::State;
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<Self::State>; 2]> {
@ -72,4 +73,25 @@ impl<E: ParentElement> ParentElement for ElementGroup<E> {
}
}
impl<E> IdentifiedElement for ElementGroup<E> where E: IdentifiedElement {}
impl<E> IdentifiedElement for Group<E> where E: IdentifiedElement {}
impl<E> Styled for Group<E>
where
E: Styled,
{
type Style = E::Style;
fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
self.child.style_cascade()
}
fn declared_style(&mut self) -> &mut <Self::Style as refineable::Refineable>::Refinement {
self.child.declared_style()
}
}
impl<S: 'static + Send + Sync, E: Interactive<S> + Styled> Interactive<S> for Group<E> {
fn listeners(&mut self) -> &mut MouseEventListeners<S> {
self.child.listeners()
}
}

View File

@ -3,7 +3,7 @@ use crate::{
Interactive, MouseEventListeners, MouseMoveEvent, ParentElement, Pixels, SharedString, Styled,
ViewContext,
};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use refineable::{Cascade, CascadeSlot, Refineable};
use smallvec::SmallVec;
use std::sync::{
atomic::{AtomicBool, Ordering::SeqCst},
@ -36,7 +36,7 @@ where
{
type Style = E::Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
self.child.style_cascade()
}
@ -80,12 +80,13 @@ where
element_state: &mut Self::ElementState,
cx: &mut ViewContext<Self::ViewState>,
) {
let bounds = self
let hover_bounds = self
.hover_group
.as_ref()
.and_then(|group| element_group_bounds(group, cx))
.unwrap_or(bounds);
let hovered = bounds.contains_point(cx.mouse_position());
let hovered = hover_bounds.contains_point(cx.mouse_position());
let slot = self.cascade_slot;
let style = hovered.then_some(self.hovered_style.clone());
@ -97,7 +98,7 @@ where
move |_, event: &MouseMoveEvent, phase, cx| {
if phase == DispatchPhase::Capture {
if bounds.contains_point(event.position) != hovered.load(SeqCst) {
if hover_bounds.contains_point(event.position) != hovered.load(SeqCst) {
cx.notify();
}
}

View File

@ -1,4 +1,4 @@
use refineable::{Refineable, RefinementCascade};
use refineable::{Cascade, Refineable};
use smallvec::SmallVec;
use crate::{
@ -46,7 +46,7 @@ impl<E: Element> IdentifiedElement for Identified<E> {}
impl<E: Styled> Styled for Identified<E> {
type Style = E::Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
self.element.style_cascade()
}
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement {

View File

@ -2,12 +2,12 @@ use crate::{
BorrowWindow, Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled, ViewContext,
};
use futures::FutureExt;
use refineable::RefinementCascade;
use refineable::Cascade;
use std::marker::PhantomData;
use util::ResultExt;
pub struct Img<S> {
style: RefinementCascade<Style>,
style: Cascade<Style>,
uri: Option<SharedString>,
grayscale: bool,
state_type: PhantomData<S>,
@ -15,7 +15,7 @@ pub struct Img<S> {
pub fn img<S>() -> Img<S> {
Img {
style: RefinementCascade::default(),
style: Cascade::default(),
uri: None,
grayscale: false,
state_type: PhantomData,
@ -94,7 +94,7 @@ impl<S: Send + Sync + 'static> Element for Img<S> {
impl<S> Styled for Img<S> {
type Style = Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut Cascade<Self::Style> {
&mut self.style
}

View File

@ -2,7 +2,7 @@ use crate::{
AnyElement, Bounds, DispatchPhase, Element, IdentifiedElement, Interactive, MouseDownEvent,
MouseEventListeners, MouseUpEvent, ParentElement, Pixels, Styled, ViewContext,
};
use refineable::{CascadeSlot, Refineable, RefinementCascade};
use refineable::{Cascade, CascadeSlot, Refineable};
use smallvec::SmallVec;
use std::sync::{
atomic::{AtomicBool, Ordering::SeqCst},
@ -36,7 +36,7 @@ where
{
type Style = E::Style;
fn style_cascade(&mut self) -> &mut RefinementCascade<E::Style> {
fn style_cascade(&mut self) -> &mut Cascade<E::Style> {
self.child.style_cascade()
}

View File

@ -1,18 +1,18 @@
use crate::{Bounds, Element, LayoutId, Pixels, SharedString, Style, Styled};
use refineable::RefinementCascade;
use refineable::Cascade;
use std::marker::PhantomData;
use util::ResultExt;
pub struct Svg<S> {
path: Option<SharedString>,
style: RefinementCascade<Style>,
style: Cascade<Style>,
state_type: PhantomData<S>,
}
pub fn svg<S>() -> Svg<S> {
Svg {
path: None,
style: RefinementCascade::<Style>::default(),
style: Cascade::<Style>::default(),
state_type: PhantomData,
}
}
@ -64,7 +64,7 @@ impl<S: 'static + Send + Sync> Element for Svg<S> {
impl<S: 'static + Send + Sync> Styled for Svg<S> {
type Style = Style;
fn style_cascade(&mut self) -> &mut refineable::RefinementCascade<Self::Style> {
fn style_cascade(&mut self) -> &mut refineable::Cascade<Self::Style> {
&mut self.style
}

View File

@ -263,7 +263,7 @@ pub trait StyleHelpers: Styled<Style = Style> {
{
self.declared_style().box_shadow = Some(smallvec![
BoxShadow {
color: hsla(0.5, 0., 0., 1.0),
color: hsla(0.5, 0., 0., 0.1),
offset: point(px(0.), px(4.)),
blur_radius: px(6.),
spread_radius: px(-1.),

View File

@ -1,9 +1,9 @@
use crate::{Hoverable, Pressable, Refineable, RefinementCascade, SharedString};
use crate::{Cascade, Hoverable, Pressable, Refineable, SharedString};
pub trait Styled {
type Style: 'static + Refineable + Send + Sync + Default;
fn style_cascade(&mut self) -> &mut RefinementCascade<Self::Style>;
fn style_cascade(&mut self) -> &mut Cascade<Self::Style>;
fn declared_style(&mut self) -> &mut <Self::Style as Refineable>::Refinement;
fn computed_style(&mut self) -> Self::Style {

View File

@ -17,7 +17,7 @@ pub trait Refineable: Clone {
{
Self::default().refined(refinement)
}
fn from_cascade(cascade: &RefinementCascade<Self>) -> Self
fn from_cascade(cascade: &Cascade<Self>) -> Self
where
Self: Default + Sized,
{
@ -25,9 +25,9 @@ pub trait Refineable: Clone {
}
}
pub struct RefinementCascade<S: Refineable>(Vec<Option<S::Refinement>>);
pub struct Cascade<S: Refineable>(Vec<Option<S::Refinement>>);
impl<S: Refineable + Default> Default for RefinementCascade<S> {
impl<S: Refineable + Default> Default for Cascade<S> {
fn default() -> Self {
Self(vec![Some(Default::default())])
}
@ -36,7 +36,7 @@ impl<S: Refineable + Default> Default for RefinementCascade<S> {
#[derive(Copy, Clone)]
pub struct CascadeSlot(usize);
impl<S: Refineable + Default> RefinementCascade<S> {
impl<S: Refineable + Default> Cascade<S> {
pub fn reserve(&mut self) -> CascadeSlot {
self.0.push(None);
return CascadeSlot(self.0.len() - 1);

View File

@ -43,27 +43,27 @@ impl CollabPanel {
.flex_col()
.overflow_y_scroll(self.scroll_state.clone())
// List Container
.child(
div()
.id(0)
.on_click(|_, _, _| {
dbg!("click!");
})
.fill(theme.lowest.base.default.background)
.pb_1()
.border_color(theme.lowest.base.default.border)
.border_b()
//:: https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
// .group()
// List Section Header
.child(self.list_section_header(0, "#CRDB 🗃️", true, theme))
// List Item Large
.child(self.list_item(
"http://github.com/maxbrunsfeld.png?s=50",
"maxbrunsfeld",
theme,
)),
)
// .child(
// div()
// .id(0)
// .on_click(|_, _, _| {
// dbg!("click!");
// })
// .fill(theme.lowest.base.default.background)
// .pb_1()
// .border_color(theme.lowest.base.default.border)
// .border_b()
// //:: https://tailwindcss.com/docs/hover-focus-and-other-states#styling-based-on-parent-state
// // .group()
// // List Section Header
// .child(self.list_section_header(0, "#CRDB 🗃️", true, theme))
// // List Item Large
// .child(self.list_item(
// "http://github.com/maxbrunsfeld.png?s=50",
// "maxbrunsfeld",
// theme,
// )),
// )
.child(
div()
.py_2()
@ -85,19 +85,19 @@ impl CollabPanel {
"as-cii",
theme,
),
self.list_item(
"http://github.com/nathansobo.png?s=50",
"nathansobo",
theme,
),
self.list_item(
"http://github.com/maxbrunsfeld.png?s=50",
"maxbrunsfeld",
theme,
),
// self.list_item(
// "http://github.com/nathansobo.png?s=50",
// "nathansobo",
// theme,
// ),
// self.list_item(
// "http://github.com/maxbrunsfeld.png?s=50",
// "maxbrunsfeld",
// theme,
// ),
]
})
.take(5)
.take(1)
.flatten(),
),
),
@ -133,8 +133,6 @@ impl CollabPanel {
.flex()
.justify_between()
.items_center()
.hover()
.fill(theme.lowest.base.active.background)
.active()
.fill(theme.highest.accent.default.background)
.child(div().flex().gap_1().text_sm().child(label))
@ -160,6 +158,7 @@ impl CollabPanel {
theme: &Theme,
) -> impl Element<ViewState = Self> {
div()
.group("")
.h_7()
.px_2()
.flex()
@ -175,12 +174,16 @@ impl CollabPanel {
.gap_1()
.text_sm()
.child(
img()
.uri(avatar_uri)
div()
// .uri(avatar_uri)
.size_3p5()
.rounded_full()
.fill(theme.middle.positive.default.foreground)
.shadow_md(),
.shadow()
.group_hover("")
.fill(theme.middle.negative.default.foreground)
.hover()
.fill(theme.middle.warning.default.foreground),
)
.child(label),
)

View File

@ -1,10 +1,13 @@
#![allow(dead_code, unused_variables)]
use assets::Assets;
use gpui3::{px, size, Bounds, WindowBounds, WindowOptions};
use gpui3::{
div, px, size, Bounds, Element, StyleHelpers, WindowBounds, WindowContext, WindowOptions,
};
use log::LevelFilter;
use simplelog::SimpleLogger;
use std::sync::Arc;
use themes::rose_pine;
use workspace::workspace;
mod assets;

View File

@ -1,10 +1,10 @@
use crate::{
collab_panel::{collab_panel, CollabPanel},
theme::{theme, themed},
themes::rose_pine_dawn,
themes::{rose_pine, rose_pine_dawn},
};
use gpui3::{
div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, View,
div, img, svg, view, Context, Element, ParentElement, RootView, StyleHelpers, Styled, View,
ViewContext, WindowContext,
};
@ -25,8 +25,34 @@ impl Workspace {
}
}
fn hover_test(&self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
let theme = theme(cx);
div().size_full().child(
div()
.group("")
.w_full()
.h_5()
.mt_10()
.fill(theme.middle.warning.default.foreground)
.flex()
.flex_row()
.justify_center()
.child(
div()
.size_5()
.fill(theme.middle.negative.default.foreground)
.group_hover("")
.fill(theme.middle.positive.default.foreground)
.hover()
.fill(theme.middle.variant.default.foreground),
),
)
}
fn render(&mut self, cx: &mut ViewContext<Self>) -> impl Element<ViewState = Self> {
themed(rose_pine_dawn(), cx, |cx| {
themed(rose_pine(), cx, |cx| {
// self.hover_test(cx)
let theme = theme(cx);
div()
.size_full()
@ -47,8 +73,7 @@ impl Workspace {
.flex_row()
.overflow_hidden()
.child(self.left_panel.clone())
.child(div().h_full().flex_1())
.child(self.right_panel.clone()),
.child(div().h_full().flex_1()), // .child(self.right_panel.clone()),
)
.child(statusbar::statusbar(cx))
})