mirror of
https://github.com/zed-industries/zed.git
synced 2025-02-06 02:37:21 +00:00
Checkpoint
This commit is contained in:
parent
ce30a689a0
commit
27fb381cca
82 changed files with 661 additions and 1907 deletions
|
@ -1,9 +1,9 @@
|
|||
use collections::{CommandPaletteFilter, HashMap};
|
||||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use gpui::{
|
||||
actions, div, Action, AppContext, Component, Div, EventEmitter, FocusHandle, Keystroke,
|
||||
ParentElement, Render, StatelessInteractive, Styled, View, ViewContext, VisualContext,
|
||||
WeakView, WindowContext,
|
||||
actions, div, prelude::*, Action, AppContext, Component, EventEmitter, FocusHandle, Keystroke,
|
||||
Node, ParentComponent, Render, Styled, View, ViewContext, VisualContext, WeakView,
|
||||
WindowContext,
|
||||
};
|
||||
use picker::{Picker, PickerDelegate};
|
||||
use std::{
|
||||
|
@ -77,7 +77,7 @@ impl Modal for CommandPalette {
|
|||
}
|
||||
|
||||
impl Render for CommandPalette {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
v_stack().w_96().child(self.picker.clone())
|
||||
|
@ -148,7 +148,7 @@ impl CommandPaletteDelegate {
|
|||
}
|
||||
|
||||
impl PickerDelegate for CommandPaletteDelegate {
|
||||
type ListItem = Div<Picker<Self>>;
|
||||
type ListItem = Node<Picker<Self>>;
|
||||
|
||||
fn placeholder_text(&self) -> Arc<str> {
|
||||
"Execute a command...".into()
|
||||
|
|
|
@ -39,12 +39,12 @@ use futures::FutureExt;
|
|||
use fuzzy::{StringMatch, StringMatchCandidate};
|
||||
use git::diff_hunk_to_display;
|
||||
use gpui::{
|
||||
action, actions, div, point, px, relative, rems, size, uniform_list, AnyElement, AppContext,
|
||||
AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
|
||||
action, actions, div, point, prelude::*, px, relative, rems, size, uniform_list, AnyElement,
|
||||
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
|
||||
EventEmitter, FocusHandle, FontFeatures, FontStyle, FontWeight, HighlightStyle, Hsla,
|
||||
InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render,
|
||||
StatelessInteractive, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View,
|
||||
ViewContext, VisualContext, WeakView, WindowContext,
|
||||
InputHandler, KeyContext, Model, MouseButton, ParentComponent, Pixels, Render, Styled,
|
||||
Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext,
|
||||
WeakView, WindowContext,
|
||||
};
|
||||
use highlight_matching_bracket::refresh_matching_bracket_highlights;
|
||||
use hover_popover::{hide_hover, HoverState};
|
||||
|
|
|
@ -2442,7 +2442,7 @@ enum Invisible {
|
|||
impl Element<Editor> for EditorElement {
|
||||
type ElementState = ();
|
||||
|
||||
fn id(&self) -> Option<gpui::ElementId> {
|
||||
fn element_id(&self) -> Option<gpui::ElementId> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -9,7 +9,7 @@ use collections::HashSet;
|
|||
use futures::future::try_join_all;
|
||||
use gpui::{
|
||||
div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter,
|
||||
FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View,
|
||||
FocusHandle, Model, ParentComponent, Pixels, SharedString, Styled, Subscription, Task, View,
|
||||
ViewContext, VisualContext, WeakView,
|
||||
};
|
||||
use language::{
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use editor::{display_map::ToDisplayPoint, scroll::autoscroll::Autoscroll, Editor};
|
||||
use gpui::{
|
||||
actions, div, AppContext, Div, EventEmitter, ParentElement, Render, SharedString,
|
||||
StatelessInteractive, Styled, Subscription, View, ViewContext, VisualContext, WindowContext,
|
||||
actions, div, prelude::*, AppContext, EventEmitter, Node, ParentComponent, Render,
|
||||
SharedString, Styled, Subscription, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
use text::{Bias, Point};
|
||||
use theme::ActiveTheme;
|
||||
|
@ -145,11 +145,11 @@ impl GoToLine {
|
|||
}
|
||||
|
||||
impl Render for GoToLine {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
modal(cx)
|
||||
.context("GoToLine")
|
||||
.key_context("GoToLine")
|
||||
.on_action(Self::cancel)
|
||||
.on_action(Self::confirm)
|
||||
.w_96()
|
||||
|
|
|
@ -8,7 +8,7 @@ use std::{any::Any, mem};
|
|||
pub trait Element<V: 'static> {
|
||||
type ElementState: 'static;
|
||||
|
||||
fn id(&self) -> Option<ElementId>;
|
||||
fn element_id(&self) -> Option<ElementId>;
|
||||
|
||||
/// Called to initialize this element for the current frame. If this
|
||||
/// element had state in a previous frame, it will be passed in for the 3rd argument.
|
||||
|
@ -38,7 +38,7 @@ pub trait Element<V: 'static> {
|
|||
#[derive(Deref, DerefMut, Default, Clone, Debug, Eq, PartialEq, Hash)]
|
||||
pub struct GlobalElementId(SmallVec<[ElementId; 32]>);
|
||||
|
||||
pub trait ParentElement<V: 'static> {
|
||||
pub trait ParentComponent<V: 'static> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]>;
|
||||
|
||||
fn child(mut self, child: impl Component<V>) -> Self
|
||||
|
@ -120,7 +120,7 @@ where
|
|||
E::ElementState: 'static,
|
||||
{
|
||||
fn initialize(&mut self, view_state: &mut V, cx: &mut ViewContext<V>) {
|
||||
let frame_state = if let Some(id) = self.element.id() {
|
||||
let frame_state = if let Some(id) = self.element.element_id() {
|
||||
cx.with_element_state(id, |element_state, cx| {
|
||||
let element_state = self.element.initialize(view_state, element_state, cx);
|
||||
((), element_state)
|
||||
|
@ -142,7 +142,7 @@ where
|
|||
frame_state: initial_frame_state,
|
||||
} => {
|
||||
frame_state = initial_frame_state;
|
||||
if let Some(id) = self.element.id() {
|
||||
if let Some(id) = self.element.element_id() {
|
||||
layout_id = cx.with_element_state(id, |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
let layout_id = self.element.layout(state, &mut element_state, cx);
|
||||
|
@ -181,7 +181,7 @@ where
|
|||
..
|
||||
} => {
|
||||
let bounds = cx.layout_bounds(layout_id);
|
||||
if let Some(id) = self.element.id() {
|
||||
if let Some(id) = self.element.element_id() {
|
||||
cx.with_element_state(id, |element_state, cx| {
|
||||
let mut element_state = element_state.unwrap();
|
||||
self.element
|
||||
|
@ -351,7 +351,7 @@ where
|
|||
{
|
||||
type ElementState = AnyElement<V>;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -1,12 +1,13 @@
|
|||
mod div;
|
||||
// mod div;
|
||||
mod img;
|
||||
mod node;
|
||||
mod svg;
|
||||
mod text;
|
||||
mod uniform_list;
|
||||
|
||||
pub use div::*;
|
||||
// pub use div::*;
|
||||
pub use img::*;
|
||||
pub use node::*;
|
||||
pub use svg::*;
|
||||
pub use text::*;
|
||||
pub use uniform_list::*;
|
||||
|
|
|
@ -55,16 +55,6 @@ where
|
|||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
pub fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||
self.group = Some(group.into());
|
||||
self
|
||||
}
|
||||
|
||||
pub fn z_index(mut self, z_index: u32) -> Self {
|
||||
self.base_style.z_index = Some(z_index);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn context<C>(mut self, context: C) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
|
@ -77,22 +67,6 @@ where
|
|||
self
|
||||
}
|
||||
|
||||
pub fn overflow_hidden(mut self) -> Self {
|
||||
self.base_style.overflow.x = Some(Overflow::Hidden);
|
||||
self.base_style.overflow.y = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_hidden_x(mut self) -> Self {
|
||||
self.base_style.overflow.x = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_hidden_y(mut self) -> Self {
|
||||
self.base_style.overflow.y = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn compute_style(
|
||||
&self,
|
||||
bounds: Bounds<Pixels>,
|
||||
|
@ -135,22 +109,6 @@ impl<V: 'static> Div<V, StatefulInteractivity<V>, NonFocusableKeyDispatch> {
|
|||
base_style: self.base_style,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn overflow_scroll(mut self) -> Self {
|
||||
self.base_style.overflow.x = Some(Overflow::Scroll);
|
||||
self.base_style.overflow.y = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_x_scroll(mut self) -> Self {
|
||||
self.base_style.overflow.x = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
pub fn overflow_y_scroll(mut self) -> Self {
|
||||
self.base_style.overflow.y = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Div<V, StatelessInteractivity<V>, NonFocusableKeyDispatch> {
|
||||
|
|
|
@ -1,35 +1,28 @@
|
|||
use crate::{
|
||||
div, AnyElement, BorrowWindow, Bounds, Component, Div, DivState, Element, ElementId,
|
||||
ElementInteractivity, FocusListeners, Focusable, FocusableKeyDispatch, KeyDispatch, LayoutId,
|
||||
NonFocusableKeyDispatch, Pixels, SharedString, StatefulInteractive, StatefulInteractivity,
|
||||
StatelessInteractive, StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
||||
AnyElement, BorrowWindow, Bounds, Component, Element, InteractiveComponent,
|
||||
InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement,
|
||||
Styled, ViewContext,
|
||||
};
|
||||
use futures::FutureExt;
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Img<
|
||||
V: 'static,
|
||||
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||
F: KeyDispatch<V> = NonFocusableKeyDispatch,
|
||||
> {
|
||||
base: Div<V, I, F>,
|
||||
pub struct Img<V: 'static> {
|
||||
interactivity: Interactivity<V>,
|
||||
uri: Option<SharedString>,
|
||||
grayscale: bool,
|
||||
}
|
||||
|
||||
pub fn img<V: 'static>() -> Img<V, StatelessInteractivity<V>, NonFocusableKeyDispatch> {
|
||||
pub fn img<V: 'static>() -> Img<V> {
|
||||
Img {
|
||||
base: div(),
|
||||
interactivity: Interactivity::default(),
|
||||
uri: None,
|
||||
grayscale: false,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Img<V, I, F>
|
||||
impl<V> Img<V>
|
||||
where
|
||||
V: 'static,
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
pub fn uri(mut self, uri: impl Into<SharedString>) -> Self {
|
||||
self.uri = Some(uri.into());
|
||||
|
@ -42,38 +35,17 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, F> Img<V, StatelessInteractivity<V>, F>
|
||||
where
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Img<V, StatefulInteractivity<V>, F> {
|
||||
Img {
|
||||
base: self.base.id(id),
|
||||
uri: self.uri,
|
||||
grayscale: self.grayscale,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Component<V> for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
impl<V> Component<V> for Img<V> {
|
||||
fn render(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Element<V> for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
type ElementState = DivState;
|
||||
impl<V> Element<V> for Img<V> {
|
||||
type ElementState = InteractiveElementState;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
self.base.id()
|
||||
fn element_id(&self) -> Option<crate::ElementId> {
|
||||
self.interactivity.element_id.clone()
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
|
@ -82,7 +54,7 @@ where
|
|||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
self.base.initialize(view_state, element_state, cx)
|
||||
self.interactivity.initialize(element_state, cx)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
@ -91,7 +63,9 @@ where
|
|||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> LayoutId {
|
||||
self.base.layout(view_state, element_state, cx)
|
||||
self.interactivity.layout(element_state, cx, |style, cx| {
|
||||
cx.request_layout(&style, None)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
@ -101,86 +75,50 @@ where
|
|||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
cx.with_z_index(0, |cx| {
|
||||
self.base.paint(bounds, view, element_state, cx);
|
||||
});
|
||||
self.interactivity.paint(
|
||||
bounds,
|
||||
bounds.size,
|
||||
element_state,
|
||||
cx,
|
||||
|style, scroll_offset, cx| {
|
||||
let corner_radii = style.corner_radii;
|
||||
|
||||
let style = self.base.compute_style(bounds, element_state, cx);
|
||||
let corner_radii = style.corner_radii;
|
||||
|
||||
if let Some(uri) = self.uri.clone() {
|
||||
// eprintln!(">>> image_cache.get({uri}");
|
||||
let image_future = cx.image_cache.get(uri.clone());
|
||||
// eprintln!("<<< image_cache.get({uri}");
|
||||
if let Some(data) = image_future
|
||||
.clone()
|
||||
.now_or_never()
|
||||
.and_then(ResultExt::log_err)
|
||||
{
|
||||
let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||
cx.with_z_index(1, |cx| {
|
||||
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
||||
.log_err()
|
||||
});
|
||||
} else {
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
if image_future.await.log_err().is_some() {
|
||||
cx.on_next_frame(|cx| cx.notify());
|
||||
if let Some(uri) = self.uri.clone() {
|
||||
// eprintln!(">>> image_cache.get({uri}");
|
||||
let image_future = cx.image_cache.get(uri.clone());
|
||||
// eprintln!("<<< image_cache.get({uri}");
|
||||
if let Some(data) = image_future
|
||||
.clone()
|
||||
.now_or_never()
|
||||
.and_then(ResultExt::log_err)
|
||||
{
|
||||
let corner_radii = corner_radii.to_pixels(bounds.size, cx.rem_size());
|
||||
cx.with_z_index(1, |cx| {
|
||||
cx.paint_image(bounds, corner_radii, data, self.grayscale)
|
||||
.log_err()
|
||||
});
|
||||
} else {
|
||||
cx.spawn(|_, mut cx| async move {
|
||||
if image_future.await.log_err().is_some() {
|
||||
cx.on_next_frame(|cx| cx.notify());
|
||||
}
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
})
|
||||
.detach()
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Styled for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
impl<V> Styled for Img<V> {
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.base.style()
|
||||
&mut self.interactivity.base_style
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> StatelessInteractive<V> for Img<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self.base.stateless_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, F> StatefulInteractive<V> for Img<V, StatefulInteractivity<V>, F>
|
||||
where
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||
self.base.stateful_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I> Focusable<V> for Img<V, I, FocusableKeyDispatch<V>>
|
||||
where
|
||||
V: 'static,
|
||||
I: ElementInteractivity<V>,
|
||||
{
|
||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||
self.base.focus_listeners()
|
||||
}
|
||||
|
||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_style(style)
|
||||
}
|
||||
|
||||
fn set_focus_in_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_in_style(style)
|
||||
}
|
||||
|
||||
fn set_in_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_in_focus_style(style)
|
||||
impl<V> InteractiveComponent<V> for Img<V> {
|
||||
fn interactivity(&mut self) -> &mut Interactivity<V> {
|
||||
&mut self.interactivity
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,9 +1,9 @@
|
|||
use crate::{
|
||||
point, px, Action, AnyDrag, AnyElement, AnyTooltip, AnyView, AppContext, BorrowAppContext,
|
||||
BorrowWindow, Bounds, ClickEvent, DispatchPhase, Element, ElementId, FocusEvent, FocusHandle,
|
||||
KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent, MouseMoveEvent,
|
||||
MouseUpEvent, Pixels, Point, Render, ScrollWheelEvent, SharedString, Size, Style,
|
||||
StyleRefinement, Styled, Task, View, ViewContext, Visibility,
|
||||
BorrowWindow, Bounds, ClickEvent, Component, DispatchPhase, Element, ElementId, FocusEvent,
|
||||
FocusHandle, KeyContext, KeyDownEvent, KeyUpEvent, LayoutId, MouseButton, MouseDownEvent,
|
||||
MouseMoveEvent, MouseUpEvent, ParentComponent, Pixels, Point, Render, ScrollWheelEvent,
|
||||
SharedString, Size, Style, StyleRefinement, Styled, Task, View, ViewContext, Visibility,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
|
@ -32,6 +32,11 @@ pub struct GroupStyle {
|
|||
pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
|
||||
fn interactivity(&mut self) -> &mut Interactivity<V>;
|
||||
|
||||
fn group(mut self, group: impl Into<SharedString>) -> Self {
|
||||
self.interactivity().group = Some(group.into());
|
||||
self
|
||||
}
|
||||
|
||||
fn id(mut self, id: impl Into<ElementId>) -> Stateful<V, Self> {
|
||||
self.interactivity().element_id = Some(id.into());
|
||||
|
||||
|
@ -41,9 +46,9 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
|
|||
}
|
||||
}
|
||||
|
||||
fn track_focus(mut self, focus_handle: FocusHandle) -> Focusable<V, Self> {
|
||||
fn track_focus(mut self, focus_handle: &FocusHandle) -> Focusable<V, Self> {
|
||||
self.interactivity().focusable = true;
|
||||
self.interactivity().tracked_focus_handle = Some(focus_handle);
|
||||
self.interactivity().tracked_focus_handle = Some(focus_handle.clone());
|
||||
Focusable {
|
||||
element: self,
|
||||
view_type: PhantomData,
|
||||
|
@ -269,8 +274,27 @@ pub trait InteractiveComponent<V: 'static>: Sized + Element<V> {
|
|||
}
|
||||
|
||||
pub trait StatefulInteractiveComponent<V: 'static, E: Element<V>>: InteractiveComponent<V> {
|
||||
fn focusable(mut self) -> Self {
|
||||
fn focusable(mut self) -> Focusable<V, Self> {
|
||||
self.interactivity().focusable = true;
|
||||
Focusable {
|
||||
element: self,
|
||||
view_type: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
fn overflow_scroll(mut self) -> Self {
|
||||
self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
|
||||
self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
fn overflow_x_scroll(mut self) -> Self {
|
||||
self.interactivity().base_style.overflow.x = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
fn overflow_y_scroll(mut self) -> Self {
|
||||
self.interactivity().base_style.overflow.y = Some(Overflow::Scroll);
|
||||
self
|
||||
}
|
||||
|
||||
|
@ -514,16 +538,16 @@ pub type KeyUpListener<V> =
|
|||
pub type ActionListener<V> =
|
||||
Box<dyn Fn(&mut V, &dyn Any, DispatchPhase, &mut ViewContext<V>) + 'static>;
|
||||
|
||||
pub fn node<V: 'static>() -> Node<V> {
|
||||
pub fn div<V: 'static>() -> Node<V> {
|
||||
Node {
|
||||
interactivity: Interactivity::default(),
|
||||
children: Vec::default(),
|
||||
children: SmallVec::default(),
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Node<V> {
|
||||
interactivity: Interactivity<V>,
|
||||
children: Vec<AnyElement<V>>,
|
||||
children: SmallVec<[AnyElement<V>; 2]>,
|
||||
}
|
||||
|
||||
impl<V> Styled for Node<V> {
|
||||
|
@ -538,10 +562,16 @@ impl<V: 'static> InteractiveComponent<V> for Node<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ParentComponent<V> for Node<V> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
&mut self.children
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Element<V> for Node<V> {
|
||||
type ElementState = NodeState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
self.interactivity.element_id.clone()
|
||||
}
|
||||
|
||||
|
@ -641,48 +671,54 @@ impl<V: 'static> Element<V> for Node<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Component<V> for Node<V> {
|
||||
fn render(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
pub struct NodeState {
|
||||
child_layout_ids: SmallVec<[LayoutId; 4]>,
|
||||
interactive_state: InteractiveElementState,
|
||||
}
|
||||
|
||||
pub struct Interactivity<V> {
|
||||
element_id: Option<ElementId>,
|
||||
key_context: KeyContext,
|
||||
focusable: bool,
|
||||
tracked_focus_handle: Option<FocusHandle>,
|
||||
focus_listeners: FocusListeners<V>,
|
||||
scroll_offset: Point<Pixels>,
|
||||
group: Option<SharedString>,
|
||||
base_style: StyleRefinement,
|
||||
focus_style: StyleRefinement,
|
||||
focus_in_style: StyleRefinement,
|
||||
in_focus_style: StyleRefinement,
|
||||
hover_style: StyleRefinement,
|
||||
group_hover_style: Option<GroupStyle>,
|
||||
active_style: StyleRefinement,
|
||||
group_active_style: Option<GroupStyle>,
|
||||
drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
|
||||
group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
|
||||
mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
|
||||
mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
|
||||
mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
|
||||
scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
|
||||
key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
|
||||
key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
|
||||
action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
|
||||
drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
|
||||
click_listeners: SmallVec<[ClickListener<V>; 2]>,
|
||||
drag_listener: Option<DragListener<V>>,
|
||||
hover_listener: Option<HoverListener<V>>,
|
||||
tooltip_builder: Option<TooltipBuilder<V>>,
|
||||
pub element_id: Option<ElementId>,
|
||||
pub key_context: KeyContext,
|
||||
pub focusable: bool,
|
||||
pub tracked_focus_handle: Option<FocusHandle>,
|
||||
pub focus_listeners: FocusListeners<V>,
|
||||
// pub scroll_offset: Point<Pixels>,
|
||||
pub group: Option<SharedString>,
|
||||
pub base_style: StyleRefinement,
|
||||
pub focus_style: StyleRefinement,
|
||||
pub focus_in_style: StyleRefinement,
|
||||
pub in_focus_style: StyleRefinement,
|
||||
pub hover_style: StyleRefinement,
|
||||
pub group_hover_style: Option<GroupStyle>,
|
||||
pub active_style: StyleRefinement,
|
||||
pub group_active_style: Option<GroupStyle>,
|
||||
pub drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
|
||||
pub group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
|
||||
pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
|
||||
pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
|
||||
pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
|
||||
pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
|
||||
pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
|
||||
pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
|
||||
pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
|
||||
pub drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
|
||||
pub click_listeners: SmallVec<[ClickListener<V>; 2]>,
|
||||
pub drag_listener: Option<DragListener<V>>,
|
||||
pub hover_listener: Option<HoverListener<V>>,
|
||||
pub tooltip_builder: Option<TooltipBuilder<V>>,
|
||||
}
|
||||
|
||||
impl<V> Interactivity<V>
|
||||
where
|
||||
V: 'static,
|
||||
{
|
||||
fn initialize(
|
||||
pub fn initialize(
|
||||
&mut self,
|
||||
element_state: Option<InteractiveElementState>,
|
||||
cx: &mut ViewContext<V>,
|
||||
|
@ -703,7 +739,7 @@ where
|
|||
element_state
|
||||
}
|
||||
|
||||
fn layout(
|
||||
pub fn layout(
|
||||
&mut self,
|
||||
element_state: &mut InteractiveElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
|
@ -719,7 +755,7 @@ where
|
|||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
pub fn paint(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
content_size: Size<Pixels>,
|
||||
|
@ -996,6 +1032,11 @@ where
|
|||
GroupBounds::push(group, bounds, cx);
|
||||
}
|
||||
|
||||
let scroll_offset = element_state
|
||||
.scroll_offset
|
||||
.as_ref()
|
||||
.map(|scroll_offset| *scroll_offset.lock());
|
||||
|
||||
cx.with_element_id(self.element_id.clone(), |cx| {
|
||||
cx.with_key_dispatch(
|
||||
self.key_context.clone(),
|
||||
|
@ -1026,7 +1067,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
f(style, self.scroll_offset, cx)
|
||||
f(style, scroll_offset.unwrap_or_default(), cx)
|
||||
},
|
||||
);
|
||||
});
|
||||
|
@ -1036,7 +1077,7 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
fn compute_style(
|
||||
pub fn compute_style(
|
||||
&self,
|
||||
bounds: Option<Bounds<Pixels>>,
|
||||
element_state: &mut InteractiveElementState,
|
||||
|
@ -1118,7 +1159,7 @@ impl<V: 'static> Default for Interactivity<V> {
|
|||
focusable: false,
|
||||
tracked_focus_handle: None,
|
||||
focus_listeners: SmallVec::default(),
|
||||
scroll_offset: Point::default(),
|
||||
// scroll_offset: Point::default(),
|
||||
group: None,
|
||||
base_style: StyleRefinement::default(),
|
||||
focus_style: StyleRefinement::default(),
|
||||
|
@ -1148,15 +1189,15 @@ impl<V: 'static> Default for Interactivity<V> {
|
|||
|
||||
#[derive(Default)]
|
||||
pub struct InteractiveElementState {
|
||||
focus_handle: Option<FocusHandle>,
|
||||
clicked_state: Arc<Mutex<ElementClickedState>>,
|
||||
hover_state: Arc<Mutex<bool>>,
|
||||
pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
||||
active_tooltip: Arc<Mutex<Option<ActiveTooltip>>>,
|
||||
pub focus_handle: Option<FocusHandle>,
|
||||
pub clicked_state: Arc<Mutex<ElementClickedState>>,
|
||||
pub hover_state: Arc<Mutex<bool>>,
|
||||
pub pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
pub scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
||||
pub active_tooltip: Arc<Mutex<Option<ActiveTooltip>>>,
|
||||
}
|
||||
|
||||
struct ActiveTooltip {
|
||||
pub struct ActiveTooltip {
|
||||
#[allow(unused)] // used to drop the task
|
||||
waiting: Option<Task<()>>,
|
||||
tooltip: Option<AnyTooltip>,
|
||||
|
@ -1164,7 +1205,7 @@ struct ActiveTooltip {
|
|||
|
||||
/// Whether or not the element or a group that contains it is clicked by the mouse.
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
struct ElementClickedState {
|
||||
pub struct ElementClickedState {
|
||||
pub group: bool,
|
||||
pub element: bool,
|
||||
}
|
||||
|
@ -1222,6 +1263,16 @@ impl<V: 'static, E: StatefulInteractiveComponent<V, E>> StatefulInteractiveCompo
|
|||
{
|
||||
}
|
||||
|
||||
impl<V, E> Styled for Focusable<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
E: Styled,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.element.style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, E> Element<V> for Focusable<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
|
@ -1229,8 +1280,8 @@ where
|
|||
{
|
||||
type ElementState = E::ElementState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.element.id()
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
self.element.element_id()
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
|
@ -1262,11 +1313,41 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, E> Component<V> for Focusable<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
E: 'static + Element<V>,
|
||||
{
|
||||
fn render(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, E> ParentComponent<V> for Focusable<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
E: ParentComponent<V>,
|
||||
{
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
self.element.children_mut()
|
||||
}
|
||||
}
|
||||
|
||||
pub struct Stateful<V, E> {
|
||||
element: E,
|
||||
view_type: PhantomData<V>,
|
||||
}
|
||||
|
||||
impl<V, E> Styled for Stateful<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
E: Styled,
|
||||
{
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.element.style()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, E> StatefulInteractiveComponent<V, E> for Stateful<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
|
@ -1294,8 +1375,8 @@ where
|
|||
{
|
||||
type ElementState = E::ElementState;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
self.element.id()
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
self.element.element_id()
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
|
@ -1326,3 +1407,23 @@ where
|
|||
self.element.paint(bounds, view_state, element_state, cx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, E> Component<V> for Stateful<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
E: 'static + Element<V>,
|
||||
{
|
||||
fn render(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, E> ParentComponent<V> for Stateful<V, E>
|
||||
where
|
||||
V: 'static,
|
||||
E: ParentComponent<V>,
|
||||
{
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
self.element.children_mut()
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,69 +1,40 @@
|
|||
use crate::{
|
||||
div, AnyElement, Bounds, Component, Div, DivState, Element, ElementId, ElementInteractivity,
|
||||
FocusListeners, Focusable, FocusableKeyDispatch, KeyDispatch, LayoutId,
|
||||
NonFocusableKeyDispatch, Pixels, SharedString, StatefulInteractive, StatefulInteractivity,
|
||||
StatelessInteractive, StatelessInteractivity, StyleRefinement, Styled, ViewContext,
|
||||
AnyElement, Bounds, Component, Element, ElementId, InteractiveComponent,
|
||||
InteractiveElementState, Interactivity, LayoutId, Pixels, SharedString, StyleRefinement,
|
||||
Styled, ViewContext,
|
||||
};
|
||||
use util::ResultExt;
|
||||
|
||||
pub struct Svg<
|
||||
V: 'static,
|
||||
I: ElementInteractivity<V> = StatelessInteractivity<V>,
|
||||
F: KeyDispatch<V> = NonFocusableKeyDispatch,
|
||||
> {
|
||||
base: Div<V, I, F>,
|
||||
pub struct Svg<V: 'static> {
|
||||
interactivity: Interactivity<V>,
|
||||
path: Option<SharedString>,
|
||||
}
|
||||
|
||||
pub fn svg<V: 'static>() -> Svg<V, StatelessInteractivity<V>, NonFocusableKeyDispatch> {
|
||||
pub fn svg<V: 'static>() -> Svg<V> {
|
||||
Svg {
|
||||
base: div(),
|
||||
interactivity: Interactivity::default(),
|
||||
path: None,
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
impl<V> Svg<V> {
|
||||
pub fn path(mut self, path: impl Into<SharedString>) -> Self {
|
||||
self.path = Some(path.into());
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, F> Svg<V, StatelessInteractivity<V>, F>
|
||||
where
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
pub fn id(self, id: impl Into<ElementId>) -> Svg<V, StatefulInteractivity<V>, F> {
|
||||
Svg {
|
||||
base: self.base.id(id),
|
||||
path: self.path,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Component<V> for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
impl<V> Component<V> for Svg<V> {
|
||||
fn render(self) -> AnyElement<V> {
|
||||
AnyElement::new(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Element<V> for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
type ElementState = DivState;
|
||||
impl<V> Element<V> for Svg<V> {
|
||||
type ElementState = InteractiveElementState;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
self.base.id()
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
self.interactivity.element_id.clone()
|
||||
}
|
||||
|
||||
fn initialize(
|
||||
|
@ -72,7 +43,7 @@ where
|
|||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
self.base.initialize(view_state, element_state, cx)
|
||||
self.interactivity.initialize(element_state, cx)
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
@ -81,7 +52,9 @@ where
|
|||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> LayoutId {
|
||||
self.base.layout(view_state, element_state, cx)
|
||||
self.interactivity.layout(element_state, cx, |style, cx| {
|
||||
cx.request_layout(&style, None)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
|
@ -93,65 +66,23 @@ where
|
|||
) where
|
||||
Self: Sized,
|
||||
{
|
||||
self.base.paint(bounds, view, element_state, cx);
|
||||
let color = self
|
||||
.base
|
||||
.compute_style(bounds, element_state, cx)
|
||||
.text
|
||||
.color;
|
||||
if let Some((path, color)) = self.path.as_ref().zip(color) {
|
||||
cx.paint_svg(bounds, path.clone(), color).log_err();
|
||||
}
|
||||
self.interactivity
|
||||
.paint(bounds, bounds.size, element_state, cx, |style, _, cx| {
|
||||
if let Some((path, color)) = self.path.as_ref().zip(style.text.color) {
|
||||
cx.paint_svg(bounds, path.clone(), color).log_err();
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> Styled for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
impl<V> Styled for Svg<V> {
|
||||
fn style(&mut self) -> &mut StyleRefinement {
|
||||
self.base.style()
|
||||
&mut self.interactivity.base_style
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> StatelessInteractive<V> for Svg<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self.base.stateless_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V, F> StatefulInteractive<V> for Svg<V, StatefulInteractivity<V>, F>
|
||||
where
|
||||
V: 'static,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||
self.base.stateful_interactivity()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static, I> Focusable<V> for Svg<V, I, FocusableKeyDispatch<V>>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
{
|
||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V> {
|
||||
self.base.focus_listeners()
|
||||
}
|
||||
|
||||
fn set_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_style(style)
|
||||
}
|
||||
|
||||
fn set_focus_in_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_focus_in_style(style)
|
||||
}
|
||||
|
||||
fn set_in_focus_style(&mut self, style: StyleRefinement) {
|
||||
self.base.set_in_focus_style(style)
|
||||
impl<V> InteractiveComponent<V> for Svg<V> {
|
||||
fn interactivity(&mut self) -> &mut Interactivity<V> {
|
||||
&mut self.interactivity
|
||||
}
|
||||
}
|
||||
|
|
|
@ -53,7 +53,7 @@ impl<V: 'static> Component<V> for Text<V> {
|
|||
impl<V: 'static> Element<V> for Text<V> {
|
||||
type ElementState = Arc<Mutex<Option<TextElementState>>>;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
fn element_id(&self) -> Option<crate::ElementId> {
|
||||
None
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,23 @@
|
|||
use crate::{
|
||||
point, px, size, AnyElement, AvailableSpace, BorrowWindow, Bounds, Component, Element,
|
||||
ElementId, ElementInteractivity, InteractiveElementState, LayoutId, Pixels, Point, Size,
|
||||
StatefulInteractive, StatefulInteractivity, StatelessInteractive, StatelessInteractivity,
|
||||
StyleRefinement, Styled, ViewContext,
|
||||
ElementId, InteractiveComponent, InteractiveElementState, Interactivity, LayoutId, Pixels,
|
||||
Point, Size, StyleRefinement, Styled, ViewContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use smallvec::SmallVec;
|
||||
use std::{cmp, ops::Range, sync::Arc};
|
||||
use std::{cmp, mem, ops::Range, sync::Arc};
|
||||
use taffy::style::Overflow;
|
||||
|
||||
/// uniform_list provides lazy rendering for a set of items that are of uniform height.
|
||||
/// When rendered into a container with overflow-y: hidden and a fixed (or max) height,
|
||||
/// uniform_list will only render the visibile subset of items.
|
||||
pub fn uniform_list<Id, V, C>(
|
||||
id: Id,
|
||||
pub fn uniform_list<I, V, C>(
|
||||
id: I,
|
||||
item_count: usize,
|
||||
f: impl 'static + Fn(&mut V, Range<usize>, &mut ViewContext<V>) -> SmallVec<[C; 64]>,
|
||||
) -> UniformList<V>
|
||||
where
|
||||
Id: Into<ElementId>,
|
||||
I: Into<ElementId>,
|
||||
V: 'static,
|
||||
C: Component<V>,
|
||||
{
|
||||
|
@ -37,7 +36,10 @@ where
|
|||
.map(|component| component.render())
|
||||
.collect()
|
||||
}),
|
||||
interactivity: StatefulInteractivity::new(id, StatelessInteractivity::default()),
|
||||
interactivity: Interactivity {
|
||||
element_id: Some(id.into()),
|
||||
..Default::default()
|
||||
},
|
||||
scroll_handle: None,
|
||||
}
|
||||
}
|
||||
|
@ -54,7 +56,7 @@ pub struct UniformList<V: 'static> {
|
|||
&'a mut ViewContext<V>,
|
||||
) -> SmallVec<[AnyElement<V>; 64]>,
|
||||
>,
|
||||
interactivity: StatefulInteractivity<V>,
|
||||
interactivity: Interactivity<V>,
|
||||
scroll_handle: Option<UniformListScrollHandle>,
|
||||
}
|
||||
|
||||
|
@ -103,7 +105,7 @@ pub struct UniformListState {
|
|||
impl<V: 'static> Element<V> for UniformList<V> {
|
||||
type ElementState = UniformListState;
|
||||
|
||||
fn id(&self) -> Option<crate::ElementId> {
|
||||
fn element_id(&self) -> Option<crate::ElementId> {
|
||||
Some(self.id.clone())
|
||||
}
|
||||
|
||||
|
@ -113,13 +115,18 @@ impl<V: 'static> Element<V> for UniformList<V> {
|
|||
element_state: Option<Self::ElementState>,
|
||||
cx: &mut ViewContext<V>,
|
||||
) -> Self::ElementState {
|
||||
element_state.unwrap_or_else(|| {
|
||||
if let Some(mut element_state) = element_state {
|
||||
element_state.interactive = self
|
||||
.interactivity
|
||||
.initialize(Some(element_state.interactive), cx);
|
||||
element_state
|
||||
} else {
|
||||
let item_size = self.measure_item(view_state, None, cx);
|
||||
UniformListState {
|
||||
interactive: InteractiveElementState::default(),
|
||||
interactive: self.interactivity.initialize(None, cx),
|
||||
item_size,
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fn layout(
|
||||
|
@ -132,35 +139,44 @@ impl<V: 'static> Element<V> for UniformList<V> {
|
|||
let item_size = element_state.item_size;
|
||||
let rem_size = cx.rem_size();
|
||||
|
||||
cx.request_measured_layout(
|
||||
self.computed_style(),
|
||||
rem_size,
|
||||
move |known_dimensions: Size<Option<Pixels>>, available_space: Size<AvailableSpace>| {
|
||||
let desired_height = item_size.height * max_items;
|
||||
let width = known_dimensions
|
||||
.width
|
||||
.unwrap_or(match available_space.width {
|
||||
AvailableSpace::Definite(x) => x,
|
||||
AvailableSpace::MinContent | AvailableSpace::MaxContent => item_size.width,
|
||||
});
|
||||
let height = match available_space.height {
|
||||
AvailableSpace::Definite(x) => desired_height.min(x),
|
||||
AvailableSpace::MinContent | AvailableSpace::MaxContent => desired_height,
|
||||
};
|
||||
size(width, height)
|
||||
},
|
||||
)
|
||||
self.interactivity
|
||||
.layout(&mut element_state.interactive, cx, |style, cx| {
|
||||
cx.request_measured_layout(
|
||||
style,
|
||||
rem_size,
|
||||
move |known_dimensions: Size<Option<Pixels>>,
|
||||
available_space: Size<AvailableSpace>| {
|
||||
let desired_height = item_size.height * max_items;
|
||||
let width = known_dimensions
|
||||
.width
|
||||
.unwrap_or(match available_space.width {
|
||||
AvailableSpace::Definite(x) => x,
|
||||
AvailableSpace::MinContent | AvailableSpace::MaxContent => {
|
||||
item_size.width
|
||||
}
|
||||
});
|
||||
let height = match available_space.height {
|
||||
AvailableSpace::Definite(x) => desired_height.min(x),
|
||||
AvailableSpace::MinContent | AvailableSpace::MaxContent => {
|
||||
desired_height
|
||||
}
|
||||
};
|
||||
size(width, height)
|
||||
},
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
fn paint(
|
||||
&mut self,
|
||||
bounds: crate::Bounds<crate::Pixels>,
|
||||
bounds: Bounds<crate::Pixels>,
|
||||
view_state: &mut V,
|
||||
element_state: &mut Self::ElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let style = self.computed_style();
|
||||
|
||||
let style =
|
||||
self.interactivity
|
||||
.compute_style(Some(bounds), &mut element_state.interactive, cx);
|
||||
let border = style.border_widths.to_pixels(cx.rem_size());
|
||||
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||
|
||||
|
@ -170,74 +186,75 @@ impl<V: 'static> Element<V> for UniformList<V> {
|
|||
- point(border.right + padding.right, border.bottom + padding.bottom),
|
||||
);
|
||||
|
||||
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
||||
style.paint(bounds, cx);
|
||||
let item_size = element_state.item_size;
|
||||
let content_size = Size {
|
||||
width: padded_bounds.size.width,
|
||||
height: item_size.height * self.item_count,
|
||||
};
|
||||
|
||||
let content_size;
|
||||
if self.item_count > 0 {
|
||||
let item_height = self
|
||||
.measure_item(view_state, Some(padded_bounds.size.width), cx)
|
||||
.height;
|
||||
if let Some(scroll_handle) = self.scroll_handle.clone() {
|
||||
scroll_handle.0.lock().replace(ScrollHandleState {
|
||||
item_height,
|
||||
list_height: padded_bounds.size.height,
|
||||
scroll_offset: element_state.interactive.track_scroll_offset(),
|
||||
});
|
||||
}
|
||||
let visible_item_count = if item_height > px(0.) {
|
||||
(padded_bounds.size.height / item_height).ceil() as usize + 1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
let scroll_offset = element_state
|
||||
.interactive
|
||||
.scroll_offset()
|
||||
.map_or((0.0).into(), |offset| offset.y);
|
||||
let first_visible_element_ix = (-scroll_offset / item_height).floor() as usize;
|
||||
let visible_range = first_visible_element_ix
|
||||
..cmp::min(
|
||||
first_visible_element_ix + visible_item_count,
|
||||
self.item_count,
|
||||
);
|
||||
let mut interactivity = mem::take(&mut self.interactivity);
|
||||
let shared_scroll_offset = element_state.interactive.scroll_offset.clone().unwrap();
|
||||
|
||||
let mut items = (self.render_items)(view_state, visible_range.clone(), cx);
|
||||
interactivity.paint(
|
||||
bounds,
|
||||
content_size,
|
||||
&mut element_state.interactive,
|
||||
cx,
|
||||
|style, scroll_offset, cx| {
|
||||
let border = style.border_widths.to_pixels(cx.rem_size());
|
||||
let padding = style.padding.to_pixels(bounds.size.into(), cx.rem_size());
|
||||
|
||||
content_size = Size {
|
||||
width: padded_bounds.size.width,
|
||||
height: item_height * self.item_count,
|
||||
};
|
||||
|
||||
cx.with_z_index(1, |cx| {
|
||||
for (item, ix) in items.iter_mut().zip(visible_range) {
|
||||
let item_origin =
|
||||
padded_bounds.origin + point(px(0.), item_height * ix + scroll_offset);
|
||||
let available_space = size(
|
||||
AvailableSpace::Definite(padded_bounds.size.width),
|
||||
AvailableSpace::Definite(item_height),
|
||||
);
|
||||
item.draw(item_origin, available_space, view_state, cx);
|
||||
}
|
||||
});
|
||||
} else {
|
||||
content_size = Size {
|
||||
width: bounds.size.width,
|
||||
height: px(0.),
|
||||
};
|
||||
}
|
||||
|
||||
let overflow = point(style.overflow.x, Overflow::Scroll);
|
||||
|
||||
cx.with_z_index(0, |cx| {
|
||||
self.interactivity.handle_events(
|
||||
bounds,
|
||||
content_size,
|
||||
overflow,
|
||||
&mut element_state.interactive,
|
||||
cx,
|
||||
let padded_bounds = Bounds::from_corners(
|
||||
bounds.origin + point(border.left + padding.left, border.top + padding.top),
|
||||
bounds.lower_right()
|
||||
- point(border.right + padding.right, border.bottom + padding.bottom),
|
||||
);
|
||||
});
|
||||
})
|
||||
|
||||
cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
|
||||
style.paint(bounds, cx);
|
||||
|
||||
if self.item_count > 0 {
|
||||
let item_height = self
|
||||
.measure_item(view_state, Some(padded_bounds.size.width), cx)
|
||||
.height;
|
||||
if let Some(scroll_handle) = self.scroll_handle.clone() {
|
||||
scroll_handle.0.lock().replace(ScrollHandleState {
|
||||
item_height,
|
||||
list_height: padded_bounds.size.height,
|
||||
scroll_offset: shared_scroll_offset,
|
||||
});
|
||||
}
|
||||
let visible_item_count = if item_height > px(0.) {
|
||||
(padded_bounds.size.height / item_height).ceil() as usize + 1
|
||||
} else {
|
||||
0
|
||||
};
|
||||
|
||||
let first_visible_element_ix =
|
||||
(-scroll_offset.y / item_height).floor() as usize;
|
||||
let visible_range = first_visible_element_ix
|
||||
..cmp::min(
|
||||
first_visible_element_ix + visible_item_count,
|
||||
self.item_count,
|
||||
);
|
||||
|
||||
let mut items = (self.render_items)(view_state, visible_range.clone(), cx);
|
||||
cx.with_z_index(1, |cx| {
|
||||
for (item, ix) in items.iter_mut().zip(visible_range) {
|
||||
let item_origin = padded_bounds.origin
|
||||
+ point(px(0.), item_height * ix + scroll_offset.y);
|
||||
let available_space = size(
|
||||
AvailableSpace::Definite(padded_bounds.size.width),
|
||||
AvailableSpace::Definite(item_height),
|
||||
);
|
||||
item.draw(item_origin, available_space, view_state, cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
})
|
||||
},
|
||||
);
|
||||
self.interactivity = interactivity;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -275,14 +292,8 @@ impl<V> UniformList<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> StatelessInteractive<V> for UniformList<V> {
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self.interactivity.as_stateless_mut()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> StatefulInteractive<V> for UniformList<V> {
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V> {
|
||||
impl<V> InteractiveComponent<V> for UniformList<V> {
|
||||
fn interactivity(&mut self) -> &mut crate::Interactivity<V> {
|
||||
&mut self.interactivity
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,915 +1,17 @@
|
|||
use crate::{
|
||||
div, point, px, Action, AnyDrag, AnyTooltip, AnyView, AppContext, Bounds, Component,
|
||||
DispatchPhase, Div, Element, ElementId, FocusHandle, KeyContext, Keystroke, Modifiers,
|
||||
Overflow, Pixels, Point, Render, SharedString, Size, Style, StyleRefinement, Task, View,
|
||||
ViewContext,
|
||||
div, point, px, AnyDrag, AnyTooltip, AnyView, AppContext, Bounds, Component, DispatchPhase,
|
||||
FocusHandle, Keystroke, Modifiers, Node, Pixels, Point, Render, SharedString, StyleRefinement,
|
||||
Task, ViewContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use derive_more::{Deref, DerefMut};
|
||||
use parking_lot::Mutex;
|
||||
use refineable::Refineable;
|
||||
use smallvec::SmallVec;
|
||||
use std::{
|
||||
any::{Any, TypeId},
|
||||
fmt::Debug,
|
||||
marker::PhantomData,
|
||||
mem,
|
||||
ops::Deref,
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
time::Duration,
|
||||
any::Any, fmt::Debug, marker::PhantomData, ops::Deref, path::PathBuf, sync::Arc, time::Duration,
|
||||
};
|
||||
|
||||
const DRAG_THRESHOLD: f64 = 2.;
|
||||
const TOOLTIP_DELAY: Duration = Duration::from_millis(500);
|
||||
const TOOLTIP_OFFSET: Point<Pixels> = Point::new(px(10.0), px(8.0));
|
||||
|
||||
pub trait StatelessInteractive<V: 'static>: Element<V> {
|
||||
fn stateless_interactivity(&mut self) -> &mut StatelessInteractivity<V>;
|
||||
|
||||
fn hover(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity().hover_style = f(StyleRefinement::default());
|
||||
self
|
||||
}
|
||||
|
||||
fn group_hover(
|
||||
mut self,
|
||||
group_name: impl Into<SharedString>,
|
||||
f: impl FnOnce(StyleRefinement) -> StyleRefinement,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity().group_hover_style = Some(GroupStyle {
|
||||
group: group_name.into(),
|
||||
style: f(StyleRefinement::default()),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_down(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.mouse_down_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_up(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble
|
||||
&& event.button == button
|
||||
&& bounds.contains_point(&event.position)
|
||||
{
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_down_out(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &MouseDownEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.mouse_down_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture && !bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_up_out(
|
||||
mut self,
|
||||
button: MouseButton,
|
||||
handler: impl Fn(&mut V, &MouseUpEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.mouse_up_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Capture
|
||||
&& event.button == button
|
||||
&& !bounds.contains_point(&event.position)
|
||||
{
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_mouse_move(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &MouseMoveEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.mouse_move_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_scroll_wheel(
|
||||
mut self,
|
||||
handler: impl Fn(&mut V, &ScrollWheelEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.scroll_wheel_listeners
|
||||
.push(Box::new(move |view, event, bounds, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
handler(view, event, cx);
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
/// Capture the given action, fires during the capture phase
|
||||
fn capture_action<A: Action>(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity().action_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |view, action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Capture {
|
||||
listener(view, action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
/// Add a listener for the given action, fires during the bubble event phase
|
||||
fn on_action<A: Action>(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &A, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity().action_listeners.push((
|
||||
TypeId::of::<A>(),
|
||||
Box::new(move |view, action, phase, cx| {
|
||||
let action = action.downcast_ref().unwrap();
|
||||
if phase == DispatchPhase::Bubble {
|
||||
listener(view, action, cx)
|
||||
}
|
||||
}),
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_key_down(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &KeyDownEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.key_down_listeners
|
||||
.push(Box::new(move |view, event, phase, cx| {
|
||||
listener(view, event, phase, cx)
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_key_up(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &KeyUpEvent, DispatchPhase, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.key_up_listeners
|
||||
.push(Box::new(move |view, event, phase, cx| {
|
||||
listener(view, event, phase, cx)
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn drag_over<S: 'static>(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity()
|
||||
.drag_over_styles
|
||||
.push((TypeId::of::<S>(), f(StyleRefinement::default())));
|
||||
self
|
||||
}
|
||||
|
||||
fn group_drag_over<S: 'static>(
|
||||
mut self,
|
||||
group_name: impl Into<SharedString>,
|
||||
f: impl FnOnce(StyleRefinement) -> StyleRefinement,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity().group_drag_over_styles.push((
|
||||
TypeId::of::<S>(),
|
||||
GroupStyle {
|
||||
group: group_name.into(),
|
||||
style: f(StyleRefinement::default()),
|
||||
},
|
||||
));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_drop<W: 'static>(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, View<W>, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateless_interactivity().drop_listeners.push((
|
||||
TypeId::of::<W>(),
|
||||
Box::new(move |view, dragged_view, cx| {
|
||||
listener(view, dragged_view.downcast().unwrap(), cx);
|
||||
}),
|
||||
));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait StatefulInteractive<V: 'static>: StatelessInteractive<V> {
|
||||
fn stateful_interactivity(&mut self) -> &mut StatefulInteractivity<V>;
|
||||
|
||||
fn active(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateful_interactivity().active_style = f(StyleRefinement::default());
|
||||
self
|
||||
}
|
||||
|
||||
fn group_active(
|
||||
mut self,
|
||||
group_name: impl Into<SharedString>,
|
||||
f: impl FnOnce(StyleRefinement) -> StyleRefinement,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateful_interactivity().group_active_style = Some(GroupStyle {
|
||||
group: group_name.into(),
|
||||
style: f(StyleRefinement::default()),
|
||||
});
|
||||
self
|
||||
}
|
||||
|
||||
fn on_click(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &ClickEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.stateful_interactivity()
|
||||
.click_listeners
|
||||
.push(Box::new(move |view, event, cx| listener(view, event, cx)));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_drag<W>(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
W: 'static + Render,
|
||||
{
|
||||
debug_assert!(
|
||||
self.stateful_interactivity().drag_listener.is_none(),
|
||||
"calling on_drag more than once on the same element is not supported"
|
||||
);
|
||||
self.stateful_interactivity().drag_listener =
|
||||
Some(Box::new(move |view_state, cursor_offset, cx| AnyDrag {
|
||||
view: listener(view_state, cx).into(),
|
||||
cursor_offset,
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_hover(mut self, listener: impl 'static + Fn(&mut V, bool, &mut ViewContext<V>)) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
debug_assert!(
|
||||
self.stateful_interactivity().hover_listener.is_none(),
|
||||
"calling on_hover more than once on the same element is not supported"
|
||||
);
|
||||
self.stateful_interactivity().hover_listener = Some(Box::new(listener));
|
||||
self
|
||||
}
|
||||
|
||||
fn tooltip<W>(
|
||||
mut self,
|
||||
build_tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> View<W> + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
W: 'static + Render,
|
||||
{
|
||||
debug_assert!(
|
||||
self.stateful_interactivity().tooltip_builder.is_none(),
|
||||
"calling tooltip more than once on the same element is not supported"
|
||||
);
|
||||
self.stateful_interactivity().tooltip_builder = Some(Arc::new(move |view_state, cx| {
|
||||
build_tooltip(view_state, cx).into()
|
||||
}));
|
||||
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
pub trait ElementInteractivity<V: 'static>: 'static {
|
||||
fn as_stateless(&self) -> &StatelessInteractivity<V>;
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V>;
|
||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>>;
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>>;
|
||||
|
||||
fn refine_style(
|
||||
&self,
|
||||
style: &mut Style,
|
||||
bounds: Bounds<Pixels>,
|
||||
element_state: &InteractiveElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let mouse_position = cx.mouse_position();
|
||||
let stateless = self.as_stateless();
|
||||
if let Some(group_hover) = stateless.group_hover_style.as_ref() {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_hover.group, cx) {
|
||||
if group_bounds.contains_point(&mouse_position) {
|
||||
style.refine(&group_hover.style);
|
||||
}
|
||||
}
|
||||
}
|
||||
if bounds.contains_point(&mouse_position) {
|
||||
style.refine(&stateless.hover_style);
|
||||
}
|
||||
|
||||
if let Some(drag) = cx.active_drag.take() {
|
||||
for (state_type, group_drag_style) in &self.as_stateless().group_drag_over_styles {
|
||||
if let Some(group_bounds) = GroupBounds::get(&group_drag_style.group, cx) {
|
||||
if *state_type == drag.view.entity_type()
|
||||
&& group_bounds.contains_point(&mouse_position)
|
||||
{
|
||||
style.refine(&group_drag_style.style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (state_type, drag_over_style) in &self.as_stateless().drag_over_styles {
|
||||
if *state_type == drag.view.entity_type() && bounds.contains_point(&mouse_position)
|
||||
{
|
||||
style.refine(drag_over_style);
|
||||
}
|
||||
}
|
||||
|
||||
cx.active_drag = Some(drag);
|
||||
}
|
||||
|
||||
if let Some(stateful) = self.as_stateful() {
|
||||
let active_state = element_state.active_state.lock();
|
||||
if active_state.group {
|
||||
if let Some(group_style) = stateful.group_active_style.as_ref() {
|
||||
style.refine(&group_style.style);
|
||||
}
|
||||
}
|
||||
if active_state.element {
|
||||
style.refine(&stateful.active_style);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn initialize(&mut self, cx: &mut ViewContext<V>) {
|
||||
let stateless = self.as_stateless_mut();
|
||||
|
||||
for listener in stateless.key_down_listeners.drain(..) {
|
||||
cx.on_key_event(move |state, event: &KeyDownEvent, phase, cx| {
|
||||
listener(state, event, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in stateless.key_up_listeners.drain(..) {
|
||||
cx.on_key_event(move |state, event: &KeyUpEvent, phase, cx| {
|
||||
listener(state, event, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for (action_type, listener) in stateless.action_listeners.drain(..) {
|
||||
cx.on_action(action_type, listener)
|
||||
}
|
||||
}
|
||||
|
||||
fn handle_events(
|
||||
&mut self,
|
||||
bounds: Bounds<Pixels>,
|
||||
content_size: Size<Pixels>,
|
||||
overflow: Point<Overflow>,
|
||||
element_state: &mut InteractiveElementState,
|
||||
cx: &mut ViewContext<V>,
|
||||
) {
|
||||
let stateless = self.as_stateless_mut();
|
||||
for listener in stateless.mouse_down_listeners.drain(..) {
|
||||
cx.on_mouse_event(move |state, event: &MouseDownEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in stateless.mouse_up_listeners.drain(..) {
|
||||
cx.on_mouse_event(move |state, event: &MouseUpEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in stateless.mouse_move_listeners.drain(..) {
|
||||
cx.on_mouse_event(move |state, event: &MouseMoveEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
for listener in stateless.scroll_wheel_listeners.drain(..) {
|
||||
cx.on_mouse_event(move |state, event: &ScrollWheelEvent, phase, cx| {
|
||||
listener(state, event, &bounds, phase, cx);
|
||||
})
|
||||
}
|
||||
|
||||
let hover_group_bounds = stateless
|
||||
.group_hover_style
|
||||
.as_ref()
|
||||
.and_then(|group_hover| GroupBounds::get(&group_hover.group, cx));
|
||||
|
||||
if let Some(group_bounds) = hover_group_bounds {
|
||||
let hovered = group_bounds.contains_point(&cx.mouse_position());
|
||||
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if group_bounds.contains_point(&event.position) != hovered {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if stateless.hover_style.is_some()
|
||||
|| (cx.active_drag.is_some() && !stateless.drag_over_styles.is_empty())
|
||||
{
|
||||
let hovered = bounds.contains_point(&cx.mouse_position());
|
||||
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
if bounds.contains_point(&event.position) != hovered {
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if cx.active_drag.is_some() {
|
||||
let drop_listeners = mem::take(&mut stateless.drop_listeners);
|
||||
cx.on_mouse_event(move |view, event: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
if let Some(drag_state_type) =
|
||||
cx.active_drag.as_ref().map(|drag| drag.view.entity_type())
|
||||
{
|
||||
for (drop_state_type, listener) in &drop_listeners {
|
||||
if *drop_state_type == drag_state_type {
|
||||
let drag = cx
|
||||
.active_drag
|
||||
.take()
|
||||
.expect("checked for type drag state type above");
|
||||
listener(view, drag.view.clone(), cx);
|
||||
cx.notify();
|
||||
cx.stop_propagation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(stateful) = self.as_stateful_mut() {
|
||||
let click_listeners = mem::take(&mut stateful.click_listeners);
|
||||
let drag_listener = mem::take(&mut stateful.drag_listener);
|
||||
|
||||
if !click_listeners.is_empty() || drag_listener.is_some() {
|
||||
let pending_mouse_down = element_state.pending_mouse_down.clone();
|
||||
let mouse_down = pending_mouse_down.lock().clone();
|
||||
if let Some(mouse_down) = mouse_down {
|
||||
if let Some(drag_listener) = drag_listener {
|
||||
let active_state = element_state.active_state.clone();
|
||||
|
||||
cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
|
||||
if cx.active_drag.is_some() {
|
||||
if phase == DispatchPhase::Capture {
|
||||
cx.notify();
|
||||
}
|
||||
} else if phase == DispatchPhase::Bubble
|
||||
&& bounds.contains_point(&event.position)
|
||||
&& (event.position - mouse_down.position).magnitude()
|
||||
> DRAG_THRESHOLD
|
||||
{
|
||||
*active_state.lock() = ActiveState::default();
|
||||
let cursor_offset = event.position - bounds.origin;
|
||||
let drag = drag_listener(view_state, cursor_offset, cx);
|
||||
cx.active_drag = Some(drag);
|
||||
cx.notify();
|
||||
cx.stop_propagation();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
cx.on_mouse_event(move |view_state, event: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
|
||||
{
|
||||
let mouse_click = ClickEvent {
|
||||
down: mouse_down.clone(),
|
||||
up: event.clone(),
|
||||
};
|
||||
for listener in &click_listeners {
|
||||
listener(view_state, &mouse_click, cx);
|
||||
}
|
||||
}
|
||||
*pending_mouse_down.lock() = None;
|
||||
});
|
||||
} else {
|
||||
cx.on_mouse_event(move |_state, event: &MouseDownEvent, phase, _cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position)
|
||||
{
|
||||
*pending_mouse_down.lock() = Some(event.clone());
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(hover_listener) = stateful.hover_listener.take() {
|
||||
let was_hovered = element_state.hover_state.clone();
|
||||
let has_mouse_down = element_state.pending_mouse_down.clone();
|
||||
|
||||
cx.on_mouse_event(move |view_state, event: &MouseMoveEvent, phase, cx| {
|
||||
if phase != DispatchPhase::Bubble {
|
||||
return;
|
||||
}
|
||||
let is_hovered =
|
||||
bounds.contains_point(&event.position) && has_mouse_down.lock().is_none();
|
||||
let mut was_hovered = was_hovered.lock();
|
||||
|
||||
if is_hovered != was_hovered.clone() {
|
||||
*was_hovered = is_hovered;
|
||||
drop(was_hovered);
|
||||
|
||||
hover_listener(view_state, is_hovered, cx);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if let Some(tooltip_builder) = stateful.tooltip_builder.take() {
|
||||
let active_tooltip = element_state.active_tooltip.clone();
|
||||
let pending_mouse_down = element_state.pending_mouse_down.clone();
|
||||
|
||||
cx.on_mouse_event(move |_, event: &MouseMoveEvent, phase, cx| {
|
||||
if phase != DispatchPhase::Bubble {
|
||||
return;
|
||||
}
|
||||
|
||||
let is_hovered = bounds.contains_point(&event.position)
|
||||
&& pending_mouse_down.lock().is_none();
|
||||
if !is_hovered {
|
||||
active_tooltip.lock().take();
|
||||
return;
|
||||
}
|
||||
|
||||
if active_tooltip.lock().is_none() {
|
||||
let task = cx.spawn({
|
||||
let active_tooltip = active_tooltip.clone();
|
||||
let tooltip_builder = tooltip_builder.clone();
|
||||
|
||||
move |view, mut cx| async move {
|
||||
cx.background_executor().timer(TOOLTIP_DELAY).await;
|
||||
view.update(&mut cx, move |view_state, cx| {
|
||||
active_tooltip.lock().replace(ActiveTooltip {
|
||||
waiting: None,
|
||||
tooltip: Some(AnyTooltip {
|
||||
view: tooltip_builder(view_state, cx),
|
||||
cursor_offset: cx.mouse_position() + TOOLTIP_OFFSET,
|
||||
}),
|
||||
});
|
||||
cx.notify();
|
||||
})
|
||||
.ok();
|
||||
}
|
||||
});
|
||||
active_tooltip.lock().replace(ActiveTooltip {
|
||||
waiting: Some(task),
|
||||
tooltip: None,
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
if let Some(active_tooltip) = element_state.active_tooltip.lock().as_ref() {
|
||||
if active_tooltip.tooltip.is_some() {
|
||||
cx.active_tooltip = active_tooltip.tooltip.clone()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let active_state = element_state.active_state.clone();
|
||||
if active_state.lock().is_none() {
|
||||
let active_group_bounds = stateful
|
||||
.group_active_style
|
||||
.as_ref()
|
||||
.and_then(|group_active| GroupBounds::get(&group_active.group, cx));
|
||||
cx.on_mouse_event(move |_view, down: &MouseDownEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble {
|
||||
let group = active_group_bounds
|
||||
.map_or(false, |bounds| bounds.contains_point(&down.position));
|
||||
let element = bounds.contains_point(&down.position);
|
||||
if group || element {
|
||||
*active_state.lock() = ActiveState { group, element };
|
||||
cx.notify();
|
||||
}
|
||||
}
|
||||
});
|
||||
} else {
|
||||
cx.on_mouse_event(move |_, _: &MouseUpEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Capture {
|
||||
*active_state.lock() = ActiveState::default();
|
||||
cx.notify();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
if overflow.x == Overflow::Scroll || overflow.y == Overflow::Scroll {
|
||||
let scroll_offset = element_state
|
||||
.scroll_offset
|
||||
.get_or_insert_with(Arc::default)
|
||||
.clone();
|
||||
let line_height = cx.line_height();
|
||||
let scroll_max = (content_size - bounds.size).max(&Size::default());
|
||||
|
||||
cx.on_mouse_event(move |_, event: &ScrollWheelEvent, phase, cx| {
|
||||
if phase == DispatchPhase::Bubble && bounds.contains_point(&event.position) {
|
||||
let mut scroll_offset = scroll_offset.lock();
|
||||
let old_scroll_offset = *scroll_offset;
|
||||
let delta = event.delta.pixel_delta(line_height);
|
||||
|
||||
if overflow.x == Overflow::Scroll {
|
||||
scroll_offset.x =
|
||||
(scroll_offset.x + delta.x).clamp(-scroll_max.width, px(0.));
|
||||
}
|
||||
|
||||
if overflow.y == Overflow::Scroll {
|
||||
scroll_offset.y =
|
||||
(scroll_offset.y + delta.y).clamp(-scroll_max.height, px(0.));
|
||||
}
|
||||
|
||||
if *scroll_offset != old_scroll_offset {
|
||||
cx.notify();
|
||||
cx.stop_propagation();
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Deref, DerefMut)]
|
||||
pub struct StatefulInteractivity<V> {
|
||||
pub id: ElementId,
|
||||
#[deref]
|
||||
#[deref_mut]
|
||||
stateless: StatelessInteractivity<V>,
|
||||
click_listeners: SmallVec<[ClickListener<V>; 2]>,
|
||||
active_style: StyleRefinement,
|
||||
group_active_style: Option<GroupStyle>,
|
||||
drag_listener: Option<DragListener<V>>,
|
||||
hover_listener: Option<HoverListener<V>>,
|
||||
tooltip_builder: Option<TooltipBuilder<V>>,
|
||||
}
|
||||
|
||||
impl<V: 'static> StatefulInteractivity<V> {
|
||||
pub fn new(id: ElementId, stateless: StatelessInteractivity<V>) -> Self {
|
||||
Self {
|
||||
id,
|
||||
stateless,
|
||||
click_listeners: SmallVec::new(),
|
||||
active_style: StyleRefinement::default(),
|
||||
group_active_style: None,
|
||||
drag_listener: None,
|
||||
hover_listener: None,
|
||||
tooltip_builder: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ElementInteractivity<V> for StatefulInteractivity<V> {
|
||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||
Some(self)
|
||||
}
|
||||
|
||||
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||
&self.stateless
|
||||
}
|
||||
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
&mut self.stateless
|
||||
}
|
||||
}
|
||||
|
||||
type DropListener<V> = dyn Fn(&mut V, AnyView, &mut ViewContext<V>) + 'static;
|
||||
|
||||
pub struct StatelessInteractivity<V> {
|
||||
pub dispatch_context: KeyContext,
|
||||
pub mouse_down_listeners: SmallVec<[MouseDownListener<V>; 2]>,
|
||||
pub mouse_up_listeners: SmallVec<[MouseUpListener<V>; 2]>,
|
||||
pub mouse_move_listeners: SmallVec<[MouseMoveListener<V>; 2]>,
|
||||
pub scroll_wheel_listeners: SmallVec<[ScrollWheelListener<V>; 2]>,
|
||||
pub key_down_listeners: SmallVec<[KeyDownListener<V>; 2]>,
|
||||
pub key_up_listeners: SmallVec<[KeyUpListener<V>; 2]>,
|
||||
pub action_listeners: SmallVec<[(TypeId, ActionListener<V>); 8]>,
|
||||
pub hover_style: StyleRefinement,
|
||||
pub group_hover_style: Option<GroupStyle>,
|
||||
drag_over_styles: SmallVec<[(TypeId, StyleRefinement); 2]>,
|
||||
group_drag_over_styles: SmallVec<[(TypeId, GroupStyle); 2]>,
|
||||
drop_listeners: SmallVec<[(TypeId, Box<DropListener<V>>); 2]>,
|
||||
}
|
||||
|
||||
impl<V> StatelessInteractivity<V> {
|
||||
pub fn into_stateful(self, id: impl Into<ElementId>) -> StatefulInteractivity<V> {
|
||||
StatefulInteractivity {
|
||||
id: id.into(),
|
||||
stateless: self,
|
||||
click_listeners: SmallVec::new(),
|
||||
drag_listener: None,
|
||||
hover_listener: None,
|
||||
tooltip_builder: None,
|
||||
active_style: StyleRefinement::default(),
|
||||
group_active_style: None,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GroupStyle {
|
||||
pub group: SharedString,
|
||||
pub style: StyleRefinement,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct GroupBounds(HashMap<SharedString, SmallVec<[Bounds<Pixels>; 1]>>);
|
||||
|
||||
impl GroupBounds {
|
||||
pub fn get(name: &SharedString, cx: &mut AppContext) -> Option<Bounds<Pixels>> {
|
||||
cx.default_global::<Self>()
|
||||
.0
|
||||
.get(name)
|
||||
.and_then(|bounds_stack| bounds_stack.last())
|
||||
.cloned()
|
||||
}
|
||||
|
||||
pub fn push(name: SharedString, bounds: Bounds<Pixels>, cx: &mut AppContext) {
|
||||
cx.default_global::<Self>()
|
||||
.0
|
||||
.entry(name)
|
||||
.or_default()
|
||||
.push(bounds);
|
||||
}
|
||||
|
||||
pub fn pop(name: &SharedString, cx: &mut AppContext) {
|
||||
cx.default_global::<Self>().0.get_mut(name).unwrap().pop();
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Default, Eq, PartialEq)]
|
||||
struct ActiveState {
|
||||
pub group: bool,
|
||||
pub element: bool,
|
||||
}
|
||||
|
||||
impl ActiveState {
|
||||
pub fn is_none(&self) -> bool {
|
||||
!self.group && !self.element
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct InteractiveElementState {
|
||||
active_state: Arc<Mutex<ActiveState>>,
|
||||
hover_state: Arc<Mutex<bool>>,
|
||||
pending_mouse_down: Arc<Mutex<Option<MouseDownEvent>>>,
|
||||
scroll_offset: Option<Arc<Mutex<Point<Pixels>>>>,
|
||||
active_tooltip: Arc<Mutex<Option<ActiveTooltip>>>,
|
||||
}
|
||||
|
||||
struct ActiveTooltip {
|
||||
#[allow(unused)] // used to drop the task
|
||||
waiting: Option<Task<()>>,
|
||||
tooltip: Option<AnyTooltip>,
|
||||
}
|
||||
|
||||
impl InteractiveElementState {
|
||||
pub fn scroll_offset(&self) -> Option<Point<Pixels>> {
|
||||
self.scroll_offset
|
||||
.as_ref()
|
||||
.map(|offset| offset.lock().clone())
|
||||
}
|
||||
|
||||
pub fn track_scroll_offset(&mut self) -> Arc<Mutex<Point<Pixels>>> {
|
||||
self.scroll_offset
|
||||
.get_or_insert_with(|| Arc::new(Mutex::new(Default::default())))
|
||||
.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<V> Default for StatelessInteractivity<V> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
dispatch_context: KeyContext::default(),
|
||||
mouse_down_listeners: SmallVec::new(),
|
||||
mouse_up_listeners: SmallVec::new(),
|
||||
mouse_move_listeners: SmallVec::new(),
|
||||
scroll_wheel_listeners: SmallVec::new(),
|
||||
key_down_listeners: SmallVec::new(),
|
||||
key_up_listeners: SmallVec::new(),
|
||||
action_listeners: SmallVec::new(),
|
||||
hover_style: StyleRefinement::default(),
|
||||
group_hover_style: None,
|
||||
drag_over_styles: SmallVec::new(),
|
||||
group_drag_over_styles: SmallVec::new(),
|
||||
drop_listeners: SmallVec::new(),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ElementInteractivity<V> for StatelessInteractivity<V> {
|
||||
fn as_stateful(&self) -> Option<&StatefulInteractivity<V>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_stateful_mut(&mut self) -> Option<&mut StatefulInteractivity<V>> {
|
||||
None
|
||||
}
|
||||
|
||||
fn as_stateless(&self) -> &StatelessInteractivity<V> {
|
||||
self
|
||||
}
|
||||
|
||||
fn as_stateless_mut(&mut self) -> &mut StatelessInteractivity<V> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, Eq, PartialEq)]
|
||||
pub struct KeyDownEvent {
|
||||
pub keystroke: Keystroke,
|
||||
|
@ -991,10 +93,6 @@ where
|
|||
}
|
||||
}
|
||||
|
||||
// impl<S, R, V, E> Render for Drag<S, R, V, E> {
|
||||
// // fn render(&mut self, cx: ViewContext<Self>) ->
|
||||
// }
|
||||
|
||||
#[derive(Hash, PartialEq, Eq, Copy, Clone, Debug)]
|
||||
pub enum MouseButton {
|
||||
Left,
|
||||
|
@ -1103,7 +201,7 @@ impl Deref for MouseExitEvent {
|
|||
pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>);
|
||||
|
||||
impl Render for ExternalPaths {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, _: &mut ViewContext<Self>) -> Self::Element {
|
||||
div() // Intentionally left empty because the platform will render icons for the dragged files
|
||||
|
@ -1229,8 +327,8 @@ pub type ActionListener<V> =
|
|||
#[cfg(test)]
|
||||
mod test {
|
||||
use crate::{
|
||||
self as gpui, div, Div, FocusHandle, KeyBinding, Keystroke, ParentElement, Render,
|
||||
StatefulInteractivity, StatelessInteractive, TestAppContext, VisualContext,
|
||||
self as gpui, div, FocusHandle, InteractiveComponent, KeyBinding, Keystroke, Node,
|
||||
ParentComponent, Render, Stateful, TestAppContext, VisualContext,
|
||||
};
|
||||
|
||||
struct TestView {
|
||||
|
@ -1242,12 +340,12 @@ mod test {
|
|||
actions!(TestAction);
|
||||
|
||||
impl Render for TestView {
|
||||
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||
type Element = Stateful<Self, Node<Self>>;
|
||||
|
||||
fn render(&mut self, _: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
div().id("testview").child(
|
||||
div()
|
||||
.context("test")
|
||||
.key_context("test")
|
||||
.track_focus(&self.focus_handle)
|
||||
.on_key_down(|this: &mut TestView, _, _, _| this.saw_key_down = true)
|
||||
.on_action(|this: &mut TestView, _: &TestAction, _| this.saw_action = true),
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{
|
||||
build_action_from_type, Action, Bounds, DispatchPhase, Element, FocusEvent, FocusHandle,
|
||||
FocusId, KeyContext, KeyMatch, Keymap, Keystroke, KeystrokeMatcher, MouseDownEvent, Pixels,
|
||||
Style, StyleRefinement, ViewContext, WindowContext,
|
||||
build_action_from_type, Action, Bounds, DispatchPhase, FocusEvent, FocusHandle, FocusId,
|
||||
KeyContext, KeyMatch, Keymap, Keystroke, KeystrokeMatcher, MouseDownEvent, Pixels, Style,
|
||||
StyleRefinement, ViewContext, WindowContext,
|
||||
};
|
||||
use collections::HashMap;
|
||||
use parking_lot::Mutex;
|
||||
|
@ -342,115 +342,3 @@ impl<V: 'static> KeyDispatch<V> for NonFocusableKeyDispatch {
|
|||
&mut self.key_context
|
||||
}
|
||||
}
|
||||
|
||||
pub trait Focusable<V: 'static>: Element<V> {
|
||||
fn focus_listeners(&mut self) -> &mut FocusListeners<V>;
|
||||
fn set_focus_style(&mut self, style: StyleRefinement);
|
||||
fn set_focus_in_style(&mut self, style: StyleRefinement);
|
||||
fn set_in_focus_style(&mut self, style: StyleRefinement);
|
||||
|
||||
fn focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_focus_style(f(StyleRefinement::default()));
|
||||
self
|
||||
}
|
||||
|
||||
fn focus_in(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_focus_in_style(f(StyleRefinement::default()));
|
||||
self
|
||||
}
|
||||
|
||||
fn in_focus(mut self, f: impl FnOnce(StyleRefinement) -> StyleRefinement) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.set_in_focus_style(f(StyleRefinement::default()));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.focus_listeners()
|
||||
.push(Box::new(move |view, focus_handle, event, cx| {
|
||||
if event.focused.as_ref() == Some(focus_handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_blur(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.focus_listeners()
|
||||
.push(Box::new(move |view, focus_handle, event, cx| {
|
||||
if event.blurred.as_ref() == Some(focus_handle) {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus_in(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.focus_listeners()
|
||||
.push(Box::new(move |view, focus_handle, event, cx| {
|
||||
let descendant_blurred = event
|
||||
.blurred
|
||||
.as_ref()
|
||||
.map_or(false, |blurred| focus_handle.contains(blurred, cx));
|
||||
let descendant_focused = event
|
||||
.focused
|
||||
.as_ref()
|
||||
.map_or(false, |focused| focus_handle.contains(focused, cx));
|
||||
|
||||
if !descendant_blurred && descendant_focused {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
|
||||
fn on_focus_out(
|
||||
mut self,
|
||||
listener: impl Fn(&mut V, &FocusEvent, &mut ViewContext<V>) + 'static,
|
||||
) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
self.focus_listeners()
|
||||
.push(Box::new(move |view, focus_handle, event, cx| {
|
||||
let descendant_blurred = event
|
||||
.blurred
|
||||
.as_ref()
|
||||
.map_or(false, |blurred| focus_handle.contains(blurred, cx));
|
||||
let descendant_focused = event
|
||||
.focused
|
||||
.as_ref()
|
||||
.map_or(false, |focused| focus_handle.contains(focused, cx));
|
||||
if descendant_blurred && !descendant_focused {
|
||||
listener(view, event, cx)
|
||||
}
|
||||
}));
|
||||
self
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1 +1,4 @@
|
|||
pub use crate::{Context, ParentElement, Refineable};
|
||||
pub use crate::{
|
||||
BorrowAppContext, BorrowWindow, Component, Context, FocusableComponent, InteractiveComponent,
|
||||
ParentComponent, Refineable, Render, StatefulInteractiveComponent, Styled, VisualContext,
|
||||
};
|
||||
|
|
|
@ -6,21 +6,20 @@ use crate::{
|
|||
use crate::{BoxShadow, TextStyleRefinement};
|
||||
use refineable::Refineable;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
use taffy::style::Overflow;
|
||||
|
||||
pub trait Styled {
|
||||
pub trait Styled: Sized {
|
||||
fn style(&mut self) -> &mut StyleRefinement;
|
||||
|
||||
fn computed_style(&mut self) -> Style {
|
||||
Style::default().refined(self.style().clone())
|
||||
}
|
||||
|
||||
gpui2_macros::style_helpers!();
|
||||
|
||||
fn z_index(mut self, z_index: u32) -> Self {
|
||||
self.style().z_index = Some(z_index);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the size of the element to the full width and height.
|
||||
fn full(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn full(mut self) -> Self {
|
||||
self.style().size.width = Some(relative(1.).into());
|
||||
self.style().size.height = Some(relative(1.).into());
|
||||
self
|
||||
|
@ -28,118 +27,98 @@ pub trait Styled {
|
|||
|
||||
/// Sets the position of the element to `relative`.
|
||||
/// [Docs](https://tailwindcss.com/docs/position)
|
||||
fn relative(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn relative(mut self) -> Self {
|
||||
self.style().position = Some(Position::Relative);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the position of the element to `absolute`.
|
||||
/// [Docs](https://tailwindcss.com/docs/position)
|
||||
fn absolute(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn absolute(mut self) -> Self {
|
||||
self.style().position = Some(Position::Absolute);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the display type of the element to `block`.
|
||||
/// [Docs](https://tailwindcss.com/docs/display)
|
||||
fn block(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn block(mut self) -> Self {
|
||||
self.style().display = Some(Display::Block);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the display type of the element to `flex`.
|
||||
/// [Docs](https://tailwindcss.com/docs/display)
|
||||
fn flex(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn flex(mut self) -> Self {
|
||||
self.style().display = Some(Display::Flex);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the visibility of the element to `visible`.
|
||||
/// [Docs](https://tailwindcss.com/docs/visibility)
|
||||
fn visible(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn visible(mut self) -> Self {
|
||||
self.style().visibility = Some(Visibility::Visible);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the visibility of the element to `hidden`.
|
||||
/// [Docs](https://tailwindcss.com/docs/visibility)
|
||||
fn invisible(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn invisible(mut self) -> Self {
|
||||
self.style().visibility = Some(Visibility::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
fn cursor(mut self, cursor: CursorStyle) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn overflow_hidden(mut self) -> Self {
|
||||
self.style().overflow.x = Some(Overflow::Hidden);
|
||||
self.style().overflow.y = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
fn overflow_hidden_x(mut self) -> Self {
|
||||
self.style().overflow.x = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
fn overflow_hidden_y(mut self) -> Self {
|
||||
self.style().overflow.y = Some(Overflow::Hidden);
|
||||
self
|
||||
}
|
||||
|
||||
fn cursor(mut self, cursor: CursorStyle) -> Self {
|
||||
self.style().mouse_cursor = Some(cursor);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the cursor style when hovering an element to `default`.
|
||||
/// [Docs](https://tailwindcss.com/docs/cursor)
|
||||
fn cursor_default(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn cursor_default(mut self) -> Self {
|
||||
self.style().mouse_cursor = Some(CursorStyle::Arrow);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the cursor style when hovering an element to `pointer`.
|
||||
/// [Docs](https://tailwindcss.com/docs/cursor)
|
||||
fn cursor_pointer(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn cursor_pointer(mut self) -> Self {
|
||||
self.style().mouse_cursor = Some(CursorStyle::PointingHand);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the flex direction of the element to `column`.
|
||||
/// [Docs](https://tailwindcss.com/docs/flex-direction#column)
|
||||
fn flex_col(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn flex_col(mut self) -> Self {
|
||||
self.style().flex_direction = Some(FlexDirection::Column);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the flex direction of the element to `row`.
|
||||
/// [Docs](https://tailwindcss.com/docs/flex-direction#row)
|
||||
fn flex_row(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn flex_row(mut self) -> Self {
|
||||
self.style().flex_direction = Some(FlexDirection::Row);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the element to allow a flex item to grow and shrink as needed, ignoring its initial size.
|
||||
/// [Docs](https://tailwindcss.com/docs/flex#flex-1)
|
||||
fn flex_1(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn flex_1(mut self) -> Self {
|
||||
self.style().flex_grow = Some(1.);
|
||||
self.style().flex_shrink = Some(1.);
|
||||
self.style().flex_basis = Some(relative(0.).into());
|
||||
|
@ -148,10 +127,7 @@ pub trait Styled {
|
|||
|
||||
/// Sets the element to allow a flex item to grow and shrink, taking into account its initial size.
|
||||
/// [Docs](https://tailwindcss.com/docs/flex#auto)
|
||||
fn flex_auto(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn flex_auto(mut self) -> Self {
|
||||
self.style().flex_grow = Some(1.);
|
||||
self.style().flex_shrink = Some(1.);
|
||||
self.style().flex_basis = Some(Length::Auto);
|
||||
|
@ -160,10 +136,7 @@ pub trait Styled {
|
|||
|
||||
/// Sets the element to allow a flex item to shrink but not grow, taking into account its initial size.
|
||||
/// [Docs](https://tailwindcss.com/docs/flex#initial)
|
||||
fn flex_initial(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn flex_initial(mut self) -> Self {
|
||||
self.style().flex_grow = Some(0.);
|
||||
self.style().flex_shrink = Some(1.);
|
||||
self.style().flex_basis = Some(Length::Auto);
|
||||
|
@ -172,10 +145,7 @@ pub trait Styled {
|
|||
|
||||
/// Sets the element to prevent a flex item from growing or shrinking.
|
||||
/// [Docs](https://tailwindcss.com/docs/flex#none)
|
||||
fn flex_none(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn flex_none(mut self) -> Self {
|
||||
self.style().flex_grow = Some(0.);
|
||||
self.style().flex_shrink = Some(0.);
|
||||
self
|
||||
|
@ -183,40 +153,28 @@ pub trait Styled {
|
|||
|
||||
/// Sets the element to allow a flex item to grow to fill any available space.
|
||||
/// [Docs](https://tailwindcss.com/docs/flex-grow)
|
||||
fn grow(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn grow(mut self) -> Self {
|
||||
self.style().flex_grow = Some(1.);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the element to align flex items to the start of the container's cross axis.
|
||||
/// [Docs](https://tailwindcss.com/docs/align-items#start)
|
||||
fn items_start(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn items_start(mut self) -> Self {
|
||||
self.style().align_items = Some(AlignItems::FlexStart);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the element to align flex items to the end of the container's cross axis.
|
||||
/// [Docs](https://tailwindcss.com/docs/align-items#end)
|
||||
fn items_end(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn items_end(mut self) -> Self {
|
||||
self.style().align_items = Some(AlignItems::FlexEnd);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the element to align flex items along the center of the container's cross axis.
|
||||
/// [Docs](https://tailwindcss.com/docs/align-items#center)
|
||||
fn items_center(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn items_center(mut self) -> Self {
|
||||
self.style().align_items = Some(AlignItems::Center);
|
||||
self
|
||||
}
|
||||
|
@ -224,40 +182,28 @@ pub trait Styled {
|
|||
/// Sets the element to justify flex items along the container's main axis
|
||||
/// such that there is an equal amount of space between each item.
|
||||
/// [Docs](https://tailwindcss.com/docs/justify-content#space-between)
|
||||
fn justify_between(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn justify_between(mut self) -> Self {
|
||||
self.style().justify_content = Some(JustifyContent::SpaceBetween);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the element to justify flex items along the center of the container's main axis.
|
||||
/// [Docs](https://tailwindcss.com/docs/justify-content#center)
|
||||
fn justify_center(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn justify_center(mut self) -> Self {
|
||||
self.style().justify_content = Some(JustifyContent::Center);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the element to justify flex items against the start of the container's main axis.
|
||||
/// [Docs](https://tailwindcss.com/docs/justify-content#start)
|
||||
fn justify_start(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn justify_start(mut self) -> Self {
|
||||
self.style().justify_content = Some(JustifyContent::Start);
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the element to justify flex items against the end of the container's main axis.
|
||||
/// [Docs](https://tailwindcss.com/docs/justify-content#end)
|
||||
fn justify_end(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn justify_end(mut self) -> Self {
|
||||
self.style().justify_content = Some(JustifyContent::End);
|
||||
self
|
||||
}
|
||||
|
@ -265,10 +211,7 @@ pub trait Styled {
|
|||
/// Sets the element to justify items along the container's main axis such
|
||||
/// that there is an equal amount of space on each side of each item.
|
||||
/// [Docs](https://tailwindcss.com/docs/justify-content#space-around)
|
||||
fn justify_around(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn justify_around(mut self) -> Self {
|
||||
self.style().justify_content = Some(JustifyContent::SpaceAround);
|
||||
self
|
||||
}
|
||||
|
@ -295,30 +238,21 @@ pub trait Styled {
|
|||
|
||||
/// Sets the box shadow of the element.
|
||||
/// [Docs](https://tailwindcss.com/docs/box-shadow)
|
||||
fn shadow(mut self, shadows: SmallVec<[BoxShadow; 2]>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn shadow(mut self, shadows: SmallVec<[BoxShadow; 2]>) -> Self {
|
||||
self.style().box_shadow = Some(shadows);
|
||||
self
|
||||
}
|
||||
|
||||
/// Clears the box shadow of the element.
|
||||
/// [Docs](https://tailwindcss.com/docs/box-shadow)
|
||||
fn shadow_none(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn shadow_none(mut self) -> Self {
|
||||
self.style().box_shadow = Some(Default::default());
|
||||
self
|
||||
}
|
||||
|
||||
/// Sets the box shadow of the element.
|
||||
/// [Docs](https://tailwindcss.com/docs/box-shadow)
|
||||
fn shadow_sm(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn shadow_sm(mut self) -> Self {
|
||||
self.style().box_shadow = Some(smallvec::smallvec![BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.05),
|
||||
offset: point(px(0.), px(1.)),
|
||||
|
@ -330,10 +264,7 @@ pub trait Styled {
|
|||
|
||||
/// Sets the box shadow of the element.
|
||||
/// [Docs](https://tailwindcss.com/docs/box-shadow)
|
||||
fn shadow_md(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn shadow_md(mut self) -> Self {
|
||||
self.style().box_shadow = Some(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0.5, 0., 0., 0.1),
|
||||
|
@ -353,10 +284,7 @@ pub trait Styled {
|
|||
|
||||
/// Sets the box shadow of the element.
|
||||
/// [Docs](https://tailwindcss.com/docs/box-shadow)
|
||||
fn shadow_lg(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn shadow_lg(mut self) -> Self {
|
||||
self.style().box_shadow = Some(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.1),
|
||||
|
@ -376,10 +304,7 @@ pub trait Styled {
|
|||
|
||||
/// Sets the box shadow of the element.
|
||||
/// [Docs](https://tailwindcss.com/docs/box-shadow)
|
||||
fn shadow_xl(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn shadow_xl(mut self) -> Self {
|
||||
self.style().box_shadow = Some(smallvec![
|
||||
BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.1),
|
||||
|
@ -399,10 +324,7 @@ pub trait Styled {
|
|||
|
||||
/// Sets the box shadow of the element.
|
||||
/// [Docs](https://tailwindcss.com/docs/box-shadow)
|
||||
fn shadow_2xl(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn shadow_2xl(mut self) -> Self {
|
||||
self.style().box_shadow = Some(smallvec![BoxShadow {
|
||||
color: hsla(0., 0., 0., 0.25),
|
||||
offset: point(px(0.), px(25.)),
|
||||
|
@ -417,198 +339,138 @@ pub trait Styled {
|
|||
&mut style.text
|
||||
}
|
||||
|
||||
fn text_color(mut self, color: impl Into<Hsla>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_color(mut self, color: impl Into<Hsla>) -> Self {
|
||||
self.text_style().get_or_insert_with(Default::default).color = Some(color.into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_size(mut self, size: impl Into<AbsoluteLength>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_size(mut self, size: impl Into<AbsoluteLength>) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(size.into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_xs(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_xs(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(0.75).into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_sm(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_sm(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(0.875).into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_base(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_base(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.0).into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_lg(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_lg(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.125).into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_xl(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_xl(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.25).into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_2xl(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_2xl(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.5).into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_3xl(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_3xl(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_size = Some(rems(1.875).into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_none(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_none(mut self) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.underline = None;
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_color(mut self, color: impl Into<Hsla>) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.color = Some(color.into());
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_solid(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_solid(mut self) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.wavy = false;
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_wavy(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_wavy(mut self) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.wavy = true;
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_0(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_0(mut self) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.thickness = px(0.);
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_1(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_1(mut self) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.thickness = px(1.);
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_2(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_2(mut self) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.thickness = px(2.);
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_4(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_4(mut self) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.thickness = px(4.);
|
||||
self
|
||||
}
|
||||
|
||||
fn text_decoration_8(mut self) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn text_decoration_8(mut self) -> Self {
|
||||
let style = self.text_style().get_or_insert_with(Default::default);
|
||||
let underline = style.underline.get_or_insert_with(Default::default);
|
||||
underline.thickness = px(8.);
|
||||
self
|
||||
}
|
||||
|
||||
fn font(mut self, family_name: impl Into<SharedString>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn font(mut self, family_name: impl Into<SharedString>) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.font_family = Some(family_name.into());
|
||||
self
|
||||
}
|
||||
|
||||
fn line_height(mut self, line_height: impl Into<DefiniteLength>) -> Self
|
||||
where
|
||||
Self: Sized,
|
||||
{
|
||||
fn line_height(mut self, line_height: impl Into<DefiniteLength>) -> Self {
|
||||
self.text_style()
|
||||
.get_or_insert_with(Default::default)
|
||||
.line_height = Some(line_height.into());
|
||||
|
|
|
@ -206,7 +206,7 @@ impl<V: Render> From<View<V>> for AnyView {
|
|||
impl<ParentViewState: 'static> Element<ParentViewState> for AnyView {
|
||||
type ElementState = Box<dyn Any>;
|
||||
|
||||
fn id(&self) -> Option<ElementId> {
|
||||
fn element_id(&self) -> Option<ElementId> {
|
||||
Some(self.model.entity_id.into())
|
||||
}
|
||||
|
||||
|
|
|
@ -130,7 +130,7 @@ fn generate_predefined_setter(
|
|||
|
||||
let method = quote! {
|
||||
#[doc = #doc_string]
|
||||
fn #method_name(mut self) -> Self where Self: std::marker::Sized {
|
||||
fn #method_name(mut self) -> Self {
|
||||
let style = self.style();
|
||||
#(#field_assignments)*
|
||||
self
|
||||
|
@ -163,7 +163,7 @@ fn generate_custom_value_setter(
|
|||
|
||||
let method = quote! {
|
||||
#[doc = #doc_string]
|
||||
fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui::#length_type>) -> Self where Self: std::marker::Sized {
|
||||
fn #method_name(mut self, length: impl std::clone::Clone + Into<gpui::#length_type>) -> Self {
|
||||
let style = self.style();
|
||||
#(#field_assignments)*
|
||||
self
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use editor::Editor;
|
||||
use gpui::{
|
||||
div, uniform_list, Component, Div, ParentElement, Render, StatelessInteractive, Styled, Task,
|
||||
div, uniform_list, Component, Node, ParentComponent, Render, Styled, Task,
|
||||
UniformListScrollHandle, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
use std::{cmp, sync::Arc};
|
||||
|
@ -139,11 +139,11 @@ impl<D: PickerDelegate> Picker<D> {
|
|||
}
|
||||
|
||||
impl<D: PickerDelegate> Render for Picker<D> {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div()
|
||||
.context("picker")
|
||||
.key_context("picker")
|
||||
.size_full()
|
||||
.elevation_2(cx)
|
||||
.on_action(Self::select_next)
|
||||
|
|
|
@ -1,12 +1,12 @@
|
|||
use crate::story::Story;
|
||||
use gpui::{px, Div, Render};
|
||||
use gpui::{prelude::*, px, Node, Render};
|
||||
use theme2::{default_color_scales, ColorScaleStep};
|
||||
use ui::prelude::*;
|
||||
|
||||
pub struct ColorsStory;
|
||||
|
||||
impl Render for ColorsStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let color_scales = default_color_scales();
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use gpui::{
|
||||
actions, div, Div, FocusHandle, Focusable, FocusableKeyDispatch, KeyBinding, ParentElement,
|
||||
Render, StatefulInteractivity, StatelessInteractive, Styled, View, VisualContext,
|
||||
actions, div, prelude::*, FocusHandle, Focusable, KeyBinding, Node, Render, Stateful, View,
|
||||
WindowContext,
|
||||
};
|
||||
use theme2::ActiveTheme;
|
||||
|
@ -28,7 +27,7 @@ impl FocusStory {
|
|||
}
|
||||
|
||||
impl Render for FocusStory {
|
||||
type Element = Div<Self, StatefulInteractivity<Self>, FocusableKeyDispatch<Self>>;
|
||||
type Element = Focusable<Self, Stateful<Self, Node<Self>>>;
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
let theme = cx.theme();
|
||||
|
@ -42,7 +41,7 @@ impl Render for FocusStory {
|
|||
div()
|
||||
.id("parent")
|
||||
.focusable()
|
||||
.context("parent")
|
||||
.key_context("parent")
|
||||
.on_action(|_, action: &ActionA, cx| {
|
||||
println!("Action A dispatched on parent");
|
||||
})
|
||||
|
@ -62,7 +61,7 @@ impl Render for FocusStory {
|
|||
.child(
|
||||
div()
|
||||
.track_focus(&self.child_1_focus)
|
||||
.context("child-1")
|
||||
.key_context("child-1")
|
||||
.on_action(|_, action: &ActionB, cx| {
|
||||
println!("Action B dispatched on child 1 during");
|
||||
})
|
||||
|
@ -82,7 +81,7 @@ impl Render for FocusStory {
|
|||
.child(
|
||||
div()
|
||||
.track_focus(&self.child_2_focus)
|
||||
.context("child-2")
|
||||
.key_context("child-2")
|
||||
.on_action(|_, action: &ActionC, cx| {
|
||||
println!("Action C dispatched on child 2");
|
||||
})
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::{story::Story, story_selector::ComponentStory};
|
||||
use gpui::{Div, Render, StatefulInteractivity, View, VisualContext};
|
||||
use gpui::{prelude::*, Node, Render, Stateful, View};
|
||||
use strum::IntoEnumIterator;
|
||||
use ui::prelude::*;
|
||||
|
||||
|
@ -12,7 +12,7 @@ impl KitchenSinkStory {
|
|||
}
|
||||
|
||||
impl Render for KitchenSinkStory {
|
||||
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||
type Element = Stateful<Self, Node<Self>>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let component_stories = ComponentStory::iter()
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use fuzzy::StringMatchCandidate;
|
||||
use gpui::{
|
||||
div, Component, Div, KeyBinding, ParentElement, Render, StatelessInteractive, Styled, Task,
|
||||
View, VisualContext, WindowContext,
|
||||
};
|
||||
use gpui::{div, prelude::*, KeyBinding, Node, Render, Styled, Task, View, WindowContext};
|
||||
use picker::{Picker, PickerDelegate};
|
||||
use std::sync::Arc;
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
pub struct PickerStory {
|
||||
|
@ -38,7 +34,7 @@ impl Delegate {
|
|||
}
|
||||
|
||||
impl PickerDelegate for Delegate {
|
||||
type ListItem = Div<Picker<Self>>;
|
||||
type ListItem = Node<Picker<Self>>;
|
||||
|
||||
fn match_count(&self) -> usize {
|
||||
self.candidates.len()
|
||||
|
@ -207,7 +203,7 @@ impl PickerStory {
|
|||
}
|
||||
|
||||
impl Render for PickerStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
div()
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use gpui::{
|
||||
div, px, Component, Div, ParentElement, Render, SharedString, StatefulInteractivity, Styled,
|
||||
View, VisualContext, WindowContext,
|
||||
div, prelude::*, px, Node, Render, SharedString, Stateful, Styled, View, WindowContext,
|
||||
};
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
|
@ -13,7 +12,7 @@ impl ScrollStory {
|
|||
}
|
||||
|
||||
impl Render for ScrollStory {
|
||||
type Element = Div<Self, StatefulInteractivity<Self>>;
|
||||
type Element = Stateful<Self, Node<Self>>;
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
let theme = cx.theme();
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gpui::{div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext};
|
||||
use gpui::{div, white, Node, ParentComponent, Render, Styled, View, VisualContext, WindowContext};
|
||||
|
||||
pub struct TextStory;
|
||||
|
||||
|
@ -9,7 +9,7 @@ impl TextStory {
|
|||
}
|
||||
|
||||
impl Render for TextStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
|
||||
div().size_full().bg(white()).child(concat!(
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gpui::{px, rgb, Div, Hsla, Render};
|
||||
use gpui::{px, rgb, Hsla, Node, Render};
|
||||
use ui::prelude::*;
|
||||
|
||||
use crate::story::Story;
|
||||
|
@ -8,7 +8,7 @@ use crate::story::Story;
|
|||
pub struct ZIndexStory;
|
||||
|
||||
impl Render for ZIndexStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
@ -77,7 +77,7 @@ trait Styles: Styled + Sized {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> Styles for Div<V> {}
|
||||
impl<V: 'static> Styles for Node<V> {}
|
||||
|
||||
#[derive(Component)]
|
||||
struct ZIndexExample {
|
||||
|
|
|
@ -9,7 +9,7 @@ use std::sync::Arc;
|
|||
|
||||
use clap::Parser;
|
||||
use gpui::{
|
||||
div, px, size, AnyView, AppContext, Bounds, Div, Render, ViewContext, VisualContext,
|
||||
div, px, size, AnyView, AppContext, Bounds, Node, Render, ViewContext, VisualContext,
|
||||
WindowBounds, WindowOptions,
|
||||
};
|
||||
use log::LevelFilter;
|
||||
|
@ -107,7 +107,7 @@ impl StoryWrapper {
|
|||
}
|
||||
|
||||
impl Render for StoryWrapper {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div()
|
||||
|
|
|
@ -40,12 +40,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{ActiveTheme, Story};
|
||||
use gpui::{div, img, px, Div, ParentElement, Render, Styled, ViewContext};
|
||||
use gpui::{div, img, px, Node, ParentComponent, Render, Styled, ViewContext};
|
||||
|
||||
pub struct PlayerStory;
|
||||
|
||||
impl Render for PlayerStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx).child(
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use gpui::{div, Component, Div, ParentElement, Styled, ViewContext};
|
||||
use gpui::{div, Component, Node, ParentComponent, Styled, ViewContext};
|
||||
|
||||
use crate::ActiveTheme;
|
||||
|
||||
pub struct Story {}
|
||||
|
||||
impl Story {
|
||||
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
|
||||
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Node<V> {
|
||||
div()
|
||||
.size_full()
|
||||
.flex()
|
||||
|
|
|
@ -44,12 +44,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct AvatarStory;
|
||||
|
||||
impl Render for AvatarStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use gpui::{div, DefiniteLength, Hsla, MouseButton, WindowContext};
|
||||
use gpui::{div, DefiniteLength, Hsla, MouseButton, StatefulInteractiveComponent, WindowContext};
|
||||
|
||||
use crate::{
|
||||
h_stack, prelude::*, Icon, IconButton, IconColor, IconElement, Label, LabelColor,
|
||||
|
@ -236,13 +236,13 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{h_stack, v_stack, LabelColor, Story};
|
||||
use gpui::{rems, Div, Render};
|
||||
use gpui::{rems, Node, Render};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
pub struct ButtonStory;
|
||||
|
||||
impl Render for ButtonStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let states = InteractionState::iter();
|
||||
|
|
|
@ -1,9 +1,5 @@
|
|||
use gpui::{div, prelude::*, Component, ElementId, Styled, ViewContext};
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::{
|
||||
div, Component, ElementId, ParentElement, StatefulInteractive, StatelessInteractive, Styled,
|
||||
ViewContext,
|
||||
};
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
use crate::{Icon, IconColor, IconElement, Selection};
|
||||
|
@ -175,12 +171,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{h_stack, Story};
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct CheckboxStory;
|
||||
|
||||
impl Render for CheckboxStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -65,12 +65,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::story::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct ContextMenuStory;
|
||||
|
||||
impl Render for ContextMenuStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -47,12 +47,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{Button, Story};
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct DetailsStory;
|
||||
|
||||
impl Render for DetailsStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use gpui::Div;
|
||||
use gpui::Node;
|
||||
|
||||
use crate::{prelude::*, v_stack};
|
||||
|
||||
/// Create an elevated surface.
|
||||
///
|
||||
/// Must be used inside of a relative parent element
|
||||
pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<V>) -> Div<V> {
|
||||
pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<V>) -> Node<V> {
|
||||
let colors = cx.theme().colors();
|
||||
|
||||
// let shadow = BoxShadow {
|
||||
|
@ -23,6 +23,6 @@ pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<
|
|||
.shadow(level.shadow())
|
||||
}
|
||||
|
||||
pub fn modal<V>(cx: &mut ViewContext<V>) -> Div<V> {
|
||||
pub fn modal<V: 'static>(cx: &mut ViewContext<V>) -> Node<V> {
|
||||
elevated_surface(ElevationIndex::ModalSurface, cx)
|
||||
}
|
||||
|
|
|
@ -33,12 +33,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{static_players, Story};
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct FacepileStory;
|
||||
|
||||
impl Render for FacepileStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let players = static_players();
|
||||
|
|
|
@ -204,7 +204,7 @@ pub use stories::*;
|
|||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
use strum::IntoEnumIterator;
|
||||
|
||||
use crate::Story;
|
||||
|
@ -214,7 +214,7 @@ mod stories {
|
|||
pub struct IconStory;
|
||||
|
||||
impl Render for IconStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let icons = Icon::iter();
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use gpui::{rems, MouseButton};
|
||||
|
||||
use crate::{h_stack, prelude::*};
|
||||
use crate::{ClickHandler, Icon, IconColor, IconElement};
|
||||
use gpui::{prelude::*, rems, MouseButton};
|
||||
use std::sync::Arc;
|
||||
|
||||
struct IconButtonHandlers<V: 'static> {
|
||||
click: Option<ClickHandler<V>>,
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
use crate::prelude::*;
|
||||
use crate::Label;
|
||||
use crate::LabelColor;
|
||||
use crate::{prelude::*, Label, LabelColor};
|
||||
use gpui::prelude::*;
|
||||
|
||||
#[derive(Default, PartialEq)]
|
||||
pub enum InputVariant {
|
||||
|
@ -111,12 +110,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct InputStory;
|
||||
|
||||
impl Render for InputStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -158,13 +158,13 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
use itertools::Itertools;
|
||||
|
||||
pub struct KeybindingStory;
|
||||
|
||||
impl Render for KeybindingStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let all_modifier_permutations = ModifierKey::iter().permutations(2);
|
||||
|
|
|
@ -196,12 +196,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct LabelStory;
|
||||
|
||||
impl Render for LabelStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -74,7 +74,7 @@ impl<V: 'static> Modal<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ParentElement<V> for Modal<V> {
|
||||
impl<V: 'static> ParentComponent<V> for Modal<V> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
&mut self.children
|
||||
}
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{h_stack, v_stack, Keybinding, Label, LabelColor};
|
||||
use crate::{h_stack, prelude::*, v_stack, Keybinding, Label, LabelColor};
|
||||
use gpui::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct Palette {
|
||||
|
@ -159,7 +159,7 @@ pub use stories::*;
|
|||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::{ModifierKeys, Story};
|
||||
|
||||
|
@ -168,7 +168,7 @@ mod stories {
|
|||
pub struct PaletteStory;
|
||||
|
||||
impl Render for PaletteStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
{
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gpui::{AbsoluteLength, AnyElement};
|
||||
use gpui::{prelude::*, AbsoluteLength, AnyElement};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
@ -113,7 +113,7 @@ impl<V: 'static> Panel<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ParentElement<V> for Panel<V> {
|
||||
impl<V: 'static> ParentComponent<V> for Panel<V> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
&mut self.children
|
||||
}
|
||||
|
@ -126,12 +126,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{Label, Story};
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{InteractiveComponent, Node, Render};
|
||||
|
||||
pub struct PanelStory;
|
||||
|
||||
impl Render for PanelStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,17 +1,17 @@
|
|||
use gpui::{div, Div};
|
||||
use gpui::{div, Node};
|
||||
|
||||
use crate::StyledExt;
|
||||
|
||||
/// Horizontally stacks elements.
|
||||
///
|
||||
/// Sets `flex()`, `flex_row()`, `items_center()`
|
||||
pub fn h_stack<V: 'static>() -> Div<V> {
|
||||
pub fn h_stack<V: 'static>() -> Node<V> {
|
||||
div().h_flex()
|
||||
}
|
||||
|
||||
/// Vertically stacks elements.
|
||||
///
|
||||
/// Sets `flex()`, `flex_col()`
|
||||
pub fn v_stack<V: 'static>() -> Div<V> {
|
||||
pub fn v_stack<V: 'static>() -> Node<V> {
|
||||
div().v_flex()
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{Icon, IconColor, IconElement, Label, LabelColor};
|
||||
use gpui::{red, Div, ElementId, Render, View, VisualContext};
|
||||
use gpui::{prelude::*, red, ElementId, Node, Render, View};
|
||||
|
||||
#[derive(Component, Clone)]
|
||||
pub struct Tab {
|
||||
|
@ -21,7 +21,7 @@ struct TabDragState {
|
|||
}
|
||||
|
||||
impl Render for TabDragState {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div().w_8().h_4().bg(red())
|
||||
|
@ -178,7 +178,7 @@ mod stories {
|
|||
pub struct TabStory;
|
||||
|
||||
impl Render for TabStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let git_statuses = GitStatus::iter();
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use gpui::AnyElement;
|
||||
use smallvec::SmallVec;
|
||||
|
||||
use crate::prelude::*;
|
||||
use gpui::{prelude::*, AnyElement};
|
||||
use smallvec::SmallVec;
|
||||
|
||||
#[derive(Default, Debug, PartialEq, Eq, Clone, Copy)]
|
||||
pub enum ToastOrigin {
|
||||
|
@ -59,7 +58,7 @@ impl<V: 'static> Toast<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ParentElement<V> for Toast<V> {
|
||||
impl<V: 'static> ParentComponent<V> for Toast<V> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
&mut self.children
|
||||
}
|
||||
|
@ -70,7 +69,7 @@ pub use stories::*;
|
|||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::{Label, Story};
|
||||
|
||||
|
@ -79,7 +78,7 @@ mod stories {
|
|||
pub struct ToastStory;
|
||||
|
||||
impl Render for ToastStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gpui::{div, Component, ParentElement};
|
||||
use gpui::{div, Component, ParentComponent};
|
||||
|
||||
use crate::{Icon, IconColor, IconElement, IconSize};
|
||||
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gpui::{div, Div, ParentElement, Render, SharedString, Styled, ViewContext};
|
||||
use gpui::{div, Node, ParentComponent, Render, SharedString, Styled, ViewContext};
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
|
@ -13,7 +13,7 @@ impl TextTooltip {
|
|||
}
|
||||
|
||||
impl Render for TextTooltip {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let theme = cx.theme();
|
||||
|
|
|
@ -1,8 +1,8 @@
|
|||
use gpui::rems;
|
||||
use gpui::Rems;
|
||||
pub use gpui::{
|
||||
div, Component, Element, ElementId, ParentElement, SharedString, StatefulInteractive,
|
||||
StatelessInteractive, Styled, ViewContext, WindowContext,
|
||||
div, Component, Element, ElementId, InteractiveComponent, ParentComponent, SharedString, Styled,
|
||||
ViewContext, WindowContext,
|
||||
};
|
||||
|
||||
pub use crate::elevation::*;
|
||||
|
|
|
@ -1,11 +1,11 @@
|
|||
use gpui::Div;
|
||||
use gpui::Node;
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct Story {}
|
||||
|
||||
impl Story {
|
||||
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> {
|
||||
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Node<V> {
|
||||
div()
|
||||
.size_full()
|
||||
.flex()
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gpui::{Div, ElementInteractivity, KeyDispatch, Styled, UniformList, ViewContext};
|
||||
use gpui::{Styled, ViewContext};
|
||||
use theme2::ActiveTheme;
|
||||
|
||||
use crate::{ElevationIndex, UITextSize};
|
||||
|
@ -93,11 +93,4 @@ pub trait StyledExt: Styled + Sized {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V, I, F> StyledExt for Div<V, I, F>
|
||||
where
|
||||
I: ElementInteractivity<V>,
|
||||
F: KeyDispatch<V>,
|
||||
{
|
||||
}
|
||||
|
||||
impl<V> StyledExt for UniformList<V> {}
|
||||
impl<E: Styled> StyledExt for E {}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{Icon, IconButton, Label, Panel, PanelSide};
|
||||
use gpui::{rems, AbsoluteLength};
|
||||
use gpui::{prelude::*, rems, AbsoluteLength};
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct AssistantPanel {
|
||||
|
@ -77,11 +77,11 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
pub struct AssistantPanelStory;
|
||||
|
||||
impl Render for AssistantPanelStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,9 +1,7 @@
|
|||
use crate::{h_stack, prelude::*, HighlightedText};
|
||||
use gpui::{prelude::*, Node};
|
||||
use std::path::PathBuf;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{h_stack, HighlightedText};
|
||||
use gpui::Div;
|
||||
|
||||
#[derive(Clone)]
|
||||
pub struct Symbol(pub Vec<HighlightedText>);
|
||||
|
||||
|
@ -18,7 +16,7 @@ impl Breadcrumb {
|
|||
Self { path, symbols }
|
||||
}
|
||||
|
||||
fn render_separator<V: 'static>(&self, cx: &WindowContext) -> Div<V> {
|
||||
fn render_separator<V: 'static>(&self, cx: &WindowContext) -> Node<V> {
|
||||
div()
|
||||
.child(" › ")
|
||||
.text_color(cx.theme().colors().text_muted)
|
||||
|
@ -79,7 +77,7 @@ mod stories {
|
|||
pub struct BreadcrumbStory;
|
||||
|
||||
impl Render for BreadcrumbStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -235,12 +235,12 @@ mod stories {
|
|||
empty_buffer_example, hello_world_rust_buffer_example,
|
||||
hello_world_rust_buffer_with_status_example, Story,
|
||||
};
|
||||
use gpui::{rems, Div, Render};
|
||||
use gpui::{rems, Node, Render};
|
||||
|
||||
pub struct BufferStory;
|
||||
|
||||
impl Render for BufferStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
use gpui::{Div, Render, View, VisualContext};
|
||||
use gpui::{Node, Render, View, VisualContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{h_stack, Icon, IconButton, IconColor, Input};
|
||||
|
@ -27,9 +27,9 @@ impl BufferSearch {
|
|||
}
|
||||
|
||||
impl Render for BufferSearch {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Node<Self> {
|
||||
h_stack()
|
||||
.bg(cx.theme().colors().toolbar_background)
|
||||
.p_2()
|
||||
|
|
|
@ -1,7 +1,6 @@
|
|||
use crate::{prelude::*, Icon, IconButton, Input, Label, LabelColor};
|
||||
use chrono::NaiveDateTime;
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{Icon, IconButton, Input, Label, LabelColor};
|
||||
use gpui::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct ChatPanel {
|
||||
|
@ -108,7 +107,7 @@ pub use stories::*;
|
|||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use chrono::DateTime;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::{Panel, Story};
|
||||
|
||||
|
@ -117,7 +116,7 @@ mod stories {
|
|||
pub struct ChatPanelStory;
|
||||
|
||||
impl Render for ChatPanelStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::{prelude::*, Toggle};
|
||||
use crate::{
|
||||
static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon, List, ListHeader,
|
||||
prelude::*, static_collab_panel_channels, static_collab_panel_current_call, v_stack, Icon,
|
||||
List, ListHeader, Toggle,
|
||||
};
|
||||
use gpui::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct CollabPanel {
|
||||
|
@ -92,12 +93,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct CollabPanelStory;
|
||||
|
||||
impl Render for CollabPanelStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -27,7 +27,7 @@ pub use stories::*;
|
|||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::Story;
|
||||
|
||||
|
@ -36,7 +36,7 @@ mod stories {
|
|||
pub struct CommandPaletteStory;
|
||||
|
||||
impl Render for CommandPaletteStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -25,7 +25,7 @@ pub use stories::*;
|
|||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::Story;
|
||||
|
||||
|
@ -34,7 +34,7 @@ mod stories {
|
|||
pub struct CopilotModalStory;
|
||||
|
||||
impl Render for CopilotModalStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use gpui::{Div, Render, View, VisualContext};
|
||||
use gpui::{Node, Render, View, VisualContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::{
|
||||
|
@ -48,9 +48,9 @@ impl EditorPane {
|
|||
}
|
||||
|
||||
impl Render for EditorPane {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Node<Self> {
|
||||
v_stack()
|
||||
.w_full()
|
||||
.h_full()
|
||||
|
|
|
@ -40,12 +40,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct LanguageSelectorStory;
|
||||
|
||||
impl Render for LanguageSelectorStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -40,12 +40,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{hello_world_rust_buffer_example, Story};
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct MultiBufferStory;
|
||||
|
||||
impl Render for MultiBufferStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,10 +1,9 @@
|
|||
use crate::utils::naive_format_distance_from_now;
|
||||
use crate::{
|
||||
h_stack, prelude::*, static_new_notification_items_2, v_stack, Avatar, ButtonOrIconButton,
|
||||
Icon, IconElement, Label, LabelColor, LineHeightStyle, ListHeaderMeta, ListSeparator,
|
||||
PublicPlayer, UnreadIndicator,
|
||||
h_stack, prelude::*, static_new_notification_items_2, utils::naive_format_distance_from_now,
|
||||
v_stack, Avatar, ButtonOrIconButton, ClickHandler, Icon, IconElement, Label, LabelColor,
|
||||
LineHeightStyle, ListHeader, ListHeaderMeta, ListSeparator, PublicPlayer, UnreadIndicator,
|
||||
};
|
||||
use crate::{ClickHandler, ListHeader};
|
||||
use gpui::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct NotificationsPanel {
|
||||
|
@ -353,12 +352,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{Panel, Story};
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct NotificationsPanelStory;
|
||||
|
||||
impl Render for NotificationsPanelStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -59,7 +59,7 @@ impl<V: 'static> Pane<V> {
|
|||
}
|
||||
}
|
||||
|
||||
impl<V: 'static> ParentElement<V> for Pane<V> {
|
||||
impl<V: 'static> ParentComponent<V> for Pane<V> {
|
||||
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> {
|
||||
&mut self.children
|
||||
}
|
||||
|
|
|
@ -1,7 +1,8 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{
|
||||
static_project_panel_project_items, static_project_panel_single_items, Input, List, ListHeader,
|
||||
prelude::*, static_project_panel_project_items, static_project_panel_single_items, Input, List,
|
||||
ListHeader,
|
||||
};
|
||||
use gpui::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct ProjectPanel {
|
||||
|
@ -54,12 +55,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::{Panel, Story};
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct ProjectPanelStory;
|
||||
|
||||
impl Render for ProjectPanelStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -36,12 +36,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct RecentProjectsStory;
|
||||
|
||||
impl Render for RecentProjectsStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
use crate::prelude::*;
|
||||
use crate::{Icon, IconButton, Tab};
|
||||
use crate::{prelude::*, Icon, IconButton, Tab};
|
||||
use gpui::prelude::*;
|
||||
|
||||
#[derive(Component)]
|
||||
pub struct TabBar {
|
||||
|
@ -100,12 +100,12 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
pub struct TabBarStory;
|
||||
|
||||
impl Render for TabBarStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -83,11 +83,11 @@ pub use stories::*;
|
|||
mod stories {
|
||||
use super::*;
|
||||
use crate::Story;
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
pub struct TerminalStory;
|
||||
|
||||
impl Render for TerminalStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -39,7 +39,7 @@ pub use stories::*;
|
|||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::Story;
|
||||
|
||||
|
@ -48,7 +48,7 @@ mod stories {
|
|||
pub struct ThemeSelectorStory;
|
||||
|
||||
impl Render for ThemeSelectorStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::atomic::AtomicBool;
|
||||
use std::sync::Arc;
|
||||
|
||||
use gpui::{Div, Render, View, VisualContext};
|
||||
use gpui::{Node, Render, View, VisualContext};
|
||||
|
||||
use crate::prelude::*;
|
||||
use crate::settings::user_settings;
|
||||
|
@ -86,9 +86,9 @@ impl TitleBar {
|
|||
}
|
||||
|
||||
impl Render for TitleBar {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Node<Self> {
|
||||
let settings = user_settings(cx);
|
||||
|
||||
// let has_focus = cx.window_is_active();
|
||||
|
@ -202,9 +202,9 @@ mod stories {
|
|||
}
|
||||
|
||||
impl Render for TitleBarStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Node<Self> {
|
||||
Story::container(cx)
|
||||
.child(Story::title_for::<_, TitleBar>(cx))
|
||||
.child(Story::label(cx, "Default"))
|
||||
|
|
|
@ -73,7 +73,7 @@ mod stories {
|
|||
use std::path::PathBuf;
|
||||
use std::str::FromStr;
|
||||
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::{Breadcrumb, HighlightedText, Icon, IconButton, Story, Symbol};
|
||||
|
||||
|
@ -82,7 +82,7 @@ mod stories {
|
|||
pub struct ToolbarStory;
|
||||
|
||||
impl Render for ToolbarStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -77,7 +77,7 @@ pub use stories::*;
|
|||
|
||||
#[cfg(feature = "stories")]
|
||||
mod stories {
|
||||
use gpui::{Div, Render};
|
||||
use gpui::{Node, Render};
|
||||
|
||||
use crate::Story;
|
||||
|
||||
|
@ -86,7 +86,7 @@ mod stories {
|
|||
pub struct TrafficLightsStory;
|
||||
|
||||
impl Render for TrafficLightsStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
Story::container(cx)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use std::sync::Arc;
|
||||
|
||||
use chrono::DateTime;
|
||||
use gpui::{px, relative, Div, Render, Size, View, VisualContext};
|
||||
use gpui::{px, relative, Node, Render, Size, View, VisualContext};
|
||||
use settings2::Settings;
|
||||
use theme2::ThemeSettings;
|
||||
|
||||
|
@ -192,9 +192,9 @@ impl Workspace {
|
|||
}
|
||||
|
||||
impl Render for Workspace {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> {
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Node<Self> {
|
||||
let root_group = PaneGroup::new_panes(
|
||||
vec![Pane::new(
|
||||
"pane-0",
|
||||
|
@ -388,7 +388,7 @@ mod stories {
|
|||
}
|
||||
|
||||
impl Render for WorkspaceStory {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div().child(self.workspace.clone())
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
use crate::{status_bar::StatusItemView, Axis, Workspace};
|
||||
use gpui::{
|
||||
div, Action, AnyView, AppContext, Div, Entity, EntityId, EventEmitter, ParentElement, Render,
|
||||
Subscription, View, ViewContext, WeakView, WindowContext,
|
||||
div, Action, AnyView, AppContext, Entity, EntityId, EventEmitter, Node, ParentComponent,
|
||||
Render, Subscription, View, ViewContext, WeakView, WindowContext,
|
||||
};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
@ -419,7 +419,7 @@ impl Dock {
|
|||
}
|
||||
|
||||
impl Render for Dock {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
todo!()
|
||||
|
@ -621,7 +621,7 @@ impl PanelButtons {
|
|||
// }
|
||||
|
||||
impl Render for PanelButtons {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
// todo!()
|
||||
|
@ -647,7 +647,7 @@ impl StatusItemView for PanelButtons {
|
|||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub mod test {
|
||||
use super::*;
|
||||
use gpui::{div, Div, ViewContext, WindowContext};
|
||||
use gpui::{div, Node, ViewContext, WindowContext};
|
||||
|
||||
pub struct TestPanel {
|
||||
pub position: DockPosition,
|
||||
|
@ -672,7 +672,7 @@ pub mod test {
|
|||
}
|
||||
|
||||
impl Render for TestPanel {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use gpui::{
|
||||
div, px, AnyView, Div, EventEmitter, FocusHandle, ParentElement, Render, StatelessInteractive,
|
||||
Styled, Subscription, View, ViewContext, VisualContext, WindowContext,
|
||||
div, prelude::*, px, AnyView, EventEmitter, FocusHandle, InteractiveComponent, Node,
|
||||
ParentComponent, Render, Styled, Subscription, View, ViewContext, VisualContext, WindowContext,
|
||||
};
|
||||
use ui::v_stack;
|
||||
|
||||
|
@ -76,7 +76,7 @@ impl ModalLayer {
|
|||
}
|
||||
|
||||
impl Render for ModalLayer {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let Some(active_modal) = &self.active_modal else {
|
||||
|
|
|
@ -165,7 +165,7 @@ impl Workspace {
|
|||
|
||||
pub mod simple_message_notification {
|
||||
use super::{Notification, NotificationEvent};
|
||||
use gpui::{AnyElement, AppContext, Div, EventEmitter, Render, TextStyle, ViewContext};
|
||||
use gpui::{AnyElement, AppContext, EventEmitter, Node, Render, TextStyle, ViewContext};
|
||||
use serde::Deserialize;
|
||||
use std::{borrow::Cow, sync::Arc};
|
||||
|
||||
|
@ -252,7 +252,7 @@ pub mod simple_message_notification {
|
|||
}
|
||||
|
||||
impl Render for MessageNotification {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
todo!()
|
||||
|
|
|
@ -1,5 +1,3 @@
|
|||
// mod dragged_item_receiver;
|
||||
|
||||
use crate::{
|
||||
item::{Item, ItemHandle, ItemSettings, WeakItemHandle},
|
||||
toolbar::Toolbar,
|
||||
|
@ -9,9 +7,9 @@ use crate::{
|
|||
use anyhow::Result;
|
||||
use collections::{HashMap, HashSet, VecDeque};
|
||||
use gpui::{
|
||||
actions, register_action, AppContext, AsyncWindowContext, Component, Div, EntityId,
|
||||
EventEmitter, FocusHandle, Model, PromptLevel, Render, Task, View, ViewContext, VisualContext,
|
||||
WeakView, WindowContext,
|
||||
actions, prelude::*, register_action, AppContext, AsyncWindowContext, Component, EntityId,
|
||||
EventEmitter, FocusHandle, Model, Node, PromptLevel, Render, Task, View, ViewContext,
|
||||
VisualContext, WeakView, WindowContext,
|
||||
};
|
||||
use parking_lot::Mutex;
|
||||
use project2::{Project, ProjectEntryId, ProjectPath};
|
||||
|
@ -1903,7 +1901,7 @@ impl Pane {
|
|||
// }
|
||||
|
||||
impl Render for Pane {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
v_stack()
|
||||
|
@ -2928,7 +2926,7 @@ struct DraggedTab {
|
|||
}
|
||||
|
||||
impl Render for DraggedTab {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div().w_8().h_4().bg(gpui::red())
|
||||
|
|
|
@ -2,8 +2,8 @@ use std::any::TypeId;
|
|||
|
||||
use crate::{ItemHandle, Pane};
|
||||
use gpui::{
|
||||
div, AnyView, Component, Div, ParentElement, Render, Styled, Subscription, View, ViewContext,
|
||||
WindowContext,
|
||||
div, AnyView, Component, Node, ParentComponent, Render, Styled, Subscription, View,
|
||||
ViewContext, WindowContext,
|
||||
};
|
||||
use theme2::ActiveTheme;
|
||||
use util::ResultExt;
|
||||
|
@ -34,7 +34,7 @@ pub struct StatusBar {
|
|||
}
|
||||
|
||||
impl Render for StatusBar {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
div()
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
use crate::ItemHandle;
|
||||
use gpui::{
|
||||
AnyView, Div, Entity, EntityId, EventEmitter, Render, View, ViewContext, WindowContext,
|
||||
AnyView, Entity, EntityId, EventEmitter, Node, Render, View, ViewContext, WindowContext,
|
||||
};
|
||||
|
||||
pub enum ToolbarItemEvent {
|
||||
|
@ -52,7 +52,7 @@ pub struct Toolbar {
|
|||
}
|
||||
|
||||
impl Render for Toolbar {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
todo!()
|
||||
|
|
|
@ -36,12 +36,11 @@ use futures::{
|
|||
Future, FutureExt, StreamExt,
|
||||
};
|
||||
use gpui::{
|
||||
actions, div, point, rems, size, Action, AnyModel, AnyView, AnyWeakView, AppContext,
|
||||
AsyncAppContext, AsyncWindowContext, Bounds, Component, Div, Entity, EntityId, EventEmitter,
|
||||
FocusHandle, GlobalPixels, KeyContext, Model, ModelContext, ParentElement, Point, Render, Size,
|
||||
StatefulInteractive, StatelessInteractive, StatelessInteractivity, Styled, Subscription, Task,
|
||||
View, ViewContext, VisualContext, WeakView, WindowBounds, WindowContext, WindowHandle,
|
||||
WindowOptions,
|
||||
actions, div, point, prelude::*, rems, size, Action, AnyModel, AnyView, AnyWeakView,
|
||||
AppContext, AsyncAppContext, AsyncWindowContext, Bounds, Component, Entity, EntityId,
|
||||
EventEmitter, FocusHandle, GlobalPixels, KeyContext, Model, ModelContext, Node,
|
||||
ParentComponent, Point, Render, Size, Styled, Subscription, Task, View, ViewContext, WeakView,
|
||||
WindowBounds, WindowContext, WindowHandle, WindowOptions,
|
||||
};
|
||||
use item::{FollowableItem, FollowableItemHandle, Item, ItemHandle, ItemSettings, ProjectItem};
|
||||
use itertools::Itertools;
|
||||
|
@ -443,7 +442,6 @@ struct Follower {
|
|||
impl AppState {
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test(cx: &mut AppContext) -> Arc<Self> {
|
||||
use gpui::Context;
|
||||
use node_runtime::FakeNodeRuntime;
|
||||
use settings2::SettingsStore;
|
||||
|
||||
|
@ -531,13 +529,7 @@ pub enum Event {
|
|||
pub struct Workspace {
|
||||
weak_self: WeakView<Self>,
|
||||
focus_handle: FocusHandle,
|
||||
workspace_actions: Vec<
|
||||
Box<
|
||||
dyn Fn(
|
||||
Div<Workspace, StatelessInteractivity<Workspace>>,
|
||||
) -> Div<Workspace, StatelessInteractivity<Workspace>>,
|
||||
>,
|
||||
>,
|
||||
workspace_actions: Vec<Box<dyn Fn(Node<Workspace>) -> Node<Workspace>>>,
|
||||
zoomed: Option<AnyWeakView>,
|
||||
zoomed_position: Option<DockPosition>,
|
||||
center: PaneGroup,
|
||||
|
@ -3450,7 +3442,6 @@ impl Workspace {
|
|||
|
||||
#[cfg(any(test, feature = "test-support"))]
|
||||
pub fn test_new(project: Model<Project>, cx: &mut ViewContext<Self>) -> Self {
|
||||
use gpui::Context;
|
||||
use node_runtime::FakeNodeRuntime;
|
||||
|
||||
let client = project.read(cx).client();
|
||||
|
@ -3512,10 +3503,7 @@ impl Workspace {
|
|||
}));
|
||||
}
|
||||
|
||||
fn add_workspace_actions_listeners(
|
||||
&self,
|
||||
mut div: Div<Workspace, StatelessInteractivity<Workspace>>,
|
||||
) -> Div<Workspace, StatelessInteractivity<Workspace>> {
|
||||
fn add_workspace_actions_listeners(&self, mut div: Node<Workspace>) -> Node<Workspace> {
|
||||
for action in self.workspace_actions.iter() {
|
||||
div = (action)(div)
|
||||
}
|
||||
|
@ -3740,14 +3728,14 @@ fn notify_if_database_failed(workspace: WindowHandle<Workspace>, cx: &mut AsyncA
|
|||
impl EventEmitter<Event> for Workspace {}
|
||||
|
||||
impl Render for Workspace {
|
||||
type Element = Div<Self>;
|
||||
type Element = Node<Self>;
|
||||
|
||||
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
|
||||
let mut context = KeyContext::default();
|
||||
context.add("Workspace");
|
||||
|
||||
self.add_workspace_actions_listeners(div())
|
||||
.context(context)
|
||||
.key_context(context)
|
||||
.relative()
|
||||
.size_full()
|
||||
.flex()
|
||||
|
|
Loading…
Reference in a new issue