Add resising serialization

This commit is contained in:
Mikayla Maki 2023-07-13 14:21:14 -07:00
parent 00b04f1c85
commit 5797282b98
No known key found for this signature in database
4 changed files with 159 additions and 85 deletions

View file

@ -308,7 +308,7 @@ impl Member {
pub(crate) struct PaneAxis {
pub axis: Axis,
pub members: Vec<Member>,
flexes: Rc<RefCell<Vec<f32>>>,
pub flexes: Rc<RefCell<Vec<f32>>>,
}
impl PaneAxis {
@ -321,6 +321,18 @@ impl PaneAxis {
}
}
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));
Self {
axis,
members,
flexes,
}
}
fn split(
&mut self,
old_pane: &ViewHandle<Pane>,
@ -519,23 +531,23 @@ mod element {
json::{self, ToJson},
platform::{CursorStyle, MouseButton},
AnyElement, Axis, CursorRegion, Element, LayoutContext, MouseRegion, RectFExt,
SceneBuilder, SizeConstraint, Vector2FExt, View, ViewContext,
SceneBuilder, SizeConstraint, Vector2FExt, ViewContext,
};
use crate::{
pane_group::{HANDLE_HITBOX_SIZE, HORIZONTAL_MIN_SIZE, VERTICAL_MIN_SIZE},
WorkspaceSettings,
WorkspaceSettings, Workspace,
};
pub struct PaneAxisElement<V: View> {
pub struct PaneAxisElement {
axis: Axis,
basis: usize,
active_pane_ix: Option<usize>,
flexes: Rc<RefCell<Vec<f32>>>,
children: Vec<AnyElement<V>>,
children: Vec<AnyElement<Workspace>>,
}
impl<V: View> PaneAxisElement<V> {
impl PaneAxisElement {
pub fn new(axis: Axis, basis: usize, flexes: Rc<RefCell<Vec<f32>>>) -> Self {
Self {
axis,
@ -557,8 +569,8 @@ mod element {
remaining_space: &mut f32,
remaining_flex: &mut f32,
cross_axis_max: &mut f32,
view: &mut V,
cx: &mut LayoutContext<V>,
view: &mut Workspace,
cx: &mut LayoutContext<Workspace>,
) {
let flexes = self.flexes.borrow();
let cross_axis = self.axis.invert();
@ -602,21 +614,21 @@ mod element {
}
}
impl<V: View> Extend<AnyElement<V>> for PaneAxisElement<V> {
fn extend<T: IntoIterator<Item = AnyElement<V>>>(&mut self, children: T) {
impl Extend<AnyElement<Workspace>> for PaneAxisElement {
fn extend<T: IntoIterator<Item = AnyElement<Workspace>>>(&mut self, children: T) {
self.children.extend(children);
}
}
impl<V: View> Element<V> for PaneAxisElement<V> {
impl Element<Workspace> for PaneAxisElement {
type LayoutState = f32;
type PaintState = ();
fn layout(
&mut self,
constraint: SizeConstraint,
view: &mut V,
cx: &mut LayoutContext<V>,
view: &mut Workspace,
cx: &mut LayoutContext<Workspace>,
) -> (Vector2F, Self::LayoutState) {
debug_assert!(self.children.len() == self.flexes.borrow().len());
@ -682,8 +694,8 @@ mod element {
bounds: RectF,
visible_bounds: RectF,
remaining_space: &mut Self::LayoutState,
view: &mut V,
cx: &mut ViewContext<V>,
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();
@ -750,7 +762,7 @@ mod element {
handle_bounds,
);
mouse_region =
mouse_region.on_drag(MouseButton::Left, move |drag, _: &mut V, cx| {
mouse_region.on_drag(MouseButton::Left, move |drag, workspace: &mut Workspace, cx| {
let min_size = match axis {
Axis::Horizontal => HORIZONTAL_MIN_SIZE,
Axis::Vertical => VERTICAL_MIN_SIZE,
@ -768,13 +780,15 @@ mod element {
current_target_size - child_size.along(axis);
if proposed_current_pixel_change < 0. {
current_target_size = current_target_size.max(min_size);
current_target_size = f32::max(current_target_size, min_size);
} else if proposed_current_pixel_change > 0. {
// TODO: cascade this size change down, collect all changes into a vec
let next_target_size = (next_child_size.along(axis)
- proposed_current_pixel_change)
.max(min_size);
current_target_size = current_target_size.min(
// TODO: cascade this change to other children if current item is at min size
let next_target_size = f32::max(
next_child_size.along(axis) - proposed_current_pixel_change,
min_size,
);
current_target_size = f32::min(
current_target_size,
child_size.along(axis) + next_child_size.along(axis)
- next_target_size,
);
@ -789,6 +803,7 @@ mod element {
*borrow.get_mut(ix).unwrap() = current_target_flex;
*borrow.get_mut(next_ix).unwrap() = next_target_flex;
workspace.schedule_serialize(cx);
cx.notify();
});
scene.push_mouse_region(mouse_region);
@ -809,8 +824,8 @@ mod element {
_: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
view: &V,
cx: &ViewContext<V>,
view: &Workspace,
cx: &ViewContext<Workspace>,
) -> Option<RectF> {
self.children
.iter()
@ -822,8 +837,8 @@ mod element {
bounds: RectF,
_: &Self::LayoutState,
_: &Self::PaintState,
view: &V,
cx: &ViewContext<V>,
view: &Workspace,
cx: &ViewContext<Workspace>,
) -> json::Value {
serde_json::json!({
"type": "PaneAxis",

View file

@ -45,6 +45,7 @@ define_connection! {
// parent_group_id: Option<usize>, // None indicates that this is the root node
// position: Optiopn<usize>, // None indicates that this is the root node
// axis: Option<Axis>, // 'Vertical', 'Horizontal'
// flexes: Option<Vec<f32>>, // A JSON array of floats
// )
//
// panes(
@ -168,7 +169,12 @@ define_connection! {
ALTER TABLE workspaces ADD COLUMN left_dock_zoom INTEGER; //bool
ALTER TABLE workspaces ADD COLUMN right_dock_zoom INTEGER; //bool
ALTER TABLE workspaces ADD COLUMN bottom_dock_zoom INTEGER; //bool
)];
),
// Add pane group flex data
sql!(
ALTER TABLE pane_groups ADD COLUMN flexes TEXT;
)
];
}
impl WorkspaceDb {
@ -359,38 +365,51 @@ impl WorkspaceDb {
group_id: Option<GroupId>,
) -> Result<Vec<SerializedPaneGroup>> {
type GroupKey = (Option<GroupId>, WorkspaceId);
type GroupOrPane = (Option<GroupId>, Option<Axis>, Option<PaneId>, Option<bool>);
type GroupOrPane = (
Option<GroupId>,
Option<Axis>,
Option<PaneId>,
Option<bool>,
Option<String>,
);
self.select_bound::<GroupKey, GroupOrPane>(sql!(
SELECT group_id, axis, pane_id, active
SELECT group_id, axis, pane_id, active, flexes
FROM (SELECT
group_id,
axis,
NULL as pane_id,
NULL as active,
position,
parent_group_id,
workspace_id
FROM pane_groups
group_id,
axis,
NULL as pane_id,
NULL as active,
position,
parent_group_id,
workspace_id,
flexes
FROM pane_groups
UNION
SELECT
NULL,
NULL,
center_panes.pane_id,
panes.active as active,
position,
parent_group_id,
panes.workspace_id as workspace_id
FROM center_panes
JOIN panes ON center_panes.pane_id = panes.pane_id)
SELECT
NULL,
NULL,
center_panes.pane_id,
panes.active as active,
position,
parent_group_id,
panes.workspace_id as workspace_id,
NULL
FROM center_panes
JOIN panes ON center_panes.pane_id = panes.pane_id)
WHERE parent_group_id IS ? AND workspace_id = ?
ORDER BY position
))?((group_id, workspace_id))?
.into_iter()
.map(|(group_id, axis, pane_id, active)| {
.map(|(group_id, axis, pane_id, active, flexes)| {
if let Some((group_id, axis)) = group_id.zip(axis) {
let flexes = flexes
.map(|flexes| serde_json::from_str::<Vec<f32>>(&flexes))
.transpose()?;
Ok(SerializedPaneGroup::Group {
axis,
children: self.get_pane_group(workspace_id, Some(group_id))?,
flexes,
})
} else if let Some((pane_id, active)) = pane_id.zip(active) {
Ok(SerializedPaneGroup::Pane(SerializedPane::new(
@ -417,14 +436,31 @@ impl WorkspaceDb {
parent: Option<(GroupId, usize)>,
) -> Result<()> {
match pane_group {
SerializedPaneGroup::Group { axis, children } => {
SerializedPaneGroup::Group {
axis,
children,
flexes,
} => {
let (parent_id, position) = unzip_option(parent);
let flex_string = serde_json::json!(flexes).to_string();
let group_id = conn.select_row_bound::<_, i64>(sql!(
INSERT INTO pane_groups(workspace_id, parent_group_id, position, axis)
VALUES (?, ?, ?, ?)
INSERT INTO pane_groups(
workspace_id,
parent_group_id,
position,
axis,
flexes
)
VALUES (?, ?, ?, ?, ?)
RETURNING group_id
))?((workspace_id, parent_id, position, *axis))?
))?((
workspace_id,
parent_id,
position,
*axis,
flex_string,
))?
.ok_or_else(|| anyhow!("Couldn't retrieve group_id from inserted pane_group"))?;
for (position, group) in children.iter().enumerate() {
@ -641,6 +677,14 @@ mod tests {
assert_eq!(test_text_1, "test-text-1");
}
fn group(axis: gpui::Axis, children: Vec<SerializedPaneGroup>) -> SerializedPaneGroup {
SerializedPaneGroup::Group {
axis,
flexes: None,
children,
}
}
#[gpui::test]
async fn test_full_workspace_serialization() {
env_logger::try_init().ok();
@ -652,12 +696,12 @@ mod tests {
// | - - - | |
// | 3,4 | |
// -----------------
let center_group = SerializedPaneGroup::Group {
axis: gpui::Axis::Horizontal,
children: vec![
SerializedPaneGroup::Group {
axis: gpui::Axis::Vertical,
children: vec![
let center_group = group(
gpui::Axis::Horizontal,
vec![
group(
gpui::Axis::Vertical,
vec![
SerializedPaneGroup::Pane(SerializedPane::new(
vec![
SerializedItem::new("Terminal", 5, false),
@ -673,7 +717,7 @@ mod tests {
false,
)),
],
},
),
SerializedPaneGroup::Pane(SerializedPane::new(
vec![
SerializedItem::new("Terminal", 9, false),
@ -682,7 +726,7 @@ mod tests {
false,
)),
],
};
);
let workspace = SerializedWorkspace {
id: 5,
@ -811,12 +855,12 @@ mod tests {
// | - - - | |
// | 3,4 | |
// -----------------
let center_pane = SerializedPaneGroup::Group {
axis: gpui::Axis::Horizontal,
children: vec![
SerializedPaneGroup::Group {
axis: gpui::Axis::Vertical,
children: vec![
let center_pane = group(
gpui::Axis::Horizontal,
vec![
group(
gpui::Axis::Vertical,
vec![
SerializedPaneGroup::Pane(SerializedPane::new(
vec![
SerializedItem::new("Terminal", 1, false),
@ -832,7 +876,7 @@ mod tests {
true,
)),
],
},
),
SerializedPaneGroup::Pane(SerializedPane::new(
vec![
SerializedItem::new("Terminal", 5, true),
@ -841,7 +885,7 @@ mod tests {
false,
)),
],
};
);
let workspace = default_workspace(&["/tmp"], &center_pane);
@ -858,12 +902,12 @@ mod tests {
let db = WorkspaceDb(open_test_db("test_cleanup_panes").await);
let center_pane = SerializedPaneGroup::Group {
axis: gpui::Axis::Horizontal,
children: vec![
SerializedPaneGroup::Group {
axis: gpui::Axis::Vertical,
children: vec![
let center_pane = group(
gpui::Axis::Horizontal,
vec![
group(
gpui::Axis::Vertical,
vec![
SerializedPaneGroup::Pane(SerializedPane::new(
vec![
SerializedItem::new("Terminal", 1, false),
@ -879,7 +923,7 @@ mod tests {
true,
)),
],
},
),
SerializedPaneGroup::Pane(SerializedPane::new(
vec![
SerializedItem::new("Terminal", 5, false),
@ -888,7 +932,7 @@ mod tests {
false,
)),
],
};
);
let id = &["/tmp"];
@ -896,9 +940,9 @@ mod tests {
db.save_workspace(workspace.clone()).await;
workspace.center_group = SerializedPaneGroup::Group {
axis: gpui::Axis::Vertical,
children: vec![
workspace.center_group = group(
gpui::Axis::Vertical,
vec![
SerializedPaneGroup::Pane(SerializedPane::new(
vec![
SerializedItem::new("Terminal", 1, false),
@ -914,7 +958,7 @@ mod tests {
true,
)),
],
};
);
db.save_workspace(workspace.clone()).await;

View file

@ -127,10 +127,11 @@ impl Bind for DockData {
}
}
#[derive(Debug, PartialEq, Eq, Clone)]
#[derive(Debug, PartialEq, Clone)]
pub enum SerializedPaneGroup {
Group {
axis: Axis,
flexes: Option<Vec<f32>>,
children: Vec<SerializedPaneGroup>,
},
Pane(SerializedPane),
@ -149,7 +150,7 @@ impl Default for SerializedPaneGroup {
impl SerializedPaneGroup {
#[async_recursion(?Send)]
pub(crate) async fn deserialize(
&self,
self,
project: &ModelHandle<Project>,
workspace_id: WorkspaceId,
workspace: &WeakViewHandle<Workspace>,
@ -160,7 +161,7 @@ impl SerializedPaneGroup {
Vec<Option<Box<dyn ItemHandle>>>,
)> {
match self {
SerializedPaneGroup::Group { axis, children } => {
SerializedPaneGroup::Group { axis, children, flexes } => {
let mut current_active_pane = None;
let mut members = Vec::new();
let mut items = Vec::new();
@ -184,7 +185,7 @@ impl SerializedPaneGroup {
}
Some((
Member::Axis(PaneAxis::new(*axis, members)),
Member::Axis(PaneAxis::load(axis, members, flexes)),
current_active_pane,
items,
))

View file

@ -504,6 +504,7 @@ pub struct Workspace {
subscriptions: Vec<Subscription>,
_apply_leader_updates: Task<Result<()>>,
_observe_current_user: Task<Result<()>>,
_schedule_serialize: Option<Task<()>>,
pane_history_timestamp: Arc<AtomicUsize>,
}
@ -718,6 +719,7 @@ impl Workspace {
app_state,
_observe_current_user,
_apply_leader_updates,
_schedule_serialize: None,
leader_updates_tx,
subscriptions,
pane_history_timestamp,
@ -2893,6 +2895,13 @@ impl Workspace {
cx.notify();
}
fn schedule_serialize(&mut self, cx: &mut ViewContext<Self>) {
self._schedule_serialize = Some(cx.spawn(|this, cx| async move {
cx.background().timer(Duration::from_millis(100)).await;
this.read_with(&cx, |this, cx| this.serialize_workspace(cx)).ok();
}));
}
fn serialize_workspace(&self, cx: &ViewContext<Self>) {
fn serialize_pane_handle(
pane_handle: &ViewHandle<Pane>,
@ -2923,12 +2932,17 @@ impl Workspace {
cx: &AppContext,
) -> SerializedPaneGroup {
match pane_group {
Member::Axis(PaneAxis { axis, members, .. }) => SerializedPaneGroup::Group {
Member::Axis(PaneAxis {
axis,
members,
flexes,
}) => SerializedPaneGroup::Group {
axis: *axis,
children: members
.iter()
.map(|member| build_serialized_pane_group(member, cx))
.collect::<Vec<_>>(),
flexes: Some(flexes.borrow().clone()),
},
Member::Pane(pane_handle) => {
SerializedPaneGroup::Pane(serialize_pane_handle(&pane_handle, cx))