mirror of
https://github.com/zed-industries/zed.git
synced 2025-01-24 19:10:24 +00:00
Add hover styling support
This commit is contained in:
parent
1bc4f22373
commit
569d99a5a1
8 changed files with 53 additions and 22 deletions
|
@ -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<V: 'static, E: Element<V> + Styleable> {
|
||||
pub struct Hoverable<E: Styleable> {
|
||||
hovered: Cell<bool>,
|
||||
child_style: StyleRefinement,
|
||||
hovered_style: StyleRefinement,
|
||||
child: E,
|
||||
view_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
pub fn hoverable<V, E: Element<V> + Styleable>(mut child: E) -> Hoverable<V, E> {
|
||||
pub fn hoverable<E: Styleable>(mut child: E) -> Hoverable<E> {
|
||||
Hoverable {
|
||||
hovered: Cell::new(false),
|
||||
child_style: child.declared_style().clone(),
|
||||
hovered_style: Default::default(),
|
||||
child,
|
||||
view_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, E: Element<V> + Styleable> Styleable for Hoverable<V, E> {
|
||||
impl<E: Styleable> Styleable for Hoverable<E> {
|
||||
type Style = E::Style;
|
||||
|
||||
fn declared_style(&mut self) -> &mut crate::style::StyleRefinement {
|
||||
self.child.declared_style()
|
||||
&mut self.hovered_style
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
|
||||
impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<E> {
|
||||
type Layout = E::Layout;
|
||||
|
||||
fn layout(&mut self, view: &mut V, cx: &mut LayoutContext<V>) -> Result<Layout<V, Self::Layout>>
|
||||
|
@ -53,6 +51,10 @@ impl<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
|
|||
) 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<V: 'static, E: Element<V> + Styleable> Element<V> for Hoverable<V, E> {
|
|||
*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<E: Styleable<Style = Style>> StyleHelpers for Hoverable<E> {}
|
||||
|
|
|
@ -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<V: 'static>(theme: &ThemeColors) -> impl Element<V> {
|
|||
.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!")))
|
||||
}
|
||||
|
||||
|
|
|
@ -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<Self>
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
hoverable(self)
|
||||
}
|
||||
}
|
||||
|
||||
// Helpers methods that take and return mut self. This includes tailwind style methods for standard sizes etc.
|
||||
|
|
|
@ -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");
|
||||
|
|
|
@ -70,6 +70,7 @@ impl Window {
|
|||
pub fn new<V, F>(
|
||||
handle: AnyWindowHandle,
|
||||
platform_window: Box<dyn platform::Window>,
|
||||
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,
|
||||
};
|
||||
|
|
|
@ -75,6 +75,7 @@ pub trait Platform: Send + Sync {
|
|||
fn read_credentials(&self, url: &str) -> Result<Option<(String, Vec<u8>)>>;
|
||||
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;
|
||||
|
||||
|
|
|
@ -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 {
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue