Skip to content

Commit 5d90420

Browse files
committed
Preserve active tab when a panel group is docked
1 parent d0f3214 commit 5d90420

6 files changed

Lines changed: 24 additions & 11 deletions

File tree

editor/src/messages/portfolio/portfolio_message.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -155,6 +155,7 @@ pub enum PortfolioMessage {
155155
target_group: PanelGroupId,
156156
direction: DockingSplitDirection,
157157
tabs: Vec<PanelType>,
158+
active_tab_index: usize,
158159
},
159160
SelectDocument {
160161
document_id: DocumentId,

editor/src/messages/portfolio/portfolio_message_handler.rs

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -471,6 +471,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
471471

472472
let Some(source_state) = self.workspace_panel_layout.panel_group(source_group) else { return };
473473
let tabs: Vec<PanelType> = source_state.tabs.clone();
474+
let source_active_tab_index = source_state.active_tab_index;
474475
if tabs.is_empty() {
475476
return;
476477
}
@@ -489,13 +490,13 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
489490
source.active_tab_index = 0;
490491
}
491492

492-
// Insert all tabs into the target group
493+
// Insert all tabs into the target group, preserving which tab was active in the source
493494
if let Some(target) = self.workspace_panel_layout.panel_group_mut(target_group) {
494495
let index = insert_index.min(target.tabs.len());
495496
for (i, panel_type) in tabs.iter().enumerate() {
496497
target.tabs.insert(index + i, *panel_type);
497498
}
498-
target.active_tab_index = index;
499+
target.active_tab_index = index + source_active_tab_index.min(tabs.len().saturating_sub(1));
499500
}
500501

501502
self.workspace_panel_layout.prune();
@@ -1270,7 +1271,12 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
12701271
}
12711272
}
12721273
}
1273-
PortfolioMessage::SplitPanelGroup { target_group, direction, tabs } => {
1274+
PortfolioMessage::SplitPanelGroup {
1275+
target_group,
1276+
direction,
1277+
tabs,
1278+
active_tab_index,
1279+
} => {
12741280
// Destroy layouts for the dragged tabs and the target group's active panel (it may get remounted by the frontend)
12751281
for &panel_type in &tabs {
12761282
Self::destroy_panel_layouts(panel_type, responses);
@@ -1285,7 +1291,7 @@ impl MessageHandler<PortfolioMessage, PortfolioMessageContext<'_>> for Portfolio
12851291
}
12861292

12871293
// Create the new panel group adjacent to the target, then prune empty groups
1288-
let new_id = self.workspace_panel_layout.split_panel_group(target_group, direction, tabs.clone());
1294+
let new_id = self.workspace_panel_layout.split_panel_group(target_group, direction, tabs.clone(), active_tab_index);
12891295
self.workspace_panel_layout.prune();
12901296

12911297
responses.add(MenuBarMessage::SendLayout);

editor/src/messages/portfolio/utility_types.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -221,12 +221,12 @@ impl WorkspacePanelLayout {
221221
/// The direction determines where the new group goes relative to the target.
222222
/// Left/Right creates a horizontal (row) split, Top/Bottom creates a vertical (column) split.
223223
/// Returns the ID of the newly created panel group.
224-
pub fn split_panel_group(&mut self, target_group_id: PanelGroupId, direction: DockingSplitDirection, tabs: Vec<PanelType>) -> PanelGroupId {
224+
pub fn split_panel_group(&mut self, target_group_id: PanelGroupId, direction: DockingSplitDirection, tabs: Vec<PanelType>, active_tab_index: usize) -> PanelGroupId {
225225
let new_id = self.next_id();
226226
let new_group = SplitChild {
227227
subdivision: PanelLayoutSubdivision::PanelGroup {
228228
id: new_id,
229-
state: PanelGroupState { tabs, active_tab_index: 0 },
229+
state: PanelGroupState { tabs, active_tab_index },
230230
},
231231
size: 50.,
232232
};

frontend/src/components/window/Panel.svelte

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@
3939
export let emptySpaceAction: (() => void) | undefined = undefined;
4040
export let crossPanelDropAction: ((sourcePanelId: string, targetPanelId: string, insertIndex: number) => void) | undefined = undefined;
4141
export let groupDropAction: ((sourcePanelId: string, targetPanelId: string, insertIndex: number) => void) | undefined = undefined;
42-
export let splitDropAction: ((targetPanelId: string, direction: DockingEdge, tabs: PanelType[]) => void) | undefined = undefined;
42+
export let splitDropAction: ((targetPanelId: string, direction: DockingEdge, tabs: PanelType[], activeTabIndex: number) => void) | undefined = undefined;
4343
4444
let className = "";
4545
export { className as class };
@@ -199,7 +199,12 @@
199199
}
200200
// Edge docking drop: create a new split adjacent to the target panel
201201
else if (crossPanelState.active && crossPanelState.hoverDockingPanelId && crossPanelState.hoverDockingEdge) {
202-
splitDropAction?.(crossPanelState.hoverDockingPanelId, crossPanelState.hoverDockingEdge, crossPanelState.draggedTabs);
202+
splitDropAction?.(
203+
crossPanelState.hoverDockingPanelId,
204+
crossPanelState.hoverDockingEdge,
205+
crossPanelState.draggedTabs,
206+
crossPanelState.draggingGroup ? crossPanelState.sourceTabIndex : 0,
207+
);
203208
}
204209
// Cross-panel tab bar drop: insert as a tab in the target panel group
205210
else if (

frontend/src/components/window/PanelSubdivision.svelte

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -150,8 +150,8 @@
150150
editor.moveAllPanelTabs(BigInt(sourcePanelId), BigInt(targetPanelId), insertIndex);
151151
}
152152
153-
function splitDrop(targetPanelId: string, direction: string, tabs: string[]) {
154-
editor.splitPanelGroup(BigInt(targetPanelId), direction, tabs);
153+
function splitDrop(targetPanelId: string, direction: string, tabs: string[], activeTabIndex: number) {
154+
editor.splitPanelGroup(BigInt(targetPanelId), direction, tabs, activeTabIndex);
155155
}
156156
157157
function isDocumentGroup(state: PanelGroupState): boolean {

frontend/wrapper/src/editor_wrapper.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -474,13 +474,14 @@ impl EditorWrapper {
474474
}
475475

476476
#[wasm_bindgen(js_name = splitPanelGroup)]
477-
pub fn split_panel_group(&self, target_group: u64, direction: String, tabs: JsValue) {
477+
pub fn split_panel_group(&self, target_group: u64, direction: String, tabs: JsValue, active_tab_index: usize) {
478478
let direction: DockingSplitDirection = serde_wasm_bindgen::from_value(JsValue::from_str(&direction)).unwrap();
479479
let tabs: Vec<PanelType> = serde_wasm_bindgen::from_value(tabs).unwrap();
480480
let message = PortfolioMessage::SplitPanelGroup {
481481
target_group: PanelGroupId(target_group),
482482
direction,
483483
tabs,
484+
active_tab_index,
484485
};
485486
self.dispatch(message);
486487
}

0 commit comments

Comments
 (0)