Detailed changes
@@ -331,7 +331,7 @@ impl AssistantPanel {
let measurements = Rc::new(Cell::new(BlockMeasurements::default()));
let inline_assistant = cx.build_view(|cx| {
- let assistant = InlineAssistant::new(
+ InlineAssistant::new(
inline_assist_id,
measurements.clone(),
self.include_conversation_in_next_inline_assist,
@@ -342,9 +342,7 @@ impl AssistantPanel {
self.retrieve_context_in_next_inline_assist,
self.semantic_index.clone(),
project.clone(),
- );
- assistant.focus_handle.focus(cx);
- assistant
+ )
});
let block_id = editor.update(cx, |editor, cx| {
editor.change_selections(None, cx, |selections| {
@@ -391,10 +389,7 @@ impl AssistantPanel {
if let Some(inline_assistant) = inline_assistant.upgrade() {
if let EditorEvent::SelectionsChanged { local } = event {
if *local
- && inline_assistant
- .read(cx)
- .focus_handle
- .contains_focused(cx)
+ && inline_assistant.focus_handle(cx).contains_focused(cx)
{
cx.focus_view(&editor);
}
@@ -553,9 +548,12 @@ impl AssistantPanel {
fn hide_inline_assist(&mut self, assist_id: usize, cx: &mut ViewContext<Self>) {
if let Some(pending_assist) = self.pending_inline_assists.get_mut(&assist_id) {
if let Some(editor) = pending_assist.editor.upgrade() {
- if let Some((block_id, _)) = pending_assist.inline_assistant.take() {
+ if let Some((block_id, inline_assistant)) = pending_assist.inline_assistant.take() {
editor.update(cx, |editor, cx| {
editor.remove_blocks(HashSet::from_iter([block_id]), None, cx);
+ if inline_assistant.focus_handle(cx).contains_focused(cx) {
+ editor.focus(cx);
+ }
});
}
}
@@ -891,8 +889,9 @@ impl AssistantPanel {
if search_bar.show(cx) {
search_bar.search_suggested(cx);
if action.focus {
+ let focus_handle = search_bar.focus_handle(cx);
search_bar.select_query(cx);
- cx.focus_self();
+ cx.focus(&focus_handle);
}
propagate = false
}
@@ -956,7 +955,7 @@ impl AssistantPanel {
}
fn render_split_button(cx: &mut ViewContext<Self>) -> impl IntoElement {
- IconButton::new("split_button", Icon::Menu)
+ IconButton::new("split_button", Icon::SplitMessage)
.on_click(cx.listener(|this, _event, cx| {
if let Some(active_editor) = this.active_editor() {
active_editor.update(cx, |editor, cx| editor.split(&Default::default(), cx));
@@ -966,7 +965,7 @@ impl AssistantPanel {
}
fn render_assist_button(cx: &mut ViewContext<Self>) -> impl IntoElement {
- IconButton::new("assist_button", Icon::Menu)
+ IconButton::new("assist_button", Icon::MagicWand)
.on_click(cx.listener(|this, _event, cx| {
if let Some(active_editor) = this.active_editor() {
active_editor.update(cx, |editor, cx| editor.assist(&Default::default(), cx));
@@ -976,7 +975,7 @@ impl AssistantPanel {
}
fn render_quote_button(cx: &mut ViewContext<Self>) -> impl IntoElement {
- IconButton::new("quote_button", Icon::Menu)
+ IconButton::new("quote_button", Icon::Quote)
.on_click(cx.listener(|this, _event, cx| {
if let Some(workspace) = this.workspace.upgrade() {
cx.window_context().defer(move |cx| {
@@ -990,7 +989,7 @@ impl AssistantPanel {
}
fn render_plus_button(cx: &mut ViewContext<Self>) -> impl IntoElement {
- IconButton::new("plus_button", Icon::Menu)
+ IconButton::new("plus_button", Icon::Plus)
.on_click(cx.listener(|this, _event, cx| {
this.new_conversation(cx);
}))
@@ -999,7 +998,7 @@ impl AssistantPanel {
fn render_zoom_button(&self, cx: &mut ViewContext<Self>) -> impl IntoElement {
let zoomed = self.zoomed;
- IconButton::new("zoom_button", Icon::Menu)
+ IconButton::new("zoom_button", Icon::MagnifyingGlass)
.on_click(cx.listener(|this, _event, cx| {
this.toggle_zoom(&ToggleZoom, cx);
}))
@@ -1028,6 +1027,8 @@ impl AssistantPanel {
}
fn open_conversation(&mut self, path: PathBuf, cx: &mut ViewContext<Self>) -> Task<Result<()>> {
+ cx.focus(&self.focus_handle);
+
if let Some(ix) = self.editor_index_for_path(&path, cx) {
self.set_active_editor_index(Some(ix), cx);
return Task::ready(Ok(()));
@@ -2026,7 +2027,6 @@ struct ConversationEditor {
editor: View<Editor>,
blocks: HashSet<BlockId>,
scroll_position: Option<ScrollPosition>,
- focus_handle: FocusHandle,
_subscriptions: Vec<Subscription>,
}
@@ -2057,13 +2057,10 @@ impl ConversationEditor {
editor
});
- let focus_handle = cx.focus_handle();
-
let _subscriptions = vec![
cx.observe(&conversation, |_, _, cx| cx.notify()),
cx.subscribe(&conversation, Self::handle_conversation_event),
cx.subscribe(&editor, Self::handle_editor_event),
- cx.on_focus(&focus_handle, |this, cx| cx.focus_view(&this.editor)),
];
let mut this = Self {
@@ -2073,7 +2070,6 @@ impl ConversationEditor {
scroll_position: None,
fs,
workspace,
- focus_handle,
_subscriptions,
};
this.update_message_headers(cx);
@@ -2484,8 +2480,8 @@ impl Render for ConversationEditor {
}
impl FocusableView for ConversationEditor {
- fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
- self.focus_handle.clone()
+ fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
+ self.editor.focus_handle(cx)
}
}
@@ -2539,7 +2535,6 @@ struct InlineAssistant {
prompt_editor: View<Editor>,
workspace: WeakView<Workspace>,
confirmed: bool,
- focus_handle: FocusHandle,
include_conversation: bool,
measurements: Rc<Cell<BlockMeasurements>>,
prompt_history: VecDeque<String>,
@@ -2635,8 +2630,8 @@ impl Render for InlineAssistant {
}
impl FocusableView for InlineAssistant {
- fn focus_handle(&self, _cx: &AppContext) -> FocusHandle {
- self.focus_handle.clone()
+ fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
+ self.prompt_editor.focus_handle(cx)
}
}
@@ -2662,12 +2657,11 @@ impl InlineAssistant {
editor.set_placeholder_text(placeholder, cx);
editor
});
+ cx.focus_view(&prompt_editor);
- let focus_handle = cx.focus_handle();
let mut subscriptions = vec![
cx.observe(&codegen, Self::handle_codegen_changed),
cx.subscribe(&prompt_editor, Self::handle_prompt_editor_events),
- cx.on_focus(&focus_handle, |this, cx| cx.focus_view(&this.prompt_editor)),
];
if let Some(semantic_index) = semantic_index.clone() {
@@ -2679,7 +2673,6 @@ impl InlineAssistant {
prompt_editor,
workspace,
confirmed: false,
- focus_handle,
include_conversation,
measurements,
prompt_history,
@@ -1814,34 +1814,34 @@ impl Editor {
this
}
- fn dispatch_context(&self, cx: &AppContext) -> KeyContext {
- let mut dispatch_context = KeyContext::default();
- dispatch_context.add("Editor");
+ fn key_context(&self, cx: &AppContext) -> KeyContext {
+ let mut key_context = KeyContext::default();
+ key_context.add("Editor");
let mode = match self.mode {
EditorMode::SingleLine => "single_line",
EditorMode::AutoHeight { .. } => "auto_height",
EditorMode::Full => "full",
};
- dispatch_context.set("mode", mode);
+ key_context.set("mode", mode);
if self.pending_rename.is_some() {
- dispatch_context.add("renaming");
+ key_context.add("renaming");
}
if self.context_menu_visible() {
match self.context_menu.read().as_ref() {
Some(ContextMenu::Completions(_)) => {
- dispatch_context.add("menu");
- dispatch_context.add("showing_completions")
+ key_context.add("menu");
+ key_context.add("showing_completions")
}
Some(ContextMenu::CodeActions(_)) => {
- dispatch_context.add("menu");
- dispatch_context.add("showing_code_actions")
+ key_context.add("menu");
+ key_context.add("showing_code_actions")
}
None => {}
}
}
for layer in self.keymap_context_layers.values() {
- dispatch_context.extend(layer);
+ key_context.extend(layer);
}
if let Some(extension) = self
@@ -1850,10 +1850,10 @@ impl Editor {
.as_singleton()
.and_then(|buffer| buffer.read(cx).file()?.path().extension()?.to_str())
{
- dispatch_context.set("extension", extension.to_string());
+ key_context.set("extension", extension.to_string());
}
- dispatch_context
+ key_context
}
pub fn new_file(
@@ -275,36 +275,48 @@ impl EditorElement {
register_action(view, cx, Editor::copy_relative_path);
register_action(view, cx, Editor::copy_highlight_json);
register_action(view, cx, |editor, action, cx| {
- editor
- .format(action, cx)
- .map(|task| task.detach_and_log_err(cx));
+ if let Some(task) = editor.format(action, cx) {
+ task.detach_and_log_err(cx);
+ } else {
+ cx.propagate();
+ }
});
register_action(view, cx, Editor::restart_language_server);
register_action(view, cx, Editor::show_character_palette);
register_action(view, cx, |editor, action, cx| {
- editor
- .confirm_completion(action, cx)
- .map(|task| task.detach_and_log_err(cx));
+ if let Some(task) = editor.confirm_completion(action, cx) {
+ task.detach_and_log_err(cx);
+ } else {
+ cx.propagate();
+ }
});
register_action(view, cx, |editor, action, cx| {
- editor
- .confirm_code_action(action, cx)
- .map(|task| task.detach_and_log_err(cx));
+ if let Some(task) = editor.confirm_code_action(action, cx) {
+ task.detach_and_log_err(cx);
+ } else {
+ cx.propagate();
+ }
});
register_action(view, cx, |editor, action, cx| {
- editor
- .rename(action, cx)
- .map(|task| task.detach_and_log_err(cx));
+ if let Some(task) = editor.rename(action, cx) {
+ task.detach_and_log_err(cx);
+ } else {
+ cx.propagate();
+ }
});
register_action(view, cx, |editor, action, cx| {
- editor
- .confirm_rename(action, cx)
- .map(|task| task.detach_and_log_err(cx));
+ if let Some(task) = editor.confirm_rename(action, cx) {
+ task.detach_and_log_err(cx);
+ } else {
+ cx.propagate();
+ }
});
register_action(view, cx, |editor, action, cx| {
- editor
- .find_all_references(action, cx)
- .map(|task| task.detach_and_log_err(cx));
+ if let Some(task) = editor.find_all_references(action, cx) {
+ task.detach_and_log_err(cx);
+ } else {
+ cx.propagate();
+ }
});
register_action(view, cx, Editor::next_copilot_suggestion);
register_action(view, cx, Editor::previous_copilot_suggestion);
@@ -2802,49 +2814,38 @@ impl Element for EditorElement {
};
let focus_handle = editor.focus_handle(cx);
- let dispatch_context = self.editor.read(cx).dispatch_context(cx);
- cx.with_key_dispatch(
- Some(dispatch_context),
- Some(focus_handle.clone()),
- |_, cx| {
- self.register_actions(cx);
- self.register_key_listeners(cx);
-
- // We call with_z_index to establish a new stacking context.
- cx.with_z_index(0, |cx| {
- cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
- // Paint mouse listeners at z-index 0 so any elements we paint on top of the editor
- // take precedence.
- cx.with_z_index(0, |cx| {
- self.paint_mouse_listeners(
- bounds,
- gutter_bounds,
- text_bounds,
- &layout,
- cx,
- );
- });
- let input_handler =
- ElementInputHandler::new(bounds, self.editor.clone(), cx);
- cx.handle_input(&focus_handle, input_handler);
+ let key_context = self.editor.read(cx).key_context(cx);
+ cx.with_key_dispatch(Some(key_context), Some(focus_handle.clone()), |_, cx| {
+ self.register_actions(cx);
+ self.register_key_listeners(cx);
+
+ // We call with_z_index to establish a new stacking context.
+ cx.with_z_index(0, |cx| {
+ cx.with_content_mask(Some(ContentMask { bounds }), |cx| {
+ // Paint mouse listeners at z-index 0 so any elements we paint on top of the editor
+ // take precedence.
+ cx.with_z_index(0, |cx| {
+ self.paint_mouse_listeners(bounds, gutter_bounds, text_bounds, &layout, cx);
+ });
+ let input_handler = ElementInputHandler::new(bounds, self.editor.clone(), cx);
+ cx.handle_input(&focus_handle, input_handler);
- self.paint_background(gutter_bounds, text_bounds, &layout, cx);
- if layout.gutter_size.width > Pixels::ZERO {
- self.paint_gutter(gutter_bounds, &mut layout, cx);
- }
- self.paint_text(text_bounds, &mut layout, cx);
+ self.paint_background(gutter_bounds, text_bounds, &layout, cx);
+ if layout.gutter_size.width > Pixels::ZERO {
+ self.paint_gutter(gutter_bounds, &mut layout, cx);
+ }
+ self.paint_text(text_bounds, &mut layout, cx);
- if !layout.blocks.is_empty() {
- cx.with_z_index(1, |cx| {
- cx.with_element_id(Some("editor_blocks"), |cx| {
- self.paint_blocks(bounds, &mut layout, cx);
- })
+ if !layout.blocks.is_empty() {
+ cx.with_z_index(1, |cx| {
+ cx.with_element_id(Some("editor_blocks"), |cx| {
+ self.paint_blocks(bounds, &mut layout, cx);
})
- }
- });
+ })
+ }
});
- },
- )
+ });
+ })
}
}
@@ -704,14 +704,13 @@ impl AppContext {
let focus_changed = focused.is_some() || blurred.is_some();
let event = FocusEvent { focused, blurred };
- let mut listeners = mem::take(&mut cx.window.current_frame.focus_listeners);
+ let mut listeners = mem::take(&mut cx.window.rendered_frame.focus_listeners);
if focus_changed {
for listener in &mut listeners {
listener(&event, cx);
}
}
- listeners.extend(cx.window.current_frame.focus_listeners.drain(..));
- cx.window.current_frame.focus_listeners = listeners;
+ cx.window.rendered_frame.focus_listeners = listeners;
if focus_changed {
cx.window
@@ -1029,9 +1028,13 @@ impl AppContext {
window
.update(self, |_, cx| {
cx.window
- .current_frame
+ .rendered_frame
.dispatch_tree
- .clear_pending_keystrokes()
+ .clear_pending_keystrokes();
+ cx.window
+ .next_frame
+ .dispatch_tree
+ .clear_pending_keystrokes();
})
.ok();
}
@@ -1107,6 +1110,10 @@ impl AppContext {
}
}
}
+
+ pub fn has_active_drag(&self) -> bool {
+ self.active_drag.is_some()
+ }
}
impl Context for AppContext {
@@ -69,24 +69,6 @@ pub trait IntoElement: Sized {
self.map(|this| if condition { then(this) } else { this })
}
- fn when_else(
- self,
- condition: bool,
- then: impl FnOnce(Self) -> Self,
- otherwise: impl FnOnce(Self) -> Self,
- ) -> Self
- where
- Self: Sized,
- {
- self.map(|this| {
- if condition {
- then(this)
- } else {
- otherwise(this)
- }
- })
- }
-
fn when_some<T>(self, option: Option<T>, then: impl FnOnce(Self, T) -> Self) -> Self
where
Self: Sized,
@@ -193,6 +193,12 @@ impl Deref for MouseExitEvent {
#[derive(Debug, Clone, Default)]
pub struct ExternalPaths(pub(crate) SmallVec<[PathBuf; 2]>);
+impl ExternalPaths {
+ pub fn paths(&self) -> &[PathBuf] {
+ &self.0
+ }
+}
+
impl Render for ExternalPaths {
type Element = Div;
@@ -325,7 +325,7 @@ impl MetalRenderer {
.entry(tile.texture_id)
.or_insert(Vec::new())
.extend(path.vertices.iter().map(|vertex| PathVertex {
- xy_position: vertex.xy_position - path.bounds.origin
+ xy_position: vertex.xy_position - clipped_bounds.origin
+ tile.bounds.origin.map(Into::into),
st_position: vertex.st_position,
content_mask: ContentMask {
@@ -544,9 +544,10 @@ impl MetalRenderer {
if let Some((path, tile)) = paths_and_tiles.peek() {
if prev_texture_id.map_or(true, |texture_id| texture_id == tile.texture_id) {
prev_texture_id = Some(tile.texture_id);
+ let origin = path.bounds.intersect(&path.content_mask.bounds).origin;
sprites.push(PathSprite {
bounds: Bounds {
- origin: path.bounds.origin.map(|p| p.floor()),
+ origin: origin.map(|p| p.floor()),
size: tile.bounds.size.map(Into::into),
},
color: path.color,
@@ -4,12 +4,12 @@ use crate::{
DevicePixels, DispatchNodeId, DispatchTree, DisplayId, Edges, Effect, Entity, EntityId,
EventEmitter, FileDropEvent, Flatten, FocusEvent, FontId, GlobalElementId, GlyphId, Hsla,
ImageData, InputEvent, IsZero, KeyBinding, KeyContext, KeyDownEvent, LayoutId, Model,
- ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseDownEvent, MouseMoveEvent,
- MouseUpEvent, Path, Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler,
- PlatformWindow, Point, PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams,
- RenderImageParams, RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size,
- Style, SubscriberSet, Subscription, Surface, TaffyLayoutEngine, Task, Underline,
- UnderlineStyle, View, VisualContext, WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
+ ModelContext, Modifiers, MonochromeSprite, MouseButton, MouseMoveEvent, MouseUpEvent, Path,
+ Pixels, PlatformAtlas, PlatformDisplay, PlatformInputHandler, PlatformWindow, Point,
+ PolychromeSprite, PromptLevel, Quad, Render, RenderGlyphParams, RenderImageParams,
+ RenderSvgParams, ScaledPixels, SceneBuilder, Shadow, SharedString, Size, Style, SubscriberSet,
+ Subscription, Surface, TaffyLayoutEngine, Task, Underline, UnderlineStyle, View, VisualContext,
+ WeakView, WindowBounds, WindowOptions, SUBPIXEL_VARIANTS,
};
use anyhow::{anyhow, Context as _, Result};
use collections::HashMap;
@@ -90,7 +90,7 @@ impl FocusId {
/// Obtains whether this handle contains the given handle in the most recently rendered frame.
pub(crate) fn contains(&self, other: Self, cx: &WindowContext) -> bool {
cx.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.focus_contains(*self, other)
}
@@ -212,8 +212,8 @@ pub struct Window {
layout_engine: Option<TaffyLayoutEngine>,
pub(crate) root_view: Option<AnyView>,
pub(crate) element_id_stack: GlobalElementId,
- pub(crate) previous_frame: Frame,
- pub(crate) current_frame: Frame,
+ pub(crate) rendered_frame: Frame,
+ pub(crate) next_frame: Frame,
pub(crate) focus_handles: Arc<RwLock<SlotMap<FocusId, AtomicUsize>>>,
pub(crate) focus_listeners: SubscriberSet<(), AnyWindowFocusListener>,
default_prevented: bool,
@@ -249,7 +249,7 @@ pub(crate) struct Frame {
}
impl Frame {
- pub fn new(dispatch_tree: DispatchTree) -> Self {
+ fn new(dispatch_tree: DispatchTree) -> Self {
Frame {
element_states: HashMap::default(),
mouse_listeners: HashMap::default(),
@@ -262,6 +262,14 @@ impl Frame {
element_offset_stack: Vec::new(),
}
}
+
+ fn clear(&mut self) {
+ self.element_states.clear();
+ self.mouse_listeners.values_mut().for_each(Vec::clear);
+ self.focus_listeners.clear();
+ self.dispatch_tree.clear();
+ self.depth_map.clear();
+ }
}
impl Window {
@@ -330,8 +338,8 @@ impl Window {
layout_engine: Some(TaffyLayoutEngine::new()),
root_view: None,
element_id_stack: GlobalElementId::default(),
- previous_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
- current_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
+ rendered_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
+ next_frame: Frame::new(DispatchTree::new(cx.keymap.clone(), cx.actions.clone())),
focus_handles: Arc::new(RwLock::new(SlotMap::with_key())),
focus_listeners: SubscriberSet::new(),
default_prevented: true,
@@ -428,7 +436,7 @@ impl<'a> WindowContext<'a> {
self.window.focus = Some(focus_id);
self.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.clear_pending_keystrokes();
self.app.push_effect(Effect::FocusChanged {
@@ -459,11 +467,11 @@ impl<'a> WindowContext<'a> {
let node_id = focus_handle
.and_then(|handle| {
cx.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.focusable_node_id(handle.id)
})
- .unwrap_or_else(|| cx.window.current_frame.dispatch_tree.root_node_id());
+ .unwrap_or_else(|| cx.window.rendered_frame.dispatch_tree.root_node_id());
cx.propagate_event = true;
cx.dispatch_action_on_node(node_id, action);
@@ -743,7 +751,7 @@ impl<'a> WindowContext<'a> {
self.window.default_prevented
}
- /// Register a mouse event listener on the window for the current frame. The type of event
+ /// Register a mouse event listener on the window for the next frame. The type of event
/// is determined by the first parameter of the given listener. When the next frame is rendered
/// the listener will be cleared.
///
@@ -753,9 +761,9 @@ impl<'a> WindowContext<'a> {
&mut self,
handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static,
) {
- let order = self.window.current_frame.z_index_stack.clone();
+ let order = self.window.next_frame.z_index_stack.clone();
self.window
- .current_frame
+ .next_frame
.mouse_listeners
.entry(TypeId::of::<Event>())
.or_default()
@@ -767,7 +775,7 @@ impl<'a> WindowContext<'a> {
))
}
- /// Register a key event listener on the window for the current frame. The type of event
+ /// Register a key event listener on the window for the next frame. The type of event
/// is determined by the first parameter of the given listener. When the next frame is rendered
/// the listener will be cleared.
///
@@ -778,7 +786,7 @@ impl<'a> WindowContext<'a> {
handler: impl Fn(&Event, DispatchPhase, &mut WindowContext) + 'static,
) {
self.window
- .current_frame
+ .next_frame
.dispatch_tree
.on_key_event(Rc::new(move |event, phase, cx| {
if let Some(event) = event.downcast_ref::<Event>() {
@@ -787,7 +795,7 @@ impl<'a> WindowContext<'a> {
}));
}
- /// Register an action listener on the window for the current frame. The type of action
+ /// Register an action listener on the window for the next frame. The type of action
/// is determined by the first parameter of the given listener. When the next frame is rendered
/// the listener will be cleared.
///
@@ -798,7 +806,7 @@ impl<'a> WindowContext<'a> {
action_type: TypeId,
handler: impl Fn(&dyn Any, DispatchPhase, &mut WindowContext) + 'static,
) {
- self.window.current_frame.dispatch_tree.on_action(
+ self.window.next_frame.dispatch_tree.on_action(
action_type,
Rc::new(move |action, phase, cx| handler(action, phase, cx)),
);
@@ -809,13 +817,13 @@ impl<'a> WindowContext<'a> {
.focused()
.and_then(|focused_handle| {
self.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.focusable_node_id(focused_handle.id)
})
- .unwrap_or_else(|| self.window.current_frame.dispatch_tree.root_node_id());
+ .unwrap_or_else(|| self.window.rendered_frame.dispatch_tree.root_node_id());
self.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.is_action_available(action, target)
}
@@ -832,16 +840,16 @@ impl<'a> WindowContext<'a> {
/// Called during painting to invoke the given closure in a new stacking context. The given
/// z-index is interpreted relative to the previous call to `stack`.
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
- self.window.current_frame.z_index_stack.push(z_index);
+ self.window.next_frame.z_index_stack.push(z_index);
let result = f(self);
- self.window.current_frame.z_index_stack.pop();
+ self.window.next_frame.z_index_stack.pop();
result
}
/// Called during painting to track which z-index is on top at each pixel position
pub fn add_opaque_layer(&mut self, bounds: Bounds<Pixels>) {
- let stacking_order = self.window.current_frame.z_index_stack.clone();
- let depth_map = &mut self.window.current_frame.depth_map;
+ let stacking_order = self.window.next_frame.z_index_stack.clone();
+ let depth_map = &mut self.window.next_frame.depth_map;
match depth_map.binary_search_by(|(level, _)| stacking_order.cmp(&level)) {
Ok(i) | Err(i) => depth_map.insert(i, (stacking_order, bounds)),
}
@@ -850,7 +858,7 @@ impl<'a> WindowContext<'a> {
/// Returns true if the top-most opaque layer painted over this point was part of the
/// same layer as the given stacking order.
pub fn was_top_layer(&self, point: &Point<Pixels>, level: &StackingOrder) -> bool {
- for (stack, bounds) in self.window.previous_frame.depth_map.iter() {
+ for (stack, bounds) in self.window.rendered_frame.depth_map.iter() {
if bounds.contains_point(point) {
return level.starts_with(stack) || stack.starts_with(level);
}
@@ -861,10 +869,10 @@ impl<'a> WindowContext<'a> {
/// Called during painting to get the current stacking order.
pub fn stacking_order(&self) -> &StackingOrder {
- &self.window.current_frame.z_index_stack
+ &self.window.next_frame.z_index_stack
}
- /// Paint one or more drop shadows into the scene for the current frame at the current z-index.
+ /// Paint one or more drop shadows into the scene for the next frame at the current z-index.
pub fn paint_shadows(
&mut self,
bounds: Bounds<Pixels>,
@@ -878,8 +886,8 @@ impl<'a> WindowContext<'a> {
let mut shadow_bounds = bounds;
shadow_bounds.origin += shadow.offset;
shadow_bounds.dilate(shadow.spread_radius);
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
Shadow {
order: 0,
bounds: shadow_bounds.scale(scale_factor),
@@ -892,7 +900,7 @@ impl<'a> WindowContext<'a> {
}
}
- /// Paint one or more quads into the scene for the current frame at the current stacking context.
+ /// Paint one or more quads into the scene for the next frame at the current stacking context.
/// Quads are colored rectangular regions with an optional background, border, and corner radius.
pub fn paint_quad(
&mut self,
@@ -906,8 +914,8 @@ impl<'a> WindowContext<'a> {
let content_mask = self.content_mask();
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
Quad {
order: 0,
bounds: bounds.scale(scale_factor),
@@ -920,20 +928,20 @@ impl<'a> WindowContext<'a> {
);
}
- /// Paint the given `Path` into the scene for the current frame at the current z-index.
+ /// Paint the given `Path` into the scene for the next frame at the current z-index.
pub fn paint_path(&mut self, mut path: Path<Pixels>, color: impl Into<Hsla>) {
let scale_factor = self.scale_factor();
let content_mask = self.content_mask();
path.content_mask = content_mask;
path.color = color.into();
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
- path.scale(scale_factor),
- );
+ window
+ .next_frame
+ .scene_builder
+ .insert(&window.next_frame.z_index_stack, path.scale(scale_factor));
}
- /// Paint an underline into the scene for the current frame at the current z-index.
+ /// Paint an underline into the scene for the next frame at the current z-index.
pub fn paint_underline(
&mut self,
origin: Point<Pixels>,
@@ -952,8 +960,8 @@ impl<'a> WindowContext<'a> {
};
let content_mask = self.content_mask();
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
Underline {
order: 0,
bounds: bounds.scale(scale_factor),
@@ -965,7 +973,7 @@ impl<'a> WindowContext<'a> {
);
}
- /// Paint a monochrome (non-emoji) glyph into the scene for the current frame at the current z-index.
+ /// Paint a monochrome (non-emoji) glyph into the scene for the next frame at the current z-index.
/// The y component of the origin is the baseline of the glyph.
pub fn paint_glyph(
&mut self,
@@ -1005,8 +1013,8 @@ impl<'a> WindowContext<'a> {
};
let content_mask = self.content_mask().scale(scale_factor);
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
MonochromeSprite {
order: 0,
bounds,
@@ -1019,7 +1027,7 @@ impl<'a> WindowContext<'a> {
Ok(())
}
- /// Paint an emoji glyph into the scene for the current frame at the current z-index.
+ /// Paint an emoji glyph into the scene for the next frame at the current z-index.
/// The y component of the origin is the baseline of the glyph.
pub fn paint_emoji(
&mut self,
@@ -1056,8 +1064,8 @@ impl<'a> WindowContext<'a> {
let content_mask = self.content_mask().scale(scale_factor);
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
PolychromeSprite {
order: 0,
bounds,
@@ -1071,7 +1079,7 @@ impl<'a> WindowContext<'a> {
Ok(())
}
- /// Paint a monochrome SVG into the scene for the current frame at the current stacking context.
+ /// Paint a monochrome SVG into the scene for the next frame at the current stacking context.
pub fn paint_svg(
&mut self,
bounds: Bounds<Pixels>,
@@ -1098,8 +1106,8 @@ impl<'a> WindowContext<'a> {
let content_mask = self.content_mask().scale(scale_factor);
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
MonochromeSprite {
order: 0,
bounds,
@@ -1112,7 +1120,7 @@ impl<'a> WindowContext<'a> {
Ok(())
}
- /// Paint an image into the scene for the current frame at the current z-index.
+ /// Paint an image into the scene for the next frame at the current z-index.
pub fn paint_image(
&mut self,
bounds: Bounds<Pixels>,
@@ -1134,8 +1142,8 @@ impl<'a> WindowContext<'a> {
let corner_radii = corner_radii.scale(scale_factor);
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
PolychromeSprite {
order: 0,
bounds,
@@ -1148,14 +1156,14 @@ impl<'a> WindowContext<'a> {
Ok(())
}
- /// Paint a surface into the scene for the current frame at the current z-index.
+ /// Paint a surface into the scene for the next frame at the current z-index.
pub fn paint_surface(&mut self, bounds: Bounds<Pixels>, image_buffer: CVImageBuffer) {
let scale_factor = self.scale_factor();
let bounds = bounds.scale(scale_factor);
let content_mask = self.content_mask().scale(scale_factor);
let window = &mut *self.window;
- window.current_frame.scene_builder.insert(
- &window.current_frame.z_index_stack,
+ window.next_frame.scene_builder.insert(
+ &window.next_frame.z_index_stack,
Surface {
order: 0,
bounds,
@@ -1167,15 +1175,17 @@ impl<'a> WindowContext<'a> {
/// Draw pixels to the display for this window based on the contents of its scene.
pub(crate) fn draw(&mut self) {
+ self.text_system().start_frame();
+ self.window.platform_window.clear_input_handler();
+ self.window.layout_engine.as_mut().unwrap().clear();
+ self.window.next_frame.clear();
let root_view = self.window.root_view.take().unwrap();
- self.start_frame();
-
self.with_z_index(0, |cx| {
cx.with_key_dispatch(Some(KeyContext::default()), None, |_, cx| {
for (action_type, action_listeners) in &cx.app.global_action_listeners {
for action_listener in action_listeners.iter().cloned() {
- cx.window.current_frame.dispatch_tree.on_action(
+ cx.window.next_frame.dispatch_tree.on_action(
*action_type,
Rc::new(move |action, phase, cx| action_listener(action, phase, cx)),
)
@@ -1204,16 +1214,18 @@ impl<'a> WindowContext<'a> {
}
self.window
- .current_frame
+ .next_frame
.dispatch_tree
.preserve_pending_keystrokes(
- &mut self.window.previous_frame.dispatch_tree,
+ &mut self.window.rendered_frame.dispatch_tree,
self.window.focus,
);
-
self.window.root_view = Some(root_view);
- let scene = self.window.current_frame.scene_builder.build();
+ let window = &mut self.window;
+ mem::swap(&mut window.rendered_frame, &mut window.next_frame);
+
+ let scene = self.window.rendered_frame.scene_builder.build();
self.window.platform_window.draw(scene);
let cursor_style = self
.window
@@ -1225,24 +1237,6 @@ impl<'a> WindowContext<'a> {
self.window.dirty = false;
}
- /// Rotate the current frame and the previous frame, then clear the current frame.
- /// We repopulate all state in the current frame during each paint.
- fn start_frame(&mut self) {
- self.window.platform_window.clear_input_handler();
- self.text_system().start_frame();
-
- let window = &mut *self.window;
- window.layout_engine.as_mut().unwrap().clear();
-
- mem::swap(&mut window.previous_frame, &mut window.current_frame);
- let frame = &mut window.current_frame;
- frame.element_states.clear();
- frame.mouse_listeners.values_mut().for_each(Vec::clear);
- frame.focus_listeners.clear();
- frame.dispatch_tree.clear();
- frame.depth_map.clear();
- }
-
/// Dispatch a mouse or keyboard event on the window.
pub fn dispatch_event(&mut self, event: InputEvent) -> bool {
// Handlers may set this to false by calling `stop_propagation`
@@ -1275,10 +1269,9 @@ impl<'a> WindowContext<'a> {
cursor_offset: position,
});
}
- InputEvent::MouseDown(MouseDownEvent {
+ InputEvent::MouseMove(MouseMoveEvent {
position,
- button: MouseButton::Left,
- click_count: 1,
+ pressed_button: Some(MouseButton::Left),
modifiers: Modifiers::default(),
})
}
@@ -1291,6 +1284,7 @@ impl<'a> WindowContext<'a> {
})
}
FileDropEvent::Submit { position } => {
+ self.activate(true);
self.window.mouse_position = position;
InputEvent::MouseUp(MouseUpEvent {
button: MouseButton::Left,
@@ -1321,7 +1315,7 @@ impl<'a> WindowContext<'a> {
fn dispatch_mouse_event(&mut self, event: &dyn Any) {
if let Some(mut handlers) = self
.window
- .current_frame
+ .rendered_frame
.mouse_listeners
.remove(&event.type_id())
{
@@ -1351,17 +1345,8 @@ impl<'a> WindowContext<'a> {
self.active_drag = None;
}
- // Just in case any handlers added new handlers, which is weird, but possible.
- handlers.extend(
- self.window
- .current_frame
- .mouse_listeners
- .get_mut(&event.type_id())
- .into_iter()
- .flat_map(|handlers| handlers.drain(..)),
- );
self.window
- .current_frame
+ .rendered_frame
.mouse_listeners
.insert(event.type_id(), handlers);
}
@@ -1373,15 +1358,15 @@ impl<'a> WindowContext<'a> {
.focus
.and_then(|focus_id| {
self.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.focusable_node_id(focus_id)
})
- .unwrap_or_else(|| self.window.current_frame.dispatch_tree.root_node_id());
+ .unwrap_or_else(|| self.window.rendered_frame.dispatch_tree.root_node_id());
let dispatch_path = self
.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.dispatch_path(node_id);
@@ -1392,7 +1377,7 @@ impl<'a> WindowContext<'a> {
self.propagate_event = true;
for node_id in &dispatch_path {
- let node = self.window.current_frame.dispatch_tree.node(*node_id);
+ let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
if let Some(context) = node.context.clone() {
context_stack.push(context);
@@ -1409,7 +1394,7 @@ impl<'a> WindowContext<'a> {
// Bubble phase
for node_id in dispatch_path.iter().rev() {
// Handle low level key events
- let node = self.window.current_frame.dispatch_tree.node(*node_id);
+ let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
for key_listener in node.key_listeners.clone() {
key_listener(event, DispatchPhase::Bubble, self);
if !self.propagate_event {
@@ -1418,12 +1403,12 @@ impl<'a> WindowContext<'a> {
}
// Match keystrokes
- let node = self.window.current_frame.dispatch_tree.node(*node_id);
+ let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
if node.context.is_some() {
if let Some(key_down_event) = event.downcast_ref::<KeyDownEvent>() {
if let Some(found) = self
.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.dispatch_key(&key_down_event.keystroke, &context_stack)
{
@@ -1446,13 +1431,13 @@ impl<'a> WindowContext<'a> {
fn dispatch_action_on_node(&mut self, node_id: DispatchNodeId, action: Box<dyn Action>) {
let dispatch_path = self
.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.dispatch_path(node_id);
// Capture phase
for node_id in &dispatch_path {
- let node = self.window.current_frame.dispatch_tree.node(*node_id);
+ let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
for DispatchActionListener {
action_type,
listener,
@@ -1469,7 +1454,7 @@ impl<'a> WindowContext<'a> {
}
// Bubble phase
for node_id in dispatch_path.iter().rev() {
- let node = self.window.current_frame.dispatch_tree.node(*node_id);
+ let node = self.window.rendered_frame.dispatch_tree.node(*node_id);
for DispatchActionListener {
action_type,
listener,
@@ -1529,25 +1514,25 @@ impl<'a> WindowContext<'a> {
.focus
.and_then(|focus_id| {
self.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.focusable_node_id(focus_id)
})
- .unwrap_or_else(|| self.window.current_frame.dispatch_tree.root_node_id());
+ .unwrap_or_else(|| self.window.rendered_frame.dispatch_tree.root_node_id());
self.window
- .current_frame
+ .rendered_frame
.dispatch_tree
.available_actions(node_id)
}
pub fn bindings_for_action(&self, action: &dyn Action) -> Vec<KeyBinding> {
self.window
- .previous_frame
+ .rendered_frame
.dispatch_tree
.bindings_for_action(
action,
- &self.window.previous_frame.dispatch_tree.context_stack,
+ &self.window.rendered_frame.dispatch_tree.context_stack,
)
}
@@ -1556,7 +1541,7 @@ impl<'a> WindowContext<'a> {
action: &dyn Action,
focus_handle: &FocusHandle,
) -> Vec<KeyBinding> {
- let dispatch_tree = &self.window.previous_frame.dispatch_tree;
+ let dispatch_tree = &self.window.rendered_frame.dispatch_tree;
let Some(node_id) = dispatch_tree.focusable_node_id(focus_handle.id) else {
return vec![];
@@ -1599,24 +1584,21 @@ impl<'a> WindowContext<'a> {
f: impl FnOnce(Option<FocusHandle>, &mut Self) -> R,
) -> R {
let window = &mut self.window;
- window
- .current_frame
- .dispatch_tree
- .push_node(context.clone());
+ window.next_frame.dispatch_tree.push_node(context.clone());
if let Some(focus_handle) = focus_handle.as_ref() {
window
- .current_frame
+ .next_frame
.dispatch_tree
.make_focusable(focus_handle.id);
}
let result = f(focus_handle, self);
- self.window.current_frame.dispatch_tree.pop_node();
+ self.window.next_frame.dispatch_tree.pop_node();
result
}
- /// Register a focus listener for the current frame only. It will be cleared
+ /// Register a focus listener for the next frame only. It will be cleared
/// on the next frame render. You should use this method only from within elements,
/// and we may want to enforce that better via a different context type.
// todo!() Move this to `FrameContext` to emphasize its individuality?
@@ -1625,7 +1607,7 @@ impl<'a> WindowContext<'a> {
listener: impl Fn(&FocusEvent, &mut WindowContext) + 'static,
) {
self.window
- .current_frame
+ .next_frame
.focus_listeners
.push(Box::new(move |event, cx| {
listener(event, cx);
@@ -1876,12 +1858,9 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
) -> R {
if let Some(mask) = mask {
let mask = mask.intersect(&self.content_mask());
- self.window_mut()
- .current_frame
- .content_mask_stack
- .push(mask);
+ self.window_mut().next_frame.content_mask_stack.push(mask);
let result = f(self);
- self.window_mut().current_frame.content_mask_stack.pop();
+ self.window_mut().next_frame.content_mask_stack.pop();
result
} else {
f(self)
@@ -1897,12 +1876,9 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
size: self.window().viewport_size,
},
};
- self.window_mut()
- .current_frame
- .content_mask_stack
- .push(mask);
+ self.window_mut().next_frame.content_mask_stack.push(mask);
let result = f(self);
- self.window_mut().current_frame.content_mask_stack.pop();
+ self.window_mut().next_frame.content_mask_stack.pop();
result
}
@@ -1929,26 +1905,26 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
f: impl FnOnce(&mut Self) -> R,
) -> R {
self.window_mut()
- .current_frame
+ .next_frame
.element_offset_stack
.push(offset);
let result = f(self);
- self.window_mut().current_frame.element_offset_stack.pop();
+ self.window_mut().next_frame.element_offset_stack.pop();
result
}
/// Obtain the current element offset.
fn element_offset(&self) -> Point<Pixels> {
self.window()
- .current_frame
+ .next_frame
.element_offset_stack
.last()
.copied()
.unwrap_or_default()
}
- /// Update or intialize state for an element with the given id that lives across multiple
- /// frames. If an element with this id existed in the previous frame, its state will be passed
+ /// Update or initialize state for an element with the given id that lives across multiple
+ /// frames. If an element with this id existed in the rendered frame, its state will be passed
/// to the given closure. The state returned by the closure will be stored so it can be referenced
/// when drawing the next frame.
fn with_element_state<S, R>(
@@ -1964,12 +1940,12 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
if let Some(any) = cx
.window_mut()
- .current_frame
+ .next_frame
.element_states
.remove(&global_id)
.or_else(|| {
cx.window_mut()
- .previous_frame
+ .rendered_frame
.element_states
.remove(&global_id)
})
@@ -2011,7 +1987,7 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
let (result, state) = f(Some(state), cx);
state_box.replace(state);
cx.window_mut()
- .current_frame
+ .next_frame
.element_states
.insert(global_id, ElementStateBox {
inner: state_box,
@@ -2023,7 +1999,7 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
} else {
let (result, state) = f(None, cx);
cx.window_mut()
- .current_frame
+ .next_frame
.element_states
.insert(global_id,
ElementStateBox {
@@ -2042,7 +2018,7 @@ pub trait BorrowWindow: BorrowMut<Window> + BorrowMut<AppContext> {
/// Obtain the current content mask.
fn content_mask(&self) -> ContentMask<Pixels> {
self.window()
- .current_frame
+ .next_frame
.content_mask_stack
.last()
.cloned()
@@ -2130,9 +2106,9 @@ impl<'a, V: 'static> ViewContext<'a, V> {
}
pub fn with_z_index<R>(&mut self, z_index: u32, f: impl FnOnce(&mut Self) -> R) -> R {
- self.window.current_frame.z_index_stack.push(z_index);
+ self.window.next_frame.z_index_stack.push(z_index);
let result = f(self);
- self.window.current_frame.z_index_stack.pop();
+ self.window.next_frame.z_index_stack.pop();
result
}
@@ -38,6 +38,7 @@ pub fn action(input: TokenStream) -> TokenStream {
let build_impl = if is_unit_struct {
quote! {
+ let _ = value;
Ok(std::boxed::Box::new(Self {}))
}
} else {
@@ -5,7 +5,7 @@ use gpui::{
Action, ClickEvent, Div, ElementId, EventEmitter, InteractiveElement, ParentElement, Render,
Stateful, Styled, Subscription, View, ViewContext, WeakView,
};
-use search::BufferSearchBar;
+use search::{buffer_search, BufferSearchBar};
use ui::{prelude::*, ButtonSize, ButtonStyle, Icon, IconButton, IconSize, Tooltip};
use workspace::{
item::ItemHandle, ToolbarItemEvent, ToolbarItemLocation, ToolbarItemView, Workspace,
@@ -64,12 +64,14 @@ impl Render for QuickActionBar {
"toggle buffer search",
Icon::MagnifyingGlass,
!self.buffer_search_bar.read(cx).is_dismissed(),
- Box::new(search::buffer_search::Deploy { focus: false }),
+ Box::new(buffer_search::Deploy { focus: false }),
"Buffer Search",
{
let buffer_search_bar = self.buffer_search_bar.clone();
move |_, cx| {
- buffer_search_bar.update(cx, |search_bar, cx| search_bar.toggle(cx));
+ buffer_search_bar.update(cx, |search_bar, cx| {
+ search_bar.toggle(&buffer_search::Deploy { focus: true }, cx)
+ });
}
},
))
@@ -0,0 +1 @@
+gpui::actions!(OpenRecent);
@@ -1,9 +1,10 @@
mod highlighted_workspace_location;
+mod projects;
use fuzzy::{StringMatch, StringMatchCandidate};
use gpui::{
- actions, AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView, Result, Task,
- View, ViewContext, WeakView,
+ AppContext, DismissEvent, Div, EventEmitter, FocusHandle, FocusableView, Result, Task, View,
+ ViewContext, WeakView,
};
use highlighted_workspace_location::HighlightedWorkspaceLocation;
use ordered_float::OrderedFloat;
@@ -16,7 +17,7 @@ use workspace::{
WORKSPACE_DB,
};
-actions!(OpenRecent);
+pub use projects::OpenRecent;
pub fn init(cx: &mut AppContext) {
cx.observe_new_views(RecentProjects::register).detach();
@@ -170,14 +170,25 @@ impl Render for BufferSearchBar {
h_stack()
.key_context("BufferSearchBar")
- .when(in_replace, |this| {
- this.key_context("in_replace")
- .on_action(cx.listener(Self::replace_next))
- .on_action(cx.listener(Self::replace_all))
- })
.on_action(cx.listener(Self::previous_history_query))
.on_action(cx.listener(Self::next_history_query))
.on_action(cx.listener(Self::dismiss))
+ .on_action(cx.listener(Self::select_next_match))
+ .on_action(cx.listener(Self::select_prev_match))
+ .when(self.supported_options().replacement, |this| {
+ this.on_action(cx.listener(Self::toggle_replace))
+ .when(in_replace, |this| {
+ this.key_context("in_replace")
+ .on_action(cx.listener(Self::replace_next))
+ .on_action(cx.listener(Self::replace_all))
+ })
+ })
+ .when(self.supported_options().case, |this| {
+ this.on_action(cx.listener(Self::toggle_case_sensitive))
+ })
+ .when(self.supported_options().word, |this| {
+ this.on_action(cx.listener(Self::toggle_whole_word))
+ })
.w_full()
.p_1()
.child(
@@ -305,7 +316,7 @@ impl BufferSearchBar {
let handle = cx.view().downgrade();
- editor.register_action(move |a: &Deploy, cx| {
+ editor.register_action(move |deploy: &Deploy, cx| {
let Some(pane) = handle.upgrade().and_then(|editor| editor.read(cx).pane(cx)) else {
return;
};
@@ -313,12 +324,12 @@ impl BufferSearchBar {
pane.update(cx, |this, cx| {
this.toolbar().update(cx, |this, cx| {
if let Some(search_bar) = this.item_of_type::<BufferSearchBar>() {
- search_bar.update(cx, |this, cx| this.toggle(cx));
+ search_bar.update(cx, |this, cx| this.toggle(deploy, cx));
return;
}
let view = cx.build_view(|cx| BufferSearchBar::new(cx));
this.add_item(view.clone(), cx);
- view.update(cx, |this, cx| this.deploy(a, cx));
+ view.update(cx, |this, cx| this.deploy(deploy, cx));
cx.notify();
})
});
@@ -468,7 +479,7 @@ impl BufferSearchBar {
self.search_suggested(cx);
if deploy.focus {
self.select_query(cx);
- let handle = cx.focus_handle();
+ let handle = self.query_editor.focus_handle(cx);
cx.focus(&handle);
}
return true;
@@ -477,9 +488,9 @@ impl BufferSearchBar {
false
}
- pub fn toggle(&mut self, cx: &mut ViewContext<Self>) {
+ pub fn toggle(&mut self, action: &Deploy, cx: &mut ViewContext<Self>) {
if self.is_dismissed() {
- self.show(cx);
+ self.deploy(action, cx);
} else {
self.dismiss(&Dismiss, cx);
}
@@ -28,6 +28,7 @@ pub enum ComponentStory {
ListHeader,
ListItem,
Scroll,
+ Tab,
Text,
ZIndex,
Picker,
@@ -53,6 +54,7 @@ impl ComponentStory {
Self::ListItem => cx.build_view(|_| ui::ListItemStory).into(),
Self::Scroll => ScrollStory::view(cx).into(),
Self::Text => TextStory::view(cx).into(),
+ Self::Tab => cx.build_view(|_| ui::TabStory).into(),
Self::ZIndex => cx.build_view(|_| ZIndexStory).into(),
Self::Picker => PickerStory::new(cx).into(),
}
@@ -50,7 +50,7 @@ use std::{
use thiserror::Error;
use gpui::{
- px, AnyWindowHandle, AppContext, Bounds, ClipboardItem, EventEmitter, Hsla, Keystroke,
+ actions, px, AnyWindowHandle, AppContext, Bounds, ClipboardItem, EventEmitter, Hsla, Keystroke,
ModelContext, Modifiers, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, Pixels,
Point, ScrollWheelEvent, Size, Task, TouchPhase,
};
@@ -58,6 +58,16 @@ use gpui::{
use crate::mappings::{colors::to_alac_rgb, keys::to_esc_str};
use lazy_static::lazy_static;
+actions!(
+ Clear,
+ Copy,
+ Paste,
+ ShowCharacterPalette,
+ SearchTest,
+ SendText,
+ SendKeystroke,
+);
+
///Scrolling is unbearably sluggish by default. Alacritty supports a configurable
///Scroll multiplier that is set to 3 by default. This will be removed when I
///Implement scroll bars.
@@ -1,9 +1,9 @@
use editor::{Cursor, HighlightedRange, HighlightedRangeLine};
use gpui::{
black, div, point, px, red, relative, transparent_black, AnyElement, AsyncWindowContext,
- AvailableSpace, Bounds, DispatchPhase, Element, ElementId, FocusHandle, Font, FontStyle,
- FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState, IntoElement,
- LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels,
+ AvailableSpace, Bounds, DispatchPhase, Element, ElementId, ExternalPaths, FocusHandle, Font,
+ FontStyle, FontWeight, HighlightStyle, Hsla, InteractiveElement, InteractiveElementState,
+ IntoElement, LayoutId, Model, ModelContext, ModifiersChangedEvent, MouseButton, Pixels,
PlatformInputHandler, Point, Rgba, ShapedLine, Size, StatefulInteractiveElement, Styled,
TextRun, TextStyle, TextSystem, UnderlineStyle, View, WhiteSpace, WindowContext,
};
@@ -643,13 +643,11 @@ impl TerminalElement {
let connection = connection.clone();
let focus = focus.clone();
move |e, cx| {
- if e.pressed_button.is_some() {
- if focus.is_focused(cx) {
- connection.update(cx, |terminal, cx| {
- terminal.mouse_drag(e, origin, bounds);
- cx.notify();
- })
- }
+ if e.pressed_button.is_some() && focus.is_focused(cx) && !cx.has_active_drag() {
+ connection.update(cx, |terminal, cx| {
+ terminal.mouse_drag(e, origin, bounds);
+ cx.notify();
+ })
}
}
})
@@ -806,7 +804,28 @@ impl Element for TerminalElement {
.map(|cursor| cursor.bounding_rect(origin)),
};
- let mut this = self.register_mouse_listeners(origin, layout.mode, bounds, cx);
+ let terminal_focus_handle = self.focus.clone();
+ let terminal_handle = self.terminal.clone();
+ let mut this: TerminalElement = self
+ .register_mouse_listeners(origin, layout.mode, bounds, cx)
+ .drag_over::<ExternalPaths>(|style| {
+ // todo!() why does not it work? z-index of elements?
+ style.bg(cx.theme().colors().ghost_element_hover)
+ })
+ .on_drop::<ExternalPaths>(move |external_paths, cx| {
+ cx.focus(&terminal_focus_handle);
+ let mut new_text = external_paths
+ .read(cx)
+ .paths()
+ .iter()
+ .map(|path| format!(" {path:?}"))
+ .join("");
+ new_text.push(' ');
+ terminal_handle.update(cx, |terminal, _| {
+ // todo!() long paths are not displayed properly albeit the text is there
+ terminal.paste(&new_text);
+ });
+ });
let interactivity = mem::take(&mut this.interactivity);
@@ -9,9 +9,9 @@ pub mod terminal_panel;
// use crate::terminal_element::TerminalElement;
use editor::{scroll::autoscroll::Autoscroll, Editor};
use gpui::{
- actions, div, Action, AnyElement, AppContext, Div, EventEmitter, FocusEvent, FocusHandle,
- Focusable, FocusableElement, FocusableView, KeyContext, KeyDownEvent, Keystroke, Model,
- MouseButton, MouseDownEvent, Pixels, Render, Subscription, Task, View, VisualContext, WeakView,
+ div, Action, AnyElement, AppContext, Div, EventEmitter, FocusEvent, FocusHandle, Focusable,
+ FocusableElement, FocusableView, KeyContext, KeyDownEvent, Keystroke, Model, MouseButton,
+ MouseDownEvent, Pixels, Render, Subscription, Task, View, VisualContext, WeakView,
};
use language::Bias;
use persistence::TERMINAL_DB;
@@ -22,7 +22,7 @@ use terminal::{
term::{search::RegexSearch, TermMode},
},
terminal_settings::{TerminalBlink, TerminalSettings, WorkingDirectory},
- Event, MaybeNavigationTarget, Terminal,
+ Clear, Copy, Event, MaybeNavigationTarget, Paste, ShowCharacterPalette, Terminal,
};
use terminal_element::TerminalElement;
use ui::{h_stack, prelude::*, ContextMenu, Icon, IconElement, Label};
@@ -60,8 +60,6 @@ pub struct SendText(String);
#[derive(Clone, Debug, Default, Deserialize, PartialEq, Action)]
pub struct SendKeystroke(String);
-actions!(Clear, Copy, Paste, ShowCharacterPalette, SearchTest);
-
pub fn init(cx: &mut AppContext) {
terminal_panel::init(cx);
terminal::init(cx);
@@ -187,6 +187,10 @@ impl PickerDelegate for ThemeSelectorDelegate {
Self::set_theme(self.original_theme.clone(), cx);
self.selection_completed = true;
}
+
+ self.view
+ .update(cx, |_, cx| cx.emit(DismissEvent))
+ .log_err();
}
fn selected_index(&self) -> usize {
@@ -13,6 +13,7 @@ mod popover;
mod popover_menu;
mod right_click_menu;
mod stack;
+mod tab;
mod tooltip;
#[cfg(feature = "stories")]
@@ -33,6 +34,7 @@ pub use popover::*;
pub use popover_menu::*;
pub use right_click_menu::*;
pub use stack::*;
+pub use tab::*;
pub use tooltip::*;
#[cfg(feature = "stories")]
@@ -98,11 +98,11 @@ impl RenderOnce for Key {
div()
.py_0()
- .map(|el| {
+ .map(|this| {
if single_char {
- el.w(rems(14. / 16.)).flex().flex_none().justify_center()
+ this.w(rems(14. / 16.)).flex().flex_none().justify_center()
} else {
- el.px_0p5()
+ this.px_0p5()
}
})
.h(rems(14. / 16.))
@@ -10,6 +10,7 @@ mod label;
mod list;
mod list_header;
mod list_item;
+mod tab;
pub use avatar::*;
pub use button::*;
@@ -23,3 +24,4 @@ pub use label::*;
pub use list::*;
pub use list_header::*;
pub use list_item::*;
+pub use tab::*;
@@ -0,0 +1,114 @@
+use std::cmp::Ordering;
+
+use gpui::{Div, Render};
+use story::Story;
+
+use crate::{prelude::*, TabPosition};
+use crate::{Indicator, Tab};
+
+pub struct TabStory;
+
+impl Render for TabStory {
+ type Element = Div;
+
+ fn render(&mut self, _cx: &mut ViewContext<Self>) -> Self::Element {
+ Story::container()
+ .child(Story::title_for::<Tab>())
+ .child(Story::label("Default"))
+ .child(h_stack().child(Tab::new("tab_1").child("Tab 1")))
+ .child(Story::label("With indicator"))
+ .child(
+ h_stack().child(
+ Tab::new("tab_1")
+ .start_slot(Indicator::dot().color(Color::Warning))
+ .child("Tab 1"),
+ ),
+ )
+ .child(Story::label("With close button"))
+ .child(
+ h_stack().child(
+ Tab::new("tab_1")
+ .end_slot(
+ IconButton::new("close_button", Icon::Close)
+ .icon_color(Color::Muted)
+ .size(ButtonSize::None)
+ .icon_size(IconSize::XSmall),
+ )
+ .child("Tab 1"),
+ ),
+ )
+ .child(Story::label("List of tabs"))
+ .child(
+ h_stack()
+ .child(Tab::new("tab_1").child("Tab 1"))
+ .child(Tab::new("tab_2").child("Tab 2")),
+ )
+ .child(Story::label("List of tabs with first tab selected"))
+ .child(
+ h_stack()
+ .child(
+ Tab::new("tab_1")
+ .selected(true)
+ .position(TabPosition::First)
+ .child("Tab 1"),
+ )
+ .child(
+ Tab::new("tab_2")
+ .position(TabPosition::Middle(Ordering::Greater))
+ .child("Tab 2"),
+ )
+ .child(
+ Tab::new("tab_3")
+ .position(TabPosition::Middle(Ordering::Greater))
+ .child("Tab 3"),
+ )
+ .child(Tab::new("tab_4").position(TabPosition::Last).child("Tab 4")),
+ )
+ .child(Story::label("List of tabs with last tab selected"))
+ .child(
+ h_stack()
+ .child(
+ Tab::new("tab_1")
+ .position(TabPosition::First)
+ .child("Tab 1"),
+ )
+ .child(
+ Tab::new("tab_2")
+ .position(TabPosition::Middle(Ordering::Less))
+ .child("Tab 2"),
+ )
+ .child(
+ Tab::new("tab_3")
+ .position(TabPosition::Middle(Ordering::Less))
+ .child("Tab 3"),
+ )
+ .child(
+ Tab::new("tab_4")
+ .position(TabPosition::Last)
+ .selected(true)
+ .child("Tab 4"),
+ ),
+ )
+ .child(Story::label("List of tabs with second tab selected"))
+ .child(
+ h_stack()
+ .child(
+ Tab::new("tab_1")
+ .position(TabPosition::First)
+ .child("Tab 1"),
+ )
+ .child(
+ Tab::new("tab_2")
+ .position(TabPosition::Middle(Ordering::Equal))
+ .selected(true)
+ .child("Tab 2"),
+ )
+ .child(
+ Tab::new("tab_3")
+ .position(TabPosition::Middle(Ordering::Greater))
+ .child("Tab 3"),
+ )
+ .child(Tab::new("tab_4").position(TabPosition::Last).child("Tab 4")),
+ )
+ }
+}
@@ -0,0 +1,198 @@
+use std::cmp::Ordering;
+use std::rc::Rc;
+
+use gpui::{AnyElement, AnyView, ClickEvent, IntoElement, MouseButton};
+use smallvec::SmallVec;
+
+use crate::prelude::*;
+
+/// The position of a [`Tab`] within a list of tabs.
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum TabPosition {
+ /// The tab is first in the list.
+ First,
+
+ /// The tab is in the middle of the list (i.e., it is not the first or last tab).
+ ///
+ /// The [`Ordering`] is where this tab is positioned with respect to the selected tab.
+ Middle(Ordering),
+
+ /// The tab is last in the list.
+ Last,
+}
+
+#[derive(Debug, PartialEq, Eq, Clone, Copy)]
+pub enum TabCloseSide {
+ Start,
+ End,
+}
+
+#[derive(IntoElement)]
+pub struct Tab {
+ id: ElementId,
+ selected: bool,
+ position: TabPosition,
+ close_side: TabCloseSide,
+ on_click: Option<Rc<dyn Fn(&ClickEvent, &mut WindowContext) + 'static>>,
+ tooltip: Option<Box<dyn Fn(&mut WindowContext) -> AnyView + 'static>>,
+ start_slot: Option<AnyElement>,
+ end_slot: Option<AnyElement>,
+ children: SmallVec<[AnyElement; 2]>,
+}
+
+impl Tab {
+ pub fn new(id: impl Into<ElementId>) -> Self {
+ Self {
+ id: id.into(),
+ selected: false,
+ position: TabPosition::First,
+ close_side: TabCloseSide::End,
+ on_click: None,
+ tooltip: None,
+ start_slot: None,
+ end_slot: None,
+ children: SmallVec::new(),
+ }
+ }
+
+ pub fn position(mut self, position: TabPosition) -> Self {
+ self.position = position;
+ self
+ }
+
+ pub fn close_side(mut self, close_side: TabCloseSide) -> Self {
+ self.close_side = close_side;
+ self
+ }
+
+ pub fn on_click(mut self, handler: impl Fn(&ClickEvent, &mut WindowContext) + 'static) -> Self {
+ self.on_click = Some(Rc::new(handler));
+ self
+ }
+
+ pub fn tooltip(mut self, tooltip: impl Fn(&mut WindowContext) -> AnyView + 'static) -> Self {
+ self.tooltip = Some(Box::new(tooltip));
+ self
+ }
+
+ pub fn start_slot<E: IntoElement>(mut self, element: impl Into<Option<E>>) -> Self {
+ self.start_slot = element.into().map(IntoElement::into_any_element);
+ self
+ }
+
+ pub fn end_slot<E: IntoElement>(mut self, element: impl Into<Option<E>>) -> Self {
+ self.end_slot = element.into().map(IntoElement::into_any_element);
+ self
+ }
+}
+
+impl Selectable for Tab {
+ fn selected(mut self, selected: bool) -> Self {
+ self.selected = selected;
+ self
+ }
+}
+
+impl ParentElement for Tab {
+ fn children_mut(&mut self) -> &mut SmallVec<[AnyElement; 2]> {
+ &mut self.children
+ }
+}
+
+impl RenderOnce for Tab {
+ type Rendered = Div;
+
+ fn render(self, cx: &mut WindowContext) -> Self::Rendered {
+ const HEIGHT_IN_REMS: f32 = 30. / 16.;
+
+ let (text_color, tab_bg, _tab_hover_bg, _tab_active_bg) = match self.selected {
+ false => (
+ cx.theme().colors().text_muted,
+ cx.theme().colors().tab_inactive_background,
+ cx.theme().colors().ghost_element_hover,
+ cx.theme().colors().ghost_element_active,
+ ),
+ true => (
+ cx.theme().colors().text,
+ cx.theme().colors().tab_active_background,
+ cx.theme().colors().element_hover,
+ cx.theme().colors().element_active,
+ ),
+ };
+
+ div()
+ .h(rems(HEIGHT_IN_REMS))
+ .bg(tab_bg)
+ .border_color(cx.theme().colors().border)
+ .map(|this| match self.position {
+ TabPosition::First => {
+ if self.selected {
+ this.pl_px().border_r().pb_px()
+ } else {
+ this.pl_px().pr_px().border_b()
+ }
+ }
+ TabPosition::Last => {
+ if self.selected {
+ this.border_l().border_r().pb_px()
+ } else {
+ this.pr_px().pl_px().border_b()
+ }
+ }
+ TabPosition::Middle(Ordering::Equal) => this.border_l().border_r().pb_px(),
+ TabPosition::Middle(Ordering::Less) => this.border_l().pr_px().border_b(),
+ TabPosition::Middle(Ordering::Greater) => this.border_r().pl_px().border_b(),
+ })
+ .child(
+ h_stack()
+ .group("")
+ .id(self.id)
+ .relative()
+ .h_full()
+ .px_5()
+ .gap_1()
+ .text_color(text_color)
+ // .hover(|style| style.bg(tab_hover_bg))
+ // .active(|style| style.bg(tab_active_bg))
+ .when_some(self.on_click, |tab, on_click| {
+ tab.cursor_pointer().on_click(move |event, cx| {
+ // HACK: GPUI currently fires `on_click` with any mouse button,
+ // but we only care about the left button.
+ if event.down.button == MouseButton::Left {
+ (on_click)(event, cx)
+ }
+ })
+ })
+ .when_some(self.tooltip, |tab, tooltip| {
+ tab.tooltip(move |cx| tooltip(cx))
+ })
+ .child(
+ h_stack()
+ .w_3()
+ .h_3()
+ .justify_center()
+ .absolute()
+ .map(|this| match self.close_side {
+ TabCloseSide::Start => this.right_1(),
+ TabCloseSide::End => this.left_1(),
+ })
+ .children(self.start_slot),
+ )
+ .child(
+ h_stack()
+ .invisible()
+ .w_3()
+ .h_3()
+ .justify_center()
+ .absolute()
+ .map(|this| match self.close_side {
+ TabCloseSide::Start => this.left_1(),
+ TabCloseSide::End => this.right_1(),
+ })
+ .group_hover("", |style| style.visible())
+ .children(self.end_slot),
+ )
+ .children(self.children),
+ )
+ }
+}
@@ -133,13 +133,13 @@ pub struct Dock {
panel_entries: Vec<PanelEntry>,
is_open: bool,
active_panel_index: usize,
+ focus_handle: FocusHandle,
+ focus_subscription: Subscription,
}
impl FocusableView for Dock {
- fn focus_handle(&self, cx: &AppContext) -> FocusHandle {
- self.panel_entries[self.active_panel_index]
- .panel
- .focus_handle(cx)
+ fn focus_handle(&self, _: &AppContext) -> FocusHandle {
+ self.focus_handle.clone()
}
}
@@ -190,12 +190,20 @@ pub struct PanelButtons {
}
impl Dock {
- pub fn new(position: DockPosition) -> Self {
+ pub fn new(position: DockPosition, cx: &mut ViewContext<'_, Self>) -> Self {
+ let focus_handle = cx.focus_handle();
+ let focus_subscription = cx.on_focus(&focus_handle, |dock, cx| {
+ if let Some(active_entry) = dock.panel_entries.get(dock.active_panel_index) {
+ active_entry.panel.focus_handle(cx).focus(cx)
+ }
+ });
Self {
position,
panel_entries: Default::default(),
active_panel_index: 0,
is_open: false,
+ focus_handle,
+ focus_subscription,
}
}
@@ -207,6 +215,7 @@ impl Dock {
self.is_open
}
+ // todo!()
// pub fn has_focus(&self, cx: &WindowContext) -> bool {
// self.visible_panel()
// .map_or(false, |panel| panel.has_focus(cx))
@@ -28,10 +28,10 @@ use std::{
use ui::{
h_stack, prelude::*, right_click_menu, ButtonSize, Color, Icon, IconButton, IconSize,
- Indicator, Label, Tooltip,
+ Indicator, Label, Tab, TabPosition, Tooltip,
};
use ui::{v_stack, ContextMenu};
-use util::truncate_and_remove_front;
+use util::{maybe, truncate_and_remove_front};
#[derive(PartialEq, Clone, Copy, Deserialize, Debug)]
#[serde(rename_all = "camelCase")]
@@ -1438,42 +1438,49 @@ impl Pane {
let is_active = ix == self.active_item_index;
- let indicator = {
+ let indicator = maybe!({
let indicator_color = match (item.has_conflict(cx), item.is_dirty(cx)) {
- (true, _) => Some(Color::Warning),
- (_, true) => Some(Color::Accent),
- (false, false) => None,
+ (true, _) => Color::Warning,
+ (_, true) => Color::Accent,
+ (false, false) => return None,
};
- h_stack()
- .w_3()
- .h_3()
- .justify_center()
- .absolute()
- .map(|this| match close_side {
- ClosePosition::Left => this.right_1(),
- ClosePosition::Right => this.left_1(),
+ Some(Indicator::dot().color(indicator_color))
+ });
+
+ let id = item.item_id();
+
+ let is_first_item = ix == 0;
+ let is_last_item = ix == self.items.len() - 1;
+ let position_relative_to_active_item = ix.cmp(&self.active_item_index);
+
+ let tab =
+ Tab::new(ix)
+ .position(if is_first_item {
+ TabPosition::First
+ } else if is_last_item {
+ TabPosition::Last
+ } else {
+ TabPosition::Middle(position_relative_to_active_item)
})
- .when_some(indicator_color, |this, indicator_color| {
- this.child(Indicator::dot().color(indicator_color))
+ .close_side(match close_side {
+ ClosePosition::Left => ui::TabCloseSide::Start,
+ ClosePosition::Right => ui::TabCloseSide::End,
})
- };
-
- let close_button = {
- let id = item.item_id();
-
- h_stack()
- .invisible()
- .w_3()
- .h_3()
- .justify_center()
- .absolute()
- .map(|this| match close_side {
- ClosePosition::Left => this.left_1(),
- ClosePosition::Right => this.right_1(),
+ .selected(ix == self.active_item_index())
+ .on_click(cx.listener(move |pane: &mut Self, event, cx| {
+ pane.activate_item(ix, true, true, 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))
+ // .on_drop(|_view, state: View<DraggedTab>, cx| {
+ // eprintln!("{:?}", state.read(cx));
+ // })
+ .when_some(item.tab_tooltip_text(cx), |tab, text| {
+ tab.tooltip(move |cx| Tooltip::text(text.clone(), cx))
})
- .group_hover("", |style| style.visible())
- .child(
+ .start_slot::<Indicator>(indicator)
+ .end_slot(
// TODO: Fix button size
IconButton::new("close tab", Icon::Close)
.icon_color(Color::Muted)
@@ -1484,67 +1491,7 @@ impl Pane {
.detach_and_log_err(cx);
})),
)
- };
-
- let tab = div()
- .border_color(cx.theme().colors().border)
- .bg(tab_bg)
- // 30px @ 16px/rem
- .h(rems(1.875))
- .map(|this| {
- let is_first_item = ix == 0;
- let is_last_item = ix == self.items.len() - 1;
- match ix.cmp(&self.active_item_index) {
- cmp::Ordering::Less => {
- if is_first_item {
- this.pl_px().pr_px().border_b()
- } else {
- this.border_l().pr_px().border_b()
- }
- }
- cmp::Ordering::Greater => {
- if is_last_item {
- this.pr_px().pl_px().border_b()
- } else {
- this.border_r().pl_px().border_b()
- }
- }
- cmp::Ordering::Equal => {
- if is_first_item {
- this.pl_px().border_r().pb_px()
- } else {
- this.border_l().border_r().pb_px()
- }
- }
- }
- })
- .child(
- h_stack()
- .group("")
- .id(ix)
- .relative()
- .h_full()
- .cursor_pointer()
- .when_some(item.tab_tooltip_text(cx), |div, text| {
- div.tooltip(move |cx| cx.build_view(|cx| Tooltip::new(text.clone())).into())
- })
- .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))
- // .drag_over::<DraggedTab>(|d| d.bg(cx.theme().colors().element_drop_target))
- // .on_drop(|_view, state: View<DraggedTab>, cx| {
- // eprintln!("{:?}", state.read(cx));
- // })
- .px_5()
- // .hover(|h| h.bg(tab_hover_bg))
- // .active(|a| a.bg(tab_active_bg))
- .gap_1()
- .text_color(text_color)
- .child(indicator)
- .child(close_button)
- .child(label),
- );
+ .child(label);
right_click_menu(ix).trigger(tab).menu(|cx| {
ContextMenu::build(cx, |menu, cx| {
@@ -566,9 +566,9 @@ impl Workspace {
cx.emit(Event::WorkspaceCreated(weak_handle.clone()));
- let left_dock = cx.build_view(|_| Dock::new(DockPosition::Left));
- let bottom_dock = cx.build_view(|_| Dock::new(DockPosition::Bottom));
- let right_dock = cx.build_view(|_| Dock::new(DockPosition::Right));
+ let left_dock = cx.build_view(|cx| Dock::new(DockPosition::Left, cx));
+ let bottom_dock = cx.build_view(|cx| Dock::new(DockPosition::Bottom, cx));
+ let right_dock = cx.build_view(|cx| Dock::new(DockPosition::Right, cx));
let left_dock_buttons =
cx.build_view(|cx| PanelButtons::new(left_dock.clone(), weak_handle.clone(), cx));
let bottom_dock_buttons =
@@ -4188,14 +4188,14 @@ pub fn open_paths(
});
cx.spawn(move |mut cx| async move {
if let Some(existing) = existing {
- // // Ok((
- // existing.clone(),
- // cx.update_window_root(&existing, |workspace, cx| {
- // workspace.open_paths(abs_paths, true, cx)
- // })?
- // .await,
- // ))
- todo!()
+ Ok((
+ existing.clone(),
+ existing
+ .update(&mut cx, |workspace, cx| {
+ workspace.open_paths(abs_paths, true, cx)
+ })?
+ .await,
+ ))
} else {
cx.update(move |cx| {
Workspace::new_local(abs_paths, app_state.clone(), requesting_window, cx)