1
1
// Copyright (c) 2023 Files Community
2
2
// Licensed under the MIT License. See the LICENSE.
3
3
4
- using System ;
5
- using System . Collections . Generic ;
6
- using System . Linq ;
7
4
using Windows . Graphics ;
8
- using Microsoft . UI ;
9
- using Microsoft . UI . Windowing ;
5
+ using Microsoft . UI . Input ;
10
6
using Microsoft . UI . Xaml ;
11
- using WinRT . Interop ;
12
7
13
8
namespace Files . App . Helpers
14
9
{
15
10
public static class DragZoneHelper
16
11
{
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 ) ;
23
13
24
14
/// <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
27
17
/// </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 )
34
22
{
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 )
101
34
{
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 ) ) ] ) ;
109
40
}
110
-
111
- return rects ;
112
41
}
113
42
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 )
122
44
{
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 )
156
46
{
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 ) ;
159
56
}
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 } ;
164
57
}
165
-
166
- public static IEnumerable < Range > operator - ( IEnumerable < Range > minuends , Range subtrahend )
167
- => minuends . SelectMany ( minuend => minuend - subtrahend ) ;
168
58
}
169
59
}
0 commit comments