diff --git a/crates/collab_ui2/src/collab_panel.rs b/crates/collab_ui2/src/collab_panel.rs index 9c9683d5cb5984da3b98150899f4e807f1e61ada..b62056a3be92ba178e62b44d4b1557c0d848f2a8 100644 --- a/crates/collab_ui2/src/collab_panel.rs +++ b/crates/collab_ui2/src/collab_panel.rs @@ -303,7 +303,6 @@ pub struct CollabPanel { project: Model, match_candidates: Vec, scroll_handle: ScrollHandle, - // list_state: ListState, subscriptions: Vec, collapsed_sections: Vec
, collapsed_channels: Vec, @@ -590,7 +589,6 @@ impl CollabPanel { client: workspace.app_state().client.clone(), // context_menu_on_selected: true, drag_target_channel: ChannelDragTarget::None, - // list_state, }; this.update_entries(false, cx); @@ -706,9 +704,9 @@ impl CollabPanel { let query = self.filter_editor.read(cx).text(cx); let executor = cx.background_executor().clone(); - // let prev_selected_entry = self.selection.and_then(|ix| self.entries.get(ix).cloned()); - let _old_entries = mem::take(&mut self.entries); - // let mut scroll_to_top = false; + let prev_selected_entry = self.selection.and_then(|ix| self.entries.get(ix).cloned()); + let old_entries = mem::take(&mut self.entries); + let scroll_to_top = false; // if let Some(room) = ActiveCall::global(cx).read(cx).room() { // self.entries.push(ListEntry::Header(Section::ActiveCall)); @@ -1075,71 +1073,62 @@ impl CollabPanel { self.entries.push(ListEntry::ContactPlaceholder); } - // 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); - // break; - // } - // } - // } - // } else { - // self.selection = self.selection.and_then(|prev_selection| { - // if self.entries.is_empty() { - // None - // } else { - // Some(prev_selection.min(self.entries.len() - 1)) - // } - // }); - // } + 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_handle.scroll_to_item(ix); + break; + } + } + } + } else { + self.selection = self.selection.and_then(|prev_selection| { + if self.entries.is_empty() { + None + } 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(); - - // self.list_state.reset(self.entries.len()); - - // 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., - // }) - // }); + 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 - // .scroll_to(new_scroll_top.unwrap_or(old_scroll_top)); - // } - // } + self.scroll_handle + .set_logical_scroll_top(new_index, new_offset); + } + } cx.notify(); } @@ -3430,106 +3419,106 @@ impl FocusableView for CollabPanel { } } -// impl PartialEq for ListEntry { -// fn eq(&self, other: &Self) -> bool { -// match self { -// ListEntry::Header(section_1) => { -// if let ListEntry::Header(section_2) = other { -// return section_1 == section_2; -// } -// } -// ListEntry::CallParticipant { user: user_1, .. } => { -// if let ListEntry::CallParticipant { user: user_2, .. } = other { -// return user_1.id == user_2.id; -// } -// } -// ListEntry::ParticipantProject { -// project_id: project_id_1, -// .. -// } => { -// if let ListEntry::ParticipantProject { -// project_id: project_id_2, -// .. -// } = other -// { -// return project_id_1 == project_id_2; -// } -// } -// ListEntry::ParticipantScreen { -// peer_id: peer_id_1, .. -// } => { -// if let ListEntry::ParticipantScreen { -// peer_id: peer_id_2, .. -// } = other -// { -// return peer_id_1 == peer_id_2; -// } -// } -// ListEntry::Channel { -// channel: channel_1, .. -// } => { -// if let ListEntry::Channel { -// channel: channel_2, .. -// } = other -// { -// return channel_1.id == channel_2.id; -// } -// } -// ListEntry::ChannelNotes { channel_id } => { -// if let ListEntry::ChannelNotes { -// channel_id: other_id, -// } = other -// { -// return channel_id == other_id; -// } -// } -// ListEntry::ChannelChat { channel_id } => { -// if let ListEntry::ChannelChat { -// channel_id: other_id, -// } = other -// { -// return channel_id == other_id; -// } -// } -// ListEntry::ChannelInvite(channel_1) => { -// if let ListEntry::ChannelInvite(channel_2) = other { -// return channel_1.id == channel_2.id; -// } -// } -// ListEntry::IncomingRequest(user_1) => { -// if let ListEntry::IncomingRequest(user_2) = other { -// return user_1.id == user_2.id; -// } -// } -// ListEntry::OutgoingRequest(user_1) => { -// if let ListEntry::OutgoingRequest(user_2) = other { -// return user_1.id == user_2.id; -// } -// } -// ListEntry::Contact { -// contact: contact_1, .. -// } => { -// if let ListEntry::Contact { -// contact: contact_2, .. -// } = other -// { -// return contact_1.user.id == contact_2.user.id; -// } -// } -// ListEntry::ChannelEditor { depth } => { -// if let ListEntry::ChannelEditor { depth: other_depth } = other { -// return depth == other_depth; -// } -// } -// ListEntry::ContactPlaceholder => { -// if let ListEntry::ContactPlaceholder = other { -// return true; -// } -// } -// } -// false -// } -// } +impl PartialEq for ListEntry { + fn eq(&self, other: &Self) -> bool { + match self { + ListEntry::Header(section_1) => { + if let ListEntry::Header(section_2) = other { + return section_1 == section_2; + } + } + // ListEntry::CallParticipant { user: user_1, .. } => { + // if let ListEntry::CallParticipant { user: user_2, .. } = other { + // return user_1.id == user_2.id; + // } + // } + // ListEntry::ParticipantProject { + // project_id: project_id_1, + // .. + // } => { + // if let ListEntry::ParticipantProject { + // project_id: project_id_2, + // .. + // } = other + // { + // return project_id_1 == project_id_2; + // } + // } + // ListEntry::ParticipantScreen { + // peer_id: peer_id_1, .. + // } => { + // if let ListEntry::ParticipantScreen { + // peer_id: peer_id_2, .. + // } = other + // { + // return peer_id_1 == peer_id_2; + // } + // } + ListEntry::Channel { + channel: channel_1, .. + } => { + if let ListEntry::Channel { + channel: channel_2, .. + } = other + { + return channel_1.id == channel_2.id; + } + } + // ListEntry::ChannelNotes { channel_id } => { + // if let ListEntry::ChannelNotes { + // channel_id: other_id, + // } = other + // { + // return channel_id == other_id; + // } + // } + // ListEntry::ChannelChat { channel_id } => { + // if let ListEntry::ChannelChat { + // channel_id: other_id, + // } = other + // { + // return channel_id == other_id; + // } + // } + // ListEntry::ChannelInvite(channel_1) => { + // if let ListEntry::ChannelInvite(channel_2) = other { + // return channel_1.id == channel_2.id; + // } + // } + ListEntry::IncomingRequest(user_1) => { + if let ListEntry::IncomingRequest(user_2) = other { + return user_1.id == user_2.id; + } + } + ListEntry::OutgoingRequest(user_1) => { + if let ListEntry::OutgoingRequest(user_2) = other { + return user_1.id == user_2.id; + } + } + ListEntry::Contact { + contact: contact_1, .. + } => { + if let ListEntry::Contact { + contact: contact_2, .. + } = other + { + return contact_1.user.id == contact_2.user.id; + } + } + ListEntry::ChannelEditor { depth } => { + if let ListEntry::ChannelEditor { depth: other_depth } = other { + return depth == other_depth; + } + } + ListEntry::ContactPlaceholder => { + if let ListEntry::ContactPlaceholder = other { + return true; + } + } + } + false + } +} // fn render_icon_button(style: &IconButton, svg_path: &'static str) -> impl Element { // Svg::new(svg_path) diff --git a/crates/gpui2/src/elements/div.rs b/crates/gpui2/src/elements/div.rs index 26e83a88f980b6450118470f1995ae28b7acb0e8..ced0a4767cc988d58ea49dcc6b3f3c7a78b34b4f 100644 --- a/crates/gpui2/src/elements/div.rs +++ b/crates/gpui2/src/elements/div.rs @@ -636,12 +636,20 @@ impl Element for Div { let mut state = scroll_handle.0.borrow_mut(); state.child_bounds = Vec::with_capacity(element_state.child_layout_ids.len()); 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); child_min = child_min.min(&child_bounds.origin); 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() } else { @@ -1460,6 +1468,7 @@ struct ScrollHandleState { offset: Rc>>, bounds: Bounds, child_bounds: Vec>, + requested_scroll_top: Option<(usize, Pixels)>, } #[derive(Clone)] @@ -1513,4 +1522,22 @@ impl ScrollHandle { 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)); + } }