Merge branch 'main' into fix-panel-resize
This commit is contained in:
commit
cf037ea4a8
13 changed files with 131 additions and 95 deletions
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue