co-authored-by: conrad <conrad@zed.dev>
co-authored-by: Nathan <nathan@zed.dev>
This commit is contained in:
Mikayla 2023-11-20 14:46:01 -08:00
parent 6985b70859
commit 2c4d83c9af
No known key found for this signature in database
96 changed files with 1926 additions and 1955 deletions

63
Cargo.lock generated
View file

@ -841,17 +841,6 @@ dependencies = [
"rustc-demangle", "rustc-demangle",
] ]
[[package]]
name = "backtrace-on-stack-overflow"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7fd2d70527f3737a1ad17355e260706c1badebabd1fa06a7a053407380df841b"
dependencies = [
"backtrace",
"libc",
"nix 0.23.2",
]
[[package]] [[package]]
name = "base64" name = "base64"
version = "0.13.1" version = "0.13.1"
@ -5570,19 +5559,6 @@ dependencies = [
"winapi 0.3.9", "winapi 0.3.9",
] ]
[[package]]
name = "nix"
version = "0.23.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8f3790c00a0150112de0f4cd161e3d7fc4b2d8a5542ffc35f099a2562aecb35c"
dependencies = [
"bitflags 1.3.2",
"cc",
"cfg-if 1.0.0",
"libc",
"memoffset 0.6.5",
]
[[package]] [[package]]
name = "nix" name = "nix"
version = "0.24.3" version = "0.24.3"
@ -8855,45 +8831,6 @@ version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "storybook2"
version = "0.1.0"
dependencies = [
"anyhow",
"backtrace-on-stack-overflow",
"chrono",
"clap 4.4.4",
"editor2",
"fuzzy2",
"gpui2",
"itertools 0.11.0",
"language2",
"log",
"menu2",
"picker2",
"rust-embed",
"serde",
"settings2",
"simplelog",
"smallvec",
"strum",
"theme",
"theme2",
"ui2",
"util",
]
[[package]]
name = "storybook3"
version = "0.1.0"
dependencies = [
"anyhow",
"gpui2",
"settings2",
"theme2",
"ui2",
]
[[package]] [[package]]
name = "stringprep" name = "stringprep"
version = "0.1.4" version = "0.1.4"

View file

@ -96,8 +96,8 @@ members = [
"crates/sqlez", "crates/sqlez",
"crates/sqlez_macros", "crates/sqlez_macros",
"crates/rich_text", "crates/rich_text",
"crates/storybook2", # "crates/storybook2",
"crates/storybook3", # "crates/storybook3",
"crates/sum_tree", "crates/sum_tree",
"crates/terminal", "crates/terminal",
"crates/terminal2", "crates/terminal2",

View file

@ -8,8 +8,8 @@ pub struct UpdateNotification {
impl EventEmitter<NotificationEvent> for UpdateNotification {} impl EventEmitter<NotificationEvent> for UpdateNotification {}
impl Render<Self> for UpdateNotification { impl Render for UpdateNotification {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element {
div().child("Updated zed!") div().child("Updated zed!")

View file

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

View file

@ -81,8 +81,8 @@ pub struct CollabTitlebarItem {
_subscriptions: Vec<Subscription>, _subscriptions: Vec<Subscription>,
} }
impl Render<Self> for CollabTitlebarItem { impl Render for CollabTitlebarItem {
type Element = Stateful<Self, Div<Self>>; type Element = Stateful<Div>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
h_stack() h_stack()
@ -100,7 +100,7 @@ impl Render<Self> for CollabTitlebarItem {
|s| s.pl(px(68.)), |s| s.pl(px(68.)),
) )
.bg(cx.theme().colors().title_bar_background) .bg(cx.theme().colors().title_bar_background)
.on_click(|_, event, cx| { .on_click(|event, cx| {
if event.up.click_count == 2 { if event.up.click_count == 2 {
cx.zoom_window(); cx.zoom_window();
} }
@ -117,14 +117,14 @@ impl Render<Self> for CollabTitlebarItem {
.variant(ButtonVariant::Ghost) .variant(ButtonVariant::Ghost)
.color(Some(TextColor::Player(0))), .color(Some(TextColor::Player(0))),
) )
.tooltip(move |_, cx| Tooltip::text("Toggle following", cx)), .tooltip(move |cx| Tooltip::text("Toggle following", cx)),
) )
// TODO - Add project menu // TODO - Add project menu
.child( .child(
div() div()
.id("titlebar_project_menu_button") .id("titlebar_project_menu_button")
.child(Button::new("project_name").variant(ButtonVariant::Ghost)) .child(Button::new("project_name").variant(ButtonVariant::Ghost))
.tooltip(move |_, cx| Tooltip::text("Recent Projects", cx)), .tooltip(move |cx| Tooltip::text("Recent Projects", cx)),
) )
// TODO - Add git menu // TODO - Add git menu
.child( .child(
@ -135,7 +135,7 @@ impl Render<Self> for CollabTitlebarItem {
.variant(ButtonVariant::Ghost) .variant(ButtonVariant::Ghost)
.color(Some(TextColor::Muted)), .color(Some(TextColor::Muted)),
) )
.tooltip(move |_, cx| { .tooltip(move |cx| {
cx.build_view(|_| { cx.build_view(|_| {
Tooltip::new("Recent Branches") Tooltip::new("Recent Branches")
.key_binding(KeyBinding::new(gpui::KeyBinding::new( .key_binding(KeyBinding::new(gpui::KeyBinding::new(

View file

@ -76,8 +76,8 @@ impl FocusableView for CommandPalette {
} }
} }
impl Render<Self> for CommandPalette { impl Render for CommandPalette {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
v_stack().w_96().child(self.picker.clone()) v_stack().w_96().child(self.picker.clone())
@ -140,7 +140,7 @@ impl CommandPaletteDelegate {
} }
impl PickerDelegate for CommandPaletteDelegate { impl PickerDelegate for CommandPaletteDelegate {
type ListItem = Div<Picker<Self>>; type ListItem = Div;
fn placeholder_text(&self) -> Arc<str> { fn placeholder_text(&self) -> Arc<str> {
"Execute a command...".into() "Execute a command...".into()

View file

@ -16,7 +16,7 @@ use gpui::{
actions, div, AnyElement, AnyView, AppContext, Context, Div, EventEmitter, FocusEvent, actions, div, AnyElement, AnyView, AppContext, Context, Div, EventEmitter, FocusEvent,
FocusHandle, Focusable, FocusableElement, FocusableView, InteractiveElement, Model, FocusHandle, Focusable, FocusableElement, FocusableView, InteractiveElement, Model,
ParentElement, Render, RenderOnce, SharedString, Styled, Subscription, Task, View, ViewContext, ParentElement, Render, RenderOnce, SharedString, Styled, Subscription, Task, View, ViewContext,
VisualContext, WeakView, VisualContext, WeakView, WindowContext,
}; };
use language::{ use language::{
Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection, Anchor, Bias, Buffer, Diagnostic, DiagnosticEntry, DiagnosticSeverity, Point, Selection,
@ -90,8 +90,8 @@ struct DiagnosticGroupState {
impl EventEmitter<ItemEvent> for ProjectDiagnosticsEditor {} impl EventEmitter<ItemEvent> for ProjectDiagnosticsEditor {}
impl Render<Self> for ProjectDiagnosticsEditor { impl Render for ProjectDiagnosticsEditor {
type Element = Focusable<Self, Div<Self>>; type Element = Focusable<Div>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let child = if self.path_states.is_empty() { let child = if self.path_states.is_empty() {
@ -109,8 +109,8 @@ impl Render<Self> for ProjectDiagnosticsEditor {
div() div()
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)
.size_full() .size_full()
.on_focus_in(Self::focus_in) .on_focus_in(cx.listener(Self::focus_in))
.on_action(Self::toggle_warnings) .on_action(cx.listener(Self::toggle_warnings))
.child(child) .child(child)
} }
} }
@ -662,7 +662,7 @@ impl Item for ProjectDiagnosticsEditor {
Some("Project Diagnostics".into()) Some("Project Diagnostics".into())
} }
fn tab_content<T: 'static>(&self, _detail: Option<usize>, _: &AppContext) -> AnyElement<T> { fn tab_content(&self, _detail: Option<usize>, _: &WindowContext) -> AnyElement {
render_summary(&self.summary) render_summary(&self.summary)
} }
@ -796,11 +796,10 @@ fn diagnostic_header_renderer(diagnostic: Diagnostic) -> RenderBlock {
}) })
} }
pub(crate) fn render_summary<T: 'static>(summary: &DiagnosticSummary) -> AnyElement<T> { pub(crate) fn render_summary(summary: &DiagnosticSummary) -> AnyElement {
if summary.error_count == 0 && summary.warning_count == 0 { if summary.error_count == 0 && summary.warning_count == 0 {
let label = Label::new("No problems"); let label = Label::new("No problems");
label.render_into_any() label.render_into_any()
//.render()
} else { } else {
h_stack() h_stack()
.bg(gpui::red()) .bg(gpui::red())

View file

@ -21,8 +21,8 @@ pub struct DiagnosticIndicator {
_observe_active_editor: Option<Subscription>, _observe_active_editor: Option<Subscription>,
} }
impl Render<Self> for DiagnosticIndicator { impl Render for DiagnosticIndicator {
type Element = Stateful<Self, Div<Self>>; type Element = Stateful<Div>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let diagnostic_indicator = match (self.summary.error_count, self.summary.warning_count) { let diagnostic_indicator = match (self.summary.error_count, self.summary.warning_count) {
@ -45,7 +45,7 @@ impl Render<Self> for DiagnosticIndicator {
h_stack() h_stack()
.id(cx.entity_id()) .id(cx.entity_id())
.on_action(Self::go_to_next_diagnostic) .on_action(cx.listener(Self::go_to_next_diagnostic))
.rounded_md() .rounded_md()
.flex_none() .flex_none()
.h(rems(1.375)) .h(rems(1.375))
@ -54,14 +54,14 @@ impl Render<Self> for DiagnosticIndicator {
.bg(cx.theme().colors().ghost_element_background) .bg(cx.theme().colors().ghost_element_background)
.hover(|style| style.bg(cx.theme().colors().ghost_element_hover)) .hover(|style| style.bg(cx.theme().colors().ghost_element_hover))
.active(|style| style.bg(cx.theme().colors().ghost_element_active)) .active(|style| style.bg(cx.theme().colors().ghost_element_active))
.tooltip(|_, cx| Tooltip::text("Project Diagnostics", cx)) .tooltip(|cx| Tooltip::text("Project Diagnostics", cx))
.on_click(|this, _, cx| { .on_click(cx.listener(|this, _, cx| {
if let Some(workspace) = this.workspace.upgrade() { if let Some(workspace) = this.workspace.upgrade() {
workspace.update(cx, |workspace, cx| { workspace.update(cx, |workspace, cx| {
ProjectDiagnosticsEditor::deploy(workspace, &Default::default(), cx) ProjectDiagnosticsEditor::deploy(workspace, &Default::default(), cx)
}) })
} }
}) }))
.child(diagnostic_indicator) .child(diagnostic_indicator)
} }
} }

View file

@ -7,8 +7,8 @@ pub struct ToolbarControls {
editor: Option<WeakView<ProjectDiagnosticsEditor>>, editor: Option<WeakView<ProjectDiagnosticsEditor>>,
} }
impl Render<Self> for ToolbarControls { impl Render for ToolbarControls {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let include_warnings = self let include_warnings = self
@ -26,14 +26,14 @@ impl Render<Self> for ToolbarControls {
div().child( div().child(
IconButton::new("toggle-warnings", Icon::ExclamationTriangle) IconButton::new("toggle-warnings", Icon::ExclamationTriangle)
.tooltip(move |_, cx| Tooltip::text(tooltip, cx)) .tooltip(move |cx| Tooltip::text(tooltip, cx))
.on_click(|this: &mut Self, cx| { .on_click(cx.listener(|this, _, cx| {
if let Some(editor) = this.editor.as_ref().and_then(|editor| editor.upgrade()) { if let Some(editor) = this.editor.as_ref().and_then(|editor| editor.upgrade()) {
editor.update(cx, |editor, cx| { editor.update(cx, |editor, cx| {
editor.toggle_warnings(&Default::default(), cx); editor.toggle_warnings(&Default::default(), cx);
}); });
} }
}), })),
) )
} }
} }

View file

@ -50,7 +50,7 @@ struct BlockRow(u32);
#[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)] #[derive(Copy, Clone, Debug, Default, Eq, Ord, PartialOrd, PartialEq)]
struct WrapRow(u32); struct WrapRow(u32);
pub type RenderBlock = Arc<dyn Fn(&mut BlockContext) -> AnyElement<Editor>>; pub type RenderBlock = Arc<dyn Fn(&mut BlockContext) -> AnyElement>;
pub struct Block { pub struct Block {
id: BlockId, id: BlockId,
@ -69,7 +69,7 @@ where
pub position: P, pub position: P,
pub height: u8, pub height: u8,
pub style: BlockStyle, pub style: BlockStyle,
pub render: Arc<dyn Fn(&mut BlockContext) -> AnyElement<Editor>>, pub render: Arc<dyn Fn(&mut BlockContext) -> AnyElement>,
pub disposition: BlockDisposition, pub disposition: BlockDisposition,
} }
@ -947,7 +947,7 @@ impl DerefMut for BlockContext<'_, '_> {
} }
impl Block { impl Block {
pub fn render(&self, cx: &mut BlockContext) -> AnyElement<Editor> { pub fn render(&self, cx: &mut BlockContext) -> AnyElement {
self.render.lock()(cx) self.render.lock()(cx)
} }

View file

@ -907,7 +907,7 @@ impl ContextMenu {
style: &EditorStyle, style: &EditorStyle,
workspace: Option<WeakView<Workspace>>, workspace: Option<WeakView<Workspace>>,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> (DisplayPoint, AnyElement<Editor>) { ) -> (DisplayPoint, AnyElement) {
match self { match self {
ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)), ContextMenu::Completions(menu) => (cursor_position, menu.render(style, workspace, cx)),
ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx), ContextMenu::CodeActions(menu) => menu.render(cursor_position, style, cx),
@ -1223,7 +1223,7 @@ impl CompletionsMenu {
style: &EditorStyle, style: &EditorStyle,
workspace: Option<WeakView<Workspace>>, workspace: Option<WeakView<Workspace>>,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> AnyElement<Editor> { ) -> AnyElement {
todo!("old implementation below") todo!("old implementation below")
} }
@ -1541,13 +1541,15 @@ impl CodeActionsMenu {
mut cursor_position: DisplayPoint, mut cursor_position: DisplayPoint,
style: &EditorStyle, style: &EditorStyle,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> (DisplayPoint, AnyElement<Editor>) { ) -> (DisplayPoint, AnyElement) {
let actions = self.actions.clone(); let actions = self.actions.clone();
let selected_item = self.selected_item; let selected_item = self.selected_item;
let element = uniform_list( let element = uniform_list(
cx.view().clone(),
"code_actions_menu", "code_actions_menu",
self.actions.len(), self.actions.len(),
move |editor, range, cx| { move |this, range, cx| {
actions[range.clone()] actions[range.clone()]
.iter() .iter()
.enumerate() .enumerate()
@ -1569,7 +1571,9 @@ impl CodeActionsMenu {
.bg(colors.element_hover) .bg(colors.element_hover)
.text_color(colors.text_accent) .text_color(colors.text_accent)
}) })
.on_mouse_down(MouseButton::Left, move |editor: &mut Editor, _, cx| { .on_mouse_down(
MouseButton::Left,
cx.listener(move |editor, _, cx| {
cx.stop_propagation(); cx.stop_propagation();
editor editor
.confirm_code_action( .confirm_code_action(
@ -1579,7 +1583,8 @@ impl CodeActionsMenu {
cx, cx,
) )
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}) }),
)
// TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here. // TASK: It would be good to make lsp_action.title a SharedString to avoid allocating here.
.child(SharedString::from(action.lsp_action.title.clone())) .child(SharedString::from(action.lsp_action.title.clone()))
}) })
@ -4354,11 +4359,11 @@ impl Editor {
style: &EditorStyle, style: &EditorStyle,
is_active: bool, is_active: bool,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Option<IconButton<Self>> { ) -> Option<IconButton> {
if self.available_code_actions.is_some() { if self.available_code_actions.is_some() {
Some( Some(
IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click( IconButton::new("code_actions_indicator", ui::Icon::Bolt).on_click(cx.listener(
|editor: &mut Editor, cx| { |editor, e, cx| {
editor.toggle_code_actions( editor.toggle_code_actions(
&ToggleCodeActions { &ToggleCodeActions {
deployed_from_indicator: true, deployed_from_indicator: true,
@ -4366,7 +4371,7 @@ impl Editor {
cx, cx,
); );
}, },
), )),
) )
} else { } else {
None None
@ -4381,7 +4386,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<IconButton<Self>>> { ) -> Vec<Option<IconButton>> {
fold_data fold_data
.iter() .iter()
.enumerate() .enumerate()
@ -4394,14 +4399,14 @@ impl Editor {
FoldStatus::Foldable => ui::Icon::ChevronDown, FoldStatus::Foldable => ui::Icon::ChevronDown,
}; };
IconButton::new(ix as usize, icon) IconButton::new(ix as usize, icon)
.on_click(move |editor: &mut Editor, cx| match fold_status { .on_click(cx.listener(move |editor, e, 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);
} }
}) }))
.color(ui::TextColor::Muted) .color(ui::TextColor::Muted)
}) })
}) })
@ -4422,7 +4427,7 @@ impl Editor {
cursor_position: DisplayPoint, cursor_position: DisplayPoint,
style: &EditorStyle, style: &EditorStyle,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> Option<(DisplayPoint, AnyElement<Editor>)> { ) -> Option<(DisplayPoint, AnyElement)> {
self.context_menu.read().as_ref().map(|menu| { self.context_menu.read().as_ref().map(|menu| {
menu.render( menu.render(
cursor_position, cursor_position,
@ -7781,7 +7786,7 @@ impl Editor {
} }
div() div()
.pl(cx.anchor_x) .pl(cx.anchor_x)
.child(rename_editor.render_with(EditorElement::new( .child(EditorElement::new(
&rename_editor, &rename_editor,
EditorStyle { EditorStyle {
background: cx.theme().system().transparent, background: cx.theme().system().transparent,
@ -7789,10 +7794,12 @@ impl Editor {
text: text_style, text: text_style,
scrollbar_width: cx.editor_style.scrollbar_width, scrollbar_width: cx.editor_style.scrollbar_width,
syntax: cx.editor_style.syntax.clone(), syntax: cx.editor_style.syntax.clone(),
diagnostic_style: diagnostic_style: cx
cx.editor_style.diagnostic_style.clone(), .editor_style
.diagnostic_style
.clone(),
}, },
))) ))
.render_into_any() .render_into_any()
} }
}), }),
@ -9382,7 +9389,7 @@ impl FocusableView for Editor {
} }
} }
impl Render<Self> for Editor { impl Render for Editor {
type Element = EditorElement; type Element = EditorElement;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
@ -9996,10 +10003,10 @@ pub fn diagnostic_block_renderer(diagnostic: Diagnostic, is_valid: bool) -> Rend
.ml(cx.anchor_x) .ml(cx.anchor_x)
})) }))
.cursor_pointer() .cursor_pointer()
.on_click(move |_, _, cx| { .on_click(cx.listener(move |_, _, cx| {
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_into_any() .render_into_any()
}) })
} }

View file

@ -23,7 +23,7 @@ use gpui::{
ElementId, ElementInputHandler, Entity, EntityId, Hsla, InteractiveElement, LineLayout, ElementId, ElementInputHandler, Entity, EntityId, Hsla, InteractiveElement, LineLayout,
MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, RenderOnce, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, RenderOnce,
ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled, ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled,
TextRun, TextStyle, View, ViewContext, WindowContext, WrappedLine, TextRun, TextStyle, View, ViewContext, WeakView, WindowContext, WrappedLine,
}; };
use itertools::Itertools; use itertools::Itertools;
use language::language_settings::ShowWhitespaceSetting; use language::language_settings::ShowWhitespaceSetting;
@ -112,14 +112,14 @@ impl SelectionLayout {
} }
pub struct EditorElement { pub struct EditorElement {
editor_id: EntityId, editor: View<Editor>,
style: EditorStyle, style: EditorStyle,
} }
impl EditorElement { impl EditorElement {
pub fn new(editor: &View<Editor>, style: EditorStyle) -> Self { pub fn new(editor: &View<Editor>, style: EditorStyle) -> Self {
Self { Self {
editor_id: editor.entity_id(), editor: editor.clone(),
style, style,
} }
} }
@ -349,7 +349,7 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>, gutter_bounds: Bounds<Pixels>,
text_bounds: Bounds<Pixels>, text_bounds: Bounds<Pixels>,
layout: &LayoutState, layout: &LayoutState,
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let bounds = gutter_bounds.union(&text_bounds); let bounds = gutter_bounds.union(&text_bounds);
let scroll_top = let scroll_top =
@ -460,7 +460,7 @@ impl EditorElement {
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
editor: &mut Editor, editor: &mut Editor,
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let line_height = layout.position_map.line_height; let line_height = layout.position_map.line_height;
@ -495,7 +495,7 @@ impl EditorElement {
AvailableSpace::MinContent, AvailableSpace::MinContent,
AvailableSpace::Definite(line_height * 0.55), AvailableSpace::Definite(line_height * 0.55),
); );
let fold_indicator_size = fold_indicator.measure(available_space, editor, cx); let fold_indicator_size = fold_indicator.measure(available_space, cx);
let position = point( let position = point(
bounds.size.width - layout.gutter_padding, bounds.size.width - layout.gutter_padding,
@ -506,7 +506,7 @@ impl EditorElement {
(line_height - fold_indicator_size.height) / 2., (line_height - fold_indicator_size.height) / 2.,
); );
let origin = bounds.origin + position + centering_offset; let origin = bounds.origin + position + centering_offset;
fold_indicator.draw(origin, available_space, editor, cx); fold_indicator.draw(origin, available_space, cx);
} }
} }
@ -516,7 +516,7 @@ impl EditorElement {
AvailableSpace::MinContent, AvailableSpace::MinContent,
AvailableSpace::Definite(line_height), AvailableSpace::Definite(line_height),
); );
let indicator_size = button.measure(available_space, editor, cx); let indicator_size = button.measure(available_space, 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;
@ -524,15 +524,11 @@ impl EditorElement {
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.;
button.draw(bounds.origin + point(x, y), available_space, editor, cx); button.draw(bounds.origin + point(x, y), available_space, cx);
} }
} }
fn paint_diff_hunks( fn paint_diff_hunks(bounds: Bounds<Pixels>, layout: &LayoutState, cx: &mut WindowContext) {
bounds: Bounds<Pixels>,
layout: &LayoutState,
cx: &mut ViewContext<Editor>,
) {
// todo!() // todo!()
// let diff_style = &theme::current(cx).editor.diff.clone(); // let diff_style = &theme::current(cx).editor.diff.clone();
// let line_height = layout.position_map.line_height; // let line_height = layout.position_map.line_height;
@ -621,7 +617,7 @@ impl EditorElement {
text_bounds: Bounds<Pixels>, text_bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
editor: &mut Editor, editor: &mut Editor,
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let scroll_position = layout.position_map.snapshot.scroll_position(); let scroll_position = layout.position_map.snapshot.scroll_position();
let start_row = layout.visible_display_row_range.start; let start_row = layout.visible_display_row_range.start;
@ -676,8 +672,10 @@ impl EditorElement {
div() div()
.id(fold.id) .id(fold.id)
.size_full() .size_full()
.on_mouse_down(MouseButton::Left, |_, _, cx| cx.stop_propagation()) .on_mouse_down(MouseButton::Left, |_, cx| cx.stop_propagation())
.on_click(move |editor: &mut Editor, _, cx| { .on_click(cx.listener_for(
&self.editor,
move |editor: &mut Editor, _, cx| {
editor.unfold_ranges( editor.unfold_ranges(
[fold_range.start..fold_range.end], [fold_range.start..fold_range.end],
true, true,
@ -685,11 +683,11 @@ impl EditorElement {
cx, cx,
); );
cx.stop_propagation(); cx.stop_propagation();
}) },
))
.draw( .draw(
fold_bounds.origin, fold_bounds.origin,
fold_bounds.size, fold_bounds.size,
editor,
cx, cx,
|fold_element_state, cx| { |fold_element_state, cx| {
if fold_element_state.is_active() { if fold_element_state.is_active() {
@ -852,7 +850,7 @@ impl EditorElement {
.min((text_bounds.size.height - line_height) / 2.), .min((text_bounds.size.height - line_height) / 2.),
), ),
); );
let context_menu_size = context_menu.measure(available_space, editor, cx); let context_menu_size = context_menu.measure(available_space, cx);
let cursor_row_layout = &layout.position_map.line_layouts let cursor_row_layout = &layout.position_map.line_layouts
[(position.row() - start_row) as usize] [(position.row() - start_row) as usize]
@ -876,7 +874,7 @@ impl EditorElement {
list_origin.y -= layout.position_map.line_height - list_height; list_origin.y -= layout.position_map.line_height - list_height;
} }
context_menu.draw(list_origin, available_space, editor, cx); context_menu.draw(list_origin, available_space, cx);
}) })
} }
@ -1167,7 +1165,7 @@ impl EditorElement {
layout: &LayoutState, layout: &LayoutState,
content_origin: gpui::Point<Pixels>, content_origin: gpui::Point<Pixels>,
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let start_row = layout.visible_display_row_range.start; let start_row = layout.visible_display_row_range.start;
let end_row = layout.visible_display_row_range.end; let end_row = layout.visible_display_row_range.end;
@ -1220,7 +1218,7 @@ impl EditorElement {
bounds: Bounds<Pixels>, bounds: Bounds<Pixels>,
layout: &mut LayoutState, layout: &mut LayoutState,
editor: &mut Editor, editor: &mut Editor,
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let scroll_position = layout.position_map.snapshot.scroll_position(); let scroll_position = layout.position_map.snapshot.scroll_position();
let scroll_left = scroll_position.x * layout.position_map.em_width; let scroll_left = scroll_position.x * layout.position_map.em_width;
@ -1235,9 +1233,7 @@ impl EditorElement {
if !matches!(block.style, BlockStyle::Sticky) { if !matches!(block.style, BlockStyle::Sticky) {
origin += point(-scroll_left, Pixels::ZERO); origin += point(-scroll_left, Pixels::ZERO);
} }
block block.element.draw(origin, block.available_space, cx);
.element
.draw(origin, block.available_space, editor, cx);
} }
} }
@ -2030,12 +2026,10 @@ impl EditorElement {
let jump_position = language::ToPoint::to_point(&jump_anchor, buffer); let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
IconButton::new(block_id, ui::Icon::ArrowUpRight) IconButton::new(block_id, ui::Icon::ArrowUpRight)
.on_click(move |editor: &mut Editor, cx| { .on_click(cx.listener_for(&self.editor, move |editor, e, cx| {
editor.jump(jump_path.clone(), jump_position, jump_anchor, cx); editor.jump(jump_path.clone(), jump_position, jump_anchor, cx);
}) }))
.tooltip(move |_, cx| { .tooltip(|cx| Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx))
Tooltip::for_action("Jump to Buffer", &OpenExcerpts, cx)
})
}); });
let element = if *starts_new_buffer { let element = if *starts_new_buffer {
@ -2074,7 +2068,7 @@ impl EditorElement {
} }
}; };
let size = element.measure(available_space, editor, cx); let size = element.measure(available_space, cx);
(element, size) (element, size)
}; };
@ -2133,47 +2127,61 @@ impl EditorElement {
gutter_bounds: Bounds<Pixels>, gutter_bounds: Bounds<Pixels>,
text_bounds: Bounds<Pixels>, text_bounds: Bounds<Pixels>,
layout: &LayoutState, layout: &LayoutState,
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO); let content_origin = text_bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
cx.on_mouse_event({ cx.on_mouse_event({
let position_map = layout.position_map.clone(); let position_map = layout.position_map.clone();
move |editor, event: &ScrollWheelEvent, phase, cx| { let editor = self.editor.clone();
move |event: &ScrollWheelEvent, phase, cx| {
if phase != DispatchPhase::Bubble { if phase != DispatchPhase::Bubble {
return; return;
} }
if Self::scroll(editor, event, &position_map, bounds, cx) { let should_cancel = editor.update(cx, |editor, cx| {
Self::scroll(editor, event, &position_map, bounds, cx)
});
if should_cancel {
cx.stop_propagation(); cx.stop_propagation();
} }
} }
}); });
cx.on_mouse_event({ cx.on_mouse_event({
let position_map = layout.position_map.clone(); let position_map = layout.position_map.clone();
move |editor, event: &MouseDownEvent, phase, cx| { let editor = self.editor.clone();
move |event: &MouseDownEvent, phase, cx| {
if phase != DispatchPhase::Bubble { if phase != DispatchPhase::Bubble {
return; return;
} }
if Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx) { let should_cancel = editor.update(cx, |editor, cx| {
Self::mouse_down(editor, event, &position_map, text_bounds, gutter_bounds, cx)
});
if should_cancel {
cx.stop_propagation() cx.stop_propagation()
} }
} }
}); });
cx.on_mouse_event({ cx.on_mouse_event({
let position_map = layout.position_map.clone(); let position_map = layout.position_map.clone();
move |editor, event: &MouseUpEvent, phase, cx| { let editor = self.editor.clone();
if phase != DispatchPhase::Bubble { move |event: &MouseUpEvent, phase, cx| {
return; let should_cancel = editor.update(cx, |editor, cx| {
} Self::mouse_up(editor, event, &position_map, text_bounds, cx)
});
if Self::mouse_up(editor, event, &position_map, text_bounds, cx) { if should_cancel {
cx.stop_propagation() cx.stop_propagation()
} }
} }
}); });
// todo!() //todo!()
// on_down(MouseButton::Right, { // on_down(MouseButton::Right, {
// let position_map = layout.position_map.clone(); // let position_map = layout.position_map.clone();
// move |event, editor, cx| { // move |event, editor, cx| {
@ -2190,12 +2198,17 @@ impl EditorElement {
// }); // });
cx.on_mouse_event({ cx.on_mouse_event({
let position_map = layout.position_map.clone(); let position_map = layout.position_map.clone();
move |editor, event: &MouseMoveEvent, phase, cx| { let editor = self.editor.clone();
move |event: &MouseMoveEvent, phase, cx| {
if phase != DispatchPhase::Bubble { if phase != DispatchPhase::Bubble {
return; return;
} }
if Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx) { let stop_propogating = editor.update(cx, |editor, cx| {
Self::mouse_moved(editor, event, &position_map, text_bounds, gutter_bounds, cx)
});
if stop_propogating {
cx.stop_propagation() cx.stop_propagation()
} }
} }
@ -2324,7 +2337,7 @@ impl LineWithInvisibles {
content_origin: gpui::Point<Pixels>, content_origin: gpui::Point<Pixels>,
whitespace_setting: ShowWhitespaceSetting, whitespace_setting: ShowWhitespaceSetting,
selection_ranges: &[Range<DisplayPoint>], selection_ranges: &[Range<DisplayPoint>],
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let line_height = layout.position_map.line_height; let line_height = layout.position_map.line_height;
let line_y = line_height * row as f32 - layout.position_map.scroll_position.y; let line_y = line_height * row as f32 - layout.position_map.scroll_position.y;
@ -2356,7 +2369,7 @@ impl LineWithInvisibles {
row: u32, row: u32,
line_height: Pixels, line_height: Pixels,
whitespace_setting: ShowWhitespaceSetting, whitespace_setting: ShowWhitespaceSetting,
cx: &mut ViewContext<Editor>, cx: &mut WindowContext,
) { ) {
let allowed_invisibles_regions = match whitespace_setting { let allowed_invisibles_regions = match whitespace_setting {
ShowWhitespaceSetting::None => return, ShowWhitespaceSetting::None => return,
@ -2399,36 +2412,41 @@ enum Invisible {
Whitespace { line_offset: usize }, Whitespace { line_offset: usize },
} }
impl Element<Editor> for EditorElement { impl Element for EditorElement {
type State = (); type State = ();
fn layout( fn layout(
&mut self, &mut self,
editor: &mut Editor,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut gpui::ViewContext<Editor>, cx: &mut gpui::WindowContext,
) -> (gpui::LayoutId, Self::State) { ) -> (gpui::LayoutId, Self::State) {
self.editor.update(cx, |editor, cx| {
editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this. editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this.
let rem_size = cx.rem_size(); let rem_size = cx.rem_size();
let mut style = Style::default(); let mut style = Style::default();
style.size.width = relative(1.).into(); style.size.width = relative(1.).into();
style.size.height = match editor.mode { style.size.height = match editor.mode {
EditorMode::SingleLine => self.style.text.line_height_in_pixels(cx.rem_size()).into(), EditorMode::SingleLine => {
self.style.text.line_height_in_pixels(cx.rem_size()).into()
}
EditorMode::AutoHeight { .. } => todo!(), EditorMode::AutoHeight { .. } => todo!(),
EditorMode::Full => relative(1.).into(), EditorMode::Full => relative(1.).into(),
}; };
let layout_id = cx.request_layout(&style, None); let layout_id = cx.request_layout(&style, None);
(layout_id, ()) (layout_id, ())
})
} }
fn paint( fn paint(
mut self, mut self,
bounds: Bounds<gpui::Pixels>, bounds: Bounds<gpui::Pixels>,
editor: &mut Editor,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut gpui::ViewContext<Editor>, cx: &mut gpui::WindowContext,
) { ) {
let editor = self.editor.clone();
editor.update(cx, |editor, cx| {
let mut layout = self.compute_layout(editor, cx, bounds); let mut layout = self.compute_layout(editor, cx, bounds);
let gutter_bounds = Bounds { let gutter_bounds = Bounds {
origin: bounds.origin, origin: bounds.origin,
@ -2440,19 +2458,26 @@ impl Element<Editor> for EditorElement {
}; };
let dispatch_context = editor.dispatch_context(cx); let dispatch_context = editor.dispatch_context(cx);
let editor_handle = cx.view().clone();
cx.with_key_dispatch( cx.with_key_dispatch(
dispatch_context, dispatch_context,
Some(editor.focus_handle.clone()), Some(editor.focus_handle.clone()),
|_, cx| { |_, cx| {
register_actions(cx); register_actions(&editor_handle, cx);
// We call with_z_index to establish a new stacking context. // We call with_z_index to establish a new stacking context.
cx.with_z_index(0, |cx| { cx.with_z_index(0, |cx| {
cx.with_content_mask(Some(ContentMask { bounds }), |cx| { cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
// Paint mouse listeners first, so any elements we paint on top of the editor // Paint mouse listeners first, so any elements we paint on top of the editor
// take precedence. // take precedence.
self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx); self.paint_mouse_listeners(
let input_handler = ElementInputHandler::new(bounds, cx); bounds,
gutter_bounds,
text_bounds,
&layout,
cx,
);
let input_handler = ElementInputHandler::new(bounds, editor_handle, cx);
cx.handle_input(&editor.focus_handle, input_handler); cx.handle_input(&editor.focus_handle, input_handler);
self.paint_background(gutter_bounds, text_bounds, &layout, cx); self.paint_background(gutter_bounds, text_bounds, &layout, cx);
@ -2470,14 +2495,15 @@ impl Element<Editor> for EditorElement {
}); });
}, },
) )
})
} }
} }
impl RenderOnce<Editor> for EditorElement { impl RenderOnce for EditorElement {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<gpui::ElementId> { fn element_id(&self) -> Option<gpui::ElementId> {
Some(self.editor_id.into()) self.editor.element_id()
} }
fn render_once(self) -> Self::Element { fn render_once(self) -> Self::Element {
@ -3106,17 +3132,17 @@ pub struct LayoutState {
show_scrollbars: bool, show_scrollbars: bool,
is_singleton: bool, is_singleton: bool,
max_row: u32, max_row: u32,
context_menu: Option<(DisplayPoint, AnyElement<Editor>)>, context_menu: Option<(DisplayPoint, AnyElement)>,
code_actions_indicator: Option<CodeActionsIndicator>, code_actions_indicator: Option<CodeActionsIndicator>,
// hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>, // hover_popovers: Option<(DisplayPoint, Vec<AnyElement>)>,
fold_indicators: Vec<Option<IconButton<Editor>>>, fold_indicators: Vec<Option<IconButton>>,
tab_invisible: ShapedLine, tab_invisible: ShapedLine,
space_invisible: ShapedLine, space_invisible: ShapedLine,
} }
struct CodeActionsIndicator { struct CodeActionsIndicator {
row: u32, row: u32,
button: IconButton<Editor>, button: IconButton,
} }
struct PositionMap { struct PositionMap {
@ -3201,7 +3227,7 @@ impl PositionMap {
struct BlockLayout { struct BlockLayout {
row: u32, row: u32,
element: AnyElement<Editor>, element: AnyElement,
available_space: Size<AvailableSpace>, available_space: Size<AvailableSpace>,
style: BlockStyle, style: BlockStyle,
} }
@ -3906,187 +3932,191 @@ fn scale_horizontal_mouse_autoscroll_delta(delta: Pixels) -> f32 {
// } // }
// } // }
fn register_actions(cx: &mut ViewContext<Editor>) { fn register_actions(view: &View<Editor>, cx: &mut WindowContext) {
register_action(cx, Editor::move_left); register_action(view, cx, Editor::move_left);
register_action(cx, Editor::move_right); register_action(view, cx, Editor::move_right);
register_action(cx, Editor::move_down); register_action(view, cx, Editor::move_down);
register_action(cx, Editor::move_up); register_action(view, cx, Editor::move_up);
// on_action(cx, Editor::new_file); todo!() // on_action(cx, Editor::new_file); todo!()
// on_action(cx, Editor::new_file_in_direction); todo!() // on_action(cx, Editor::new_file_in_direction); todo!()
register_action(cx, Editor::cancel); register_action(view, cx, Editor::cancel);
register_action(cx, Editor::newline); register_action(view, cx, Editor::newline);
register_action(cx, Editor::newline_above); register_action(view, cx, Editor::newline_above);
register_action(cx, Editor::newline_below); register_action(view, cx, Editor::newline_below);
register_action(cx, Editor::backspace); register_action(view, cx, Editor::backspace);
register_action(cx, Editor::delete); register_action(view, cx, Editor::delete);
register_action(cx, Editor::tab); register_action(view, cx, Editor::tab);
register_action(cx, Editor::tab_prev); register_action(view, cx, Editor::tab_prev);
register_action(cx, Editor::indent); register_action(view, cx, Editor::indent);
register_action(cx, Editor::outdent); register_action(view, cx, Editor::outdent);
register_action(cx, Editor::delete_line); register_action(view, cx, Editor::delete_line);
register_action(cx, Editor::join_lines); register_action(view, cx, Editor::join_lines);
register_action(cx, Editor::sort_lines_case_sensitive); register_action(view, cx, Editor::sort_lines_case_sensitive);
register_action(cx, Editor::sort_lines_case_insensitive); register_action(view, cx, Editor::sort_lines_case_insensitive);
register_action(cx, Editor::reverse_lines); register_action(view, cx, Editor::reverse_lines);
register_action(cx, Editor::shuffle_lines); register_action(view, cx, Editor::shuffle_lines);
register_action(cx, Editor::convert_to_upper_case); register_action(view, cx, Editor::convert_to_upper_case);
register_action(cx, Editor::convert_to_lower_case); register_action(view, cx, Editor::convert_to_lower_case);
register_action(cx, Editor::convert_to_title_case); register_action(view, cx, Editor::convert_to_title_case);
register_action(cx, Editor::convert_to_snake_case); register_action(view, cx, Editor::convert_to_snake_case);
register_action(cx, Editor::convert_to_kebab_case); register_action(view, cx, Editor::convert_to_kebab_case);
register_action(cx, Editor::convert_to_upper_camel_case); register_action(view, cx, Editor::convert_to_upper_camel_case);
register_action(cx, Editor::convert_to_lower_camel_case); register_action(view, cx, Editor::convert_to_lower_camel_case);
register_action(cx, Editor::delete_to_previous_word_start); register_action(view, cx, Editor::delete_to_previous_word_start);
register_action(cx, Editor::delete_to_previous_subword_start); register_action(view, cx, Editor::delete_to_previous_subword_start);
register_action(cx, Editor::delete_to_next_word_end); register_action(view, cx, Editor::delete_to_next_word_end);
register_action(cx, Editor::delete_to_next_subword_end); register_action(view, cx, Editor::delete_to_next_subword_end);
register_action(cx, Editor::delete_to_beginning_of_line); register_action(view, cx, Editor::delete_to_beginning_of_line);
register_action(cx, Editor::delete_to_end_of_line); register_action(view, cx, Editor::delete_to_end_of_line);
register_action(cx, Editor::cut_to_end_of_line); register_action(view, cx, Editor::cut_to_end_of_line);
register_action(cx, Editor::duplicate_line); register_action(view, cx, Editor::duplicate_line);
register_action(cx, Editor::move_line_up); register_action(view, cx, Editor::move_line_up);
register_action(cx, Editor::move_line_down); register_action(view, cx, Editor::move_line_down);
register_action(cx, Editor::transpose); register_action(view, cx, Editor::transpose);
register_action(cx, Editor::cut); register_action(view, cx, Editor::cut);
register_action(cx, Editor::copy); register_action(view, cx, Editor::copy);
register_action(cx, Editor::paste); register_action(view, cx, Editor::paste);
register_action(cx, Editor::undo); register_action(view, cx, Editor::undo);
register_action(cx, Editor::redo); register_action(view, cx, Editor::redo);
register_action(cx, Editor::move_page_up); register_action(view, cx, Editor::move_page_up);
register_action(cx, Editor::move_page_down); register_action(view, cx, Editor::move_page_down);
register_action(cx, Editor::next_screen); register_action(view, cx, Editor::next_screen);
register_action(cx, Editor::scroll_cursor_top); register_action(view, cx, Editor::scroll_cursor_top);
register_action(cx, Editor::scroll_cursor_center); register_action(view, cx, Editor::scroll_cursor_center);
register_action(cx, Editor::scroll_cursor_bottom); register_action(view, cx, Editor::scroll_cursor_bottom);
register_action(cx, |editor, _: &LineDown, cx| { register_action(view, cx, |editor, _: &LineDown, cx| {
editor.scroll_screen(&ScrollAmount::Line(1.), cx) editor.scroll_screen(&ScrollAmount::Line(1.), cx)
}); });
register_action(cx, |editor, _: &LineUp, cx| { register_action(view, cx, |editor, _: &LineUp, cx| {
editor.scroll_screen(&ScrollAmount::Line(-1.), cx) editor.scroll_screen(&ScrollAmount::Line(-1.), cx)
}); });
register_action(cx, |editor, _: &HalfPageDown, cx| { register_action(view, cx, |editor, _: &HalfPageDown, cx| {
editor.scroll_screen(&ScrollAmount::Page(0.5), cx) editor.scroll_screen(&ScrollAmount::Page(0.5), cx)
}); });
register_action(cx, |editor, _: &HalfPageUp, cx| { register_action(view, cx, |editor, _: &HalfPageUp, cx| {
editor.scroll_screen(&ScrollAmount::Page(-0.5), cx) editor.scroll_screen(&ScrollAmount::Page(-0.5), cx)
}); });
register_action(cx, |editor, _: &PageDown, cx| { register_action(view, cx, |editor, _: &PageDown, cx| {
editor.scroll_screen(&ScrollAmount::Page(1.), cx) editor.scroll_screen(&ScrollAmount::Page(1.), cx)
}); });
register_action(cx, |editor, _: &PageUp, cx| { register_action(view, cx, |editor, _: &PageUp, cx| {
editor.scroll_screen(&ScrollAmount::Page(-1.), cx) editor.scroll_screen(&ScrollAmount::Page(-1.), cx)
}); });
register_action(cx, Editor::move_to_previous_word_start); register_action(view, cx, Editor::move_to_previous_word_start);
register_action(cx, Editor::move_to_previous_subword_start); register_action(view, cx, Editor::move_to_previous_subword_start);
register_action(cx, Editor::move_to_next_word_end); register_action(view, cx, Editor::move_to_next_word_end);
register_action(cx, Editor::move_to_next_subword_end); register_action(view, cx, Editor::move_to_next_subword_end);
register_action(cx, Editor::move_to_beginning_of_line); register_action(view, cx, Editor::move_to_beginning_of_line);
register_action(cx, Editor::move_to_end_of_line); register_action(view, cx, Editor::move_to_end_of_line);
register_action(cx, Editor::move_to_start_of_paragraph); register_action(view, cx, Editor::move_to_start_of_paragraph);
register_action(cx, Editor::move_to_end_of_paragraph); register_action(view, cx, Editor::move_to_end_of_paragraph);
register_action(cx, Editor::move_to_beginning); register_action(view, cx, Editor::move_to_beginning);
register_action(cx, Editor::move_to_end); register_action(view, cx, Editor::move_to_end);
register_action(cx, Editor::select_up); register_action(view, cx, Editor::select_up);
register_action(cx, Editor::select_down); register_action(view, cx, Editor::select_down);
register_action(cx, Editor::select_left); register_action(view, cx, Editor::select_left);
register_action(cx, Editor::select_right); register_action(view, cx, Editor::select_right);
register_action(cx, Editor::select_to_previous_word_start); register_action(view, cx, Editor::select_to_previous_word_start);
register_action(cx, Editor::select_to_previous_subword_start); register_action(view, cx, Editor::select_to_previous_subword_start);
register_action(cx, Editor::select_to_next_word_end); register_action(view, cx, Editor::select_to_next_word_end);
register_action(cx, Editor::select_to_next_subword_end); register_action(view, cx, Editor::select_to_next_subword_end);
register_action(cx, Editor::select_to_beginning_of_line); register_action(view, cx, Editor::select_to_beginning_of_line);
register_action(cx, Editor::select_to_end_of_line); register_action(view, cx, Editor::select_to_end_of_line);
register_action(cx, Editor::select_to_start_of_paragraph); register_action(view, cx, Editor::select_to_start_of_paragraph);
register_action(cx, Editor::select_to_end_of_paragraph); register_action(view, cx, Editor::select_to_end_of_paragraph);
register_action(cx, Editor::select_to_beginning); register_action(view, cx, Editor::select_to_beginning);
register_action(cx, Editor::select_to_end); register_action(view, cx, Editor::select_to_end);
register_action(cx, Editor::select_all); register_action(view, cx, Editor::select_all);
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor.select_all_matches(action, cx).log_err(); editor.select_all_matches(action, cx).log_err();
}); });
register_action(cx, Editor::select_line); register_action(view, cx, Editor::select_line);
register_action(cx, Editor::split_selection_into_lines); register_action(view, cx, Editor::split_selection_into_lines);
register_action(cx, Editor::add_selection_above); register_action(view, cx, Editor::add_selection_above);
register_action(cx, Editor::add_selection_below); register_action(view, cx, Editor::add_selection_below);
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor.select_next(action, cx).log_err(); editor.select_next(action, cx).log_err();
}); });
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor.select_previous(action, cx).log_err(); editor.select_previous(action, cx).log_err();
}); });
register_action(cx, Editor::toggle_comments); register_action(view, cx, Editor::toggle_comments);
register_action(cx, Editor::select_larger_syntax_node); register_action(view, cx, Editor::select_larger_syntax_node);
register_action(cx, Editor::select_smaller_syntax_node); register_action(view, cx, Editor::select_smaller_syntax_node);
register_action(cx, Editor::move_to_enclosing_bracket); register_action(view, cx, Editor::move_to_enclosing_bracket);
register_action(cx, Editor::undo_selection); register_action(view, cx, Editor::undo_selection);
register_action(cx, Editor::redo_selection); register_action(view, cx, Editor::redo_selection);
register_action(cx, Editor::go_to_diagnostic); register_action(view, cx, Editor::go_to_diagnostic);
register_action(cx, Editor::go_to_prev_diagnostic); register_action(view, cx, Editor::go_to_prev_diagnostic);
register_action(cx, Editor::go_to_hunk); register_action(view, cx, Editor::go_to_hunk);
register_action(cx, Editor::go_to_prev_hunk); register_action(view, cx, Editor::go_to_prev_hunk);
register_action(cx, Editor::go_to_definition); register_action(view, cx, Editor::go_to_definition);
register_action(cx, Editor::go_to_definition_split); register_action(view, cx, Editor::go_to_definition_split);
register_action(cx, Editor::go_to_type_definition); register_action(view, cx, Editor::go_to_type_definition);
register_action(cx, Editor::go_to_type_definition_split); register_action(view, cx, Editor::go_to_type_definition_split);
register_action(cx, Editor::fold); register_action(view, cx, Editor::fold);
register_action(cx, Editor::fold_at); register_action(view, cx, Editor::fold_at);
register_action(cx, Editor::unfold_lines); register_action(view, cx, Editor::unfold_lines);
register_action(cx, Editor::unfold_at); register_action(view, cx, Editor::unfold_at);
register_action(cx, Editor::fold_selected_ranges); register_action(view, cx, Editor::fold_selected_ranges);
register_action(cx, Editor::show_completions); register_action(view, cx, Editor::show_completions);
register_action(cx, Editor::toggle_code_actions); register_action(view, cx, Editor::toggle_code_actions);
// on_action(cx, Editor::open_excerpts); todo!() // on_action(cx, Editor::open_excerpts); todo!()
register_action(cx, Editor::toggle_soft_wrap); register_action(view, cx, Editor::toggle_soft_wrap);
register_action(cx, Editor::toggle_inlay_hints); register_action(view, cx, Editor::toggle_inlay_hints);
register_action(cx, Editor::reveal_in_finder); register_action(view, cx, Editor::reveal_in_finder);
register_action(cx, Editor::copy_path); register_action(view, cx, Editor::copy_path);
register_action(cx, Editor::copy_relative_path); register_action(view, cx, Editor::copy_relative_path);
register_action(cx, Editor::copy_highlight_json); register_action(view, cx, Editor::copy_highlight_json);
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor editor
.format(action, cx) .format(action, cx)
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}); });
register_action(cx, Editor::restart_language_server); register_action(view, cx, Editor::restart_language_server);
register_action(cx, Editor::show_character_palette); register_action(view, cx, Editor::show_character_palette);
// on_action(cx, Editor::confirm_completion); todo!() // on_action(cx, Editor::confirm_completion); todo!()
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor editor
.confirm_code_action(action, cx) .confirm_code_action(action, cx)
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}); });
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor editor
.rename(action, cx) .rename(action, cx)
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}); });
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor editor
.confirm_rename(action, cx) .confirm_rename(action, cx)
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}); });
register_action(cx, |editor, action, cx| { register_action(view, cx, |editor, action, cx| {
editor editor
.find_all_references(action, cx) .find_all_references(action, cx)
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}); });
register_action(cx, Editor::next_copilot_suggestion); register_action(view, cx, Editor::next_copilot_suggestion);
register_action(cx, Editor::previous_copilot_suggestion); register_action(view, cx, Editor::previous_copilot_suggestion);
register_action(cx, Editor::copilot_suggest); register_action(view, cx, Editor::copilot_suggest);
register_action(cx, Editor::context_menu_first); register_action(view, cx, Editor::context_menu_first);
register_action(cx, Editor::context_menu_prev); register_action(view, cx, Editor::context_menu_prev);
register_action(cx, Editor::context_menu_next); register_action(view, cx, Editor::context_menu_next);
register_action(cx, Editor::context_menu_last); register_action(view, cx, Editor::context_menu_last);
} }
fn register_action<T: Action>( fn register_action<T: Action>(
cx: &mut ViewContext<Editor>, view: &View<Editor>,
cx: &mut WindowContext,
listener: impl Fn(&mut Editor, &T, &mut ViewContext<Editor>) + 'static, listener: impl Fn(&mut Editor, &T, &mut ViewContext<Editor>) + 'static,
) { ) {
cx.on_action(TypeId::of::<T>(), move |editor, action, phase, cx| { let view = view.clone();
cx.on_action(TypeId::of::<T>(), move |action, phase, cx| {
let action = action.downcast_ref().unwrap(); let action = action.downcast_ref().unwrap();
if phase == DispatchPhase::Bubble { if phase == DispatchPhase::Bubble {
view.update(cx, |editor, cx| {
listener(editor, action, cx); listener(editor, action, cx);
})
} }
}) })
} }

View file

@ -422,7 +422,7 @@ impl HoverState {
visible_rows: Range<u32>, visible_rows: Range<u32>,
workspace: Option<WeakView<Workspace>>, workspace: Option<WeakView<Workspace>>,
cx: &mut ViewContext<Editor>, cx: &mut ViewContext<Editor>,
) -> Option<(DisplayPoint, Vec<AnyElement<Editor>>)> { ) -> Option<(DisplayPoint, Vec<AnyElement>)> {
todo!("old version below") todo!("old version below")
} }
// // If there is a diagnostic, position the popovers based on that. // // If there is a diagnostic, position the popovers based on that.
@ -504,7 +504,7 @@ pub struct DiagnosticPopover {
} }
impl DiagnosticPopover { impl DiagnosticPopover {
pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> AnyElement<Editor> { pub fn render(&self, style: &EditorStyle, cx: &mut ViewContext<Editor>) -> AnyElement {
todo!() todo!()
// enum PrimaryDiagnostic {} // enum PrimaryDiagnostic {}

View file

@ -10,7 +10,7 @@ use futures::future::try_join_all;
use gpui::{ use gpui::{
div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter, div, point, AnyElement, AppContext, AsyncAppContext, Entity, EntityId, EventEmitter,
FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View, FocusHandle, Model, ParentElement, Pixels, SharedString, Styled, Subscription, Task, View,
ViewContext, VisualContext, WeakView, ViewContext, VisualContext, WeakView, WindowContext,
}; };
use language::{ use language::{
proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt, proto::serialize_anchor as serialize_text_anchor, Bias, Buffer, CharKind, OffsetRangeExt,
@ -584,7 +584,7 @@ impl Item for Editor {
Some(path.to_string_lossy().to_string().into()) Some(path.to_string_lossy().to_string().into())
} }
fn tab_content<T: 'static>(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<T> { fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement {
let theme = cx.theme(); let theme = cx.theme();
AnyElement::new( AnyElement::new(

View file

@ -117,8 +117,8 @@ impl FocusableView for FileFinder {
self.picker.focus_handle(cx) self.picker.focus_handle(cx)
} }
} }
impl Render<Self> for FileFinder { impl Render for FileFinder {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
v_stack().w_96().child(self.picker.clone()) v_stack().w_96().child(self.picker.clone())
@ -530,7 +530,7 @@ impl FileFinderDelegate {
} }
impl PickerDelegate for FileFinderDelegate { impl PickerDelegate for FileFinderDelegate {
type ListItem = Div<Picker<Self>>; type ListItem = Div;
fn placeholder_text(&self) -> Arc<str> { fn placeholder_text(&self) -> Arc<str> {
"Search project files...".into() "Search project files...".into()

View file

@ -144,15 +144,15 @@ impl GoToLine {
} }
} }
impl Render<Self> for GoToLine { impl Render for GoToLine {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div() div()
.elevation_2(cx) .elevation_2(cx)
.key_context("GoToLine") .key_context("GoToLine")
.on_action(Self::cancel) .on_action(cx.listener(Self::cancel))
.on_action(Self::confirm) .on_action(cx.listener(Self::confirm))
.w_96() .w_96()
.child( .child(
v_stack() v_stack()

View file

@ -1,7 +1,7 @@
use crate::{ use crate::{
point, px, size, AnyElement, AvailableSpace, Bounds, Element, ElementId, InteractiveElement, point, px, size, AnyElement, AvailableSpace, Bounds, Element, ElementId, InteractiveElement,
InteractiveElementState, Interactivity, LayoutId, Pixels, Point, RenderOnce, Size, InteractiveElementState, Interactivity, LayoutId, Pixels, Point, Render, RenderOnce, Size,
StyleRefinement, Styled, WindowContext, StyleRefinement, Styled, View, ViewContext, WindowContext,
}; };
use smallvec::SmallVec; use smallvec::SmallVec;
use std::{cell::RefCell, cmp, ops::Range, rc::Rc}; use std::{cell::RefCell, cmp, ops::Range, rc::Rc};
@ -10,30 +10,36 @@ use taffy::style::Overflow;
/// uniform_list provides lazy rendering for a set of items that are of uniform height. /// 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, /// 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. /// uniform_list will only render the visibile subset of items.
pub fn uniform_list<I, R>( pub fn uniform_list<I, R, V>(
view: View<V>,
id: I, id: I,
item_count: usize, item_count: usize,
f: impl 'static + Fn(Range<usize>, &mut WindowContext) -> Vec<R>, f: impl 'static + Fn(&mut V, Range<usize>, &mut ViewContext<V>) -> Vec<R>,
) -> UniformList ) -> UniformList
where where
I: Into<ElementId>, I: Into<ElementId>,
R: RenderOnce, R: RenderOnce,
V: Render,
{ {
let id = id.into(); let id = id.into();
let mut style = StyleRefinement::default(); let mut style = StyleRefinement::default();
style.overflow.y = Some(Overflow::Hidden); style.overflow.y = Some(Overflow::Hidden);
let render_range = move |range, cx: &mut WindowContext| {
view.update(cx, |this, cx| {
f(this, range, cx)
.into_iter()
.map(|component| component.render_into_any())
.collect()
})
};
UniformList { UniformList {
id: id.clone(), id: id.clone(),
style, style,
item_count, item_count,
item_to_measure_index: 0, item_to_measure_index: 0,
render_items: Box::new(move |visible_range, cx| { render_items: Box::new(render_range),
f(visible_range, cx)
.into_iter()
.map(|component| component.render_into_any())
.collect()
}),
interactivity: Interactivity { interactivity: Interactivity {
element_id: Some(id.into()), element_id: Some(id.into()),
..Default::default() ..Default::default()

View file

@ -1,4 +1,6 @@
use crate::{AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext}; use crate::{
AsyncWindowContext, Bounds, Pixels, PlatformInputHandler, View, ViewContext, WindowContext,
};
use std::ops::Range; use std::ops::Range;
/// Implement this trait to allow views to handle textual input when implementing an editor, field, etc. /// Implement this trait to allow views to handle textual input when implementing an editor, field, etc.
@ -43,9 +45,9 @@ pub struct ElementInputHandler<V> {
impl<V: 'static> ElementInputHandler<V> { impl<V: 'static> ElementInputHandler<V> {
/// Used in [Element::paint] with the element's bounds and a view context for its /// Used in [Element::paint] with the element's bounds and a view context for its
/// containing view. /// containing view.
pub fn new(element_bounds: Bounds<Pixels>, cx: &mut ViewContext<V>) -> Self { pub fn new(element_bounds: Bounds<Pixels>, view: View<V>, cx: &mut WindowContext) -> Self {
ElementInputHandler { ElementInputHandler {
view: cx.view().clone(), view,
element_bounds, element_bounds,
cx: cx.to_async(), cx: cx.to_async(),
} }

View file

@ -309,50 +309,6 @@ where
} }
} }
// pub struct RenderViewWith<E, V> {
// view: View<V>,
// element: Option<E>,
// }
// impl<E> Element for RenderViewWith<E>
// where
// E: 'static + Element,
// {
// type State = Option<AnyElement>;
// fn layout(
// &mut self,
// _: Option<Self::State>,
// cx: &mut WindowContext,
// ) -> (LayoutId, Self::State) {
// self.view.update(cx, |view, cx| {
// let mut element = self.element.take().unwrap().into_any();
// let layout_id = element.layout(view, cx);
// (layout_id, Some(element))
// })
// }
// fn paint(self, _: Bounds<Pixels>, element: &mut Self::ElementState, cx: &mut WindowContext) {
// element.paint(cx)
// }
// }
// impl<E> RenderOnce for RenderViewWith<E>
// where
// E: 'static + Element<V>,
// ParentV: 'static,
// {
// type Element = Self;
// fn element_id(&self) -> Option<ElementId> {
// self.element.as_ref().unwrap().element_id()
// }
// fn render_once(self) -> Self::Element {
// self
// }
// }
mod any_view { mod any_view {
use crate::{AnyElement, AnyView, BorrowWindow, Element, LayoutId, Render, WindowContext}; use crate::{AnyElement, AnyView, BorrowWindow, Element, LayoutId, Render, WindowContext};

View file

@ -1437,7 +1437,27 @@ impl<'a> WindowContext<'a> {
.bindings_for_action(action) .bindings_for_action(action)
} }
///========== ELEMENT RELATED FUNCTIONS =========== pub fn listener_for<V: Render, E>(
&self,
view: &View<V>,
f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
) -> impl Fn(&E, &mut WindowContext) + 'static {
let view = view.downgrade();
move |e: &E, cx: &mut WindowContext| {
view.update(cx, |view, cx| f(view, e, cx)).ok();
}
}
pub fn constructor_for<V: Render, R>(
&self,
view: &View<V>,
f: impl Fn(&mut V, &mut ViewContext<V>) -> R + 'static,
) -> impl Fn(&mut WindowContext) -> R + 'static {
let view = view.clone();
move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))
}
//========== ELEMENT RELATED FUNCTIONS ===========
pub fn with_key_dispatch<R>( pub fn with_key_dispatch<R>(
&mut self, &mut self,
context: KeyContext, context: KeyContext,
@ -1477,6 +1497,21 @@ impl<'a> WindowContext<'a> {
listener(event, cx); listener(event, cx);
})); }));
} }
/// Set an input handler, such as [ElementInputHandler], which interfaces with the
/// platform to receive textual input with proper integration with concerns such
/// as IME interactions.
pub fn handle_input(
&mut self,
focus_handle: &FocusHandle,
input_handler: impl PlatformInputHandler,
) {
if focus_handle.is_focused(self) {
self.window
.platform_window
.set_input_handler(Box::new(input_handler));
}
}
} }
impl Context for WindowContext<'_> { impl Context for WindowContext<'_> {
@ -1658,6 +1693,10 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
self.borrow_mut() self.borrow_mut()
} }
fn app(&self) -> &AppContext {
self.borrow()
}
fn window(&self) -> &Window { fn window(&self) -> &Window {
self.borrow() self.borrow()
} }
@ -2241,21 +2280,6 @@ impl<'a, V: 'static> ViewContext<'a, V> {
}); });
} }
/// Set an input handler, such as [ElementInputHandler], which interfaces with the
/// platform to receive textual input with proper integration with concerns such
/// as IME interactions.
pub fn handle_input(
&mut self,
focus_handle: &FocusHandle,
input_handler: impl PlatformInputHandler,
) {
if focus_handle.is_focused(self) {
self.window
.platform_window
.set_input_handler(Box::new(input_handler));
}
}
pub fn emit<Evt>(&mut self, event: Evt) pub fn emit<Evt>(&mut self, event: Evt)
where where
Evt: 'static, Evt: 'static,
@ -2287,19 +2311,11 @@ impl<'a, V: 'static> ViewContext<'a, V> {
&self, &self,
f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static, f: impl Fn(&mut V, &E, &mut ViewContext<V>) + 'static,
) -> impl Fn(&E, &mut WindowContext) + 'static { ) -> impl Fn(&E, &mut WindowContext) + 'static {
let view = self.view().clone(); let view = self.view().downgrade();
move |e: &E, cx: &mut WindowContext| { move |e: &E, cx: &mut WindowContext| {
view.update(cx, |view, cx| f(view, e, cx)); view.update(cx, |view, cx| f(view, e, cx)).ok();
} }
} }
pub fn constructor<R>(
&self,
f: impl Fn(&mut V, &mut ViewContext<V>) -> R + 'static,
) -> impl Fn(&mut WindowContext) -> R {
let view = self.view().clone();
move |cx: &mut WindowContext| view.update(cx, |view, cx| f(view, cx))
}
} }
impl<V> Context for ViewContext<'_, V> { impl<V> Context for ViewContext<'_, V> {

View file

@ -1,7 +1,7 @@
use editor::Editor; use editor::Editor;
use gpui::{ use gpui::{
div, prelude::*, uniform_list, AppContext, Div, FocusHandle, FocusableView, MouseButton, div, prelude::*, uniform_list, AppContext, Div, FocusHandle, FocusableView, MouseButton,
Render, Task, UniformListScrollHandle, View, ViewContext, WindowContext, MouseDownEvent, 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: RenderOnce<Picker<Self>>; type ListItem: RenderOnce;
fn match_count(&self) -> usize; fn match_count(&self) -> usize;
fn selected_index(&self) -> usize; fn selected_index(&self) -> usize;
@ -180,21 +180,21 @@ impl<D: PickerDelegate> Picker<D> {
} }
} }
impl<D: PickerDelegate> Render<Self> for Picker<D> { impl<D: PickerDelegate> Render for Picker<D> {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div() div()
.key_context("picker") .key_context("picker")
.size_full() .size_full()
.elevation_2(cx) .elevation_2(cx)
.on_action(Self::select_next) .on_action(cx.listener(Self::select_next))
.on_action(Self::select_prev) .on_action(cx.listener(Self::select_prev))
.on_action(Self::select_first) .on_action(cx.listener(Self::select_first))
.on_action(Self::select_last) .on_action(cx.listener(Self::select_last))
.on_action(Self::cancel) .on_action(cx.listener(Self::cancel))
.on_action(Self::confirm) .on_action(cx.listener(Self::confirm))
.on_action(Self::secondary_confirm) .on_action(cx.listener(Self::secondary_confirm))
.child( .child(
v_stack() v_stack()
.py_0p5() .py_0p5()
@ -208,31 +208,37 @@ impl<D: PickerDelegate> Render<Self> for Picker<D> {
.p_1() .p_1()
.grow() .grow()
.child( .child(
uniform_list("candidates", self.delegate.match_count(), { uniform_list(
move |this: &mut Self, visible_range, cx| { cx.view().clone(),
let selected_ix = this.delegate.selected_index(); "candidates",
self.delegate.match_count(),
{
let selected_index = self.delegate.selected_index();
move |picker, visible_range, cx| {
visible_range visible_range
.map(|ix| { .map(|ix| {
div() div()
.on_mouse_down( .on_mouse_down(
MouseButton::Left, MouseButton::Left,
move |this: &mut Self, event, cx| { cx.listener(move |this, event: &MouseDownEvent, cx| {
this.handle_click( this.handle_click(
ix, ix,
event.modifiers.command, event.modifiers.command,
cx, cx,
) )
}, }),
) )
.child(this.delegate.render_match( .child(picker.delegate.render_match(
ix, ix,
ix == selected_ix, ix == selected_index,
cx, cx,
)) ))
}) })
.collect() .collect()
} }
}) },
)
.track_scroll(self.scroll_handle.clone()), .track_scroll(self.scroll_handle.clone()),
) )
.max_h_72() .max_h_72()

View file

@ -10,9 +10,9 @@ 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, Div, EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement, ClipboardItem, Div, EventEmitter, FocusHandle, Focusable, FocusableView, InteractiveElement,
Model, MouseButton, ParentElement, Pixels, Point, PromptLevel, Render, RenderOnce, Stateful, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Point, PromptLevel, Render,
StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View, ViewContext, RenderOnce, Stateful, StatefulInteractiveElement, Styled, Task, UniformListScrollHandle, View,
VisualContext as _, WeakView, WindowContext, ViewContext, VisualContext as _, WeakView, WindowContext,
}; };
use menu::{Confirm, SelectNext, SelectPrev}; use menu::{Confirm, SelectNext, SelectPrev};
use project::{ use project::{
@ -1339,7 +1339,7 @@ impl ProjectPanel {
editor: Option<&View<Editor>>, editor: Option<&View<Editor>>,
padding: Pixels, padding: Pixels,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Div<Self> { ) -> Div {
let show_editor = details.is_editing && !details.is_processing; let show_editor = details.is_editing && !details.is_processing;
let theme = cx.theme(); let theme = cx.theme();
@ -1378,7 +1378,7 @@ impl ProjectPanel {
details: EntryDetails, details: EntryDetails,
// dragged_entry_destination: &mut Option<Arc<Path>>, // dragged_entry_destination: &mut Option<Arc<Path>>,
cx: &mut ViewContext<Self>, cx: &mut ViewContext<Self>,
) -> Stateful<Self, Div<Self>> { ) -> Stateful<Div> {
let kind = details.kind; let kind = details.kind;
let settings = ProjectPanelSettings::get_global(cx); let settings = ProjectPanelSettings::get_global(cx);
const INDENT_SIZE: Pixels = px(16.0); const INDENT_SIZE: Pixels = px(16.0);
@ -1396,7 +1396,7 @@ impl ProjectPanel {
this.bg(cx.theme().colors().element_selected) this.bg(cx.theme().colors().element_selected)
}) })
.hover(|style| style.bg(cx.theme().colors().element_hover)) .hover(|style| style.bg(cx.theme().colors().element_hover))
.on_click(move |this, event, cx| { .on_click(cx.listener(move |this, event: &gpui::ClickEvent, cx| {
if !show_editor { if !show_editor {
if kind.is_dir() { if kind.is_dir() {
this.toggle_expanded(entry_id, cx); this.toggle_expanded(entry_id, cx);
@ -1408,10 +1408,13 @@ impl ProjectPanel {
} }
} }
} }
}) }))
.on_mouse_down(MouseButton::Right, move |this, event, cx| { .on_mouse_down(
MouseButton::Right,
cx.listener(move |this, event: &MouseDownEvent, cx| {
this.deploy_context_menu(event.position, entry_id, cx); this.deploy_context_menu(event.position, entry_id, cx);
}) }),
)
// .on_drop::<ProjectEntryId>(|this, event, cx| { // .on_drop::<ProjectEntryId>(|this, event, cx| {
// this.move_entry( // this.move_entry(
// *dragged_entry, // *dragged_entry,
@ -1423,10 +1426,10 @@ impl ProjectPanel {
} }
} }
impl Render<Self> for ProjectPanel { impl Render for ProjectPanel {
type Element = Focusable<Self, Stateful<Self, Div<Self>>>; type Element = Focusable<Stateful<Div>>;
fn render(&mut self, _cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
let has_worktree = self.visible_entries.len() != 0; let has_worktree = self.visible_entries.len() != 0;
if has_worktree { if has_worktree {
@ -1434,40 +1437,43 @@ impl Render<Self> for ProjectPanel {
.id("project-panel") .id("project-panel")
.size_full() .size_full()
.key_context("ProjectPanel") .key_context("ProjectPanel")
.on_action(Self::select_next) .on_action(cx.listener(Self::select_next))
.on_action(Self::select_prev) .on_action(cx.listener(Self::select_prev))
.on_action(Self::expand_selected_entry) .on_action(cx.listener(Self::expand_selected_entry))
.on_action(Self::collapse_selected_entry) .on_action(cx.listener(Self::collapse_selected_entry))
.on_action(Self::collapse_all_entries) .on_action(cx.listener(Self::collapse_all_entries))
.on_action(Self::new_file) .on_action(cx.listener(Self::new_file))
.on_action(Self::new_directory) .on_action(cx.listener(Self::new_directory))
.on_action(Self::rename) .on_action(cx.listener(Self::rename))
.on_action(Self::delete) .on_action(cx.listener(Self::delete))
.on_action(Self::confirm) .on_action(cx.listener(Self::confirm))
.on_action(Self::open_file) .on_action(cx.listener(Self::open_file))
.on_action(Self::cancel) .on_action(cx.listener(Self::cancel))
.on_action(Self::cut) .on_action(cx.listener(Self::cut))
.on_action(Self::copy) .on_action(cx.listener(Self::copy))
.on_action(Self::copy_path) .on_action(cx.listener(Self::copy_path))
.on_action(Self::copy_relative_path) .on_action(cx.listener(Self::copy_relative_path))
.on_action(Self::paste) .on_action(cx.listener(Self::paste))
.on_action(Self::reveal_in_finder) .on_action(cx.listener(Self::reveal_in_finder))
.on_action(Self::open_in_terminal) .on_action(cx.listener(Self::open_in_terminal))
.on_action(Self::new_search_in_directory) .on_action(cx.listener(Self::new_search_in_directory))
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)
.child( .child(
uniform_list( uniform_list(
cx.view().clone(),
"entries", "entries",
self.visible_entries self.visible_entries
.iter() .iter()
.map(|(_, worktree_entries)| worktree_entries.len()) .map(|(_, worktree_entries)| worktree_entries.len())
.sum(), .sum(),
|this: &mut Self, range, cx| { {
|this, range, cx| {
let mut items = Vec::new(); let mut items = Vec::new();
this.for_each_visible_entry(range, cx, |id, details, cx| { this.for_each_visible_entry(range, cx, |id, details, cx| {
items.push(this.render_entry(id, details, cx)); items.push(this.render_entry(id, details, cx));
}); });
items items
}
}, },
) )
.size_full() .size_full()

View file

@ -56,12 +56,12 @@ pub struct Mention {
} }
impl RichText { impl RichText {
pub fn element<V: 'static>( pub fn element(
&self, &self,
// syntax: Arc<SyntaxTheme>, // syntax: Arc<SyntaxTheme>,
// style: RichTextStyle, // style: RichTextStyle,
// cx: &mut ViewContext<V>, // cx: &mut ViewContext<V>,
) -> AnyElement<V> { ) -> AnyElement {
todo!(); todo!();
// let mut region_id = 0; // let mut region_id = 0;

View file

@ -5,8 +5,8 @@ use ui::prelude::*;
pub struct ColorsStory; pub struct ColorsStory;
impl Render<Self> for ColorsStory { impl Render for ColorsStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let color_scales = default_color_scales(); let color_scales = default_color_scales();

View file

@ -27,7 +27,7 @@ impl FocusStory {
} }
impl Render<Self> for FocusStory { impl Render<Self> for FocusStory {
type Element = Focusable<Self, Stateful<Self, Div<Self>>>; type Element = Focusable<Stateful<Div>>;
fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut gpui::ViewContext<Self>) -> Self::Element {
let theme = cx.theme(); let theme = cx.theme();
@ -42,18 +42,20 @@ impl Render<Self> for FocusStory {
.id("parent") .id("parent")
.focusable() .focusable()
.key_context("parent") .key_context("parent")
.on_action(|_, action: &ActionA, cx| { .on_action(cx.listener(|_, action: &ActionA, cx| {
println!("Action A dispatched on parent"); println!("Action A dispatched on parent");
}) }))
.on_action(|_, action: &ActionB, cx| { .on_action(cx.listener(|_, action: &ActionB, cx| {
println!("Action B dispatched on parent"); println!("Action B dispatched on parent");
}) }))
.on_focus(|_, _, _| println!("Parent focused")) .on_focus(cx.listener(|_, _, _| println!("Parent focused")))
.on_blur(|_, _, _| println!("Parent blurred")) .on_blur(cx.listener(|_, _, _| println!("Parent blurred")))
.on_focus_in(|_, _, _| println!("Parent focus_in")) .on_focus_in(cx.listener(|_, _, _| println!("Parent focus_in")))
.on_focus_out(|_, _, _| println!("Parent focus_out")) .on_focus_out(cx.listener(|_, _, _| println!("Parent focus_out")))
.on_key_down(|_, event, phase, _| println!("Key down on parent {:?}", event)) .on_key_down(
.on_key_up(|_, event, phase, _| println!("Key up on parent {:?}", event)) cx.listener(|_, event, phase, _| println!("Key down on parent {:?}", event)),
)
.on_key_up(cx.listener(|_, event, phase, _| println!("Key up on parent {:?}", event)))
.size_full() .size_full()
.bg(color_1) .bg(color_1)
.focus(|style| style.bg(color_2)) .focus(|style| style.bg(color_2))
@ -61,38 +63,42 @@ impl Render<Self> for FocusStory {
div() div()
.track_focus(&self.child_1_focus) .track_focus(&self.child_1_focus)
.key_context("child-1") .key_context("child-1")
.on_action(|_, action: &ActionB, cx| { .on_action(cx.listener(|_, action: &ActionB, cx| {
println!("Action B dispatched on child 1 during"); println!("Action B dispatched on child 1 during");
}) }))
.w_full() .w_full()
.h_6() .h_6()
.bg(color_4) .bg(color_4)
.focus(|style| style.bg(color_5)) .focus(|style| style.bg(color_5))
.in_focus(|style| style.bg(color_6)) .in_focus(|style| style.bg(color_6))
.on_focus(|_, _, _| println!("Child 1 focused")) .on_focus(cx.listener(|_, _, _| println!("Child 1 focused")))
.on_blur(|_, _, _| println!("Child 1 blurred")) .on_blur(cx.listener(|_, _, _| println!("Child 1 blurred")))
.on_focus_in(|_, _, _| println!("Child 1 focus_in")) .on_focus_in(cx.listener(|_, _, _| println!("Child 1 focus_in")))
.on_focus_out(|_, _, _| println!("Child 1 focus_out")) .on_focus_out(cx.listener(|_, _, _| println!("Child 1 focus_out")))
.on_key_down(|_, event, phase, _| println!("Key down on child 1 {:?}", event)) .on_key_down(
.on_key_up(|_, event, phase, _| println!("Key up on child 1 {:?}", event)) cx.listener(|_, event, _| println!("Key down on child 1 {:?}", event)),
)
.on_key_up(cx.listener(|_, event, _| println!("Key up on child 1 {:?}", event)))
.child("Child 1"), .child("Child 1"),
) )
.child( .child(
div() div()
.track_focus(&self.child_2_focus) .track_focus(&self.child_2_focus)
.key_context("child-2") .key_context("child-2")
.on_action(|_, action: &ActionC, cx| { .on_action(cx.listener(|_, action: &ActionC, cx| {
println!("Action C dispatched on child 2"); println!("Action C dispatched on child 2");
}) }))
.w_full() .w_full()
.h_6() .h_6()
.bg(color_4) .bg(color_4)
.on_focus(|_, _, _| println!("Child 2 focused")) .on_focus(cx.listener(|_, _, _| println!("Child 2 focused")))
.on_blur(|_, _, _| println!("Child 2 blurred")) .on_blur(cx.listener(|_, _, _| println!("Child 2 blurred")))
.on_focus_in(|_, _, _| println!("Child 2 focus_in")) .on_focus_in(cx.listener(|_, _, _| println!("Child 2 focus_in")))
.on_focus_out(|_, _, _| println!("Child 2 focus_out")) .on_focus_out(cx.listener(|_, _, _| println!("Child 2 focus_out")))
.on_key_down(|_, event, phase, _| println!("Key down on child 2 {:?}", event)) .on_key_down(
.on_key_up(|_, event, phase, _| println!("Key up on child 2 {:?}", event)) cx.listener(|_, event, _| println!("Key down on child 2 {:?}", event)),
)
.on_key_up(cx.listener(|_, event, _| println!("Key up on child 2 {:?}", event)))
.child("Child 2"), .child("Child 2"),
) )
} }

View file

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

View file

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

View file

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

View file

@ -9,10 +9,10 @@ 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, Action, AnyElement, AppContext, DispatchPhase, Div, Element, EventEmitter, actions, div, Action, AnyElement, AppContext, Div, Element, EventEmitter, FocusEvent,
FocusEvent, FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler, FocusHandle, Focusable, FocusableElement, FocusableView, InputHandler, InteractiveElement,
InteractiveElement, KeyDownEvent, Keystroke, Model, MouseButton, ParentElement, Pixels, Render, KeyDownEvent, Keystroke, Model, MouseButton, MouseDownEvent, ParentElement, Pixels, Render,
SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, SharedString, Styled, Task, View, ViewContext, VisualContext, WeakView, WindowContext,
}; };
use language::Bias; use language::Bias;
use persistence::TERMINAL_DB; use persistence::TERMINAL_DB;
@ -84,7 +84,7 @@ pub struct TerminalView {
has_new_content: bool, has_new_content: bool,
//Currently using iTerm bell, show bell emoji in tab until input is received //Currently using iTerm bell, show bell emoji in tab until input is received
has_bell: bool, has_bell: bool,
context_menu: Option<View<ContextMenu<Self>>>, context_menu: Option<View<ContextMenu>>,
blink_state: bool, blink_state: bool,
blinking_on: bool, blinking_on: bool,
blinking_paused: bool, blinking_paused: bool,
@ -505,12 +505,7 @@ pub fn regex_search_for_query(query: &project::search::SearchQuery) -> Option<Re
} }
impl TerminalView { impl TerminalView {
fn key_down( fn key_down(&mut self, event: &KeyDownEvent, cx: &mut ViewContext<Self>) {
&mut self,
event: &KeyDownEvent,
_dispatch_phase: DispatchPhase,
cx: &mut ViewContext<Self>,
) {
self.clear_bel(cx); self.clear_bel(cx);
self.pause_cursor_blinking(cx); self.pause_cursor_blinking(cx);
@ -537,8 +532,8 @@ impl TerminalView {
} }
} }
impl Render<Self> for TerminalView { impl Render for TerminalView {
type Element = Focusable<Self, Div<Self>>; type Element = Focusable<Div>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let terminal_handle = self.terminal.clone().downgrade(); let terminal_handle = self.terminal.clone().downgrade();
@ -552,14 +547,14 @@ impl Render<Self> for TerminalView {
div() div()
.z_index(0) .z_index(0)
.absolute() .absolute()
.on_key_down(Self::key_down) .on_key_down(cx.listener(Self::key_down))
.on_action(TerminalView::send_text) .on_action(cx.listener(TerminalView::send_text))
.on_action(TerminalView::send_keystroke) .on_action(cx.listener(TerminalView::send_keystroke))
.on_action(TerminalView::copy) .on_action(cx.listener(TerminalView::copy))
.on_action(TerminalView::paste) .on_action(cx.listener(TerminalView::paste))
.on_action(TerminalView::clear) .on_action(cx.listener(TerminalView::clear))
.on_action(TerminalView::show_character_palette) .on_action(cx.listener(TerminalView::show_character_palette))
.on_action(TerminalView::select_all) .on_action(cx.listener(TerminalView::select_all))
// todo!() // todo!()
.child( .child(
"TERMINAL HERE", // TerminalElement::new( "TERMINAL HERE", // TerminalElement::new(
@ -569,10 +564,13 @@ impl Render<Self> for TerminalView {
// self.can_navigate_to_selected_word, // self.can_navigate_to_selected_word,
// ) // )
) )
.on_mouse_down(MouseButton::Right, |this, event, cx| { .on_mouse_down(
MouseButton::Right,
cx.listener(|this, event: &MouseDownEvent, cx| {
this.deploy_context_menu(event.position, cx); this.deploy_context_menu(event.position, cx);
cx.notify(); cx.notify();
}), }),
),
) )
.children( .children(
self.context_menu self.context_menu
@ -580,8 +578,8 @@ impl Render<Self> for TerminalView {
.map(|context_menu| div().z_index(1).absolute().child(context_menu)), .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(cx.listener(Self::focus_in))
.on_focus_out(Self::focus_out) .on_focus_out(cx.listener(Self::focus_out))
} }
} }
@ -746,11 +744,7 @@ impl Item for TerminalView {
Some(self.terminal().read(cx).title().into()) Some(self.terminal().read(cx).title().into())
} }
fn tab_content<T: 'static>( fn tab_content(&self, _detail: Option<usize>, cx: &WindowContext) -> AnyElement {
&self,
_detail: Option<usize>,
cx: &gpui::AppContext,
) -> AnyElement<T> {
let title = self.terminal().read(cx).title(); let title = self.terminal().read(cx).title();
div() div()

View file

@ -1,11 +1,11 @@
use gpui::{div, Div, Element, ParentElement, SharedString, Styled, ViewContext}; use gpui::{div, Div, Element, ParentElement, SharedString, Styled, WindowContext};
use crate::ActiveTheme; use crate::ActiveTheme;
pub struct Story {} pub struct Story {}
impl Story { impl Story {
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> { pub fn container(cx: &mut WindowContext) -> Div {
div() div()
.size_full() .size_full()
.flex() .flex()
@ -16,21 +16,18 @@ impl Story {
.bg(cx.theme().colors().background) .bg(cx.theme().colors().background)
} }
pub fn title<V: 'static>(cx: &mut ViewContext<V>, title: SharedString) -> impl Element<V> { pub fn title(cx: &mut WindowContext, title: SharedString) -> impl Element {
div() div()
.text_xl() .text_xl()
.text_color(cx.theme().colors().text) .text_color(cx.theme().colors().text)
.child(title) .child(title)
} }
pub fn title_for<V: 'static, T>(cx: &mut ViewContext<V>) -> impl Element<V> { pub fn title_for<T>(cx: &mut WindowContext) -> impl Element {
Self::title(cx, std::any::type_name::<T>().into()) Self::title(cx, std::any::type_name::<T>().into())
} }
pub fn label<V: 'static>( pub fn label(cx: &mut WindowContext, label: impl Into<SharedString>) -> impl Element {
cx: &mut ViewContext<V>,
label: impl Into<SharedString>,
) -> impl Element<V> {
div() div()
.mt_4() .mt_4()
.mb_2() .mb_2()

View file

@ -147,8 +147,8 @@ mod stories {
pub struct PlayerStory; pub struct PlayerStory;
impl Render<Self> for PlayerStory { impl Render for PlayerStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx).child( Story::container(cx).child(
@ -156,7 +156,7 @@ mod stories {
.flex() .flex()
.flex_col() .flex_col()
.gap_4() .gap_4()
.child(Story::title_for::<_, PlayerColors>(cx)) .child(Story::title_for::<PlayerColors>(cx))
.child(Story::label(cx, "Player Colors")) .child(Story::label(cx, "Player Colors"))
.child( .child(
div() div()

View file

@ -63,6 +63,12 @@ impl ActiveTheme for AppContext {
} }
} }
// impl<'a> ActiveTheme for WindowContext<'a> {
// fn theme(&self) -> &Arc<Theme> {
// &ThemeSettings::get_global(self.app()).active_theme
// }
// }
pub struct ThemeFamily { pub struct ThemeFamily {
pub id: String, pub id: String,
pub name: SharedString, pub name: SharedString,

View file

@ -7,10 +7,10 @@ pub struct Avatar {
shape: Shape, shape: Shape,
} }
impl<V: 'static> Component<V> for Avatar { impl Component for Avatar {
type Rendered = Img<V>; type Rendered = Img;
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, _: &mut WindowContext) -> Self::Rendered {
let mut img = img(); let mut img = img();
if self.shape == Shape::Circle { if self.shape == Shape::Circle {
@ -51,12 +51,12 @@ mod stories {
pub struct AvatarStory; pub struct AvatarStory;
impl Render<Self> for AvatarStory { impl Render for AvatarStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut WindowContext) -> Self::Element {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, Avatar>(cx)) .child(Story::title_for::<Avatar>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(Avatar::new( .child(Avatar::new(
"https://avatars.githubusercontent.com/u/1714999?v=4", "https://avatars.githubusercontent.com/u/1714999?v=4",

View file

@ -1,8 +1,8 @@
use std::sync::Arc; use std::rc::Rc;
use gpui::{ use gpui::{
DefiniteLength, DefiniteLength, Div, Hsla, MouseButton, RenderOnce, Stateful, DefiniteLength, Div, Hsla, MouseButton, MouseDownEvent, RenderOnce, StatefulInteractiveElement,
StatefulInteractiveElement, WindowContext, WindowContext,
}; };
use crate::prelude::*; use crate::prelude::*;
@ -64,9 +64,10 @@ impl ButtonVariant {
} }
} }
#[derive(RenderOnce)]
pub struct Button { pub struct Button {
disabled: bool, disabled: bool,
click_handler: Option<CallbackHandle<()>>, click_handler: Option<Rc<dyn Fn(&MouseDownEvent, &mut WindowContext)>>,
icon: Option<Icon>, icon: Option<Icon>,
icon_position: Option<IconPosition>, icon_position: Option<IconPosition>,
label: SharedString, label: SharedString,
@ -75,10 +76,10 @@ pub struct Button {
color: Option<TextColor>, color: Option<TextColor>,
} }
impl RenderOnce for Button { impl Component for Button {
type Element = Stateful<Div>; type Rendered = gpui::Stateful<Div>;
fn render(self) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let (icon_color, label_color) = match (self.disabled, self.color) { let (icon_color, label_color) = match (self.disabled, self.color) {
(true, _) => (TextColor::Disabled, TextColor::Disabled), (true, _) => (TextColor::Disabled, TextColor::Disabled),
(_, None) => (TextColor::Default, TextColor::Default), (_, None) => (TextColor::Default, TextColor::Default),
@ -116,9 +117,9 @@ impl RenderOnce for Button {
button = button.w(width).justify_center(); button = button.w(width).justify_center();
} }
if let Some(click_handler) = self.handlers.click.clone() { if let Some(click_handler) = self.click_handler.clone() {
button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| { button = button.on_mouse_down(MouseButton::Left, move |event, cx| {
click_handler(state, cx); click_handler(event, cx);
}); });
} }
@ -167,8 +168,11 @@ impl Button {
self self
} }
pub fn on_click(mut self, handler: CallbackHandle<()>) -> Self { pub fn on_click(
self.handlers.click = Some(handler); mut self,
handler: impl Fn(&MouseDownEvent, &mut WindowContext) + 'static,
) -> Self {
self.click_handler = Some(Rc::new(handler));
self self
} }
@ -215,15 +219,15 @@ impl Component for ButtonGroup {
let mut group = h_stack(); let mut group = h_stack();
for button in self.buttons.into_iter() { for button in self.buttons.into_iter() {
group = group.child(button.render(view, cx)); group = group.child(button.render(cx));
} }
group group
} }
} }
impl<V: 'static> ButtonGroup<V> { impl ButtonGroup {
pub fn new(buttons: Vec<Button<V>>) -> Self { pub fn new(buttons: Vec<Button>) -> Self {
Self { buttons } Self { buttons }
} }
} }

View file

@ -1,10 +1,10 @@
use gpui::{div, prelude::*, Div, Element, ElementId, RenderOnce, Stateful, Styled, ViewContext}; use gpui::{div, prelude::*, Div, Element, ElementId, RenderOnce, Styled, WindowContext};
use std::sync::Arc;
use theme2::ActiveTheme; use theme2::ActiveTheme;
use crate::{Icon, IconElement, Selection, TextColor}; use crate::{Icon, IconElement, Selection, TextColor};
pub type CheckHandler<V> = Arc<dyn Fn(Selection, &mut V, &mut ViewContext<V>) + Send + Sync>; pub type CheckHandler = Box<dyn Fn(&Selection, &mut WindowContext) + 'static>;
/// # Checkbox /// # Checkbox
/// ///
@ -12,17 +12,17 @@ pub type CheckHandler<V> = Arc<dyn Fn(Selection, &mut V, &mut ViewContext<V>) +
/// Each checkbox works independently from other checkboxes in the list, /// Each checkbox works independently from other checkboxes in the list,
/// therefore checking an additional box does not affect any other selections. /// therefore checking an additional box does not affect any other selections.
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Checkbox<V: 'static> { pub struct Checkbox {
id: ElementId, id: ElementId,
checked: Selection, checked: Selection,
disabled: bool, disabled: bool,
on_click: Option<CheckHandler<V>>, on_click: Option<CheckHandler>,
} }
impl<V: 'static> Component<V> for Checkbox<V> { impl Component for Checkbox {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let group_id = format!("checkbox_group_{:?}", self.id); let group_id = format!("checkbox_group_{:?}", self.id);
let icon = match self.checked { let icon = match self.checked {
@ -137,13 +137,11 @@ impl<V: 'static> Component<V> for Checkbox<V> {
) )
.when_some( .when_some(
self.on_click.filter(|_| !self.disabled), self.on_click.filter(|_| !self.disabled),
|this, on_click| { |this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
this.on_click(move |view, _, cx| on_click(self.checked.inverse(), view, cx))
},
) )
} }
} }
impl<V: 'static> Checkbox<V> { impl Checkbox {
pub fn new(id: impl Into<ElementId>, checked: Selection) -> Self { pub fn new(id: impl Into<ElementId>, checked: Selection) -> Self {
Self { Self {
id: id.into(), id: id.into(),
@ -160,13 +158,13 @@ impl<V: 'static> Checkbox<V> {
pub fn on_click( pub fn on_click(
mut self, mut self,
handler: impl 'static + Fn(Selection, &mut V, &mut ViewContext<V>) + Send + Sync, handler: impl 'static + Fn(&Selection, &mut WindowContext) + Send + Sync,
) -> Self { ) -> Self {
self.on_click = Some(Arc::new(handler)); self.on_click = Some(Box::new(handler));
self self
} }
pub fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { pub fn render(self, cx: &mut WindowContext) -> impl Element {
let group_id = format!("checkbox_group_{:?}", self.id); let group_id = format!("checkbox_group_{:?}", self.id);
let icon = match self.checked { let icon = match self.checked {
@ -281,9 +279,7 @@ impl<V: 'static> Checkbox<V> {
) )
.when_some( .when_some(
self.on_click.filter(|_| !self.disabled), self.on_click.filter(|_| !self.disabled),
|this, on_click| { |this, on_click| this.on_click(move |_, cx| on_click(&self.checked.inverse(), cx)),
this.on_click(move |view, _, cx| on_click(self.checked.inverse(), view, cx))
},
) )
} }
} }
@ -299,8 +295,8 @@ mod stories {
pub struct CheckboxStory; pub struct CheckboxStory;
impl Render<Self> for CheckboxStory { impl Render for CheckboxStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -4,44 +4,39 @@ use std::rc::Rc;
use crate::{prelude::*, v_stack, List, ListItem}; use crate::{prelude::*, v_stack, List, ListItem};
use crate::{ListEntry, ListSeparator, ListSubHeader}; use crate::{ListEntry, ListSeparator, ListSubHeader};
use gpui::{ use gpui::{
overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, DispatchPhase, Div, overlay, px, Action, AnchorCorner, AnyElement, AppContext, Bounds, ClickEvent, DispatchPhase,
EventEmitter, FocusHandle, FocusableView, LayoutId, ManagedView, Manager, MouseButton, Div, EventEmitter, FocusHandle, FocusableView, LayoutId, ManagedView, Manager, MouseButton,
MouseDownEvent, Pixels, Point, Render, RenderOnce, View, VisualContext, WeakView, MouseDownEvent, Pixels, Point, Render, RenderOnce, View, VisualContext,
}; };
pub enum ContextMenuItem<V> { pub enum ContextMenuItem {
Separator(ListSeparator), Separator(ListSeparator),
Header(ListSubHeader), Header(ListSubHeader),
Entry( Entry(ListEntry, Rc<dyn Fn(&ClickEvent, &mut WindowContext)>),
ListEntry<ContextMenu<V>>,
Rc<dyn Fn(&mut V, &mut ViewContext<V>)>,
),
} }
pub struct ContextMenu<V> { pub struct ContextMenu {
items: Vec<ContextMenuItem<V>>, items: Vec<ContextMenuItem>,
focus_handle: FocusHandle, focus_handle: FocusHandle,
handle: WeakView<V>,
} }
impl<V: 'static> FocusableView for ContextMenu<V> { impl FocusableView for ContextMenu {
fn focus_handle(&self, _cx: &AppContext) -> FocusHandle { fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
self.focus_handle.clone() self.focus_handle.clone()
} }
} }
impl<V: 'static> EventEmitter<Manager> for ContextMenu<V> {} impl EventEmitter<Manager> for ContextMenu {}
impl<V: 'static> ContextMenu<V> { impl ContextMenu {
pub fn build( pub fn build(
cx: &mut ViewContext<V>, cx: &mut WindowContext,
f: impl FnOnce(Self, &mut ViewContext<Self>) -> Self, f: impl FnOnce(Self, &mut WindowContext) -> Self,
) -> View<Self> { ) -> View<Self> {
let handle = cx.view().downgrade(); // let handle = cx.view().downgrade();
cx.build_view(|cx| { cx.build_view(|cx| {
f( f(
Self { Self {
handle,
items: Default::default(), items: Default::default(),
focus_handle: cx.focus_handle(), focus_handle: cx.focus_handle(),
}, },
@ -63,15 +58,15 @@ impl<V: 'static> ContextMenu<V> {
pub fn entry( pub fn entry(
mut self, mut self,
view: ListEntry<Self>, view: ListEntry,
on_click: impl Fn(&mut V, &mut ViewContext<V>) + 'static, on_click: impl Fn(&ClickEvent, &mut WindowContext) + 'static,
) -> Self { ) -> Self {
self.items self.items
.push(ContextMenuItem::Entry(view, Rc::new(on_click))); .push(ContextMenuItem::Entry(view, Rc::new(on_click)));
self self
} }
pub fn action(self, view: ListEntry<Self>, action: Box<dyn Action>) -> Self { pub fn action(self, view: ListEntry, action: Box<dyn Action>) -> Self {
// todo: add the keybindings to the list entry // todo: add the keybindings to the list entry
self.entry(view, move |_, cx| cx.dispatch_action(action.boxed_clone())) self.entry(view, move |_, cx| cx.dispatch_action(action.boxed_clone()))
} }
@ -86,21 +81,23 @@ impl<V: 'static> ContextMenu<V> {
} }
} }
impl<V: 'static> Render<Self> for ContextMenu<V> { impl Render for ContextMenu {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div().elevation_2(cx).flex().flex_row().child( div().elevation_2(cx).flex().flex_row().child(
v_stack() v_stack()
.min_w(px(200.)) .min_w(px(200.))
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)
.on_mouse_down_out(|this: &mut Self, _, cx| this.cancel(&Default::default(), cx)) .on_mouse_down_out(
cx.listener(|this: &mut Self, _, cx| this.cancel(&Default::default(), cx)),
)
// .on_action(ContextMenu::select_first) // .on_action(ContextMenu::select_first)
// .on_action(ContextMenu::select_last) // .on_action(ContextMenu::select_last)
// .on_action(ContextMenu::select_next) // .on_action(ContextMenu::select_next)
// .on_action(ContextMenu::select_prev) // .on_action(ContextMenu::select_prev)
.on_action(ContextMenu::confirm) .on_action(cx.listener(ContextMenu::confirm))
.on_action(ContextMenu::cancel) .on_action(cx.listener(ContextMenu::cancel))
.flex_none() .flex_none()
// .bg(cx.theme().colors().elevated_surface_background) // .bg(cx.theme().colors().elevated_surface_background)
// .border() // .border()
@ -115,10 +112,11 @@ impl<V: 'static> Render<Self> for ContextMenu<V> {
ContextMenuItem::Header(header) => ListItem::Header(header.clone()), ContextMenuItem::Header(header) => ListItem::Header(header.clone()),
ContextMenuItem::Entry(entry, callback) => { ContextMenuItem::Entry(entry, callback) => {
let callback = callback.clone(); let callback = callback.clone();
let handle = self.handle.clone(); let dismiss = cx.listener(|_, _, cx| cx.emit(Manager::Dismiss));
ListItem::Entry(entry.clone().on_click(move |this, cx| {
handle.update(cx, |view, cx| callback(view, cx)).ok(); ListItem::Entry(entry.clone().on_click(move |event, cx| {
cx.emit(Manager::Dismiss); callback(event, cx);
dismiss(event, cx)
})) }))
} }
}) })
@ -128,22 +126,21 @@ impl<V: 'static> Render<Self> for ContextMenu<V> {
} }
} }
pub struct MenuHandle<V: 'static, M: ManagedView> { pub struct MenuHandle<M: ManagedView> {
id: ElementId, id: ElementId,
child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement<V> + 'static>>, child_builder: Option<Box<dyn FnOnce(bool) -> AnyElement + 'static>>,
menu_builder: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) -> View<M> + 'static>>, menu_builder: Option<Rc<dyn Fn(&mut WindowContext) -> View<M> + 'static>>,
anchor: Option<AnchorCorner>, anchor: Option<AnchorCorner>,
attach: Option<AnchorCorner>, attach: Option<AnchorCorner>,
} }
impl<V: 'static, M: ManagedView> MenuHandle<V, M> { impl<M: ManagedView> MenuHandle<M> {
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 WindowContext) -> View<M> + 'static) -> Self {
self.menu_builder = Some(Rc::new(f)); self.menu_builder = Some(Rc::new(f));
self self
} }
pub fn child<R: RenderOnce<V>>(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self { pub fn child<R: RenderOnce>(mut self, f: impl FnOnce(bool) -> R + 'static) -> Self {
self.child_builder = Some(Box::new(|b| f(b).render_once().into_any())); self.child_builder = Some(Box::new(|b| f(b).render_once().into_any()));
self self
} }
@ -162,7 +159,7 @@ impl<V: 'static, M: ManagedView> MenuHandle<V, M> {
} }
} }
pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<V, M> { pub fn menu_handle<M: ManagedView>(id: impl Into<ElementId>) -> MenuHandle<M> {
MenuHandle { MenuHandle {
id: id.into(), id: id.into(),
child_builder: None, child_builder: None,
@ -172,21 +169,20 @@ pub fn menu_handle<V: 'static, M: ManagedView>(id: impl Into<ElementId>) -> Menu
} }
} }
pub struct MenuHandleState<V, M> { pub struct MenuHandleState<M> {
menu: Rc<RefCell<Option<View<M>>>>, menu: Rc<RefCell<Option<View<M>>>>,
position: Rc<RefCell<Point<Pixels>>>, position: Rc<RefCell<Point<Pixels>>>,
child_layout_id: Option<LayoutId>, child_layout_id: Option<LayoutId>,
child_element: Option<AnyElement<V>>, child_element: Option<AnyElement>,
menu_element: Option<AnyElement<V>>, menu_element: Option<AnyElement>,
} }
impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> { impl<M: ManagedView> Element for MenuHandle<M> {
type State = MenuHandleState<V, M>; type State = MenuHandleState<M>;
fn layout( fn layout(
&mut self, &mut self,
view_state: &mut V,
element_state: Option<Self::State>, element_state: Option<Self::State>,
cx: &mut crate::ViewContext<V>, cx: &mut WindowContext,
) -> (gpui::LayoutId, Self::State) { ) -> (gpui::LayoutId, Self::State) {
let (menu, position) = if let Some(element_state) = element_state { let (menu, position) = if let Some(element_state) = element_state {
(element_state.menu, element_state.position) (element_state.menu, element_state.position)
@ -197,14 +193,14 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
let mut menu_layout_id = None; let mut menu_layout_id = None;
let menu_element = menu.borrow_mut().as_mut().map(|menu| { let menu_element = menu.borrow_mut().as_mut().map(|menu| {
let mut overlay = overlay::<V>().snap_to_window(); let mut overlay = overlay().snap_to_window();
if let Some(anchor) = self.anchor { if let Some(anchor) = self.anchor {
overlay = overlay.anchor(anchor); overlay = overlay.anchor(anchor);
} }
overlay = overlay.position(*position.borrow()); overlay = overlay.position(*position.borrow());
let mut element = overlay.child(menu.clone()).into_any(); let mut element = overlay.child(menu.clone()).into_any();
menu_layout_id = Some(element.layout(view_state, cx)); menu_layout_id = Some(element.layout(cx));
element element
}); });
@ -215,7 +211,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
let child_layout_id = child_element let child_layout_id = child_element
.as_mut() .as_mut()
.map(|child_element| child_element.layout(view_state, cx)); .map(|child_element| child_element.layout(cx));
let layout_id = cx.request_layout( let layout_id = cx.request_layout(
&gpui::Style::default(), &gpui::Style::default(),
@ -237,16 +233,15 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
fn paint( fn paint(
self, self,
bounds: Bounds<gpui::Pixels>, bounds: Bounds<gpui::Pixels>,
view_state: &mut V,
element_state: &mut Self::State, element_state: &mut Self::State,
cx: &mut crate::ViewContext<V>, cx: &mut WindowContext,
) { ) {
if let Some(child) = element_state.child_element.take() { if let Some(child) = element_state.child_element.take() {
child.paint(view_state, cx); child.paint(cx);
} }
if let Some(menu) = element_state.menu_element.take() { if let Some(menu) = element_state.menu_element.take() {
menu.paint(view_state, cx); menu.paint(cx);
return; return;
} }
@ -258,7 +253,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
let attach = self.attach.clone(); let attach = self.attach.clone();
let child_layout_id = element_state.child_layout_id.clone(); let child_layout_id = element_state.child_layout_id.clone();
cx.on_mouse_event(move |view_state, event: &MouseDownEvent, phase, cx| { cx.on_mouse_event(move |event: &MouseDownEvent, phase, cx| {
if phase == DispatchPhase::Bubble if phase == DispatchPhase::Bubble
&& event.button == MouseButton::Right && event.button == MouseButton::Right
&& bounds.contains_point(&event.position) && bounds.contains_point(&event.position)
@ -266,9 +261,9 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
cx.stop_propagation(); cx.stop_propagation();
cx.prevent_default(); cx.prevent_default();
let new_menu = (builder)(view_state, cx); let new_menu = (builder)(cx);
let menu2 = menu.clone(); let menu2 = menu.clone();
cx.subscribe(&new_menu, move |this, modal, e, cx| match e { cx.subscribe(&new_menu, move |modal, e, cx| match e {
&Manager::Dismiss => { &Manager::Dismiss => {
*menu2.borrow_mut() = None; *menu2.borrow_mut() = None;
cx.notify(); cx.notify();
@ -291,7 +286,7 @@ impl<V: 'static, M: ManagedView> Element<V> for MenuHandle<V, M> {
} }
} }
impl<V: 'static, M: ManagedView> RenderOnce<V> for MenuHandle<V, M> { impl<M: ManagedView> RenderOnce for MenuHandle<M> {
type Element = Self; type Element = Self;
fn element_id(&self) -> Option<gpui::ElementId> { fn element_id(&self) -> Option<gpui::ElementId> {
@ -314,11 +309,10 @@ mod stories {
actions!(PrintCurrentDate, PrintBestFood); actions!(PrintCurrentDate, PrintBestFood);
fn build_menu<V: Render<V>>( fn build_menu<V: Render>(
cx: &mut ViewContext<V>, cx: &mut WindowContext,
header: impl Into<SharedString>, header: impl Into<SharedString>,
) -> View<ContextMenu<V>> { ) -> View<ContextMenu> {
let handle = cx.view().clone();
ContextMenu::build(cx, |menu, _| { ContextMenu::build(cx, |menu, _| {
menu.header(header) menu.header(header)
.separator() .separator()
@ -334,8 +328,8 @@ mod stories {
pub struct ContextMenuStory; pub struct ContextMenuStory;
impl Render<Self> for ContextMenuStory { impl Render for ContextMenuStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -2,16 +2,16 @@ use crate::prelude::*;
use crate::{v_stack, ButtonGroup}; use crate::{v_stack, ButtonGroup};
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Details<V: 'static> { pub struct Details {
text: &'static str, text: &'static str,
meta: Option<&'static str>, meta: Option<&'static str>,
actions: Option<ButtonGroup<V>>, actions: Option<ButtonGroup>,
} }
impl<V: 'static> Component<V> for Details<V> { impl Component for Details {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
v_stack() v_stack()
.p_1() .p_1()
.gap_0p5() .gap_0p5()
@ -24,7 +24,7 @@ impl<V: 'static> Component<V> for Details<V> {
} }
} }
impl<V: 'static> Details<V> { impl Details {
pub fn new(text: &'static str) -> Self { pub fn new(text: &'static str) -> Self {
Self { Self {
text, text,
@ -38,7 +38,7 @@ impl<V: 'static> Details<V> {
self self
} }
pub fn actions(mut self, actions: ButtonGroup<V>) -> Self { pub fn actions(mut self, actions: ButtonGroup) -> Self {
self.actions = Some(actions); self.actions = Some(actions);
self self
} }
@ -56,8 +56,8 @@ mod stories {
pub struct DetailsStory; pub struct DetailsStory;
impl Render<Self> for DetailsStory { impl Render for DetailsStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -13,10 +13,10 @@ pub struct Divider {
inset: bool, inset: bool,
} }
impl<V: 'static> Component<V> for Divider { impl Component for Divider {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.map(|this| match self.direction { .map(|this| match self.direction {
DividerDirection::Horizontal => { DividerDirection::Horizontal => {
@ -50,7 +50,7 @@ impl Divider {
self self
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
div() div()
.map(|this| match self.direction { .map(|this| match self.direction {
DividerDirection::Horizontal => { DividerDirection::Horizontal => {

View file

@ -5,7 +5,7 @@ use crate::{prelude::*, v_stack};
/// Create an elevated surface. /// Create an elevated surface.
/// ///
/// Must be used inside of a relative parent element /// 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(level: ElevationIndex, cx: &mut WindowContext) -> Div {
let colors = cx.theme().colors(); let colors = cx.theme().colors();
// let shadow = BoxShadow { // let shadow = BoxShadow {
@ -23,6 +23,6 @@ pub fn elevated_surface<V: 'static>(level: ElevationIndex, cx: &mut ViewContext<
.shadow(level.shadow()) .shadow(level.shadow())
} }
pub fn modal<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> { pub fn modal(cx: &mut WindowContext) -> Div {
elevated_surface(ElevationIndex::ModalSurface, cx) elevated_surface(ElevationIndex::ModalSurface, cx)
} }

View file

@ -6,10 +6,10 @@ pub struct Facepile {
players: Vec<Player>, players: Vec<Player>,
} }
impl<V: 'static> Component<V> for Facepile { impl Component for Facepile {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let player_count = self.players.len(); let player_count = self.players.len();
let player_list = self.players.iter().enumerate().map(|(ix, player)| { let player_list = self.players.iter().enumerate().map(|(ix, player)| {
let isnt_last = ix < player_count - 1; let isnt_last = ix < player_count - 1;
@ -42,8 +42,8 @@ mod stories {
pub struct FacepileStory; pub struct FacepileStory;
impl Render<Self> for FacepileStory { impl Render for FacepileStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let players = static_players(); let players = static_players();

View file

@ -136,10 +136,10 @@ pub struct IconElement {
size: IconSize, size: IconSize,
} }
impl<V: 'static> Component<V> for IconElement { impl Component for IconElement {
type Rendered = Svg<V>; type Rendered = Svg;
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let svg_size = match self.size { let svg_size = match self.size {
IconSize::Small => rems(0.75), IconSize::Small => rems(0.75),
IconSize::Medium => rems(0.9375), IconSize::Medium => rems(0.9375),
@ -180,7 +180,7 @@ impl IconElement {
self self
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
let svg_size = match self.size { let svg_size = match self.size {
IconSize::Small => rems(0.75), IconSize::Small => rems(0.75),
IconSize::Medium => rems(0.9375), IconSize::Medium => rems(0.9375),
@ -208,8 +208,8 @@ mod stories {
pub struct IconStory; pub struct IconStory;
impl Render<Self> for IconStory { impl Render for IconStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let icons = Icon::iter(); let icons = Icon::iter();

View file

@ -1,33 +1,22 @@
use crate::{h_stack, prelude::*, ClickHandler, Icon, IconElement}; use crate::{h_stack, prelude::*, Icon, IconElement};
use gpui::{prelude::*, Action, AnyView, Div, MouseButton, Stateful}; use gpui::{prelude::*, Action, AnyView, Div, MouseButton, MouseDownEvent, Stateful};
use std::sync::Arc;
struct IconButtonHandlers<V: 'static> {
click: Option<ClickHandler<V>>,
}
impl<V: 'static> Default for IconButtonHandlers<V> {
fn default() -> Self {
Self { click: None }
}
}
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct IconButton<V: 'static> { pub struct IconButton {
id: ElementId, id: ElementId,
icon: Icon, icon: Icon,
color: TextColor, color: TextColor,
variant: ButtonVariant, variant: ButtonVariant,
state: InteractionState, state: InteractionState,
selected: bool, selected: bool,
tooltip: Option<Box<dyn Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static>>, tooltip: Option<Box<dyn Fn(&mut WindowContext) -> AnyView + 'static>>,
handlers: IconButtonHandlers<V>, on_mouse_down: Option<Box<dyn Fn(&MouseDownEvent, &mut WindowContext) + 'static>>,
} }
impl<V: 'static> Component<V> for IconButton<V> { impl Component for IconButton {
type Rendered = Stateful<V, Div<V>>; type Rendered = Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let icon_color = match (self.state, self.color) { let icon_color = match (self.state, self.color) {
(InteractionState::Disabled, _) => TextColor::Disabled, (InteractionState::Disabled, _) => TextColor::Disabled,
(InteractionState::Active, _) => TextColor::Selected, (InteractionState::Active, _) => TextColor::Selected,
@ -65,16 +54,16 @@ impl<V: 'static> Component<V> for IconButton<V> {
.active(|style| style.bg(bg_active_color)) .active(|style| style.bg(bg_active_color))
.child(IconElement::new(self.icon).color(icon_color)); .child(IconElement::new(self.icon).color(icon_color));
if let Some(click_handler) = self.handlers.click.clone() { if let Some(click_handler) = self.on_mouse_down {
button = button.on_mouse_down(MouseButton::Left, move |state, event, cx| { button = button.on_mouse_down(MouseButton::Left, move |event, cx| {
cx.stop_propagation(); cx.stop_propagation();
click_handler(state, cx); click_handler(event, cx);
}) })
} }
if let Some(tooltip) = self.tooltip { if let Some(tooltip) = self.tooltip {
if !self.selected { if !self.selected {
button = button.tooltip(move |view: &mut V, cx| (tooltip)(view, cx)) button = button.tooltip(move |cx| tooltip(cx))
} }
} }
@ -82,7 +71,7 @@ impl<V: 'static> Component<V> for IconButton<V> {
} }
} }
impl<V: 'static> IconButton<V> { impl IconButton {
pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self { pub fn new(id: impl Into<ElementId>, icon: Icon) -> Self {
Self { Self {
id: id.into(), id: id.into(),
@ -92,7 +81,7 @@ impl<V: 'static> IconButton<V> {
state: InteractionState::default(), state: InteractionState::default(),
selected: false, selected: false,
tooltip: None, tooltip: None,
handlers: IconButtonHandlers::default(), on_mouse_down: None,
} }
} }
@ -121,16 +110,16 @@ impl<V: 'static> IconButton<V> {
self self
} }
pub fn tooltip( pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
mut self,
tooltip: impl Fn(&mut V, &mut ViewContext<V>) -> AnyView + 'static,
) -> Self {
self.tooltip = Some(Box::new(tooltip)); self.tooltip = Some(Box::new(tooltip));
self self
} }
pub fn on_click(mut self, handler: impl 'static + Fn(&mut V, &mut ViewContext<V>)) -> Self { pub fn on_click(
self.handlers.click = Some(Arc::new(handler)); mut self,
handler: impl 'static + Fn(&MouseDownEvent, &mut WindowContext),
) -> Self {
self.on_mouse_down = Some(Box::new(handler));
self self
} }

View file

@ -4,10 +4,10 @@ use gpui::{px, Div, RenderOnce};
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct UnreadIndicator; pub struct UnreadIndicator;
impl<V: 'static> Component<V> for UnreadIndicator { impl Component for UnreadIndicator {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.rounded_full() .rounded_full()
.border_2() .border_2()
@ -24,7 +24,7 @@ impl UnreadIndicator {
Self Self
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
div() div()
.rounded_full() .rounded_full()
.border_2() .border_2()

View file

@ -18,10 +18,10 @@ pub struct Input {
is_active: bool, is_active: bool,
} }
impl<V: 'static> Component<V> for Input { impl Component for Input {
type Rendered = Stateful<V, Div<V>>; type Rendered = Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let (input_bg, input_hover_bg, input_active_bg) = match self.variant { let (input_bg, input_hover_bg, input_active_bg) = match self.variant {
InputVariant::Ghost => ( InputVariant::Ghost => (
cx.theme().colors().ghost_element_background, cx.theme().colors().ghost_element_background,
@ -118,8 +118,8 @@ mod stories {
pub struct InputStory; pub struct InputStory;
impl Render<Self> for InputStory { impl Render for InputStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -10,10 +10,10 @@ pub struct KeyBinding {
key_binding: gpui::KeyBinding, key_binding: gpui::KeyBinding,
} }
impl<V: 'static> Component<V> for KeyBinding { impl Component for KeyBinding {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.flex() .flex()
.gap_2() .gap_2()
@ -49,11 +49,10 @@ pub struct Key {
key: SharedString, key: SharedString,
} }
impl<V: 'static> Component<V> for Key { impl Component for Key {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let _view: &mut V = view;
div() div()
.px_2() .px_2()
.py_0() .py_0()
@ -89,8 +88,8 @@ mod stories {
gpui::KeyBinding::new(key, NoAction {}, None) gpui::KeyBinding::new(key, NoAction {}, None)
} }
impl Render<Self> for KeybindingStory { impl Render for KeybindingStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let all_modifier_permutations = let all_modifier_permutations =

View file

@ -68,10 +68,10 @@ pub struct Label {
strikethrough: bool, strikethrough: bool,
} }
impl<V: 'static> Component<V> for Label { impl Component for Label {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.when(self.strikethrough, |this| { .when(self.strikethrough, |this| {
this.relative().child( this.relative().child(
@ -136,10 +136,10 @@ pub struct HighlightedLabel {
strikethrough: bool, strikethrough: bool,
} }
impl<V: 'static> Component<V> for HighlightedLabel { impl Component for HighlightedLabel {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let highlight_color = cx.theme().colors().text_accent; let highlight_color = cx.theme().colors().text_accent;
let mut text_style = cx.text_style().clone(); let mut text_style = cx.text_style().clone();
@ -242,8 +242,8 @@ mod stories {
pub struct LabelStory; pub struct LabelStory;
impl Render<Self> for LabelStory { impl Render for LabelStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -1,4 +1,4 @@
use gpui::{div, Div, RenderOnce, Stateful, StatefulInteractiveElement}; use gpui::{div, ClickEvent, Div, RenderOnce, Stateful, StatefulInteractiveElement};
use std::rc::Rc; use std::rc::Rc;
use crate::settings::user_settings; use crate::settings::user_settings;
@ -32,10 +32,10 @@ pub struct ListHeader {
toggle: Toggle, toggle: Toggle,
} }
impl<V: 'static> Component<V> for ListHeader { impl Component for ListHeader {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let disclosure_control = disclosure_control(self.toggle); let disclosure_control = disclosure_control(self.toggle);
let meta = match self.meta { let meta = match self.meta {
@ -198,7 +198,7 @@ impl ListSubHeader {
self self
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
h_stack().flex_1().w_full().relative().py_1().child( h_stack().flex_1().w_full().relative().py_1().child(
div() div()
.h_6() .h_6()
@ -233,36 +233,36 @@ pub enum ListEntrySize {
} }
#[derive(Clone)] #[derive(Clone)]
pub enum ListItem<V: 'static> { pub enum ListItem {
Entry(ListEntry<V>), Entry(ListEntry),
Separator(ListSeparator), Separator(ListSeparator),
Header(ListSubHeader), Header(ListSubHeader),
} }
impl<V: 'static> From<ListEntry<V>> for ListItem<V> { impl From<ListEntry> for ListItem {
fn from(entry: ListEntry<V>) -> Self { fn from(entry: ListEntry) -> Self {
Self::Entry(entry) Self::Entry(entry)
} }
} }
impl<V: 'static> From<ListSeparator> for ListItem<V> { impl From<ListSeparator> for ListItem {
fn from(entry: ListSeparator) -> Self { fn from(entry: ListSeparator) -> Self {
Self::Separator(entry) Self::Separator(entry)
} }
} }
impl<V: 'static> From<ListSubHeader> for ListItem<V> { impl From<ListSubHeader> for ListItem {
fn from(entry: ListSubHeader) -> Self { fn from(entry: ListSubHeader) -> Self {
Self::Header(entry) Self::Header(entry)
} }
} }
impl<V: 'static> ListItem<V> { impl ListItem {
pub fn new(label: Label) -> Self { pub fn new(label: Label) -> Self {
Self::Entry(ListEntry::new(label)) Self::Entry(ListEntry::new(label))
} }
pub fn as_entry(&mut self) -> Option<&mut ListEntry<V>> { pub fn as_entry(&mut self) -> Option<&mut ListEntry> {
if let Self::Entry(entry) = self { if let Self::Entry(entry) = self {
Some(entry) Some(entry)
} else { } else {
@ -270,17 +270,17 @@ impl<V: 'static> ListItem<V> {
} }
} }
fn render(self, view: &mut V, ix: usize, cx: &mut ViewContext<V>) -> Div<V> { fn render(self, ix: usize, cx: &mut WindowContext) -> Div {
match self { match self {
ListItem::Entry(entry) => div().child(entry.render(ix, cx)), ListItem::Entry(entry) => div().child(entry.render(ix, cx)),
ListItem::Separator(separator) => div().child(separator.render(view, cx)), ListItem::Separator(separator) => div().child(separator.render(cx)),
ListItem::Header(header) => div().child(header.render(view, cx)), ListItem::Header(header) => div().child(header.render(cx)),
} }
} }
} }
// #[derive(RenderOnce)] // #[derive(RenderOnce)]
pub struct ListEntry<V> { pub struct ListEntry {
disabled: bool, disabled: bool,
// TODO: Reintroduce this // TODO: Reintroduce this
// disclosure_control_style: DisclosureControlVisibility, // disclosure_control_style: DisclosureControlVisibility,
@ -291,10 +291,10 @@ pub struct ListEntry<V> {
size: ListEntrySize, size: ListEntrySize,
toggle: Toggle, toggle: Toggle,
variant: ListItemVariant, variant: ListItemVariant,
on_click: Option<Rc<dyn Fn(&mut V, &mut ViewContext<V>) + 'static>>, on_click: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
} }
impl<V> Clone for ListEntry<V> { impl Clone for ListEntry {
fn clone(&self) -> Self { fn clone(&self) -> Self {
Self { Self {
disabled: self.disabled, disabled: self.disabled,
@ -310,7 +310,7 @@ impl<V> Clone for ListEntry<V> {
} }
} }
impl<V: 'static> ListEntry<V> { impl ListEntry {
pub fn new(label: Label) -> Self { pub fn new(label: Label) -> Self {
Self { Self {
disabled: false, disabled: false,
@ -325,7 +325,7 @@ impl<V: 'static> ListEntry<V> {
} }
} }
pub fn on_click(mut self, handler: impl Fn(&mut V, &mut ViewContext<V>) + 'static) -> Self { pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
self.on_click = Some(Rc::new(handler)); self.on_click = Some(Rc::new(handler));
self self
} }
@ -365,7 +365,7 @@ impl<V: 'static> ListEntry<V> {
self self
} }
fn render(self, ix: usize, cx: &mut ViewContext<V>) -> Stateful<V, Div<V>> { fn render(self, ix: usize, cx: &mut WindowContext) -> Stateful<Div> {
let settings = user_settings(cx); let settings = user_settings(cx);
let left_content = match self.left_slot.clone() { let left_content = match self.left_slot.clone() {
@ -392,13 +392,11 @@ impl<V: 'static> ListEntry<V> {
style.background = Some(cx.theme().colors().editor_background.into()); style.background = Some(cx.theme().colors().editor_background.into());
style style
}) })
.on_click({ .map(|div| {
let on_click = self.on_click.clone(); if let Some(on_click) = self.on_click.clone() {
div.on_click(move |e, cx| on_click(e, cx))
move |view: &mut V, event, cx| { } else {
if let Some(on_click) = &on_click { div
(on_click)(view, cx)
}
} }
}) })
.bg(cx.theme().colors().surface_background) .bg(cx.theme().colors().surface_background)
@ -444,17 +442,17 @@ impl ListSeparator {
} }
} }
impl<V: 'static> Component<V> for ListSeparator { impl Component for ListSeparator {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().h_px().w_full().bg(cx.theme().colors().border_variant) div().h_px().w_full().bg(cx.theme().colors().border_variant)
} }
} }
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct List<V: 'static> { pub struct List {
items: Vec<ListItem<V>>, items: Vec<ListItem>,
/// Message to display when the list is empty /// Message to display when the list is empty
/// Defaults to "No items" /// Defaults to "No items"
empty_message: SharedString, empty_message: SharedString,
@ -462,16 +460,16 @@ pub struct List<V: 'static> {
toggle: Toggle, toggle: Toggle,
} }
impl<V: 'static> Component<V> for List<V> { impl Component for List {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let list_content = match (self.items.is_empty(), self.toggle) { let list_content = match (self.items.is_empty(), self.toggle) {
(false, _) => div().children( (false, _) => div().children(
self.items self.items
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(ix, item)| item.render(view, ix, cx)), .map(|(ix, item)| item.render(ix, cx)),
), ),
(true, Toggle::Toggled(false)) => div(), (true, Toggle::Toggled(false)) => div(),
(true, _) => { (true, _) => {
@ -487,8 +485,8 @@ impl<V: 'static> Component<V> for List<V> {
} }
} }
impl<V: 'static> List<V> { impl List {
pub fn new(items: Vec<ListItem<V>>) -> Self { pub fn new(items: Vec<ListItem>) -> Self {
Self { Self {
items, items,
empty_message: "No items".into(), empty_message: "No items".into(),
@ -512,13 +510,13 @@ impl<V: 'static> List<V> {
self self
} }
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
let list_content = match (self.items.is_empty(), self.toggle) { let list_content = match (self.items.is_empty(), self.toggle) {
(false, _) => div().children( (false, _) => div().children(
self.items self.items
.into_iter() .into_iter()
.enumerate() .enumerate()
.map(|(ix, item)| item.render(view, ix, cx)), .map(|(ix, item)| item.render(ix, cx)),
), ),
(true, Toggle::Toggled(false)) => div(), (true, Toggle::Toggled(false)) => div(),
(true, _) => { (true, _) => {

View file

@ -1,22 +1,21 @@
use gpui::{AnyElement, Div, RenderOnce, Stateful}; use gpui::{AnyElement, Div, RenderOnce};
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label}; use crate::{h_stack, prelude::*, v_stack, Button, Icon, IconButton, Label};
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Modal<V: 'static> { pub struct Modal {
id: ElementId, id: ElementId,
title: Option<SharedString>, title: Option<SharedString>,
primary_action: Option<Button<V>>, primary_action: Option<Button>,
secondary_action: Option<Button<V>>, secondary_action: Option<Button>,
children: SmallVec<[AnyElement<V>; 2]>, children: SmallVec<[AnyElement; 2]>,
} }
impl<V: 'static> Component<V> for Modal<V> { impl Component for Modal {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let _view: &mut V = view;
v_stack() v_stack()
.id(self.id.clone()) .id(self.id.clone())
.w_96() .w_96()
@ -52,7 +51,7 @@ impl<V: 'static> Component<V> for Modal<V> {
} }
} }
impl<V: 'static> Modal<V> { impl Modal {
pub fn new(id: impl Into<ElementId>) -> Self { pub fn new(id: impl Into<ElementId>) -> Self {
Self { Self {
id: id.into(), id: id.into(),
@ -68,19 +67,19 @@ impl<V: 'static> Modal<V> {
self self
} }
pub fn primary_action(mut self, action: Button<V>) -> Self { pub fn primary_action(mut self, action: Button) -> Self {
self.primary_action = Some(action); self.primary_action = Some(action);
self self
} }
pub fn secondary_action(mut self, action: Button<V>) -> Self { pub fn secondary_action(mut self, action: Button) -> Self {
self.secondary_action = Some(action); self.secondary_action = Some(action);
self self
} }
} }
impl<V: 'static> ParentElement<V> for Modal<V> { impl ParentElement for Modal {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children &mut self.children
} }
} }

View file

@ -22,7 +22,7 @@ impl NotificationToast {
self self
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
h_stack() h_stack()
.z_index(5) .z_index(5)
.absolute() .absolute()

View file

@ -1,7 +1,6 @@
use crate::{h_stack, prelude::*, v_stack, KeyBinding, Label}; use crate::{h_stack, prelude::*, v_stack, KeyBinding, Label};
use gpui::prelude::*; use gpui::prelude::*;
use gpui::Div; use gpui::Div;
use gpui::Stateful;
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Palette { pub struct Palette {
@ -12,10 +11,10 @@ pub struct Palette {
default_order: OrderMethod, default_order: OrderMethod,
} }
impl<V: 'static> Component<V> for Palette { impl Component for Palette {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
v_stack() v_stack()
.id(self.id) .id(self.id)
.w_96() .w_96()
@ -116,10 +115,10 @@ pub struct PaletteItem {
pub key_binding: Option<KeyBinding>, pub key_binding: Option<KeyBinding>,
} }
impl<V: 'static> Component<V> for PaletteItem { impl Component for PaletteItem {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.flex() .flex()
.flex_row() .flex_row()
@ -173,8 +172,8 @@ mod stories {
pub struct PaletteStory; pub struct PaletteStory;
impl Render<Self> for PaletteStory { impl Render for PaletteStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
{ {

View file

@ -1,4 +1,4 @@
use gpui::{prelude::*, AbsoluteLength, AnyElement, Div, RenderOnce, Stateful}; use gpui::{prelude::*, AbsoluteLength, AnyElement, Div, RenderOnce};
use smallvec::SmallVec; use smallvec::SmallVec;
use crate::prelude::*; use crate::prelude::*;
@ -39,20 +39,20 @@ pub enum PanelSide {
use std::collections::HashSet; use std::collections::HashSet;
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Panel<V: 'static> { pub struct Panel {
id: ElementId, id: ElementId,
current_side: PanelSide, current_side: PanelSide,
/// Defaults to PanelAllowedSides::LeftAndRight /// Defaults to PanelAllowedSides::LeftAndRight
allowed_sides: PanelAllowedSides, allowed_sides: PanelAllowedSides,
initial_width: AbsoluteLength, initial_width: AbsoluteLength,
width: Option<AbsoluteLength>, width: Option<AbsoluteLength>,
children: SmallVec<[AnyElement<V>; 2]>, children: SmallVec<[AnyElement; 2]>,
} }
impl<V: 'static> Component<V> for Panel<V> { impl Component for Panel {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let current_size = self.width.unwrap_or(self.initial_width); let current_size = self.width.unwrap_or(self.initial_width);
v_stack() v_stack()
@ -73,7 +73,7 @@ impl<V: 'static> Component<V> for Panel<V> {
} }
} }
impl<V: 'static> Panel<V> { impl Panel {
pub fn new(id: impl Into<ElementId>, cx: &mut WindowContext) -> Self { pub fn new(id: impl Into<ElementId>, cx: &mut WindowContext) -> Self {
let settings = user_settings(cx); let settings = user_settings(cx);
@ -117,8 +117,8 @@ impl<V: 'static> Panel<V> {
} }
} }
impl<V: 'static> ParentElement<V> for Panel<V> { impl ParentElement for Panel {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children &mut self.children
} }
} }
@ -134,12 +134,12 @@ mod stories {
pub struct PanelStory; pub struct PanelStory;
impl Render<Self> for PanelStory { impl Render for PanelStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, Panel<Self>>(cx)) .child(Story::title_for::<Panel<Self>>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child( .child(
Panel::new("panel", cx).child( Panel::new("panel", cx).child(

View file

@ -1,4 +1,4 @@
use gpui::{Hsla, ViewContext}; use gpui::Hsla;
use crate::prelude::*; use crate::prelude::*;
@ -156,11 +156,11 @@ impl Player {
self self
} }
pub fn cursor_color<V: 'static>(&self, cx: &mut ViewContext<V>) -> Hsla { pub fn cursor_color(&self, cx: &mut WindowContext) -> Hsla {
cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].cursor cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].cursor
} }
pub fn selection_color<V: 'static>(&self, cx: &mut ViewContext<V>) -> Hsla { pub fn selection_color(&self, cx: &mut WindowContext) -> Hsla {
cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].selection cx.theme().styles.player.0[self.index % cx.theme().styles.player.0.len()].selection
} }

View file

@ -8,10 +8,10 @@ pub struct PlayerStack {
player_with_call_status: PlayerWithCallStatus, player_with_call_status: PlayerWithCallStatus,
} }
impl<V: 'static> Component<V> for PlayerStack { impl Component for PlayerStack {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let player = self.player_with_call_status.get_player(); let player = self.player_with_call_status.get_player();
let followers = self let followers = self

View file

@ -5,13 +5,13 @@ use crate::StyledExt;
/// Horizontally stacks elements. /// Horizontally stacks elements.
/// ///
/// Sets `flex()`, `flex_row()`, `items_center()` /// Sets `flex()`, `flex_row()`, `items_center()`
pub fn h_stack<V: 'static>() -> Div<V> { pub fn h_stack() -> Div {
div().h_flex() div().h_flex()
} }
/// Vertically stacks elements. /// Vertically stacks elements.
/// ///
/// Sets `flex()`, `flex_col()` /// Sets `flex()`, `flex_col()`
pub fn v_stack<V: 'static>() -> Div<V> { pub fn v_stack() -> Div {
div().v_flex() div().v_flex()
} }

View file

@ -1,276 +1,276 @@
use crate::prelude::*; // use crate::prelude::*;
use crate::{Icon, IconElement, Label, TextColor}; // use crate::{Icon, IconElement, Label, TextColor};
use gpui::{prelude::*, red, Div, ElementId, Render, RenderOnce, Stateful, View}; // use gpui::{prelude::*, red, Div, ElementId, Render, RenderOnce, View};
#[derive(RenderOnce, Clone)] // #[derive(RenderOnce, Clone)]
pub struct Tab { // pub struct Tab {
id: ElementId, // id: ElementId,
title: String, // title: String,
icon: Option<Icon>, // icon: Option<Icon>,
current: bool, // current: bool,
dirty: bool, // dirty: bool,
fs_status: FileSystemStatus, // fs_status: FileSystemStatus,
git_status: GitStatus, // git_status: GitStatus,
diagnostic_status: DiagnosticStatus, // diagnostic_status: DiagnosticStatus,
close_side: IconSide, // close_side: IconSide,
} // }
#[derive(Clone, Debug)] // #[derive(Clone, Debug)]
struct TabDragState { // struct TabDragState {
title: String, // title: String,
} // }
impl Render<Self> for TabDragState { // impl Render for TabDragState {
type Element = Div<Self>; // type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { // fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div().w_8().h_4().bg(red()) // div().w_8().h_4().bg(red())
} // }
} // }
impl<V: 'static> Component<V> for Tab { // impl Component for Tab {
type Rendered = Stateful<V, Div<V>>; // type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { // fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict; // let has_fs_conflict = self.fs_status == FileSystemStatus::Conflict;
let is_deleted = self.fs_status == FileSystemStatus::Deleted; // let is_deleted = self.fs_status == FileSystemStatus::Deleted;
let label = match (self.git_status, is_deleted) { // let label = match (self.git_status, is_deleted) {
(_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone()) // (_, true) | (GitStatus::Deleted, false) => Label::new(self.title.clone())
.color(TextColor::Hidden) // .color(TextColor::Hidden)
.set_strikethrough(true), // .set_strikethrough(true),
(GitStatus::None, false) => Label::new(self.title.clone()), // (GitStatus::None, false) => Label::new(self.title.clone()),
(GitStatus::Created, false) => Label::new(self.title.clone()).color(TextColor::Created), // (GitStatus::Created, false) => Label::new(self.title.clone()).color(TextColor::Created),
(GitStatus::Modified, false) => { // (GitStatus::Modified, false) => {
Label::new(self.title.clone()).color(TextColor::Modified) // Label::new(self.title.clone()).color(TextColor::Modified)
} // }
(GitStatus::Renamed, false) => Label::new(self.title.clone()).color(TextColor::Accent), // (GitStatus::Renamed, false) => Label::new(self.title.clone()).color(TextColor::Accent),
(GitStatus::Conflict, false) => Label::new(self.title.clone()), // (GitStatus::Conflict, false) => Label::new(self.title.clone()),
}; // };
let close_icon = || IconElement::new(Icon::Close).color(TextColor::Muted); // let close_icon = || IconElement::new(Icon::Close).color(TextColor::Muted);
let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current { // let (tab_bg, tab_hover_bg, tab_active_bg) = match self.current {
false => ( // false => (
cx.theme().colors().tab_inactive_background, // cx.theme().colors().tab_inactive_background,
cx.theme().colors().ghost_element_hover, // cx.theme().colors().ghost_element_hover,
cx.theme().colors().ghost_element_active, // cx.theme().colors().ghost_element_active,
), // ),
true => ( // true => (
cx.theme().colors().tab_active_background, // cx.theme().colors().tab_active_background,
cx.theme().colors().element_hover, // cx.theme().colors().element_hover,
cx.theme().colors().element_active, // cx.theme().colors().element_active,
), // ),
}; // };
let drag_state = TabDragState { // let drag_state = TabDragState {
title: self.title.clone(), // title: self.title.clone(),
}; // };
div() // div()
.id(self.id.clone()) // .id(self.id.clone())
.on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone())) // .on_drag(move |_view, cx| cx.build_view(|cx| drag_state.clone()))
.drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background)) // .drag_over::<TabDragState>(|d| d.bg(cx.theme().colors().drop_target_background))
.on_drop(|_view, state: View<TabDragState>, cx| { // .on_drop(|_view, state: View<TabDragState>, cx| {
eprintln!("{:?}", state.read(cx)); // eprintln!("{:?}", state.read(cx));
}) // })
.px_2() // .px_2()
.py_0p5() // .py_0p5()
.flex() // .flex()
.items_center() // .items_center()
.justify_center() // .justify_center()
.bg(tab_bg) // .bg(tab_bg)
.hover(|h| h.bg(tab_hover_bg)) // .hover(|h| h.bg(tab_hover_bg))
.active(|a| a.bg(tab_active_bg)) // .active(|a| a.bg(tab_active_bg))
.child( // .child(
div() // div()
.px_1() // .px_1()
.flex() // .flex()
.items_center() // .items_center()
.gap_1p5() // .gap_1p5()
.children(has_fs_conflict.then(|| { // .children(has_fs_conflict.then(|| {
IconElement::new(Icon::ExclamationTriangle) // IconElement::new(Icon::ExclamationTriangle)
.size(crate::IconSize::Small) // .size(crate::IconSize::Small)
.color(TextColor::Warning) // .color(TextColor::Warning)
})) // }))
.children(self.icon.map(IconElement::new)) // .children(self.icon.map(IconElement::new))
.children(if self.close_side == IconSide::Left { // .children(if self.close_side == IconSide::Left {
Some(close_icon()) // Some(close_icon())
} else { // } else {
None // None
}) // })
.child(label) // .child(label)
.children(if self.close_side == IconSide::Right { // .children(if self.close_side == IconSide::Right {
Some(close_icon()) // Some(close_icon())
} else { // } else {
None // None
}), // }),
) // )
} // }
} // }
impl Tab { // impl Tab {
pub fn new(id: impl Into<ElementId>) -> Self { // pub fn new(id: impl Into<ElementId>) -> Self {
Self { // Self {
id: id.into(), // id: id.into(),
title: "untitled".to_string(), // title: "untitled".to_string(),
icon: None, // icon: None,
current: false, // current: false,
dirty: false, // dirty: false,
fs_status: FileSystemStatus::None, // fs_status: FileSystemStatus::None,
git_status: GitStatus::None, // git_status: GitStatus::None,
diagnostic_status: DiagnosticStatus::None, // diagnostic_status: DiagnosticStatus::None,
close_side: IconSide::Right, // close_side: IconSide::Right,
} // }
} // }
pub fn current(mut self, current: bool) -> Self { // pub fn current(mut self, current: bool) -> Self {
self.current = current; // self.current = current;
self // self
} // }
pub fn title(mut self, title: String) -> Self { // pub fn title(mut self, title: String) -> Self {
self.title = title; // self.title = title;
self // self
} // }
pub fn icon<I>(mut self, icon: I) -> Self // pub fn icon<I>(mut self, icon: I) -> Self
where // where
I: Into<Option<Icon>>, // I: Into<Option<Icon>>,
{ // {
self.icon = icon.into(); // self.icon = icon.into();
self // self
} // }
pub fn dirty(mut self, dirty: bool) -> Self { // pub fn dirty(mut self, dirty: bool) -> Self {
self.dirty = dirty; // self.dirty = dirty;
self // self
} // }
pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self { // pub fn fs_status(mut self, fs_status: FileSystemStatus) -> Self {
self.fs_status = fs_status; // self.fs_status = fs_status;
self // self
} // }
pub fn git_status(mut self, git_status: GitStatus) -> Self { // pub fn git_status(mut self, git_status: GitStatus) -> Self {
self.git_status = git_status; // self.git_status = git_status;
self // self
} // }
pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self { // pub fn diagnostic_status(mut self, diagnostic_status: DiagnosticStatus) -> Self {
self.diagnostic_status = diagnostic_status; // self.diagnostic_status = diagnostic_status;
self // self
} // }
pub fn close_side(mut self, close_side: IconSide) -> Self { // pub fn close_side(mut self, close_side: IconSide) -> Self {
self.close_side = close_side; // self.close_side = close_side;
self // self
} // }
} // }
#[cfg(feature = "stories")] // #[cfg(feature = "stories")]
pub use stories::*; // pub use stories::*;
#[cfg(feature = "stories")] // #[cfg(feature = "stories")]
mod stories { // mod stories {
use super::*; // use super::*;
use crate::{h_stack, v_stack, Icon, Story}; // use crate::{h_stack, v_stack, Icon, Story};
use strum::IntoEnumIterator; // use strum::IntoEnumIterator;
pub struct TabStory; // pub struct TabStory;
impl Render<Self> for TabStory { // impl Render for TabStory {
type Element = Div<Self>; // type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { // fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let git_statuses = GitStatus::iter(); // let git_statuses = GitStatus::iter();
let fs_statuses = FileSystemStatus::iter(); // let fs_statuses = FileSystemStatus::iter();
Story::container(cx) // Story::container(cx)
.child(Story::title_for::<_, Tab>(cx)) // .child(Story::title_for::<_, Tab>(cx))
.child( // .child(
h_stack().child( // h_stack().child(
v_stack() // v_stack()
.gap_2() // .gap_2()
.child(Story::label(cx, "Default")) // .child(Story::label(cx, "Default"))
.child(Tab::new("default")), // .child(Tab::new("default")),
), // ),
) // )
.child( // .child(
h_stack().child( // h_stack().child(
v_stack().gap_2().child(Story::label(cx, "Current")).child( // v_stack().gap_2().child(Story::label(cx, "Current")).child(
h_stack() // h_stack()
.gap_4() // .gap_4()
.child( // .child(
Tab::new("current") // Tab::new("current")
.title("Current".to_string()) // .title("Current".to_string())
.current(true), // .current(true),
) // )
.child( // .child(
Tab::new("not_current") // Tab::new("not_current")
.title("Not Current".to_string()) // .title("Not Current".to_string())
.current(false), // .current(false),
), // ),
), // ),
), // ),
) // )
.child( // .child(
h_stack().child( // h_stack().child(
v_stack() // v_stack()
.gap_2() // .gap_2()
.child(Story::label(cx, "Titled")) // .child(Story::label(cx, "Titled"))
.child(Tab::new("titled").title("label".to_string())), // .child(Tab::new("titled").title("label".to_string())),
), // ),
) // )
.child( // .child(
h_stack().child( // h_stack().child(
v_stack() // v_stack()
.gap_2() // .gap_2()
.child(Story::label(cx, "With Icon")) // .child(Story::label(cx, "With Icon"))
.child( // .child(
Tab::new("with_icon") // Tab::new("with_icon")
.title("label".to_string()) // .title("label".to_string())
.icon(Some(Icon::Envelope)), // .icon(Some(Icon::Envelope)),
), // ),
), // ),
) // )
.child( // .child(
h_stack().child( // h_stack().child(
v_stack() // v_stack()
.gap_2() // .gap_2()
.child(Story::label(cx, "Close Side")) // .child(Story::label(cx, "Close Side"))
.child( // .child(
h_stack() // h_stack()
.gap_4() // .gap_4()
.child( // .child(
Tab::new("left") // Tab::new("left")
.title("Left".to_string()) // .title("Left".to_string())
.close_side(IconSide::Left), // .close_side(IconSide::Left),
) // )
.child(Tab::new("right").title("Right".to_string())), // .child(Tab::new("right").title("Right".to_string())),
), // ),
), // ),
) // )
.child( // .child(
v_stack() // v_stack()
.gap_2() // .gap_2()
.child(Story::label(cx, "Git Status")) // .child(Story::label(cx, "Git Status"))
.child(h_stack().gap_4().children(git_statuses.map(|git_status| { // .child(h_stack().gap_4().children(git_statuses.map(|git_status| {
Tab::new("git_status") // Tab::new("git_status")
.title(git_status.to_string()) // .title(git_status.to_string())
.git_status(git_status) // .git_status(git_status)
}))), // }))),
) // )
.child( // .child(
v_stack() // v_stack()
.gap_2() // .gap_2()
.child(Story::label(cx, "File System Status")) // .child(Story::label(cx, "File System Status"))
.child(h_stack().gap_4().children(fs_statuses.map(|fs_status| { // .child(h_stack().gap_4().children(fs_statuses.map(|fs_status| {
Tab::new("file_system_status") // Tab::new("file_system_status")
.title(fs_status.to_string()) // .title(fs_status.to_string())
.fs_status(fs_status) // .fs_status(fs_status)
}))), // }))),
) // )
} // }
} // }
} // }

View file

@ -23,15 +23,15 @@ pub enum ToastOrigin {
/// ///
/// Only one toast may be visible at a time. /// Only one toast may be visible at a time.
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Toast<V: 'static> { pub struct Toast {
origin: ToastOrigin, origin: ToastOrigin,
children: SmallVec<[AnyElement<V>; 2]>, children: SmallVec<[AnyElement; 2]>,
} }
impl<V: 'static> Component<V> for Toast<V> { impl Component for Toast {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let mut div = div(); let mut div = div();
if self.origin == ToastOrigin::Bottom { if self.origin == ToastOrigin::Bottom {
@ -54,7 +54,7 @@ impl<V: 'static> Component<V> for Toast<V> {
} }
} }
impl<V: 'static> Toast<V> { impl Toast {
pub fn new(origin: ToastOrigin) -> Self { pub fn new(origin: ToastOrigin) -> Self {
Self { Self {
origin, origin,
@ -62,7 +62,7 @@ impl<V: 'static> Toast<V> {
} }
} }
fn render(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
let mut div = div(); let mut div = div();
if self.origin == ToastOrigin::Bottom { if self.origin == ToastOrigin::Bottom {
@ -85,8 +85,8 @@ impl<V: 'static> Toast<V> {
} }
} }
impl<V: 'static> ParentElement<V> for Toast<V> { impl ParentElement for Toast {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children &mut self.children
} }
} }
@ -104,12 +104,12 @@ mod stories {
pub struct ToastStory; pub struct ToastStory;
impl Render<Self> for ToastStory { impl Render for ToastStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, Toast<Self>>(cx)) .child(Story::title_for::<Toast<Self>>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child(Toast::new(ToastOrigin::Bottom).child(Label::new("label"))) .child(Toast::new(ToastOrigin::Bottom).child(Label::new("label")))
} }

View file

@ -44,7 +44,7 @@ impl From<bool> for Toggle {
} }
} }
pub fn disclosure_control<V: 'static>(toggle: Toggle) -> impl Element<V> { pub fn disclosure_control(toggle: Toggle) -> impl Element {
match (toggle.is_toggleable(), toggle.is_toggled()) { match (toggle.is_toggleable(), toggle.is_toggled()) {
(false, _) => div(), (false, _) => div(),
(_, true) => div().child( (_, true) => div().child(

View file

@ -4,10 +4,10 @@ use gpui::{Div, RenderOnce};
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct ToolDivider; pub struct ToolDivider;
impl<V: 'static> Component<V> for ToolDivider { impl Component for ToolDivider {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().w_px().h_3().bg(cx.theme().colors().border) div().w_px().h_3().bg(cx.theme().colors().border)
} }
} }
@ -17,7 +17,7 @@ impl ToolDivider {
Self Self
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
div().w_px().h_3().bg(cx.theme().colors().border) div().w_px().h_3().bg(cx.theme().colors().border)
} }
} }

View file

@ -67,8 +67,8 @@ impl Tooltip {
} }
} }
impl Render<Self> for Tooltip { impl Render for Tooltip {
type Element = Overlay<Self>; type Element = Overlay;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone(); let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();

View file

@ -18,7 +18,7 @@ mod components;
mod elevation; mod elevation;
pub mod prelude; pub mod prelude;
pub mod settings; pub mod settings;
mod static_data; // mod static_data;
mod styled_ext; mod styled_ext;
mod to_extract; mod to_extract;
pub mod utils; pub mod utils;
@ -26,7 +26,7 @@ pub mod utils;
pub use components::*; pub use components::*;
use gpui::actions; use gpui::actions;
pub use prelude::*; pub use prelude::*;
pub use static_data::*; // pub use static_data::*;
pub use styled_ext::*; pub use styled_ext::*;
pub use to_extract::*; pub use to_extract::*;

View file

@ -5,7 +5,7 @@ use crate::prelude::*;
pub struct Story {} pub struct Story {}
impl Story { impl Story {
pub fn container<V: 'static>(cx: &mut ViewContext<V>) -> Div<V> { pub fn container(cx: &mut gpui::WindowContext) -> Div {
div() div()
.size_full() .size_full()
.flex() .flex()
@ -16,23 +16,23 @@ impl Story {
} }
pub fn title<V: 'static>( pub fn title<V: 'static>(
cx: &mut ViewContext<V>, cx: &mut WindowContext,
title: impl Into<SharedString>, title: impl Into<SharedString>,
) -> impl Element<V> { ) -> impl Element {
div() div()
.text_xl() .text_xl()
.text_color(cx.theme().colors().text) .text_color(cx.theme().colors().text)
.child(title.into()) .child(title.into())
} }
pub fn title_for<V: 'static, T>(cx: &mut ViewContext<V>) -> impl Element<V> { pub fn title_for<T>(cx: &mut WindowContext) -> impl Element {
Self::title(cx, std::any::type_name::<T>()) Self::title(cx, std::any::type_name::<T>())
} }
pub fn label<V: 'static>( pub fn label<V: 'static>(
cx: &mut ViewContext<V>, cx: &mut WindowContext,
label: impl Into<SharedString>, label: impl Into<SharedString>,
) -> impl Element<V> { ) -> impl Element {
div() div()
.mt_4() .mt_4()
.mb_2() .mb_2()

View file

@ -1,9 +1,9 @@
use gpui::{Styled, ViewContext}; use gpui::{Styled, WindowContext};
use theme2::ActiveTheme; use theme2::ActiveTheme;
use crate::{ElevationIndex, UITextSize}; use crate::{ElevationIndex, UITextSize};
fn elevated<E: Styled, V: 'static>(this: E, cx: &mut ViewContext<V>, index: ElevationIndex) -> E { fn elevated<E: Styled>(this: E, cx: &mut WindowContext, index: ElevationIndex) -> E {
this.bg(cx.theme().colors().elevated_surface_background) this.bg(cx.theme().colors().elevated_surface_background)
.z_index(index.z_index()) .z_index(index.z_index())
.rounded_lg() .rounded_lg()
@ -65,7 +65,7 @@ pub trait StyledExt: Styled + Sized {
/// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()` /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
/// ///
/// Example Elements: Title Bar, Panel, Tab Bar, Editor /// Example Elements: Title Bar, Panel, Tab Bar, Editor
fn elevation_1<V: 'static>(self, cx: &mut ViewContext<V>) -> Self { fn elevation_1(self, cx: &mut WindowContext) -> Self {
elevated(self, cx, ElevationIndex::Surface) elevated(self, cx, ElevationIndex::Surface)
} }
@ -74,7 +74,7 @@ pub trait StyledExt: Styled + Sized {
/// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()` /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
/// ///
/// Examples: Notifications, Palettes, Detached/Floating Windows, Detached/Floating Panels /// Examples: Notifications, Palettes, Detached/Floating Windows, Detached/Floating Panels
fn elevation_2<V: 'static>(self, cx: &mut ViewContext<V>) -> Self { fn elevation_2(self, cx: &mut WindowContext) -> Self {
elevated(self, cx, ElevationIndex::ElevatedSurface) elevated(self, cx, ElevationIndex::ElevatedSurface)
} }
@ -89,7 +89,7 @@ pub trait StyledExt: Styled + Sized {
/// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()` /// Sets `bg()`, `rounded_lg()`, `border()`, `border_color()`, `shadow()`
/// ///
/// Examples: Settings Modal, Channel Management, Wizards/Setup UI, Dialogs /// Examples: Settings Modal, Channel Management, Wizards/Setup UI, Dialogs
fn elevation_4<V: 'static>(self, cx: &mut ViewContext<V>) -> Self { fn elevation_4(self, cx: &mut WindowContext) -> Self {
elevated(self, cx, ElevationIndex::ModalSurface) elevated(self, cx, ElevationIndex::ModalSurface)
} }
} }

View file

@ -1,47 +1,48 @@
mod assistant_panel; //TODO!(Restore later)
mod breadcrumb; // mod assistant_panel;
mod buffer; // mod breadcrumb;
mod buffer_search; // mod buffer;
mod chat_panel; // mod buffer_search;
mod collab_panel; // mod chat_panel;
mod command_palette; // mod collab_panel;
mod copilot; // mod command_palette;
mod editor_pane; // mod copilot;
mod language_selector; // mod editor_pane;
mod multi_buffer; // mod language_selector;
mod notifications_panel; // mod multi_buffer;
mod panes; // mod notifications_panel;
mod project_panel; // mod panes;
mod recent_projects; // mod project_panel;
mod status_bar; // mod recent_projects;
mod tab_bar; // mod status_bar;
mod terminal; // mod tab_bar;
mod theme_selector; // mod terminal;
mod title_bar; // mod theme_selector;
mod toolbar; // mod title_bar;
mod traffic_lights; // mod toolbar;
mod workspace; // mod traffic_lights;
// mod workspace;
pub use assistant_panel::*; // pub use assistant_panel::*;
pub use breadcrumb::*; // pub use breadcrumb::*;
pub use buffer::*; // pub use buffer::*;
pub use buffer_search::*; // pub use buffer_search::*;
pub use chat_panel::*; // pub use chat_panel::*;
pub use collab_panel::*; // pub use collab_panel::*;
pub use command_palette::*; // pub use command_palette::*;
pub use copilot::*; // pub use copilot::*;
pub use editor_pane::*; // pub use editor_pane::*;
pub use language_selector::*; // pub use language_selector::*;
pub use multi_buffer::*; // pub use multi_buffer::*;
pub use notifications_panel::*; // pub use notifications_panel::*;
pub use panes::*; // pub use panes::*;
pub use project_panel::*; // pub use project_panel::*;
pub use recent_projects::*; // pub use recent_projects::*;
pub use status_bar::*; // pub use status_bar::*;
pub use tab_bar::*; // pub use tab_bar::*;
pub use terminal::*; // pub use terminal::*;
pub use theme_selector::*; // pub use theme_selector::*;
pub use title_bar::*; // pub use title_bar::*;
pub use toolbar::*; // pub use toolbar::*;
pub use traffic_lights::*; // pub use traffic_lights::*;
pub use workspace::*; // pub use workspace::*;

View file

@ -8,10 +8,10 @@ pub struct AssistantPanel {
current_side: PanelSide, current_side: PanelSide,
} }
impl<V: 'static> Component<V> for AssistantPanel { impl Component for AssistantPanel {
type Rendered = Panel<V>; type Rendered = Panel;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
Panel::new(self.id.clone(), cx) Panel::new(self.id.clone(), cx)
.children(vec![div() .children(vec![div()
.flex() .flex()
@ -84,8 +84,8 @@ mod stories {
use gpui::{Div, Render}; use gpui::{Div, Render};
pub struct AssistantPanelStory; pub struct AssistantPanelStory;
impl Render<Self> for AssistantPanelStory { impl Render for AssistantPanelStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -11,10 +11,10 @@ pub struct Breadcrumb {
symbols: Vec<Symbol>, symbols: Vec<Symbol>,
} }
impl<V: 'static> Component<V> for Breadcrumb { impl Component for Breadcrumb {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view_state: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let symbols_len = self.symbols.len(); let symbols_len = self.symbols.len();
h_stack() h_stack()
.id("breadcrumb") .id("breadcrumb")
@ -62,7 +62,7 @@ impl Breadcrumb {
Self { path, symbols } Self { path, symbols }
} }
fn render_separator<V: 'static>(&self, cx: &WindowContext) -> Div<V> { fn render_separator(&self, cx: &WindowContext) -> Div {
div() div()
.child(" ") .child(" ")
.text_color(cx.theme().colors().text_muted) .text_color(cx.theme().colors().text_muted)
@ -81,8 +81,8 @@ mod stories {
pub struct BreadcrumbStory; pub struct BreadcrumbStory;
impl Render<Self> for BreadcrumbStory { impl Render for BreadcrumbStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -117,10 +117,10 @@ pub struct Buffer {
path: Option<String>, path: Option<String>,
} }
impl<V: 'static> Component<V> for Buffer { impl Component for Buffer {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let rows = self.render_rows(cx); let rows = self.render_rows(cx);
v_stack() v_stack()
@ -169,7 +169,7 @@ impl Buffer {
self self
} }
fn render_row<V: 'static>(row: BufferRow, cx: &WindowContext) -> impl Element<V> { fn render_row(row: BufferRow, cx: &WindowContext) -> impl Element {
let line_background = if row.current { let line_background = if row.current {
cx.theme().colors().editor_active_line_background cx.theme().colors().editor_active_line_background
} else { } else {
@ -217,7 +217,7 @@ impl Buffer {
})) }))
} }
fn render_rows<V: 'static>(&self, cx: &WindowContext) -> Vec<impl Element<V>> { fn render_rows(&self, cx: &WindowContext) -> Vec<impl Element> {
match &self.rows { match &self.rows {
Some(rows) => rows Some(rows) => rows
.rows .rows
@ -228,7 +228,7 @@ impl Buffer {
} }
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
let rows = self.render_rows(cx); let rows = self.render_rows(cx);
v_stack() v_stack()
@ -254,8 +254,8 @@ mod stories {
pub struct BufferStory; pub struct BufferStory;
impl Render<Self> for BufferStory { impl Render for BufferStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -25,10 +25,10 @@ impl BufferSearch {
} }
} }
impl Render<Self> for BufferSearch { impl Render for BufferSearch {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> { fn render(&mut self, cx: &mut WindowContext) -> Div {
h_stack() h_stack()
.bg(cx.theme().colors().toolbar_background) .bg(cx.theme().colors().toolbar_background)
.p_2() .p_2()

View file

@ -8,10 +8,10 @@ pub struct ChatPanel {
messages: Vec<ChatMessage>, messages: Vec<ChatMessage>,
} }
impl<V: 'static> Component<V> for ChatPanel { impl Component for ChatPanel {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.id(self.element_id.clone()) .id(self.element_id.clone())
.flex() .flex()
@ -78,10 +78,10 @@ pub struct ChatMessage {
sent_at: NaiveDateTime, sent_at: NaiveDateTime,
} }
impl<V: 'static> Component<V> for ChatMessage { impl Component for ChatMessage {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.flex() .flex()
.flex_col() .flex_col()
@ -123,8 +123,8 @@ mod stories {
pub struct ChatPanelStory; pub struct ChatPanelStory;
impl Render<Self> for ChatPanelStory { impl Render for ChatPanelStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -9,10 +9,10 @@ pub struct CollabPanel {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for CollabPanel { impl Component for CollabPanel {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
v_stack() v_stack()
.id(self.id.clone()) .id(self.id.clone())
.h_full() .h_full()
@ -101,8 +101,8 @@ mod stories {
pub struct CollabPanelStory; pub struct CollabPanelStory;
impl Render<Self> for CollabPanelStory { impl Render for CollabPanelStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -6,10 +6,10 @@ pub struct CommandPalette {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for CommandPalette { impl Component for CommandPalette {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().id(self.id.clone()).child( div().id(self.id.clone()).child(
Palette::new("palette") Palette::new("palette")
.items(example_editor_actions()) .items(example_editor_actions())
@ -40,8 +40,8 @@ mod stories {
pub struct CommandPaletteStory; pub struct CommandPaletteStory;
impl Render<Self> for CommandPaletteStory { impl Render for CommandPaletteStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -5,10 +5,10 @@ pub struct CopilotModal {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for CopilotModal { impl Component for CopilotModal {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().id(self.id.clone()).child( div().id(self.id.clone()).child(
Modal::new("some-id") Modal::new("some-id")
.title("Connect Copilot to Zed") .title("Connect Copilot to Zed")
@ -36,8 +36,8 @@ mod stories {
pub struct CopilotModalStory; pub struct CopilotModalStory;
impl Render<Self> for CopilotModalStory { impl Render for CopilotModalStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -47,10 +47,10 @@ impl EditorPane {
} }
} }
impl Render<Self> for EditorPane { impl Render for EditorPane {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> { fn render(&mut self, cx: &mut WindowContext) -> Div {
v_stack() v_stack()
.w_full() .w_full()
.h_full() .h_full()

View file

@ -6,10 +6,10 @@ pub struct LanguageSelector {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for LanguageSelector { impl Component for LanguageSelector {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().id(self.id.clone()).child( div().id(self.id.clone()).child(
Palette::new("palette") Palette::new("palette")
.items(vec![ .items(vec![
@ -36,7 +36,7 @@ impl LanguageSelector {
Self { id: id.into() } Self { id: id.into() }
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
div().id(self.id.clone()).child( div().id(self.id.clone()).child(
Palette::new("palette") Palette::new("palette")
.items(vec![ .items(vec![
@ -58,7 +58,7 @@ impl LanguageSelector {
} }
} }
use gpui::{Div, RenderOnce, Stateful}; use gpui::{Div, RenderOnce};
#[cfg(feature = "stories")] #[cfg(feature = "stories")]
pub use stories::*; pub use stories::*;
@ -70,8 +70,8 @@ mod stories {
pub struct LanguageSelectorStory; pub struct LanguageSelectorStory;
impl Render<Self> for LanguageSelectorStory { impl Render for LanguageSelectorStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -6,10 +6,10 @@ pub struct MultiBuffer {
buffers: Vec<Buffer>, buffers: Vec<Buffer>,
} }
impl<V: 'static> Component<V> for MultiBuffer { impl Component for MultiBuffer {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
v_stack() v_stack()
.w_full() .w_full()
.h_full() .h_full()
@ -49,8 +49,8 @@ mod stories {
pub struct MultiBufferStory; pub struct MultiBufferStory;
impl Render<Self> for MultiBufferStory { impl Render for MultiBufferStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -1,19 +1,19 @@
use crate::{ use crate::{
h_stack, prelude::*, static_new_notification_items_2, utils::naive_format_distance_from_now, h_stack, prelude::*, static_new_notification_items_2, utils::naive_format_distance_from_now,
v_stack, Avatar, ButtonOrIconButton, ClickHandler, Icon, IconElement, Label, LineHeightStyle, v_stack, Avatar, ButtonOrIconButton, Icon, IconElement, Label, LineHeightStyle, ListHeader,
ListHeader, ListHeaderMeta, ListSeparator, PublicPlayer, TextColor, UnreadIndicator, ListHeaderMeta, ListSeparator, PublicPlayer, TextColor, UnreadIndicator,
}; };
use gpui::{prelude::*, Div, Stateful}; use gpui::{prelude::*, ClickEvent, Div};
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct NotificationsPanel { pub struct NotificationsPanel {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for NotificationsPanel { impl Component for NotificationsPanel {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.id(self.id.clone()) .id(self.id.clone())
.flex() .flex()
@ -60,8 +60,8 @@ impl NotificationsPanel {
} }
} }
pub struct NotificationAction<V: 'static> { pub struct NotificationAction {
button: ButtonOrIconButton<V>, button: ButtonOrIconButton,
tooltip: SharedString, tooltip: SharedString,
/// Shows after action is chosen /// Shows after action is chosen
/// ///
@ -73,9 +73,9 @@ pub struct NotificationAction<V: 'static> {
taken_message: (Option<Icon>, SharedString), taken_message: (Option<Icon>, SharedString),
} }
impl<V: 'static> NotificationAction<V> { impl NotificationAction {
pub fn new( pub fn new(
button: impl Into<ButtonOrIconButton<V>>, button: impl Into<ButtonOrIconButton>,
tooltip: impl Into<SharedString>, tooltip: impl Into<SharedString>,
(icon, taken_message): (Option<Icon>, impl Into<SharedString>), (icon, taken_message): (Option<Icon>, impl Into<SharedString>),
) -> Self { ) -> Self {
@ -92,38 +92,40 @@ pub enum ActorOrIcon {
Icon(Icon), Icon(Icon),
} }
pub struct NotificationMeta<V: 'static> { pub type ClickHandler = Box<dyn Fn(&ClickEvent, &mut WindowContext)>;
items: Vec<(Option<Icon>, SharedString, Option<ClickHandler<V>>)>,
pub struct NotificationMeta {
items: Vec<(Option<Icon>, SharedString, Option<ClickHandler>)>,
} }
struct NotificationHandlers<V: 'static> { struct NotificationHandlers {
click: Option<ClickHandler<V>>, click: Option<ClickHandler>,
} }
impl<V: 'static> Default for NotificationHandlers<V> { impl Default for NotificationHandlers {
fn default() -> Self { fn default() -> Self {
Self { click: None } Self { click: None }
} }
} }
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Notification<V: 'static> { pub struct Notification {
id: ElementId, id: ElementId,
slot: ActorOrIcon, slot: ActorOrIcon,
message: SharedString, message: SharedString,
date_received: NaiveDateTime, date_received: NaiveDateTime,
meta: Option<NotificationMeta<V>>, meta: Option<NotificationMeta>,
actions: Option<[NotificationAction<V>; 2]>, actions: Option<[NotificationAction; 2]>,
unread: bool, unread: bool,
new: bool, new: bool,
action_taken: Option<NotificationAction<V>>, action_taken: Option<NotificationAction>,
handlers: NotificationHandlers<V>, handlers: NotificationHandlers,
} }
impl<V: 'static> Component<V> for Notification<V> { impl Component for Notification {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.relative() .relative()
.id(self.id.clone()) .id(self.id.clone())
@ -199,13 +201,13 @@ impl<V: 'static> Component<V> for Notification<V> {
} }
} }
impl<V> Notification<V> { impl Notification {
fn new( fn new(
id: ElementId, id: ElementId,
message: SharedString, message: SharedString,
date_received: NaiveDateTime, date_received: NaiveDateTime,
slot: ActorOrIcon, slot: ActorOrIcon,
click_action: Option<ClickHandler<V>>, click_action: Option<ClickHandler>,
) -> Self { ) -> Self {
let handlers = if click_action.is_some() { let handlers = if click_action.is_some() {
NotificationHandlers { NotificationHandlers {
@ -237,7 +239,7 @@ impl<V> Notification<V> {
message: impl Into<SharedString>, message: impl Into<SharedString>,
date_received: NaiveDateTime, date_received: NaiveDateTime,
actor: PublicPlayer, actor: PublicPlayer,
click_action: ClickHandler<V>, click_action: ClickHandler,
) -> Self { ) -> Self {
Self::new( Self::new(
id.into(), id.into(),
@ -256,7 +258,7 @@ impl<V> Notification<V> {
message: impl Into<SharedString>, message: impl Into<SharedString>,
date_received: NaiveDateTime, date_received: NaiveDateTime,
icon: Icon, icon: Icon,
click_action: ClickHandler<V>, click_action: ClickHandler,
) -> Self { ) -> Self {
Self::new( Self::new(
id.into(), id.into(),
@ -276,7 +278,7 @@ impl<V> Notification<V> {
message: impl Into<SharedString>, message: impl Into<SharedString>,
date_received: NaiveDateTime, date_received: NaiveDateTime,
actor: PublicPlayer, actor: PublicPlayer,
actions: [NotificationAction<V>; 2], actions: [NotificationAction; 2],
) -> Self { ) -> Self {
Self::new( Self::new(
id.into(), id.into(),
@ -297,7 +299,7 @@ impl<V> Notification<V> {
message: impl Into<SharedString>, message: impl Into<SharedString>,
date_received: NaiveDateTime, date_received: NaiveDateTime,
icon: Icon, icon: Icon,
actions: [NotificationAction<V>; 2], actions: [NotificationAction; 2],
) -> Self { ) -> Self {
Self::new( Self::new(
id.into(), id.into(),
@ -309,22 +311,22 @@ impl<V> Notification<V> {
.actions(actions) .actions(actions)
} }
fn on_click(mut self, handler: ClickHandler<V>) -> Self { fn on_click(mut self, handler: ClickHandler) -> Self {
self.handlers.click = Some(handler); self.handlers.click = Some(handler);
self self
} }
pub fn actions(mut self, actions: [NotificationAction<V>; 2]) -> Self { pub fn actions(mut self, actions: [NotificationAction; 2]) -> Self {
self.actions = Some(actions); self.actions = Some(actions);
self self
} }
pub fn meta(mut self, meta: NotificationMeta<V>) -> Self { pub fn meta(mut self, meta: NotificationMeta) -> Self {
self.meta = Some(meta); self.meta = Some(meta);
self self
} }
fn render_meta_items(&self, cx: &mut ViewContext<V>) -> impl Element<V> { fn render_meta_items(&self, cx: &mut WindowContext) -> impl Element {
if let Some(meta) = &self.meta { if let Some(meta) = &self.meta {
h_stack().children( h_stack().children(
meta.items meta.items
@ -343,7 +345,7 @@ impl<V> Notification<V> {
} }
} }
fn render_slot(&self, cx: &mut ViewContext<V>) -> impl Element<V> { fn render_slot(&self, cx: &mut WindowContext) -> impl Element {
match &self.slot { match &self.slot {
ActorOrIcon::Actor(actor) => Avatar::new(actor.avatar.clone()).render_into_any(), ActorOrIcon::Actor(actor) => Avatar::new(actor.avatar.clone()).render_into_any(),
ActorOrIcon::Icon(icon) => IconElement::new(icon.clone()).render_into_any(), ActorOrIcon::Icon(icon) => IconElement::new(icon.clone()).render_into_any(),
@ -364,12 +366,12 @@ mod stories {
pub struct NotificationsPanelStory; pub struct NotificationsPanelStory;
impl Render<Self> for NotificationsPanelStory { impl Render for NotificationsPanelStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, NotificationsPanel>(cx)) .child(Story::title_for::<NotificationsPanel>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))
.child( .child(
Panel::new("panel", cx).child(NotificationsPanel::new("notifications_panel")), Panel::new("panel", cx).child(NotificationsPanel::new("notifications_panel")),

View file

@ -14,17 +14,17 @@ pub enum SplitDirection {
} }
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Pane<V: 'static> { pub struct Pane {
id: ElementId, id: ElementId,
size: Size<Length>, size: Size<Length>,
fill: Hsla, fill: Hsla,
children: SmallVec<[AnyElement<V>; 2]>, children: SmallVec<[AnyElement; 2]>,
} }
impl<V: 'static> Component<V> for Pane<V> { impl Component for Pane {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.id(self.id.clone()) .id(self.id.clone())
.flex() .flex()
@ -48,7 +48,7 @@ impl<V: 'static> Component<V> for Pane<V> {
} }
} }
impl<V: 'static> Pane<V> { impl Pane {
pub fn new(id: impl Into<ElementId>, size: Size<Length>) -> Self { pub fn new(id: impl Into<ElementId>, size: Size<Length>) -> Self {
// Fill is only here for debugging purposes, remove before release // Fill is only here for debugging purposes, remove before release
@ -66,23 +66,23 @@ impl<V: 'static> Pane<V> {
} }
} }
impl<V: 'static> ParentElement<V> for Pane<V> { impl ParentElement for Pane {
fn children_mut(&mut self) -> &mut SmallVec<[AnyElement<V>; 2]> { fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
&mut self.children &mut self.children
} }
} }
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct PaneGroup<V: 'static> { pub struct PaneGroup {
groups: Vec<PaneGroup<V>>, groups: Vec<PaneGroup>,
panes: Vec<Pane<V>>, panes: Vec<Pane>,
split_direction: SplitDirection, split_direction: SplitDirection,
} }
impl<V: 'static> Component<V> for PaneGroup<V> { impl Component for PaneGroup {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
if !self.panes.is_empty() { if !self.panes.is_empty() {
let el = div() let el = div()
.flex() .flex()
@ -90,7 +90,7 @@ impl<V: 'static> Component<V> for PaneGroup<V> {
.gap_px() .gap_px()
.w_full() .w_full()
.h_full() .h_full()
.children(self.panes.into_iter().map(|pane| pane.render(view, cx))); .children(self.panes.into_iter().map(|pane| pane.render(cx)));
if self.split_direction == SplitDirection::Horizontal { if self.split_direction == SplitDirection::Horizontal {
return el; return el;
@ -107,7 +107,7 @@ impl<V: 'static> Component<V> for PaneGroup<V> {
.w_full() .w_full()
.h_full() .h_full()
.bg(cx.theme().colors().editor_background) .bg(cx.theme().colors().editor_background)
.children(self.groups.into_iter().map(|group| group.render(view, cx))); .children(self.groups.into_iter().map(|group| group.render(cx)));
if self.split_direction == SplitDirection::Horizontal { if self.split_direction == SplitDirection::Horizontal {
return el; return el;
@ -120,8 +120,8 @@ impl<V: 'static> Component<V> for PaneGroup<V> {
} }
} }
impl<V: 'static> PaneGroup<V> { impl PaneGroup {
pub fn new_groups(groups: Vec<PaneGroup<V>>, split_direction: SplitDirection) -> Self { pub fn new_groups(groups: Vec<PaneGroup>, split_direction: SplitDirection) -> Self {
Self { Self {
groups, groups,
panes: Vec::new(), panes: Vec::new(),
@ -129,7 +129,7 @@ impl<V: 'static> PaneGroup<V> {
} }
} }
pub fn new_panes(panes: Vec<Pane<V>>, split_direction: SplitDirection) -> Self { pub fn new_panes(panes: Vec<Pane>, split_direction: SplitDirection) -> Self {
Self { Self {
groups: Vec::new(), groups: Vec::new(),
panes, panes,

View file

@ -11,10 +11,10 @@ pub struct ProjectPanel {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for ProjectPanel { impl Component for ProjectPanel {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() div()
.id(self.id.clone()) .id(self.id.clone())
.flex() .flex()
@ -52,7 +52,7 @@ impl ProjectPanel {
Self { id: id.into() } Self { id: id.into() }
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
div() div()
.id(self.id.clone()) .id(self.id.clone())
.flex() .flex()
@ -97,8 +97,8 @@ mod stories {
pub struct ProjectPanelStory; pub struct ProjectPanelStory;
impl Render<Self> for ProjectPanelStory { impl Render for ProjectPanelStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -6,10 +6,10 @@ pub struct RecentProjects {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for RecentProjects { impl Component for RecentProjects {
type Rendered = Stateful<V, Div<V>>; type Rendered = Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div().id(self.id.clone()).child( div().id(self.id.clone()).child(
Palette::new("palette") Palette::new("palette")
.items(vec![ .items(vec![
@ -45,10 +45,10 @@ mod stories {
pub struct RecentProjectsStory; pub struct RecentProjectsStory;
impl Render<Self> for RecentProjectsStory { impl Render for RecentProjectsStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut WindowContext) -> Self::Element {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, RecentProjects>(cx)) .child(Story::title_for::<_, RecentProjects>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))

View file

@ -328,7 +328,7 @@ pub fn static_players_with_call_status() -> Vec<PlayerWithCallStatus> {
] ]
} }
pub fn static_new_notification_items_2<V: 'static>() -> Vec<Notification<V>> { pub fn static_new_notification_items_2() -> Vec<Notification> {
vec![ vec![
Notification::new_icon_message( Notification::new_icon_message(
"notif-1", "notif-1",
@ -478,7 +478,7 @@ pub fn static_new_notification_items_2<V: 'static>() -> Vec<Notification<V>> {
] ]
} }
pub fn static_project_panel_project_items<V>() -> Vec<ListItem<V>> { pub fn static_project_panel_project_items() -> Vec<ListItem> {
vec![ vec![
ListEntry::new(Label::new("zed")) ListEntry::new(Label::new("zed"))
.left_icon(Icon::FolderOpen.into()) .left_icon(Icon::FolderOpen.into())
@ -605,7 +605,7 @@ pub fn static_project_panel_project_items<V>() -> Vec<ListItem<V>> {
.collect() .collect()
} }
pub fn static_project_panel_single_items<V>() -> Vec<ListItem<V>> { pub fn static_project_panel_single_items() -> Vec<ListItem> {
vec![ vec![
ListEntry::new(Label::new("todo.md")) ListEntry::new(Label::new("todo.md"))
.left_icon(Icon::FileDoc.into()) .left_icon(Icon::FileDoc.into())
@ -622,7 +622,7 @@ pub fn static_project_panel_single_items<V>() -> Vec<ListItem<V>> {
.collect() .collect()
} }
pub fn static_collab_panel_current_call<V>() -> Vec<ListItem<V>> { pub fn static_collab_panel_current_call() -> Vec<ListItem> {
vec![ vec![
ListEntry::new(Label::new("as-cii")).left_avatar("http://github.com/as-cii.png?s=50"), ListEntry::new(Label::new("as-cii")).left_avatar("http://github.com/as-cii.png?s=50"),
ListEntry::new(Label::new("nathansobo")) ListEntry::new(Label::new("nathansobo"))
@ -635,7 +635,7 @@ pub fn static_collab_panel_current_call<V>() -> Vec<ListItem<V>> {
.collect() .collect()
} }
pub fn static_collab_panel_channels<V>() -> Vec<ListItem<V>> { pub fn static_collab_panel_channels<V>() -> Vec<ListItem> {
vec![ vec![
ListEntry::new(Label::new("zed")) ListEntry::new(Label::new("zed"))
.left_icon(Icon::Hash.into()) .left_icon(Icon::Hash.into())

View file

@ -38,8 +38,8 @@ pub struct StatusBar {
bottom_tools: Option<ToolGroup>, bottom_tools: Option<ToolGroup>,
} }
impl Component<Workspace> for StatusBar { impl Component for StatusBar {
type Rendered = Div<Workspace>; type Rendered = Div;
fn render(self, view: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Self::Rendered { fn render(self, view: &mut Workspace, cx: &mut ViewContext<Workspace>) -> Self::Rendered {
div() div()
@ -100,7 +100,7 @@ impl StatusBar {
self self
} }
fn left_tools(&self, workspace: &mut Workspace, cx: &WindowContext) -> impl Element<Workspace> { fn left_tools(&self, workspace: &mut Workspace, cx: &WindowContext) -> impl Element {
div() div()
.flex() .flex()
.items_center() .items_center()
@ -127,11 +127,7 @@ impl StatusBar {
.child(IconButton::new("diagnostics", Icon::XCircle)) .child(IconButton::new("diagnostics", Icon::XCircle))
} }
fn right_tools( fn right_tools(&self, workspace: &mut Workspace, cx: &WindowContext) -> impl Element {
&self,
workspace: &mut Workspace,
cx: &WindowContext,
) -> impl Element<Workspace> {
div() div()
.flex() .flex()
.items_center() .items_center()

View file

@ -11,10 +11,10 @@ pub struct TabBar {
tabs: Vec<Tab>, tabs: Vec<Tab>,
} }
impl<V: 'static> Component<V> for TabBar { impl Component for TabBar {
type Rendered = Stateful<V, Div<V>>; type Rendered = gpui::Stateful<Div>;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let (can_navigate_back, can_navigate_forward) = self.can_navigate; let (can_navigate_back, can_navigate_forward) = self.can_navigate;
div() div()
@ -110,8 +110,8 @@ mod stories {
pub struct TabBarStory; pub struct TabBarStory;
impl Render<Self> for TabBarStory { impl Render for TabBarStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -5,10 +5,10 @@ use gpui::{relative, rems, Div, RenderOnce, Size};
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Terminal; pub struct Terminal;
impl<V: 'static> Component<V> for Terminal { impl Component for Terminal {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let can_navigate_back = true; let can_navigate_back = true;
let can_navigate_forward = false; let can_navigate_forward = false;
@ -78,7 +78,7 @@ impl Terminal {
Self Self
} }
fn render<V: 'static>(self, _view: &mut V, cx: &mut ViewContext<V>) -> impl Element<V> { fn render(self, cx: &mut WindowContext) -> impl Element {
let can_navigate_back = true; let can_navigate_back = true;
let can_navigate_forward = false; let can_navigate_forward = false;
@ -153,8 +153,8 @@ mod stories {
use gpui::{Div, Render}; use gpui::{Div, Render};
pub struct TerminalStory; pub struct TerminalStory;
impl Render<Self> for TerminalStory { impl Render for TerminalStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -6,11 +6,10 @@ pub struct ThemeSelector {
id: ElementId, id: ElementId,
} }
impl<V: 'static> Component<V> for ThemeSelector { impl Component for ThemeSelector {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let cx: &mut ViewContext<V> = cx;
div().child( div().child(
Palette::new(self.id.clone()) Palette::new(self.id.clone())
.items(vec![ .items(vec![
@ -53,8 +52,8 @@ mod stories {
pub struct ThemeSelectorStory; pub struct ThemeSelectorStory;
impl Render<Self> for ThemeSelectorStory { impl Render for ThemeSelectorStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) Story::container(cx)

View file

@ -85,10 +85,10 @@ impl TitleBar {
} }
} }
impl Render<Self> for TitleBar { impl Render for TitleBar {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> { fn render(&mut self, cx: &mut WindowContext) -> Div {
let settings = user_settings(cx); let settings = user_settings(cx);
// let has_focus = cx.window_is_active(); // let has_focus = cx.window_is_active();
@ -205,10 +205,10 @@ mod stories {
} }
} }
impl Render<Self> for TitleBarStory { impl Render for TitleBarStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> { fn render(&mut self, cx: &mut WindowContext) -> Div {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, TitleBar>(cx)) .child(Story::title_for::<_, TitleBar>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))

View file

@ -7,15 +7,15 @@ use crate::prelude::*;
pub struct ToolbarItem {} pub struct ToolbarItem {}
#[derive(RenderOnce)] #[derive(RenderOnce)]
pub struct Toolbar<V: 'static> { pub struct Toolbar {
left_items: SmallVec<[AnyElement<V>; 2]>, left_items: SmallVec<[AnyElement; 2]>,
right_items: SmallVec<[AnyElement<V>; 2]>, right_items: SmallVec<[AnyElement; 2]>,
} }
impl<V: 'static> Component<V> for Toolbar<V> { impl Component for Toolbar {
type Rendered = Div<V>; type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { fn render(self, cx: &WindowContext) -> Self::Rendered {
div() div()
.bg(cx.theme().colors().toolbar_background) .bg(cx.theme().colors().toolbar_background)
.p_2() .p_2()
@ -26,7 +26,7 @@ impl<V: 'static> Component<V> for Toolbar<V> {
} }
} }
impl<V: 'static> Toolbar<V> { impl Toolbar {
pub fn new() -> Self { pub fn new() -> Self {
Self { Self {
left_items: SmallVec::new(), left_items: SmallVec::new(),
@ -34,7 +34,7 @@ impl<V: 'static> Toolbar<V> {
} }
} }
pub fn left_item(mut self, child: impl RenderOnce<V>) -> Self pub fn left_item(mut self, child: impl RenderOnce) -> Self
where where
Self: Sized, Self: Sized,
{ {
@ -42,7 +42,7 @@ impl<V: 'static> Toolbar<V> {
self self
} }
pub fn left_items(mut self, iter: impl IntoIterator<Item = impl RenderOnce<V>>) -> Self pub fn left_items(mut self, iter: impl IntoIterator<Item = impl RenderOnce>) -> Self
where where
Self: Sized, Self: Sized,
{ {
@ -51,7 +51,7 @@ impl<V: 'static> Toolbar<V> {
self self
} }
pub fn right_item(mut self, child: impl RenderOnce<V>) -> Self pub fn right_item(mut self, child: impl RenderOnce) -> Self
where where
Self: Sized, Self: Sized,
{ {
@ -59,7 +59,7 @@ impl<V: 'static> Toolbar<V> {
self self
} }
pub fn right_items(mut self, iter: impl IntoIterator<Item = impl RenderOnce<V>>) -> Self pub fn right_items(mut self, iter: impl IntoIterator<Item = impl RenderOnce>) -> Self
where where
Self: Sized, Self: Sized,
{ {
@ -85,10 +85,10 @@ mod stories {
pub struct ToolbarStory; pub struct ToolbarStory;
impl Render<Self> for ToolbarStory { impl Render for ToolbarStory {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut WindowContext) -> Self::Element {
Story::container(cx) Story::container(cx)
.child(Story::title_for::<_, Toolbar<Self>>(cx)) .child(Story::title_for::<_, Toolbar<Self>>(cx))
.child(Story::label(cx, "Default")) .child(Story::label(cx, "Default"))

View file

@ -1,109 +1,109 @@
use crate::prelude::*; // use crate::prelude::*;
#[derive(Clone, Copy)] // #[derive(Clone, Copy)]
enum TrafficLightColor { // enum TrafficLightColor {
Red, // Red,
Yellow, // Yellow,
Green, // Green,
} // }
#[derive(RenderOnce)] // #[derive(RenderOnce)]
struct TrafficLight { // struct TrafficLight {
color: TrafficLightColor, // color: TrafficLightColor,
window_has_focus: bool, // window_has_focus: bool,
} // }
impl<V: 'static> Component<V> for TrafficLight { // impl Component for TrafficLight {
type Rendered = Div<V>; // type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { // fn render(self, cx: &mut WindowContext) -> Self::Rendered {
let system_colors = &cx.theme().styles.system; // let system_colors = &cx.theme().styles.system;
let fill = match (self.window_has_focus, self.color) { // let fill = match (self.window_has_focus, self.color) {
(true, TrafficLightColor::Red) => system_colors.mac_os_traffic_light_red, // (true, TrafficLightColor::Red) => system_colors.mac_os_traffic_light_red,
(true, TrafficLightColor::Yellow) => system_colors.mac_os_traffic_light_yellow, // (true, TrafficLightColor::Yellow) => system_colors.mac_os_traffic_light_yellow,
(true, TrafficLightColor::Green) => system_colors.mac_os_traffic_light_green, // (true, TrafficLightColor::Green) => system_colors.mac_os_traffic_light_green,
(false, _) => cx.theme().colors().element_background, // (false, _) => cx.theme().colors().element_background,
}; // };
div().w_3().h_3().rounded_full().bg(fill) // div().w_3().h_3().rounded_full().bg(fill)
} // }
} // }
impl TrafficLight { // impl TrafficLight {
fn new(color: TrafficLightColor, window_has_focus: bool) -> Self { // fn new(color: TrafficLightColor, window_has_focus: bool) -> Self {
Self { // Self {
color, // color,
window_has_focus, // window_has_focus,
} // }
} // }
} // }
#[derive(RenderOnce)] // #[derive(RenderOnce)]
pub struct TrafficLights { // pub struct TrafficLights {
window_has_focus: bool, // window_has_focus: bool,
} // }
impl<V: 'static> Component<V> for TrafficLights { // impl Component for TrafficLights {
type Rendered = Div<V>; // type Rendered = Div;
fn render(self, view: &mut V, cx: &mut ViewContext<V>) -> Self::Rendered { // fn render(self, cx: &mut WindowContext) -> Self::Rendered {
div() // div()
.flex() // .flex()
.items_center() // .items_center()
.gap_2() // .gap_2()
.child(TrafficLight::new( // .child(TrafficLight::new(
TrafficLightColor::Red, // TrafficLightColor::Red,
self.window_has_focus, // self.window_has_focus,
)) // ))
.child(TrafficLight::new( // .child(TrafficLight::new(
TrafficLightColor::Yellow, // TrafficLightColor::Yellow,
self.window_has_focus, // self.window_has_focus,
)) // ))
.child(TrafficLight::new( // .child(TrafficLight::new(
TrafficLightColor::Green, // TrafficLightColor::Green,
self.window_has_focus, // self.window_has_focus,
)) // ))
} // }
} // }
impl TrafficLights { // impl TrafficLights {
pub fn new() -> Self { // pub fn new() -> Self {
Self { // Self {
window_has_focus: true, // window_has_focus: true,
} // }
} // }
pub fn window_has_focus(mut self, window_has_focus: bool) -> Self { // pub fn window_has_focus(mut self, window_has_focus: bool) -> Self {
self.window_has_focus = window_has_focus; // self.window_has_focus = window_has_focus;
self // self
} // }
} // }
use gpui::{Div, RenderOnce}; // use gpui::{Div, RenderOnce};
#[cfg(feature = "stories")] // #[cfg(feature = "stories")]
pub use stories::*; // pub use stories::*;
#[cfg(feature = "stories")] // #[cfg(feature = "stories")]
mod stories { // mod stories {
use gpui::{Div, Render}; // use gpui::{Div, Render};
use crate::Story; // use crate::Story;
use super::*; // use super::*;
pub struct TrafficLightsStory; // pub struct TrafficLightsStory;
impl Render<Self> for TrafficLightsStory { // impl Render for TrafficLightsStory {
type Element = Div<Self>; // type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { // fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
Story::container(cx) // Story::container(cx)
.child(Story::title_for::<_, TrafficLights>(cx)) // .child(Story::title_for::<TrafficLights>(cx))
.child(Story::label(cx, "Default")) // .child(Story::label(cx, "Default"))
.child(TrafficLights::new()) // .child(TrafficLights::new())
.child(Story::label(cx, "Unfocused")) // .child(Story::label(cx, "Unfocused"))
.child(TrafficLights::new().window_has_focus(false)) // .child(TrafficLights::new().window_has_focus(false))
} // }
} // }
} // }

View file

@ -1,398 +1,398 @@
use std::sync::Arc; // use std::sync::Arc;
use chrono::DateTime; // use chrono::DateTime;
use gpui::{px, relative, Div, Render, RenderOnce, Size, View, VisualContext}; // use gpui::{px, relative, Div, Render, RenderOnce, Size, View, VisualContext};
use settings2::Settings; // use settings2::Settings;
use theme2::ThemeSettings; // use theme2::ThemeSettings;
use crate::prelude::*; // use crate::prelude::*;
use crate::{ // use crate::{
static_livestream, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, Checkbox, // static_livestream, v_stack, AssistantPanel, Button, ChatMessage, ChatPanel, Checkbox,
CollabPanel, EditorPane, Label, LanguageSelector, NotificationsPanel, Pane, PaneGroup, Panel, // CollabPanel, EditorPane, Label, LanguageSelector, NotificationsPanel, Pane, PaneGroup, Panel,
PanelAllowedSides, PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar, // PanelAllowedSides, PanelSide, ProjectPanel, SplitDirection, StatusBar, Terminal, TitleBar,
Toast, ToastOrigin, // Toast, ToastOrigin,
}; // };
#[derive(Clone)] // #[derive(Clone)]
pub struct Gpui2UiDebug { // pub struct Gpui2UiDebug {
pub in_livestream: bool, // pub in_livestream: bool,
pub enable_user_settings: bool, // pub enable_user_settings: bool,
pub show_toast: bool, // pub show_toast: bool,
} // }
impl Default for Gpui2UiDebug { // impl Default for Gpui2UiDebug {
fn default() -> Self { // fn default() -> Self {
Self { // Self {
in_livestream: false, // in_livestream: false,
enable_user_settings: false, // enable_user_settings: false,
show_toast: false, // show_toast: false,
} // }
} // }
} // }
#[derive(Clone)] // #[derive(Clone)]
pub struct Workspace { // pub struct Workspace {
title_bar: View<TitleBar>, // title_bar: View<TitleBar>,
editor_1: View<EditorPane>, // editor_1: View<EditorPane>,
show_project_panel: bool, // show_project_panel: bool,
show_collab_panel: bool, // show_collab_panel: bool,
show_chat_panel: bool, // show_chat_panel: bool,
show_assistant_panel: bool, // show_assistant_panel: bool,
show_notifications_panel: bool, // show_notifications_panel: bool,
show_terminal: bool, // show_terminal: bool,
show_debug: bool, // show_debug: bool,
show_language_selector: bool, // show_language_selector: bool,
test_checkbox_selection: Selection, // test_checkbox_selection: Selection,
debug: Gpui2UiDebug, // debug: Gpui2UiDebug,
} // }
impl Workspace { // impl Workspace {
pub fn new(cx: &mut ViewContext<Self>) -> Self { // pub fn new(cx: &mut ViewContext<Self>) -> Self {
Self { // Self {
title_bar: TitleBar::view(cx, None), // title_bar: TitleBar::view(cx, None),
editor_1: EditorPane::view(cx), // editor_1: EditorPane::view(cx),
show_project_panel: true, // show_project_panel: true,
show_collab_panel: false, // show_collab_panel: false,
show_chat_panel: false, // show_chat_panel: false,
show_assistant_panel: false, // show_assistant_panel: false,
show_terminal: true, // show_terminal: true,
show_language_selector: false, // show_language_selector: false,
show_debug: false, // show_debug: false,
show_notifications_panel: true, // show_notifications_panel: true,
test_checkbox_selection: Selection::Unselected, // test_checkbox_selection: Selection::Unselected,
debug: Gpui2UiDebug::default(), // debug: Gpui2UiDebug::default(),
} // }
} // }
pub fn is_project_panel_open(&self) -> bool { // pub fn is_project_panel_open(&self) -> bool {
self.show_project_panel // self.show_project_panel
} // }
pub fn toggle_project_panel(&mut self, cx: &mut ViewContext<Self>) { // pub fn toggle_project_panel(&mut self, cx: &mut ViewContext<Self>) {
self.show_project_panel = !self.show_project_panel; // self.show_project_panel = !self.show_project_panel;
self.show_collab_panel = false; // self.show_collab_panel = false;
cx.notify(); // cx.notify();
} // }
pub fn is_collab_panel_open(&self) -> bool { // pub fn is_collab_panel_open(&self) -> bool {
self.show_collab_panel // self.show_collab_panel
} // }
pub fn toggle_collab_panel(&mut self) { // pub fn toggle_collab_panel(&mut self) {
self.show_collab_panel = !self.show_collab_panel; // self.show_collab_panel = !self.show_collab_panel;
self.show_project_panel = false; // self.show_project_panel = false;
} // }
pub fn is_terminal_open(&self) -> bool { // pub fn is_terminal_open(&self) -> bool {
self.show_terminal // self.show_terminal
} // }
pub fn toggle_terminal(&mut self, cx: &mut ViewContext<Self>) { // pub fn toggle_terminal(&mut self, cx: &mut ViewContext<Self>) {
self.show_terminal = !self.show_terminal; // self.show_terminal = !self.show_terminal;
cx.notify(); // cx.notify();
} // }
pub fn is_chat_panel_open(&self) -> bool { // pub fn is_chat_panel_open(&self) -> bool {
self.show_chat_panel // self.show_chat_panel
} // }
pub fn toggle_chat_panel(&mut self, cx: &mut ViewContext<Self>) { // pub fn toggle_chat_panel(&mut self, cx: &mut ViewContext<Self>) {
self.show_chat_panel = !self.show_chat_panel; // self.show_chat_panel = !self.show_chat_panel;
self.show_assistant_panel = false; // self.show_assistant_panel = false;
self.show_notifications_panel = false; // self.show_notifications_panel = false;
cx.notify(); // cx.notify();
} // }
pub fn is_notifications_panel_open(&self) -> bool { // pub fn is_notifications_panel_open(&self) -> bool {
self.show_notifications_panel // self.show_notifications_panel
} // }
pub fn toggle_notifications_panel(&mut self, cx: &mut ViewContext<Self>) { // pub fn toggle_notifications_panel(&mut self, cx: &mut ViewContext<Self>) {
self.show_notifications_panel = !self.show_notifications_panel; // self.show_notifications_panel = !self.show_notifications_panel;
self.show_chat_panel = false; // self.show_chat_panel = false;
self.show_assistant_panel = false; // self.show_assistant_panel = false;
cx.notify(); // cx.notify();
} // }
pub fn is_assistant_panel_open(&self) -> bool { // pub fn is_assistant_panel_open(&self) -> bool {
self.show_assistant_panel // self.show_assistant_panel
} // }
pub fn toggle_assistant_panel(&mut self, cx: &mut ViewContext<Self>) { // pub fn toggle_assistant_panel(&mut self, cx: &mut ViewContext<Self>) {
self.show_assistant_panel = !self.show_assistant_panel; // self.show_assistant_panel = !self.show_assistant_panel;
self.show_chat_panel = false; // self.show_chat_panel = false;
self.show_notifications_panel = false; // self.show_notifications_panel = false;
cx.notify(); // cx.notify();
} // }
pub fn is_language_selector_open(&self) -> bool { // pub fn is_language_selector_open(&self) -> bool {
self.show_language_selector // self.show_language_selector
} // }
pub fn toggle_language_selector(&mut self, cx: &mut ViewContext<Self>) { // pub fn toggle_language_selector(&mut self, cx: &mut ViewContext<Self>) {
self.show_language_selector = !self.show_language_selector; // self.show_language_selector = !self.show_language_selector;
cx.notify(); // cx.notify();
} // }
pub fn toggle_debug(&mut self, cx: &mut ViewContext<Self>) { // pub fn toggle_debug(&mut self, cx: &mut ViewContext<Self>) {
self.show_debug = !self.show_debug; // self.show_debug = !self.show_debug;
cx.notify(); // cx.notify();
} // }
pub fn debug_toggle_user_settings(&mut self, cx: &mut ViewContext<Self>) { // pub fn debug_toggle_user_settings(&mut self, cx: &mut ViewContext<Self>) {
self.debug.enable_user_settings = !self.debug.enable_user_settings; // self.debug.enable_user_settings = !self.debug.enable_user_settings;
let mut theme_settings = ThemeSettings::get_global(cx).clone(); // let mut theme_settings = ThemeSettings::get_global(cx).clone();
if self.debug.enable_user_settings { // if self.debug.enable_user_settings {
theme_settings.ui_font_size = 18.0.into(); // theme_settings.ui_font_size = 18.0.into();
} else { // } else {
theme_settings.ui_font_size = 16.0.into(); // theme_settings.ui_font_size = 16.0.into();
} // }
ThemeSettings::override_global(theme_settings.clone(), cx); // ThemeSettings::override_global(theme_settings.clone(), cx);
cx.set_rem_size(theme_settings.ui_font_size); // cx.set_rem_size(theme_settings.ui_font_size);
cx.notify(); // cx.notify();
} // }
pub fn debug_toggle_livestream(&mut self, cx: &mut ViewContext<Self>) { // pub fn debug_toggle_livestream(&mut self, cx: &mut ViewContext<Self>) {
self.debug.in_livestream = !self.debug.in_livestream; // self.debug.in_livestream = !self.debug.in_livestream;
self.title_bar = TitleBar::view( // self.title_bar = TitleBar::view(
cx, // cx,
Some(static_livestream()).filter(|_| self.debug.in_livestream), // Some(static_livestream()).filter(|_| self.debug.in_livestream),
); // );
cx.notify(); // cx.notify();
} // }
pub fn debug_toggle_toast(&mut self, cx: &mut ViewContext<Self>) { // pub fn debug_toggle_toast(&mut self, cx: &mut ViewContext<Self>) {
self.debug.show_toast = !self.debug.show_toast; // self.debug.show_toast = !self.debug.show_toast;
cx.notify(); // cx.notify();
} // }
pub fn view(cx: &mut WindowContext) -> View<Self> { // pub fn view(cx: &mut WindowContext) -> View<Self> {
cx.build_view(|cx| Self::new(cx)) // cx.build_view(|cx| Self::new(cx))
} // }
} // }
impl Render<Self> for Workspace { // impl Render for Workspace {
type Element = Div<Self>; // type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Div<Self> { // fn render(&mut self, cx: &mut WindowContext) -> Div {
let root_group = PaneGroup::new_panes( // let root_group = PaneGroup::new_panes(
vec![Pane::new( // vec![Pane::new(
"pane-0", // "pane-0",
Size { // Size {
width: relative(1.).into(), // width: relative(1.).into(),
height: relative(1.).into(), // height: relative(1.).into(),
}, // },
) // )
.child(self.editor_1.clone())], // .child(self.editor_1.clone())],
SplitDirection::Horizontal, // SplitDirection::Horizontal,
); // );
let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone(); // let ui_font = ThemeSettings::get_global(cx).ui_font.family.clone();
div() // div()
.relative() // .relative()
.size_full() // .size_full()
.flex() // .flex()
.flex_col() // .flex_col()
.font(ui_font) // .font(ui_font)
.gap_0() // .gap_0()
.justify_start() // .justify_start()
.items_start() // .items_start()
.text_color(cx.theme().colors().text) // .text_color(cx.theme().colors().text)
.bg(cx.theme().colors().background) // .bg(cx.theme().colors().background)
.child(self.title_bar.clone()) // .child(self.title_bar.clone())
.child( // .child(
div() // div()
.absolute() // .absolute()
.top_12() // .top_12()
.left_12() // .left_12()
.z_index(99) // .z_index(99)
.bg(cx.theme().colors().background) // .bg(cx.theme().colors().background)
.child( // .child(
Checkbox::new("test_checkbox", self.test_checkbox_selection).on_click( // Checkbox::new("test_checkbox", self.test_checkbox_selection).on_click(
|selection, workspace: &mut Workspace, cx| { // |selection, workspace: &mut Workspace, cx| {
workspace.test_checkbox_selection = selection; // workspace.test_checkbox_selection = selection;
cx.notify(); // cx.notify();
}, // },
), // ),
), // ),
) // )
.child( // .child(
div() // div()
.flex_1() // .flex_1()
.w_full() // .w_full()
.flex() // .flex()
.flex_row() // .flex_row()
.overflow_hidden() // .overflow_hidden()
.border_t() // .border_t()
.border_b() // .border_b()
.border_color(cx.theme().colors().border) // .border_color(cx.theme().colors().border)
.children( // .children(
Some( // Some(
Panel::new("project-panel-outer", cx) // Panel::new("project-panel-outer", cx)
.side(PanelSide::Left) // .side(PanelSide::Left)
.child(ProjectPanel::new("project-panel-inner")), // .child(ProjectPanel::new("project-panel-inner")),
) // )
.filter(|_| self.is_project_panel_open()), // .filter(|_| self.is_project_panel_open()),
) // )
.children( // .children(
Some( // Some(
Panel::new("collab-panel-outer", cx) // Panel::new("collab-panel-outer", cx)
.child(CollabPanel::new("collab-panel-inner")) // .child(CollabPanel::new("collab-panel-inner"))
.side(PanelSide::Left), // .side(PanelSide::Left),
) // )
.filter(|_| self.is_collab_panel_open()), // .filter(|_| self.is_collab_panel_open()),
) // )
// .child(NotificationToast::new( // // .child(NotificationToast::new(
// "maxbrunsfeld has requested to add you as a contact.".into(), // // "maxbrunsfeld has requested to add you as a contact.".into(),
// )) // // ))
.child( // .child(
v_stack() // v_stack()
.flex_1() // .flex_1()
.h_full() // .h_full()
.child(div().flex().flex_1().child(root_group)) // .child(div().flex().flex_1().child(root_group))
.children( // .children(
Some( // Some(
Panel::new("terminal-panel", cx) // Panel::new("terminal-panel", cx)
.child(Terminal::new()) // .child(Terminal::new())
.allowed_sides(PanelAllowedSides::BottomOnly) // .allowed_sides(PanelAllowedSides::BottomOnly)
.side(PanelSide::Bottom), // .side(PanelSide::Bottom),
) // )
.filter(|_| self.is_terminal_open()), // .filter(|_| self.is_terminal_open()),
), // ),
) // )
.children( // .children(
Some( // Some(
Panel::new("chat-panel-outer", cx) // Panel::new("chat-panel-outer", cx)
.side(PanelSide::Right) // .side(PanelSide::Right)
.child(ChatPanel::new("chat-panel-inner").messages(vec![ // .child(ChatPanel::new("chat-panel-inner").messages(vec![
ChatMessage::new( // ChatMessage::new(
"osiewicz".to_string(), // "osiewicz".to_string(),
"is this thing on?".to_string(), // "is this thing on?".to_string(),
DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z") // DateTime::parse_from_rfc3339("2023-09-27T15:40:52.707Z")
.unwrap() // .unwrap()
.naive_local(), // .naive_local(),
), // ),
ChatMessage::new( // ChatMessage::new(
"maxdeviant".to_string(), // "maxdeviant".to_string(),
"Reading you loud and clear!".to_string(), // "Reading you loud and clear!".to_string(),
DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z") // DateTime::parse_from_rfc3339("2023-09-28T15:40:52.707Z")
.unwrap() // .unwrap()
.naive_local(), // .naive_local(),
), // ),
])), // ])),
) // )
.filter(|_| self.is_chat_panel_open()), // .filter(|_| self.is_chat_panel_open()),
) // )
.children( // .children(
Some( // Some(
Panel::new("notifications-panel-outer", cx) // Panel::new("notifications-panel-outer", cx)
.side(PanelSide::Right) // .side(PanelSide::Right)
.child(NotificationsPanel::new("notifications-panel-inner")), // .child(NotificationsPanel::new("notifications-panel-inner")),
) // )
.filter(|_| self.is_notifications_panel_open()), // .filter(|_| self.is_notifications_panel_open()),
) // )
.children( // .children(
Some( // Some(
Panel::new("assistant-panel-outer", cx) // Panel::new("assistant-panel-outer", cx)
.child(AssistantPanel::new("assistant-panel-inner")), // .child(AssistantPanel::new("assistant-panel-inner")),
) // )
.filter(|_| self.is_assistant_panel_open()), // .filter(|_| self.is_assistant_panel_open()),
), // ),
) // )
.child(StatusBar::new()) // .child(StatusBar::new())
.when(self.debug.show_toast, |this| { // .when(self.debug.show_toast, |this| {
this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast"))) // this.child(Toast::new(ToastOrigin::Bottom).child(Label::new("A toast")))
}) // })
.children( // .children(
Some( // Some(
div() // div()
.absolute() // .absolute()
.top(px(50.)) // .top(px(50.))
.left(px(640.)) // .left(px(640.))
.z_index(8) // .z_index(8)
.child(LanguageSelector::new("language-selector")), // .child(LanguageSelector::new("language-selector")),
) // )
.filter(|_| self.is_language_selector_open()), // .filter(|_| self.is_language_selector_open()),
) // )
.z_index(8) // .z_index(8)
// Debug // // Debug
.child( // .child(
v_stack() // v_stack()
.z_index(9) // .z_index(9)
.absolute() // .absolute()
.top_20() // .top_20()
.left_1_4() // .left_1_4()
.w_40() // .w_40()
.gap_2() // .gap_2()
.when(self.show_debug, |this| { // .when(self.show_debug, |this| {
this.child(Button::<Workspace>::new("Toggle User Settings").on_click( // this.child(Button::<Workspace>::new("Toggle User Settings").on_click(
Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)), // Arc::new(|workspace, cx| workspace.debug_toggle_user_settings(cx)),
)) // ))
.child( // .child(
Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new( // Button::<Workspace>::new("Toggle Toasts").on_click(Arc::new(
|workspace, cx| workspace.debug_toggle_toast(cx), // |workspace, cx| workspace.debug_toggle_toast(cx),
)), // )),
) // )
.child( // .child(
Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new( // Button::<Workspace>::new("Toggle Livestream").on_click(Arc::new(
|workspace, cx| workspace.debug_toggle_livestream(cx), // |workspace, cx| workspace.debug_toggle_livestream(cx),
)), // )),
) // )
}) // })
.child( // .child(
Button::<Workspace>::new("Toggle Debug") // Button::<Workspace>::new("Toggle Debug")
.on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))), // .on_click(Arc::new(|workspace, cx| workspace.toggle_debug(cx))),
), // ),
) // )
} // }
} // }
#[cfg(feature = "stories")] // #[cfg(feature = "stories")]
pub use stories::*; // pub use stories::*;
#[cfg(feature = "stories")] // #[cfg(feature = "stories")]
mod stories { // mod stories {
use super::*; // use super::*;
use gpui::VisualContext; // use gpui::VisualContext;
pub struct WorkspaceStory { // pub struct WorkspaceStory {
workspace: View<Workspace>, // workspace: View<Workspace>,
} // }
impl WorkspaceStory { // impl WorkspaceStory {
pub fn view(cx: &mut WindowContext) -> View<Self> { // pub fn view(cx: &mut WindowContext) -> View<Self> {
cx.build_view(|cx| Self { // cx.build_view(|cx| Self {
workspace: Workspace::view(cx), // workspace: Workspace::view(cx),
}) // })
} // }
} // }
impl Render<Self> for WorkspaceStory { // impl Render for WorkspaceStory {
type Element = Div<Self>; // type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { // fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div().child(self.workspace.clone()) // div().child(self.workspace.clone())
} // }
} // }
} // }

View file

@ -8,9 +8,7 @@ use schemars::JsonSchema;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use std::sync::Arc; use std::sync::Arc;
use theme2::ActiveTheme; use theme2::ActiveTheme;
use ui::{ use ui::{h_stack, menu_handle, ContextMenu, IconButton, InteractionState, Tooltip};
h_stack, menu_handle, ContextMenu, IconButton, InteractionState, Label, ListEntry, Tooltip,
};
pub enum PanelEvent { pub enum PanelEvent {
ChangePosition, ChangePosition,
@ -476,8 +474,8 @@ impl Dock {
} }
} }
impl Render<Self> for Dock { impl Render for Dock {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
if let Some(entry) = self.visible_entry() { if let Some(entry) = self.visible_entry() {
@ -662,8 +660,8 @@ impl PanelButtons {
// } // }
// here be kittens // here be kittens
impl Render<Self> for PanelButtons { impl Render for PanelButtons {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
// todo!() // todo!()
@ -688,45 +686,50 @@ impl Render<Self> for PanelButtons {
let name = entry.panel.persistent_name(); let name = entry.panel.persistent_name();
let panel = entry.panel.clone(); let panel = entry.panel.clone();
let mut button: IconButton<Self> = if i == active_index && is_open { let mut button: IconButton = if i == active_index && is_open {
let action = dock.toggle_action(); let action = dock.toggle_action();
let tooltip: SharedString = let tooltip: SharedString =
format!("Close {} dock", dock.position.to_label()).into(); format!("Close {} dock", dock.position.to_label()).into();
IconButton::new(name, icon) IconButton::new(name, icon)
.state(InteractionState::Active) .state(InteractionState::Active)
.action(action.boxed_clone()) .action(action.boxed_clone())
.tooltip(move |_, cx| Tooltip::for_action(tooltip.clone(), &*action, cx)) .tooltip(move |cx| Tooltip::for_action(tooltip.clone(), &*action, cx))
} else { } else {
let action = entry.panel.toggle_action(cx); let action = entry.panel.toggle_action(cx);
IconButton::new(name, icon) IconButton::new(name, icon)
.action(action.boxed_clone()) .action(action.boxed_clone())
.tooltip(move |_, cx| Tooltip::for_action(name, &*action, cx)) .tooltip(move |cx| Tooltip::for_action(name, &*action, cx))
}; };
Some( Some(
menu_handle(name) menu_handle(name)
.menu(move |_, cx| { .menu(move |cx| {
const POSITIONS: [DockPosition; 3] = [ const POSITIONS: [DockPosition; 3] = [
DockPosition::Left, DockPosition::Left,
DockPosition::Right, DockPosition::Right,
DockPosition::Bottom, DockPosition::Bottom,
]; ];
//CX: Pane
ContextMenu::build(cx, |mut menu, cx| { ContextMenu::build(cx, |mut menu, cx| {
// CX: Menu
for position in POSITIONS { for position in POSITIONS {
if position != dock_position if position != dock_position
&& panel.position_is_valid(position, cx) && panel.position_is_valid(position, cx)
{ {
let panel = panel.clone(); // let panel = panel.clone();
menu = menu.entry( todo!()
ListEntry::new(Label::new(format!( // menu = menu.entry(
"Dock {}", // ListEntry::new(Label::new(format!(
position.to_label() // "Dock {}",
))), // position.to_label()
move |_, cx| { // ))),
panel.set_position(position, cx); // cx.listener(move |_, cx| {
}, // //What should CX be? CX: Pane
) // panel.set_position(position, cx);
// }),
//)
} }
} }
menu menu
@ -780,8 +783,8 @@ pub mod test {
} }
} }
impl Render<Self> for TestPanel { impl Render for TestPanel {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
div() div()

View file

@ -104,7 +104,7 @@ pub trait Item: FocusableView + EventEmitter<ItemEvent> {
fn tab_description(&self, _: usize, _: &AppContext) -> Option<SharedString> { fn tab_description(&self, _: usize, _: &AppContext) -> Option<SharedString> {
None None
} }
fn tab_content<V: 'static>(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<V>; fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement;
/// (model id, Item) /// (model id, Item)
fn for_each_project_item( fn for_each_project_item(
@ -214,8 +214,8 @@ pub trait ItemHandle: 'static + Send {
) -> gpui::Subscription; ) -> gpui::Subscription;
fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString>; fn tab_tooltip_text(&self, cx: &AppContext) -> Option<SharedString>;
fn tab_description(&self, detail: usize, cx: &AppContext) -> Option<SharedString>; fn tab_description(&self, detail: usize, cx: &AppContext) -> Option<SharedString>;
fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane>; fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement;
fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace>; fn dragged_tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement;
fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>; fn project_path(&self, cx: &AppContext) -> Option<ProjectPath>;
fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>; fn project_entry_ids(&self, cx: &AppContext) -> SmallVec<[ProjectEntryId; 3]>;
fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[EntityId; 3]>; fn project_item_model_ids(&self, cx: &AppContext) -> SmallVec<[EntityId; 3]>;
@ -307,11 +307,11 @@ impl<T: Item> ItemHandle for View<T> {
self.read(cx).tab_description(detail, cx) self.read(cx).tab_description(detail, cx)
} }
fn tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Pane> { fn tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement {
self.read(cx).tab_content(detail, cx) self.read(cx).tab_content(detail, cx)
} }
fn dragged_tab_content(&self, detail: Option<usize>, cx: &AppContext) -> AnyElement<Workspace> { fn dragged_tab_content(&self, detail: Option<usize>, cx: &WindowContext) -> AnyElement {
self.read(cx).tab_content(detail, cx) self.read(cx).tab_content(detail, cx)
} }

View file

@ -71,8 +71,8 @@ impl ModalLayer {
} }
} }
impl Render<Self> for ModalLayer { impl Render for ModalLayer {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let Some(active_modal) = &self.active_modal else { let Some(active_modal) = &self.active_modal else {
@ -97,11 +97,11 @@ impl Render<Self> for ModalLayer {
h_stack() h_stack()
// needed to prevent mouse events leaking to the // needed to prevent mouse events leaking to the
// UI below. // todo! for gpui3. // UI below. // todo! for gpui3.
.on_any_mouse_down(|_, _, cx| cx.stop_propagation()) .on_any_mouse_down(|_, cx| cx.stop_propagation())
.on_any_mouse_up(|_, _, cx| cx.stop_propagation()) .on_any_mouse_up(|_, cx| cx.stop_propagation())
.on_mouse_down_out(|this: &mut Self, event, cx| { .on_mouse_down_out(cx.listener(|this, _, cx| {
this.hide_modal(cx); this.hide_modal(cx);
}) }))
.child(active_modal.modal.clone()), .child(active_modal.modal.clone()),
), ),
) )

View file

@ -13,9 +13,9 @@ pub enum NotificationEvent {
Dismiss, Dismiss,
} }
pub trait Notification: EventEmitter<NotificationEvent> + Render<Self> {} pub trait Notification: EventEmitter<NotificationEvent> + Render {}
impl<V: EventEmitter<NotificationEvent> + Render<Self>> Notification for V {} impl<V: EventEmitter<NotificationEvent> + Render> Notification for V {}
pub trait NotificationHandle: Send { pub trait NotificationHandle: Send {
fn id(&self) -> EntityId; fn id(&self) -> EntityId;
@ -198,7 +198,7 @@ pub mod simple_message_notification {
enum NotificationMessage { enum NotificationMessage {
Text(Cow<'static, str>), Text(Cow<'static, str>),
Element(fn(TextStyle, &AppContext) -> AnyElement<MessageNotification>), Element(fn(TextStyle, &AppContext) -> AnyElement),
} }
pub struct MessageNotification { pub struct MessageNotification {
@ -222,7 +222,7 @@ pub mod simple_message_notification {
} }
pub fn new_element( pub fn new_element(
message: fn(TextStyle, &AppContext) -> AnyElement<MessageNotification>, message: fn(TextStyle, &AppContext) -> AnyElement,
) -> MessageNotification { ) -> MessageNotification {
Self { Self {
message: NotificationMessage::Element(message), message: NotificationMessage::Element(message),
@ -253,8 +253,8 @@ pub mod simple_message_notification {
// } // }
} }
impl Render<Self> for MessageNotification { impl Render for MessageNotification {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
todo!() todo!()

View file

@ -594,7 +594,7 @@ impl Pane {
self.items.iter() self.items.iter()
} }
pub fn items_of_type<T: Render<T>>(&self) -> impl '_ + Iterator<Item = View<T>> { pub fn items_of_type<T: Render>(&self) -> impl '_ + Iterator<Item = View<T>> {
self.items self.items
.iter() .iter()
.filter_map(|item| item.to_any().downcast().ok()) .filter_map(|item| item.to_any().downcast().ok())
@ -1344,7 +1344,7 @@ impl Pane {
item: &Box<dyn ItemHandle>, item: &Box<dyn ItemHandle>,
detail: usize, detail: usize,
cx: &mut ViewContext<'_, Pane>, cx: &mut ViewContext<'_, Pane>,
) -> impl RenderOnce<Self> { ) -> impl RenderOnce {
let label = item.tab_content(Some(detail), cx); let label = item.tab_content(Some(detail), cx);
let close_icon = || { let close_icon = || {
let id = item.item_id(); let id = item.item_id();
@ -1353,12 +1353,14 @@ impl Pane {
.id(item.item_id()) .id(item.item_id())
.invisible() .invisible()
.group_hover("", |style| style.visible()) .group_hover("", |style| style.visible())
.child(IconButton::new("close_tab", Icon::Close).on_click( .child(
move |pane: &mut Self, cx| { IconButton::new("close_tab", Icon::Close).on_click(cx.listener(
move |pane, _, cx| {
pane.close_item_by_id(id, SaveIntent::Close, cx) pane.close_item_by_id(id, SaveIntent::Close, cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
}, },
)) )),
)
}; };
let (text_color, tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index { let (text_color, tab_bg, tab_hover_bg, tab_active_bg) = match ix == self.active_item_index {
@ -1383,9 +1385,9 @@ impl Pane {
.id(item.item_id()) .id(item.item_id())
.cursor_pointer() .cursor_pointer()
.when_some(item.tab_tooltip_text(cx), |div, text| { .when_some(item.tab_tooltip_text(cx), |div, text| {
div.tooltip(move |_, cx| cx.build_view(|cx| Tooltip::new(text.clone())).into()) div.tooltip(move |cx| cx.build_view(|cx| Tooltip::new(text.clone())).into())
}) })
.on_click(move |v: &mut Self, e, cx| v.activate_item(ix, true, true, cx)) .on_click(cx.listener(move |v: &mut Self, e, cx| v.activate_item(ix, true, true, cx)))
// .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx)) // .on_drag(move |pane, cx| pane.render_tab(ix, item.boxed_clone(), detail, cx))
// .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target)) // .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))
// .on_drop(|_view, state: View<DraggedTab>, cx| { // .on_drop(|_view, state: View<DraggedTab>, cx| {
@ -1437,7 +1439,7 @@ impl Pane {
) )
} }
fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl RenderOnce<Self> { fn render_tab_bar(&mut self, cx: &mut ViewContext<'_, Pane>) -> impl RenderOnce {
div() div()
.group("tab_bar") .group("tab_bar")
.id("tab_bar") .id("tab_bar")
@ -1891,17 +1893,25 @@ impl FocusableView for Pane {
} }
} }
impl Render<Self> for Pane { impl Render for Pane {
type Element = Focusable<Self, Div<Self>>; type Element = Focusable<Div>;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
v_stack() v_stack()
.key_context("Pane") .key_context("Pane")
.track_focus(&self.focus_handle) .track_focus(&self.focus_handle)
.on_action(|pane: &mut Pane, _: &SplitLeft, cx| pane.split(SplitDirection::Left, cx)) .on_action(cx.listener(|pane: &mut Pane, _: &SplitLeft, cx| {
.on_action(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx)) pane.split(SplitDirection::Left, cx)
.on_action(|pane: &mut Pane, _: &SplitRight, cx| pane.split(SplitDirection::Right, cx)) }))
.on_action(|pane: &mut Pane, _: &SplitDown, cx| pane.split(SplitDirection::Down, cx)) .on_action(
cx.listener(|pane: &mut Pane, _: &SplitUp, cx| pane.split(SplitDirection::Up, cx)),
)
.on_action(cx.listener(|pane: &mut Pane, _: &SplitRight, cx| {
pane.split(SplitDirection::Right, cx)
}))
.on_action(cx.listener(|pane: &mut Pane, _: &SplitDown, cx| {
pane.split(SplitDirection::Down, cx)
}))
// cx.add_action(Pane::toggle_zoom); // cx.add_action(Pane::toggle_zoom);
// cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| { // cx.add_action(|pane: &mut Pane, action: &ActivateItem, cx| {
// pane.activate_item(action.0, true, true, cx); // pane.activate_item(action.0, true, true, cx);
@ -1922,10 +1932,12 @@ impl Render<Self> for Pane {
// cx.add_async_action(Pane::close_items_to_the_right); // cx.add_async_action(Pane::close_items_to_the_right);
// cx.add_async_action(Pane::close_all_items); // cx.add_async_action(Pane::close_all_items);
.size_full() .size_full()
.on_action(|pane: &mut Self, action: &CloseActiveItem, cx| { .on_action(
cx.listener(|pane: &mut Self, action: &CloseActiveItem, cx| {
pane.close_active_item(action, cx) pane.close_active_item(action, cx)
.map(|task| task.detach_and_log_err(cx)); .map(|task| task.detach_and_log_err(cx));
}) }),
)
.child(self.render_tab_bar(cx)) .child(self.render_tab_bar(cx))
// .child( // .child(
// div() // div()
@ -2947,8 +2959,8 @@ struct DraggedTab {
title: String, title: String,
} }
impl Render<Self> for DraggedTab { impl Render for DraggedTab {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div().w_8().h_4().bg(gpui::red()) div().w_8().h_4().bg(gpui::red())

View file

@ -132,7 +132,7 @@ impl PaneGroup {
zoomed: Option<&AnyWeakView>, zoomed: Option<&AnyWeakView>,
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> impl RenderOnce<Workspace> { ) -> impl RenderOnce {
self.root.render( self.root.render(
project, project,
0, 0,
@ -204,7 +204,7 @@ impl Member {
zoomed: Option<&AnyWeakView>, zoomed: Option<&AnyWeakView>,
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> impl RenderOnce<Workspace> { ) -> impl RenderOnce {
match self { match self {
Member::Pane(pane) => { Member::Pane(pane) => {
// todo!() // todo!()
@ -561,7 +561,7 @@ impl PaneAxis {
zoomed: Option<&AnyWeakView>, zoomed: Option<&AnyWeakView>,
app_state: &Arc<AppState>, app_state: &Arc<AppState>,
cx: &mut ViewContext<Workspace>, cx: &mut ViewContext<Workspace>,
) -> Div<Workspace> { ) -> Div {
debug_assert!(self.members.len() == self.flexes.lock().len()); debug_assert!(self.members.len() == self.flexes.lock().len());
div() div()

View file

@ -9,7 +9,7 @@ use theme2::ActiveTheme;
use ui::h_stack; use ui::h_stack;
use util::ResultExt; use util::ResultExt;
pub trait StatusItemView: Render<Self> { pub trait StatusItemView: Render {
fn set_active_pane_item( fn set_active_pane_item(
&mut self, &mut self,
active_pane_item: Option<&dyn crate::ItemHandle>, active_pane_item: Option<&dyn crate::ItemHandle>,
@ -34,8 +34,8 @@ pub struct StatusBar {
_observe_active_pane: Subscription, _observe_active_pane: Subscription,
} }
impl Render<Self> for StatusBar { impl Render for StatusBar {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
div() div()
@ -53,14 +53,14 @@ impl Render<Self> for StatusBar {
} }
impl StatusBar { impl StatusBar {
fn render_left_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce<Self> { fn render_left_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce {
h_stack() h_stack()
.items_center() .items_center()
.gap_2() .gap_2()
.children(self.left_items.iter().map(|item| item.to_any())) .children(self.left_items.iter().map(|item| item.to_any()))
} }
fn render_right_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce<Self> { fn render_right_tools(&self, cx: &mut ViewContext<Self>) -> impl RenderOnce {
h_stack() h_stack()
.items_center() .items_center()
.gap_2() .gap_2()

View file

@ -7,7 +7,7 @@ pub enum ToolbarItemEvent {
ChangeLocation(ToolbarItemLocation), ChangeLocation(ToolbarItemLocation),
} }
pub trait ToolbarItemView: Render<Self> + EventEmitter<ToolbarItemEvent> { pub trait ToolbarItemView: Render + EventEmitter<ToolbarItemEvent> {
fn set_active_pane_item( fn set_active_pane_item(
&mut self, &mut self,
active_pane_item: Option<&dyn crate::ItemHandle>, active_pane_item: Option<&dyn crate::ItemHandle>,
@ -51,8 +51,8 @@ pub struct Toolbar {
items: Vec<(Box<dyn ToolbarItemViewHandle>, ToolbarItemLocation)>, items: Vec<(Box<dyn ToolbarItemViewHandle>, ToolbarItemLocation)>,
} }
impl Render<Self> for Toolbar { impl Render for Toolbar {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
todo!() todo!()

View file

@ -411,7 +411,7 @@ pub enum Event {
pub struct Workspace { pub struct Workspace {
window_self: WindowHandle<Self>, window_self: WindowHandle<Self>,
weak_self: WeakView<Self>, weak_self: WeakView<Self>,
workspace_actions: Vec<Box<dyn Fn(Div<Workspace>) -> Div<Workspace>>>, workspace_actions: Vec<Box<dyn Fn(Div, &mut ViewContext<Self>) -> Div>>,
zoomed: Option<AnyWeakView>, zoomed: Option<AnyWeakView>,
zoomed_position: Option<DockPosition>, zoomed_position: Option<DockPosition>,
center: PaneGroup, center: PaneGroup,
@ -3204,53 +3204,63 @@ impl Workspace {
}) })
} }
fn actions(&self, div: Div<Self>) -> Div<Self> { fn actions(&self, div: Div, cx: &mut ViewContext<Self>) -> Div {
self.add_workspace_actions_listeners(div) self.add_workspace_actions_listeners(div, cx)
// cx.add_async_action(Workspace::open); // cx.add_async_action(Workspace::open);
// cx.add_async_action(Workspace::follow_next_collaborator); // cx.add_async_action(Workspace::follow_next_collaborator);
// cx.add_async_action(Workspace::close); // cx.add_async_action(Workspace::close);
.on_action(Self::close_inactive_items_and_panes) .on_action(cx.listener(Self::close_inactive_items_and_panes))
.on_action(Self::close_all_items_and_panes) .on_action(cx.listener(Self::close_all_items_and_panes))
// cx.add_global_action(Workspace::close_global); // cx.add_global_action(Workspace::close_global);
// cx.add_global_action(restart); // cx.add_global_action(restart);
.on_action(Self::save_all) .on_action(cx.listener(Self::save_all))
.on_action(Self::add_folder_to_project) .on_action(cx.listener(Self::add_folder_to_project))
.on_action(|workspace, _: &Unfollow, cx| { .on_action(cx.listener(|workspace, _: &Unfollow, cx| {
let pane = workspace.active_pane().clone(); let pane = workspace.active_pane().clone();
workspace.unfollow(&pane, cx); workspace.unfollow(&pane, cx);
}) }))
.on_action(|workspace, action: &Save, cx| { .on_action(cx.listener(|workspace, action: &Save, cx| {
workspace workspace
.save_active_item(action.save_intent.unwrap_or(SaveIntent::Save), cx) .save_active_item(action.save_intent.unwrap_or(SaveIntent::Save), cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
}) }))
.on_action(|workspace, _: &SaveAs, cx| { .on_action(cx.listener(|workspace, _: &SaveAs, cx| {
workspace workspace
.save_active_item(SaveIntent::SaveAs, cx) .save_active_item(SaveIntent::SaveAs, cx)
.detach_and_log_err(cx); .detach_and_log_err(cx);
}) }))
.on_action(|workspace, _: &ActivatePreviousPane, cx| { .on_action(cx.listener(|workspace, _: &ActivatePreviousPane, cx| {
workspace.activate_previous_pane(cx) workspace.activate_previous_pane(cx)
}) }))
.on_action(|workspace, _: &ActivateNextPane, cx| workspace.activate_next_pane(cx)) .on_action(
.on_action(|workspace, action: &ActivatePaneInDirection, cx| { cx.listener(|workspace, _: &ActivateNextPane, cx| workspace.activate_next_pane(cx)),
)
.on_action(
cx.listener(|workspace, action: &ActivatePaneInDirection, cx| {
workspace.activate_pane_in_direction(action.0, cx) workspace.activate_pane_in_direction(action.0, cx)
}) }),
.on_action(|workspace, action: &SwapPaneInDirection, cx| { )
.on_action(cx.listener(|workspace, action: &SwapPaneInDirection, cx| {
workspace.swap_pane_in_direction(action.0, cx) workspace.swap_pane_in_direction(action.0, cx)
}) }))
.on_action(|this, e: &ToggleLeftDock, cx| { .on_action(cx.listener(|this, e: &ToggleLeftDock, cx| {
this.toggle_dock(DockPosition::Left, cx); this.toggle_dock(DockPosition::Left, cx);
}) }))
.on_action(|workspace: &mut Workspace, _: &ToggleRightDock, cx| { .on_action(
cx.listener(|workspace: &mut Workspace, _: &ToggleRightDock, cx| {
workspace.toggle_dock(DockPosition::Right, cx); workspace.toggle_dock(DockPosition::Right, cx);
}) }),
.on_action(|workspace: &mut Workspace, _: &ToggleBottomDock, cx| { )
.on_action(
cx.listener(|workspace: &mut Workspace, _: &ToggleBottomDock, cx| {
workspace.toggle_dock(DockPosition::Bottom, cx); workspace.toggle_dock(DockPosition::Bottom, cx);
}) }),
.on_action(|workspace: &mut Workspace, _: &CloseAllDocks, cx| { )
.on_action(
cx.listener(|workspace: &mut Workspace, _: &CloseAllDocks, cx| {
workspace.close_all_docks(cx); workspace.close_all_docks(cx);
}) }),
)
// cx.add_action(Workspace::activate_pane_at_index); // cx.add_action(Workspace::activate_pane_at_index);
// cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| { // cx.add_action(|workspace: &mut Workspace, _: &ReopenClosedItem, cx| {
// workspace.reopen_closed_item(cx).detach(); // workspace.reopen_closed_item(cx).detach();
@ -3346,22 +3356,24 @@ impl Workspace {
) -> &mut Self { ) -> &mut Self {
let callback = Arc::new(callback); let callback = Arc::new(callback);
self.workspace_actions.push(Box::new(move |div| { self.workspace_actions.push(Box::new(move |div, cx| {
let callback = callback.clone(); let callback = callback.clone();
div.on_action(move |workspace, event, cx| (callback.clone())(workspace, event, cx)) div.on_action(
cx.listener(move |workspace, event, cx| (callback.clone())(workspace, event, cx)),
)
})); }));
self self
} }
fn add_workspace_actions_listeners(&self, mut div: Div<Workspace>) -> Div<Workspace> { fn add_workspace_actions_listeners(&self, mut div: Div, cx: &mut ViewContext<Self>) -> Div {
let mut div = div let mut div = div
.on_action(Self::close_inactive_items_and_panes) .on_action(cx.listener(Self::close_inactive_items_and_panes))
.on_action(Self::close_all_items_and_panes) .on_action(cx.listener(Self::close_all_items_and_panes))
.on_action(Self::add_folder_to_project) .on_action(cx.listener(Self::add_folder_to_project))
.on_action(Self::save_all) .on_action(cx.listener(Self::save_all))
.on_action(Self::open); .on_action(cx.listener(Self::open));
for action in self.workspace_actions.iter() { for action in self.workspace_actions.iter() {
div = (action)(div) div = (action)(div, cx)
} }
div div
} }
@ -3594,8 +3606,8 @@ impl FocusableView for Workspace {
} }
} }
impl Render<Self> for Workspace { impl Render for Workspace {
type Element = Div<Self>; type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element { fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
let mut context = KeyContext::default(); let mut context = KeyContext::default();
@ -3611,7 +3623,7 @@ impl Render<Self> for Workspace {
cx.set_rem_size(ui_font_size); cx.set_rem_size(ui_font_size);
self.actions(div()) self.actions(div(), cx)
.key_context(context) .key_context(context)
.relative() .relative()
.size_full() .size_full()