Rename Handle to Model
This commit is contained in:
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,993 @@
|
||||
use crate::{AppState, FollowerState, Pane, Workspace};
|
||||
use anyhow::{anyhow, Result};
|
||||
use call2::ActiveCall;
|
||||
use collections::HashMap;
|
||||
use gpui2::{size, AnyElement, AnyView, Bounds, Handle, Pixels, Point, View, ViewContext};
|
||||
use project2::Project;
|
||||
use serde::Deserialize;
|
||||
use std::{cell::RefCell, rc::Rc, sync::Arc};
|
||||
use theme2::Theme;
|
||||
|
||||
const HANDLE_HITBOX_SIZE: f32 = 4.0;
|
||||
const HORIZONTAL_MIN_SIZE: f32 = 80.;
|
||||
const VERTICAL_MIN_SIZE: f32 = 100.;
|
||||
|
||||
pub enum Axis {
|
||||
Vertical,
|
||||
Horizontal,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct PaneGroup {
|
||||
pub(crate) root: Member,
|
||||
}
|
||||
|
||||
impl PaneGroup {
|
||||
pub(crate) fn with_root(root: Member) -> Self {
|
||||
Self { root }
|
||||
}
|
||||
|
||||
pub fn new(pane: View<Pane>) -> Self {
|
||||
Self {
|
||||
root: Member::Pane(pane),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn split(
|
||||
&mut self,
|
||||
old_pane: &View<Pane>,
|
||||
new_pane: &View<Pane>,
|
||||
direction: SplitDirection,
|
||||
) -> Result<()> {
|
||||
match &mut self.root {
|
||||
Member::Pane(pane) => {
|
||||
if pane == old_pane {
|
||||
self.root = Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
|
||||
Ok(())
|
||||
} else {
|
||||
Err(anyhow!("Pane not found"))
|
||||
}
|
||||
}
|
||||
Member::Axis(axis) => axis.split(old_pane, new_pane, direction),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
|
||||
match &self.root {
|
||||
Member::Pane(_) => None,
|
||||
Member::Axis(axis) => axis.bounding_box_for_pane(pane),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
|
||||
match &self.root {
|
||||
Member::Pane(pane) => Some(pane),
|
||||
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns:
|
||||
/// - Ok(true) if it found and removed a pane
|
||||
/// - Ok(false) if it found but did not remove the pane
|
||||
/// - Err(_) if it did not find the pane
|
||||
pub fn remove(&mut self, pane: &View<Pane>) -> Result<bool> {
|
||||
match &mut self.root {
|
||||
Member::Pane(_) => Ok(false),
|
||||
Member::Axis(axis) => {
|
||||
if let Some(last_pane) = axis.remove(pane)? {
|
||||
self.root = last_pane;
|
||||
}
|
||||
Ok(true)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
|
||||
match &mut self.root {
|
||||
Member::Pane(_) => {}
|
||||
Member::Axis(axis) => axis.swap(from, to),
|
||||
};
|
||||
}
|
||||
|
||||
pub(crate) fn render(
|
||||
&self,
|
||||
project: &Handle<Project>,
|
||||
theme: &Theme,
|
||||
follower_states: &HashMap<View<Pane>, FollowerState>,
|
||||
active_call: Option<&Handle<ActiveCall>>,
|
||||
active_pane: &View<Pane>,
|
||||
zoomed: Option<&AnyView>,
|
||||
app_state: &Arc<AppState>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> AnyElement<Workspace> {
|
||||
self.root.render(
|
||||
project,
|
||||
0,
|
||||
theme,
|
||||
follower_states,
|
||||
active_call,
|
||||
active_pane,
|
||||
zoomed,
|
||||
app_state,
|
||||
cx,
|
||||
)
|
||||
}
|
||||
|
||||
pub(crate) fn panes(&self) -> Vec<&View<Pane>> {
|
||||
let mut panes = Vec::new();
|
||||
self.root.collect_panes(&mut panes);
|
||||
panes
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) enum Member {
|
||||
Axis(PaneAxis),
|
||||
Pane(View<Pane>),
|
||||
}
|
||||
|
||||
impl Member {
|
||||
fn new_axis(old_pane: View<Pane>, new_pane: View<Pane>, direction: SplitDirection) -> Self {
|
||||
use Axis::*;
|
||||
use SplitDirection::*;
|
||||
|
||||
let axis = match direction {
|
||||
Up | Down => Vertical,
|
||||
Left | Right => Horizontal,
|
||||
};
|
||||
|
||||
let members = match direction {
|
||||
Up | Left => vec![Member::Pane(new_pane), Member::Pane(old_pane)],
|
||||
Down | Right => vec![Member::Pane(old_pane), Member::Pane(new_pane)],
|
||||
};
|
||||
|
||||
Member::Axis(PaneAxis::new(axis, members))
|
||||
}
|
||||
|
||||
fn contains(&self, needle: &View<Pane>) -> bool {
|
||||
match self {
|
||||
Member::Axis(axis) => axis.members.iter().any(|member| member.contains(needle)),
|
||||
Member::Pane(pane) => pane == needle,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn render(
|
||||
&self,
|
||||
project: &Handle<Project>,
|
||||
basis: usize,
|
||||
theme: &Theme,
|
||||
follower_states: &HashMap<View<Pane>, FollowerState>,
|
||||
active_call: Option<&Handle<ActiveCall>>,
|
||||
active_pane: &View<Pane>,
|
||||
zoomed: Option<&AnyView>,
|
||||
app_state: &Arc<AppState>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> AnyElement<Workspace> {
|
||||
todo!()
|
||||
|
||||
// enum FollowIntoExternalProject {}
|
||||
|
||||
// match self {
|
||||
// Member::Pane(pane) => {
|
||||
// let pane_element = if Some(&**pane) == zoomed {
|
||||
// Empty::new().into_any()
|
||||
// } else {
|
||||
// ChildView::new(pane, cx).into_any()
|
||||
// };
|
||||
|
||||
// let leader = follower_states.get(pane).and_then(|state| {
|
||||
// let room = active_call?.read(cx).room()?.read(cx);
|
||||
// room.remote_participant_for_peer_id(state.leader_id)
|
||||
// });
|
||||
|
||||
// let mut leader_border = Border::default();
|
||||
// let mut leader_status_box = None;
|
||||
// if let Some(leader) = &leader {
|
||||
// let leader_color = theme
|
||||
// .editor
|
||||
// .selection_style_for_room_participant(leader.participant_index.0)
|
||||
// .cursor;
|
||||
// leader_border = Border::all(theme.workspace.leader_border_width, leader_color);
|
||||
// leader_border
|
||||
// .color
|
||||
// .fade_out(1. - theme.workspace.leader_border_opacity);
|
||||
// leader_border.overlay = true;
|
||||
|
||||
// leader_status_box = match leader.location {
|
||||
// ParticipantLocation::SharedProject {
|
||||
// project_id: leader_project_id,
|
||||
// } => {
|
||||
// if Some(leader_project_id) == project.read(cx).remote_id() {
|
||||
// None
|
||||
// } else {
|
||||
// let leader_user = leader.user.clone();
|
||||
// let leader_user_id = leader.user.id;
|
||||
// Some(
|
||||
// MouseEventHandler::new::<FollowIntoExternalProject, _>(
|
||||
// pane.id(),
|
||||
// cx,
|
||||
// |_, _| {
|
||||
// Label::new(
|
||||
// format!(
|
||||
// "Follow {} to their active project",
|
||||
// leader_user.github_login,
|
||||
// ),
|
||||
// theme
|
||||
// .workspace
|
||||
// .external_location_message
|
||||
// .text
|
||||
// .clone(),
|
||||
// )
|
||||
// .contained()
|
||||
// .with_style(
|
||||
// theme.workspace.external_location_message.container,
|
||||
// )
|
||||
// },
|
||||
// )
|
||||
// .with_cursor_style(CursorStyle::PointingHand)
|
||||
// .on_click(MouseButton::Left, move |_, this, cx| {
|
||||
// crate::join_remote_project(
|
||||
// leader_project_id,
|
||||
// leader_user_id,
|
||||
// this.app_state().clone(),
|
||||
// cx,
|
||||
// )
|
||||
// .detach_and_log_err(cx);
|
||||
// })
|
||||
// .aligned()
|
||||
// .bottom()
|
||||
// .right()
|
||||
// .into_any(),
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// ParticipantLocation::UnsharedProject => Some(
|
||||
// Label::new(
|
||||
// format!(
|
||||
// "{} is viewing an unshared Zed project",
|
||||
// leader.user.github_login
|
||||
// ),
|
||||
// theme.workspace.external_location_message.text.clone(),
|
||||
// )
|
||||
// .contained()
|
||||
// .with_style(theme.workspace.external_location_message.container)
|
||||
// .aligned()
|
||||
// .bottom()
|
||||
// .right()
|
||||
// .into_any(),
|
||||
// ),
|
||||
// ParticipantLocation::External => Some(
|
||||
// Label::new(
|
||||
// format!(
|
||||
// "{} is viewing a window outside of Zed",
|
||||
// leader.user.github_login
|
||||
// ),
|
||||
// theme.workspace.external_location_message.text.clone(),
|
||||
// )
|
||||
// .contained()
|
||||
// .with_style(theme.workspace.external_location_message.container)
|
||||
// .aligned()
|
||||
// .bottom()
|
||||
// .right()
|
||||
// .into_any(),
|
||||
// ),
|
||||
// };
|
||||
// }
|
||||
|
||||
// Stack::new()
|
||||
// .with_child(pane_element.contained().with_border(leader_border))
|
||||
// .with_children(leader_status_box)
|
||||
// .into_any()
|
||||
// }
|
||||
// Member::Axis(axis) => axis.render(
|
||||
// project,
|
||||
// basis + 1,
|
||||
// theme,
|
||||
// follower_states,
|
||||
// active_call,
|
||||
// active_pane,
|
||||
// zoomed,
|
||||
// app_state,
|
||||
// cx,
|
||||
// ),
|
||||
// }
|
||||
}
|
||||
|
||||
fn collect_panes<'a>(&'a self, panes: &mut Vec<&'a View<Pane>>) {
|
||||
match self {
|
||||
Member::Axis(axis) => {
|
||||
for member in &axis.members {
|
||||
member.collect_panes(panes);
|
||||
}
|
||||
}
|
||||
Member::Pane(pane) => panes.push(pane),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub(crate) struct PaneAxis {
|
||||
pub axis: Axis,
|
||||
pub members: Vec<Member>,
|
||||
pub flexes: Rc<RefCell<Vec<f32>>>,
|
||||
pub bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
|
||||
}
|
||||
|
||||
impl PaneAxis {
|
||||
pub fn new(axis: Axis, members: Vec<Member>) -> Self {
|
||||
let flexes = Rc::new(RefCell::new(vec![1.; members.len()]));
|
||||
let bounding_boxes = Rc::new(RefCell::new(vec![None; members.len()]));
|
||||
Self {
|
||||
axis,
|
||||
members,
|
||||
flexes,
|
||||
bounding_boxes,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn load(axis: Axis, members: Vec<Member>, flexes: Option<Vec<f32>>) -> Self {
|
||||
let flexes = flexes.unwrap_or_else(|| vec![1.; members.len()]);
|
||||
debug_assert!(members.len() == flexes.len());
|
||||
|
||||
let flexes = Rc::new(RefCell::new(flexes));
|
||||
let bounding_boxes = Rc::new(RefCell::new(vec![None; members.len()]));
|
||||
Self {
|
||||
axis,
|
||||
members,
|
||||
flexes,
|
||||
bounding_boxes,
|
||||
}
|
||||
}
|
||||
|
||||
fn split(
|
||||
&mut self,
|
||||
old_pane: &View<Pane>,
|
||||
new_pane: &View<Pane>,
|
||||
direction: SplitDirection,
|
||||
) -> Result<()> {
|
||||
for (mut idx, member) in self.members.iter_mut().enumerate() {
|
||||
match member {
|
||||
Member::Axis(axis) => {
|
||||
if axis.split(old_pane, new_pane, direction).is_ok() {
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
Member::Pane(pane) => {
|
||||
if pane == old_pane {
|
||||
if direction.axis() == self.axis {
|
||||
if direction.increasing() {
|
||||
idx += 1;
|
||||
}
|
||||
|
||||
self.members.insert(idx, Member::Pane(new_pane.clone()));
|
||||
*self.flexes.borrow_mut() = vec![1.; self.members.len()];
|
||||
} else {
|
||||
*member =
|
||||
Member::new_axis(old_pane.clone(), new_pane.clone(), direction);
|
||||
}
|
||||
return Ok(());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Err(anyhow!("Pane not found"))
|
||||
}
|
||||
|
||||
fn remove(&mut self, pane_to_remove: &View<Pane>) -> Result<Option<Member>> {
|
||||
let mut found_pane = false;
|
||||
let mut remove_member = None;
|
||||
for (idx, member) in self.members.iter_mut().enumerate() {
|
||||
match member {
|
||||
Member::Axis(axis) => {
|
||||
if let Ok(last_pane) = axis.remove(pane_to_remove) {
|
||||
if let Some(last_pane) = last_pane {
|
||||
*member = last_pane;
|
||||
}
|
||||
found_pane = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
Member::Pane(pane) => {
|
||||
if pane == pane_to_remove {
|
||||
found_pane = true;
|
||||
remove_member = Some(idx);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if found_pane {
|
||||
if let Some(idx) = remove_member {
|
||||
self.members.remove(idx);
|
||||
*self.flexes.borrow_mut() = vec![1.; self.members.len()];
|
||||
}
|
||||
|
||||
if self.members.len() == 1 {
|
||||
let result = self.members.pop();
|
||||
*self.flexes.borrow_mut() = vec![1.; self.members.len()];
|
||||
Ok(result)
|
||||
} else {
|
||||
Ok(None)
|
||||
}
|
||||
} else {
|
||||
Err(anyhow!("Pane not found"))
|
||||
}
|
||||
}
|
||||
|
||||
fn swap(&mut self, from: &View<Pane>, to: &View<Pane>) {
|
||||
for member in self.members.iter_mut() {
|
||||
match member {
|
||||
Member::Axis(axis) => axis.swap(from, to),
|
||||
Member::Pane(pane) => {
|
||||
if pane == from {
|
||||
*member = Member::Pane(to.clone());
|
||||
} else if pane == to {
|
||||
*member = Member::Pane(from.clone())
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn bounding_box_for_pane(&self, pane: &View<Pane>) -> Option<Bounds<Pixels>> {
|
||||
debug_assert!(self.members.len() == self.bounding_boxes.borrow().len());
|
||||
|
||||
for (idx, member) in self.members.iter().enumerate() {
|
||||
match member {
|
||||
Member::Pane(found) => {
|
||||
if pane == found {
|
||||
return self.bounding_boxes.borrow()[idx];
|
||||
}
|
||||
}
|
||||
Member::Axis(axis) => {
|
||||
if let Some(rect) = axis.bounding_box_for_pane(pane) {
|
||||
return Some(rect);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn pane_at_pixel_position(&self, coordinate: Point<Pixels>) -> Option<&View<Pane>> {
|
||||
debug_assert!(self.members.len() == self.bounding_boxes.borrow().len());
|
||||
|
||||
let bounding_boxes = self.bounding_boxes.borrow();
|
||||
|
||||
for (idx, member) in self.members.iter().enumerate() {
|
||||
if let Some(coordinates) = bounding_boxes[idx] {
|
||||
if coordinates.contains_point(&coordinate) {
|
||||
return match member {
|
||||
Member::Pane(found) => Some(found),
|
||||
Member::Axis(axis) => axis.pane_at_pixel_position(coordinate),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
fn render(
|
||||
&self,
|
||||
project: &Handle<Project>,
|
||||
basis: usize,
|
||||
theme: &Theme,
|
||||
follower_states: &HashMap<View<Pane>, FollowerState>,
|
||||
active_call: Option<&Handle<ActiveCall>>,
|
||||
active_pane: &View<Pane>,
|
||||
zoomed: Option<&AnyView>,
|
||||
app_state: &Arc<AppState>,
|
||||
cx: &mut ViewContext<Workspace>,
|
||||
) -> AnyElement<Workspace> {
|
||||
debug_assert!(self.members.len() == self.flexes.borrow().len());
|
||||
|
||||
todo!()
|
||||
// let mut pane_axis = PaneAxisElement::new(
|
||||
// self.axis,
|
||||
// basis,
|
||||
// self.flexes.clone(),
|
||||
// self.bounding_boxes.clone(),
|
||||
// );
|
||||
// let mut active_pane_ix = None;
|
||||
|
||||
// let mut members = self.members.iter().enumerate().peekable();
|
||||
// while let Some((ix, member)) = members.next() {
|
||||
// let last = members.peek().is_none();
|
||||
|
||||
// if member.contains(active_pane) {
|
||||
// active_pane_ix = Some(ix);
|
||||
// }
|
||||
|
||||
// let mut member = member.render(
|
||||
// project,
|
||||
// (basis + ix) * 10,
|
||||
// theme,
|
||||
// follower_states,
|
||||
// active_call,
|
||||
// active_pane,
|
||||
// zoomed,
|
||||
// app_state,
|
||||
// cx,
|
||||
// );
|
||||
|
||||
// if !last {
|
||||
// let mut border = theme.workspace.pane_divider;
|
||||
// border.left = false;
|
||||
// border.right = false;
|
||||
// border.top = false;
|
||||
// border.bottom = false;
|
||||
|
||||
// match self.axis {
|
||||
// Axis::Vertical => border.bottom = true,
|
||||
// Axis::Horizontal => border.right = true,
|
||||
// }
|
||||
|
||||
// member = member.contained().with_border(border).into_any();
|
||||
// }
|
||||
|
||||
// pane_axis = pane_axis.with_child(member.into_any());
|
||||
// }
|
||||
// pane_axis.set_active_pane(active_pane_ix);
|
||||
// pane_axis.into_any()
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy, Debug, Deserialize, PartialEq)]
|
||||
pub enum SplitDirection {
|
||||
Up,
|
||||
Down,
|
||||
Left,
|
||||
Right,
|
||||
}
|
||||
|
||||
impl SplitDirection {
|
||||
pub fn all() -> [Self; 4] {
|
||||
[Self::Up, Self::Down, Self::Left, Self::Right]
|
||||
}
|
||||
|
||||
pub fn edge(&self, rect: Bounds<Pixels>) -> f32 {
|
||||
match self {
|
||||
Self::Up => rect.min_y(),
|
||||
Self::Down => rect.max_y(),
|
||||
Self::Left => rect.min_x(),
|
||||
Self::Right => rect.max_x(),
|
||||
}
|
||||
}
|
||||
|
||||
pub fn along_edge(&self, bounds: Bounds<Pixels>, length: Pixels) -> Bounds<Pixels> {
|
||||
match self {
|
||||
Self::Up => Bounds {
|
||||
origin: bounds.origin(),
|
||||
size: size(bounds.width(), length),
|
||||
},
|
||||
Self::Down => Bounds {
|
||||
origin: size(bounds.min_x(), bounds.max_y() - length),
|
||||
size: size(bounds.width(), length),
|
||||
},
|
||||
Self::Left => Bounds {
|
||||
origin: bounds.origin(),
|
||||
size: size(length, bounds.height()),
|
||||
},
|
||||
Self::Right => Bounds {
|
||||
origin: size(bounds.max_x() - length, bounds.min_y()),
|
||||
size: size(length, bounds.height()),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
pub fn axis(&self) -> Axis {
|
||||
match self {
|
||||
Self::Up | Self::Down => Axis::Vertical,
|
||||
Self::Left | Self::Right => Axis::Horizontal,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn increasing(&self) -> bool {
|
||||
match self {
|
||||
Self::Left | Self::Up => false,
|
||||
Self::Down | Self::Right => true,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// mod element {
|
||||
// // use std::{cell::RefCell, iter::from_fn, ops::Range, rc::Rc};
|
||||
|
||||
// // use gpui::{
|
||||
// // geometry::{
|
||||
// // rect::Bounds<Pixels>,
|
||||
// // vector::{vec2f, Vector2F},
|
||||
// // },
|
||||
// // json::{self, ToJson},
|
||||
// // platform::{CursorStyle, MouseButton},
|
||||
// // scene::MouseDrag,
|
||||
// // AnyElement, Axis, CursorRegion, Element, EventContext, MouseRegion, Bounds<Pixels>Ext,
|
||||
// // SizeConstraint, Vector2FExt, ViewContext,
|
||||
// // };
|
||||
|
||||
// use crate::{
|
||||
// pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE},
|
||||
// Workspace, WorkspaceSettings,
|
||||
// };
|
||||
|
||||
// pub struct PaneAxisElement {
|
||||
// axis: Axis,
|
||||
// basis: usize,
|
||||
// active_pane_ix: Option<usize>,
|
||||
// flexes: Rc<RefCell<Vec<f32>>>,
|
||||
// children: Vec<AnyElement<Workspace>>,
|
||||
// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
|
||||
// }
|
||||
|
||||
// impl PaneAxisElement {
|
||||
// pub fn new(
|
||||
// axis: Axis,
|
||||
// basis: usize,
|
||||
// flexes: Rc<RefCell<Vec<f32>>>,
|
||||
// bounding_boxes: Rc<RefCell<Vec<Option<Bounds<Pixels>>>>>,
|
||||
// ) -> Self {
|
||||
// Self {
|
||||
// axis,
|
||||
// basis,
|
||||
// flexes,
|
||||
// bounding_boxes,
|
||||
// active_pane_ix: None,
|
||||
// children: Default::default(),
|
||||
// }
|
||||
// }
|
||||
|
||||
// pub fn set_active_pane(&mut self, active_pane_ix: Option<usize>) {
|
||||
// self.active_pane_ix = active_pane_ix;
|
||||
// }
|
||||
|
||||
// fn layout_children(
|
||||
// &mut self,
|
||||
// active_pane_magnification: f32,
|
||||
// constraint: SizeConstraint,
|
||||
// remaining_space: &mut f32,
|
||||
// remaining_flex: &mut f32,
|
||||
// cross_axis_max: &mut f32,
|
||||
// view: &mut Workspace,
|
||||
// cx: &mut ViewContext<Workspace>,
|
||||
// ) {
|
||||
// let flexes = self.flexes.borrow();
|
||||
// let cross_axis = self.axis.invert();
|
||||
// for (ix, child) in self.children.iter_mut().enumerate() {
|
||||
// let flex = if active_pane_magnification != 1. {
|
||||
// if let Some(active_pane_ix) = self.active_pane_ix {
|
||||
// if ix == active_pane_ix {
|
||||
// active_pane_magnification
|
||||
// } else {
|
||||
// 1.
|
||||
// }
|
||||
// } else {
|
||||
// 1.
|
||||
// }
|
||||
// } else {
|
||||
// flexes[ix]
|
||||
// };
|
||||
|
||||
// let child_size = if *remaining_flex == 0.0 {
|
||||
// *remaining_space
|
||||
// } else {
|
||||
// let space_per_flex = *remaining_space / *remaining_flex;
|
||||
// space_per_flex * flex
|
||||
// };
|
||||
|
||||
// let child_constraint = match self.axis {
|
||||
// Axis::Horizontal => SizeConstraint::new(
|
||||
// vec2f(child_size, constraint.min.y()),
|
||||
// vec2f(child_size, constraint.max.y()),
|
||||
// ),
|
||||
// Axis::Vertical => SizeConstraint::new(
|
||||
// vec2f(constraint.min.x(), child_size),
|
||||
// vec2f(constraint.max.x(), child_size),
|
||||
// ),
|
||||
// };
|
||||
// let child_size = child.layout(child_constraint, view, cx);
|
||||
// *remaining_space -= child_size.along(self.axis);
|
||||
// *remaining_flex -= flex;
|
||||
// *cross_axis_max = cross_axis_max.max(child_size.along(cross_axis));
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn handle_resize(
|
||||
// flexes: Rc<RefCell<Vec<f32>>>,
|
||||
// axis: Axis,
|
||||
// preceding_ix: usize,
|
||||
// child_start: Vector2F,
|
||||
// drag_bounds: Bounds<Pixels>,
|
||||
// ) -> impl Fn(MouseDrag, &mut Workspace, &mut EventContext<Workspace>) {
|
||||
// let size = move |ix, flexes: &[f32]| {
|
||||
// drag_bounds.length_along(axis) * (flexes[ix] / flexes.len() as f32)
|
||||
// };
|
||||
|
||||
// move |drag, workspace: &mut Workspace, cx| {
|
||||
// if drag.end {
|
||||
// // TODO: Clear cascading resize state
|
||||
// return;
|
||||
// }
|
||||
// let min_size = match axis {
|
||||
// Axis::Horizontal => HORIZONTAL_MIN_SIZE,
|
||||
// Axis::Vertical => VERTICAL_MIN_SIZE,
|
||||
// };
|
||||
// let mut flexes = flexes.borrow_mut();
|
||||
|
||||
// // Don't allow resizing to less than the minimum size, if elements are already too small
|
||||
// if min_size - 1. > size(preceding_ix, flexes.as_slice()) {
|
||||
// return;
|
||||
// }
|
||||
|
||||
// let mut proposed_current_pixel_change = (drag.position - child_start).along(axis)
|
||||
// - size(preceding_ix, flexes.as_slice());
|
||||
|
||||
// let flex_changes = |pixel_dx, target_ix, next: isize, flexes: &[f32]| {
|
||||
// let flex_change = pixel_dx / drag_bounds.length_along(axis);
|
||||
// let current_target_flex = flexes[target_ix] + flex_change;
|
||||
// let next_target_flex =
|
||||
// flexes[(target_ix as isize + next) as usize] - flex_change;
|
||||
// (current_target_flex, next_target_flex)
|
||||
// };
|
||||
|
||||
// let mut successors = from_fn({
|
||||
// let forward = proposed_current_pixel_change > 0.;
|
||||
// let mut ix_offset = 0;
|
||||
// let len = flexes.len();
|
||||
// move || {
|
||||
// let result = if forward {
|
||||
// (preceding_ix + 1 + ix_offset < len).then(|| preceding_ix + ix_offset)
|
||||
// } else {
|
||||
// (preceding_ix as isize - ix_offset as isize >= 0)
|
||||
// .then(|| preceding_ix - ix_offset)
|
||||
// };
|
||||
|
||||
// ix_offset += 1;
|
||||
|
||||
// result
|
||||
// }
|
||||
// });
|
||||
|
||||
// while proposed_current_pixel_change.abs() > 0. {
|
||||
// let Some(current_ix) = successors.next() else {
|
||||
// break;
|
||||
// };
|
||||
|
||||
// let next_target_size = f32::max(
|
||||
// size(current_ix + 1, flexes.as_slice()) - proposed_current_pixel_change,
|
||||
// min_size,
|
||||
// );
|
||||
|
||||
// let current_target_size = f32::max(
|
||||
// size(current_ix, flexes.as_slice())
|
||||
// + size(current_ix + 1, flexes.as_slice())
|
||||
// - next_target_size,
|
||||
// min_size,
|
||||
// );
|
||||
|
||||
// let current_pixel_change =
|
||||
// current_target_size - size(current_ix, flexes.as_slice());
|
||||
|
||||
// let (current_target_flex, next_target_flex) =
|
||||
// flex_changes(current_pixel_change, current_ix, 1, flexes.as_slice());
|
||||
|
||||
// flexes[current_ix] = current_target_flex;
|
||||
// flexes[current_ix + 1] = next_target_flex;
|
||||
|
||||
// proposed_current_pixel_change -= current_pixel_change;
|
||||
// }
|
||||
|
||||
// workspace.schedule_serialize(cx);
|
||||
// cx.notify();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Extend<AnyElement<Workspace>> for PaneAxisElement {
|
||||
// fn extend<T: IntoIterator<Item = AnyElement<Workspace>>>(&mut self, children: T) {
|
||||
// self.children.extend(children);
|
||||
// }
|
||||
// }
|
||||
|
||||
// impl Element<Workspace> for PaneAxisElement {
|
||||
// type LayoutState = f32;
|
||||
// type PaintState = ();
|
||||
|
||||
// fn layout(
|
||||
// &mut self,
|
||||
// constraint: SizeConstraint,
|
||||
// view: &mut Workspace,
|
||||
// cx: &mut ViewContext<Workspace>,
|
||||
// ) -> (Vector2F, Self::LayoutState) {
|
||||
// debug_assert!(self.children.len() == self.flexes.borrow().len());
|
||||
|
||||
// let active_pane_magnification =
|
||||
// settings::get::<WorkspaceSettings>(cx).active_pane_magnification;
|
||||
|
||||
// let mut remaining_flex = 0.;
|
||||
|
||||
// if active_pane_magnification != 1. {
|
||||
// let active_pane_flex = self
|
||||
// .active_pane_ix
|
||||
// .map(|_| active_pane_magnification)
|
||||
// .unwrap_or(1.);
|
||||
// remaining_flex += self.children.len() as f32 - 1. + active_pane_flex;
|
||||
// } else {
|
||||
// for flex in self.flexes.borrow().iter() {
|
||||
// remaining_flex += flex;
|
||||
// }
|
||||
// }
|
||||
|
||||
// let mut cross_axis_max: f32 = 0.0;
|
||||
// let mut remaining_space = constraint.max_along(self.axis);
|
||||
|
||||
// if remaining_space.is_infinite() {
|
||||
// panic!("flex contains flexible children but has an infinite constraint along the flex axis");
|
||||
// }
|
||||
|
||||
// self.layout_children(
|
||||
// active_pane_magnification,
|
||||
// constraint,
|
||||
// &mut remaining_space,
|
||||
// &mut remaining_flex,
|
||||
// &mut cross_axis_max,
|
||||
// view,
|
||||
// cx,
|
||||
// );
|
||||
|
||||
// let mut size = match self.axis {
|
||||
// Axis::Horizontal => vec2f(constraint.max.x() - remaining_space, cross_axis_max),
|
||||
// Axis::Vertical => vec2f(cross_axis_max, constraint.max.y() - remaining_space),
|
||||
// };
|
||||
|
||||
// if constraint.min.x().is_finite() {
|
||||
// size.set_x(size.x().max(constraint.min.x()));
|
||||
// }
|
||||
// if constraint.min.y().is_finite() {
|
||||
// size.set_y(size.y().max(constraint.min.y()));
|
||||
// }
|
||||
|
||||
// if size.x() > constraint.max.x() {
|
||||
// size.set_x(constraint.max.x());
|
||||
// }
|
||||
// if size.y() > constraint.max.y() {
|
||||
// size.set_y(constraint.max.y());
|
||||
// }
|
||||
|
||||
// (size, remaining_space)
|
||||
// }
|
||||
|
||||
// fn paint(
|
||||
// &mut self,
|
||||
// bounds: Bounds<Pixels>,
|
||||
// visible_bounds: Bounds<Pixels>,
|
||||
// remaining_space: &mut Self::LayoutState,
|
||||
// view: &mut Workspace,
|
||||
// cx: &mut ViewContext<Workspace>,
|
||||
// ) -> Self::PaintState {
|
||||
// let can_resize = settings::get::<WorkspaceSettings>(cx).active_pane_magnification == 1.;
|
||||
// let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
|
||||
|
||||
// let overflowing = *remaining_space < 0.;
|
||||
// if overflowing {
|
||||
// cx.scene().push_layer(Some(visible_bounds));
|
||||
// }
|
||||
|
||||
// let mut child_origin = bounds.origin();
|
||||
|
||||
// let mut bounding_boxes = self.bounding_boxes.borrow_mut();
|
||||
// bounding_boxes.clear();
|
||||
|
||||
// let mut children_iter = self.children.iter_mut().enumerate().peekable();
|
||||
// while let Some((ix, child)) = children_iter.next() {
|
||||
// let child_start = child_origin.clone();
|
||||
// child.paint(child_origin, visible_bounds, view, cx);
|
||||
|
||||
// bounding_boxes.push(Some(Bounds<Pixels>::new(child_origin, child.size())));
|
||||
|
||||
// match self.axis {
|
||||
// Axis::Horizontal => child_origin += vec2f(child.size().x(), 0.0),
|
||||
// Axis::Vertical => child_origin += vec2f(0.0, child.size().y()),
|
||||
// }
|
||||
|
||||
// if can_resize && children_iter.peek().is_some() {
|
||||
// cx.scene().push_stacking_context(None, None);
|
||||
|
||||
// let handle_origin = match self.axis {
|
||||
// Axis::Horizontal => child_origin - vec2f(HANDLE_HITBOX_SIZE / 2., 0.0),
|
||||
// Axis::Vertical => child_origin - vec2f(0.0, HANDLE_HITBOX_SIZE / 2.),
|
||||
// };
|
||||
|
||||
// let handle_bounds = match self.axis {
|
||||
// Axis::Horizontal => Bounds<Pixels>::new(
|
||||
// handle_origin,
|
||||
// vec2f(HANDLE_HITBOX_SIZE, visible_bounds.height()),
|
||||
// ),
|
||||
// Axis::Vertical => Bounds<Pixels>::new(
|
||||
// handle_origin,
|
||||
// vec2f(visible_bounds.width(), HANDLE_HITBOX_SIZE),
|
||||
// ),
|
||||
// };
|
||||
|
||||
// let style = match self.axis {
|
||||
// Axis::Horizontal => CursorStyle::ResizeLeftRight,
|
||||
// Axis::Vertical => CursorStyle::ResizeUpDown,
|
||||
// };
|
||||
|
||||
// cx.scene().push_cursor_region(CursorRegion {
|
||||
// bounds: handle_bounds,
|
||||
// style,
|
||||
// });
|
||||
|
||||
// enum ResizeHandle {}
|
||||
// let mut mouse_region = MouseRegion::new::<ResizeHandle>(
|
||||
// cx.view_id(),
|
||||
// self.basis + ix,
|
||||
// handle_bounds,
|
||||
// );
|
||||
// mouse_region = mouse_region
|
||||
// .on_drag(
|
||||
// MouseButton::Left,
|
||||
// Self::handle_resize(
|
||||
// self.flexes.clone(),
|
||||
// self.axis,
|
||||
// ix,
|
||||
// child_start,
|
||||
// visible_bounds.clone(),
|
||||
// ),
|
||||
// )
|
||||
// .on_click(MouseButton::Left, {
|
||||
// let flexes = self.flexes.clone();
|
||||
// move |e, v: &mut Workspace, cx| {
|
||||
// if e.click_count >= 2 {
|
||||
// let mut borrow = flexes.borrow_mut();
|
||||
// *borrow = vec![1.; borrow.len()];
|
||||
// v.schedule_serialize(cx);
|
||||
// cx.notify();
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
// cx.scene().push_mouse_region(mouse_region);
|
||||
|
||||
// cx.scene().pop_stacking_context();
|
||||
// }
|
||||
// }
|
||||
|
||||
// if overflowing {
|
||||
// cx.scene().pop_layer();
|
||||
// }
|
||||
// }
|
||||
|
||||
// fn rect_for_text_range(
|
||||
// &self,
|
||||
// range_utf16: Range<usize>,
|
||||
// _: Bounds<Pixels>,
|
||||
// _: Bounds<Pixels>,
|
||||
// _: &Self::LayoutState,
|
||||
// _: &Self::PaintState,
|
||||
// view: &Workspace,
|
||||
// cx: &ViewContext<Workspace>,
|
||||
// ) -> Option<Bounds<Pixels>> {
|
||||
// self.children
|
||||
// .iter()
|
||||
// .find_map(|child| child.rect_for_text_range(range_utf16.clone(), view, cx))
|
||||
// }
|
||||
|
||||
// fn debug(
|
||||
// &self,
|
||||
// bounds: Bounds<Pixels>,
|
||||
// _: &Self::LayoutState,
|
||||
// _: &Self::PaintState,
|
||||
// view: &Workspace,
|
||||
// cx: &ViewContext<Workspace>,
|
||||
// ) -> json::Value {
|
||||
// serde_json::json!({
|
||||
// "type": "PaneAxis",
|
||||
// "bounds": bounds.to_json(),
|
||||
// "axis": self.axis.to_json(),
|
||||
// "flexes": *self.flexes.borrow(),
|
||||
// "children": self.children.iter().map(|child| child.debug(view, cx)).collect::<Vec<json::Value>>()
|
||||
// })
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
@@ -0,0 +1,340 @@
|
||||
use crate::{
|
||||
item::ItemHandle, Axis, ItemDeserializers, Member, Pane, PaneAxis, Workspace, WorkspaceId,
|
||||
};
|
||||
use anyhow::{Context, Result};
|
||||
use async_recursion::async_recursion;
|
||||
use db2::sqlez::{
|
||||
bindable::{Bind, Column, StaticColumnCount},
|
||||
statement::Statement,
|
||||
};
|
||||
use gpui2::{AsyncAppContext, Handle, Task, View, WeakView, WindowBounds};
|
||||
use project2::Project;
|
||||
use std::{
|
||||
path::{Path, PathBuf},
|
||||
sync::Arc,
|
||||
};
|
||||
use util::ResultExt;
|
||||
use uuid::Uuid;
|
||||
|
||||
#[derive(Debug, Clone, PartialEq, Eq)]
|
||||
pub struct WorkspaceLocation(Arc<Vec<PathBuf>>);
|
||||
|
||||
impl WorkspaceLocation {
|
||||
pub fn paths(&self) -> Arc<Vec<PathBuf>> {
|
||||
self.0.clone()
|
||||
}
|
||||
}
|
||||
|
||||
impl<P: AsRef<Path>, T: IntoIterator<Item = P>> From<T> for WorkspaceLocation {
|
||||
fn from(iterator: T) -> Self {
|
||||
let mut roots = iterator
|
||||
.into_iter()
|
||||
.map(|p| p.as_ref().to_path_buf())
|
||||
.collect::<Vec<_>>();
|
||||
roots.sort();
|
||||
Self(Arc::new(roots))
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticColumnCount for WorkspaceLocation {}
|
||||
impl Bind for &WorkspaceLocation {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
bincode::serialize(&self.0)
|
||||
.expect("Bincode serialization of paths should not fail")
|
||||
.bind(statement, start_index)
|
||||
}
|
||||
}
|
||||
|
||||
impl Column for WorkspaceLocation {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let blob = statement.column_blob(start_index)?;
|
||||
Ok((
|
||||
WorkspaceLocation(bincode::deserialize(blob).context("Bincode failed")?),
|
||||
start_index + 1,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub struct SerializedWorkspace {
|
||||
pub id: WorkspaceId,
|
||||
pub location: WorkspaceLocation,
|
||||
pub center_group: SerializedPaneGroup,
|
||||
pub bounds: Option<WindowBounds>,
|
||||
pub display: Option<Uuid>,
|
||||
pub docks: DockStructure,
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub struct DockStructure {
|
||||
pub(crate) left: DockData,
|
||||
pub(crate) right: DockData,
|
||||
pub(crate) bottom: DockData,
|
||||
}
|
||||
|
||||
impl Column for DockStructure {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let (left, next_index) = DockData::column(statement, start_index)?;
|
||||
let (right, next_index) = DockData::column(statement, next_index)?;
|
||||
let (bottom, next_index) = DockData::column(statement, next_index)?;
|
||||
Ok((
|
||||
DockStructure {
|
||||
left,
|
||||
right,
|
||||
bottom,
|
||||
},
|
||||
next_index,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind for DockStructure {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
let next_index = statement.bind(&self.left, start_index)?;
|
||||
let next_index = statement.bind(&self.right, next_index)?;
|
||||
statement.bind(&self.bottom, next_index)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone, Default)]
|
||||
pub struct DockData {
|
||||
pub(crate) visible: bool,
|
||||
pub(crate) active_panel: Option<String>,
|
||||
pub(crate) zoom: bool,
|
||||
}
|
||||
|
||||
impl Column for DockData {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let (visible, next_index) = Option::<bool>::column(statement, start_index)?;
|
||||
let (active_panel, next_index) = Option::<String>::column(statement, next_index)?;
|
||||
let (zoom, next_index) = Option::<bool>::column(statement, next_index)?;
|
||||
Ok((
|
||||
DockData {
|
||||
visible: visible.unwrap_or(false),
|
||||
active_panel,
|
||||
zoom: zoom.unwrap_or(false),
|
||||
},
|
||||
next_index,
|
||||
))
|
||||
}
|
||||
}
|
||||
|
||||
impl Bind for DockData {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
let next_index = statement.bind(&self.visible, start_index)?;
|
||||
let next_index = statement.bind(&self.active_panel, next_index)?;
|
||||
statement.bind(&self.zoom, next_index)
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Clone)]
|
||||
pub enum SerializedPaneGroup {
|
||||
Group {
|
||||
axis: Axis,
|
||||
flexes: Option<Vec<f32>>,
|
||||
children: Vec<SerializedPaneGroup>,
|
||||
},
|
||||
Pane(SerializedPane),
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for SerializedPaneGroup {
|
||||
fn default() -> Self {
|
||||
Self::Pane(SerializedPane {
|
||||
children: vec![SerializedItem::default()],
|
||||
active: false,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl SerializedPaneGroup {
|
||||
#[async_recursion(?Send)]
|
||||
pub(crate) async fn deserialize(
|
||||
self,
|
||||
project: &Handle<Project>,
|
||||
workspace_id: WorkspaceId,
|
||||
workspace: &WeakView<Workspace>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Option<(Member, Option<View<Pane>>, Vec<Option<Box<dyn ItemHandle>>>)> {
|
||||
match self {
|
||||
SerializedPaneGroup::Group {
|
||||
axis,
|
||||
children,
|
||||
flexes,
|
||||
} => {
|
||||
let mut current_active_pane = None;
|
||||
let mut members = Vec::new();
|
||||
let mut items = Vec::new();
|
||||
for child in children {
|
||||
if let Some((new_member, active_pane, new_items)) = child
|
||||
.deserialize(project, workspace_id, workspace, cx)
|
||||
.await
|
||||
{
|
||||
members.push(new_member);
|
||||
items.extend(new_items);
|
||||
current_active_pane = current_active_pane.or(active_pane);
|
||||
}
|
||||
}
|
||||
|
||||
if members.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
if members.len() == 1 {
|
||||
return Some((members.remove(0), current_active_pane, items));
|
||||
}
|
||||
|
||||
Some((
|
||||
Member::Axis(PaneAxis::load(axis, members, flexes)),
|
||||
current_active_pane,
|
||||
items,
|
||||
))
|
||||
}
|
||||
SerializedPaneGroup::Pane(serialized_pane) => {
|
||||
let pane = workspace
|
||||
.update(cx, |workspace, cx| workspace.add_pane(cx).downgrade())
|
||||
.log_err()?;
|
||||
let active = serialized_pane.active;
|
||||
let new_items = serialized_pane
|
||||
.deserialize_to(project, &pane, workspace_id, workspace, cx)
|
||||
.await
|
||||
.log_err()?;
|
||||
|
||||
if pane
|
||||
.read_with(cx, |pane, _| pane.items_len() != 0)
|
||||
.log_err()?
|
||||
{
|
||||
let pane = pane.upgrade()?;
|
||||
Some((Member::Pane(pane.clone()), active.then(|| pane), new_items))
|
||||
} else {
|
||||
let pane = pane.upgrade()?;
|
||||
workspace
|
||||
.update(cx, |workspace, cx| workspace.force_remove_pane(&pane, cx))
|
||||
.log_err()?;
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Default, Clone)]
|
||||
pub struct SerializedPane {
|
||||
pub(crate) active: bool,
|
||||
pub(crate) children: Vec<SerializedItem>,
|
||||
}
|
||||
|
||||
impl SerializedPane {
|
||||
pub fn new(children: Vec<SerializedItem>, active: bool) -> Self {
|
||||
SerializedPane { children, active }
|
||||
}
|
||||
|
||||
pub async fn deserialize_to(
|
||||
&self,
|
||||
project: &Handle<Project>,
|
||||
pane: &WeakView<Pane>,
|
||||
workspace_id: WorkspaceId,
|
||||
workspace: &WeakView<Workspace>,
|
||||
cx: &mut AsyncAppContext,
|
||||
) -> Result<Vec<Option<Box<dyn ItemHandle>>>> {
|
||||
let mut items = Vec::new();
|
||||
let mut active_item_index = None;
|
||||
for (index, item) in self.children.iter().enumerate() {
|
||||
let project = project.clone();
|
||||
let item_handle = pane
|
||||
.update(cx, |_, cx| {
|
||||
if let Some(deserializer) = cx.global::<ItemDeserializers>().get(&item.kind) {
|
||||
deserializer(project, workspace.clone(), workspace_id, item.item_id, cx)
|
||||
} else {
|
||||
Task::ready(Err(anyhow::anyhow!(
|
||||
"Deserializer does not exist for item kind: {}",
|
||||
item.kind
|
||||
)))
|
||||
}
|
||||
})?
|
||||
.await
|
||||
.log_err();
|
||||
|
||||
items.push(item_handle.clone());
|
||||
|
||||
if let Some(item_handle) = item_handle {
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.add_item(item_handle.clone(), true, true, None, cx);
|
||||
})?;
|
||||
}
|
||||
|
||||
if item.active {
|
||||
active_item_index = Some(index);
|
||||
}
|
||||
}
|
||||
|
||||
if let Some(active_item_index) = active_item_index {
|
||||
pane.update(cx, |pane, cx| {
|
||||
pane.activate_item(active_item_index, false, false, cx);
|
||||
})?;
|
||||
}
|
||||
|
||||
anyhow::Ok(items)
|
||||
}
|
||||
}
|
||||
|
||||
pub type GroupId = i64;
|
||||
pub type PaneId = i64;
|
||||
pub type ItemId = usize;
|
||||
|
||||
#[derive(Debug, PartialEq, Eq, Clone)]
|
||||
pub struct SerializedItem {
|
||||
pub kind: Arc<str>,
|
||||
pub item_id: ItemId,
|
||||
pub active: bool,
|
||||
}
|
||||
|
||||
impl SerializedItem {
|
||||
pub fn new(kind: impl AsRef<str>, item_id: ItemId, active: bool) -> Self {
|
||||
Self {
|
||||
kind: Arc::from(kind.as_ref()),
|
||||
item_id,
|
||||
active,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
impl Default for SerializedItem {
|
||||
fn default() -> Self {
|
||||
SerializedItem {
|
||||
kind: Arc::from("Terminal"),
|
||||
item_id: 100000,
|
||||
active: false,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl StaticColumnCount for SerializedItem {
|
||||
fn column_count() -> usize {
|
||||
3
|
||||
}
|
||||
}
|
||||
impl Bind for &SerializedItem {
|
||||
fn bind(&self, statement: &Statement, start_index: i32) -> Result<i32> {
|
||||
let next_index = statement.bind(&self.kind, start_index)?;
|
||||
let next_index = statement.bind(&self.item_id, next_index)?;
|
||||
statement.bind(&self.active, next_index)
|
||||
}
|
||||
}
|
||||
|
||||
impl Column for SerializedItem {
|
||||
fn column(statement: &mut Statement, start_index: i32) -> Result<(Self, i32)> {
|
||||
let (kind, next_index) = Arc::<str>::column(statement, start_index)?;
|
||||
let (item_id, next_index) = ItemId::column(statement, next_index)?;
|
||||
let (active, next_index) = bool::column(statement, next_index)?;
|
||||
Ok((
|
||||
SerializedItem {
|
||||
kind,
|
||||
item_id,
|
||||
active,
|
||||
},
|
||||
next_index,
|
||||
))
|
||||
}
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user