mirror of
https://github.com/ppy/osu.git
synced 2025-01-31 00:02:55 +08:00
Merge remote-tracking branch 'refs/remotes/ppy/master' into beatmap-mod-selector
This commit is contained in:
commit
aca3690d77
@ -49,12 +49,12 @@ desc 'Deploy to play store'
|
|||||||
desc 'Compile the project'
|
desc 'Compile the project'
|
||||||
lane :build do |options|
|
lane :build do |options|
|
||||||
nuget_restore(
|
nuget_restore(
|
||||||
project_path: 'osu.Android.sln'
|
project_path: 'osu.sln'
|
||||||
)
|
)
|
||||||
|
|
||||||
souyuz(
|
souyuz(
|
||||||
build_configuration: 'Release',
|
build_configuration: 'Release',
|
||||||
solution_path: 'osu.Android.sln',
|
solution_path: 'osu.sln',
|
||||||
platform: "android",
|
platform: "android",
|
||||||
output_path: "osu.Android/bin/Release/",
|
output_path: "osu.Android/bin/Release/",
|
||||||
keystore_path: options[:keystore_path],
|
keystore_path: options[:keystore_path],
|
||||||
@ -70,7 +70,7 @@ desc 'Deploy to play store'
|
|||||||
android_build = split.join('')
|
android_build = split.join('')
|
||||||
|
|
||||||
app_version(
|
app_version(
|
||||||
solution_path: 'osu.Android.sln',
|
solution_path: 'osu.sln',
|
||||||
version: options[:version],
|
version: options[:version],
|
||||||
build: android_build,
|
build: android_build,
|
||||||
)
|
)
|
||||||
@ -106,7 +106,7 @@ platform :ios do
|
|||||||
desc 'Compile the project'
|
desc 'Compile the project'
|
||||||
lane :build do
|
lane :build do
|
||||||
nuget_restore(
|
nuget_restore(
|
||||||
project_path: 'osu.iOS.sln'
|
project_path: 'osu.sln'
|
||||||
)
|
)
|
||||||
|
|
||||||
souyuz(
|
souyuz(
|
||||||
|
@ -53,6 +53,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1108.0" />
|
<PackageReference Include="ppy.osu.Framework.Android" Version="2019.1112.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
@ -126,7 +126,7 @@ namespace osu.Game.Rulesets.Catch.Objects
|
|||||||
|
|
||||||
public double Distance => Path.Distance;
|
public double Distance => Path.Distance;
|
||||||
|
|
||||||
public List<List<HitSampleInfo>> NodeSamples { get; set; } = new List<List<HitSampleInfo>>();
|
public List<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
|
||||||
|
|
||||||
public double? LegacyLastTickOffset { get; set; }
|
public double? LegacyLastTickOffset { get; set; }
|
||||||
}
|
}
|
||||||
|
@ -255,7 +255,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The time to retrieve the sample info list from.</param>
|
/// <param name="time">The time to retrieve the sample info list from.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private List<HitSampleInfo> sampleInfoListAt(double time)
|
private IList<HitSampleInfo> sampleInfoListAt(double time)
|
||||||
{
|
{
|
||||||
var curveData = HitObject as IHasCurve;
|
var curveData = HitObject as IHasCurve;
|
||||||
|
|
||||||
|
@ -472,7 +472,7 @@ namespace osu.Game.Rulesets.Mania.Beatmaps.Patterns.Legacy
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="time">The time to retrieve the sample info list from.</param>
|
/// <param name="time">The time to retrieve the sample info list from.</param>
|
||||||
/// <returns></returns>
|
/// <returns></returns>
|
||||||
private List<HitSampleInfo> sampleInfoListAt(double time)
|
private IList<HitSampleInfo> sampleInfoListAt(double time)
|
||||||
{
|
{
|
||||||
var curveData = HitObject as IHasCurve;
|
var curveData = HitObject as IHasCurve;
|
||||||
|
|
||||||
|
@ -126,6 +126,67 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
AddAssert("body positioned correctly", () => slider.Position == slider.HitObject.StackedPosition);
|
AddAssert("body positioned correctly", () => slider.Position == slider.HitObject.StackedPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestChangeSamplesWithNoNodeSamples()
|
||||||
|
{
|
||||||
|
DrawableSlider slider = null;
|
||||||
|
|
||||||
|
AddStep("create slider", () =>
|
||||||
|
{
|
||||||
|
slider = (DrawableSlider)createSlider(repeats: 1);
|
||||||
|
Add(slider);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("change samples", () => slider.HitObject.Samples = new[]
|
||||||
|
{
|
||||||
|
new HitSampleInfo { Name = HitSampleInfo.HIT_CLAP },
|
||||||
|
new HitSampleInfo { Name = HitSampleInfo.HIT_WHISTLE },
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("head samples updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle));
|
||||||
|
AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderTick>().All(assertTickSamples));
|
||||||
|
AddAssert("repeat samples updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<RepeatPoint>().All(assertSamples));
|
||||||
|
AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0);
|
||||||
|
|
||||||
|
bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick";
|
||||||
|
|
||||||
|
bool assertSamples(HitObject hitObject)
|
||||||
|
{
|
||||||
|
return hitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_CLAP)
|
||||||
|
&& hitObject.Samples.Any(s => s.Name == HitSampleInfo.HIT_WHISTLE);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
[Test]
|
||||||
|
public void TestChangeSamplesWithNodeSamples()
|
||||||
|
{
|
||||||
|
DrawableSlider slider = null;
|
||||||
|
|
||||||
|
AddStep("create slider", () =>
|
||||||
|
{
|
||||||
|
slider = (DrawableSlider)createSlider(repeats: 1);
|
||||||
|
|
||||||
|
for (int i = 0; i < 2; i++)
|
||||||
|
((Slider)slider.HitObject).NodeSamples.Add(new List<HitSampleInfo> { new HitSampleInfo { Name = HitSampleInfo.HIT_FINISH } });
|
||||||
|
|
||||||
|
Add(slider);
|
||||||
|
});
|
||||||
|
|
||||||
|
AddStep("change samples", () => slider.HitObject.Samples = new[]
|
||||||
|
{
|
||||||
|
new HitSampleInfo { Name = HitSampleInfo.HIT_CLAP },
|
||||||
|
new HitSampleInfo { Name = HitSampleInfo.HIT_WHISTLE },
|
||||||
|
});
|
||||||
|
|
||||||
|
AddAssert("head samples not updated", () => assertSamples(((Slider)slider.HitObject).HeadCircle));
|
||||||
|
AddAssert("tick samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<SliderTick>().All(assertTickSamples));
|
||||||
|
AddAssert("repeat samples not updated", () => ((Slider)slider.HitObject).NestedHitObjects.OfType<RepeatPoint>().All(assertSamples));
|
||||||
|
AddAssert("tail has no samples", () => ((Slider)slider.HitObject).TailCircle.Samples.Count == 0);
|
||||||
|
|
||||||
|
bool assertTickSamples(SliderTick tick) => tick.Samples.Single().Name == "slidertick";
|
||||||
|
bool assertSamples(HitObject hitObject) => hitObject.Samples.All(s => s.Name != HitSampleInfo.HIT_CLAP && s.Name != HitSampleInfo.HIT_WHISTLE);
|
||||||
|
}
|
||||||
|
|
||||||
private Drawable testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
|
private Drawable testSimpleBig(int repeats = 0) => createSlider(2, repeats: repeats);
|
||||||
|
|
||||||
private Drawable testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
|
private Drawable testSimpleBigLargeStackOffset(int repeats = 0) => createSlider(2, repeats: repeats, stackHeight: 10);
|
||||||
@ -143,7 +204,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new Vector2(52, -34)
|
new Vector2(52, -34)
|
||||||
}, 700),
|
}, 700),
|
||||||
RepeatCount = repeats,
|
RepeatCount = repeats,
|
||||||
NodeSamples = createEmptySamples(repeats),
|
|
||||||
StackHeight = 10
|
StackHeight = 10
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -174,7 +234,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new Vector2(distance, 0),
|
new Vector2(distance, 0),
|
||||||
}, distance),
|
}, distance),
|
||||||
RepeatCount = repeats,
|
RepeatCount = repeats,
|
||||||
NodeSamples = createEmptySamples(repeats),
|
|
||||||
StackHeight = stackHeight
|
StackHeight = stackHeight
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -194,7 +253,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new Vector2(400, 0)
|
new Vector2(400, 0)
|
||||||
}, 600),
|
}, 600),
|
||||||
RepeatCount = repeats,
|
RepeatCount = repeats,
|
||||||
NodeSamples = createEmptySamples(repeats)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return createDrawable(slider, 2, 3);
|
return createDrawable(slider, 2, 3);
|
||||||
@ -218,7 +276,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new Vector2(430, 0)
|
new Vector2(430, 0)
|
||||||
}),
|
}),
|
||||||
RepeatCount = repeats,
|
RepeatCount = repeats,
|
||||||
NodeSamples = createEmptySamples(repeats)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return createDrawable(slider, 2, 3);
|
return createDrawable(slider, 2, 3);
|
||||||
@ -241,7 +298,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new Vector2(430, 0)
|
new Vector2(430, 0)
|
||||||
}),
|
}),
|
||||||
RepeatCount = repeats,
|
RepeatCount = repeats,
|
||||||
NodeSamples = createEmptySamples(repeats)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return createDrawable(slider, 2, 3);
|
return createDrawable(slider, 2, 3);
|
||||||
@ -265,7 +321,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
new Vector2(0, -200)
|
new Vector2(0, -200)
|
||||||
}),
|
}),
|
||||||
RepeatCount = repeats,
|
RepeatCount = repeats,
|
||||||
NodeSamples = createEmptySamples(repeats)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
return createDrawable(slider, 2, 3);
|
return createDrawable(slider, 2, 3);
|
||||||
@ -275,7 +330,7 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
|
|
||||||
private Drawable createCatmull(int repeats = 0)
|
private Drawable createCatmull(int repeats = 0)
|
||||||
{
|
{
|
||||||
var repeatSamples = new List<List<HitSampleInfo>>();
|
var repeatSamples = new List<IList<HitSampleInfo>>();
|
||||||
for (int i = 0; i < repeats; i++)
|
for (int i = 0; i < repeats; i++)
|
||||||
repeatSamples.Add(new List<HitSampleInfo>());
|
repeatSamples.Add(new List<HitSampleInfo>());
|
||||||
|
|
||||||
@ -297,14 +352,6 @@ namespace osu.Game.Rulesets.Osu.Tests
|
|||||||
return createDrawable(slider, 3, 1);
|
return createDrawable(slider, 3, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<List<HitSampleInfo>> createEmptySamples(int repeats)
|
|
||||||
{
|
|
||||||
var repeatSamples = new List<List<HitSampleInfo>>();
|
|
||||||
for (int i = 0; i < repeats; i++)
|
|
||||||
repeatSamples.Add(new List<HitSampleInfo>());
|
|
||||||
return repeatSamples;
|
|
||||||
}
|
|
||||||
|
|
||||||
private Drawable createDrawable(Slider slider, float circleSize, double speedMultiplier)
|
private Drawable createDrawable(Slider slider, float circleSize, double speedMultiplier)
|
||||||
{
|
{
|
||||||
var cpi = new ControlPointInfo();
|
var cpi = new ControlPointInfo();
|
||||||
|
@ -1,8 +1,14 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Diagnostics;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
|
using osu.Framework.Input.Events;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Types;
|
using osu.Game.Rulesets.Objects.Types;
|
||||||
@ -10,6 +16,7 @@ using osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders.Components;
|
|||||||
using osu.Game.Rulesets.Osu.Objects;
|
using osu.Game.Rulesets.Osu.Objects;
|
||||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
||||||
{
|
{
|
||||||
@ -44,6 +51,78 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
BodyPiece.UpdateFrom(HitObject);
|
BodyPiece.UpdateFrom(HitObject);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private Vector2 rightClickPosition;
|
||||||
|
|
||||||
|
protected override bool OnMouseDown(MouseDownEvent e)
|
||||||
|
{
|
||||||
|
switch (e.Button)
|
||||||
|
{
|
||||||
|
case MouseButton.Right:
|
||||||
|
rightClickPosition = e.MouseDownPosition;
|
||||||
|
return false; // Allow right click to be handled by context menu
|
||||||
|
|
||||||
|
case MouseButton.Left when e.ControlPressed && IsSelected:
|
||||||
|
placementControlPointIndex = addControlPoint(e.MousePosition);
|
||||||
|
return true; // Stop input from being handled and modifying the selection
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int? placementControlPointIndex;
|
||||||
|
|
||||||
|
protected override bool OnDragStart(DragStartEvent e) => placementControlPointIndex != null;
|
||||||
|
|
||||||
|
protected override bool OnDrag(DragEvent e)
|
||||||
|
{
|
||||||
|
Debug.Assert(placementControlPointIndex != null);
|
||||||
|
|
||||||
|
Vector2 position = e.MousePosition - HitObject.Position;
|
||||||
|
|
||||||
|
var controlPoints = HitObject.Path.ControlPoints.ToArray();
|
||||||
|
controlPoints[placementControlPointIndex.Value] = position;
|
||||||
|
|
||||||
|
onNewControlPoints(controlPoints);
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnDragEnd(DragEndEvent e)
|
||||||
|
{
|
||||||
|
placementControlPointIndex = null;
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
private int addControlPoint(Vector2 position)
|
||||||
|
{
|
||||||
|
position -= HitObject.Position;
|
||||||
|
|
||||||
|
var controlPoints = new Vector2[HitObject.Path.ControlPoints.Length + 1];
|
||||||
|
HitObject.Path.ControlPoints.CopyTo(controlPoints);
|
||||||
|
|
||||||
|
int insertionIndex = 0;
|
||||||
|
float minDistance = float.MaxValue;
|
||||||
|
|
||||||
|
for (int i = 0; i < controlPoints.Length - 2; i++)
|
||||||
|
{
|
||||||
|
float dist = new Line(controlPoints[i], controlPoints[i + 1]).DistanceToPoint(position);
|
||||||
|
|
||||||
|
if (dist < minDistance)
|
||||||
|
{
|
||||||
|
insertionIndex = i + 1;
|
||||||
|
minDistance = dist;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Move the control points from the insertion index onwards to make room for the insertion
|
||||||
|
Array.Copy(controlPoints, insertionIndex, controlPoints, insertionIndex + 1, controlPoints.Length - insertionIndex - 1);
|
||||||
|
controlPoints[insertionIndex] = position;
|
||||||
|
|
||||||
|
onNewControlPoints(controlPoints);
|
||||||
|
|
||||||
|
return insertionIndex;
|
||||||
|
}
|
||||||
|
|
||||||
private void onNewControlPoints(Vector2[] controlPoints)
|
private void onNewControlPoints(Vector2[] controlPoints)
|
||||||
{
|
{
|
||||||
var unsnappedPath = new SliderPath(controlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, controlPoints);
|
var unsnappedPath = new SliderPath(controlPoints.Length > 2 ? PathType.Bezier : PathType.Linear, controlPoints);
|
||||||
@ -54,6 +133,11 @@ namespace osu.Game.Rulesets.Osu.Edit.Blueprints.Sliders
|
|||||||
UpdateHitObject();
|
UpdateHitObject();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public override MenuItem[] ContextMenuItems => new MenuItem[]
|
||||||
|
{
|
||||||
|
new OsuMenuItem("Add control point", MenuItemType.Standard, () => addControlPoint(rightClickPosition)),
|
||||||
|
};
|
||||||
|
|
||||||
public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint;
|
public override Vector2 SelectionPoint => HeadBlueprint.SelectionPoint;
|
||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => BodyPiece.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
@ -70,7 +70,7 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
internal float LazyTravelDistance;
|
internal float LazyTravelDistance;
|
||||||
|
|
||||||
public List<List<HitSampleInfo>> NodeSamples { get; set; } = new List<List<HitSampleInfo>>();
|
public List<IList<HitSampleInfo>> NodeSamples { get; set; } = new List<IList<HitSampleInfo>>();
|
||||||
|
|
||||||
private int repeatCount;
|
private int repeatCount;
|
||||||
|
|
||||||
@ -108,6 +108,12 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
public HitCircle HeadCircle;
|
public HitCircle HeadCircle;
|
||||||
public SliderTailCircle TailCircle;
|
public SliderTailCircle TailCircle;
|
||||||
|
|
||||||
|
public Slider()
|
||||||
|
{
|
||||||
|
SamplesBindable.ItemsAdded += _ => updateNestedSamples();
|
||||||
|
SamplesBindable.ItemsRemoved += _ => updateNestedSamples();
|
||||||
|
}
|
||||||
|
|
||||||
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
protected override void ApplyDefaultsToSelf(ControlPointInfo controlPointInfo, BeatmapDifficulty difficulty)
|
||||||
{
|
{
|
||||||
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
base.ApplyDefaultsToSelf(controlPointInfo, difficulty);
|
||||||
@ -128,20 +134,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
foreach (var e in
|
foreach (var e in
|
||||||
SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset))
|
SliderEventGenerator.Generate(StartTime, SpanDuration, Velocity, TickDistance, Path.Distance, this.SpanCount(), LegacyLastTickOffset))
|
||||||
{
|
{
|
||||||
var firstSample = Samples.Find(s => s.Name == HitSampleInfo.HIT_NORMAL)
|
|
||||||
?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
|
|
||||||
var sampleList = new List<HitSampleInfo>();
|
|
||||||
|
|
||||||
if (firstSample != null)
|
|
||||||
{
|
|
||||||
sampleList.Add(new HitSampleInfo
|
|
||||||
{
|
|
||||||
Bank = firstSample.Bank,
|
|
||||||
Volume = firstSample.Volume,
|
|
||||||
Name = @"slidertick",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (e.Type)
|
switch (e.Type)
|
||||||
{
|
{
|
||||||
case SliderEventType.Tick:
|
case SliderEventType.Tick:
|
||||||
@ -153,7 +145,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
Position = Position + Path.PositionAt(e.PathProgress),
|
Position = Position + Path.PositionAt(e.PathProgress),
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
Scale = Scale,
|
Scale = Scale,
|
||||||
Samples = sampleList
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
|
|
||||||
@ -163,7 +154,6 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
StartTime = e.Time,
|
StartTime = e.Time,
|
||||||
Position = Position,
|
Position = Position,
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
Samples = getNodeSamples(0),
|
|
||||||
SampleControlPoint = SampleControlPoint,
|
SampleControlPoint = SampleControlPoint,
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
@ -189,11 +179,12 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
Position = Position + Path.PositionAt(e.PathProgress),
|
Position = Position + Path.PositionAt(e.PathProgress),
|
||||||
StackHeight = StackHeight,
|
StackHeight = StackHeight,
|
||||||
Scale = Scale,
|
Scale = Scale,
|
||||||
Samples = getNodeSamples(e.SpanIndex + 1)
|
|
||||||
});
|
});
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
updateNestedSamples();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void updateNestedPositions()
|
private void updateNestedPositions()
|
||||||
@ -205,7 +196,33 @@ namespace osu.Game.Rulesets.Osu.Objects
|
|||||||
TailCircle.Position = EndPosition;
|
TailCircle.Position = EndPosition;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HitSampleInfo> getNodeSamples(int nodeIndex) =>
|
private void updateNestedSamples()
|
||||||
|
{
|
||||||
|
var firstSample = Samples.FirstOrDefault(s => s.Name == HitSampleInfo.HIT_NORMAL)
|
||||||
|
?? Samples.FirstOrDefault(); // TODO: remove this when guaranteed sort is present for samples (https://github.com/ppy/osu/issues/1933)
|
||||||
|
var sampleList = new List<HitSampleInfo>();
|
||||||
|
|
||||||
|
if (firstSample != null)
|
||||||
|
{
|
||||||
|
sampleList.Add(new HitSampleInfo
|
||||||
|
{
|
||||||
|
Bank = firstSample.Bank,
|
||||||
|
Volume = firstSample.Volume,
|
||||||
|
Name = @"slidertick",
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (var tick in NestedHitObjects.OfType<SliderTick>())
|
||||||
|
tick.Samples = sampleList;
|
||||||
|
|
||||||
|
foreach (var repeat in NestedHitObjects.OfType<RepeatPoint>())
|
||||||
|
repeat.Samples = getNodeSamples(repeat.RepeatIndex + 1);
|
||||||
|
|
||||||
|
if (HeadCircle != null)
|
||||||
|
HeadCircle.Samples = getNodeSamples(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private IList<HitSampleInfo> getNodeSamples(int nodeIndex) =>
|
||||||
nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples;
|
nodeIndex < NodeSamples.Count ? NodeSamples[nodeIndex] : Samples;
|
||||||
|
|
||||||
public override Judgement CreateJudgement() => new OsuJudgement();
|
public override Judgement CreateJudgement() => new OsuJudgement();
|
||||||
|
@ -79,7 +79,7 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
var curveData = obj as IHasCurve;
|
var curveData = obj as IHasCurve;
|
||||||
|
|
||||||
// Old osu! used hit sounding to determine various hit type information
|
// Old osu! used hit sounding to determine various hit type information
|
||||||
List<HitSampleInfo> samples = obj.Samples;
|
IList<HitSampleInfo> samples = obj.Samples;
|
||||||
|
|
||||||
bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
|
bool strong = samples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
|
||||||
|
|
||||||
@ -117,13 +117,13 @@ namespace osu.Game.Rulesets.Taiko.Beatmaps
|
|||||||
|
|
||||||
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
|
if (!isForCurrentRuleset && tickSpacing > 0 && osuDuration < 2 * speedAdjustedBeatLength)
|
||||||
{
|
{
|
||||||
List<List<HitSampleInfo>> allSamples = curveData != null ? curveData.NodeSamples : new List<List<HitSampleInfo>>(new[] { samples });
|
List<IList<HitSampleInfo>> allSamples = curveData != null ? curveData.NodeSamples : new List<IList<HitSampleInfo>>(new[] { samples });
|
||||||
|
|
||||||
int i = 0;
|
int i = 0;
|
||||||
|
|
||||||
for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing)
|
for (double j = obj.StartTime; j <= obj.StartTime + taikoDuration + tickSpacing / 8; j += tickSpacing)
|
||||||
{
|
{
|
||||||
List<HitSampleInfo> currentSamples = allSamples[i];
|
IList<HitSampleInfo> currentSamples = allSamples[i];
|
||||||
bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
|
bool isRim = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_CLAP || s.Name == HitSampleInfo.HIT_WHISTLE);
|
||||||
strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
|
strong = currentSamples.Any(s => s.Name == HitSampleInfo.HIT_FINISH);
|
||||||
|
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Audio.Track;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Beatmaps;
|
using osu.Game.Beatmaps;
|
||||||
|
using static osu.Game.Tests.Visual.Components.TestScenePreviewTrackManager.TestPreviewTrackManager;
|
||||||
|
|
||||||
namespace osu.Game.Tests.Visual.Components
|
namespace osu.Game.Tests.Visual.Components
|
||||||
{
|
{
|
||||||
@ -59,6 +60,9 @@ namespace osu.Game.Tests.Visual.Components
|
|||||||
AddStep("start track 2", () => track2.Start());
|
AddStep("start track 2", () => track2.Start());
|
||||||
AddAssert("track 1 stopped", () => !track1.IsRunning);
|
AddAssert("track 1 stopped", () => !track1.IsRunning);
|
||||||
AddAssert("track 2 started", () => track2.IsRunning);
|
AddAssert("track 2 started", () => track2.IsRunning);
|
||||||
|
AddStep("start track 1", () => track1.Start());
|
||||||
|
AddAssert("track 2 stopped", () => !track2.IsRunning);
|
||||||
|
AddAssert("track 1 started", () => track1.IsRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
[Test]
|
[Test]
|
||||||
@ -88,9 +92,25 @@ namespace osu.Game.Tests.Visual.Components
|
|||||||
AddAssert("stopped", () => !track.IsRunning);
|
AddAssert("stopped", () => !track.IsRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
private PreviewTrack getTrack() => trackManager.Get(null);
|
[Test]
|
||||||
|
public void TestNonPresentTrack()
|
||||||
|
{
|
||||||
|
TestPreviewTrack track = null;
|
||||||
|
|
||||||
private PreviewTrack getOwnedTrack()
|
AddStep("get non-present track", () =>
|
||||||
|
{
|
||||||
|
Add(new TestTrackOwner(track = getTrack()));
|
||||||
|
track.Alpha = 0;
|
||||||
|
});
|
||||||
|
AddUntilStep("wait loaded", () => track.IsLoaded);
|
||||||
|
AddStep("start", () => track.Start());
|
||||||
|
AddStep("seek to end", () => track.Track.Seek(track.Track.Length));
|
||||||
|
AddAssert("track stopped", () => !track.IsRunning);
|
||||||
|
}
|
||||||
|
|
||||||
|
private TestPreviewTrack getTrack() => (TestPreviewTrack)trackManager.Get(null);
|
||||||
|
|
||||||
|
private TestPreviewTrack getOwnedTrack()
|
||||||
{
|
{
|
||||||
var track = getTrack();
|
var track = getTrack();
|
||||||
|
|
||||||
@ -122,14 +142,16 @@ namespace osu.Game.Tests.Visual.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private class TestPreviewTrackManager : PreviewTrackManager
|
public class TestPreviewTrackManager : PreviewTrackManager
|
||||||
{
|
{
|
||||||
protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore);
|
protected override TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TestPreviewTrack(beatmapSetInfo, trackStore);
|
||||||
|
|
||||||
protected class TestPreviewTrack : TrackManagerPreviewTrack
|
public class TestPreviewTrack : TrackManagerPreviewTrack
|
||||||
{
|
{
|
||||||
private readonly ITrackStore trackManager;
|
private readonly ITrackStore trackManager;
|
||||||
|
|
||||||
|
public new Track Track => base.Track;
|
||||||
|
|
||||||
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackManager)
|
public TestPreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackManager)
|
||||||
: base(beatmapSetInfo, trackManager)
|
: base(beatmapSetInfo, trackManager)
|
||||||
{
|
{
|
||||||
|
@ -5,6 +5,7 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using Newtonsoft.Json;
|
using Newtonsoft.Json;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
|
|
||||||
namespace osu.Game.Tournament.Models
|
namespace osu.Game.Tournament.Models
|
||||||
{
|
{
|
||||||
@ -14,6 +15,8 @@ namespace osu.Game.Tournament.Models
|
|||||||
[Serializable]
|
[Serializable]
|
||||||
public class LadderInfo
|
public class LadderInfo
|
||||||
{
|
{
|
||||||
|
public Bindable<RulesetInfo> Ruleset = new Bindable<RulesetInfo>();
|
||||||
|
|
||||||
public BindableList<TournamentMatch> Matches = new BindableList<TournamentMatch>();
|
public BindableList<TournamentMatch> Matches = new BindableList<TournamentMatch>();
|
||||||
public BindableList<TournamentRound> Rounds = new BindableList<TournamentRound>();
|
public BindableList<TournamentRound> Rounds = new BindableList<TournamentRound>();
|
||||||
public BindableList<TournamentTeam> Teams = new BindableList<TournamentTeam>();
|
public BindableList<TournamentTeam> Teams = new BindableList<TournamentTeam>();
|
||||||
|
@ -12,7 +12,6 @@ using osu.Framework.Graphics.Containers;
|
|||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Online.API.Requests;
|
|
||||||
using osu.Game.Overlays.Settings;
|
using osu.Game.Overlays.Settings;
|
||||||
using osu.Game.Tournament.Components;
|
using osu.Game.Tournament.Components;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
@ -24,7 +23,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
public class TeamEditorScreen : TournamentEditorScreen<TeamEditorScreen.TeamRow, TournamentTeam>
|
public class TeamEditorScreen : TournamentEditorScreen<TeamEditorScreen.TeamRow, TournamentTeam>
|
||||||
{
|
{
|
||||||
[Resolved]
|
[Resolved]
|
||||||
private Framework.Game game { get; set; }
|
private TournamentGameBase game { get; set; }
|
||||||
|
|
||||||
protected override BindableList<TournamentTeam> Storage => LadderInfo.Teams;
|
protected override BindableList<TournamentTeam> Storage => LadderInfo.Teams;
|
||||||
|
|
||||||
@ -198,6 +197,9 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
protected IAPIProvider API { get; private set; }
|
protected IAPIProvider API { get; private set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private TournamentGameBase game { get; set; }
|
||||||
|
|
||||||
private readonly Bindable<string> userId = new Bindable<string>();
|
private readonly Bindable<string> userId = new Bindable<string>();
|
||||||
|
|
||||||
private readonly Container drawableContainer;
|
private readonly Container drawableContainer;
|
||||||
@ -280,25 +282,7 @@ namespace osu.Game.Tournament.Screens.Editors
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var req = new GetUserRequest(user.Id);
|
game.PopulateUser(user, updatePanel, updatePanel);
|
||||||
|
|
||||||
req.Success += res =>
|
|
||||||
{
|
|
||||||
// TODO: this should be done in a better way.
|
|
||||||
user.Username = res.Username;
|
|
||||||
user.Country = res.Country;
|
|
||||||
user.Cover = res.Cover;
|
|
||||||
|
|
||||||
updatePanel();
|
|
||||||
};
|
|
||||||
|
|
||||||
req.Failure += _ =>
|
|
||||||
{
|
|
||||||
user.Id = 1;
|
|
||||||
updatePanel();
|
|
||||||
};
|
|
||||||
|
|
||||||
API.Queue(req);
|
|
||||||
}, true);
|
}, true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -2,6 +2,7 @@
|
|||||||
// See the LICENCE file in the repository root for full licence text.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
using System;
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
@ -10,6 +11,7 @@ using osu.Game.Graphics.UserInterface;
|
|||||||
using osu.Game.Graphics.UserInterfaceV2;
|
using osu.Game.Graphics.UserInterfaceV2;
|
||||||
using osu.Game.Online.API;
|
using osu.Game.Online.API;
|
||||||
using osu.Game.Overlays;
|
using osu.Game.Overlays;
|
||||||
|
using osu.Game.Rulesets;
|
||||||
using osu.Game.Tournament.IPC;
|
using osu.Game.Tournament.IPC;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
@ -28,6 +30,9 @@ namespace osu.Game.Tournament.Screens
|
|||||||
[Resolved]
|
[Resolved]
|
||||||
private IAPIProvider api { get; set; }
|
private IAPIProvider api { get; set; }
|
||||||
|
|
||||||
|
[Resolved]
|
||||||
|
private RulesetStore rulesets { get; set; }
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
@ -85,7 +90,34 @@ namespace osu.Game.Tournament.Screens
|
|||||||
Value = api?.LocalUser.Value.Username,
|
Value = api?.LocalUser.Value.Username,
|
||||||
Failing = api?.IsLoggedIn != true,
|
Failing = api?.IsLoggedIn != true,
|
||||||
Description = "In order to access the API and display metadata, a login is required."
|
Description = "In order to access the API and display metadata, a login is required."
|
||||||
}
|
},
|
||||||
|
new LabelledDropdown<RulesetInfo>
|
||||||
|
{
|
||||||
|
Label = "Ruleset",
|
||||||
|
Description = "Decides what stats are displayed and which ranks are retrieved for players",
|
||||||
|
Items = rulesets.AvailableRulesets,
|
||||||
|
Current = LadderInfo.Ruleset,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
public class LabelledDropdown<T> : LabelledComponent<OsuDropdown<T>, T>
|
||||||
|
{
|
||||||
|
public LabelledDropdown()
|
||||||
|
: base(true)
|
||||||
|
{
|
||||||
|
}
|
||||||
|
|
||||||
|
public IEnumerable<T> Items
|
||||||
|
{
|
||||||
|
get => Component.Items;
|
||||||
|
set => Component.Items = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override OsuDropdown<T> CreateComponent() => new OsuDropdown<T>
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Width = 0.5f,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@ -21,11 +22,13 @@ using osu.Game.Graphics;
|
|||||||
using osu.Game.Online.API.Requests;
|
using osu.Game.Online.API.Requests;
|
||||||
using osu.Game.Tournament.IPC;
|
using osu.Game.Tournament.IPC;
|
||||||
using osu.Game.Tournament.Models;
|
using osu.Game.Tournament.Models;
|
||||||
|
using osu.Game.Users;
|
||||||
using osuTK.Graphics;
|
using osuTK.Graphics;
|
||||||
using osuTK.Input;
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Tournament
|
namespace osu.Game.Tournament
|
||||||
{
|
{
|
||||||
|
[Cached(typeof(TournamentGameBase))]
|
||||||
public abstract class TournamentGameBase : OsuGameBase
|
public abstract class TournamentGameBase : OsuGameBase
|
||||||
{
|
{
|
||||||
private const string bracket_filename = "bracket.json";
|
private const string bracket_filename = "bracket.json";
|
||||||
@ -126,6 +129,8 @@ namespace osu.Game.Tournament
|
|||||||
ladder = new LadderInfo();
|
ladder = new LadderInfo();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Ruleset.BindTo(ladder.Ruleset);
|
||||||
|
|
||||||
dependencies.Cache(ladder);
|
dependencies.Cache(ladder);
|
||||||
|
|
||||||
bool addedInfo = false;
|
bool addedInfo = false;
|
||||||
@ -197,14 +202,8 @@ namespace osu.Game.Tournament
|
|||||||
{
|
{
|
||||||
foreach (var p in t.Players)
|
foreach (var p in t.Players)
|
||||||
{
|
{
|
||||||
if (string.IsNullOrEmpty(p.Username))
|
PopulateUser(p);
|
||||||
{
|
addedInfo = true;
|
||||||
var req = new GetUserRequest(p.Id);
|
|
||||||
req.Perform(API);
|
|
||||||
p.Username = req.Result.Username;
|
|
||||||
|
|
||||||
addedInfo = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -236,6 +235,30 @@ namespace osu.Game.Tournament
|
|||||||
return addedInfo;
|
return addedInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void PopulateUser(User user, Action success = null, Action failure = null)
|
||||||
|
{
|
||||||
|
var req = new GetUserRequest(user.Id, Ruleset.Value);
|
||||||
|
|
||||||
|
req.Success += res =>
|
||||||
|
{
|
||||||
|
user.Username = res.Username;
|
||||||
|
user.Statistics = res.Statistics;
|
||||||
|
user.Username = res.Username;
|
||||||
|
user.Country = res.Country;
|
||||||
|
user.Cover = res.Cover;
|
||||||
|
|
||||||
|
success?.Invoke();
|
||||||
|
};
|
||||||
|
|
||||||
|
req.Failure += _ =>
|
||||||
|
{
|
||||||
|
user.Id = 1;
|
||||||
|
failure?.Invoke();
|
||||||
|
};
|
||||||
|
|
||||||
|
API.Queue(req);
|
||||||
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
MenuCursorContainer.Cursor.AlwaysPresent = true; // required for tooltip display
|
MenuCursorContainer.Cursor.AlwaysPresent = true; // required for tooltip display
|
||||||
|
@ -24,36 +24,37 @@ namespace osu.Game.Audio
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public event Action Started;
|
public event Action Started;
|
||||||
|
|
||||||
private Track track;
|
protected Track Track { get; private set; }
|
||||||
|
|
||||||
private bool hasStarted;
|
private bool hasStarted;
|
||||||
|
|
||||||
[BackgroundDependencyLoader]
|
[BackgroundDependencyLoader]
|
||||||
private void load()
|
private void load()
|
||||||
{
|
{
|
||||||
track = GetTrack();
|
Track = GetTrack();
|
||||||
if (track != null)
|
if (Track != null)
|
||||||
track.Completed += Stop;
|
Track.Completed += Stop;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Length of the track.
|
/// Length of the track.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double Length => track?.Length ?? 0;
|
public double Length => Track?.Length ?? 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The current track time.
|
/// The current track time.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public double CurrentTime => track?.CurrentTime ?? 0;
|
public double CurrentTime => Track?.CurrentTime ?? 0;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the track is loaded.
|
/// Whether the track is loaded.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool TrackLoaded => track?.IsLoaded ?? false;
|
public bool TrackLoaded => Track?.IsLoaded ?? false;
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Whether the track is playing.
|
/// Whether the track is playing.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public bool IsRunning => track?.IsRunning ?? false;
|
public bool IsRunning => Track?.IsRunning ?? false;
|
||||||
|
|
||||||
private ScheduledDelegate startDelegate;
|
private ScheduledDelegate startDelegate;
|
||||||
|
|
||||||
@ -63,7 +64,7 @@ namespace osu.Game.Audio
|
|||||||
/// <returns>Whether the track is started or already playing.</returns>
|
/// <returns>Whether the track is started or already playing.</returns>
|
||||||
public bool Start()
|
public bool Start()
|
||||||
{
|
{
|
||||||
if (track == null)
|
if (Track == null)
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
startDelegate = Schedule(() =>
|
startDelegate = Schedule(() =>
|
||||||
@ -73,7 +74,7 @@ namespace osu.Game.Audio
|
|||||||
|
|
||||||
hasStarted = true;
|
hasStarted = true;
|
||||||
|
|
||||||
track.Restart();
|
Track.Restart();
|
||||||
Started?.Invoke();
|
Started?.Invoke();
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -87,7 +88,7 @@ namespace osu.Game.Audio
|
|||||||
{
|
{
|
||||||
startDelegate?.Cancel();
|
startDelegate?.Cancel();
|
||||||
|
|
||||||
if (track == null)
|
if (Track == null)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (!hasStarted)
|
if (!hasStarted)
|
||||||
@ -95,7 +96,7 @@ namespace osu.Game.Audio
|
|||||||
|
|
||||||
hasStarted = false;
|
hasStarted = false;
|
||||||
|
|
||||||
track.Stop();
|
Track.Stop();
|
||||||
|
|
||||||
Stopped?.Invoke();
|
Stopped?.Invoke();
|
||||||
}
|
}
|
||||||
|
@ -55,6 +55,9 @@ namespace osu.Game.Audio
|
|||||||
|
|
||||||
track.Stopped += () => Schedule(() =>
|
track.Stopped += () => Schedule(() =>
|
||||||
{
|
{
|
||||||
|
if (current != track)
|
||||||
|
return;
|
||||||
|
|
||||||
current = null;
|
current = null;
|
||||||
audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
|
audio.Tracks.RemoveAdjustment(AdjustableProperty.Volume, muteBindable);
|
||||||
});
|
});
|
||||||
@ -85,7 +88,7 @@ namespace osu.Game.Audio
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
protected virtual TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TrackManagerPreviewTrack(beatmapSetInfo, trackStore);
|
protected virtual TrackManagerPreviewTrack CreatePreviewTrack(BeatmapSetInfo beatmapSetInfo, ITrackStore trackStore) => new TrackManagerPreviewTrack(beatmapSetInfo, trackStore);
|
||||||
|
|
||||||
protected class TrackManagerPreviewTrack : PreviewTrack
|
public class TrackManagerPreviewTrack : PreviewTrack
|
||||||
{
|
{
|
||||||
public IPreviewTrackOwner Owner { get; private set; }
|
public IPreviewTrackOwner Owner { get; private set; }
|
||||||
|
|
||||||
|
@ -102,8 +102,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
|
private readonly List<OverlayContainer> overlays = new List<OverlayContainer>();
|
||||||
|
|
||||||
private readonly List<VisibilityContainer> toolbarElements = new List<VisibilityContainer>();
|
|
||||||
|
|
||||||
private readonly List<OverlayContainer> visibleBlockingOverlays = new List<OverlayContainer>();
|
private readonly List<OverlayContainer> visibleBlockingOverlays = new List<OverlayContainer>();
|
||||||
|
|
||||||
public OsuGame(string[] args = null)
|
public OsuGame(string[] args = null)
|
||||||
@ -134,17 +132,13 @@ namespace osu.Game
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// Close all game-wide overlays.
|
/// Close all game-wide overlays.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
/// <param name="hideToolbarElements">Whether the toolbar (and accompanying controls) should also be hidden.</param>
|
/// <param name="hideToolbar">Whether the toolbar should also be hidden.</param>
|
||||||
public void CloseAllOverlays(bool hideToolbarElements = true)
|
public void CloseAllOverlays(bool hideToolbar = true)
|
||||||
{
|
{
|
||||||
foreach (var overlay in overlays)
|
foreach (var overlay in overlays)
|
||||||
overlay.Hide();
|
overlay.Hide();
|
||||||
|
|
||||||
if (hideToolbarElements)
|
if (hideToolbar) Toolbar.Hide();
|
||||||
{
|
|
||||||
foreach (var overlay in toolbarElements)
|
|
||||||
overlay.Hide();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private DependencyContainer dependencies;
|
private DependencyContainer dependencies;
|
||||||
@ -393,6 +387,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
protected virtual Loader CreateLoader() => new Loader();
|
protected virtual Loader CreateLoader() => new Loader();
|
||||||
|
|
||||||
|
protected override Container CreateScalingContainer() => new ScalingContainer(ScalingMode.Everything);
|
||||||
|
|
||||||
#region Beatmap progression
|
#region Beatmap progression
|
||||||
|
|
||||||
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> beatmap)
|
private void beatmapChanged(ValueChangedEvent<WorkingBeatmap> beatmap)
|
||||||
@ -572,11 +568,7 @@ namespace osu.Game
|
|||||||
CloseAllOverlays(false);
|
CloseAllOverlays(false);
|
||||||
menuScreen?.MakeCurrent();
|
menuScreen?.MakeCurrent();
|
||||||
},
|
},
|
||||||
}, d =>
|
}, topMostOverlayContent.Add);
|
||||||
{
|
|
||||||
topMostOverlayContent.Add(d);
|
|
||||||
toolbarElements.Add(d);
|
|
||||||
});
|
|
||||||
|
|
||||||
loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add, true);
|
loadComponentSingleFile(volume = new VolumeOverlay(), leftFloatingOverlayContent.Add, true);
|
||||||
|
|
||||||
@ -615,11 +607,7 @@ namespace osu.Game
|
|||||||
GetToolbarHeight = () => ToolbarOffset,
|
GetToolbarHeight = () => ToolbarOffset,
|
||||||
Anchor = Anchor.TopRight,
|
Anchor = Anchor.TopRight,
|
||||||
Origin = Anchor.TopRight,
|
Origin = Anchor.TopRight,
|
||||||
}, d =>
|
}, rightFloatingOverlayContent.Add, true);
|
||||||
{
|
|
||||||
rightFloatingOverlayContent.Add(d);
|
|
||||||
toolbarElements.Add(d);
|
|
||||||
}, true);
|
|
||||||
|
|
||||||
loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
|
loadComponentSingleFile(new AccountCreationOverlay(), topMostOverlayContent.Add, true);
|
||||||
loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true);
|
loadComponentSingleFile(new DialogOverlay(), topMostOverlayContent.Add, true);
|
||||||
@ -629,8 +617,8 @@ namespace osu.Game
|
|||||||
|
|
||||||
Add(externalLinkOpener = new ExternalLinkOpener());
|
Add(externalLinkOpener = new ExternalLinkOpener());
|
||||||
|
|
||||||
|
// side overlays which cancel each other.
|
||||||
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
|
var singleDisplaySideOverlays = new OverlayContainer[] { Settings, notifications };
|
||||||
overlays.AddRange(singleDisplaySideOverlays);
|
|
||||||
|
|
||||||
foreach (var overlay in singleDisplaySideOverlays)
|
foreach (var overlay in singleDisplaySideOverlays)
|
||||||
{
|
{
|
||||||
@ -644,7 +632,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
// eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time.
|
// eventually informational overlays should be displayed in a stack, but for now let's only allow one to stay open at a time.
|
||||||
var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile };
|
var informationalOverlays = new OverlayContainer[] { beatmapSetOverlay, userProfile };
|
||||||
overlays.AddRange(informationalOverlays);
|
|
||||||
|
|
||||||
foreach (var overlay in informationalOverlays)
|
foreach (var overlay in informationalOverlays)
|
||||||
{
|
{
|
||||||
@ -658,7 +645,6 @@ namespace osu.Game
|
|||||||
|
|
||||||
// ensure only one of these overlays are open at once.
|
// ensure only one of these overlays are open at once.
|
||||||
var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct, changelogOverlay };
|
var singleDisplayOverlays = new OverlayContainer[] { chatOverlay, social, direct, changelogOverlay };
|
||||||
overlays.AddRange(singleDisplayOverlays);
|
|
||||||
|
|
||||||
foreach (var overlay in singleDisplayOverlays)
|
foreach (var overlay in singleDisplayOverlays)
|
||||||
{
|
{
|
||||||
@ -759,6 +745,9 @@ namespace osu.Game
|
|||||||
if (cache)
|
if (cache)
|
||||||
dependencies.Cache(d);
|
dependencies.Cache(d);
|
||||||
|
|
||||||
|
if (d is OverlayContainer overlay)
|
||||||
|
overlays.Add(overlay);
|
||||||
|
|
||||||
// schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached).
|
// schedule is here to ensure that all component loads are done after LoadComplete is run (and thus all dependencies are cached).
|
||||||
// with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile,
|
// with some better organisation of LoadComplete to do construction and dependency caching in one step, followed by calls to loadComponentSingleFile,
|
||||||
// we could avoid the need for scheduling altogether.
|
// we could avoid the need for scheduling altogether.
|
||||||
|
@ -26,7 +26,6 @@ using osu.Framework.Input;
|
|||||||
using osu.Framework.Logging;
|
using osu.Framework.Logging;
|
||||||
using osu.Game.Audio;
|
using osu.Game.Audio;
|
||||||
using osu.Game.Database;
|
using osu.Game.Database;
|
||||||
using osu.Game.Graphics.Containers;
|
|
||||||
using osu.Game.Input;
|
using osu.Game.Input;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.IO;
|
using osu.Game.IO;
|
||||||
@ -228,7 +227,7 @@ namespace osu.Game
|
|||||||
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
|
Child = content = new OsuTooltipContainer(MenuCursorContainer.Cursor) { RelativeSizeAxes = Axes.Both }
|
||||||
};
|
};
|
||||||
|
|
||||||
base.Content.Add(new ScalingContainer(ScalingMode.Everything) { Child = MenuCursorContainer });
|
base.Content.Add(CreateScalingContainer().WithChild(MenuCursorContainer));
|
||||||
|
|
||||||
KeyBindingStore.Register(globalBinding);
|
KeyBindingStore.Register(globalBinding);
|
||||||
dependencies.Cache(globalBinding);
|
dependencies.Cache(globalBinding);
|
||||||
@ -238,6 +237,8 @@ namespace osu.Game
|
|||||||
Add(previewTrackManager);
|
Add(previewTrackManager);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected virtual Container CreateScalingContainer() => new DrawSizePreservingFillContainer();
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
{
|
{
|
||||||
base.LoadComplete();
|
base.LoadComplete();
|
||||||
|
@ -1,11 +1,12 @@
|
|||||||
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
|
// 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.
|
// See the LICENCE file in the repository root for full licence text.
|
||||||
|
|
||||||
|
using System;
|
||||||
using osu.Framework.Configuration.Tracking;
|
using osu.Framework.Configuration.Tracking;
|
||||||
|
|
||||||
namespace osu.Game.Rulesets.Configuration
|
namespace osu.Game.Rulesets.Configuration
|
||||||
{
|
{
|
||||||
public interface IRulesetConfigManager : ITrackableConfigManager
|
public interface IRulesetConfigManager : ITrackableConfigManager, IDisposable
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Game.Graphics.UserInterface;
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -104,6 +105,11 @@ namespace osu.Game.Rulesets.Edit
|
|||||||
|
|
||||||
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.ReceivePositionalInputAt(screenSpacePos);
|
public override bool ReceivePositionalInputAt(Vector2 screenSpacePos) => DrawableObject.ReceivePositionalInputAt(screenSpacePos);
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// The <see cref="MenuItem"/>s to be displayed in the context menu for this <see cref="SelectionBlueprint"/>.
|
||||||
|
/// </summary>
|
||||||
|
public virtual MenuItem[] ContextMenuItems => Array.Empty<MenuItem>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The screen-space point that causes this <see cref="SelectionBlueprint"/> to be selected.
|
/// The screen-space point that causes this <see cref="SelectionBlueprint"/> to be selected.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -34,7 +34,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
// Todo: Rulesets should be overriding the resources instead, but we need to figure out where/when to apply overrides first
|
// Todo: Rulesets should be overriding the resources instead, but we need to figure out where/when to apply overrides first
|
||||||
protected virtual string SampleNamespace => null;
|
protected virtual string SampleNamespace => null;
|
||||||
|
|
||||||
protected SkinnableSound Samples;
|
protected SkinnableSound Samples { get; private set; }
|
||||||
|
|
||||||
protected virtual IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples;
|
protected virtual IEnumerable<HitSampleInfo> GetSamples() => HitObject.Samples;
|
||||||
|
|
||||||
@ -78,6 +78,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
/// </summary>
|
/// </summary>
|
||||||
public JudgementResult Result { get; private set; }
|
public JudgementResult Result { get; private set; }
|
||||||
|
|
||||||
|
private BindableList<HitSampleInfo> samplesBindable;
|
||||||
private Bindable<double> startTimeBindable;
|
private Bindable<double> startTimeBindable;
|
||||||
private Bindable<int> comboIndexBindable;
|
private Bindable<int> comboIndexBindable;
|
||||||
|
|
||||||
@ -108,22 +109,7 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
throw new InvalidOperationException($"{GetType().ReadableName()} must provide a {nameof(JudgementResult)} through {nameof(CreateResult)}.");
|
||||||
}
|
}
|
||||||
|
|
||||||
var samples = GetSamples().ToArray();
|
loadSamples();
|
||||||
|
|
||||||
if (samples.Length > 0)
|
|
||||||
{
|
|
||||||
if (HitObject.SampleControlPoint == null)
|
|
||||||
{
|
|
||||||
throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}."
|
|
||||||
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
|
||||||
}
|
|
||||||
|
|
||||||
samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray();
|
|
||||||
foreach (var s in samples)
|
|
||||||
s.Namespace = SampleNamespace;
|
|
||||||
|
|
||||||
AddInternal(Samples = new SkinnableSound(samples));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override void LoadComplete()
|
protected override void LoadComplete()
|
||||||
@ -141,10 +127,40 @@ namespace osu.Game.Rulesets.Objects.Drawables
|
|||||||
comboIndexBindable.BindValueChanged(_ => updateAccentColour(), true);
|
comboIndexBindable.BindValueChanged(_ => updateAccentColour(), true);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
samplesBindable = HitObject.SamplesBindable.GetBoundCopy();
|
||||||
|
samplesBindable.ItemsAdded += _ => loadSamples();
|
||||||
|
samplesBindable.ItemsRemoved += _ => loadSamples();
|
||||||
|
|
||||||
updateState(ArmedState.Idle, true);
|
updateState(ArmedState.Idle, true);
|
||||||
onDefaultsApplied();
|
onDefaultsApplied();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void loadSamples()
|
||||||
|
{
|
||||||
|
if (Samples != null)
|
||||||
|
{
|
||||||
|
RemoveInternal(Samples);
|
||||||
|
Samples = null;
|
||||||
|
}
|
||||||
|
|
||||||
|
var samples = GetSamples().ToArray();
|
||||||
|
|
||||||
|
if (samples.Length <= 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (HitObject.SampleControlPoint == null)
|
||||||
|
{
|
||||||
|
throw new ArgumentNullException(nameof(HitObject.SampleControlPoint), $"{nameof(HitObject)}s must always have an attached {nameof(HitObject.SampleControlPoint)}."
|
||||||
|
+ $" This is an indication that {nameof(HitObject.ApplyDefaults)} has not been invoked on {this}.");
|
||||||
|
}
|
||||||
|
|
||||||
|
samples = samples.Select(s => HitObject.SampleControlPoint.ApplyTo(s)).ToArray();
|
||||||
|
foreach (var s in samples)
|
||||||
|
s.Namespace = SampleNamespace;
|
||||||
|
|
||||||
|
AddInternal(Samples = new SkinnableSound(samples));
|
||||||
|
}
|
||||||
|
|
||||||
private void onDefaultsApplied() => apply(HitObject);
|
private void onDefaultsApplied() => apply(HitObject);
|
||||||
|
|
||||||
private void apply(HitObject hitObject)
|
private void apply(HitObject hitObject)
|
||||||
|
@ -45,7 +45,7 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
set => StartTimeBindable.Value = value;
|
set => StartTimeBindable.Value = value;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<HitSampleInfo> samples;
|
public readonly BindableList<HitSampleInfo> SamplesBindable = new BindableList<HitSampleInfo>();
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The samples to be played when this hit object is hit.
|
/// The samples to be played when this hit object is hit.
|
||||||
@ -54,10 +54,14 @@ namespace osu.Game.Rulesets.Objects
|
|||||||
/// and can be treated as the default samples for the hit object.
|
/// and can be treated as the default samples for the hit object.
|
||||||
/// </para>
|
/// </para>
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public List<HitSampleInfo> Samples
|
public IList<HitSampleInfo> Samples
|
||||||
{
|
{
|
||||||
get => samples ?? (samples = new List<HitSampleInfo>());
|
get => SamplesBindable;
|
||||||
set => samples = value;
|
set
|
||||||
|
{
|
||||||
|
SamplesBindable.Clear();
|
||||||
|
SamplesBindable.AddRange(value);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
[JsonIgnore]
|
[JsonIgnore]
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Catch
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
||||||
List<List<HitSampleInfo>> nodeSamples)
|
List<IList<HitSampleInfo>> nodeSamples)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
newCombo |= forceNewCombo;
|
||||||
comboOffset += extraComboOffset;
|
comboOffset += extraComboOffset;
|
||||||
|
@ -184,7 +184,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Generate the final per-node samples
|
// Generate the final per-node samples
|
||||||
var nodeSamples = new List<List<HitSampleInfo>>(nodes);
|
var nodeSamples = new List<IList<HitSampleInfo>>(nodes);
|
||||||
for (int i = 0; i < nodes; i++)
|
for (int i = 0; i < nodes; i++)
|
||||||
nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]));
|
nodeSamples.Add(convertSoundType(nodeSoundTypes[i], nodeBankInfos[i]));
|
||||||
|
|
||||||
@ -282,7 +282,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
/// <param name="nodeSamples">The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.</param>
|
/// <param name="nodeSamples">The samples to be played when the slider nodes are hit. This includes the head and tail of the slider.</param>
|
||||||
/// <returns>The hit object.</returns>
|
/// <returns>The hit object.</returns>
|
||||||
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
protected abstract HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
||||||
List<List<HitSampleInfo>> nodeSamples);
|
List<IList<HitSampleInfo>> nodeSamples);
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a legacy Spinner-type hit object.
|
/// Creates a legacy Spinner-type hit object.
|
||||||
|
@ -23,7 +23,7 @@ namespace osu.Game.Rulesets.Objects.Legacy
|
|||||||
|
|
||||||
public double Distance => Path.Distance;
|
public double Distance => Path.Distance;
|
||||||
|
|
||||||
public List<List<HitSampleInfo>> NodeSamples { get; set; }
|
public List<IList<HitSampleInfo>> NodeSamples { get; set; }
|
||||||
public int RepeatCount { get; set; }
|
public int RepeatCount { get; set; }
|
||||||
|
|
||||||
public double EndTime => StartTime + this.SpanCount() * Distance / Velocity;
|
public double EndTime => StartTime + this.SpanCount() * Distance / Velocity;
|
||||||
|
@ -27,7 +27,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Mania
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
||||||
List<List<HitSampleInfo>> nodeSamples)
|
List<IList<HitSampleInfo>> nodeSamples)
|
||||||
{
|
{
|
||||||
return new ConvertSlider
|
return new ConvertSlider
|
||||||
{
|
{
|
||||||
|
@ -38,7 +38,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Osu
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
||||||
List<List<HitSampleInfo>> nodeSamples)
|
List<IList<HitSampleInfo>> nodeSamples)
|
||||||
{
|
{
|
||||||
newCombo |= forceNewCombo;
|
newCombo |= forceNewCombo;
|
||||||
comboOffset += extraComboOffset;
|
comboOffset += extraComboOffset;
|
||||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Rulesets.Objects.Legacy.Taiko
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
protected override HitObject CreateSlider(Vector2 position, bool newCombo, int comboOffset, Vector2[] controlPoints, double? length, PathType pathType, int repeatCount,
|
||||||
List<List<HitSampleInfo>> nodeSamples)
|
List<IList<HitSampleInfo>> nodeSamples)
|
||||||
{
|
{
|
||||||
return new ConvertSlider
|
return new ConvertSlider
|
||||||
{
|
{
|
||||||
|
@ -25,7 +25,7 @@ namespace osu.Game.Rulesets.Objects.Types
|
|||||||
/// n-1: The last repeat.<br />
|
/// n-1: The last repeat.<br />
|
||||||
/// n: The last node.
|
/// n: The last node.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
List<List<HitSampleInfo>> NodeSamples { get; }
|
List<IList<HitSampleInfo>> NodeSamples { get; }
|
||||||
}
|
}
|
||||||
|
|
||||||
public static class HasRepeatsExtensions
|
public static class HasRepeatsExtensions
|
||||||
|
@ -43,7 +43,7 @@ namespace osu.Game.Rulesets
|
|||||||
|
|
||||||
// ensures any potential database operations are finalised before game destruction.
|
// ensures any potential database operations are finalised before game destruction.
|
||||||
foreach (var c in configCache.Values)
|
foreach (var c in configCache.Values)
|
||||||
(c as IDisposable)?.Dispose();
|
c?.Dispose();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ using osu.Framework.Graphics;
|
|||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Primitives;
|
using osu.Framework.Graphics.Primitives;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.Events;
|
using osu.Framework.Input.Events;
|
||||||
using osu.Framework.Timing;
|
using osu.Framework.Timing;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
@ -17,10 +18,11 @@ using osu.Game.Rulesets.Edit.Tools;
|
|||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
using osuTK;
|
using osuTK;
|
||||||
|
using osuTK.Input;
|
||||||
|
|
||||||
namespace osu.Game.Screens.Edit.Compose.Components
|
namespace osu.Game.Screens.Edit.Compose.Components
|
||||||
{
|
{
|
||||||
public class BlueprintContainer : CompositeDrawable
|
public class BlueprintContainer : CompositeDrawable, IKeyBindingHandler<PlatformAction>
|
||||||
{
|
{
|
||||||
public event Action<IEnumerable<HitObject>> SelectionChanged;
|
public event Action<IEnumerable<HitObject>> SelectionChanged;
|
||||||
|
|
||||||
@ -96,11 +98,14 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
protected override bool OnMouseDown(MouseDownEvent e)
|
protected override bool OnMouseDown(MouseDownEvent e)
|
||||||
{
|
{
|
||||||
beginClickSelection(e);
|
beginClickSelection(e);
|
||||||
return true;
|
return e.Button == MouseButton.Left;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnClick(ClickEvent e)
|
protected override bool OnClick(ClickEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.Button == MouseButton.Right)
|
||||||
|
return false;
|
||||||
|
|
||||||
// Deselection should only occur if no selected blueprints are hovered
|
// Deselection should only occur if no selected blueprints are hovered
|
||||||
// A special case for when a blueprint was selected via this click is added since OnClick() may occur outside the hitobject and should not trigger deselection
|
// A special case for when a blueprint was selected via this click is added since OnClick() may occur outside the hitobject and should not trigger deselection
|
||||||
if (endClickSelection() || selectionHandler.SelectedBlueprints.Any(b => b.IsHovered))
|
if (endClickSelection() || selectionHandler.SelectedBlueprints.Any(b => b.IsHovered))
|
||||||
@ -112,6 +117,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected override bool OnDoubleClick(DoubleClickEvent e)
|
protected override bool OnDoubleClick(DoubleClickEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.Button == MouseButton.Right)
|
||||||
|
return false;
|
||||||
|
|
||||||
SelectionBlueprint clickedBlueprint = selectionHandler.SelectedBlueprints.FirstOrDefault(b => b.IsHovered);
|
SelectionBlueprint clickedBlueprint = selectionHandler.SelectedBlueprints.FirstOrDefault(b => b.IsHovered);
|
||||||
|
|
||||||
if (clickedBlueprint == null)
|
if (clickedBlueprint == null)
|
||||||
@ -125,7 +133,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
{
|
{
|
||||||
// Special case for when a drag happened instead of a click
|
// Special case for when a drag happened instead of a click
|
||||||
Schedule(() => endClickSelection());
|
Schedule(() => endClickSelection());
|
||||||
return true;
|
return e.Button == MouseButton.Left;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected override bool OnMouseMove(MouseMoveEvent e)
|
protected override bool OnMouseMove(MouseMoveEvent e)
|
||||||
@ -141,6 +149,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected override bool OnDragStart(DragStartEvent e)
|
protected override bool OnDragStart(DragStartEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.Button == MouseButton.Right)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!beginSelectionMovement())
|
if (!beginSelectionMovement())
|
||||||
{
|
{
|
||||||
dragBox.UpdateDrag(e);
|
dragBox.UpdateDrag(e);
|
||||||
@ -152,6 +163,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected override bool OnDrag(DragEvent e)
|
protected override bool OnDrag(DragEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.Button == MouseButton.Right)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!moveCurrentSelection(e))
|
if (!moveCurrentSelection(e))
|
||||||
dragBox.UpdateDrag(e);
|
dragBox.UpdateDrag(e);
|
||||||
|
|
||||||
@ -160,6 +174,9 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
|
|
||||||
protected override bool OnDragEnd(DragEndEvent e)
|
protected override bool OnDragEnd(DragEndEvent e)
|
||||||
{
|
{
|
||||||
|
if (e.Button == MouseButton.Right)
|
||||||
|
return false;
|
||||||
|
|
||||||
if (!finishSelectionMovement())
|
if (!finishSelectionMovement())
|
||||||
{
|
{
|
||||||
dragBox.FadeOut(250, Easing.OutQuint);
|
dragBox.FadeOut(250, Easing.OutQuint);
|
||||||
@ -169,6 +186,37 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyDown(KeyDownEvent e)
|
||||||
|
{
|
||||||
|
switch (e.Key)
|
||||||
|
{
|
||||||
|
case Key.Escape:
|
||||||
|
if (!selectionHandler.SelectedBlueprints.Any())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
deselectAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
protected override bool OnKeyUp(KeyUpEvent e) => false;
|
||||||
|
|
||||||
|
public bool OnPressed(PlatformAction action)
|
||||||
|
{
|
||||||
|
switch (action.ActionType)
|
||||||
|
{
|
||||||
|
case PlatformActionType.SelectAll:
|
||||||
|
selectAll();
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
public bool OnReleased(PlatformAction action) => false;
|
||||||
|
|
||||||
protected override void Update()
|
protected override void Update()
|
||||||
{
|
{
|
||||||
base.Update();
|
base.Update();
|
||||||
@ -314,6 +362,15 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Selects all <see cref="SelectionBlueprint"/>s.
|
||||||
|
/// </summary>
|
||||||
|
private void selectAll()
|
||||||
|
{
|
||||||
|
selectionBlueprints.ToList().ForEach(m => m.Select());
|
||||||
|
selectionHandler.UpdateVisibility();
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Deselects all selected <see cref="SelectionBlueprint"/>s.
|
/// Deselects all selected <see cref="SelectionBlueprint"/>s.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
@ -7,11 +7,15 @@ using System.Linq;
|
|||||||
using osu.Framework.Allocation;
|
using osu.Framework.Allocation;
|
||||||
using osu.Framework.Graphics;
|
using osu.Framework.Graphics;
|
||||||
using osu.Framework.Graphics.Containers;
|
using osu.Framework.Graphics.Containers;
|
||||||
|
using osu.Framework.Graphics.Cursor;
|
||||||
using osu.Framework.Graphics.Shapes;
|
using osu.Framework.Graphics.Shapes;
|
||||||
|
using osu.Framework.Graphics.UserInterface;
|
||||||
using osu.Framework.Input;
|
using osu.Framework.Input;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
using osu.Framework.Input.States;
|
using osu.Framework.Input.States;
|
||||||
|
using osu.Game.Audio;
|
||||||
using osu.Game.Graphics;
|
using osu.Game.Graphics;
|
||||||
|
using osu.Game.Graphics.UserInterface;
|
||||||
using osu.Game.Rulesets.Edit;
|
using osu.Game.Rulesets.Edit;
|
||||||
using osu.Game.Rulesets.Objects;
|
using osu.Game.Rulesets.Objects;
|
||||||
using osu.Game.Rulesets.Objects.Drawables;
|
using osu.Game.Rulesets.Objects.Drawables;
|
||||||
@ -22,7 +26,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// A component which outlines <see cref="DrawableHitObject"/>s and handles movement of selections.
|
/// A component which outlines <see cref="DrawableHitObject"/>s and handles movement of selections.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public class SelectionHandler : CompositeDrawable, IKeyBindingHandler<PlatformAction>
|
public class SelectionHandler : CompositeDrawable, IKeyBindingHandler<PlatformAction>, IHasContextMenu
|
||||||
{
|
{
|
||||||
public const float BORDER_RADIUS = 2;
|
public const float BORDER_RADIUS = 2;
|
||||||
|
|
||||||
@ -76,8 +80,7 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
switch (action.ActionMethod)
|
switch (action.ActionMethod)
|
||||||
{
|
{
|
||||||
case PlatformActionMethod.Delete:
|
case PlatformActionMethod.Delete:
|
||||||
foreach (var h in selectedBlueprints.ToList())
|
deleteSelected();
|
||||||
placementHandler.Delete(h.DrawableObject.HitObject);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -140,8 +143,16 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
UpdateVisibility();
|
UpdateVisibility();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void deleteSelected()
|
||||||
|
{
|
||||||
|
foreach (var h in selectedBlueprints.ToList())
|
||||||
|
placementHandler.Delete(h.DrawableObject.HitObject);
|
||||||
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
#region Outline Display
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Updates whether this <see cref="SelectionHandler"/> is visible.
|
/// Updates whether this <see cref="SelectionHandler"/> is visible.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
@ -176,5 +187,104 @@ namespace osu.Game.Screens.Edit.Compose.Components
|
|||||||
outline.Size = bottomRight - topLeft;
|
outline.Size = bottomRight - topLeft;
|
||||||
outline.Position = topLeft;
|
outline.Position = topLeft;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Sample Changes
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Adds a hit sample to all selected <see cref="HitObject"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sampleName">The name of the hit sample.</param>
|
||||||
|
public void AddHitSample(string sampleName)
|
||||||
|
{
|
||||||
|
foreach (var h in SelectedHitObjects)
|
||||||
|
{
|
||||||
|
// Make sure there isn't already an existing sample
|
||||||
|
if (h.Samples.Any(s => s.Name == sampleName))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
h.Samples.Add(new HitSampleInfo { Name = sampleName });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// Removes a hit sample from all selected <see cref="HitObject"/>s.
|
||||||
|
/// </summary>
|
||||||
|
/// <param name="sampleName">The name of the hit sample.</param>
|
||||||
|
public void RemoveHitSample(string sampleName)
|
||||||
|
{
|
||||||
|
foreach (var h in SelectedHitObjects)
|
||||||
|
h.SamplesBindable.RemoveAll(s => s.Name == sampleName);
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
#region Context Menu
|
||||||
|
|
||||||
|
public virtual MenuItem[] ContextMenuItems
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
if (!selectedBlueprints.Any(b => b.IsHovered))
|
||||||
|
return Array.Empty<MenuItem>();
|
||||||
|
|
||||||
|
var items = new List<MenuItem>
|
||||||
|
{
|
||||||
|
new OsuMenuItem("Sound")
|
||||||
|
{
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
createHitSampleMenuItem("Whistle", HitSampleInfo.HIT_WHISTLE),
|
||||||
|
createHitSampleMenuItem("Clap", HitSampleInfo.HIT_CLAP),
|
||||||
|
createHitSampleMenuItem("Finish", HitSampleInfo.HIT_FINISH)
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new OsuMenuItem("Delete", MenuItemType.Destructive, deleteSelected),
|
||||||
|
};
|
||||||
|
|
||||||
|
if (selectedBlueprints.Count == 1)
|
||||||
|
items.AddRange(selectedBlueprints[0].ContextMenuItems);
|
||||||
|
|
||||||
|
return items.ToArray();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private MenuItem createHitSampleMenuItem(string name, string sampleName)
|
||||||
|
{
|
||||||
|
return new TernaryStateMenuItem(name, MenuItemType.Standard, setHitSampleState)
|
||||||
|
{
|
||||||
|
State = { Value = getHitSampleState() }
|
||||||
|
};
|
||||||
|
|
||||||
|
void setHitSampleState(TernaryState state)
|
||||||
|
{
|
||||||
|
switch (state)
|
||||||
|
{
|
||||||
|
case TernaryState.False:
|
||||||
|
RemoveHitSample(sampleName);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TernaryState.True:
|
||||||
|
AddHitSample(sampleName);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TernaryState getHitSampleState()
|
||||||
|
{
|
||||||
|
int countExisting = SelectedHitObjects.Count(h => h.Samples.Any(s => s.Name == sampleName));
|
||||||
|
|
||||||
|
if (countExisting == 0)
|
||||||
|
return TernaryState.False;
|
||||||
|
|
||||||
|
if (countExisting < SelectedHitObjects.Count())
|
||||||
|
return TernaryState.Indeterminate;
|
||||||
|
|
||||||
|
return TernaryState.True;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#endregion
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -24,6 +24,7 @@ using osuTK.Input;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using osu.Framework;
|
using osu.Framework;
|
||||||
using osu.Framework.Input.Bindings;
|
using osu.Framework.Input.Bindings;
|
||||||
|
using osu.Game.Graphics.Cursor;
|
||||||
using osu.Game.Input.Bindings;
|
using osu.Game.Input.Bindings;
|
||||||
using osu.Game.Screens.Edit.Compose;
|
using osu.Game.Screens.Edit.Compose;
|
||||||
using osu.Game.Screens.Edit.Setup;
|
using osu.Game.Screens.Edit.Setup;
|
||||||
@ -90,87 +91,91 @@ namespace osu.Game.Screens.Edit
|
|||||||
|
|
||||||
fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit));
|
fileMenuItems.Add(new EditorMenuItem("Exit", MenuItemType.Standard, this.Exit));
|
||||||
|
|
||||||
InternalChildren = new[]
|
InternalChild = new OsuContextMenuContainer
|
||||||
{
|
{
|
||||||
new Container
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Children = new[]
|
||||||
{
|
{
|
||||||
Name = "Screen container",
|
new Container
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding { Top = 40, Bottom = 60 },
|
|
||||||
Child = screenContainer = new Container
|
|
||||||
{
|
{
|
||||||
|
Name = "Screen container",
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Masking = true
|
Padding = new MarginPadding { Top = 40, Bottom = 60 },
|
||||||
}
|
Child = screenContainer = new Container
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Name = "Top bar",
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 40,
|
|
||||||
Child = menuBar = new EditorMenuBar
|
|
||||||
{
|
|
||||||
Anchor = Anchor.CentreLeft,
|
|
||||||
Origin = Anchor.CentreLeft,
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Items = new[]
|
|
||||||
{
|
|
||||||
new MenuItem("File")
|
|
||||||
{
|
|
||||||
Items = fileMenuItems
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
Name = "Bottom bar",
|
|
||||||
Anchor = Anchor.BottomLeft,
|
|
||||||
Origin = Anchor.BottomLeft,
|
|
||||||
RelativeSizeAxes = Axes.X,
|
|
||||||
Height = 60,
|
|
||||||
Children = new Drawable[]
|
|
||||||
{
|
|
||||||
bottomBackground = new Box { RelativeSizeAxes = Axes.Both },
|
|
||||||
new Container
|
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
Padding = new MarginPadding { Vertical = 5, Horizontal = 10 },
|
Masking = true
|
||||||
Child = new GridContainer
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = "Top bar",
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 40,
|
||||||
|
Child = menuBar = new EditorMenuBar
|
||||||
|
{
|
||||||
|
Anchor = Anchor.CentreLeft,
|
||||||
|
Origin = Anchor.CentreLeft,
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Items = new[]
|
||||||
|
{
|
||||||
|
new MenuItem("File")
|
||||||
|
{
|
||||||
|
Items = fileMenuItems
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
Name = "Bottom bar",
|
||||||
|
Anchor = Anchor.BottomLeft,
|
||||||
|
Origin = Anchor.BottomLeft,
|
||||||
|
RelativeSizeAxes = Axes.X,
|
||||||
|
Height = 60,
|
||||||
|
Children = new Drawable[]
|
||||||
|
{
|
||||||
|
bottomBackground = new Box { RelativeSizeAxes = Axes.Both },
|
||||||
|
new Container
|
||||||
{
|
{
|
||||||
RelativeSizeAxes = Axes.Both,
|
RelativeSizeAxes = Axes.Both,
|
||||||
ColumnDimensions = new[]
|
Padding = new MarginPadding { Vertical = 5, Horizontal = 10 },
|
||||||
|
Child = new GridContainer
|
||||||
{
|
{
|
||||||
new Dimension(GridSizeMode.Absolute, 220),
|
RelativeSizeAxes = Axes.Both,
|
||||||
new Dimension(),
|
ColumnDimensions = new[]
|
||||||
new Dimension(GridSizeMode.Absolute, 220)
|
|
||||||
},
|
|
||||||
Content = new[]
|
|
||||||
{
|
|
||||||
new Drawable[]
|
|
||||||
{
|
{
|
||||||
new Container
|
new Dimension(GridSizeMode.Absolute, 220),
|
||||||
{
|
new Dimension(),
|
||||||
RelativeSizeAxes = Axes.Both,
|
new Dimension(GridSizeMode.Absolute, 220)
|
||||||
Padding = new MarginPadding { Right = 10 },
|
|
||||||
Child = new TimeInfoContainer { RelativeSizeAxes = Axes.Both },
|
|
||||||
},
|
|
||||||
new SummaryTimeline
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
},
|
|
||||||
new Container
|
|
||||||
{
|
|
||||||
RelativeSizeAxes = Axes.Both,
|
|
||||||
Padding = new MarginPadding { Left = 10 },
|
|
||||||
Child = new PlaybackControl { RelativeSizeAxes = Axes.Both },
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
}
|
Content = new[]
|
||||||
},
|
{
|
||||||
|
new Drawable[]
|
||||||
|
{
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Right = 10 },
|
||||||
|
Child = new TimeInfoContainer { RelativeSizeAxes = Axes.Both },
|
||||||
|
},
|
||||||
|
new SummaryTimeline
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
},
|
||||||
|
new Container
|
||||||
|
{
|
||||||
|
RelativeSizeAxes = Axes.Both,
|
||||||
|
Padding = new MarginPadding { Left = 10 },
|
||||||
|
Child = new PlaybackControl { RelativeSizeAxes = Axes.Both },
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
},
|
||||||
},
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
menuBar.Mode.ValueChanged += onModeChanged;
|
menuBar.Mode.ValueChanged += onModeChanged;
|
||||||
|
@ -10,6 +10,8 @@ using osu.Framework.Allocation;
|
|||||||
using osu.Framework.Audio;
|
using osu.Framework.Audio;
|
||||||
using osu.Framework.Audio.Track;
|
using osu.Framework.Audio.Track;
|
||||||
using osu.Framework.Bindables;
|
using osu.Framework.Bindables;
|
||||||
|
using osu.Framework.Graphics;
|
||||||
|
using osu.Framework.Graphics.Containers;
|
||||||
using osu.Framework.Graphics.Textures;
|
using osu.Framework.Graphics.Textures;
|
||||||
using osu.Framework.Platform;
|
using osu.Framework.Platform;
|
||||||
using osu.Framework.Testing;
|
using osu.Framework.Testing;
|
||||||
@ -93,6 +95,10 @@ namespace osu.Game.Tests.Visual
|
|||||||
return Dependencies;
|
return Dependencies;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
protected override Container<Drawable> Content => content ?? base.Content;
|
||||||
|
|
||||||
|
private readonly Container content;
|
||||||
|
|
||||||
protected OsuTestScene()
|
protected OsuTestScene()
|
||||||
{
|
{
|
||||||
localStorage = new Lazy<Storage>(() => new NativeStorage($"{GetType().Name}-{Guid.NewGuid()}"));
|
localStorage = new Lazy<Storage>(() => new NativeStorage($"{GetType().Name}-{Guid.NewGuid()}"));
|
||||||
@ -104,6 +110,8 @@ namespace osu.Game.Tests.Visual
|
|||||||
usage.Migrate();
|
usage.Migrate();
|
||||||
return factory;
|
return factory;
|
||||||
});
|
});
|
||||||
|
|
||||||
|
base.Content.Add(content = new DrawSizePreservingFillContainer());
|
||||||
}
|
}
|
||||||
|
|
||||||
[Resolved]
|
[Resolved]
|
||||||
|
@ -21,7 +21,7 @@
|
|||||||
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.6" />
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
<PackageReference Include="Newtonsoft.Json" Version="12.0.3" />
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework" Version="2019.1108.0" />
|
<PackageReference Include="ppy.osu.Framework" Version="2019.1112.0" />
|
||||||
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
<PackageReference Include="SharpCompress" Version="0.24.0" />
|
||||||
<PackageReference Include="NUnit" Version="3.12.0" />
|
<PackageReference Include="NUnit" Version="3.12.0" />
|
||||||
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
<PackageReference Include="SharpRaven" Version="2.4.0" />
|
||||||
|
@ -73,6 +73,6 @@
|
|||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup Label="Package References">
|
<ItemGroup Label="Package References">
|
||||||
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.1010.0" />
|
||||||
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.1108.0" />
|
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.1112.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
||||||
|
Loading…
Reference in New Issue
Block a user