Skip to content

Commit

Permalink
Code Quality: Migrate to InputNonClientPointerSource (files-community…
Browse files Browse the repository at this point in the history
  • Loading branch information
Poker-sang authored Jan 2, 2024
1 parent b892e05 commit 962f2cc
Show file tree
Hide file tree
Showing 7 changed files with 65 additions and 175 deletions.
Original file line number Diff line number Diff line change
@@ -1,9 +1,7 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.

using Microsoft.UI.Windowing;
using Microsoft.UI.Xaml;
using System.Threading;

namespace Files.App.Data.Parameters
{
Expand All @@ -16,7 +14,5 @@ public class PropertiesPageNavigationParameter
public IShellPage AppInstance;

public Window Window;

public AppWindow AppWindow;
}
}
180 changes: 35 additions & 145 deletions src/Files.App/Helpers/UI/DragZoneHelper.cs
Original file line number Diff line number Diff line change
@@ -1,169 +1,59 @@
// Copyright (c) 2023 Files Community
// Licensed under the MIT License. See the LICENSE.

using System;
using System.Collections.Generic;
using System.Linq;
using Windows.Graphics;
using Microsoft.UI;
using Microsoft.UI.Windowing;
using Microsoft.UI.Input;
using Microsoft.UI.Xaml;
using WinRT.Interop;

namespace Files.App.Helpers
{
public static class DragZoneHelper
{
/// <summary>
/// Get Scale Adjustment
/// </summary>
/// <param name="window"></param>
/// <returns>scale factor percent</returns>
public static double GetScaleAdjustment(Window window) => window.Content.XamlRoot.RasterizationScale;
public delegate int SetTitleBarDragRegionDelegate(InputNonClientPointerSource source, SizeInt32 size, double scaleFactor, Func<UIElement, RectInt32?, RectInt32> getScaledRect);

/// <summary>
/// Calculate dragging-zones of title bar<br/>
/// <strong>You MUST transform the rectangles with <see cref="GetScaleAdjustment"/> before calling <see cref="AppWindowTitleBar.SetDragRectangles"/></strong>
/// Informs the bearer to refresh the drag region.
/// will not set<see cref="NonClientRegionKind.LeftBorder"/>, <see cref="NonClientRegionKind.RightBorder"/>, <see cref="NonClientRegionKind.Caption"/>when titleBarHeight less than 0
/// </summary>
/// <param name="viewportWidth"></param>
/// <param name="dragZoneHeight"></param>
/// <param name="dragZoneLeftIndent"></param>
/// <param name="nonDraggingZones"></param>
/// <returns></returns>
public static IEnumerable<RectInt32> GetDragZones(int viewportWidth, int dragZoneHeight, int dragZoneLeftIndent, IEnumerable<RectInt32> nonDraggingZones)
/// <param name="element"></param>
/// <param name="window"></param>
/// <param name="setTitleBarDragRegion"></param>
public static void RaiseSetTitleBarDragRegion(this Window window, SetTitleBarDragRegionDelegate setTitleBarDragRegion)
{
var draggingZonesX = new List<Range> { new(dragZoneLeftIndent, viewportWidth) };
var draggingZonesY = new List<IEnumerable<Range>> { new[] { new Range(0, dragZoneHeight) } };

foreach (var nonDraggingZone in nonDraggingZones)
{
for (var i = 0; i < draggingZonesX.Count; ++i)
{
var x = draggingZonesX[i];
var y = draggingZonesY[i].ToArray();
var xSubtrahend = new Range(nonDraggingZone.X, nonDraggingZone.X + nonDraggingZone.Width);
var ySubtrahend = new Range(nonDraggingZone.Y, nonDraggingZone.Y + nonDraggingZone.Height);
var xResult = (x - xSubtrahend).ToArray();
if (xResult.Length is 1 && xResult[0] == x)
continue;
var yResult = (y - ySubtrahend).ToArray();
switch (xResult.Length)
{
case 0:
draggingZonesY[i] = yResult;
break;
case 1:
draggingZonesX.RemoveAt(i);
draggingZonesY.RemoveAt(i);
if (xResult[0].Lower == x.Lower)
{
draggingZonesY.InsertRange(i, new[] { y, yResult });
draggingZonesX.InsertRange(i, new[]
{
x with { Upper = xResult[0].Upper },
x with { Lower = xSubtrahend.Lower }
});
}
else // xResult[0].Upper == x.Upper
{
draggingZonesY.InsertRange(i, new[] { yResult, y });
draggingZonesX.InsertRange(i, new[]
{
x with { Upper = xSubtrahend.Upper },
x with { Lower = xResult[0].Lower }
});
}
++i;
break;
case 2:
draggingZonesX.RemoveAt(i);
draggingZonesY.RemoveAt(i);
draggingZonesY.InsertRange(i, new[] { y, yResult, y });
draggingZonesX.InsertRange(i, new[]
{
x with { Upper = xResult[0].Upper },
xSubtrahend,
x with { Lower = xResult[1].Lower }
});
++i;
++i;
break;
}
}
}

var rects = draggingZonesX
.SelectMany((rangeX, i) => draggingZonesY[i]
.Select(rangeY => new RectInt32(rangeX.Lower, rangeY.Lower, rangeX.Distance, rangeY.Distance)))
.OrderBy(t => t.Y)
.ThenBy(t => t.X).ToList();
for (var i = 0; i < rects.Count - 1; ++i)
if (!window.AppWindow.IsVisible)
return;
// UIElement.RasterizationScale is always 1
var source = InputNonClientPointerSource.GetForWindowId(window.AppWindow.Id);
var uiElement = window.Content;
var scaleFactor = uiElement.XamlRoot.RasterizationScale;
var size = window.AppWindow.Size;
// 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
source.ClearRegionRects(NonClientRegionKind.Passthrough);
var titleBarHeight = setTitleBarDragRegion(source, size, scaleFactor, GetScaledRect);
if (titleBarHeight >= 0)
{
var now = rects[i];
var next = rects[i + 1];
if (now.Height == next.Height && now.X + now.Width == next.X)
{
rects.RemoveRange(i, 2);
rects.Insert(i, now with { Width = now.Width + next.Width });
}
// region under the buttons
const int borderThickness = 5;
source.SetRegionRects(NonClientRegionKind.LeftBorder, [GetScaledRect(uiElement, new(0, 0, borderThickness, titleBarHeight))]);
source.SetRegionRects(NonClientRegionKind.RightBorder, [GetScaledRect(uiElement, new(size.Width, 0, borderThickness, titleBarHeight))]);
source.SetRegionRects(NonClientRegionKind.Caption, [GetScaledRect(uiElement, new(0, 0, size.Width, titleBarHeight))]);
}

return rects;
}

/// <summary>
/// Set dragging-zones of title bar
/// </summary>
/// <param name="window"></param>
/// <param name="dragZoneHeight"></param>
/// <param name="dragZoneLeftIndent"></param>
/// <param name="nonDraggingZones"></param>
public static void SetDragZones(Window window, int dragZoneHeight = 40, int dragZoneLeftIndent = 0, IEnumerable<RectInt32>? nonDraggingZones = null)
private static RectInt32 GetScaledRect(this UIElement uiElement, RectInt32? r = null)
{
var hWnd = WindowNative.GetWindowHandle(window);
var windowId = Win32Interop.GetWindowIdFromWindow(hWnd);
var appWindow = AppWindow.GetFromWindowId(windowId);
var scaleAdjustment = GetScaleAdjustment(window);
var windowWidth = (int)(appWindow.Size.Width / scaleAdjustment);
nonDraggingZones ??= Array.Empty<RectInt32>();
#if DEBUG
// Subtract the toolbar area (center-top in window), only in DEBUG mode.
nonDraggingZones = nonDraggingZones.Concat(new RectInt32[] { new((windowWidth - DebugToolbarWidth) / 2, 0, DebugToolbarWidth, DebugToolbarHeight) });
#endif
appWindow.TitleBar.SetDragRectangles(
GetDragZones(windowWidth, dragZoneHeight, dragZoneLeftIndent, nonDraggingZones)
.Select(rect => new RectInt32(
(int)(rect.X * scaleAdjustment),
(int)(rect.Y * scaleAdjustment),
(int)(rect.Width * scaleAdjustment),
(int)(rect.Height * scaleAdjustment)))
.ToArray());
}

private const int DebugToolbarWidth = 217;
private const int DebugToolbarHeight = 25;
}

file record Range(int Lower, int Upper)
{
public int Distance => Upper - Lower;

private bool Intersects(Range other) => other.Lower <= Upper && other.Upper >= Lower;

public static IEnumerable<Range> operator -(Range minuend, Range subtrahend)
{
if (!minuend.Intersects(subtrahend))
if (r is { } rect)
{
yield return minuend;
yield break;
var scaleFactor = uiElement.XamlRoot.RasterizationScale;
return new((int)(rect.X * scaleFactor), (int)(rect.Y * scaleFactor), (int)(rect.Width * scaleFactor),
(int)(rect.Height * scaleFactor));
}
else
{
var pos = uiElement.TransformToVisual(null).TransformPoint(new(0, 0));
rect = new RectInt32((int)pos.X, (int)pos.Y, (int)uiElement.ActualSize.X, (int)uiElement.ActualSize.Y);
return GetScaledRect(uiElement, rect);
}
if (minuend.Lower < subtrahend.Lower)
yield return minuend with { Upper = subtrahend.Lower };
if (minuend.Upper > subtrahend.Upper)
yield return minuend with { Lower = subtrahend.Upper };
}

public static IEnumerable<Range> operator -(IEnumerable<Range> minuends, Range subtrahend)
=> minuends.SelectMany(minuend => minuend - subtrahend);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -128,7 +128,6 @@ public static void OpenPropertiesWindow(object item, IShellPage associatedInstan
{
Parameter = item,
AppInstance = associatedInstance,
AppWindow = appWindow,
Window = propertiesWindow
},
new SuppressNavigationTransitionInfo());
Expand Down
13 changes: 5 additions & 8 deletions src/Files.App/ViewModels/Properties/MainPropertiesViewModel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -24,13 +24,12 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
if (SetProperty(ref _SelectedNavigationViewItem, value) &&
!_selectionChangedAutomatically)
{
var parameter = new PropertiesPageNavigationParameter()
var parameter = new PropertiesPageNavigationParameter
{
AppInstance = _parameter.AppInstance,
CancellationTokenSource = ChangedPropertiesCancellationTokenSource,
Parameter = _parameter.Parameter,
Window = Window,
AppWindow = AppWindow,
Window = Window
};

var page = value.ItemType switch
Expand Down Expand Up @@ -79,8 +78,7 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem

private readonly Window Window;

private readonly AppWindow AppWindow;

private AppWindow AppWindow => Window.AppWindow;
private readonly Frame _mainFrame;

private readonly BaseProperties _baseProperties;
Expand All @@ -93,12 +91,11 @@ public NavigationViewItemButtonStyleItem SelectedNavigationViewItem
public IAsyncRelayCommand SaveChangedPropertiesCommand { get; }
public IRelayCommand CancelChangedPropertiesCommand { get; }

public MainPropertiesViewModel(Window window, AppWindow appWindow, Frame mainFrame, BaseProperties baseProperties, PropertiesPageNavigationParameter parameter)
public MainPropertiesViewModel(Window window, Frame mainFrame, BaseProperties baseProperties, PropertiesPageNavigationParameter parameter)
{
ChangedPropertiesCancellationTokenSource = new();

Window = window;
AppWindow = appWindow;
_mainFrame = mainFrame;
_parameter = parameter;
_baseProperties = baseProperties;
Expand All @@ -108,7 +105,7 @@ public MainPropertiesViewModel(Window window, AppWindow appWindow, Frame mainFra
CancelChangedPropertiesCommand = new RelayCommand(ExecuteCancelChangedPropertiesCommand);

NavigationViewItems = PropertiesNavigationViewItemFactory.Initialize(parameter.Parameter);
SelectedNavigationViewItem = NavigationViewItems.Where(x => x.ItemType == PropertiesNavigationViewItemType.General).First();
SelectedNavigationViewItem = NavigationViewItems.First(x => x.ItemType == PropertiesNavigationViewItemType.General);
}

private void ExecuteDoBackwardNavigationCommand()
Expand Down
18 changes: 10 additions & 8 deletions src/Files.App/Views/MainPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
using Windows.ApplicationModel;
using Windows.ApplicationModel.DataTransfer;
using Windows.Foundation.Metadata;
using Windows.Graphics;
using Windows.Services.Store;
using WinRT.Interop;
using VirtualKey = Windows.System.VirtualKey;
Expand Down Expand Up @@ -121,7 +122,7 @@ private async Task AppRunningAsAdminPromptAsync()
// WINUI3
private ContentDialog SetContentDialogRoot(ContentDialog contentDialog)
{
if (Windows.Foundation.Metadata.ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
if (ApiInformation.IsApiContractPresent("Windows.Foundation.UniversalApiContract", 8))
contentDialog.XamlRoot = MainWindow.Instance.Content.XamlRoot;

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

private void HorizontalMultitaskingControl_Loaded(object sender, RoutedEventArgs e)
{
TabControl.DragArea.SizeChanged += (_, _) => SetRectDragRegion();

if (ViewModel.MultitaskingControl is not UserControls.TabBar.TabBar)
TabControl.DragArea.SizeChanged += (_, _) => MainWindow.Instance.RaiseSetTitleBarDragRegion(SetTitleBarDragRegion);
if (ViewModel.MultitaskingControl is not TabBar)
{
ViewModel.MultitaskingControl = TabControl;
ViewModel.MultitaskingControls.Add(TabControl);
ViewModel.MultitaskingControl.CurrentInstanceChanged += MultitaskingControl_CurrentInstanceChanged;
}
}

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

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

private void Page_Loaded(object sender, RoutedEventArgs e)
{
MainWindow.Instance.AppWindow.Changed += (_, _) => MainWindow.Instance.RaiseSetTitleBarDragRegion(SetTitleBarDragRegion);

// Defers the status bar loading until after the page has loaded to improve startup perf
FindName(nameof(StatusBarControl));
FindName(nameof(InnerNavigationToolbar));
Expand Down
4 changes: 2 additions & 2 deletions src/Files.App/Views/Properties/CustomizationPage.xaml.cs
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,10 @@ protected override void OnNavigatedTo(NavigationEventArgs e)

base.OnNavigatedTo(e);

CustomizationViewModel = new(AppInstance, BaseProperties, parameter.AppWindow);
CustomizationViewModel = new(AppInstance, BaseProperties, parameter.Window.AppWindow);
}

public async override Task<bool> SaveChangesAsync()
public override async Task<bool> SaveChangesAsync()
=> await CustomizationViewModel.UpdateIcon();

public override void Dispose()
Expand Down
Loading

0 comments on commit 962f2cc

Please sign in to comment.