Restore logical offset preservation behaviour
This commit is contained in:
parent
54cfcef0aa
commit
4fbbb28da2
2 changed files with 186 additions and 170 deletions
|
@ -303,7 +303,6 @@ pub struct CollabPanel {
|
||||||
project: Model<Project>,
|
project: Model<Project>,
|
||||||
match_candidates: Vec<StringMatchCandidate>,
|
match_candidates: Vec<StringMatchCandidate>,
|
||||||
scroll_handle: ScrollHandle,
|
scroll_handle: ScrollHandle,
|
||||||
// list_state: ListState<Self>,
|
|
||||||
subscriptions: Vec<Subscription>,
|
subscriptions: Vec<Subscription>,
|
||||||
collapsed_sections: Vec<Section>,
|
collapsed_sections: Vec<Section>,
|
||||||
collapsed_channels: Vec<ChannelId>,
|
collapsed_channels: Vec<ChannelId>,
|
||||||
|
@ -590,7 +589,6 @@ impl CollabPanel {
|
||||||
client: workspace.app_state().client.clone(),
|
client: workspace.app_state().client.clone(),
|
||||||
// context_menu_on_selected: true,
|
// context_menu_on_selected: true,
|
||||||
drag_target_channel: ChannelDragTarget::None,
|
drag_target_channel: ChannelDragTarget::None,
|
||||||
// list_state,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.update_entries(false, cx);
|
this.update_entries(false, cx);
|
||||||
|
@ -706,9 +704,9 @@ impl CollabPanel {
|
||||||
let query = self.filter_editor.read(cx).text(cx);
|
let query = self.filter_editor.read(cx).text(cx);
|
||||||
let executor = cx.background_executor().clone();
|
let executor = cx.background_executor().clone();
|
||||||
|
|
||||||
// let prev_selected_entry = self.selection.and_then(|ix| self.entries.get(ix).cloned());
|
let prev_selected_entry = self.selection.and_then(|ix| self.entries.get(ix).cloned());
|
||||||
let _old_entries = mem::take(&mut self.entries);
|
let old_entries = mem::take(&mut self.entries);
|
||||||
// let mut scroll_to_top = false;
|
let scroll_to_top = false;
|
||||||
|
|
||||||
// if let Some(room) = ActiveCall::global(cx).read(cx).room() {
|
// if let Some(room) = ActiveCall::global(cx).read(cx).room() {
|
||||||
// self.entries.push(ListEntry::Header(Section::ActiveCall));
|
// self.entries.push(ListEntry::Header(Section::ActiveCall));
|
||||||
|
@ -1075,71 +1073,62 @@ impl CollabPanel {
|
||||||
self.entries.push(ListEntry::ContactPlaceholder);
|
self.entries.push(ListEntry::ContactPlaceholder);
|
||||||
}
|
}
|
||||||
|
|
||||||
// if select_same_item {
|
if select_same_item {
|
||||||
// if let Some(prev_selected_entry) = prev_selected_entry {
|
if let Some(prev_selected_entry) = prev_selected_entry {
|
||||||
// self.selection.take();
|
self.selection.take();
|
||||||
// for (ix, entry) in self.entries.iter().enumerate() {
|
for (ix, entry) in self.entries.iter().enumerate() {
|
||||||
// if *entry == prev_selected_entry {
|
if *entry == prev_selected_entry {
|
||||||
// self.selection = Some(ix);
|
self.selection = Some(ix);
|
||||||
// break;
|
self.scroll_handle.scroll_to_item(ix);
|
||||||
// }
|
break;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// } else {
|
}
|
||||||
// self.selection = self.selection.and_then(|prev_selection| {
|
} else {
|
||||||
// if self.entries.is_empty() {
|
self.selection = self.selection.and_then(|prev_selection| {
|
||||||
// None
|
if self.entries.is_empty() {
|
||||||
// } else {
|
None
|
||||||
// Some(prev_selection.min(self.entries.len() - 1))
|
} else {
|
||||||
// }
|
let ix = prev_selection.min(self.entries.len() - 1);
|
||||||
// });
|
self.scroll_handle.scroll_to_item(ix);
|
||||||
// }
|
Some(ix)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
// let old_scroll_top = self.list_state.logical_scroll_top();
|
if scroll_to_top {
|
||||||
|
self.scroll_handle.scroll_to_item(0)
|
||||||
|
} else {
|
||||||
|
let (old_index, old_offset) = self.scroll_handle.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
|
||||||
|
.entries
|
||||||
|
.iter()
|
||||||
|
.position(|entry| entry == old_top_entry)
|
||||||
|
.map(|item_ix| (item_ix, old_offset))
|
||||||
|
.or_else(|| {
|
||||||
|
let entry_after_old_top = old_entries.get(old_index + 1)?;
|
||||||
|
let item_ix = self
|
||||||
|
.entries
|
||||||
|
.iter()
|
||||||
|
.position(|entry| entry == entry_after_old_top)?;
|
||||||
|
Some((item_ix, px(0.)))
|
||||||
|
})
|
||||||
|
.or_else(|| {
|
||||||
|
let entry_before_old_top = old_entries.get(old_index.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));
|
||||||
|
|
||||||
// self.list_state.reset(self.entries.len());
|
self.scroll_handle
|
||||||
|
.set_logical_scroll_top(new_index, new_offset);
|
||||||
// if scroll_to_top {
|
}
|
||||||
// self.list_state.scroll_to(ListOffset::default());
|
}
|
||||||
// } else {
|
|
||||||
// // Attempt to maintain the same scroll position.
|
|
||||||
// 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| ListOffset {
|
|
||||||
// item_ix,
|
|
||||||
// offset_in_item: old_scroll_top.offset_in_item,
|
|
||||||
// })
|
|
||||||
// .or_else(|| {
|
|
||||||
// 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(ListOffset {
|
|
||||||
// item_ix,
|
|
||||||
// offset_in_item: 0.,
|
|
||||||
// })
|
|
||||||
// })
|
|
||||||
// .or_else(|| {
|
|
||||||
// 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(ListOffset {
|
|
||||||
// item_ix,
|
|
||||||
// offset_in_item: 0.,
|
|
||||||
// })
|
|
||||||
// });
|
|
||||||
|
|
||||||
// self.list_state
|
|
||||||
// .scroll_to(new_scroll_top.unwrap_or(old_scroll_top));
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
cx.notify();
|
cx.notify();
|
||||||
}
|
}
|
||||||
|
@ -3430,106 +3419,106 @@ impl FocusableView for CollabPanel {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// impl PartialEq for ListEntry {
|
impl PartialEq for ListEntry {
|
||||||
// fn eq(&self, other: &Self) -> bool {
|
fn eq(&self, other: &Self) -> bool {
|
||||||
// match self {
|
match self {
|
||||||
// ListEntry::Header(section_1) => {
|
ListEntry::Header(section_1) => {
|
||||||
// if let ListEntry::Header(section_2) = other {
|
if let ListEntry::Header(section_2) = other {
|
||||||
// return section_1 == section_2;
|
return section_1 == section_2;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// ListEntry::CallParticipant { user: user_1, .. } => {
|
// ListEntry::CallParticipant { user: user_1, .. } => {
|
||||||
// if let ListEntry::CallParticipant { user: user_2, .. } = other {
|
// if let ListEntry::CallParticipant { user: user_2, .. } = other {
|
||||||
// return user_1.id == user_2.id;
|
// return user_1.id == user_2.id;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// ListEntry::ParticipantProject {
|
// ListEntry::ParticipantProject {
|
||||||
// project_id: project_id_1,
|
// project_id: project_id_1,
|
||||||
// ..
|
// ..
|
||||||
// } => {
|
// } => {
|
||||||
// if let ListEntry::ParticipantProject {
|
// if let ListEntry::ParticipantProject {
|
||||||
// project_id: project_id_2,
|
// project_id: project_id_2,
|
||||||
// ..
|
// ..
|
||||||
// } = other
|
// } = other
|
||||||
// {
|
// {
|
||||||
// return project_id_1 == project_id_2;
|
// return project_id_1 == project_id_2;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// ListEntry::ParticipantScreen {
|
// ListEntry::ParticipantScreen {
|
||||||
// peer_id: peer_id_1, ..
|
// peer_id: peer_id_1, ..
|
||||||
// } => {
|
// } => {
|
||||||
// if let ListEntry::ParticipantScreen {
|
// if let ListEntry::ParticipantScreen {
|
||||||
// peer_id: peer_id_2, ..
|
// peer_id: peer_id_2, ..
|
||||||
// } = other
|
// } = other
|
||||||
// {
|
// {
|
||||||
// return peer_id_1 == peer_id_2;
|
// return peer_id_1 == peer_id_2;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// ListEntry::Channel {
|
ListEntry::Channel {
|
||||||
// channel: channel_1, ..
|
channel: channel_1, ..
|
||||||
// } => {
|
} => {
|
||||||
// if let ListEntry::Channel {
|
if let ListEntry::Channel {
|
||||||
// channel: channel_2, ..
|
channel: channel_2, ..
|
||||||
// } = other
|
} = other
|
||||||
// {
|
{
|
||||||
// return channel_1.id == channel_2.id;
|
return channel_1.id == channel_2.id;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// ListEntry::ChannelNotes { channel_id } => {
|
// ListEntry::ChannelNotes { channel_id } => {
|
||||||
// if let ListEntry::ChannelNotes {
|
// if let ListEntry::ChannelNotes {
|
||||||
// channel_id: other_id,
|
// channel_id: other_id,
|
||||||
// } = other
|
// } = other
|
||||||
// {
|
// {
|
||||||
// return channel_id == other_id;
|
// return channel_id == other_id;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// ListEntry::ChannelChat { channel_id } => {
|
// ListEntry::ChannelChat { channel_id } => {
|
||||||
// if let ListEntry::ChannelChat {
|
// if let ListEntry::ChannelChat {
|
||||||
// channel_id: other_id,
|
// channel_id: other_id,
|
||||||
// } = other
|
// } = other
|
||||||
// {
|
// {
|
||||||
// return channel_id == other_id;
|
// return channel_id == other_id;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// ListEntry::ChannelInvite(channel_1) => {
|
// ListEntry::ChannelInvite(channel_1) => {
|
||||||
// if let ListEntry::ChannelInvite(channel_2) = other {
|
// if let ListEntry::ChannelInvite(channel_2) = other {
|
||||||
// return channel_1.id == channel_2.id;
|
// return channel_1.id == channel_2.id;
|
||||||
// }
|
// }
|
||||||
// }
|
// }
|
||||||
// ListEntry::IncomingRequest(user_1) => {
|
ListEntry::IncomingRequest(user_1) => {
|
||||||
// if let ListEntry::IncomingRequest(user_2) = other {
|
if let ListEntry::IncomingRequest(user_2) = other {
|
||||||
// return user_1.id == user_2.id;
|
return user_1.id == user_2.id;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// ListEntry::OutgoingRequest(user_1) => {
|
ListEntry::OutgoingRequest(user_1) => {
|
||||||
// if let ListEntry::OutgoingRequest(user_2) = other {
|
if let ListEntry::OutgoingRequest(user_2) = other {
|
||||||
// return user_1.id == user_2.id;
|
return user_1.id == user_2.id;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// ListEntry::Contact {
|
ListEntry::Contact {
|
||||||
// contact: contact_1, ..
|
contact: contact_1, ..
|
||||||
// } => {
|
} => {
|
||||||
// if let ListEntry::Contact {
|
if let ListEntry::Contact {
|
||||||
// contact: contact_2, ..
|
contact: contact_2, ..
|
||||||
// } = other
|
} = other
|
||||||
// {
|
{
|
||||||
// return contact_1.user.id == contact_2.user.id;
|
return contact_1.user.id == contact_2.user.id;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// ListEntry::ChannelEditor { depth } => {
|
ListEntry::ChannelEditor { depth } => {
|
||||||
// if let ListEntry::ChannelEditor { depth: other_depth } = other {
|
if let ListEntry::ChannelEditor { depth: other_depth } = other {
|
||||||
// return depth == other_depth;
|
return depth == other_depth;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// ListEntry::ContactPlaceholder => {
|
ListEntry::ContactPlaceholder => {
|
||||||
// if let ListEntry::ContactPlaceholder = other {
|
if let ListEntry::ContactPlaceholder = other {
|
||||||
// return true;
|
return true;
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
// false
|
false
|
||||||
// }
|
}
|
||||||
// }
|
}
|
||||||
|
|
||||||
// fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element<CollabPanel> {
|
// fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element<CollabPanel> {
|
||||||
// Svg::new(svg_path)
|
// Svg::new(svg_path)
|
||||||
|
|
|
@ -636,12 +636,20 @@ impl Element for Div {
|
||||||
let mut state = scroll_handle.0.borrow_mut();
|
let mut state = scroll_handle.0.borrow_mut();
|
||||||
state.child_bounds = Vec::with_capacity(element_state.child_layout_ids.len());
|
state.child_bounds = Vec::with_capacity(element_state.child_layout_ids.len());
|
||||||
state.bounds = bounds;
|
state.bounds = bounds;
|
||||||
|
let requested = state.requested_scroll_top.take();
|
||||||
|
|
||||||
for child_layout_id in &element_state.child_layout_ids {
|
for (ix, child_layout_id) in element_state.child_layout_ids.iter().enumerate() {
|
||||||
let child_bounds = cx.layout_bounds(*child_layout_id);
|
let child_bounds = cx.layout_bounds(*child_layout_id);
|
||||||
child_min = child_min.min(&child_bounds.origin);
|
child_min = child_min.min(&child_bounds.origin);
|
||||||
child_max = child_max.max(&child_bounds.lower_right());
|
child_max = child_max.max(&child_bounds.lower_right());
|
||||||
state.child_bounds.push(child_bounds)
|
state.child_bounds.push(child_bounds);
|
||||||
|
|
||||||
|
if let Some(requested) = requested.as_ref() {
|
||||||
|
if requested.0 == ix {
|
||||||
|
*state.offset.borrow_mut() =
|
||||||
|
bounds.origin - (child_bounds.origin - point(px(0.), requested.1));
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
(child_max - child_min).into()
|
(child_max - child_min).into()
|
||||||
} else {
|
} else {
|
||||||
|
@ -1460,6 +1468,7 @@ struct ScrollHandleState {
|
||||||
offset: Rc<RefCell<Point<Pixels>>>,
|
offset: Rc<RefCell<Point<Pixels>>>,
|
||||||
bounds: Bounds<Pixels>,
|
bounds: Bounds<Pixels>,
|
||||||
child_bounds: Vec<Bounds<Pixels>>,
|
child_bounds: Vec<Bounds<Pixels>>,
|
||||||
|
requested_scroll_top: Option<(usize, Pixels)>,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
|
@ -1513,4 +1522,22 @@ impl ScrollHandle {
|
||||||
state.offset.borrow_mut().y = state.bounds.bottom() - bounds.bottom();
|
state.offset.borrow_mut().y = state.bounds.bottom() - bounds.bottom();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn logical_scroll_top(&self) -> (usize, Pixels) {
|
||||||
|
let ix = self.top_item();
|
||||||
|
let state = self.0.borrow();
|
||||||
|
|
||||||
|
if let Some(child_bounds) = state.child_bounds.get(ix) {
|
||||||
|
(
|
||||||
|
ix,
|
||||||
|
child_bounds.top() + state.offset.borrow().y - state.bounds.top(),
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
(ix, px(0.))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn set_logical_scroll_top(&self, ix: usize, px: Pixels) {
|
||||||
|
self.0.borrow_mut().requested_scroll_top = Some((ix, px));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue