Clean compile with redesigned element traits

This commit is contained in:
Nathan Sobo 2023-11-18 21:51:47 -07:00
parent 0673606de8
commit 33cd6f520a
35 changed files with 278 additions and 216 deletions

View file

@ -3294,7 +3294,7 @@ impl CollabPanel {
// .with_width(size.x()) // .with_width(size.x())
// } // }
impl Render for CollabPanel { impl Render<Self> for CollabPanel {
type Element = Focusable<Self, Div<Self>>; type Element = Focusable<Self, Div<Self>>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -31,7 +31,7 @@ use std::sync::Arc;
use call::ActiveCall; use call::ActiveCall;
use client::{Client, UserStore}; use client::{Client, UserStore};
use gpui::{ use gpui::{
div, px, rems, AppContext, Component, Div, InteractiveElement, Model, ParentElement, Render, div, px, rems, AppContext, Div, InteractiveElement, Model, ParentElement, Render, RenderOnce,
Stateful, StatefulInteractiveElement, Styled, Subscription, ViewContext, VisualContext, Stateful, StatefulInteractiveElement, Styled, Subscription, ViewContext, VisualContext,
WeakView, WindowBounds, WeakView, WindowBounds,
}; };
@ -81,7 +81,7 @@ pub struct CollabTitlebarItem {
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
impl Render for CollabTitlebarItem { impl Render<Self> for CollabTitlebarItem {
type Element = Stateful<Self, Div<Self>>; type Element = Stateful<Self, Div<Self>>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -1,7 +1,7 @@
use collections::{CommandPaletteFilter, HashMap}; use collections::{CommandPaletteFilter, HashMap};
use fuzzy::{StringMatch, StringMatchCandidate}; use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{ use gpui::{
actions, div, prelude::*, Action, AppContext, Component, Dismiss, Div, FocusHandle, Keystroke, actions, div, prelude::*, Action, AppContext, Dismiss, Div, FocusHandle, Keystroke,
ManagedView, ParentElement, Render, Styled, View, ViewContext, VisualContext, WeakView, ManagedView, ParentElement, Render, Styled, View, ViewContext, VisualContext, WeakView,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
@ -74,7 +74,7 @@ impl ManagedView for CommandPalette {
} }
} }
impl Render for CommandPalette { impl Render<Self> for CommandPalette {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -42,9 +42,9 @@ use gpui::{
actions, div, point, prelude::*, px, relative, rems, size, uniform_list, Action, AnyElement, actions, div, point, prelude::*, px, relative, rems, size, uniform_list, Action, AnyElement,
AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context, AppContext, AsyncWindowContext, BackgroundExecutor, Bounds, ClipboardItem, Component, Context,
EventEmitter, FocusHandle, FocusableView, FontFeatures, FontStyle, FontWeight, HighlightStyle, EventEmitter, FocusHandle, FocusableView, FontFeatures, FontStyle, FontWeight, HighlightStyle,
Hsla, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render, Styled, Hsla, InputHandler, KeyContext, Model, MouseButton, ParentElement, Pixels, Render,
Subscription, Task, TextStyle, UniformListScrollHandle, View, ViewContext, VisualContext, SharedString, Styled, Subscription, Task, TextStyle, UniformListScrollHandle, View,
WeakView, WindowContext, ViewContext, VisualContext, WeakView, WindowContext,
}; };
use highlight_matching_bracket::refresh_matching_bracket_highlights; use highlight_matching_bracket::refresh_matching_bracket_highlights;
use hover_popover::{hide_hover, HoverState}; use hover_popover::{hide_hover, HoverState};
@ -1580,7 +1580,8 @@ impl CodeActionsMenu {
) )
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}) })
.child(action.lsp_action.title.clone()) // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
.child(SharedString::from(action.lsp_action.title.clone()))
}) })
.collect() .collect()
}, },
@ -1595,7 +1596,7 @@ impl CodeActionsMenu {
.max_by_key(|(_, action)| action.lsp_action.title.chars().count()) .max_by_key(|(_, action)| action.lsp_action.title.chars().count())
.map(|(ix, _)| ix), .map(|(ix, _)| ix),
) )
.render_once(); .render_into_any();
if self.deployed_from_indicator { if self.deployed_from_indicator {
*cursor_position.column_mut() = 0; *cursor_position.column_mut() = 0;
@ -4353,19 +4354,19 @@ impl Editor {
style: &EditorStyle, style: &EditorStyle,
is_active: bool, is_active: bool,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Option<AnyElement<Self>> { ) -> Option<IconButton<Self>> {
if self.available_code_actions.is_some() { if self.available_code_actions.is_some() {
Some( Some(
IconButton::new("code_actions_indicator", ui::Icon::Bolt) IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click(
.on_click(|editor: &mut Editor, cx| { |editor: &mut Editor, cx| {
editor.toggle_code_actions( editor.toggle_code_actions(
&ToggleCodeActions { &ToggleCodeActions {
deployed_from_indicator: true, deployed_from_indicator: true,
}, },
cx, cx,
); );
}) },
.into_any(), ),
) )
} else { } else {
None None
@ -4380,7 +4381,7 @@ impl Editor {
line_height: Pixels, line_height: Pixels,
gutter_margin: Pixels, gutter_margin: Pixels,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Vec<Option<AnyElement<Self>>> { ) -> Vec<Option<IconButton<Self>>> {
fold_data fold_data
.iter() .iter()
.enumerate() .enumerate()
@ -4392,16 +4393,16 @@ impl Editor {
FoldStatus::Folded => ui::Icon::ChevronRight, FoldStatus::Folded => ui::Icon::ChevronRight,
FoldStatus::Foldable => ui::Icon::ChevronDown, FoldStatus::Foldable => ui::Icon::ChevronDown,
}; };
IconButton::new(ix as usize, icon) IconButton::new(ix as usize, icon).on_click(
.on_click(move |editor: &mut Editor, cx| match fold_status { move |editor: &mut Editor, cx| match fold_status {
FoldStatus::Folded => { FoldStatus::Folded => {
editor.unfold_at(&UnfoldAt { buffer_row }, cx); editor.unfold_at(&UnfoldAt { buffer_row }, cx);
} }
FoldStatus::Foldable => { FoldStatus::Foldable => {
editor.fold_at(&FoldAt { buffer_row }, cx); editor.fold_at(&FoldAt { buffer_row }, cx);
} }
}) },
.into_any() )
}) })
}) })
.flatten() .flatten()
@ -7792,7 +7793,7 @@ impl Editor {
cx.editor_style.diagnostic_style.clone(), cx.editor_style.diagnostic_style.clone(),
}, },
))) )))
.render_once() .render_into_any()
} }
}), }),
disposition: BlockDisposition::Below, disposition: BlockDisposition::Below,
@ -9994,7 +9995,7 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
cx.write_to_clipboard(ClipboardItem::new(message.clone())); cx.write_to_clipboard(ClipboardItem::new(message.clone()));
}) })
.tooltip(|_, cx| Tooltip::text("Copy diagnostic message", cx)) .tooltip(|_, cx| Tooltip::text("Copy diagnostic message", cx))
.render_once() .render_into_any()
}) })
} }

View file

@ -3048,7 +3048,7 @@ fn test_move_line_up_down_with_blocks(cx: &mut TestAppContext) {
position: snapshot.anchor_after(Point::new(2, 0)), position: snapshot.anchor_after(Point::new(2, 0)),
disposition: BlockDisposition::Below, disposition: BlockDisposition::Below,
height: 1, height: 1,
render: Arc::new(|_| div().render_once()), render: Arc::new(|_| div().into_any()),
}], }],
Some(Autoscroll::fit()), Some(Autoscroll::fit()),
cx, cx,

View file

@ -490,6 +490,7 @@ impl EditorElement {
for (ix, fold_indicator) in layout.fold_indicators.drain(..).enumerate() { for (ix, fold_indicator) in layout.fold_indicators.drain(..).enumerate() {
if let Some(mut fold_indicator) = fold_indicator { if let Some(mut fold_indicator) = fold_indicator {
let mut fold_indicator = fold_indicator.render_into_any();
let available_space = size( let available_space = size(
AvailableSpace::MinContent, AvailableSpace::MinContent,
AvailableSpace::Definite(line_height * 0.55), AvailableSpace::Definite(line_height * 0.55),
@ -509,20 +510,21 @@ impl EditorElement {
} }
} }
if let Some(mut indicator) = layout.code_actions_indicator.take() { if let Some(indicator) = layout.code_actions_indicator.take() {
let mut button = indicator.button.render_into_any();
let available_space = size( let available_space = size(
AvailableSpace::MinContent, AvailableSpace::MinContent,
AvailableSpace::Definite(line_height), AvailableSpace::Definite(line_height),
); );
let indicator_size = indicator.element.measure(available_space, editor, cx); let indicator_size = button.measure(available_space, editor, cx);
let mut x = Pixels::ZERO; let mut x = Pixels::ZERO;
let mut y = indicator.row as f32 * line_height - scroll_top; let mut y = indicator.row as f32 * line_height - scroll_top;
// Center indicator. // Center indicator.
x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.; x += ((layout.gutter_padding + layout.gutter_margin) - indicator_size.width) / 2.;
y += (line_height - indicator_size.height) / 2.; y += (line_height - indicator_size.height) / 2.;
indicator
.element button.draw(bounds.origin + point(x, y), available_space, editor, cx);
.draw(bounds.origin + point(x, y), available_space, editor, cx);
} }
} }
@ -1810,7 +1812,7 @@ impl EditorElement {
.render_code_actions_indicator(&style, active, cx) .render_code_actions_indicator(&style, active, cx)
.map(|element| CodeActionsIndicator { .map(|element| CodeActionsIndicator {
row: newest_selection_head.row(), row: newest_selection_head.row(),
element, button: element,
}); });
} }
} }
@ -2041,14 +2043,19 @@ impl EditorElement {
// Can't use .and_then() because `.file_name()` and `.parent()` return references :( // Can't use .and_then() because `.file_name()` and `.parent()` return references :(
if let Some(path) = path { if let Some(path) = path {
filename = path.file_name().map(|f| f.to_string_lossy().to_string()); filename = path.file_name().map(|f| f.to_string_lossy().to_string());
parent_path = parent_path = path
path.parent().map(|p| p.to_string_lossy().to_string() + "/"); .parent()
.map(|p| SharedString::from(p.to_string_lossy().to_string() + "/"));
} }
h_stack() h_stack()
.size_full() .size_full()
.bg(gpui::red()) .bg(gpui::red())
.child(filename.unwrap_or_else(|| "untitled".to_string())) .child(
filename
.map(SharedString::from)
.unwrap_or_else(|| "untitled".into()),
)
.children(parent_path) .children(parent_path)
.children(jump_icon) // .p_x(gutter_padding) .children(jump_icon) // .p_x(gutter_padding)
} else { } else {
@ -2059,7 +2066,7 @@ impl EditorElement {
.child("") .child("")
.children(jump_icon) // .p_x(gutter_padding) .children(jump_icon) // .p_x(gutter_padding)
}; };
element.render() element.into_any()
} }
}; };
@ -2391,10 +2398,6 @@ enum Invisible {
impl Element<Editor> for EditorElement { impl Element<Editor> for EditorElement {
type State = (); type State = ();
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.editor_id.into())
}
fn layout( fn layout(
&mut self, &mut self,
editor: &mut Editor, editor: &mut Editor,
@ -2469,6 +2472,10 @@ impl Element<Editor> for EditorElement {
impl RenderOnce<Editor> for EditorElement { impl RenderOnce<Editor> for EditorElement {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.editor_id.into())
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -3098,14 +3105,14 @@ pub struct LayoutState {
context_menu: Option<(DisplayPoint, AnyElement<Editor>)>, context_menu: Option<(DisplayPoint, AnyElement<Editor>)>,
code_actions_indicator: Option<CodeActionsIndicator>, code_actions_indicator: Option<CodeActionsIndicator>,
// hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>, // hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>,
fold_indicators: Vec<Option<AnyElement<Editor>>>, fold_indicators: Vec<Option<IconButton<Editor>>>,
tab_invisible: ShapedLine, tab_invisible: ShapedLine,
space_invisible: ShapedLine, space_invisible: ShapedLine,
} }
struct CodeActionsIndicator { struct CodeActionsIndicator {
row: u32, row: u32,
element: AnyElement<Editor>, button: IconButton<Editor>,
} }
struct PositionMap { struct PositionMap {

View file

@ -2,9 +2,8 @@ use collections::HashMap;
use editor::{scroll::autoscroll::Autoscroll, Bias, Editor}; use editor::{scroll::autoscroll::Autoscroll, Bias, Editor};
use fuzzy::{CharBag, PathMatch, PathMatchCandidate}; use fuzzy::{CharBag, PathMatch, PathMatchCandidate};
use gpui::{ use gpui::{
actions, div, AppContext, Component, Dismiss, Div, FocusHandle, InteractiveElement, actions, div, AppContext, Dismiss, Div, FocusHandle, InteractiveElement, ManagedView, Model,
ManagedView, Model, ParentElement, Render, Styled, Task, View, ViewContext, VisualContext, ParentElement, Render, RenderOnce, Styled, Task, View, ViewContext, VisualContext, WeakView,
WeakView,
}; };
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId}; use project::{PathMatchCandidateSet, Project, ProjectPath, WorktreeId};
@ -116,7 +115,7 @@ impl ManagedView for FileFinder {
self.picker.focus_handle(cx) self.picker.focus_handle(cx)
} }
} }
impl Render for FileFinder { impl Render<Self> for FileFinder {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -143,7 +143,7 @@ impl GoToLine {
} }
} }
impl Render for GoToLine { impl Render<Self> for GoToLine {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -14,12 +14,50 @@ pub trait Render<V: 'static>: 'static + Sized {
pub trait RenderOnce<V: 'static>: Sized { pub trait RenderOnce<V: 'static>: Sized {
type Element: Element<V> + 'static; type Element: Element<V> + 'static;
fn element_id(&self) -> Option<ElementId>;
fn render_once(self) -> Self::Element; fn render_once(self) -> Self::Element;
fn render_into_any(self) -> AnyElement<V> { fn render_into_any(self) -> AnyElement<V> {
self.render_once().into_any() self.render_once().into_any()
} }
fn draw<T, R>(
self,
origin: Point<Pixels>,
available_space: Size<T>,
view_state: &mut V,
cx: &mut ViewContext<V>,
f: impl FnOnce(&mut <Self::Element as Element<V>>::State, &mut ViewContext<V>) -> R,
) -> R
where
T: Clone + Default + Debug + Into<AvailableSpace>,
{
let element = self.render_once();
let element_id = element.element_id();
let element = DrawableElement {
element: Some(element),
phase: ElementDrawPhase::Start,
};
let frame_state = DrawableElement::draw(
element,
origin,
available_space.map(Into::into),
view_state,
cx,
);
if let Some(mut frame_state) = frame_state {
f(&mut frame_state, cx)
} else {
cx.with_element_state(element_id.unwrap(), |element_state, cx| {
let mut element_state = element_state.unwrap();
let result = f(&mut element_state, cx);
(result, element_state)
})
}
}
fn map<U>(self, f: impl FnOnce(Self) -> U) -> U fn map<U>(self, f: impl FnOnce(Self) -> U) -> U
where where
Self: Sized, Self: Sized,
@ -52,8 +90,6 @@ pub trait RenderOnce<V: 'static>: Sized {
pub trait Element<V: 'static>: 'static + RenderOnce<V> { pub trait Element<V: 'static>: 'static + RenderOnce<V> {
type State: 'static; type State: 'static;
fn element_id(&self) -> Option<ElementId>;
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -72,35 +108,6 @@ pub trait Element<V: 'static>: 'static + RenderOnce<V> {
fn into_any(self) -> AnyElement<V> { fn into_any(self) -> AnyElement<V> {
AnyElement::new(self) AnyElement::new(self)
} }
fn draw<T, R>(
self,
origin: Point<Pixels>,
available_space: Size<T>,
view_state: &mut V,
cx: &mut ViewContext<V>,
f: impl FnOnce(&mut Self::State, &mut ViewContext<V>) -> R,
) -> R
where
T: Clone + Default + Debug + Into<AvailableSpace>,
{
let element_id = self.element_id();
let element = DrawableElement {
element: Some(self),
phase: ElementDrawPhase::Start,
};
let frame_state = element.draw(origin, available_space.map(Into::into), view_state, cx);
if let Some(mut frame_state) = frame_state {
f(&mut frame_state, cx)
} else {
cx.with_element_state(element_id.unwrap(), |element_state, cx| {
let mut element_state = element_state.unwrap();
let result = f(&mut element_state, cx);
(result, element_state)
})
}
}
} }
pub trait Component<V: 'static>: 'static { pub trait Component<V: 'static>: 'static {
@ -131,10 +138,6 @@ impl<V, C> CompositeElement<V, C> {
impl<V: 'static, C: Component<V>> Element<V> for CompositeElement<V, C> { impl<V: 'static, C: Component<V>> Element<V> for CompositeElement<V, C> {
type State = CompositeElementState<V, C>; type State = CompositeElementState<V, C>;
fn element_id(&self) -> Option<ElementId> {
None
}
fn layout( fn layout(
&mut self, &mut self,
view: &mut V, view: &mut V,
@ -174,6 +177,10 @@ impl<V: 'static, C: Component<V>> Element<V> for CompositeElement<V, C> {
impl<V: 'static, C: Component<V>> RenderOnce<V> for CompositeElement<V, C> { impl<V: 'static, C: Component<V>> RenderOnce<V> for CompositeElement<V, C> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -231,23 +238,21 @@ pub struct DrawableElement<V: 'static, E: Element<V>> {
} }
#[derive(Default)] #[derive(Default)]
enum ElementDrawPhase<V> { enum ElementDrawPhase<S> {
#[default] #[default]
Start, Start,
LayoutRequested { LayoutRequested {
layout_id: LayoutId, layout_id: LayoutId,
frame_state: Option<V>, frame_state: Option<S>,
}, },
LayoutComputed { LayoutComputed {
layout_id: LayoutId, layout_id: LayoutId,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
frame_state: Option<V>, frame_state: Option<S>,
}, },
} }
/// Internal struct that wraps an element to store Layout and ElementState after the element is rendered. /// A wrapper around an implementer of [Element] that allows it to be drawn in a window.
/// It's allocated as a trait object to erase the element type and wrapped in AnyElement<E::State> for
/// improved usability.
impl<V, E: Element<V>> DrawableElement<V, E> { impl<V, E: Element<V>> DrawableElement<V, E> {
fn new(element: E) -> Self { fn new(element: E) -> Self {
DrawableElement { DrawableElement {
@ -379,6 +384,41 @@ impl<V, E: Element<V>> DrawableElement<V, E> {
} }
} }
// impl<V: 'static, E: Element<V>> Element<V> for DrawableElement<V, E> {
// type State = <E::Element as Element<V>>::State;
// fn layout(
// &mut self,
// view_state: &mut V,
// element_state: Option<Self::State>,
// cx: &mut ViewContext<V>,
// ) -> (LayoutId, Self::State) {
// }
// fn paint(
// self,
// bounds: Bounds<Pixels>,
// view_state: &mut V,
// element_state: &mut Self::State,
// cx: &mut ViewContext<V>,
// ) {
// todo!()
// }
// }
// impl<V: 'static, E: 'static + Element<V>> RenderOnce<V> for DrawableElement<V, E> {
// type Element = Self;
// fn element_id(&self) -> Option<ElementId> {
// self.element.as_ref()?.element_id()
// }
// fn render_once(self) -> Self::Element {
// self
// }
// }
impl<V, E> ElementObject<V> for Option<DrawableElement<V, E>> impl<V, E> ElementObject<V> for Option<DrawableElement<V, E>>
where where
E: Element<V>, E: Element<V>,
@ -476,10 +516,6 @@ impl<V: 'static> AnyElement<V> {
impl<V: 'static> Element<V> for AnyElement<V> { impl<V: 'static> Element<V> for AnyElement<V> {
type State = (); type State = ();
fn element_id(&self) -> Option<ElementId> {
AnyElement::element_id(self)
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -504,6 +540,10 @@ impl<V: 'static> Element<V> for AnyElement<V> {
impl<V: 'static> RenderOnce<V> for AnyElement<V> { impl<V: 'static> RenderOnce<V> for AnyElement<V> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
AnyElement::element_id(self)
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -602,10 +602,6 @@ impl<V: 'static> ParentElement<V> for Div<V> {
impl<V: 'static> Element<V> for Div<V> { impl<V: 'static> Element<V> for Div<V> {
type State = DivState; type State = DivState;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -694,6 +690,10 @@ impl<V: 'static> Element<V> for Div<V> {
impl<V: 'static> RenderOnce<V> for Div<V> { impl<V: 'static> RenderOnce<V> for Div<V> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -1293,10 +1293,6 @@ where
{ {
type State = E::State; type State = E::State;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -1324,6 +1320,10 @@ where
{ {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -1381,10 +1381,6 @@ where
{ {
type State = E::State; type State = E::State;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -1412,6 +1408,10 @@ where
{ {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.element.element_id()
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -37,10 +37,6 @@ where
impl<V> Element<V> for Img<V> { impl<V> Element<V> for Img<V> {
type State = InteractiveElementState; type State = InteractiveElementState;
fn element_id(&self) -> Option<crate::ElementId> {
self.interactivity.element_id.clone()
}
fn layout( fn layout(
&mut self, &mut self,
_view_state: &mut V, _view_state: &mut V,
@ -98,6 +94,10 @@ impl<V> Element<V> for Img<V> {
impl<V: 'static> RenderOnce<V> for Img<V> { impl<V: 'static> RenderOnce<V> for Img<V> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -60,10 +60,6 @@ impl<V: 'static> ParentElement<V> for Overlay<V> {
impl<V: 'static> Element<V> for Overlay<V> { impl<V: 'static> Element<V> for Overlay<V> {
type State = OverlayState; type State = OverlayState;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -160,6 +156,10 @@ impl<V: 'static> Element<V> for Overlay<V> {
impl<V: 'static> RenderOnce<V> for Overlay<V> { impl<V: 'static> RenderOnce<V> for Overlay<V> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -26,10 +26,6 @@ impl<V> Svg<V> {
impl<V> Element<V> for Svg<V> { impl<V> Element<V> for Svg<V> {
type State = InteractiveElementState; type State = InteractiveElementState;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn layout( fn layout(
&mut self, &mut self,
_view_state: &mut V, _view_state: &mut V,
@ -62,6 +58,10 @@ impl<V> Element<V> for Svg<V> {
impl<V: 'static> RenderOnce<V> for Svg<V> { impl<V: 'static> RenderOnce<V> for Svg<V> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.interactivity.element_id.clone()
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -11,10 +11,6 @@ use util::ResultExt;
impl<V: 'static> Element<V> for &'static str { impl<V: 'static> Element<V> for &'static str {
type State = TextState; type State = TextState;
fn element_id(&self) -> Option<ElementId> {
None
}
fn layout( fn layout(
&mut self, &mut self,
_: &mut V, _: &mut V,
@ -40,6 +36,10 @@ impl<V: 'static> Element<V> for &'static str {
impl<V: 'static> RenderOnce<V> for &'static str { impl<V: 'static> RenderOnce<V> for &'static str {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -48,10 +48,6 @@ impl<V: 'static> RenderOnce<V> for &'static str {
impl<V: 'static> Element<V> for SharedString { impl<V: 'static> Element<V> for SharedString {
type State = TextState; type State = TextState;
fn element_id(&self) -> Option<ElementId> {
Some(self.clone().into())
}
fn layout( fn layout(
&mut self, &mut self,
_: &mut V, _: &mut V,
@ -78,6 +74,10 @@ impl<V: 'static> Element<V> for SharedString {
impl<V: 'static> RenderOnce<V> for SharedString { impl<V: 'static> RenderOnce<V> for SharedString {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
Some(self.clone().into())
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -105,10 +105,6 @@ impl StyledText {
impl<V: 'static> Element<V> for StyledText { impl<V: 'static> Element<V> for StyledText {
type State = TextState; type State = TextState;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn layout( fn layout(
&mut self, &mut self,
_view: &mut V, _view: &mut V,
@ -194,6 +190,10 @@ impl<V: 'static> Element<V> for StyledText {
impl<V: 'static> RenderOnce<V> for StyledText { impl<V: 'static> RenderOnce<V> for StyledText {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
None
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -300,10 +300,6 @@ struct InteractiveTextState {
impl<V: 'static> Element<V> for InteractiveText { impl<V: 'static> Element<V> for InteractiveText {
type State = InteractiveTextState; type State = InteractiveTextState;
fn element_id(&self) -> Option<ElementId> {
Some(self.id.clone())
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -346,6 +342,10 @@ impl<V: 'static> Element<V> for InteractiveText {
impl<V: 'static> RenderOnce<V> for InteractiveText { impl<V: 'static> RenderOnce<V> for InteractiveText {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
Some(self.id.clone())
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -104,10 +104,6 @@ pub struct UniformListState {
impl<V: 'static> Element<V> for UniformList<V> { impl<V: 'static> Element<V> for UniformList<V> {
type State = UniformListState; type State = UniformListState;
fn element_id(&self) -> Option<crate::ElementId> {
Some(self.id.clone())
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -255,6 +251,10 @@ impl<V: 'static> Element<V> for UniformList<V> {
impl<V> RenderOnce<V> for UniformList<V> { impl<V> RenderOnce<V> for UniformList<V> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<crate::ElementId> {
Some(self.id.clone())
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -208,10 +208,6 @@ impl<V: 'static + Render<V>> From<View<V>> for AnyView {
impl<V: 'static + Render<V>, ParentV: 'static> Element<ParentV> for View<V> { impl<V: 'static + Render<V>, ParentV: 'static> Element<ParentV> for View<V> {
type State = Option<AnyElement<V>>; type State = Option<AnyElement<V>>;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn layout( fn layout(
&mut self, &mut self,
_parent_view: &mut ParentV, _parent_view: &mut ParentV,
@ -241,6 +237,10 @@ impl<V: 'static + Render<V>, ParentV: 'static> Element<ParentV> for View<V> {
impl<V: 'static + Render<V>, ParentV: 'static> RenderOnce<ParentV> for View<V> { impl<V: 'static + Render<V>, ParentV: 'static> RenderOnce<ParentV> for View<V> {
type Element = View<V>; type Element = View<V>;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -249,10 +249,6 @@ impl<V: 'static + Render<V>, ParentV: 'static> RenderOnce<ParentV> for View<V> {
impl<V: 'static> Element<V> for AnyView { impl<V: 'static> Element<V> for AnyView {
type State = Option<Box<dyn Any>>; type State = Option<Box<dyn Any>>;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn layout( fn layout(
&mut self, &mut self,
_view_state: &mut V, _view_state: &mut V,
@ -277,6 +273,10 @@ impl<V: 'static> Element<V> for AnyView {
impl<ParentV: 'static> RenderOnce<ParentV> for AnyView { impl<ParentV: 'static> RenderOnce<ParentV> for AnyView {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
Some(self.model.entity_id.into())
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -334,10 +334,6 @@ where
{ {
type State = Option<AnyElement<V>>; type State = Option<AnyElement<V>>;
fn element_id(&self) -> Option<ElementId> {
Some(self.view.entity_id().into())
}
fn layout( fn layout(
&mut self, &mut self,
_: &mut ParentV, _: &mut ParentV,
@ -371,6 +367,10 @@ where
{ {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<ElementId> {
self.element.as_ref().unwrap().element_id()
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }

View file

@ -33,6 +33,10 @@ pub fn derive_render_once(input: TokenStream) -> TokenStream {
{ {
type Element = gpui::CompositeElement<#view_type, Self>; type Element = gpui::CompositeElement<#view_type, Self>;
fn element_id(&self) -> Option<ElementId> {
None
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
gpui::CompositeElement::new(self) gpui::CompositeElement::new(self)
} }

View file

@ -1,7 +1,7 @@
use editor::Editor; use editor::Editor;
use gpui::{ use gpui::{
div, prelude::*, uniform_list, AppContext, Component, Div, FocusHandle, FocusableView, div, prelude::*, uniform_list, AppContext, Div, FocusHandle, FocusableView, MouseButton,
MouseButton, Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext, Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext,
}; };
use std::{cmp, sync::Arc}; use std::{cmp, sync::Arc};
use ui::{prelude::*, v_stack, Divider, Label, TextColor}; use ui::{prelude::*, v_stack, Divider, Label, TextColor};
@ -15,7 +15,7 @@ pub struct Picker<D: PickerDelegate> {
} }
pub trait PickerDelegate: Sized + 'static { pub trait PickerDelegate: Sized + 'static {
type ListItem: Component<Picker<Self>>; type ListItem: RenderOnce<Picker<Self>>;
fn match_count(&self) -> usize; fn match_count(&self) -> usize;
fn selected_index(&self) -> usize; fn selected_index(&self) -> usize;
@ -180,7 +180,7 @@ impl<D: PickerDelegate> Picker<D> {
} }
} }
impl<D: PickerDelegate> Render for Picker<D> { impl<D: PickerDelegate> Render<Self> for Picker<D> {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -9,9 +9,9 @@ use file_associations::FileAssociations;
use anyhow::{anyhow, Result}; use anyhow::{anyhow, Result};
use gpui::{ use gpui::{
actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext, actions, div, px, uniform_list, Action, AppContext, AssetSource, AsyncWindowContext,
ClipboardItem, Component, Div, EventEmitter, FocusHandle, Focusable, FocusableView, ClipboardItem, Div, EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement,
InteractiveElement, Model, MouseButton, ParentElement, Pixels, Point, PromptLevel, Render, Model, MouseButton, ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, Stateful,
Stateful, StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, ViewContext, StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, ViewContext,
VisualContext as _, WeakView, WindowContext, VisualContext as _, WeakView, WindowContext,
}; };
use menu::{Confirm, SelectNext, SelectPrev}; use menu::{Confirm, SelectNext, SelectPrev};
@ -1423,7 +1423,7 @@ impl ProjectPanel {
} }
} }
impl Render for ProjectPanel { impl Render<Self> for ProjectPanel {
type Element = Focusable<Self, Stateful<Self, Div<Self>>>; type Element = Focusable<Self, Stateful<Self, Div<Self>>>;
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View file

@ -5,7 +5,7 @@ use ui::prelude::*;
pub struct ColorsStory; pub struct ColorsStory;
impl Render for ColorsStory { impl Render<Self> for ColorsStory {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@ -28,7 +28,7 @@ impl Render for ColorsStory {
div() div()
.w(px(75.)) .w(px(75.))
.line_height(px(24.)) .line_height(px(24.))
.child(scale.name().to_string()), .child(scale.name().clone()),
) )
.child( .child(
div() div()

View file

@ -26,7 +26,7 @@ impl FocusStory {
} }
} }
impl Render for FocusStory { impl Render<Self> for FocusStory {
type Element = Focusable<Self, Stateful<Self, Div<Self>>>; type Element = Focusable<Self, Stateful<Self, Div<Self>>>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View file

@ -11,7 +11,7 @@ impl KitchenSinkStory {
} }
} }
impl Render for KitchenSinkStory { impl Render<Self> for KitchenSinkStory {
type Element = Stateful<Self, Div<Self>>; type Element = Stateful<Self, Div<Self>>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -1,5 +1,7 @@
use fuzzy::StringMatchCandidate; use fuzzy::StringMatchCandidate;
use gpui::{div, prelude::*, Div, KeyBinding, Render, Styled, Task, View, WindowContext}; use gpui::{
div, prelude::*, Div, KeyBinding, Render, SharedString, Styled, Task, View, WindowContext,
};
use picker::{Picker, PickerDelegate}; use picker::{Picker, PickerDelegate};
use std::sync::Arc; use std::sync::Arc;
use theme2::ActiveTheme; use theme2::ActiveTheme;
@ -54,7 +56,8 @@ impl PickerDelegate for Delegate {
let Some(candidate_ix) = self.matches.get(ix) else { let Some(candidate_ix) = self.matches.get(ix) else {
return div(); return div();
}; };
let candidate = self.candidates[*candidate_ix].string.clone(); // TASK: Make StringMatchCandidate::string a SharedString
let candidate = SharedString::from(self.candidates[*candidate_ix].string.clone());
div() div()
.text_color(colors.text) .text_color(colors.text)
@ -202,7 +205,7 @@ impl PickerStory {
} }
} }
impl Render for PickerStory { impl Render<Self> for PickerStory {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View file

@ -10,7 +10,7 @@ impl ScrollStory {
} }
} }
impl Render for ScrollStory { impl Render<Self> for ScrollStory {
type Element = Stateful<Self, Div<Self>>; type Element = Stateful<Self, Div<Self>>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View file

@ -1,6 +1,4 @@
use gpui::{ use gpui::{div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext};
div, white, Div, ParentElement, Render, Styled, View, VisualContext, WindowContext,
};
pub struct TextStory; pub struct TextStory;
@ -10,7 +8,7 @@ impl TextStory {
} }
} }
impl Render for TextStory { impl Render<Self> for TextStory {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {

View file

@ -1,4 +1,4 @@
use gpui::{px, rgb, Div, Hsla, Render}; use gpui::{px, rgb, Div, Hsla, Render, RenderOnce};
use ui::prelude::*; use ui::prelude::*;
use crate::story::Story; use crate::story::Story;
@ -7,7 +7,7 @@ use crate::story::Story;
/// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index). /// [https://developer.mozilla.org/en-US/docs/Web/CSS/z-index](https://developer.mozilla.org/en-US/docs/Web/CSS/z-index).
pub struct ZIndexStory; pub struct ZIndexStory;
impl Render for ZIndexStory { impl Render<Self> for ZIndexStory {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@ -79,17 +79,15 @@ trait Styles: Styled + Sized {
impl<V: 'static> Styles for Div<V> {} impl<V: 'static> Styles for Div<V> {}
// #[derive(RenderOnce)] #[derive(RenderOnce)]
struct ZIndexExample { struct ZIndexExample {
z_index: u32, z_index: u32,
} }
impl ZIndexExample { impl<V: 'static> Component<V> for ZIndexExample {
pub fn new(z_index: u32) -> Self { type Rendered = Div<V>;
Self { z_index }
}
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
div() div()
.relative() .relative()
.size_full() .size_full()
@ -109,14 +107,14 @@ impl ZIndexExample {
// HACK: Simulate `text-align: center`. // HACK: Simulate `text-align: center`.
.pl(px(24.)) .pl(px(24.))
.z_index(self.z_index) .z_index(self.z_index)
.child(format!( .child(SharedString::from(format!(
"z-index: {}", "z-index: {}",
if self.z_index == 0 { if self.z_index == 0 {
"auto".to_string() "auto".to_string()
} else { } else {
self.z_index.to_string() self.z_index.to_string()
} }
)), ))),
) )
// Blue blocks. // Blue blocks.
.child( .child(
@ -173,3 +171,9 @@ impl ZIndexExample {
) )
} }
} }
impl ZIndexExample {
pub fn new(z_index: u32) -> Self {
Self { z_index }
}
}

View file

@ -105,7 +105,7 @@ impl StoryWrapper {
} }
} }
impl Render for StoryWrapper { impl Render<Self> for StoryWrapper {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -335,7 +335,7 @@ impl TerminalPanel {
impl EventEmitter<PanelEvent> for TerminalPanel {} impl EventEmitter<PanelEvent> for TerminalPanel {}
impl Render for TerminalPanel { impl Render<Self> for TerminalPanel {
type Element = Div<Self>; type Element = Div<Self>;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {

View file

@ -9,7 +9,7 @@ pub mod terminal_panel;
// use crate::terminal_element::TerminalElement; // use crate::terminal_element::TerminalElement;
use editor::{scroll::autoscroll::Autoscroll, Editor}; use editor::{scroll::autoscroll::Autoscroll, Editor};
use gpui::{ use gpui::{
actions, div, img, red, Action, AnyElement, AppContext, Component, DispatchPhase, Div, actions, div, img, red, Action, AnyElement, AppContext, DispatchPhase, Div, Element,
EventEmitter, FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, EventEmitter, FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView,
InputHandler, InteractiveElement, KeyDownEvent, Keystroke, Model, MouseButton, ParentElement, InputHandler, InteractiveElement, KeyDownEvent, Keystroke, Model, MouseButton, ParentElement,
Pixels, Render, SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, Pixels, Render, SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView,
@ -538,7 +538,7 @@ impl TerminalView {
} }
} }
impl Render for TerminalView { impl Render<Self> for TerminalView {
type Element = Focusable<Self, Div<Self>>; type Element = Focusable<Self, Div<Self>>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@ -578,7 +578,7 @@ impl Render for TerminalView {
.children( .children(
self.context_menu self.context_menu
.clone() .clone()
.map(|context_menu| div().z_index(1).absolute().child(context_menu.render())), .map(|context_menu| div().z_index(1).absolute().child(context_menu)),
) )
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)
.on_focus_in(Self::focus_in) .on_focus_in(Self::focus_in)
@ -756,8 +756,8 @@ impl Item for TerminalView {
div() div()
.child(img().uri("icons/terminal.svg").bg(red())) .child(img().uri("icons/terminal.svg").bg(red()))
.child(title) .child(SharedString::from(title))
.render() .into_any()
} }
fn clone_on_split( fn clone_on_split(

View file

@ -78,7 +78,7 @@ impl Render<Self> for ContextMenu {
} }
pub struct MenuHandle<V: 'static, M: ManagedView> { pub struct MenuHandle<V: 'static, M: ManagedView> {
id: Option<ElementId>, id: ElementId,
child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement<V> + 'static>>, child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement<V> + 'static>>,
menu_builder: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static>>, menu_builder: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static>>,
@ -87,11 +87,6 @@ pub struct MenuHandle<V: 'static, M: ManagedView> {
} }
impl<V: 'static, M: ManagedView> MenuHandle<V, M> { impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
pub fn id(mut self, id: impl Into<ElementId>) -> Self {
self.id = Some(id.into());
self
}
pub fn menu(mut self, f: impl Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static) -> Self { pub fn menu(mut self, f: impl Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static) -> Self {
self.menu_builder = Some(Rc::new(f)); self.menu_builder = Some(Rc::new(f));
self self
@ -116,9 +111,9 @@ impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
} }
} }
pub fn menu_handle<V: 'static, M: ManagedView>() -> MenuHandle<V, M> { pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<V, M> {
MenuHandle { MenuHandle {
id: None, id: id.into(),
child_builder: None, child_builder: None,
menu_builder: None, menu_builder: None,
anchor: None, anchor: None,
@ -136,10 +131,6 @@ pub struct MenuHandleState<V, M> {
impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> { impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
type State = MenuHandleState<V, M>; type State = MenuHandleState<V, M>;
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.id.clone().expect("menu_handle must have an id()"))
}
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V, view_state: &mut V,
@ -251,6 +242,10 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
impl<V: 'static, M: ManagedView> RenderOnce<V> for MenuHandle<V, M> { impl<V: 'static, M: ManagedView> RenderOnce<V> for MenuHandle<V, M> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.id.clone())
}
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
self self
} }
@ -297,8 +292,7 @@ mod stories {
.flex_col() .flex_col()
.justify_between() .justify_between()
.child( .child(
menu_handle() menu_handle("test2")
.id("test2")
.child(|is_open| { .child(|is_open| {
Label::new(if is_open { Label::new(if is_open {
"TOP LEFT" "TOP LEFT"
@ -309,8 +303,7 @@ mod stories {
.menu(move |_, cx| build_menu(cx, "top left")), .menu(move |_, cx| build_menu(cx, "top left")),
) )
.child( .child(
menu_handle() menu_handle("test1")
.id("test1")
.child(|is_open| { .child(|is_open| {
Label::new(if is_open { Label::new(if is_open {
"BOTTOM LEFT" "BOTTOM LEFT"
@ -329,8 +322,7 @@ mod stories {
.flex_col() .flex_col()
.justify_between() .justify_between()
.child( .child(
menu_handle() menu_handle("test3")
.id("test3")
.child(|is_open| { .child(|is_open| {
Label::new(if is_open { Label::new(if is_open {
"TOP RIGHT" "TOP RIGHT"
@ -342,8 +334,7 @@ mod stories {
.menu(move |_, cx| build_menu(cx, "top right")), .menu(move |_, cx| build_menu(cx, "top right")),
) )
.child( .child(
menu_handle() menu_handle("test4")
.id("test4")
.child(|is_open| { .child(|is_open| {
Label::new(if is_open { Label::new(if is_open {
"BOTTOM RIGHT" "BOTTOM RIGHT"

View file

@ -1,4 +1,4 @@
use gpui::RenderOnce; use gpui::{Div, RenderOnce};
use crate::prelude::*; use crate::prelude::*;
@ -7,12 +7,29 @@ enum DividerDirection {
Vertical, Vertical,
} }
// #[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Divider { pub struct Divider {
direction: DividerDirection, direction: DividerDirection,
inset: bool, inset: bool,
} }
impl<V: 'static> Component<V> for Divider {
type Rendered = Div<V>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered {
div()
.map(|this| match self.direction {
DividerDirection::Horizontal => {
this.h_px().w_full().when(self.inset, |this| this.mx_1p5())
}
DividerDirection::Vertical => {
this.w_px().h_full().when(self.inset, |this| this.my_1p5())
}
})
.bg(cx.theme().colors().border_variant)
}
}
impl Divider { impl Divider {
pub fn horizontal() -> Self { pub fn horizontal() -> Self {
Self { Self {

View file

@ -1,8 +1,8 @@
use crate::{status_bar::StatusItemView, Axis, Workspace}; use crate::{status_bar::StatusItemView, Axis, Workspace};
use gpui::{ use gpui::{
div, px, Action, AnchorCorner, AnyView, AppContext, Component, Div, Entity, EntityId, div, px, Action, AnchorCorner, AnyView, AppContext, Div, Entity, EntityId, EventEmitter,
EventEmitter, FocusHandle, FocusableView, ParentElement, Render, RenderOnce, SharedString, FocusHandle, FocusableView, ParentElement, Render, RenderOnce, SharedString, Styled,
Styled, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext, Subscription, View, ViewContext, VisualContext, WeakView, WindowContext,
}; };
use schemars::JsonSchema; use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
@ -653,8 +653,7 @@ impl Render<Self> for PanelButtons {
}; };
Some( Some(
menu_handle() menu_handle(name)
.id(name)
.menu(move |_, cx| { .menu(move |_, cx| {
cx.build_view(|cx| ContextMenu::new(cx).header("SECTION")) cx.build_view(|cx| ContextMenu::new(cx).header("SECTION"))
}) })

View file

@ -7,9 +7,9 @@ use crate::{
use anyhow::Result; use anyhow::Result;
use collections::{HashMap, HashSet, VecDeque}; use collections::{HashMap, HashSet, VecDeque};
use gpui::{ use gpui::{
actions, prelude::*, Action, AppContext, AsyncWindowContext, Component, Div, EntityId, actions, prelude::*, Action, AppContext, AsyncWindowContext, Div, EntityId, EventEmitter,
EventEmitter, FocusHandle, Focusable, FocusableView, Model, Pixels, Point, PromptLevel, Render, FocusHandle, Focusable, FocusableView, Model, Pixels, Point, PromptLevel, Render, Task, View,
Task, View, ViewContext, VisualContext, WeakView, WindowContext, ViewContext, VisualContext, WeakView, WindowContext,
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use project2::{Project, ProjectEntryId, ProjectPath}; use project2::{Project, ProjectEntryId, ProjectPath};

View file

@ -7,8 +7,7 @@ use db2::sqlez::{
statement::Statement, statement::Statement,
}; };
use gpui::{ use gpui::{
point, size, AnyElement, AnyWeakView, Bounds, Div, Model, Pixels, Point, RenderOnce, View, point, size, AnyWeakView, Bounds, Div, Model, Pixels, Point, RenderOnce, View, ViewContext,
ViewContext,
}; };
use parking_lot::Mutex; use parking_lot::Mutex;
use project2::Project; use project2::Project;

View file

@ -2,8 +2,8 @@ use std::any::TypeId;
use crate::{ItemHandle, Pane}; use crate::{ItemHandle, Pane};
use gpui::{ use gpui::{
div, AnyView, Component, Div, ParentElement, Render, RenderOnce, Styled, Subscription, View, div, AnyView, Div, ParentElement, Render, RenderOnce, Styled, Subscription, View, ViewContext,
ViewContext, WindowContext, WindowContext,
}; };
use theme2::ActiveTheme; use theme2::ActiveTheme;
use ui::h_stack; use ui::h_stack;