Detailed changes
@@ -962,15 +962,12 @@ impl CollabPanel {
self.entries.push(ListEntry::ContactPlaceholder);
}
- self.list_state.reset(self.entries.len());
-
if select_same_item {
if let Some(prev_selected_entry) = prev_selected_entry {
self.selection.take();
for (ix, entry) in self.entries.iter().enumerate() {
if *entry == prev_selected_entry {
self.selection = Some(ix);
- self.scroll_to_item(ix);
break;
}
}
@@ -980,49 +977,53 @@ impl CollabPanel {
if self.entries.is_empty() {
None
} else {
- let ix = prev_selection.min(self.entries.len() - 1);
- self.scroll_to_item(ix);
- Some(ix)
+ Some(prev_selection.min(self.entries.len() - 1))
}
});
}
+ let old_scroll_top = self.list_state.logical_scroll_top();
+ self.list_state.reset(self.entries.len());
+
if scroll_to_top {
- self.scroll_to_item(0)
+ self.list_state.scroll_to(ListOffset::default());
} else {
- let ListOffset {
- item_ix: old_index,
- offset_in_item: old_offset,
- } = self.list_state.logical_scroll_top();
// Attempt to maintain the same scroll position.
- if let Some(old_top_entry) = old_entries.get(old_index) {
- let (new_index, new_offset) = self
+ if let Some(old_top_entry) = old_entries.get(old_scroll_top.item_ix) {
+ let new_scroll_top = self
.entries
.iter()
.position(|entry| entry == old_top_entry)
- .map(|item_ix| (item_ix, old_offset))
+ .map(|item_ix| ListOffset {
+ item_ix,
+ offset_in_item: old_scroll_top.offset_in_item,
+ })
.or_else(|| {
- let entry_after_old_top = old_entries.get(old_index + 1)?;
+ let entry_after_old_top = old_entries.get(old_scroll_top.item_ix + 1)?;
let item_ix = self
.entries
.iter()
.position(|entry| entry == entry_after_old_top)?;
- Some((item_ix, px(0.)))
+ Some(ListOffset {
+ item_ix,
+ offset_in_item: Pixels::ZERO,
+ })
})
.or_else(|| {
- let entry_before_old_top = old_entries.get(old_index.saturating_sub(1))?;
+ let entry_before_old_top =
+ old_entries.get(old_scroll_top.item_ix.saturating_sub(1))?;
let item_ix = self
.entries
.iter()
.position(|entry| entry == entry_before_old_top)?;
- Some((item_ix, px(0.)))
- })
- .unwrap_or_else(|| (old_index, old_offset));
+ Some(ListOffset {
+ item_ix,
+ offset_in_item: Pixels::ZERO,
+ })
+ });
- self.list_state.scroll_to(ListOffset {
- item_ix: new_index,
- offset_in_item: new_offset,
- });
+ self.list_state
+ .scroll_to(new_scroll_top.unwrap_or(old_scroll_top));
}
}
@@ -3,11 +3,12 @@ use call::{room, ActiveCall};
use client::User;
use collections::HashMap;
use gpui::{
- px, AppContext, Div, Element, ParentElement, Render, RenderOnce, Size, Styled, ViewContext,
- VisualContext,
+ img, px, AppContext, Div, ParentElement, Render, Size, Styled, ViewContext, VisualContext,
};
+use settings::Settings;
use std::sync::{Arc, Weak};
-use ui::{h_stack, v_stack, Avatar, Button, Clickable, Label};
+use theme::ThemeSettings;
+use ui::{h_stack, prelude::*, v_stack, Button, Label};
use workspace::AppState;
pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
@@ -21,8 +22,8 @@ pub fn init(app_state: &Arc<AppState>, cx: &mut AppContext) {
worktree_root_names,
} => {
let window_size = Size {
- width: px(380.),
- height: px(64.),
+ width: px(400.),
+ height: px(96.),
};
for screen in cx.displays() {
@@ -116,56 +117,70 @@ impl ProjectSharedNotification {
});
}
}
-
- fn render_owner(&self) -> impl Element {
- h_stack()
- .child(Avatar::new(self.owner.avatar_uri.clone()))
- .child(
- v_stack()
- .child(Label::new(self.owner.github_login.clone()))
- .child(Label::new(format!(
- "is sharing a project in Zed{}",
- if self.worktree_root_names.is_empty() {
- ""
- } else {
- ":"
- }
- )))
- .children(if self.worktree_root_names.is_empty() {
- None
- } else {
- Some(Label::new(self.worktree_root_names.join(", ")))
- }),
- )
- }
-
- fn render_buttons(&self, cx: &mut ViewContext<Self>) -> impl Element {
- let this = cx.view().clone();
- v_stack()
- .child(Button::new("open", "Open").render(cx).on_click({
- let this = this.clone();
- move |_, cx| {
- this.update(cx, |this, cx| this.join(cx));
- }
- }))
- .child(
- Button::new("dismiss", "Dismiss")
- .render(cx)
- .on_click(move |_, cx| {
- this.update(cx, |this, cx| this.dismiss(cx));
- }),
- )
- }
}
impl Render for ProjectSharedNotification {
type Element = Div;
fn render(&mut self, cx: &mut ViewContext<Self>) -> Self::Element {
+ // TODO: Is there a better place for us to initialize the font?
+ let (ui_font, ui_font_size) = {
+ let theme_settings = ThemeSettings::get_global(cx);
+ (
+ theme_settings.ui_font.family.clone(),
+ theme_settings.ui_font_size.clone(),
+ )
+ };
+
+ cx.set_rem_size(ui_font_size);
+
h_stack()
+ .font(ui_font)
+ .text_ui()
+ .justify_between()
.size_full()
- .bg(gpui::red())
- .child(self.render_owner())
- .child(self.render_buttons(cx))
+ .elevation_3(cx)
+ .p_2()
+ .gap_2()
+ .child(
+ h_stack()
+ .gap_2()
+ .child(
+ img(self.owner.avatar_uri.clone())
+ .w_16()
+ .h_16()
+ .rounded_full(),
+ )
+ .child(
+ v_stack()
+ .child(Label::new(self.owner.github_login.clone()))
+ .child(Label::new(format!(
+ "is sharing a project in Zed{}",
+ if self.worktree_root_names.is_empty() {
+ ""
+ } else {
+ ":"
+ }
+ )))
+ .children(if self.worktree_root_names.is_empty() {
+ None
+ } else {
+ Some(Label::new(self.worktree_root_names.join(", ")))
+ }),
+ ),
+ )
+ .child(
+ v_stack()
+ .child(Button::new("open", "Open").on_click(cx.listener(
+ move |this, _event, cx| {
+ this.join(cx);
+ },
+ )))
+ .child(Button::new("dismiss", "Dismiss").on_click(cx.listener(
+ move |this, _event, cx| {
+ this.dismiss(cx);
+ },
+ ))),
+ )
}
}
@@ -1351,7 +1351,7 @@ impl EditorElement {
));
}
- let mouse_position = cx.mouse_position();
+ let mut mouse_position = cx.mouse_position();
if track_bounds.contains(&mouse_position) {
cx.set_cursor_style(CursorStyle::Arrow);
}
@@ -1377,6 +1377,8 @@ impl EditorElement {
}
editor.set_scroll_position(position, cx);
}
+
+ mouse_position = event.position;
cx.stop_propagation();
} else {
editor.scroll_manager.set_is_dragging_scrollbar(false, cx);
@@ -1392,6 +1394,10 @@ impl EditorElement {
cx.on_mouse_event({
let editor = self.editor.clone();
move |event: &MouseUpEvent, phase, cx| {
+ if phase == DispatchPhase::Capture {
+ return;
+ }
+
editor.update(cx, |editor, cx| {
editor.scroll_manager.set_is_dragging_scrollbar(false, cx);
cx.stop_propagation();
@@ -1402,6 +1408,10 @@ impl EditorElement {
cx.on_mouse_event({
let editor = self.editor.clone();
move |event: &MouseDownEvent, phase, cx| {
+ if phase == DispatchPhase::Capture {
+ return;
+ }
+
editor.update(cx, |editor, cx| {
if track_bounds.contains(&event.position) {
editor.scroll_manager.set_is_dragging_scrollbar(true, cx);
@@ -567,12 +567,7 @@ impl<'a> VisualTestContext<'a> {
pub fn window_title(&mut self) -> Option<String> {
self.cx
.update_window(self.window, |_, cx| {
- cx.window
- .platform_window
- .as_test()
- .unwrap()
- .window_title
- .clone()
+ cx.window.platform_window.as_test().unwrap().title.clone()
})
.unwrap()
}
@@ -1061,7 +1061,7 @@ impl Interactivity {
{
cx.focus(&focus_handle);
// If there is a parent that is also focusable, prevent it
- // from trasferring focus because we already did so.
+ // from transferring focus because we already did so.
cx.prevent_default();
}
}
@@ -293,7 +293,7 @@ impl std::fmt::Debug for ListItem {
}
}
-#[derive(Debug, Clone, Copy)]
+#[derive(Debug, Clone, Copy, Default)]
pub struct ListOffset {
pub item_ix: usize,
pub offset_in_item: Pixels,
@@ -21,7 +21,8 @@ pub(crate) struct TestWindowHandlers {
pub struct TestWindow {
pub(crate) bounds: WindowBounds,
display: Rc<dyn PlatformDisplay>,
- pub(crate) window_title: Option<String>,
+ pub(crate) title: Option<String>,
+ pub(crate) edited: bool,
pub(crate) input_handler: Option<Arc<Mutex<Box<dyn PlatformInputHandler>>>>,
pub(crate) handlers: Arc<Mutex<TestWindowHandlers>>,
platform: Weak<TestPlatform>,
@@ -41,7 +42,8 @@ impl TestWindow {
input_handler: None,
sprite_atlas: Arc::new(TestAtlas::new()),
handlers: Default::default(),
- window_title: Default::default(),
+ title: Default::default(),
+ edited: false,
}
}
}
@@ -109,11 +111,11 @@ impl PlatformWindow for TestWindow {
}
fn set_title(&mut self, title: &str) {
- self.window_title = Some(title.to_owned());
+ self.title = Some(title.to_owned());
}
- fn set_edited(&mut self, _edited: bool) {
- unimplemented!()
+ fn set_edited(&mut self, edited: bool) {
+ self.edited = edited;
}
fn show_character_palette(&self) {
@@ -773,6 +773,10 @@ impl<'a> WindowContext<'a> {
self.window.platform_window.set_title(title);
}
+ pub fn set_window_edited(&mut self, edited: bool) {
+ self.window.platform_window.set_edited(edited);
+ }
+
pub fn display(&self) -> Option<Rc<dyn PlatformDisplay>> {
self.platform
.displays()
@@ -752,8 +752,7 @@ impl Item for TerminalView {
) -> Task<anyhow::Result<View<Self>>> {
let window = cx.window_handle();
cx.spawn(|pane, mut cx| async move {
- let cwd = None;
- TERMINAL_DB
+ let cwd = TERMINAL_DB
.get_working_directory(item_id, workspace_id)
.log_err()
.flatten()
@@ -1,4 +1,4 @@
-use gpui::{relative, DefiniteLength};
+use gpui::{relative, DefiniteLength, MouseButton};
use gpui::{rems, transparent_black, AnyElement, AnyView, ClickEvent, Div, Hsla, Rems, Stateful};
use smallvec::SmallVec;
@@ -372,10 +372,11 @@ impl RenderOnce for ButtonLike {
.when_some(
self.on_click.filter(|_| !self.disabled),
|this, on_click| {
- this.on_click(move |event, cx| {
- cx.stop_propagation();
- (on_click)(event, cx)
- })
+ this.on_mouse_down(MouseButton::Left, |_, cx| cx.prevent_default())
+ .on_click(move |event, cx| {
+ cx.stop_propagation();
+ (on_click)(event, cx)
+ })
},
)
.when_some(self.tooltip, |this, tooltip| {
@@ -5,6 +5,7 @@ use crate::StyledExt;
/// Horizontally stacks elements.
///
/// Sets `flex()`, `flex_row()`, `items_center()`
+#[track_caller]
pub fn h_stack() -> Div {
div().h_flex()
}
@@ -12,6 +13,7 @@ pub fn h_stack() -> Div {
/// Vertically stacks elements.
///
/// Sets `flex()`, `flex_col()`
+#[track_caller]
pub fn v_stack() -> Div {
div().v_flex()
}
@@ -1493,6 +1493,14 @@ impl Pane {
.on_click(
cx.listener(move |pane: &mut Self, _, cx| pane.activate_item(ix, true, true, cx)),
)
+ // TODO: This should be a click listener with the middle mouse button instead of a mouse down listener.
+ .on_mouse_down(
+ MouseButton::Middle,
+ cx.listener(move |pane, _event, cx| {
+ pane.close_item_by_id(item_id, SaveIntent::Close, cx)
+ .detach_and_log_err(cx);
+ }),
+ )
.on_drag(
DraggedTab {
pane: cx.view().clone(),
@@ -2520,8 +2520,7 @@ impl Workspace {
.any(|item| item.has_conflict(cx) || item.is_dirty(cx));
if is_edited != self.window_edited {
self.window_edited = is_edited;
- // todo!()
- // cx.set_window_edited(self.window_edited)
+ cx.set_window_edited(self.window_edited)
}
}