Public Access
55 lines
2.2 KiB
C#
55 lines
2.2 KiB
C#
using Avalonia;
|
|
using Avalonia.Controls;
|
|
using Avalonia.Input;
|
|
|
|
namespace DodoSSH.Client.App.Views;
|
|
|
|
/// <summary>
|
|
/// Tells a drawn titlebar's double-click from a press that starts a drag.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// <para>
|
|
/// Both titlebars used to answer a double-click through <c>DoubleTapped</c> and start a drag on every press.
|
|
/// The two do not mix: <c>BeginMoveDrag</c> hands the press to the operating system's own move loop, which
|
|
/// eats the release — and a double tap is a gesture Avalonia assembles from presses <em>and</em> releases,
|
|
/// so the second click often never completed one and the window did not maximise. The convention it was
|
|
/// imitating is one nobody thinks about until it does not work.
|
|
/// </para>
|
|
/// <para>
|
|
/// So the press decides, before the drag begins: a second press inside the platform's double-click time and
|
|
/// distance is the maximise, and does not start a drag at all. The click count is honoured where the platform
|
|
/// reports one, and the time and distance are measured here for where the move loop kept it from counting.
|
|
/// </para>
|
|
/// </remarks>
|
|
internal sealed class CaptionPresses
|
|
{
|
|
private ulong lastAt;
|
|
|
|
private Point lastWhere;
|
|
|
|
private bool waitingForASecond;
|
|
|
|
/// <summary>Whether this press is the second of a double-click on <paramref name="bar"/>.</summary>
|
|
internal bool IsSecond(PointerPressedEventArgs e, Visual bar)
|
|
{
|
|
var settings = Application.Current?.PlatformSettings;
|
|
var time = settings?.GetDoubleTapTime(e.Pointer.Type) ?? TimeSpan.FromMilliseconds(500);
|
|
var size = settings?.GetDoubleTapSize(e.Pointer.Type) ?? new Size(4, 4);
|
|
var where = e.GetPosition(bar);
|
|
|
|
var second = e.ClickCount == 2
|
|
|| (waitingForASecond
|
|
&& e.Timestamp - lastAt <= (ulong)time.TotalMilliseconds
|
|
&& Math.Abs(where.X - lastWhere.X) <= size.Width
|
|
&& Math.Abs(where.Y - lastWhere.Y) <= size.Height);
|
|
|
|
// A double-click spends both presses: a third that follows quickly starts again rather than toggling
|
|
// the window straight back.
|
|
waitingForASecond = !second;
|
|
lastAt = e.Timestamp;
|
|
lastWhere = where;
|
|
|
|
return second;
|
|
}
|
|
}
|