Detailed changes
@@ -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);
- });
-
- 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());
+ self.interactivity.paint(
+ bounds,
+ bounds.size,
+ element_state,
+ cx,
+ |style, scroll_offset, 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());
+ }
+ })
+ .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()
- }
-}
-
-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()
+ &mut self.interactivity.base_style
}
}
-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,
- };
+ 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(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.),
- };
- }
+ cx.with_z_index(style.z_index.unwrap_or(0), |cx| {
+ style.paint(bounds, cx);
- let overflow = point(style.overflow.x, Overflow::Scroll);
+ 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
+ };
- cx.with_z_index(0, |cx| {
- self.interactivity.handle_events(
- bounds,
- content_size,
- overflow,
- &mut element_state.interactive,
- cx,
- );
- });
- })
+ 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
- fn shadow_md(mut self) -> Self
- where
- Self: Sized,
- {
+ fn shadow_md(mut self) -> Self {
self.style().box_shadow = Some(smallvec
- fn shadow_lg(mut self) -> Self
- where
- Self: Sized,
- {
+ fn shadow_lg(mut self) -> Self {
self.style().box_shadow = Some(smallvec
- fn shadow_xl(mut self) -> Self
- where
- Self: Sized,
- {
+ fn shadow_xl(mut self) -> Self {
self.style().box_shadow = Some(smallvec
- 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()