Skip to content

Commit 962f2cc

Browse files
authored
Code Quality: Migrate to InputNonClientPointerSource (#14342)
1 parent b892e05 commit 962f2cc

File tree

7 files changed

+65
-175
lines changed

7 files changed

+65
-175
lines changed

src/Files.App/Data/Parameters/PropertiesPageNavigationParameter.cs

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,7 @@
11
// Copyright (c) 2023 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
using Microsoft.UI.Windowing;
54
using Microsoft.UI.Xaml;
6-
using System.Threading;
75

86
namespace Files.App.Data.Parameters
97
{
@@ -16,7 +14,5 @@ public class PropertiesPageNavigationParameter
1614
public IShellPage AppInstance;
1715

1816
public Window Window;
19-
20-
public AppWindow AppWindow;
2117
}
2218
}
Lines changed: 35 additions & 145 deletions
Original file line numberDiff line numberDiff line change
@@ -1,169 +1,59 @@
11
// Copyright (c) 2023 Files Community
22
// Licensed under the MIT License. See the LICENSE.
33

4-
using System;
5-
using System.Collections.Generic;
6-
using System.Linq;
74
using Windows.Graphics;
8-
using Microsoft.UI;
9-
using Microsoft.UI.Windowing;
5+
using Microsoft.UI.Input;
106
using Microsoft.UI.Xaml;
11-
using WinRT.Interop;
127

138
namespace Files.App.Helpers
149
{
1510
public static class DragZoneHelper
1611
{
17-
/// <summary>
18-
/// Get Scale Adjustment
19-
/// </summary>
20-
/// <param name="window"></param>
21-
/// <returns>scale factor percent</returns>
22-
public static double GetScaleAdjustment(Window window) => window.Content.XamlRoot.RasterizationScale;
12+
public delegate int SetTitleBarDragRegionDelegate(InputNonClientPointerSource source, SizeInt32 size, double scaleFactor, Func<UIElement, RectInt32?, RectInt32> getScaledRect);
2313

2414
/// <summary>
25-
/// Calculate dragging-zones of title bar<br/>
26-
/// <strong>You MUST transform the rectangles with <see cref="GetScaleAdjustment"/> before calling <see cref="AppWindowTitleBar.SetDragRectangles"/></strong>
15+
/// Informs the bearer to refresh the drag region.
16+
/// will not set<see cref="NonClientRegionKind.LeftBorder"/>, <see cref="NonClientRegionKind.RightBorder"/>, <see cref="NonClientRegionKind.Caption"/>when titleBarHeight less than 0
2717
/// </summary>
28-
/// <param name="viewportWidth"></param>
29-
/// <param name="dragZoneHeight"></param>
30-
/// <param name="dragZoneLeftIndent"></param>
31-
/// <param name="nonDraggingZones"></param>
32-
/// <returns></returns>
33-
public static IEnumerable<RectInt32> GetDragZones(int viewportWidth, int dragZoneHeight, int dragZoneLeftIndent, IEnumerable<RectInt32> nonDraggingZones)
18+
/// <param name="element"></param>
19+
/// <param name="window"></param>
20+
/// <param name="setTitleBarDragRegion"></param>
21+
public static void RaiseSetTitleBarDragRegion(this Window window, SetTitleBarDragRegionDelegate setTitleBarDragRegion)
3422
{
35-
var draggingZonesX = new List<Range> { new(dragZoneLeftIndent, viewportWidth) };
36-
var draggingZonesY = new List<IEnumerable<Range>> { new[] { new Range(0, dragZoneHeight) } };
37-
38-
foreach (var nonDraggingZone in nonDraggingZones)
39-
{
40-
for (var i = 0; i < draggingZonesX.Count; ++i)
41-
{
42-
var x = draggingZonesX[i];
43-
var y = draggingZonesY[i].ToArray();
44-
var xSubtrahend = new Range(nonDraggingZone.X, nonDraggingZone.X + nonDraggingZone.Width);
45-
var ySubtrahend = new Range(nonDraggingZone.Y, nonDraggingZone.Y + nonDraggingZone.Height);
46-
var xResult = (x - xSubtrahend).ToArray();
47-
if (xResult.Length is 1 && xResult[0] == x)
48-
continue;
49-
var yResult = (y - ySubtrahend).ToArray();
50-
switch (xResult.Length)
51-
{
52-
case 0:
53-
draggingZonesY[i] = yResult;
54-
break;
55-
case 1:
56-
draggingZonesX.RemoveAt(i);
57-
draggingZonesY.RemoveAt(i);
58-
if (xResult[0].Lower == x.Lower)
59-
{
60-
draggingZonesY.InsertRange(i, new[] { y, yResult });
61-
draggingZonesX.InsertRange(i, new[]
62-
{
63-
x with { Upper = xResult[0].Upper },
64-
x with { Lower = xSubtrahend.Lower }
65-
});
66-
}
67-
else // xResult[0].Upper == x.Upper
68-
{
69-
draggingZonesY.InsertRange(i, new[] { yResult, y });
70-
draggingZonesX.InsertRange(i, new[]
71-
{
72-
x with { Upper = xSubtrahend.Upper },
73-
x with { Lower = xResult[0].Lower }
74-
});
75-
}
76-
++i;
77-
break;
78-
case 2:
79-
draggingZonesX.RemoveAt(i);
80-
draggingZonesY.RemoveAt(i);
81-
draggingZonesY.InsertRange(i, new[] { y, yResult, y });
82-
draggingZonesX.InsertRange(i, new[]
83-
{
84-
x with { Upper = xResult[0].Upper },
85-
xSubtrahend,
86-
x with { Lower = xResult[1].Lower }
87-
});
88-
++i;
89-
++i;
90-
break;
91-
}
92-
}
93-
}
94-
95-
var rects = draggingZonesX
96-
.SelectMany((rangeX, i) => draggingZonesY[i]
97-
.Select(rangeY => new RectInt32(rangeX.Lower, rangeY.Lower, rangeX.Distance, rangeY.Distance)))
98-
.OrderBy(t => t.Y)
99-
.ThenBy(t => t.X).ToList();
100-
for (var i = 0; i < rects.Count - 1; ++i)
23+
if (!window.AppWindow.IsVisible)
24+
return;
25+
// UIElement.RasterizationScale is always 1
26+
var source = InputNonClientPointerSource.GetForWindowId(window.AppWindow.Id);
27+
var uiElement = window.Content;
28+
var scaleFactor = uiElement.XamlRoot.RasterizationScale;
29+
var size = window.AppWindow.Size;
30+
// If the number of regions is 0 or 1, AppWindow will automatically reset to the default region next time, but if it is >=2, it will not and need to be manually cleared
31+
source.ClearRegionRects(NonClientRegionKind.Passthrough);
32+
var titleBarHeight = setTitleBarDragRegion(source, size, scaleFactor, GetScaledRect);
33+
if (titleBarHeight >= 0)
10134
{
102-
var now = rects[i];
103-
var next = rects[i + 1];
104-
if (now.Height == next.Height && now.X + now.Width == next.X)
105-
{
106-
rects.RemoveRange(i, 2);
107-
rects.Insert(i, now with { Width = now.Width + next.Width });
108-
}
35+
// region under the buttons
36+
const int borderThickness = 5;
37+
source.SetRegionRects(NonClientRegionKind.LeftBorder, [GetScaledRect(uiElement, new(0, 0, borderThickness, titleBarHeight))]);
38+
source.SetRegionRects(NonClientRegionKind.RightBorder, [GetScaledRect(uiElement, new(size.Width, 0, borderThickness, titleBarHeight))]);
39+
source.SetRegionRects(NonClientRegionKind.Caption, [GetScaledRect(uiElement, new(0, 0, size.Width, titleBarHeight))]);
10940
}
110-
111-
return rects;
11241
}
11342

114-
/// <summary>
115-
/// Set dragging-zones of title bar
116-
/// </summary>
117-
/// <param name="window"></param>
118-
/// <param name="dragZoneHeight"></param>
119-
/// <param name="dragZoneLeftIndent"></param>
120-
/// <param name="nonDraggingZones"></param>
121-
public static void SetDragZones(Window window, int dragZoneHeight = 40, int dragZoneLeftIndent = 0, IEnumerable<RectInt32>? nonDraggingZones = null)
43+
private static RectInt32 GetScaledRect(this UIElement uiElement, RectInt32? r = null)
12244
{
123-
var hWnd = WindowNative.GetWindowHandle(window);
124-
var windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
125-
var appWindow = AppWindow.GetFromWindowId(windowId);
126-
var scaleAdjustment = GetScaleAdjustment(window);
127-
var windowWidth = (int)(appWindow.Size.Width / scaleAdjustment);
128-
nonDraggingZones ??= Array.Empty<RectInt32>();
129-
#if DEBUG
130-
// Subtract the toolbar area (center-top in window), only in DEBUG mode.
131-
nonDraggingZones = nonDraggingZones.Concat(new RectInt32[] { new((windowWidth - DebugToolbarWidth) / 2, 0, DebugToolbarWidth, DebugToolbarHeight) });
132-
#endif
133-
appWindow.TitleBar.SetDragRectangles(
134-
GetDragZones(windowWidth, dragZoneHeight, dragZoneLeftIndent, nonDraggingZones)
135-
.Select(rect => new RectInt32(
136-
(int)(rect.X * scaleAdjustment),
137-
(int)(rect.Y * scaleAdjustment),
138-
(int)(rect.Width * scaleAdjustment),
139-
(int)(rect.Height * scaleAdjustment)))
140-
.ToArray());
141-
}
142-
143-
private const int DebugToolbarWidth = 217;
144-
private const int DebugToolbarHeight = 25;
145-
}
146-
147-
file record Range(int Lower, int Upper)
148-
{
149-
public int Distance => Upper - Lower;
150-
151-
private bool Intersects(Range other) => other.Lower <= Upper && other.Upper >= Lower;
152-
153-
public static IEnumerable<Range> operator -(Range minuend, Range subtrahend)
154-
{
155-
if (!minuend.Intersects(subtrahend))
45+
if (r is { } rect)
15646
{
157-
yield return minuend;
158-
yield break;
47+
var scaleFactor = uiElement.XamlRoot.RasterizationScale;
48+
return new((int)(rect.X * scaleFactor), (int)(rect.Y * scaleFactor), (int)(rect.Width * scaleFactor),
49+
(int)(rect.Height * scaleFactor));
50+
}
51+
else
52+
{
53+
var pos = uiElement.TransformToVisual(null).TransformPoint(new(0, 0));
54+
rect = new RectInt32((int)pos.X, (int)pos.Y, (int)uiElement.ActualSize.X, (int)uiElement.ActualSize.Y);
55+
return GetScaledRect(uiElement, rect);
15956
}
160-
if (minuend.Lower < subtrahend.Lower)
161-
yield return minuend with { Upper = subtrahend.Lower };
162-
if (minuend.Upper > subtrahend.Upper)
163-
yield return minuend with { Lower = subtrahend.Upper };
16457
}
165-
166-
public static IEnumerable<Range> operator -(IEnumerable<Range> minuends, Range subtrahend)
167-
=> minuends.SelectMany(minuend => minuend - subtrahend);
16858
}
16959
}

src/Files.App/Utils/Storage/Helpers/FilePropertiesHelpers.cs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -128,7 +128,6 @@ public static void OpenPropertiesWindow(object item, IShellPage associatedInstan
128128
{
129129
Parameter = item,
130130
AppInstance = associatedInstance,
131-
AppWindow = appWindow,
132131
Window = propertiesWindow
133132
},
134133
new SuppressNavigationTransitionInfo());

src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -24,13 +24,12 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
2424
if (SetProperty(ref _SelectedNavigationViewItem, value) &&
2525
!_selectionChangedAutomatically)
2626
{
27-
var parameter = new PropertiesPageNavigationParameter()
27+
var parameter = new PropertiesPageNavigationParameter
2828
{
2929
AppInstance = _parameter.AppInstance,
3030
CancellationTokenSource = ChangedPropertiesCancellationTokenSource,
3131
Parameter = _parameter.Parameter,
32-
Window = Window,
33-
AppWindow = AppWindow,
32+
Window = Window
3433
};
3534

3635
var page = value.ItemType switch
@@ -79,8 +78,7 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
7978

8079
private readonly Window Window;
8180

82-
private readonly AppWindow AppWindow;
83-
81+
private AppWindow AppWindow => Window.AppWindow;
8482
private readonly Frame _mainFrame;
8583

8684
private readonly BaseProperties _baseProperties;
@@ -93,12 +91,11 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
9391
public IAsyncRelayCommand SaveChangedPropertiesCommand { get; }
9492
public IRelayCommand CancelChangedPropertiesCommand { get; }
9593

96-
public MainPropertiesViewModel(Window window, AppWindow appWindow, Frame mainFrame, BaseProperties baseProperties, PropertiesPageNavigationParameter parameter)
94+
public MainPropertiesViewModel(Window window, Frame mainFrame, BaseProperties baseProperties, PropertiesPageNavigationParameter parameter)
9795
{
9896
ChangedPropertiesCancellationTokenSource = new();
9997

10098
Window = window;
101-
AppWindow = appWindow;
10299
_mainFrame = mainFrame;
103100
_parameter = parameter;
104101
_baseProperties = baseProperties;
@@ -108,7 +105,7 @@ public MainPropertiesViewModel(Window window, AppWindow appWindow, Frame mainFra
108105
CancelChangedPropertiesCommand = new RelayCommand(ExecuteCancelChangedPropertiesCommand);
109106

110107
NavigationViewItems = PropertiesNavigationViewItemFactory.Initialize(parameter.Parameter);
111-
SelectedNavigationViewItem = NavigationViewItems.Where(x => x.ItemType == PropertiesNavigationViewItemType.General).First();
108+
SelectedNavigationViewItem = NavigationViewItems.First(x => x.ItemType == PropertiesNavigationViewItemType.General);
112109
}
113110

114111
private void ExecuteDoBackwardNavigationCommand()

src/Files.App/Views/MainPage.xaml.cs

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@
1616
using Windows.ApplicationModel;
1717
using Windows.ApplicationModel.DataTransfer;
1818
using Windows.Foundation.Metadata;
19+
using Windows.Graphics;
1920
using Windows.Services.Store;
2021
using WinRT.Interop;
2122
using VirtualKey = Windows.System.VirtualKey;
@@ -121,7 +122,7 @@ private async Task AppRunningAsAdminPromptAsync()
121122
// WINUI3
122123
private ContentDialog SetContentDialogRoot(ContentDialog contentDialog)
123124
{
124-
if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
125+
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
125126
contentDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot;
126127

127128
return contentDialog;
@@ -139,21 +140,20 @@ private void UserSettingsService_OnSettingChangedEvent(object? sender, SettingCh
139140

140141
private void HorizontalMultitaskingControl_Loaded(object sender, RoutedEventArgs e)
141142
{
142-
TabControl.DragArea.SizeChanged += (_, _) => SetRectDragRegion();
143-
144-
if (ViewModel.MultitaskingControl is not UserControls.TabBar.TabBar)
143+
TabControl.DragArea.SizeChanged += (_, _) => MainWindow.Instance.RaiseSetTitleBarDragRegion(SetTitleBarDragRegion);
144+
if (ViewModel.MultitaskingControl is not TabBar)
145145
{
146146
ViewModel.MultitaskingControl = TabControl;
147147
ViewModel.MultitaskingControls.Add(TabControl);
148148
ViewModel.MultitaskingControl.CurrentInstanceChanged += MultitaskingControl_CurrentInstanceChanged;
149149
}
150150
}
151151

152-
private void SetRectDragRegion()
152+
private int SetTitleBarDragRegion(InputNonClientPointerSource source, SizeInt32 size, double scaleFactor, Func<UIElement, RectInt32?, RectInt32> getScaledRect)
153153
{
154-
DragZoneHelper.SetDragZones(
155-
MainWindow.Instance,
156-
dragZoneLeftIndent: (int)(TabControl.ActualWidth + TabControl.Margin.Left - TabControl.DragArea.ActualWidth));
154+
var height = (int)TabControl.ActualHeight;
155+
source.SetRegionRects(NonClientRegionKind.Passthrough, [getScaledRect(this, new RectInt32(0, 0, (int)(TabControl.ActualWidth + TabControl.Margin.Left - TabControl.DragArea.ActualWidth), height))]);
156+
return height;
157157
}
158158

159159
public async void TabItemContent_ContentChanged(object? sender, CustomTabViewItemParameter e)
@@ -289,6 +289,8 @@ protected override void OnLostFocus(RoutedEventArgs e)
289289

290290
private void Page_Loaded(object sender, RoutedEventArgs e)
291291
{
292+
MainWindow.Instance.AppWindow.Changed += (_, _) => MainWindow.Instance.RaiseSetTitleBarDragRegion(SetTitleBarDragRegion);
293+
292294
// Defers the status bar loading until after the page has loaded to improve startup perf
293295
FindName(nameof(StatusBarControl));
294296
FindName(nameof(InnerNavigationToolbar));

src/Files.App/Views/Properties/CustomizationPage.xaml.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,10 +22,10 @@ protected override void OnNavigatedTo(NavigationEventArgs e)
2222

2323
base.OnNavigatedTo(e);
2424

25-
CustomizationViewModel = new(AppInstance, BaseProperties, parameter.AppWindow);
25+
CustomizationViewModel = new(AppInstance, BaseProperties, parameter.Window.AppWindow);
2626
}
2727

28-
public async override Task<bool> SaveChangesAsync()
28+
public override async Task<bool> SaveChangesAsync()
2929
=> await CustomizationViewModel.UpdateIcon();
3030

3131
public override void Dispose()

0 commit comments

Comments
 (0)