Bring back HasFlagsFast

.NET version performs poorly on debug.
This commit is contained in:
Dean Herbert
2024-08-19 19:40:59 +09:00
parent 69fcbfe846
commit b4ed7217c1
43 changed files with 263 additions and 136 deletions

View File

@@ -2,6 +2,7 @@ M:System.Object.Equals(System.Object,System.Object)~System.Boolean;Don't use obj
M:System.Object.Equals(System.Object)~System.Boolean;Don't use object.Equals. Use IEquatable<T> or EqualityComparer<T>.Default instead.
M:System.ValueType.Equals(System.Object)~System.Boolean;Don't use object.Equals(Fallbacks to ValueType). Use IEquatable<T> or EqualityComparer<T>.Default instead.
T:System.IComparable;Don't use non-generic IComparable. Use generic version instead.
M:System.Enum.HasFlag(System.Enum);Use osu.Framework.Extensions.EnumExtensions.HasFlagFast<T>() instead.
F:System.UriKind.RelativeOrAbsolute;Incompatible results when run on mono (see https://www.mono-project.com/docs/faq/known-issues/urikind-relativeorabsolute/). Use Validation.TryParseUri(string, out Uri?) instead.
M:System.Threading.Tasks.Task.Wait();Don't use Task.Wait. Use Task.WaitSafely() to ensure we avoid deadlocks.
M:System.Guid.#ctor;Probably meaning to use Guid.NewGuid() instead. If actually wanting empty, use Guid.Empty.

View File

@@ -0,0 +1,42 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using BenchmarkDotNet.Attributes;
using osu.Framework.Extensions.EnumExtensions;
namespace osu.Framework.Benchmarks
{
[MemoryDiagnoser]
public class BenchmarkEnum
{
[Benchmark]
public bool HasFlag()
{
#pragma warning disable RS0030 // (banned API)
return (FlagsEnum.Flag2 | FlagsEnum.Flag3).HasFlag(FlagsEnum.Flag2);
#pragma warning restore RS0030
}
[Benchmark]
public bool BitwiseAnd()
{
return ((FlagsEnum.Flag2 | FlagsEnum.Flag3) & FlagsEnum.Flag2) > 0;
}
[Benchmark]
public bool HasFlagFast()
{
return (FlagsEnum.Flag2 | FlagsEnum.Flag3).HasFlagFast(FlagsEnum.Flag2);
}
[Flags]
private enum FlagsEnum
{
Flag1 = 1,
Flag2 = 2,
Flag3 = 4,
Flag4 = 8
}
}
}

View File

@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -50,10 +51,10 @@ namespace osu.Framework.Tests.Visual.Containers
private void addBoxAssert(OverrideTestContainer container)
{
bool leftOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlag(Edges.Left);
bool topOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlag(Edges.Top);
bool rightOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlag(Edges.Right);
bool bottomOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlag(Edges.Bottom);
bool leftOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlagFast(Edges.Left);
bool topOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlagFast(Edges.Top);
bool rightOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlagFast(Edges.Right);
bool bottomOverridden = container.SafeAreaContainer.SafeAreaOverrideEdges.HasFlagFast(Edges.Bottom);
AddAssert($"\"{container.Name}\" overrides correctly", () =>
leftOverridden == container.SafeAreaContainer.Padding.Left < 0

View File

@@ -4,6 +4,7 @@
#nullable disable
using NUnit.Framework;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
@@ -84,7 +85,7 @@ namespace osu.Framework.Tests.Visual.Drawables
Anchor = anchor,
Origin = anchor,
Size = new Vector2(10),
Position = new Vector2(anchor.HasFlag(Anchor.x0) ? -5 : 5, anchor.HasFlag(Anchor.y0) ? -5 : 5),
Position = new Vector2(anchor.HasFlagFast(Anchor.x0) ? -5 : 5, anchor.HasFlagFast(Anchor.y0) ? -5 : 5),
}
};
});
@@ -117,7 +118,7 @@ namespace osu.Framework.Tests.Visual.Drawables
Anchor = anchor,
Origin = anchor,
Size = new Vector2(10),
Position = new Vector2(anchor.HasFlag(Anchor.x0) ? -20 : 20, anchor.HasFlag(Anchor.y0) ? -20 : 20),
Position = new Vector2(anchor.HasFlagFast(Anchor.x0) ? -20 : 20, anchor.HasFlagFast(Anchor.y0) ? -20 : 20),
}
};
});

View File

@@ -6,6 +6,7 @@
using System;
using System.Linq;
using NUnit.Framework;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@@ -199,14 +200,14 @@ namespace osu.Framework.Tests.Visual.UserInterface
{
box.Anchor = anchor;
if (anchor.HasFlag(Anchor.x0))
if (anchor.HasFlagFast(Anchor.x0))
box.X -= contextMenuContainer.CurrentMenu.DrawWidth + 10;
else if (anchor.HasFlag(Anchor.x2))
else if (anchor.HasFlagFast(Anchor.x2))
box.X += 10;
if (anchor.HasFlag(Anchor.y0))
if (anchor.HasFlagFast(Anchor.y0))
box.Y -= contextMenuContainer.CurrentMenu.DrawHeight + 10;
else if (anchor.HasFlag(Anchor.y2))
else if (anchor.HasFlagFast(Anchor.y2))
box.Y += 10;
});

View File

@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Runtime.InteropServices;
using ManagedBass;
using ManagedBass.Mix;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Statistics;
namespace osu.Framework.Audio.Mixing.Bass
@@ -158,7 +159,7 @@ namespace osu.Framework.Audio.Mixing.Bass
// The channel is always in a playing state unless stopped or stalled as it's a decoding channel. Retrieve the true playing state from the mixer channel.
if (state == PlaybackState.Playing)
state = BassMix.ChannelFlags(channel.Handle, BassFlags.Default, BassFlags.Default).HasFlag(BassFlags.MixerChanPause) ? PlaybackState.Paused : state;
state = BassMix.ChannelFlags(channel.Handle, BassFlags.Default, BassFlags.Default).HasFlagFast(BassFlags.MixerChanPause) ? PlaybackState.Paused : state;
return state;
}

View File

@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osuTK;
@@ -21,9 +22,9 @@ namespace osu.Framework.Extensions
if (anchor == Anchor.Custom)
throw new ArgumentException($"{nameof(Anchor.Custom)} is not supported.", nameof(anchor));
if (anchor.HasFlag(Anchor.x0) || anchor.HasFlag(Anchor.x2))
if (anchor.HasFlagFast(Anchor.x0) || anchor.HasFlagFast(Anchor.x2))
anchor ^= Anchor.x0 | Anchor.x2;
if (anchor.HasFlag(Anchor.y0) || anchor.HasFlag(Anchor.y2))
if (anchor.HasFlagFast(Anchor.y0) || anchor.HasFlagFast(Anchor.y2))
anchor ^= Anchor.y0 | Anchor.y2;
return anchor;
@@ -39,18 +40,18 @@ namespace osu.Framework.Extensions
Vector2 position = new Vector2();
if (anchor.HasFlag(Anchor.x0))
if (anchor.HasFlagFast(Anchor.x0))
position.X = quad.TopLeft.X;
else if (anchor.HasFlag(Anchor.x1))
else if (anchor.HasFlagFast(Anchor.x1))
position.X = quad.Centre.X;
else if (anchor.HasFlag(Anchor.x2))
else if (anchor.HasFlagFast(Anchor.x2))
position.X = quad.BottomRight.X;
if (anchor.HasFlag(Anchor.y0))
if (anchor.HasFlagFast(Anchor.y0))
position.Y = quad.TopLeft.Y;
else if (anchor.HasFlag(Anchor.y1))
else if (anchor.HasFlagFast(Anchor.y1))
position.Y = quad.Centre.Y;
else if (anchor.HasFlag(Anchor.y2))
else if (anchor.HasFlagFast(Anchor.y2))
position.Y = quad.BottomRight.Y;
return position;

View File

@@ -6,6 +6,7 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.CompilerServices;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Utils;
@@ -54,5 +55,48 @@ namespace osu.Framework.Extensions.EnumExtensions
throw new ArgumentException($"Not all values of {typeof(T)} have {nameof(OrderAttribute)} specified.");
});
}
#pragma warning disable RS0030 // (banned API)
/// <summary>
/// A fast alternative functionally equivalent to <see cref="Enum.HasFlag"/>, eliminating boxing in all scenarios.
/// </summary>
/// <param name="enumValue">The enum to check.</param>
/// <param name="flag">The flag to check for.</param>
#pragma warning restore RS0030
[MethodImpl(MethodImplOptions.AggressiveInlining)]
public static unsafe bool HasFlagFast<T>(this T enumValue, T flag) where T : unmanaged, Enum
{
// Note: Using a switch statement would eliminate inlining.
if (sizeof(T) == 1)
{
byte value1 = Unsafe.As<T, byte>(ref enumValue);
byte value2 = Unsafe.As<T, byte>(ref flag);
return (value1 & value2) == value2;
}
if (sizeof(T) == 2)
{
short value1 = Unsafe.As<T, short>(ref enumValue);
short value2 = Unsafe.As<T, short>(ref flag);
return (value1 & value2) == value2;
}
if (sizeof(T) == 4)
{
int value1 = Unsafe.As<T, int>(ref enumValue);
int value2 = Unsafe.As<T, int>(ref flag);
return (value1 & value2) == value2;
}
if (sizeof(T) == 8)
{
long value1 = Unsafe.As<T, long>(ref enumValue);
long value2 = Unsafe.As<T, long>(ref flag);
return (value1 & value2) == value2;
}
throw new ArgumentException($"Invalid enum type provided: {typeof(T)}.");
}
}
}

View File

@@ -4,6 +4,7 @@
using System;
using System.Threading;
using System.Threading.Tasks;
using osu.Framework.Extensions.EnumExtensions;
namespace osu.Framework.Extensions
{
@@ -42,7 +43,7 @@ namespace osu.Framework.Extensions
private static bool isWaitingValid(Task task)
{
// In the case the task has been started with the LongRunning flag, it will not be in the TPL thread pool and we can allow waiting regardless.
if (task.CreationOptions.HasFlag(TaskCreationOptions.LongRunning))
if (task.CreationOptions.HasFlagFast(TaskCreationOptions.LongRunning))
return true;
// Otherwise only allow waiting from a non-TPL thread pool thread.

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections;
using System.Collections.Generic;
using osu.Framework.Audio;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Audio;
using osu.Framework.Graphics.Effects;
using osuTK;
@@ -40,8 +41,8 @@ namespace osu.Framework.Graphics.Containers
set
{
base.Size = new Vector2(
RelativeSizeAxes.HasFlag(Axes.X) ? 1 : value.X,
RelativeSizeAxes.HasFlag(Axes.Y) ? 1 : value.Y);
RelativeSizeAxes.HasFlagFast(Axes.X) ? 1 : value.X,
RelativeSizeAxes.HasFlagFast(Axes.Y) ? 1 : value.Y);
container.Size = value;
}

View File

@@ -23,6 +23,7 @@ using osu.Framework.Statistics;
using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework.Development;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.ExceptionExtensions;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Primitives;
@@ -722,9 +723,9 @@ namespace osu.Framework.Graphics.Containers
{
var state = checkChildLife(internalChildren[i]);
anyAliveChanged |= state.HasFlag(ChildLifeStateChange.MadeAlive) || state.HasFlag(ChildLifeStateChange.MadeDead);
anyAliveChanged |= state.HasFlagFast(ChildLifeStateChange.MadeAlive) || state.HasFlagFast(ChildLifeStateChange.MadeDead);
if (state.HasFlag(ChildLifeStateChange.Removed))
if (state.HasFlagFast(ChildLifeStateChange.Removed))
i--;
}
@@ -1839,7 +1840,7 @@ namespace osu.Framework.Graphics.Containers
{
get
{
if (!isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlag(Axes.X))
if (!isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlagFast(Axes.X))
updateChildrenSizeDependencies();
return base.Width;
}
@@ -1857,7 +1858,7 @@ namespace osu.Framework.Graphics.Containers
{
get
{
if (!isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlag(Axes.Y))
if (!isComputingChildrenSizeDependencies && AutoSizeAxes.HasFlagFast(Axes.Y))
updateChildrenSizeDependencies();
return base.Height;
}
@@ -1913,16 +1914,16 @@ namespace osu.Framework.Graphics.Containers
Vector2 cBound = c.RequiredParentSizeToFit;
if (!c.BypassAutoSizeAxes.HasFlag(Axes.X))
if (!c.BypassAutoSizeAxes.HasFlagFast(Axes.X))
maxBoundSize.X = Math.Max(maxBoundSize.X, cBound.X);
if (!c.BypassAutoSizeAxes.HasFlag(Axes.Y))
if (!c.BypassAutoSizeAxes.HasFlagFast(Axes.Y))
maxBoundSize.Y = Math.Max(maxBoundSize.Y, cBound.Y);
}
if (!AutoSizeAxes.HasFlag(Axes.X))
if (!AutoSizeAxes.HasFlagFast(Axes.X))
maxBoundSize.X = DrawSize.X;
if (!AutoSizeAxes.HasFlag(Axes.Y))
if (!AutoSizeAxes.HasFlagFast(Axes.Y))
maxBoundSize.Y = DrawSize.Y;
return new Vector2(maxBoundSize.X, maxBoundSize.Y);
@@ -1942,8 +1943,8 @@ namespace osu.Framework.Graphics.Containers
Vector2 b = computeAutoSize() + Padding.Total;
autoSizeResizeTo(new Vector2(
AutoSizeAxes.HasFlag(Axes.X) ? b.X : base.Width,
AutoSizeAxes.HasFlag(Axes.Y) ? b.Y : base.Height
AutoSizeAxes.HasFlagFast(Axes.X) ? b.X : base.Width,
AutoSizeAxes.HasFlagFast(Axes.Y) ? b.Y : base.Height
), AutoSizeDuration, AutoSizeEasing);
//note that this is called before autoSize becomes valid. may be something to consider down the line.

View File

@@ -4,6 +4,7 @@
using osuTK;
using System;
using System.Collections.Generic;
using osu.Framework.Extensions.EnumExtensions;
namespace osu.Framework.Graphics.Containers
{
@@ -41,13 +42,13 @@ namespace osu.Framework.Graphics.Containers
// For anchor/origin positioning to be preserved correctly,
// relatively sized axes must be lifted to the wrapping container.
if (container.RelativeSizeAxes.HasFlag(Axes.X))
if (container.RelativeSizeAxes.HasFlagFast(Axes.X))
{
container.Width = drawable.Width;
drawable.Width = 1;
}
if (container.RelativeSizeAxes.HasFlag(Axes.Y))
if (container.RelativeSizeAxes.HasFlagFast(Axes.Y))
{
container.Height = drawable.Height;
drawable.Height = 1;

View File

@@ -5,6 +5,7 @@ using System;
using System.Buffers;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Utils;
using osuTK;
@@ -88,9 +89,9 @@ namespace osu.Framework.Graphics.Containers
private Vector2 spacingFactor(Drawable c)
{
Vector2 result = c.RelativeOriginPosition;
if (c.Anchor.HasFlag(Anchor.x2))
if (c.Anchor.HasFlagFast(Anchor.x2))
result.X = 1 - result.X;
if (c.Anchor.HasFlag(Anchor.y2))
if (c.Anchor.HasFlagFast(Anchor.y2))
result.Y = 1 - result.Y;
return result;
}
@@ -105,8 +106,8 @@ namespace osu.Framework.Graphics.Containers
// If we are autosize and haven't specified a maximum size, we should allow infinite expansion.
// If we are inheriting then we need to use the parent size (our ActualSize).
max.X = AutoSizeAxes.HasFlag(Axes.X) ? float.MaxValue : s.X;
max.Y = AutoSizeAxes.HasFlag(Axes.Y) ? float.MaxValue : s.Y;
max.X = AutoSizeAxes.HasFlagFast(Axes.X) ? float.MaxValue : s.X;
max.Y = AutoSizeAxes.HasFlagFast(Axes.Y) ? float.MaxValue : s.Y;
}
var children = FlowingChildren.ToArray();
@@ -269,17 +270,17 @@ namespace osu.Framework.Graphics.Containers
}
var layoutPosition = layoutPositions[i];
if (c.Anchor.HasFlag(Anchor.x1))
if (c.Anchor.HasFlagFast(Anchor.x1))
// Begin flow at centre of row
layoutPosition.X += rowOffsetsToMiddle[rowIndices[i]];
else if (c.Anchor.HasFlag(Anchor.x2))
else if (c.Anchor.HasFlagFast(Anchor.x2))
// Flow right-to-left
layoutPosition.X = -layoutPosition.X;
if (c.Anchor.HasFlag(Anchor.y1))
if (c.Anchor.HasFlagFast(Anchor.y1))
// Begin flow at centre of total height
layoutPosition.Y -= height / 2;
else if (c.Anchor.HasFlag(Anchor.y2))
else if (c.Anchor.HasFlagFast(Anchor.y2))
// Flow bottom-to-top
layoutPosition.Y = -layoutPosition.Y;

View File

@@ -9,6 +9,7 @@ using System.Diagnostics;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Caching;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Layout;
using osuTK;
@@ -283,7 +284,7 @@ namespace osu.Framework.Graphics.Containers
for (int r = 0; r < cellRows; r++)
{
var cell = Content[r]?[i];
if (cell == null || cell.RelativeSizeAxes.HasFlag(axis))
if (cell == null || cell.RelativeSizeAxes.HasFlagFast(axis))
continue;
size = Math.Max(size, getCellWidth(cell));
@@ -295,7 +296,7 @@ namespace osu.Framework.Graphics.Containers
for (int c = 0; c < cellColumns; c++)
{
var cell = Content[i]?[c];
if (cell == null || cell.RelativeSizeAxes.HasFlag(axis))
if (cell == null || cell.RelativeSizeAxes.HasFlagFast(axis))
continue;
size = Math.Max(size, getCellHeight(cell));

View File

@@ -13,6 +13,7 @@ using Markdig.Syntax;
using Markdig.Syntax.Inlines;
using osu.Framework.Allocation;
using osu.Framework.Caching;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Containers.Markdown.Footnotes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Utils;
@@ -40,7 +41,7 @@ namespace osu.Framework.Graphics.Containers.Markdown
get => base.AutoSizeAxes;
set
{
if (value.HasFlag(Axes.X))
if (value.HasFlagFast(Axes.X))
throw new ArgumentException($"{nameof(MarkdownContainer)} does not support an {nameof(AutoSizeAxes)} of {value}");
base.AutoSizeAxes = value;

View File

@@ -6,6 +6,7 @@
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Layout;
using osuTK;
@@ -81,10 +82,10 @@ namespace osu.Framework.Graphics.Containers
return new MarginPadding
{
Left = SafeAreaOverrideEdges.HasFlag(Edges.Left) ? nonSafeLocalSpace.TopLeft.X : Math.Clamp(localTopLeft.X, 0, absDrawSize.X),
Right = SafeAreaOverrideEdges.HasFlag(Edges.Right) ? DrawRectangle.BottomRight.X - nonSafeLocalSpace.BottomRight.X : Math.Clamp(absDrawSize.X - localBottomRight.X, 0, absDrawSize.X),
Top = SafeAreaOverrideEdges.HasFlag(Edges.Top) ? nonSafeLocalSpace.TopLeft.Y : Math.Clamp(localTopLeft.Y, 0, absDrawSize.Y),
Bottom = SafeAreaOverrideEdges.HasFlag(Edges.Bottom) ? DrawRectangle.BottomRight.Y - nonSafeLocalSpace.BottomRight.Y : Math.Clamp(absDrawSize.Y - localBottomRight.Y, 0, absDrawSize.Y)
Left = SafeAreaOverrideEdges.HasFlagFast(Edges.Left) ? nonSafeLocalSpace.TopLeft.X : Math.Clamp(localTopLeft.X, 0, absDrawSize.X),
Right = SafeAreaOverrideEdges.HasFlagFast(Edges.Right) ? DrawRectangle.BottomRight.X - nonSafeLocalSpace.BottomRight.X : Math.Clamp(absDrawSize.X - localBottomRight.X, 0, absDrawSize.X),
Top = SafeAreaOverrideEdges.HasFlagFast(Edges.Top) ? nonSafeLocalSpace.TopLeft.Y : Math.Clamp(localTopLeft.Y, 0, absDrawSize.Y),
Bottom = SafeAreaOverrideEdges.HasFlagFast(Edges.Bottom) ? DrawRectangle.BottomRight.Y - nonSafeLocalSpace.BottomRight.Y : Math.Clamp(absDrawSize.Y - localBottomRight.Y, 0, absDrawSize.Y)
};
}
}

View File

@@ -10,6 +10,7 @@ using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Localisation;
@@ -206,7 +207,7 @@ namespace osu.Framework.Graphics.Containers
{
// FillFlowContainer will reverse the ordering of right-anchored words such that the (previously) first word would be
// the right-most word, whereas it should still be flowed left-to-right. This is achieved by reversing the comparator.
if (TextAnchor.HasFlag(Anchor.x2))
if (TextAnchor.HasFlagFast(Anchor.x2))
return base.Compare(y, x);
return base.Compare(x, y);

View File

@@ -3,6 +3,7 @@
using System;
using osu.Framework.Extensions;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.UserInterface;
@@ -156,18 +157,18 @@ namespace osu.Framework.Graphics.Cursor
// left anchor = area to the left of the quad, right anchor = area to the right of the quad.
// for horizontal centre assume we have the whole quad width to work with.
if (anchor.HasFlag(Anchor.x0))
if (anchor.HasFlagFast(Anchor.x0))
availableSize.X = MathF.Max(0, targetLocalQuad.TopLeft.X);
else if (anchor.HasFlag(Anchor.x2))
else if (anchor.HasFlagFast(Anchor.x2))
availableSize.X = MathF.Max(0, DrawWidth - targetLocalQuad.BottomRight.X);
else
availableSize.X = DrawWidth;
// top anchor = area above quad, bottom anchor = area below quad.
// for vertical centre assume we have the whole quad height to work with.
if (anchor.HasFlag(Anchor.y0))
if (anchor.HasFlagFast(Anchor.y0))
availableSize.Y = MathF.Max(0, targetLocalQuad.TopLeft.Y);
else if (anchor.HasFlag(Anchor.y2))
else if (anchor.HasFlagFast(Anchor.y2))
availableSize.Y = MathF.Max(0, DrawHeight - targetLocalQuad.BottomRight.Y);
else
availableSize.Y = DrawHeight;

View File

@@ -28,6 +28,7 @@ using System.Threading;
using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Development;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Input.Events;
using osu.Framework.Input.States;
@@ -682,10 +683,10 @@ namespace osu.Framework.Graphics
{
offset = Parent.RelativeChildOffset;
if (!RelativePositionAxes.HasFlag(Axes.X))
if (!RelativePositionAxes.HasFlagFast(Axes.X))
offset.X = 0;
if (!RelativePositionAxes.HasFlag(Axes.Y))
if (!RelativePositionAxes.HasFlagFast(Axes.Y))
offset.Y = 0;
}
@@ -811,8 +812,8 @@ namespace osu.Framework.Graphics
relativeSizeAxes = value;
if (relativeSizeAxes.HasFlag(Axes.X) && Width == 0) Width = 1;
if (relativeSizeAxes.HasFlag(Axes.Y) && Height == 0) Height = 1;
if (relativeSizeAxes.HasFlagFast(Axes.X) && Width == 0) Width = 1;
if (relativeSizeAxes.HasFlagFast(Axes.Y) && Height == 0) Height = 1;
updateBypassAutoSizeAxes();
@@ -906,9 +907,9 @@ namespace osu.Framework.Graphics
{
Vector2 conversion = relativeToAbsoluteFactor;
if (relativeAxes.HasFlag(Axes.X))
if (relativeAxes.HasFlagFast(Axes.X))
v.X *= conversion.X;
if (relativeAxes.HasFlag(Axes.Y))
if (relativeAxes.HasFlagFast(Axes.Y))
v.Y *= conversion.Y;
// FillMode only makes sense if both axes are relatively sized as the general rule
@@ -1136,14 +1137,14 @@ namespace osu.Framework.Graphics
throw new InvalidOperationException(@"Can not obtain relative origin position for custom origins.");
Vector2 result = Vector2.Zero;
if (origin.HasFlag(Anchor.x1))
if (origin.HasFlagFast(Anchor.x1))
result.X = 0.5f;
else if (origin.HasFlag(Anchor.x2))
else if (origin.HasFlagFast(Anchor.x2))
result.X = 1;
if (origin.HasFlag(Anchor.y1))
if (origin.HasFlagFast(Anchor.y1))
result.Y = 0.5f;
else if (origin.HasFlag(Anchor.y2))
else if (origin.HasFlagFast(Anchor.y2))
result.Y = 1;
return result;
@@ -1224,14 +1225,14 @@ namespace osu.Framework.Graphics
return customRelativeAnchorPosition;
Vector2 result = Vector2.Zero;
if (anchor.HasFlag(Anchor.x1))
if (anchor.HasFlagFast(Anchor.x1))
result.X = 0.5f;
else if (anchor.HasFlag(Anchor.x2))
else if (anchor.HasFlagFast(Anchor.x2))
result.X = 1;
if (anchor.HasFlag(Anchor.y1))
if (anchor.HasFlagFast(Anchor.y1))
result.Y = 0.5f;
else if (anchor.HasFlag(Anchor.y2))
else if (anchor.HasFlagFast(Anchor.y2))
result.Y = 1;
return result;
@@ -1269,14 +1270,14 @@ namespace osu.Framework.Graphics
{
Vector2 result = Vector2.Zero;
if (anchor.HasFlag(Anchor.x1))
if (anchor.HasFlagFast(Anchor.x1))
result.X = size.X / 2f;
else if (anchor.HasFlag(Anchor.x2))
else if (anchor.HasFlagFast(Anchor.x2))
result.X = size.X;
if (anchor.HasFlag(Anchor.y1))
if (anchor.HasFlagFast(Anchor.y1))
result.Y = size.Y / 2f;
else if (anchor.HasFlag(Anchor.y2))
else if (anchor.HasFlagFast(Anchor.y2))
result.Y = size.Y;
return result;

View File

@@ -11,6 +11,7 @@ using osu.Framework.Graphics.Shaders;
using osu.Framework.Allocation;
using System.Collections.Generic;
using osu.Framework.Caching;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Layout;
using osuTK.Graphics;
@@ -117,7 +118,7 @@ namespace osu.Framework.Graphics.Lines
{
get
{
if (AutoSizeAxes.HasFlag(Axes.X))
if (AutoSizeAxes.HasFlagFast(Axes.X))
return base.Width = vertexBounds.Width;
return base.Width;
@@ -135,7 +136,7 @@ namespace osu.Framework.Graphics.Lines
{
get
{
if (AutoSizeAxes.HasFlag(Axes.Y))
if (AutoSizeAxes.HasFlagFast(Axes.Y))
return base.Height = vertexBounds.Height;
return base.Height;

View File

@@ -6,6 +6,7 @@ using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.OpenGL.Buffers;
using osu.Framework.Graphics.OpenGL.Textures;
using osu.Framework.Graphics.OpenGL.Batches;
@@ -324,10 +325,10 @@ namespace osu.Framework.Graphics.OpenGL
protected override void SetBlendMaskImplementation(BlendingMask blendingMask)
{
GL.ColorMask(blendingMask.HasFlag(BlendingMask.Red),
blendingMask.HasFlag(BlendingMask.Green),
blendingMask.HasFlag(BlendingMask.Blue),
blendingMask.HasFlag(BlendingMask.Alpha));
GL.ColorMask(blendingMask.HasFlagFast(BlendingMask.Red),
blendingMask.HasFlagFast(BlendingMask.Green),
blendingMask.HasFlagFast(BlendingMask.Blue),
blendingMask.HasFlagFast(BlendingMask.Alpha));
}
protected override void SetViewportImplementation(RectangleI viewport) => GL.Viewport(viewport.Left, viewport.Top, viewport.Width, viewport.Height);

View File

@@ -2,6 +2,7 @@
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Layout;
@@ -117,7 +118,7 @@ namespace osu.Framework.Graphics.Pooling
protected override bool OnInvalidate(Invalidation invalidation, InvalidationSource source)
{
if (source != InvalidationSource.Child && invalidation.HasFlag(Invalidation.Parent))
if (source != InvalidationSource.Child && invalidation.HasFlagFast(Invalidation.Parent))
{
if (IsInUse && Parent == null)
Return();

View File

@@ -3,6 +3,7 @@
using System;
using System.IO;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Visualisation;
@@ -95,8 +96,8 @@ namespace osu.Framework.Graphics.Textures
if (relativeSizeAxes != Axes.None)
{
Vector2 scale = new Vector2(
relativeSizeAxes.HasFlag(Axes.X) ? Width : 1,
relativeSizeAxes.HasFlag(Axes.Y) ? Height : 1
relativeSizeAxes.HasFlagFast(Axes.X) ? Width : 1,
relativeSizeAxes.HasFlagFast(Axes.Y) ? Height : 1
);
cropRectangle *= scale;
}

View File

@@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Shapes;
using osuTK;
@@ -24,7 +25,7 @@ namespace osu.Framework.Graphics.UserInterface
{
base.AnchorUpdated(anchor);
bool isCenteredAnchor = anchor.HasFlag(Anchor.x1) || anchor.HasFlag(Anchor.y1);
bool isCenteredAnchor = anchor.HasFlagFast(Anchor.x1) || anchor.HasFlagFast(Anchor.y1);
Body.Margin = new MarginPadding(isCenteredAnchor ? 10 : 3);
Arrow.Size = new Vector2(isCenteredAnchor ? 12 : 15);
}

View File

@@ -9,6 +9,7 @@ using System.IO;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Platform;
using osuTK;
@@ -205,7 +206,7 @@ namespace osu.Framework.Graphics.UserInterface
{
foreach (var dir in path.GetDirectories().OrderBy(d => d.Name))
{
if (ShowHiddenItems.Value || !dir.Attributes.HasFlag(FileAttributes.Hidden))
if (ShowHiddenItems.Value || !dir.Attributes.HasFlagFast(FileAttributes.Hidden))
items.Add(CreateDirectoryItem(dir));
}

View File

@@ -8,6 +8,7 @@ using System.IO;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Input.Events;
using osu.Framework.Extensions.EnumExtensions;
namespace osu.Framework.Graphics.UserInterface
{
@@ -26,7 +27,7 @@ namespace osu.Framework.Graphics.UserInterface
try
{
bool isHidden = directory?.Attributes.HasFlag(FileAttributes.Hidden) == true;
bool isHidden = directory?.Attributes.HasFlagFast(FileAttributes.Hidden) == true;
// On Windows, system drives are returned with `System | Hidden | Directory` file attributes,
// but the expectation is that they shouldn't be shown in a hidden state.

View File

@@ -9,6 +9,7 @@ using System.IO;
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Input.Events;
namespace osu.Framework.Graphics.UserInterface
@@ -48,7 +49,7 @@ namespace osu.Framework.Graphics.UserInterface
foreach (var file in files.OrderBy(d => d.Name))
{
if (ShowHiddenItems.Value || !file.Attributes.HasFlag(FileAttributes.Hidden))
if (ShowHiddenItems.Value || !file.Attributes.HasFlagFast(FileAttributes.Hidden))
items.Add(CreateFileItem(file));
}
@@ -73,7 +74,7 @@ namespace osu.Framework.Graphics.UserInterface
try
{
if (File?.Attributes.HasFlag(FileAttributes.Hidden) == true)
if (File?.Attributes.HasFlagFast(FileAttributes.Hidden) == true)
ApplyHiddenState();
}
catch (UnauthorizedAccessException)

View File

@@ -7,6 +7,7 @@ using System;
using System.Collections.Generic;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osuTK.Graphics;
@@ -497,8 +498,8 @@ namespace osu.Framework.Graphics.UserInterface
height = Math.Min(MaxHeight, height);
// Regardless of the above result, if we are relative-sizing, just use the stored width/height
width = RelativeSizeAxes.HasFlag(Axes.X) ? Width : width;
height = RelativeSizeAxes.HasFlag(Axes.Y) ? Height : height;
width = RelativeSizeAxes.HasFlagFast(Axes.X) ? Width : width;
height = RelativeSizeAxes.HasFlagFast(Axes.Y) ? Height : height;
if (State == MenuState.Closed && Direction == Direction.Horizontal)
width = 0;

View File

@@ -4,6 +4,7 @@
using System;
using System.Collections.Generic;
using osu.Framework.Extensions;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Primitives;
@@ -191,7 +192,7 @@ namespace osu.Framework.Graphics.UserInterface
get => Body.Width;
set
{
if (Body.AutoSizeAxes.HasFlag(Axes.X))
if (Body.AutoSizeAxes.HasFlagFast(Axes.X))
Body.AutoSizeAxes &= ~Axes.X;
Body.Width = value;
@@ -203,7 +204,7 @@ namespace osu.Framework.Graphics.UserInterface
get => Body.Height;
set
{
if (Body.AutoSizeAxes.HasFlag(Axes.Y))
if (Body.AutoSizeAxes.HasFlagFast(Axes.Y))
Body.AutoSizeAxes &= ~Axes.Y;
Body.Height = value;

View File

@@ -9,6 +9,7 @@ using System.Diagnostics;
using System.Linq;
using JetBrains.Annotations;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Containers;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
@@ -171,8 +172,8 @@ namespace osu.Framework.Graphics.UserInterface
AddInternal(Dropdown);
Trace.Assert(Dropdown.Header.Anchor.HasFlag(Anchor.x2), $@"The {nameof(Dropdown)} implementation should use a right-based anchor inside a TabControl.");
Trace.Assert(!Dropdown.Header.RelativeSizeAxes.HasFlag(Axes.X), $@"The {nameof(Dropdown)} implementation's header should have a specific size.");
Trace.Assert(Dropdown.Header.Anchor.HasFlagFast(Anchor.x2), $@"The {nameof(Dropdown)} implementation should use a right-based anchor inside a TabControl.");
Trace.Assert(!Dropdown.Header.RelativeSizeAxes.HasFlagFast(Axes.X), $@"The {nameof(Dropdown)} implementation's header should have a specific size.");
}
AddInternal(TabContainer = CreateTabFlow());

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Runtime.InteropServices;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Graphics.Textures;
@@ -105,10 +106,10 @@ namespace osu.Framework.Graphics.Veldrid
{
ColorWriteMask writeMask = ColorWriteMask.None;
if (mask.HasFlag(BlendingMask.Red)) writeMask |= ColorWriteMask.Red;
if (mask.HasFlag(BlendingMask.Green)) writeMask |= ColorWriteMask.Green;
if (mask.HasFlag(BlendingMask.Blue)) writeMask |= ColorWriteMask.Blue;
if (mask.HasFlag(BlendingMask.Alpha)) writeMask |= ColorWriteMask.Alpha;
if (mask.HasFlagFast(BlendingMask.Red)) writeMask |= ColorWriteMask.Red;
if (mask.HasFlagFast(BlendingMask.Green)) writeMask |= ColorWriteMask.Green;
if (mask.HasFlagFast(BlendingMask.Blue)) writeMask |= ColorWriteMask.Blue;
if (mask.HasFlagFast(BlendingMask.Alpha)) writeMask |= ColorWriteMask.Alpha;
return writeMask;
}

View File

@@ -18,6 +18,7 @@ using System.Threading.Tasks;
using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Rendering;
using osu.Framework.Logging;
using osu.Framework.Platform;
@@ -795,7 +796,7 @@ namespace osu.Framework.Graphics.Video
{
var hwVideoDecoder = hwDeviceType.ToHardwareVideoDecoder();
if (!hwVideoDecoder.HasValue || !targetHwDecoders.HasFlag(hwVideoDecoder.Value))
if (!hwVideoDecoder.HasValue || !targetHwDecoders.HasFlagFast(hwVideoDecoder.Value))
continue;
codecs.Add((codec, hwDeviceType));

View File

@@ -5,6 +5,7 @@
using System.Diagnostics;
using osu.Framework.Bindables;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Input.StateChanges;
using osu.Framework.Platform;
using osu.Framework.Statistics;
@@ -57,7 +58,7 @@ namespace osu.Framework.Input.Handlers.Mouse
/// <summary>
/// Whether the application should be handling the cursor.
/// </summary>
private bool cursorCaptured => isActive.Value && (window.CursorInWindow.Value || window.CursorState.HasFlag(CursorState.Confined));
private bool cursorCaptured => isActive.Value && (window.CursorInWindow.Value || window.CursorState.HasFlagFast(CursorState.Confined));
/// <summary>
/// Whether the last position (as reported by <see cref="FeedbackMousePositionChange"/>)
@@ -163,7 +164,7 @@ namespace osu.Framework.Input.Handlers.Mouse
// handle the case where relative / raw input is active, but the cursor may have exited the window
// bounds and is not intended to be confined.
if (!window.CursorState.HasFlag(CursorState.Confined) && positionOutsideWindow && !previousPositionOutsideWindow)
if (!window.CursorState.HasFlagFast(CursorState.Confined) && positionOutsideWindow && !previousPositionOutsideWindow)
{
// setting relative mode to false will allow the window manager to take control until the next
// updateRelativeMode() call succeeds (likely from the cursor returning inside the window).
@@ -193,7 +194,7 @@ namespace osu.Framework.Input.Handlers.Mouse
// relative mode only works when the window is active and the cursor is contained. aka the OS cursor isn't being displayed outside the window.
&& cursorCaptured
// relative mode shouldn't ever be enabled if the framework or a consumer has chosen not to hide the cursor.
&& window.CursorState.HasFlag(CursorState.Hidden);
&& window.CursorState.HasFlagFast(CursorState.Hidden);
if (!window.RelativeMouseMode)
transferLastPositionToHostCursor();

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.ObjectExtensions;
using osu.Framework.Graphics;
using osu.Framework.Input.Events;
@@ -217,7 +218,7 @@ namespace osu.Framework.Input
private void draggedDrawableInvalidated(Drawable drawable, Invalidation invalidation)
{
if (invalidation.HasFlag(Invalidation.Parent))
if (invalidation.HasFlagFast(Invalidation.Parent))
{
// end drag if no longer rooted.
if (!drawable.IsRootedAt(InputManager))

View File

@@ -5,6 +5,7 @@ using System;
using System.Collections.Immutable;
using System.Drawing;
using osu.Framework.Configuration;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Input.Handlers;
using osu.Framework.Input.StateChanges;
using osu.Framework.Input.StateChanges.Events;
@@ -44,7 +45,7 @@ namespace osu.Framework.Input
var clientSize = Host.Window.ClientSize;
var windowRect = new RectangleF(0, 0, clientSize.Width, clientSize.Height);
if (Host.Window.CursorState.HasFlag(CursorState.Confined))
if (Host.Window.CursorState.HasFlagFast(CursorState.Confined))
{
cursorConfineRect = Host.Window.CursorConfineRect ?? windowRect;
}

View File

@@ -6,6 +6,7 @@
using System;
using System.Drawing;
using System.Runtime.InteropServices;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
@@ -20,7 +21,7 @@ namespace osu.Framework.Platform.SDL2
{
// Apple devices don't have the notion of NumLock (they have a Clear key instead).
// treat them as if they always have NumLock on (the numpad always performs its primary actions).
bool numLockOn = sdlKeysym.mod.HasFlag(SDL_Keymod.KMOD_NUM) || RuntimeInfo.IsApple;
bool numLockOn = sdlKeysym.mod.HasFlagFast(SDL_Keymod.KMOD_NUM) || RuntimeInfo.IsApple;
switch (sdlKeysym.scancode)
{
@@ -863,17 +864,17 @@ namespace osu.Framework.Platform.SDL2
public static WindowState ToWindowState(this SDL_WindowFlags windowFlags)
{
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP) ||
windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_BORDERLESS))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_FULLSCREEN_DESKTOP) ||
windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_BORDERLESS))
return WindowState.FullscreenBorderless;
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
return WindowState.Minimised;
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_FULLSCREEN))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_FULLSCREEN))
return WindowState.Fullscreen;
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_MAXIMIZED))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MAXIMIZED))
return WindowState.Maximised;
return WindowState.Normal;

View File

@@ -8,6 +8,7 @@ using JetBrains.Annotations;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.ImageExtensions;
using osu.Framework.Logging;
using osu.Framework.Threading;
@@ -162,7 +163,7 @@ namespace osu.Framework.Platform.SDL2
return wmInfo;
}
public bool CapsLockPressed => SDL_GetModState().HasFlag(SDL_Keymod.KMOD_CAPS);
public bool CapsLockPressed => SDL_GetModState().HasFlagFast(SDL_Keymod.KMOD_CAPS);
// references must be kept to avoid GC, see https://stackoverflow.com/a/6193914
@@ -203,7 +204,7 @@ namespace osu.Framework.Platform.SDL2
CursorStateBindable.ValueChanged += evt =>
{
updateCursorVisibility(!evt.NewValue.HasFlag(CursorState.Hidden));
updateCursorVisibility(!evt.NewValue.HasFlagFast(CursorState.Hidden));
updateCursorConfinement();
};
@@ -406,7 +407,7 @@ namespace osu.Framework.Platform.SDL2
{
var flags = (SDL_WindowFlags)SDL_GetWindowFlags(SDLWindowHandle);
if (flags.HasFlag(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
if (flags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
SDL_RestoreWindow(SDLWindowHandle);
SDL_RaiseWindow(SDLWindowHandle);

View File

@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Drawing;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Framework.Input.States;
@@ -43,7 +44,7 @@ namespace osu.Framework.Platform.SDL2
if (relativeMouseMode == value)
return;
if (value && !CursorState.HasFlag(CursorState.Hidden))
if (value && !CursorState.HasFlagFast(CursorState.Hidden))
throw new InvalidOperationException($"Cannot set {nameof(RelativeMouseMode)} to true when the cursor is not hidden via {nameof(CursorState)}.");
relativeMouseMode = value;
@@ -101,7 +102,7 @@ namespace osu.Framework.Platform.SDL2
/// </summary>
private void updateCursorConfinement()
{
bool confined = CursorState.HasFlag(CursorState.Confined);
bool confined = CursorState.HasFlagFast(CursorState.Confined);
ScheduleCommand(() => SDL_SetWindowGrab(SDLWindowHandle, confined ? SDL_bool.SDL_TRUE : SDL_bool.SDL_FALSE));
@@ -163,11 +164,11 @@ namespace osu.Framework.Platform.SDL2
// the outer if just optimises for the common case that there are no buttons to release.
if (buttonsToRelease != SDLButtonMask.None)
{
if (buttonsToRelease.HasFlag(SDLButtonMask.Left)) MouseUp?.Invoke(MouseButton.Left);
if (buttonsToRelease.HasFlag(SDLButtonMask.Middle)) MouseUp?.Invoke(MouseButton.Middle);
if (buttonsToRelease.HasFlag(SDLButtonMask.Right)) MouseUp?.Invoke(MouseButton.Right);
if (buttonsToRelease.HasFlag(SDLButtonMask.X1)) MouseUp?.Invoke(MouseButton.Button1);
if (buttonsToRelease.HasFlag(SDLButtonMask.X2)) MouseUp?.Invoke(MouseButton.Button2);
if (buttonsToRelease.HasFlagFast(SDLButtonMask.Left)) MouseUp?.Invoke(MouseButton.Left);
if (buttonsToRelease.HasFlagFast(SDLButtonMask.Middle)) MouseUp?.Invoke(MouseButton.Middle);
if (buttonsToRelease.HasFlagFast(SDLButtonMask.Right)) MouseUp?.Invoke(MouseButton.Right);
if (buttonsToRelease.HasFlagFast(SDLButtonMask.X1)) MouseUp?.Invoke(MouseButton.Button1);
if (buttonsToRelease.HasFlagFast(SDLButtonMask.X2)) MouseUp?.Invoke(MouseButton.Button2);
}
}

View File

@@ -3,6 +3,7 @@
using System.Diagnostics.CodeAnalysis;
using System.Drawing;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Framework.Input.Bindings;
@@ -18,7 +19,7 @@ namespace osu.Framework.Platform.SDL3
{
// Apple devices don't have the notion of NumLock (they have a Clear key instead).
// treat them as if they always have NumLock on (the numpad always performs its primary actions).
bool numLockOn = sdlKeyboardEvent.mod.HasFlag(SDL_Keymod.SDL_KMOD_NUM) || RuntimeInfo.IsApple;
bool numLockOn = sdlKeyboardEvent.mod.HasFlagFast(SDL_Keymod.SDL_KMOD_NUM) || RuntimeInfo.IsApple;
switch (sdlKeyboardEvent.scancode)
{
@@ -861,16 +862,16 @@ namespace osu.Framework.Platform.SDL3
public static WindowState ToWindowState(this SDL_WindowFlags windowFlags)
{
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_BORDERLESS))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_BORDERLESS))
return WindowState.FullscreenBorderless;
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
return WindowState.Minimised;
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_FULLSCREEN))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_FULLSCREEN))
return WindowState.Fullscreen;
if (windowFlags.HasFlag(SDL_WindowFlags.SDL_WINDOW_MAXIMIZED))
if (windowFlags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MAXIMIZED))
return WindowState.Maximised;
return WindowState.Normal;

View File

@@ -9,6 +9,7 @@ using System.Runtime.Versioning;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Extensions.ImageExtensions;
using osu.Framework.Logging;
using osu.Framework.Threading;
@@ -142,7 +143,7 @@ namespace osu.Framework.Platform.SDL3
[SupportedOSPlatform("android")]
public virtual IntPtr SurfaceHandle => throw new PlatformNotSupportedException();
public bool CapsLockPressed => SDL_GetModState().HasFlag(SDL_Keymod.SDL_KMOD_CAPS);
public bool CapsLockPressed => SDL_GetModState().HasFlagFast(SDL_Keymod.SDL_KMOD_CAPS);
/// <summary>
/// Represents a handle to this <see cref="SDL3Window"/> instance, used for unmanaged callbacks.
@@ -173,7 +174,7 @@ namespace osu.Framework.Platform.SDL3
CursorStateBindable.ValueChanged += evt =>
{
updateCursorVisibility(!evt.NewValue.HasFlag(CursorState.Hidden));
updateCursorVisibility(!evt.NewValue.HasFlagFast(CursorState.Hidden));
updateCursorConfinement();
};
@@ -373,7 +374,7 @@ namespace osu.Framework.Platform.SDL3
{
var flags = SDL_GetWindowFlags(SDLWindowHandle);
if (flags.HasFlag(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
if (flags.HasFlagFast(SDL_WindowFlags.SDL_WINDOW_MINIMIZED))
SDL_RestoreWindow(SDLWindowHandle);
SDL_RaiseWindow(SDLWindowHandle);

View File

@@ -7,6 +7,7 @@ using System.Diagnostics;
using System.Drawing;
using osu.Framework.Bindables;
using osu.Framework.Configuration;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Input;
using osu.Framework.Input.States;
@@ -44,7 +45,7 @@ namespace osu.Framework.Platform.SDL3
if (relativeMouseMode == value)
return;
if (value && !CursorState.HasFlag(CursorState.Hidden))
if (value && !CursorState.HasFlagFast(CursorState.Hidden))
throw new InvalidOperationException($"Cannot set {nameof(RelativeMouseMode)} to true when the cursor is not hidden via {nameof(CursorState)}.");
relativeMouseMode = value;
@@ -108,7 +109,7 @@ namespace osu.Framework.Platform.SDL3
/// </summary>
private void updateCursorConfinement()
{
bool confined = CursorState.HasFlag(CursorState.Confined);
bool confined = CursorState.HasFlagFast(CursorState.Confined);
ScheduleCommand(() => SDL_SetWindowMouseGrab(SDLWindowHandle, confined ? SDL_bool.SDL_TRUE : SDL_bool.SDL_FALSE));
@@ -174,11 +175,11 @@ namespace osu.Framework.Platform.SDL3
// the outer if just optimises for the common case that there are no buttons to release.
if (buttonsToRelease != 0)
{
if (buttonsToRelease.HasFlag(SDL_MouseButtonFlags.SDL_BUTTON_LMASK)) MouseUp?.Invoke(MouseButton.Left);
if (buttonsToRelease.HasFlag(SDL_MouseButtonFlags.SDL_BUTTON_MMASK)) MouseUp?.Invoke(MouseButton.Middle);
if (buttonsToRelease.HasFlag(SDL_MouseButtonFlags.SDL_BUTTON_RMASK)) MouseUp?.Invoke(MouseButton.Right);
if (buttonsToRelease.HasFlag(SDL_MouseButtonFlags.SDL_BUTTON_X1MASK)) MouseUp?.Invoke(MouseButton.Button1);
if (buttonsToRelease.HasFlag(SDL_MouseButtonFlags.SDL_BUTTON_X2MASK)) MouseUp?.Invoke(MouseButton.Button2);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_LMASK)) MouseUp?.Invoke(MouseButton.Left);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_MMASK)) MouseUp?.Invoke(MouseButton.Middle);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_RMASK)) MouseUp?.Invoke(MouseButton.Right);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_X1MASK)) MouseUp?.Invoke(MouseButton.Button1);
if (buttonsToRelease.HasFlagFast(SDL_MouseButtonFlags.SDL_BUTTON_X2MASK)) MouseUp?.Invoke(MouseButton.Button2);
}
}

View File

@@ -6,6 +6,7 @@ using System.Diagnostics.CodeAnalysis;
using System.Runtime.InteropServices;
using System.Text;
using Microsoft.Win32.SafeHandles;
using osu.Framework.Extensions.EnumExtensions;
namespace osu.Framework.Platform.Windows.Native
{
@@ -139,7 +140,7 @@ namespace osu.Framework.Platform.Windows.Native
{
size = -1;
if (!lParam.HasFlag(compositionString))
if (!lParam.HasFlagFast(compositionString))
return false;
size = ImmGetCompositionString(handle, compositionString, null, 0);

View File

@@ -3,6 +3,7 @@
using System;
using System.Drawing;
using osu.Framework.Extensions.EnumExtensions;
using osu.Framework.Input.StateChanges;
using osu.Framework.Platform.Windows.Native;
using osu.Framework.Statistics;
@@ -91,9 +92,9 @@ namespace osu.Framework.Platform.Windows
var position = new Vector2(mouse.LastX, mouse.LastY);
float sensitivity = (float)Sensitivity.Value;
if (mouse.Flags.HasFlag(RawMouseFlags.MoveAbsolute))
if (mouse.Flags.HasFlagFast(RawMouseFlags.MoveAbsolute))
{
var screenRect = mouse.Flags.HasFlag(RawMouseFlags.VirtualDesktop) ? Native.Input.VirtualScreenRect : new Rectangle(window.Position, window.ClientSize);
var screenRect = mouse.Flags.HasFlagFast(RawMouseFlags.VirtualDesktop) ? Native.Input.VirtualScreenRect : new Rectangle(window.Position, window.ClientSize);
Vector2 screenSize = new Vector2(screenRect.Width, screenRect.Height);