mirror of
https://github.com/ppy/osu.git
synced 2024-11-14 15:17:27 +08:00
Merge pull request #25743 from peppy/merge-everything-at-once
Merge everything at once
This commit is contained in:
commit
ec6200b4ad
@ -10,7 +10,7 @@
|
||||
<EmbedAssembliesIntoApk>true</EmbedAssembliesIntoApk>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.1201.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2023.1213.0" />
|
||||
</ItemGroup>
|
||||
<PropertyGroup>
|
||||
<!-- Fody does not handle Android build well, and warns when unchanged.
|
||||
|
@ -310,9 +310,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
AddStep("release left button", () => InputManager.ReleaseButton(MouseButton.Left));
|
||||
|
||||
assertPlaced(true);
|
||||
assertLength(760, tolerance: 10);
|
||||
assertLength(808, tolerance: 10);
|
||||
assertControlPointCount(5);
|
||||
assertControlPointType(0, PathType.BSpline(3));
|
||||
assertControlPointType(0, PathType.BSpline(4));
|
||||
assertControlPointType(1, null);
|
||||
assertControlPointType(2, null);
|
||||
assertControlPointType(3, null);
|
||||
@ -337,9 +337,9 @@ namespace osu.Game.Rulesets.Osu.Tests.Editor
|
||||
assertPlaced(true);
|
||||
assertLength(600, tolerance: 10);
|
||||
assertControlPointCount(4);
|
||||
assertControlPointType(0, PathType.LINEAR);
|
||||
assertControlPointType(1, null);
|
||||
assertControlPointType(2, null);
|
||||
assertControlPointType(0, PathType.BSpline(4));
|
||||
assertControlPointType(1, PathType.BSpline(4));
|
||||
assertControlPointType(2, PathType.BSpline(4));
|
||||
assertControlPointType(3, null);
|
||||
}
|
||||
|
||||
|
@ -373,7 +373,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components
|
||||
curveTypeItems.Add(createMenuItemForPathType(PathType.LINEAR));
|
||||
curveTypeItems.Add(createMenuItemForPathType(PathType.PERFECT_CURVE));
|
||||
curveTypeItems.Add(createMenuItemForPathType(PathType.BEZIER));
|
||||
curveTypeItems.Add(createMenuItemForPathType(PathType.BSpline(3)));
|
||||
curveTypeItems.Add(createMenuItemForPathType(PathType.BSpline(4)));
|
||||
|
||||
if (selectedPieces.Any(piece => piece.ControlPoint.Type?.Type == SplineType.Catmull))
|
||||
curveTypeItems.Add(createMenuItemForPathType(PathType.CATMULL));
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
#nullable disable
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Linq;
|
||||
@ -41,15 +42,18 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
private int currentSegmentLength;
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
[CanBeNull]
|
||||
private IPositionSnapProvider positionSnapProvider { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
[CanBeNull]
|
||||
private IDistanceSnapProvider distanceSnapProvider { get; set; }
|
||||
|
||||
[Resolved(CanBeNull = true)]
|
||||
[CanBeNull]
|
||||
private FreehandSliderToolboxGroup freehandToolboxGroup { get; set; }
|
||||
|
||||
private readonly IncrementalBSplineBuilder bSplineBuilder = new IncrementalBSplineBuilder();
|
||||
private readonly IncrementalBSplineBuilder bSplineBuilder = new IncrementalBSplineBuilder { Degree = 4 };
|
||||
|
||||
protected override bool IsValidForPlacement => HitObject.Path.HasValidLength;
|
||||
|
||||
@ -94,6 +98,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
bSplineBuilder.CornerThreshold = e.NewValue;
|
||||
Scheduler.AddOnce(updateSliderPathFromBSplineBuilder);
|
||||
}, true);
|
||||
|
||||
freehandToolboxGroup.CircleThreshold.BindValueChanged(e =>
|
||||
{
|
||||
Scheduler.AddOnce(updateSliderPathFromBSplineBuilder);
|
||||
}, true);
|
||||
}
|
||||
}
|
||||
|
||||
@ -197,7 +206,14 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
base.OnDragEnd(e);
|
||||
|
||||
if (state == SliderPlacementState.Drawing)
|
||||
{
|
||||
bSplineBuilder.Finish();
|
||||
updateSliderPathFromBSplineBuilder();
|
||||
|
||||
// Change the state so it will snap the expected distance in endCurve.
|
||||
state = SliderPlacementState.Finishing;
|
||||
endCurve();
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnMouseUp(MouseUpEvent e)
|
||||
@ -232,7 +248,7 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
{
|
||||
if (state == SliderPlacementState.Drawing)
|
||||
{
|
||||
segmentStart.Type = PathType.BSpline(3);
|
||||
segmentStart.Type = PathType.BSpline(4);
|
||||
return;
|
||||
}
|
||||
|
||||
@ -300,7 +316,10 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
|
||||
private void updateSlider()
|
||||
{
|
||||
HitObject.Path.ExpectedDistance.Value = distanceSnapProvider?.FindSnappedDistance(HitObject, (float)HitObject.Path.CalculatedDistance) ?? (float)HitObject.Path.CalculatedDistance;
|
||||
if (state == SliderPlacementState.Drawing)
|
||||
HitObject.Path.ExpectedDistance.Value = (float)HitObject.Path.CalculatedDistance;
|
||||
else
|
||||
HitObject.Path.ExpectedDistance.Value = distanceSnapProvider?.FindSnappedDistance(HitObject, (float)HitObject.Path.CalculatedDistance) ?? (float)HitObject.Path.CalculatedDistance;
|
||||
|
||||
bodyPiece.UpdateFrom(HitObject);
|
||||
headCirclePiece.UpdateFrom(HitObject.HeadCircle);
|
||||
@ -309,53 +328,126 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||
|
||||
private void updateSliderPathFromBSplineBuilder()
|
||||
{
|
||||
IReadOnlyList<Vector2> builderPoints = bSplineBuilder.ControlPoints;
|
||||
IReadOnlyList<List<Vector2>> builderPoints = bSplineBuilder.ControlPoints;
|
||||
|
||||
if (builderPoints.Count == 0)
|
||||
if (builderPoints.Count == 0 || builderPoints[0].Count == 0)
|
||||
return;
|
||||
|
||||
int lastSegmentStart = 0;
|
||||
PathType? lastPathType = null;
|
||||
|
||||
HitObject.Path.ControlPoints.Clear();
|
||||
|
||||
// Iterate through generated points, finding each segment and adding non-inheriting path types where appropriate.
|
||||
// Importantly, the B-Spline builder returns three Vector2s at the same location when a new segment is to be started.
|
||||
// Iterate through generated segments and adding non-inheriting path types where appropriate.
|
||||
for (int i = 0; i < builderPoints.Count; i++)
|
||||
{
|
||||
bool isLastPoint = i == builderPoints.Count - 1;
|
||||
bool isNewSegment = i < builderPoints.Count - 2 && builderPoints[i] == builderPoints[i + 1] && builderPoints[i] == builderPoints[i + 2];
|
||||
bool isLastSegment = i == builderPoints.Count - 1;
|
||||
var segment = builderPoints[i];
|
||||
|
||||
if (isNewSegment || isLastPoint)
|
||||
if (segment.Count == 0)
|
||||
continue;
|
||||
|
||||
// Replace this segment with a circular arc if it is a reasonable substitute.
|
||||
var circleArcSegment = tryCircleArc(segment);
|
||||
|
||||
if (circleArcSegment is not null)
|
||||
{
|
||||
int pointsInSegment = i - lastSegmentStart;
|
||||
|
||||
// Where possible, we can use the simpler LINEAR path type.
|
||||
PathType? pathType = pointsInSegment == 1 ? PathType.LINEAR : PathType.BSpline(3);
|
||||
|
||||
// Linear segments can be combined, as two adjacent linear sections are computationally the same as one with the points combined.
|
||||
if (lastPathType == pathType && lastPathType == PathType.LINEAR)
|
||||
pathType = null;
|
||||
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(builderPoints[lastSegmentStart], pathType));
|
||||
for (int j = lastSegmentStart + 1; j < i; j++)
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(builderPoints[j]));
|
||||
|
||||
if (isLastPoint)
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(builderPoints[i]));
|
||||
|
||||
// Skip the redundant duplicated points (see isNewSegment above) which have been coalesced into a path type.
|
||||
lastSegmentStart = (i += 2);
|
||||
if (pathType != null) lastPathType = pathType;
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(circleArcSegment[0], PathType.PERFECT_CURVE));
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(circleArcSegment[1]));
|
||||
}
|
||||
else
|
||||
{
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(segment[0], PathType.BSpline(4)));
|
||||
for (int j = 1; j < segment.Count - 1; j++)
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(segment[j]));
|
||||
}
|
||||
|
||||
if (isLastSegment)
|
||||
HitObject.Path.ControlPoints.Add(new PathControlPoint(segment[^1]));
|
||||
}
|
||||
}
|
||||
|
||||
private Vector2[] tryCircleArc(List<Vector2> segment)
|
||||
{
|
||||
if (segment.Count < 3 || freehandToolboxGroup?.CircleThreshold.Value == 0) return null;
|
||||
|
||||
// Assume the segment creates a reasonable circular arc and then check if it reasonable
|
||||
var points = PathApproximator.BSplineToPiecewiseLinear(segment.ToArray(), bSplineBuilder.Degree);
|
||||
var circleArcControlPoints = new[] { points[0], points[points.Count / 2], points[^1] };
|
||||
var circleArc = new CircularArcProperties(circleArcControlPoints);
|
||||
|
||||
if (!circleArc.IsValid) return null;
|
||||
|
||||
double length = circleArc.ThetaRange * circleArc.Radius;
|
||||
|
||||
if (length > 1000) return null;
|
||||
|
||||
double loss = 0;
|
||||
Vector2? lastPoint = null;
|
||||
Vector2? lastVec = null;
|
||||
Vector2? lastVec2 = null;
|
||||
int? lastDir = null;
|
||||
int? lastDir2 = null;
|
||||
double totalWinding = 0;
|
||||
|
||||
// Loop through the points and check if they are not too far away from the circular arc.
|
||||
// Also make sure it curves monotonically in one direction and at most one loop is done.
|
||||
foreach (var point in points)
|
||||
{
|
||||
var vec = point - circleArc.Centre;
|
||||
loss += Math.Pow((vec.Length - circleArc.Radius) / length, 2);
|
||||
|
||||
if (lastVec.HasValue)
|
||||
{
|
||||
double det = lastVec.Value.X * vec.Y - lastVec.Value.Y * vec.X;
|
||||
int dir = Math.Sign(det);
|
||||
|
||||
if (dir == 0)
|
||||
continue;
|
||||
|
||||
if (lastDir.HasValue && dir != lastDir)
|
||||
return null; // Circle center is not inside the polygon
|
||||
|
||||
lastDir = dir;
|
||||
}
|
||||
|
||||
lastVec = vec;
|
||||
|
||||
if (lastPoint.HasValue)
|
||||
{
|
||||
var vec2 = point - lastPoint.Value;
|
||||
|
||||
if (lastVec2.HasValue)
|
||||
{
|
||||
double dot = Vector2.Dot(vec2, lastVec2.Value);
|
||||
double det = lastVec2.Value.X * vec2.Y - lastVec2.Value.Y * vec2.X;
|
||||
double angle = Math.Atan2(det, dot);
|
||||
int dir2 = Math.Sign(angle);
|
||||
|
||||
if (dir2 == 0)
|
||||
continue;
|
||||
|
||||
if (lastDir2.HasValue && dir2 != lastDir2)
|
||||
return null; // Curvature changed, like in an S-shape
|
||||
|
||||
totalWinding += Math.Abs(angle);
|
||||
lastDir2 = dir2;
|
||||
}
|
||||
|
||||
lastVec2 = vec2;
|
||||
}
|
||||
|
||||
lastPoint = point;
|
||||
}
|
||||
|
||||
loss /= points.Count;
|
||||
|
||||
return loss > freehandToolboxGroup?.CircleThreshold.Value || totalWinding > MathHelper.TwoPi ? null : circleArcControlPoints;
|
||||
}
|
||||
|
||||
private enum SliderPlacementState
|
||||
{
|
||||
Initial,
|
||||
ControlPoints,
|
||||
Drawing
|
||||
Drawing,
|
||||
Finishing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -17,10 +17,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
{
|
||||
}
|
||||
|
||||
public BindableFloat Tolerance { get; } = new BindableFloat(1.5f)
|
||||
public BindableFloat Tolerance { get; } = new BindableFloat(1.8f)
|
||||
{
|
||||
MinValue = 0.05f,
|
||||
MaxValue = 3f,
|
||||
MaxValue = 2.0f,
|
||||
Precision = 0.01f
|
||||
};
|
||||
|
||||
@ -31,8 +31,15 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
Precision = 0.01f
|
||||
};
|
||||
|
||||
public BindableFloat CircleThreshold { get; } = new BindableFloat(0.0015f)
|
||||
{
|
||||
MinValue = 0f,
|
||||
MaxValue = 0.005f,
|
||||
Precision = 0.0001f
|
||||
};
|
||||
|
||||
// We map internal ranges to a more standard range of values for display to the user.
|
||||
private readonly BindableInt displayTolerance = new BindableInt(40)
|
||||
private readonly BindableInt displayTolerance = new BindableInt(90)
|
||||
{
|
||||
MinValue = 5,
|
||||
MaxValue = 100
|
||||
@ -44,8 +51,15 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
MaxValue = 100
|
||||
};
|
||||
|
||||
private readonly BindableInt displayCircleThreshold = new BindableInt(30)
|
||||
{
|
||||
MinValue = 0,
|
||||
MaxValue = 100
|
||||
};
|
||||
|
||||
private ExpandableSlider<int> toleranceSlider = null!;
|
||||
private ExpandableSlider<int> cornerThresholdSlider = null!;
|
||||
private ExpandableSlider<int> circleThresholdSlider = null!;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
@ -59,6 +73,10 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
cornerThresholdSlider = new ExpandableSlider<int>
|
||||
{
|
||||
Current = displayCornerThreshold
|
||||
},
|
||||
circleThresholdSlider = new ExpandableSlider<int>
|
||||
{
|
||||
Current = displayCircleThreshold
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -83,18 +101,32 @@ namespace osu.Game.Rulesets.Osu.Edit
|
||||
CornerThreshold.Value = displayToInternalCornerThreshold(threshold.NewValue);
|
||||
}, true);
|
||||
|
||||
displayCircleThreshold.BindValueChanged(threshold =>
|
||||
{
|
||||
circleThresholdSlider.ContractedLabelText = $"P. C. T.: {threshold.NewValue:N0}";
|
||||
circleThresholdSlider.ExpandedLabelText = $"Perfect Curve Threshold: {threshold.NewValue:N0}";
|
||||
|
||||
CircleThreshold.Value = displayToInternalCircleThreshold(threshold.NewValue);
|
||||
}, true);
|
||||
|
||||
Tolerance.BindValueChanged(tolerance =>
|
||||
displayTolerance.Value = internalToDisplayTolerance(tolerance.NewValue)
|
||||
);
|
||||
CornerThreshold.BindValueChanged(threshold =>
|
||||
displayCornerThreshold.Value = internalToDisplayCornerThreshold(threshold.NewValue)
|
||||
);
|
||||
CircleThreshold.BindValueChanged(threshold =>
|
||||
displayCircleThreshold.Value = internalToDisplayCircleThreshold(threshold.NewValue)
|
||||
);
|
||||
|
||||
float displayToInternalTolerance(float v) => v / 33f;
|
||||
int internalToDisplayTolerance(float v) => (int)Math.Round(v * 33f);
|
||||
float displayToInternalTolerance(float v) => v / 50f;
|
||||
int internalToDisplayTolerance(float v) => (int)Math.Round(v * 50f);
|
||||
|
||||
float displayToInternalCornerThreshold(float v) => v / 100f;
|
||||
int internalToDisplayCornerThreshold(float v) => (int)Math.Round(v * 100f);
|
||||
|
||||
float displayToInternalCircleThreshold(float v) => v / 20000f;
|
||||
int internalToDisplayCircleThreshold(float v) => (int)Math.Round(v * 20000f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -132,7 +132,7 @@ namespace osu.Game.Rulesets.Osu.Skinning.Argon
|
||||
relativeGlowSize = Source.glowSize / Source.DrawSize.X;
|
||||
}
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
drawGlow(renderer);
|
||||
|
@ -231,7 +231,7 @@ namespace osu.Game.Rulesets.Osu.Skinning
|
||||
points.AddRange(Source.SmokePoints.Skip(firstVisiblePointIndex).Take(futurePointIndex - firstVisiblePointIndex));
|
||||
}
|
||||
|
||||
public sealed override void Draw(IRenderer renderer)
|
||||
protected sealed override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -258,7 +258,7 @@ namespace osu.Game.Rulesets.Osu.UI.Cursor
|
||||
|
||||
private IUniformBuffer<CursorTrailParameters> cursorTrailParameters;
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -143,13 +143,13 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
|
||||
PushAndConfirm(() => songSelect = new TestPlaySongSelect());
|
||||
|
||||
AddStep("set filter", () => songSelect.ChildrenOfType<SearchTextBox>().Single().Current.Value = "test");
|
||||
AddStep("set filter", () => filterControlTextBox().Current.Value = "test");
|
||||
AddStep("press back", () => InputManager.Click(MouseButton.Button1));
|
||||
|
||||
AddAssert("still at song select", () => Game.ScreenStack.CurrentScreen == songSelect);
|
||||
AddAssert("filter cleared", () => string.IsNullOrEmpty(songSelect.ChildrenOfType<SearchTextBox>().Single().Current.Value));
|
||||
AddAssert("filter cleared", () => string.IsNullOrEmpty(filterControlTextBox().Current.Value));
|
||||
|
||||
AddStep("set filter again", () => songSelect.ChildrenOfType<SearchTextBox>().Single().Current.Value = "test");
|
||||
AddStep("set filter again", () => filterControlTextBox().Current.Value = "test");
|
||||
AddStep("open collections dropdown", () =>
|
||||
{
|
||||
InputManager.MoveMouseTo(songSelect.ChildrenOfType<CollectionDropdown>().Single());
|
||||
@ -163,10 +163,12 @@ namespace osu.Game.Tests.Visual.Navigation
|
||||
.ChildrenOfType<Dropdown<CollectionFilterMenuItem>.DropdownMenu>().Single().State == MenuState.Closed);
|
||||
|
||||
AddStep("press back a second time", () => InputManager.Click(MouseButton.Button1));
|
||||
AddAssert("filter cleared", () => string.IsNullOrEmpty(songSelect.ChildrenOfType<SearchTextBox>().Single().Current.Value));
|
||||
AddAssert("filter cleared", () => string.IsNullOrEmpty(filterControlTextBox().Current.Value));
|
||||
|
||||
AddStep("press back a third time", () => InputManager.Click(MouseButton.Button1));
|
||||
ConfirmAtMainMenu();
|
||||
|
||||
TextBox filterControlTextBox() => songSelect.ChildrenOfType<FilterControl.FilterControlTextBox>().Single();
|
||||
}
|
||||
|
||||
[Test]
|
||||
|
@ -631,7 +631,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert("Nothing happened", () => this.ChildrenOfType<ReportChatPopover>().Any());
|
||||
AddStep("Set report data", () =>
|
||||
{
|
||||
var field = this.ChildrenOfType<ReportChatPopover>().Single().ChildrenOfType<OsuTextBox>().Single();
|
||||
var field = this.ChildrenOfType<ReportChatPopover>().Single().ChildrenOfType<OsuTextBox>().First();
|
||||
field.Current.Value = "test other";
|
||||
});
|
||||
|
||||
|
@ -262,7 +262,7 @@ namespace osu.Game.Tests.Visual.Online
|
||||
AddAssert("Nothing happened", () => this.ChildrenOfType<ReportCommentPopover>().Any());
|
||||
AddStep("Set report data", () =>
|
||||
{
|
||||
var field = this.ChildrenOfType<ReportCommentPopover>().Single().ChildrenOfType<OsuTextBox>().Single();
|
||||
var field = this.ChildrenOfType<ReportCommentPopover>().Single().ChildrenOfType<OsuTextBox>().First();
|
||||
field.Current.Value = report_text;
|
||||
var reason = this.ChildrenOfType<OsuEnumDropdown<CommentReportReason>>().Single();
|
||||
reason.Current.Value = CommentReportReason.Other;
|
||||
|
@ -49,12 +49,12 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
AddStep("reset mouse", () => InputManager.MoveMouseTo(settings));
|
||||
|
||||
if (beforeLoad)
|
||||
AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType<SearchTextBox>().First().Current.Value = "scaling");
|
||||
AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().First().Current.Value = "scaling");
|
||||
|
||||
AddUntilStep("wait for items to load", () => settings.SectionsContainer.ChildrenOfType<IFilterable>().Any());
|
||||
|
||||
if (!beforeLoad)
|
||||
AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType<SearchTextBox>().First().Current.Value = "scaling");
|
||||
AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().First().Current.Value = "scaling");
|
||||
|
||||
AddAssert("ensure all items match filter", () => settings.SectionsContainer
|
||||
.ChildrenOfType<SettingsSection>().Where(f => f.IsPresent)
|
||||
@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
|
||||
AddUntilStep("wait for items to load", () => settings.SectionsContainer.ChildrenOfType<IFilterable>().Any());
|
||||
|
||||
AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType<SearchTextBox>().First().Current.Value = "scaling");
|
||||
AddStep("set filter", () => settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().First().Current.Value = "scaling");
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -94,7 +94,7 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
AddStep("reset mouse", () => InputManager.MoveMouseTo(settings));
|
||||
|
||||
AddUntilStep("sections loaded", () => settings.SectionsContainer.Children.Count > 0);
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<FocusedTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
|
||||
AddStep("open key binding subpanel", () =>
|
||||
{
|
||||
@ -106,13 +106,13 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
|
||||
AddUntilStep("binding panel textbox focused", () => settings
|
||||
.ChildrenOfType<KeyBindingPanel>().FirstOrDefault()?
|
||||
.ChildrenOfType<FocusedTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
.ChildrenOfType<SettingsSearchTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
|
||||
AddStep("Press back", () => settings
|
||||
.ChildrenOfType<KeyBindingPanel>().FirstOrDefault()?
|
||||
.ChildrenOfType<SettingsSubPanel.BackButton>().FirstOrDefault()?.TriggerClick());
|
||||
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<FocusedTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
@ -121,7 +121,7 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
AddStep("reset mouse", () => InputManager.MoveMouseTo(settings));
|
||||
|
||||
AddUntilStep("sections loaded", () => settings.SectionsContainer.Children.Count > 0);
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<FocusedTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
|
||||
AddStep("open key binding subpanel", () =>
|
||||
{
|
||||
@ -133,19 +133,19 @@ namespace osu.Game.Tests.Visual.Settings
|
||||
|
||||
AddUntilStep("binding panel textbox focused", () => settings
|
||||
.ChildrenOfType<KeyBindingPanel>().FirstOrDefault()?
|
||||
.ChildrenOfType<FocusedTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
.ChildrenOfType<SettingsSearchTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
|
||||
AddStep("Escape", () => InputManager.Key(Key.Escape));
|
||||
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<FocusedTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
AddUntilStep("top-level textbox focused", () => settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().FirstOrDefault()?.HasFocus == true);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void TestSearchTextBoxSelectedOnShow()
|
||||
{
|
||||
SearchTextBox searchTextBox = null!;
|
||||
SettingsSearchTextBox searchTextBox = null!;
|
||||
|
||||
AddStep("set text", () => (searchTextBox = settings.SectionsContainer.ChildrenOfType<SearchTextBox>().First()).Current.Value = "some text");
|
||||
AddStep("set text", () => (searchTextBox = settings.SectionsContainer.ChildrenOfType<SettingsSearchTextBox>().First()).Current.Value = "some text");
|
||||
AddAssert("no text selected", () => searchTextBox.SelectedText == string.Empty);
|
||||
AddRepeatStep("toggle visibility", () => settings.ToggleVisibility(), 2);
|
||||
AddAssert("search text selected", () => searchTextBox.SelectedText == searchTextBox.Current.Value);
|
||||
|
@ -22,7 +22,6 @@ using osu.Game.Beatmaps;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Extensions;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API.Requests.Responses;
|
||||
using osu.Game.Online.Chat;
|
||||
using osu.Game.Overlays;
|
||||
@ -614,7 +613,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo != null);
|
||||
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nonono");
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<FilterControl.FilterControlTextBox>().First().Text = "nonono");
|
||||
|
||||
AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap);
|
||||
|
||||
@ -648,7 +647,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddUntilStep("carousel has correct", () => songSelect!.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true);
|
||||
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target));
|
||||
|
||||
AddStep("reset filter text", () => songSelect!.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = string.Empty);
|
||||
AddStep("reset filter text", () => songSelect!.FilterControl.ChildrenOfType<FilterControl.FilterControlTextBox>().First().Text = string.Empty);
|
||||
|
||||
AddAssert("game still correct", () => Beatmap.Value?.BeatmapInfo.MatchesOnlineID(target) == true);
|
||||
AddAssert("carousel still correct", () => songSelect!.Carousel.SelectedBeatmapInfo.MatchesOnlineID(target));
|
||||
@ -666,7 +665,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
|
||||
AddUntilStep("has selection", () => songSelect!.Carousel.SelectedBeatmapInfo != null);
|
||||
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nonono");
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<FilterControl.FilterControlTextBox>().First().Text = "nonono");
|
||||
|
||||
AddUntilStep("dummy selected", () => Beatmap.Value is DummyWorkingBeatmap);
|
||||
|
||||
@ -689,7 +688,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
AddUntilStep("carousel has correct", () => songSelect!.Carousel.SelectedBeatmapInfo?.MatchesOnlineID(target) == true);
|
||||
AddUntilStep("game has correct", () => Beatmap.Value.BeatmapInfo.MatchesOnlineID(target));
|
||||
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nononoo");
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<FilterControl.FilterControlTextBox>().First().Text = "nononoo");
|
||||
|
||||
AddUntilStep("game lost selection", () => Beatmap.Value is DummyWorkingBeatmap);
|
||||
AddAssert("carousel lost selection", () => songSelect!.Carousel.SelectedBeatmapInfo == null);
|
||||
@ -1135,7 +1134,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
{
|
||||
createSongSelect();
|
||||
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<SearchTextBox>().First().Text = "nonono");
|
||||
AddStep("set filter text", () => songSelect!.FilterControl.ChildrenOfType<FilterControl.FilterControlTextBox>().First().Text = "nonono");
|
||||
AddStep("select all", () => InputManager.Keys(PlatformAction.SelectAll));
|
||||
AddStep("press ctrl-x", () =>
|
||||
{
|
||||
@ -1144,7 +1143,7 @@ namespace osu.Game.Tests.Visual.SongSelect
|
||||
InputManager.ReleaseKey(Key.ControlLeft);
|
||||
});
|
||||
|
||||
AddAssert("filter text cleared", () => songSelect!.FilterControl.ChildrenOfType<SearchTextBox>().First().Text, () => Is.Empty);
|
||||
AddAssert("filter text cleared", () => songSelect!.FilterControl.ChildrenOfType<FilterControl.FilterControlTextBox>().First().Text, () => Is.Empty);
|
||||
}
|
||||
|
||||
private void waitForInitialSelection()
|
||||
|
@ -1,9 +1,17 @@
|
||||
// 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.Linq;
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input.Events;
|
||||
using osu.Framework.Input.States;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Input.Bindings;
|
||||
|
||||
namespace osu.Game.Tests.Visual.UserInterface
|
||||
{
|
||||
@ -13,8 +21,29 @@ namespace osu.Game.Tests.Visual.UserInterface
|
||||
new OsuEnumDropdown<BeatmapOnlineStatus>
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Width = 150
|
||||
};
|
||||
|
||||
[Test]
|
||||
// todo: this can be written much better if ThemeComparisonTestScene has a manual input manager
|
||||
public void TestBackAction()
|
||||
{
|
||||
AddStep("open", () => dropdown().ChildrenOfType<Menu>().Single().Open());
|
||||
AddStep("press back", () => dropdown().OnPressed(new KeyBindingPressEvent<GlobalAction>(new InputState(), GlobalAction.Back)));
|
||||
AddAssert("closed", () => dropdown().ChildrenOfType<Menu>().Single().State == MenuState.Closed);
|
||||
|
||||
AddStep("open", () => dropdown().ChildrenOfType<Menu>().Single().Open());
|
||||
AddStep("type something", () => dropdown().ChildrenOfType<DropdownSearchBar>().Single().SearchTerm.Value = "something");
|
||||
AddAssert("search bar visible", () => dropdown().ChildrenOfType<DropdownSearchBar>().Single().State.Value == Visibility.Visible);
|
||||
AddStep("press back", () => dropdown().OnPressed(new KeyBindingPressEvent<GlobalAction>(new InputState(), GlobalAction.Back)));
|
||||
AddAssert("text clear", () => dropdown().ChildrenOfType<DropdownSearchBar>().Single().SearchTerm.Value == string.Empty);
|
||||
AddAssert("search bar hidden", () => dropdown().ChildrenOfType<DropdownSearchBar>().Single().State.Value == Visibility.Hidden);
|
||||
AddAssert("still open", () => dropdown().ChildrenOfType<Menu>().Single().State == MenuState.Open);
|
||||
AddStep("press back", () => dropdown().OnPressed(new KeyBindingPressEvent<GlobalAction>(new InputState(), GlobalAction.Back)));
|
||||
AddAssert("closed", () => dropdown().ChildrenOfType<Menu>().Single().State == MenuState.Closed);
|
||||
|
||||
OsuEnumDropdown<BeatmapOnlineStatus> dropdown() => this.ChildrenOfType<OsuEnumDropdown<BeatmapOnlineStatus>>().First();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -286,7 +286,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
|
||||
private IUniformBuffer<TriangleBorderData> borderDataBuffer;
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -228,7 +228,7 @@ namespace osu.Game.Graphics.Backgrounds
|
||||
|
||||
private IUniformBuffer<TriangleBorderData>? borderDataBuffer;
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -134,7 +134,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
lengths.AddRange(Source.bars.InstantaneousLengths);
|
||||
}
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -22,7 +22,7 @@ using osuTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public partial class OsuDropdown<T> : Dropdown<T>
|
||||
public partial class OsuDropdown<T> : Dropdown<T>, IKeyBindingHandler<GlobalAction>
|
||||
{
|
||||
private const float corner_radius = 5;
|
||||
|
||||
@ -30,9 +30,23 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new OsuDropdownMenu();
|
||||
|
||||
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||
{
|
||||
if (e.Repeat) return false;
|
||||
|
||||
if (e.Action == GlobalAction.Back)
|
||||
return Back();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
||||
{
|
||||
}
|
||||
|
||||
#region OsuDropdownMenu
|
||||
|
||||
protected partial class OsuDropdownMenu : DropdownMenu, IKeyBindingHandler<GlobalAction>
|
||||
protected partial class OsuDropdownMenu : DropdownMenu
|
||||
{
|
||||
public override bool HandleNonPositionalInput => State == MenuState.Open;
|
||||
|
||||
@ -276,23 +290,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
public bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||
{
|
||||
if (e.Repeat) return false;
|
||||
|
||||
if (e.Action == GlobalAction.Back)
|
||||
{
|
||||
State = MenuState.Closed;
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReleased(KeyBindingReleaseEvent<GlobalAction> e)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
@ -355,11 +352,77 @@ namespace osu.Game.Graphics.UserInterface
|
||||
AddInternal(new HoverClickSounds());
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OverlayColourProvider? colourProvider, OsuColour colours)
|
||||
[Resolved]
|
||||
private OverlayColourProvider? colourProvider { get; set; }
|
||||
|
||||
[Resolved]
|
||||
private OsuColour colours { get; set; } = null!;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
BackgroundColour = colourProvider?.Background5 ?? Color4.Black.Opacity(0.5f);
|
||||
BackgroundColourHover = colourProvider?.Light4 ?? colours.PinkDarker;
|
||||
base.LoadComplete();
|
||||
|
||||
SearchBar.State.ValueChanged += _ => updateColour();
|
||||
updateColour();
|
||||
}
|
||||
|
||||
protected override bool OnHover(HoverEvent e)
|
||||
{
|
||||
updateColour();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(HoverLostEvent e)
|
||||
{
|
||||
updateColour();
|
||||
}
|
||||
|
||||
private void updateColour()
|
||||
{
|
||||
bool hovered = Enabled.Value && IsHovered;
|
||||
var hoveredColour = colourProvider?.Light4 ?? colours.PinkDarker;
|
||||
var unhoveredColour = colourProvider?.Background5 ?? Color4.Black.Opacity(0.5f);
|
||||
|
||||
if (SearchBar.State.Value == Visibility.Visible)
|
||||
{
|
||||
Icon.Colour = hovered ? hoveredColour.Lighten(0.5f) : Colour4.White;
|
||||
Background.Colour = unhoveredColour;
|
||||
}
|
||||
else
|
||||
{
|
||||
Icon.Colour = Color4.White;
|
||||
Background.Colour = hovered ? hoveredColour : unhoveredColour;
|
||||
}
|
||||
}
|
||||
|
||||
protected override DropdownSearchBar CreateSearchBar() => new OsuDropdownSearchBar
|
||||
{
|
||||
Padding = new MarginPadding { Right = 36 },
|
||||
};
|
||||
|
||||
private partial class OsuDropdownSearchBar : DropdownSearchBar
|
||||
{
|
||||
protected override void PopIn() => this.FadeIn();
|
||||
|
||||
protected override void PopOut() => this.FadeOut();
|
||||
|
||||
protected override TextBox CreateTextBox() => new DropdownSearchTextBox
|
||||
{
|
||||
FontSize = OsuFont.Default.Size,
|
||||
};
|
||||
|
||||
private partial class DropdownSearchTextBox : SearchTextBox
|
||||
{
|
||||
public override bool OnPressed(KeyBindingPressEvent<GlobalAction> e)
|
||||
{
|
||||
if (e.Action == GlobalAction.Back)
|
||||
// this method is blocking Dropdown from receiving the back action, despite this text box residing in a separate input manager.
|
||||
// to fix this properly, a local global action container needs to be added as well, but for simplicity, just don't handle the back action here.
|
||||
return false;
|
||||
|
||||
return base.OnPressed(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new PasswordMaskChar(CalculatedTextSize),
|
||||
Child = new PasswordMaskChar(FontSize),
|
||||
};
|
||||
|
||||
protected override bool AllowUniqueCharacterSamples => false;
|
||||
|
@ -268,7 +268,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected override Drawable GetDrawableCharacter(char c) => new FallingDownContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Child = new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: CalculatedTextSize) },
|
||||
Child = new OsuSpriteText { Text = c.ToString(), Font = OsuFont.GetFont(size: FontSize) },
|
||||
};
|
||||
|
||||
protected override Caret CreateCaret() => caret = new OsuCaret
|
||||
@ -314,18 +314,16 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
public OsuCaret()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
Size = new Vector2(1, 0.9f);
|
||||
|
||||
Colour = Color4.Transparent;
|
||||
Anchor = Anchor.CentreLeft;
|
||||
Origin = Anchor.CentreLeft;
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 1;
|
||||
InternalChild = beatSync = new CaretBeatSyncedContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Masking = true,
|
||||
CornerRadius = 1f,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 0.9f,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -221,7 +221,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
tierColours.AddRange(Source.tierColours);
|
||||
}
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -110,7 +110,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
BackgroundFocused = colourProvider.Background4;
|
||||
BackgroundUnfocused = colourProvider.Background4;
|
||||
|
||||
Placeholder.Font = OsuFont.GetFont(size: CalculatedTextSize, weight: FontWeight.SemiBold);
|
||||
Placeholder.Font = OsuFont.GetFont(size: FontSize, weight: FontWeight.SemiBold);
|
||||
PlaceholderText = CommonStrings.InputSearch;
|
||||
|
||||
CornerRadius = corner_radius;
|
||||
|
@ -121,7 +121,7 @@ namespace osu.Game.Graphics.UserInterfaceV2
|
||||
break;
|
||||
|
||||
default:
|
||||
slider.Current.Parse(textBox.Current.Value);
|
||||
slider.Current.Parse(textBox.Current.Value, CultureInfo.CurrentCulture);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -57,9 +57,11 @@ namespace osu.Game.Overlays.Settings.Sections
|
||||
{
|
||||
skinDropdown = new SkinSettingsDropdown
|
||||
{
|
||||
AlwaysShowSearchBar = true,
|
||||
AllowNonContiguousMatching = true,
|
||||
LabelText = SkinSettingsStrings.CurrentSkin,
|
||||
Current = skins.CurrentSkinInfo,
|
||||
Keywords = new[] { @"skins" }
|
||||
Keywords = new[] { @"skins" },
|
||||
},
|
||||
new SettingsButton
|
||||
{
|
||||
|
@ -16,6 +16,18 @@ namespace osu.Game.Overlays.Settings
|
||||
{
|
||||
protected new OsuDropdown<T> Control => (OsuDropdown<T>)base.Control;
|
||||
|
||||
public bool AlwaysShowSearchBar
|
||||
{
|
||||
get => Control.AlwaysShowSearchBar;
|
||||
set => Control.AlwaysShowSearchBar = value;
|
||||
}
|
||||
|
||||
public bool AllowNonContiguousMatching
|
||||
{
|
||||
get => Control.AllowNonContiguousMatching;
|
||||
set => Control.AllowNonContiguousMatching = value;
|
||||
}
|
||||
|
||||
public IEnumerable<T> Items
|
||||
{
|
||||
get => Control.Items;
|
||||
|
@ -84,7 +84,7 @@ namespace osu.Game.Rulesets.Configuration
|
||||
|
||||
if (setting != null)
|
||||
{
|
||||
bindable.Parse(setting.Value);
|
||||
bindable.Parse(setting.Value, CultureInfo.InvariantCulture);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -3,6 +3,7 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using Newtonsoft.Json;
|
||||
@ -284,7 +285,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
if (!(target is IParseable parseable))
|
||||
throw new InvalidOperationException($"Bindable type {target.GetType().ReadableName()} is not {nameof(IParseable)}.");
|
||||
|
||||
parseable.Parse(source);
|
||||
parseable.Parse(source, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -252,7 +252,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
|
||||
private IUniformBuffer<FlashlightParameters>? flashlightParametersBuffer;
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -103,7 +103,7 @@ namespace osu.Game.Screens.Edit.Timing
|
||||
break;
|
||||
|
||||
default:
|
||||
slider.Current.Parse(t.Text);
|
||||
slider.Current.Parse(t.Text, CultureInfo.CurrentCulture);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -189,7 +189,7 @@ namespace osu.Game.Screens.Menu
|
||||
Source.frequencyAmplitudes.AsSpan().CopyTo(audioData);
|
||||
}
|
||||
|
||||
public override void Draw(IRenderer renderer)
|
||||
protected override void Draw(IRenderer renderer)
|
||||
{
|
||||
base.Draw(renderer);
|
||||
|
||||
|
@ -250,7 +250,7 @@ namespace osu.Game.Screens.Select
|
||||
|
||||
protected override bool OnHover(HoverEvent e) => true;
|
||||
|
||||
private partial class FilterControlTextBox : SeekLimitedSearchTextBox
|
||||
internal partial class FilterControlTextBox : SeekLimitedSearchTextBox
|
||||
{
|
||||
private const float filter_text_size = 12;
|
||||
|
||||
|
@ -2,6 +2,7 @@
|
||||
// See the LICENCE file in the repository root for full licence text.
|
||||
|
||||
using System;
|
||||
using System.Globalization;
|
||||
using osu.Framework.Bindables;
|
||||
using osu.Framework.Extensions.TypeExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -46,7 +47,7 @@ namespace osu.Game.Skinning
|
||||
if (!(target is IParseable parseable))
|
||||
throw new InvalidOperationException($"Bindable type {target.GetType().ReadableName()} is not {nameof(IParseable)}.");
|
||||
|
||||
parseable.Parse(source);
|
||||
parseable.Parse(source, CultureInfo.InvariantCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -5,6 +5,7 @@ using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using JetBrains.Annotations;
|
||||
@ -330,7 +331,7 @@ namespace osu.Game.Skinning
|
||||
|
||||
var bindable = new Bindable<TValue>();
|
||||
if (val != null)
|
||||
bindable.Parse(val);
|
||||
bindable.Parse(val, CultureInfo.InvariantCulture);
|
||||
return bindable;
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@
|
||||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||||
</PackageReference>
|
||||
<PackageReference Include="Realm" Version="11.5.0" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2023.1201.1" />
|
||||
<PackageReference Include="ppy.osu.Framework" Version="2023.1213.0" />
|
||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2023.1127.0" />
|
||||
<PackageReference Include="Sentry" Version="3.40.0" />
|
||||
<!-- Held back due to 0.34.0 failing AOT compilation on ZstdSharp.dll dependency. -->
|
||||
|
@ -23,6 +23,6 @@
|
||||
<RuntimeIdentifier>iossimulator-x64</RuntimeIdentifier>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.1201.1" />
|
||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2023.1213.0" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
|
Loading…
Reference in New Issue
Block a user