Skip to content

Commit ee46960

Browse files
authored
Feature: Added support for canceling tab tear off (#13642)
1 parent 20e04d0 commit ee46960

File tree

1 file changed

+33
-14
lines changed

1 file changed

+33
-14
lines changed

src/Files.App/UserControls/TabBar/TabBar.xaml.cs

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44
using CommunityToolkit.WinUI.UI;
55
using Microsoft.UI.Xaml;
66
using Microsoft.UI.Xaml.Controls;
7+
using Microsoft.UI.Xaml.Input;
78
using Microsoft.UI.Xaml.Shapes;
89
using Windows.ApplicationModel.DataTransfer;
910
using Windows.Storage;
@@ -62,6 +63,12 @@ public Rectangle DragArea
6263
/// <summary> Starting time when dragging a tab. </summary>
6364
private DateTimeOffset dragStartTime;
6465

66+
/// <summary>
67+
/// Indicates if drag operation should be canceled.
68+
/// This value gets reset at the start of the drag operation
69+
/// </summary>
70+
private bool isCancelingDragOperation;
71+
6572
public TabBar()
6673
{
6774
InitializeComponent();
@@ -82,9 +89,7 @@ public TabBar()
8289
private void TabView_TabItemsChanged(TabView sender, Windows.Foundation.Collections.IVectorChangedEventArgs args)
8390
{
8491
if (args.CollectionChange == Windows.Foundation.Collections.CollectionChange.ItemRemoved)
85-
{
8692
App.AppModel.TabStripSelectedIndex = Items.IndexOf(HorizontalTabView.SelectedItem as TabBarItem);
87-
}
8893

8994
if (App.AppModel.TabStripSelectedIndex >= 0 && App.AppModel.TabStripSelectedIndex < Items.Count)
9095
{
@@ -132,19 +137,34 @@ private void TabHoverSelected(object sender, object e)
132137
{
133138
tabHoverTimer.Stop();
134139
if (hoveredTabViewItem is not null)
135-
{
136140
App.AppModel.TabStripSelectedIndex = Items.IndexOf(hoveredTabViewItem.DataContext as TabBarItem);
137-
}
138141
}
139142

140143
private void TabView_TabDragStarting(TabView sender, TabViewTabDragStartingEventArgs args)
141144
{
145+
// Reset value
146+
isCancelingDragOperation = false;
147+
142148
var tabViewItemArgs = (args.Item as TabBarItem).NavigationParameter;
143149
args.Data.Properties.Add(TabPathIdentifier, tabViewItemArgs.Serialize());
144150
args.Data.RequestedOperation = DataPackageOperation.Move;
145151

152+
// Get cursor position & time to track how far the tab was dragged.
146153
InteropHelpers.GetCursorPos(out dragStartPoint);
147154
dragStartTime = DateTimeOffset.UtcNow;
155+
156+
// Focus the UI Element, without this the focus sometimes changes
157+
// and the PreviewKeyDown event won't trigger.
158+
Focus(FocusState.Programmatic);
159+
PreviewKeyDown += TabDragging_PreviewKeyDown;
160+
}
161+
162+
private void TabDragging_PreviewKeyDown(object sender, KeyRoutedEventArgs e)
163+
{
164+
// Pressing escape will automatically complete the drag event but we need to set the
165+
// isCancelingDragOperation field in order to detect if escape was pressed.
166+
if (e.Key is Windows.System.VirtualKey.Escape)
167+
isCancelingDragOperation = true;
148168
}
149169

150170
private void TabView_TabStripDragOver(object sender, DragEventArgs e)
@@ -178,9 +198,7 @@ private async void TabView_TabStripDrop(object sender, DragEventArgs e)
178198

179199
if (!e.DataView.Properties.TryGetValue(TabPathIdentifier, out object tabViewItemPathObj) ||
180200
!(tabViewItemPathObj is string tabViewItemString))
181-
{
182201
return;
183-
}
184202

185203
var index = -1;
186204

@@ -202,24 +220,27 @@ private async void TabView_TabStripDrop(object sender, DragEventArgs e)
202220

203221
private void TabView_TabDragCompleted(TabView sender, TabViewTabDragCompletedEventArgs args)
204222
{
223+
// Unsubscribe from the key down event, it's only needed when a tab is actively being dragged
224+
PreviewKeyDown -= TabDragging_PreviewKeyDown;
225+
205226
if (ApplicationData.Current.LocalSettings.Values.ContainsKey(TabDropHandledIdentifier) &&
206227
(bool)ApplicationData.Current.LocalSettings.Values[TabDropHandledIdentifier])
207-
{
208228
CloseTab(args.Item as TabBarItem);
209-
}
210229
else
211-
{
212230
HorizontalTabView.SelectedItem = args.Tab;
213-
}
214231

215232
if (ApplicationData.Current.LocalSettings.Values.ContainsKey(TabDropHandledIdentifier))
216-
{
217233
ApplicationData.Current.LocalSettings.Values.Remove(TabDropHandledIdentifier);
218-
}
219234
}
220235

221236
private async void TabView_TabDroppedOutside(TabView sender, TabViewTabDroppedOutsideEventArgs args)
222237
{
238+
// Unsubscribe from the key down event, it's only needed when a tab is actively being dragged
239+
PreviewKeyDown -= TabDragging_PreviewKeyDown;
240+
241+
if (isCancelingDragOperation)
242+
return;
243+
223244
InteropHelpers.GetCursorPos(out var droppedPoint);
224245
var droppedTime = DateTimeOffset.UtcNow;
225246
var dragTime = droppedTime - dragStartTime;
@@ -241,10 +262,8 @@ private async void TabView_TabDroppedOutside(TabView sender, TabViewTabDroppedOu
241262
sender.SelectedIndex = selectedTabViewItemIndex;
242263
}
243264
else
244-
{
245265
// Dispose tab arguments
246266
(args.Item as TabBarItem)?.Unload();
247-
}
248267
}
249268

250269
private void TabItemContextMenu_Opening(object sender, object e)

0 commit comments

Comments
 (0)