1
0
mirror of https://github.com/ppy/osu.git synced 2024-09-22 01:27:29 +08:00

Merge remote-tracking branch 'upstream/master' into user-status-wiring

This commit is contained in:
Lucas A 2019-05-25 11:02:19 +02:00
commit a819dd764f
57 changed files with 674 additions and 343 deletions

View File

@ -35,7 +35,7 @@ platform :ios do
changelog.gsub!('$BUILD_ID', options[:build])
pilot(
wait_processing_interval: 900,
wait_processing_interval: 1800,
changelog: changelog,
ipa: './osu.iOS/bin/iPhone/Release/osu.iOS.ipa'
)

View File

@ -2,8 +2,8 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>

View File

@ -11,10 +11,10 @@ using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Game.Beatmaps;
using osu.Game.Beatmaps.ControlPoints;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets.Mania.Objects;
using osu.Game.Rulesets.Mania.Objects.Drawables;
using osu.Game.Rulesets.Objects.Drawables;
@ -138,7 +138,7 @@ namespace osu.Game.Rulesets.Mania.Tests
content = new Container { RelativeSizeAxes = Axes.Both }
}
},
new SpriteText
new OsuSpriteText
{
Anchor = Anchor.TopCentre,
Origin = Anchor.TopCentre,

View File

@ -2,8 +2,8 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>

View File

@ -2,8 +2,8 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>

View File

@ -2,8 +2,8 @@
<Import Project="..\osu.TestProject.props" />
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>

View File

@ -170,27 +170,98 @@ namespace osu.Game.Tests.Beatmaps.Formats
var controlPoints = beatmap.ControlPointInfo;
Assert.AreEqual(4, controlPoints.TimingPoints.Count);
var timingPoint = controlPoints.TimingPoints[0];
Assert.AreEqual(42, controlPoints.DifficultyPoints.Count);
Assert.AreEqual(42, controlPoints.SamplePoints.Count);
Assert.AreEqual(42, controlPoints.EffectPoints.Count);
var timingPoint = controlPoints.TimingPointAt(0);
Assert.AreEqual(956, timingPoint.Time);
Assert.AreEqual(329.67032967033, timingPoint.BeatLength);
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
timingPoint = controlPoints.TimingPointAt(48428);
Assert.AreEqual(956, timingPoint.Time);
Assert.AreEqual(329.67032967033d, timingPoint.BeatLength);
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
Assert.AreEqual(5, controlPoints.DifficultyPoints.Count);
var difficultyPoint = controlPoints.DifficultyPoints[0];
Assert.AreEqual(116999, difficultyPoint.Time);
Assert.AreEqual(0.75000000000000189d, difficultyPoint.SpeedMultiplier);
timingPoint = controlPoints.TimingPointAt(119637);
Assert.AreEqual(119637, timingPoint.Time);
Assert.AreEqual(659.340659340659, timingPoint.BeatLength);
Assert.AreEqual(TimeSignatures.SimpleQuadruple, timingPoint.TimeSignature);
Assert.AreEqual(34, controlPoints.SamplePoints.Count);
var soundPoint = controlPoints.SamplePoints[0];
var difficultyPoint = controlPoints.DifficultyPointAt(0);
Assert.AreEqual(0, difficultyPoint.Time);
Assert.AreEqual(1.0, difficultyPoint.SpeedMultiplier);
difficultyPoint = controlPoints.DifficultyPointAt(48428);
Assert.AreEqual(48428, difficultyPoint.Time);
Assert.AreEqual(1.0, difficultyPoint.SpeedMultiplier);
difficultyPoint = controlPoints.DifficultyPointAt(116999);
Assert.AreEqual(116999, difficultyPoint.Time);
Assert.AreEqual(0.75, difficultyPoint.SpeedMultiplier, 0.1);
var soundPoint = controlPoints.SamplePointAt(0);
Assert.AreEqual(956, soundPoint.Time);
Assert.AreEqual("soft", soundPoint.SampleBank);
Assert.AreEqual(60, soundPoint.SampleVolume);
Assert.AreEqual(8, controlPoints.EffectPoints.Count);
var effectPoint = controlPoints.EffectPoints[0];
soundPoint = controlPoints.SamplePointAt(53373);
Assert.AreEqual(53373, soundPoint.Time);
Assert.AreEqual("soft", soundPoint.SampleBank);
Assert.AreEqual(60, soundPoint.SampleVolume);
soundPoint = controlPoints.SamplePointAt(119637);
Assert.AreEqual(119637, soundPoint.Time);
Assert.AreEqual("soft", soundPoint.SampleBank);
Assert.AreEqual(80, soundPoint.SampleVolume);
var effectPoint = controlPoints.EffectPointAt(0);
Assert.AreEqual(0, effectPoint.Time);
Assert.IsFalse(effectPoint.KiaiMode);
Assert.IsFalse(effectPoint.OmitFirstBarLine);
effectPoint = controlPoints.EffectPointAt(53703);
Assert.AreEqual(53703, effectPoint.Time);
Assert.IsTrue(effectPoint.KiaiMode);
Assert.IsFalse(effectPoint.OmitFirstBarLine);
effectPoint = controlPoints.EffectPointAt(119637);
Assert.AreEqual(119637, effectPoint.Time);
Assert.IsFalse(effectPoint.KiaiMode);
Assert.IsFalse(effectPoint.OmitFirstBarLine);
}
}
[Test]
public void TestDecodeOverlappingTimingPoints()
{
var decoder = new LegacyBeatmapDecoder { ApplyOffsets = false };
using (var resStream = TestResources.OpenResource("overlapping-control-points.osu"))
using (var stream = new StreamReader(resStream))
{
var controlPoints = decoder.Decode(stream).ControlPointInfo;
Assert.That(controlPoints.DifficultyPointAt(500).SpeedMultiplier, Is.EqualTo(1.5).Within(0.1));
Assert.That(controlPoints.DifficultyPointAt(1500).SpeedMultiplier, Is.EqualTo(1.5).Within(0.1));
Assert.That(controlPoints.DifficultyPointAt(2500).SpeedMultiplier, Is.EqualTo(0.75).Within(0.1));
Assert.That(controlPoints.DifficultyPointAt(3500).SpeedMultiplier, Is.EqualTo(1.5).Within(0.1));
Assert.That(controlPoints.EffectPointAt(500).KiaiMode, Is.True);
Assert.That(controlPoints.EffectPointAt(1500).KiaiMode, Is.True);
Assert.That(controlPoints.EffectPointAt(2500).KiaiMode, Is.False);
Assert.That(controlPoints.EffectPointAt(3500).KiaiMode, Is.True);
Assert.That(controlPoints.SamplePointAt(500).SampleBank, Is.EqualTo("drum"));
Assert.That(controlPoints.SamplePointAt(1500).SampleBank, Is.EqualTo("drum"));
Assert.That(controlPoints.SamplePointAt(2500).SampleBank, Is.EqualTo("normal"));
Assert.That(controlPoints.SamplePointAt(3500).SampleBank, Is.EqualTo("drum"));
Assert.That(controlPoints.TimingPointAt(500).BeatLength, Is.EqualTo(500).Within(0.1));
Assert.That(controlPoints.TimingPointAt(1500).BeatLength, Is.EqualTo(500).Within(0.1));
Assert.That(controlPoints.TimingPointAt(2500).BeatLength, Is.EqualTo(250).Within(0.1));
Assert.That(controlPoints.TimingPointAt(3500).BeatLength, Is.EqualTo(500).Within(0.1));
}
}

View File

@ -0,0 +1,19 @@
osu file format v14
[TimingPoints]
// Timing then inherited
0,500,4,2,0,100,1,0
0,-66.6666666666667,4,3,0,100,0,1
// Inherited then timing (equivalent to previous)
1000,-66.6666666666667,4,3,0,100,0,1
1000,500,4,2,0,100,1,0
// Inherited then timing (different to previous)
2000,-133.333333333333,4,1,0,100,0,0
2000,250,4,2,0,100,1,0
// Timing then inherited (different to previous)
3000,500,4,2,0,100,1,0
3000,-66.6666666666667,4,3,0,100,0,1

View File

@ -9,7 +9,6 @@ using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input.Events;
using osu.Framework.Input.States;
using osu.Framework.Platform;
@ -19,6 +18,7 @@ using osu.Game.Configuration;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
using osu.Game.Graphics.Sprites;
using osu.Game.Rulesets;
using osu.Game.Rulesets.Osu.Mods;
using osu.Game.Scoring;
@ -240,7 +240,7 @@ namespace osu.Game.Tests.Visual.Background
{
player.StoryboardEnabled.Value = false;
player.ReplacesBackground.Value = false;
player.CurrentStoryboardContainer.Add(new SpriteText
player.CurrentStoryboardContainer.Add(new OsuSpriteText
{
Size = new Vector2(250, 50),
Alpha = 1,

View File

@ -24,7 +24,9 @@ namespace osu.Game.Tests.Visual.Gameplay
GC.WaitForPendingFinalizers();
int count = 0;
workingWeakReferences.ForEachAlive(_ => count++);
foreach (var unused in workingWeakReferences)
count++;
return count == 1;
});
@ -34,7 +36,9 @@ namespace osu.Game.Tests.Visual.Gameplay
GC.WaitForPendingFinalizers();
int count = 0;
playerWeakReferences.ForEachAlive(_ => count++);
foreach (var unused in playerWeakReferences)
count++;
return count == 1;
});
}

View File

@ -5,6 +5,7 @@ using NUnit.Framework;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Play.HUD;
using osuTK;
@ -53,7 +54,7 @@ namespace osu.Game.Tests.Visual.Gameplay
};
Add(stars);
SpriteText starsLabel = new SpriteText
SpriteText starsLabel = new OsuSpriteText
{
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,

View File

@ -7,9 +7,9 @@ using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Skinning;
using osuTK.Graphics;
@ -76,7 +76,7 @@ namespace osu.Game.Tests.Visual.Gameplay
Colour = Color4.Black,
RelativeSizeAxes = Axes.Both,
},
new SpriteText
new OsuSpriteText
{
Font = OsuFont.Default.With(size: 40),
Anchor = Anchor.Centre,

View File

@ -53,38 +53,12 @@ namespace osu.Game.Tests.Visual.Menus
}
[Test]
public void TestShortLoad()
public void TestDelayedLoad()
{
bool logoVisible = false;
AddStep("begin loading", () => LoadScreen(loader = new TestLoader()));
AddWaitStep("wait", 3);
AddStep("finish loading", () =>
{
logoVisible = loader.Logo?.Alpha > 0;
loader.AllowLoad.Set();
});
AddUntilStep("wait for logo visible", () => loader.Logo?.Alpha > 0);
AddStep("finish loading", () => loader.AllowLoad.Set());
AddAssert("loaded", () => loader.Logo != null && loader.ScreenLoaded);
AddAssert("logo was visible", () => logoVisible);
AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
}
[Test]
public void TestLongLoad()
{
bool logoVisible = false;
AddStep("begin loading", () => LoadScreen(loader = new TestLoader()));
AddWaitStep("wait", 10);
AddStep("finish loading", () =>
{
logoVisible = loader.Logo?.Alpha > 0;
loader.AllowLoad.Set();
});
AddAssert("loaded", () => loader.Logo != null && loader.ScreenLoaded);
AddAssert("logo was visible", () => logoVisible);
AddUntilStep("logo gone", () => loader.Logo?.Alpha == 0);
}

View File

@ -10,6 +10,7 @@ using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using osu.Game.Graphics.Sprites;
using osu.Game.Online.Chat;
using osu.Game.Overlays.Chat.Tabs;
using osu.Game.Users;
@ -61,7 +62,7 @@ namespace osu.Game.Tests.Visual.Online
Anchor = Anchor.TopLeft,
Children = new Drawable[]
{
currentText = new SpriteText
currentText = new OsuSpriteText
{
Text = "Currently selected channel:"
}

View File

@ -31,6 +31,7 @@ namespace osu.Game.Tests.Visual.Online
var data = new int[89];
var dataWithZeros = new int[89];
var smallData = new int[89];
var edgyData = new int[89];
for (int i = 0; i < 89; i++)
data[i] = dataWithZeros[i] = (i + 1) * 1000;
@ -41,6 +42,14 @@ namespace osu.Game.Tests.Visual.Online
for (int i = 79; i < 89; i++)
smallData[i] = 100000 - i * 1000;
bool edge = true;
for (int i = 0; i < 20; i++)
{
edgyData[i] = 100000 + (edge ? 1000 : -1000) * (i + 1);
edge = !edge;
}
Add(new Container
{
Anchor = Anchor.Centre,
@ -120,6 +129,22 @@ namespace osu.Game.Tests.Visual.Online
}
};
});
AddStep("graph with edges", () =>
{
graph.User.Value = new User
{
Statistics = new UserStatistics
{
Ranks = new UserStatistics.UserRanks { Global = 12000 },
PP = 12345,
},
RankHistory = new User.RankHistoryData
{
Data = edgyData,
}
};
});
}
}
}

View File

@ -7,6 +7,7 @@ using osu.Framework.Allocation;
using osu.Game.Graphics.UserInterface;
using osu.Game.Online.API;
using osu.Game.Online.API.Requests;
using osu.Game.Overlays;
using osu.Game.Overlays.Profile;
using osu.Game.Overlays.Profile.Header;
using osu.Game.Overlays.Profile.Header.Components;
@ -21,7 +22,7 @@ namespace osu.Game.Tests.Visual.Online
typeof(ProfileHeader),
typeof(RankGraph),
typeof(LineGraph),
typeof(ProfileHeaderTabControl),
typeof(OverlayHeaderTabControl),
typeof(CentreHeaderContainer),
typeof(BottomHeaderContainer),
typeof(DetailHeaderContainer),

View File

@ -4,9 +4,9 @@
using NUnit.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Screens;
using osu.Framework.Testing;
using osu.Game.Graphics.Sprites;
using osu.Game.Screens;
using osu.Game.Screens.Play;
using osuTK.Graphics;
@ -54,7 +54,7 @@ namespace osu.Game.Tests.Visual
[BackgroundDependencyLoader]
private void load()
{
AddInternal(new SpriteText
AddInternal(new OsuSpriteText
{
Text = screenText,
Colour = Color4.White,

View File

@ -0,0 +1,50 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics.UserInterface;
using osuTK.Graphics;
namespace osu.Game.Tests.Visual.UserInterface
{
public class TestSceneExpandingBar : OsuTestScene
{
public TestSceneExpandingBar()
{
Container container;
ExpandingBar expandingBar;
Add(container = new Container
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
Children = new Drawable[]
{
new Box
{
Colour = Color4.Gray,
Alpha = 0.5f,
RelativeSizeAxes = Axes.Both,
},
expandingBar = new ExpandingBar
{
Anchor = Anchor.Centre,
ExpandedSize = 10,
CollapsedSize = 2,
Colour = Color4.DeepSkyBlue,
}
}
});
AddStep(@"Collapse", () => expandingBar.Collapse());
AddStep(@"Expand", () => expandingBar.Expand());
AddSliderStep(@"Resize container", 1, 300, 150, value => container.ResizeTo(value));
AddStep(@"Horizontal", () => expandingBar.RelativeSizeAxes = Axes.X);
AddStep(@"Anchor top", () => expandingBar.Anchor = Anchor.TopCentre);
AddStep(@"Vertical", () => expandingBar.RelativeSizeAxes = Axes.Y);
AddStep(@"Anchor left", () => expandingBar.Anchor = Anchor.CentreLeft);
}
}
}

View File

@ -9,6 +9,7 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.MathUtils;
using osu.Game.Graphics.Sprites;
using osu.Game.Overlays;
using osu.Game.Overlays.Notifications;
@ -40,7 +41,7 @@ namespace osu.Game.Tests.Visual.UserInterface
Origin = Anchor.TopRight
});
SpriteText displayedCount = new SpriteText();
SpriteText displayedCount = new OsuSpriteText();
Content.Add(displayedCount);

View File

@ -3,8 +3,8 @@
<ItemGroup Label="Package References">
<PackageReference Include="Appveyor.TestLogger" Version="2.0.0" />
<PackageReference Include="DeepEqual" Version="2.0.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.0.1" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="16.1.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="NUnit3TestAdapter" Version="3.13.0" />
<PackageReference Update="Microsoft.EntityFrameworkCore.Sqlite" Version="2.1.4" />
</ItemGroup>

View File

@ -28,7 +28,8 @@ namespace osu.Game.Audio
private void load()
{
track = GetTrack();
track.Completed += () => Schedule(Stop);
if (track != null)
track.Completed += () => Schedule(Stop);
}
/// <summary>
@ -56,19 +57,25 @@ namespace osu.Game.Audio
/// <summary>
/// Starts playing this <see cref="PreviewTrack"/>.
/// </summary>
public void Start() => startDelegate = Schedule(() =>
/// <returns>Whether the track is started or already playing.</returns>
public bool Start()
{
if (track == null)
return;
return false;
if (hasStarted)
return;
startDelegate = Schedule(() =>
{
if (hasStarted)
return;
hasStarted = true;
hasStarted = true;
track.Restart();
Started?.Invoke();
});
track.Restart();
Started?.Invoke();
});
return true;
}
/// <summary>
/// Stops playing this <see cref="PreviewTrack"/>.

View File

@ -12,17 +12,14 @@ namespace osu.Game.Beatmaps.ControlPoints
/// </summary>
public double Time;
/// <summary>
/// Whether this timing point was generated internally, as opposed to parsed from the underlying beatmap.
/// </summary>
internal bool AutoGenerated;
public int CompareTo(ControlPoint other) => Time.CompareTo(other.Time);
/// <summary>
/// Whether this <see cref="ControlPoint"/> provides the same parametric changes as another <see cref="ControlPoint"/>.
/// Basically an equality check without considering the <see cref="Time"/>.
/// </summary>
/// <param name="other">The <see cref="ControlPoint"/> to compare to.</param>
/// <returns>Whether this <see cref="ControlPoint"/> is equivalent to <paramref name="other"/>.</returns>
public virtual bool EquivalentTo(ControlPoint other) => true;
public bool Equals(ControlPoint other)
=> EquivalentTo(other) && Time.Equals(other?.Time);
=> Time.Equals(other?.Time);
}
}

View File

@ -1,11 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osuTK;
namespace osu.Game.Beatmaps.ControlPoints
{
public class DifficultyControlPoint : ControlPoint
public class DifficultyControlPoint : ControlPoint, IEquatable<DifficultyControlPoint>
{
/// <summary>
/// The speed multiplier at this control point.
@ -18,9 +19,8 @@ namespace osu.Game.Beatmaps.ControlPoints
private double speedMultiplier = 1;
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is DifficultyControlPoint difficulty
&& SpeedMultiplier.Equals(difficulty.SpeedMultiplier);
public bool Equals(DifficultyControlPoint other)
=> base.Equals(other)
&& SpeedMultiplier.Equals(other?.SpeedMultiplier);
}
}

View File

@ -1,9 +1,11 @@
// 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;
namespace osu.Game.Beatmaps.ControlPoints
{
public class EffectControlPoint : ControlPoint
public class EffectControlPoint : ControlPoint, IEquatable<EffectControlPoint>
{
/// <summary>
/// Whether this control point enables Kiai mode.
@ -15,10 +17,8 @@ namespace osu.Game.Beatmaps.ControlPoints
/// </summary>
public bool OmitFirstBarLine;
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is EffectControlPoint effect
&& KiaiMode.Equals(effect.KiaiMode)
&& OmitFirstBarLine.Equals(effect.OmitFirstBarLine);
public bool Equals(EffectControlPoint other)
=> base.Equals(other)
&& KiaiMode == other?.KiaiMode && OmitFirstBarLine == other.OmitFirstBarLine;
}
}

View File

@ -1,11 +1,12 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Game.Audio;
namespace osu.Game.Beatmaps.ControlPoints
{
public class SampleControlPoint : ControlPoint
public class SampleControlPoint : ControlPoint, IEquatable<SampleControlPoint>
{
public const string DEFAULT_BANK = "normal";
@ -44,10 +45,8 @@ namespace osu.Game.Beatmaps.ControlPoints
return newSampleInfo;
}
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is SampleControlPoint sample
&& SampleBank.Equals(sample.SampleBank)
&& SampleVolume.Equals(sample.SampleVolume);
public bool Equals(SampleControlPoint other)
=> base.Equals(other)
&& string.Equals(SampleBank, other?.SampleBank) && SampleVolume == other?.SampleVolume;
}
}

View File

@ -1,12 +1,13 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osuTK;
using osu.Game.Beatmaps.Timing;
namespace osu.Game.Beatmaps.ControlPoints
{
public class TimingControlPoint : ControlPoint
public class TimingControlPoint : ControlPoint, IEquatable<TimingControlPoint>
{
/// <summary>
/// The time signature at this control point.
@ -24,10 +25,8 @@ namespace osu.Game.Beatmaps.ControlPoints
private double beatLength = 1000;
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is TimingControlPoint timing
&& TimeSignature.Equals(timing.TimeSignature)
&& BeatLength.Equals(timing.BeatLength);
public bool Equals(TimingControlPoint other)
=> base.Equals(other)
&& TimeSignature == other?.TimeSignature && beatLength.Equals(other.beatLength);
}
}

View File

@ -32,6 +32,7 @@ namespace osu.Game.Beatmaps.Drawables
protected virtual double UnloadDelay => 10000;
private BeatmapInfo lastModel;
private bool firstLoad = true;
protected override DelayedLoadWrapper CreateDelayedLoadWrapper(Drawable content, double timeBeforeLoad)
{
@ -39,11 +40,12 @@ namespace osu.Game.Beatmaps.Drawables
{
// If DelayedLoadUnloadWrapper is attempting to RELOAD the same content (Beatmap), that means that it was
// previously UNLOADED and thus its children have been disposed of, so we need to recreate them here.
if (lastModel == Beatmap.Value)
if (!firstLoad && lastModel == Beatmap.Value)
return CreateDrawable(Beatmap.Value);
// If the model has changed since the previous unload (or if there was no load), then we can safely use the given content
lastModel = Beatmap.Value;
firstLoad = false;
return content;
}, timeBeforeLoad, UnloadDelay);
}

View File

@ -374,14 +374,16 @@ namespace osu.Game.Beatmaps.Formats
handleDifficultyControlPoint(new DifficultyControlPoint
{
Time = time,
SpeedMultiplier = speedMultiplier
SpeedMultiplier = speedMultiplier,
AutoGenerated = timingChange
});
handleEffectControlPoint(new EffectControlPoint
{
Time = time,
KiaiMode = kiaiMode,
OmitFirstBarLine = omitFirstBarSignature
OmitFirstBarLine = omitFirstBarSignature,
AutoGenerated = timingChange
});
handleSampleControlPoint(new LegacySampleControlPoint
@ -389,7 +391,8 @@ namespace osu.Game.Beatmaps.Formats
Time = time,
SampleBank = stringSampleSet,
SampleVolume = sampleVolume,
CustomSampleBank = customSampleBank
CustomSampleBank = customSampleBank,
AutoGenerated = timingChange
});
}
catch (FormatException)
@ -407,7 +410,14 @@ namespace osu.Game.Beatmaps.Formats
var existing = beatmap.ControlPointInfo.TimingPointAt(newPoint.Time);
if (existing.Time == newPoint.Time)
{
// autogenerated points should not replace non-autogenerated.
// this allows for incorrectly ordered timing points to still be correctly handled.
if (newPoint.AutoGenerated && !existing.AutoGenerated)
return;
beatmap.ControlPointInfo.TimingPoints.Remove(existing);
}
beatmap.ControlPointInfo.TimingPoints.Add(newPoint);
}
@ -416,11 +426,15 @@ namespace osu.Game.Beatmaps.Formats
{
var existing = beatmap.ControlPointInfo.DifficultyPointAt(newPoint.Time);
if (newPoint.EquivalentTo(existing))
return;
if (existing.Time == newPoint.Time)
{
// autogenerated points should not replace non-autogenerated.
// this allows for incorrectly ordered timing points to still be correctly handled.
if (newPoint.AutoGenerated && !existing.AutoGenerated)
return;
beatmap.ControlPointInfo.DifficultyPoints.Remove(existing);
}
beatmap.ControlPointInfo.DifficultyPoints.Add(newPoint);
}
@ -429,11 +443,15 @@ namespace osu.Game.Beatmaps.Formats
{
var existing = beatmap.ControlPointInfo.EffectPointAt(newPoint.Time);
if (newPoint.EquivalentTo(existing))
return;
if (existing.Time == newPoint.Time)
{
// autogenerated points should not replace non-autogenerated.
// this allows for incorrectly ordered timing points to still be correctly handled.
if (newPoint.AutoGenerated && !existing.AutoGenerated)
return;
beatmap.ControlPointInfo.EffectPoints.Remove(existing);
}
beatmap.ControlPointInfo.EffectPoints.Add(newPoint);
}
@ -442,11 +460,15 @@ namespace osu.Game.Beatmaps.Formats
{
var existing = beatmap.ControlPointInfo.SamplePointAt(newPoint.Time);
if (newPoint.EquivalentTo(existing))
return;
if (existing.Time == newPoint.Time)
{
// autogenerated points should not replace non-autogenerated.
// this allows for incorrectly ordered timing points to still be correctly handled.
if (newPoint.AutoGenerated && !existing.AutoGenerated)
return;
beatmap.ControlPointInfo.SamplePoints.Remove(existing);
}
beatmap.ControlPointInfo.SamplePoints.Add(newPoint);
}

View File

@ -189,7 +189,7 @@ namespace osu.Game.Beatmaps.Formats
Foreground = 3
}
internal class LegacySampleControlPoint : SampleControlPoint
internal class LegacySampleControlPoint : SampleControlPoint, IEquatable<LegacySampleControlPoint>
{
public int CustomSampleBank;
@ -203,10 +203,9 @@ namespace osu.Game.Beatmaps.Formats
return baseInfo;
}
public override bool EquivalentTo(ControlPoint other)
=> base.EquivalentTo(other)
&& other is LegacySampleControlPoint legacy
&& CustomSampleBank == legacy.CustomSampleBank;
public bool Equals(LegacySampleControlPoint other)
=> base.Equals(other)
&& CustomSampleBank == other?.CustomSampleBank;
}
}
}

View File

@ -4,11 +4,12 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Graphics.Containers
{
public class OsuClickableContainer : ClickableContainer
public class OsuClickableContainer : ClickableContainer, IHasTooltip
{
private readonly HoverSampleSet sampleSet;
@ -23,6 +24,8 @@ namespace osu.Game.Graphics.Containers
this.sampleSet = sampleSet;
}
public virtual string TooltipText { get; set; }
[BackgroundDependencyLoader]
private void load()
{

View File

@ -20,18 +20,41 @@ namespace osu.Game.Graphics.Containers
protected virtual IEnumerable<Drawable> EffectTargets => new[] { Content };
public OsuHoverContainer()
{
Enabled.ValueChanged += e =>
{
if (!e.NewValue) unhover();
};
}
private bool isHovered;
protected override bool OnHover(HoverEvent e)
{
if (!Enabled.Value)
return false;
EffectTargets.ForEach(d => d.FadeColour(HoverColour, FADE_DURATION, Easing.OutQuint));
isHovered = true;
return base.OnHover(e);
}
protected override void OnHoverLost(HoverLostEvent e)
{
EffectTargets.ForEach(d => d.FadeColour(IdleColour, FADE_DURATION, Easing.OutQuint));
unhover();
base.OnHoverLost(e);
}
private void unhover()
{
if (!isHovered) return;
isHovered = false;
EffectTargets.ForEach(d => d.FadeColour(IdleColour, FADE_DURATION, Easing.OutQuint));
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{

View File

@ -136,15 +136,5 @@ namespace osu.Game.Graphics
public readonly Color4 ChatBlue = FromHex(@"17292e");
public readonly Color4 ContextMenuGray = FromHex(@"223034");
public readonly Color4 CommunityUserGreenLight = FromHex(@"deff87");
public readonly Color4 CommunityUserGreen = FromHex(@"05ffa2");
public readonly Color4 CommunityUserGreenDark = FromHex(@"a6cc00");
public readonly Color4 CommunityUserGrayGreenLighter = FromHex(@"9ebab1");
public readonly Color4 CommunityUserGrayGreenLight = FromHex(@"77998e");
public readonly Color4 CommunityUserGrayGreen = FromHex(@"4e7466");
public readonly Color4 CommunityUserGrayGreenDark = FromHex(@"33413c");
public readonly Color4 CommunityUserGrayGreenDarker = FromHex(@"2c3532");
public readonly Color4 CommunityUserGrayGreenDarkest = FromHex(@"1e2422");
}
}

View File

@ -0,0 +1,101 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Shapes;
using osuTK;
namespace osu.Game.Graphics.UserInterface
{
/// <summary>
/// A rounded bar which can be expanded or collapsed.
/// Generally used for tabs or breadcrumbs.
/// </summary>
public class ExpandingBar : Circle
{
private bool isCollapsed;
public bool IsCollapsed
{
get => isCollapsed;
set
{
if (value == isCollapsed)
return;
isCollapsed = value;
updateState();
}
}
private float expandedSize = 4;
public float ExpandedSize
{
get => expandedSize;
set
{
if (value == expandedSize)
return;
expandedSize = value;
updateState();
}
}
private float collapsedSize = 2;
public float CollapsedSize
{
get => collapsedSize;
set
{
if (value == collapsedSize)
return;
collapsedSize = value;
updateState();
}
}
public override Axes RelativeSizeAxes
{
get => base.RelativeSizeAxes;
set
{
base.RelativeSizeAxes = Axes.None;
Size = Vector2.Zero;
base.RelativeSizeAxes = value;
updateState();
}
}
public ExpandingBar()
{
RelativeSizeAxes = Axes.X;
Origin = Anchor.Centre;
}
protected override void LoadComplete()
{
base.LoadComplete();
updateState();
}
public void Collapse() => IsCollapsed = true;
public void Expand() => IsCollapsed = false;
private void updateState()
{
float newSize = IsCollapsed ? CollapsedSize : ExpandedSize;
Easing easingType = IsCollapsed ? Easing.Out : Easing.OutElastic;
if (RelativeSizeAxes == Axes.X)
this.ResizeHeightTo(newSize, 400, easingType);
else
this.ResizeWidthTo(newSize, 400, easingType);
}
}
}

View File

@ -1,6 +1,7 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using System;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
@ -12,26 +13,33 @@ namespace osu.Game.Graphics.UserInterface
{
public abstract class ScreenTitle : CompositeDrawable, IHasAccentColour
{
private readonly SpriteIcon iconSprite;
public const float ICON_WIDTH = ICON_SIZE + icon_spacing;
protected const float ICON_SIZE = 25;
private SpriteIcon iconSprite;
private readonly OsuSpriteText titleText, pageText;
public const float ICON_WIDTH = icon_size + icon_spacing;
private const float icon_size = 25, icon_spacing = 10;
private const float icon_spacing = 10;
protected IconUsage Icon
{
get => iconSprite.Icon;
set => iconSprite.Icon = value;
set
{
if (iconSprite == null)
throw new InvalidOperationException($"Cannot use {nameof(Icon)} with a custom {nameof(CreateIcon)} function.");
iconSprite.Icon = value;
}
}
protected string Title
{
get => titleText.Text;
set => titleText.Text = value;
}
protected string Section
{
get => pageText.Text;
set => pageText.Text = value;
}
@ -41,6 +49,11 @@ namespace osu.Game.Graphics.UserInterface
set => pageText.Colour = value;
}
protected virtual Drawable CreateIcon() => iconSprite = new SpriteIcon
{
Size = new Vector2(ICON_SIZE),
};
protected ScreenTitle()
{
AutoSizeAxes = Axes.Both;
@ -51,12 +64,9 @@ namespace osu.Game.Graphics.UserInterface
{
AutoSizeAxes = Axes.Both,
Spacing = new Vector2(icon_spacing, 0),
Children = new Drawable[]
Children = new[]
{
iconSprite = new SpriteIcon
{
Size = new Vector2(icon_size),
},
CreateIcon(),
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,

View File

@ -1,7 +1,6 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics.Cursor;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Allocation;
@ -16,7 +15,7 @@ namespace osu.Game.Online.Chat
/// <summary>
/// An invisible drawable that brings multiple <see cref="Drawable"/> pieces together to form a consumable clickable link.
/// </summary>
public class DrawableLinkCompiler : OsuHoverContainer, IHasTooltip
public class DrawableLinkCompiler : OsuHoverContainer
{
/// <summary>
/// Each word part of a chat link (split for word-wrap support).
@ -40,8 +39,6 @@ namespace osu.Game.Online.Chat
protected override IEnumerable<Drawable> EffectTargets => Parts;
public string TooltipText { get; set; }
private class LinkHoverSounds : HoverClickSounds
{
private readonly List<Drawable> parts;

View File

@ -1,4 +1,4 @@
// 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.
using System;
@ -588,7 +588,7 @@ namespace osu.Game
private Task asyncLoadStream;
private void loadComponentSingleFile<T>(T d, Action<T> add, bool cache = false)
private T loadComponentSingleFile<T>(T d, Action<T> add, bool cache = false)
where T : Drawable
{
if (cache)
@ -636,6 +636,8 @@ namespace osu.Game
}
});
});
return d;
}
public bool OnPressed(GlobalAction action)

View File

@ -9,8 +9,6 @@ using osu.Game.Graphics.Sprites;
using osu.Game.Users;
using osuTK;
using osuTK.Graphics;
using osu.Game.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Effects;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics;
@ -129,10 +127,5 @@ namespace osu.Game.Overlays.BeatmapSet
};
}
}
private class ClickableArea : OsuClickableContainer, IHasTooltip
{
public string TooltipText => @"View Profile";
}
}
}

View File

@ -83,7 +83,7 @@ namespace osu.Game.Overlays.BeatmapSet.Scores
Origin = Anchor.CentreLeft,
AutoSizeAxes = Axes.Both,
},
date = new SpriteText
date = new OsuSpriteText
{
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,

View File

@ -129,7 +129,7 @@ namespace osu.Game.Overlays.Direct
if (Preview != null)
{
Preview.Start();
attemptStart();
return;
}
@ -147,7 +147,7 @@ namespace osu.Game.Overlays.Direct
// user may have changed their mind.
if (Playing.Value)
preview.Start();
attemptStart();
});
}
else
@ -157,6 +157,12 @@ namespace osu.Game.Overlays.Direct
}
}
private void attemptStart()
{
if (Preview?.Start() != true)
Playing.Value = false;
}
protected override void Dispose(bool isDisposing)
{
base.Dispose(isDisposing);

View File

@ -0,0 +1,70 @@
// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Overlays
{
public abstract class OverlayHeader : Container
{
protected readonly OverlayHeaderTabControl TabControl;
private const float cover_height = 150;
private const float cover_info_height = 75;
protected OverlayHeader()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
Height = cover_height,
Masking = true,
Child = CreateBackground()
},
new Container
{
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
Y = cover_height,
Height = cover_info_height,
RelativeSizeAxes = Axes.X,
Anchor = Anchor.TopLeft,
Origin = Anchor.BottomLeft,
Depth = -float.MaxValue,
Children = new Drawable[]
{
CreateTitle().With(t => t.X = -ScreenTitle.ICON_WIDTH),
TabControl = new OverlayHeaderTabControl
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = cover_info_height - 30,
Margin = new MarginPadding { Left = -UserProfileOverlay.CONTENT_X_MARGIN },
Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN }
}
}
},
new Container
{
Margin = new MarginPadding { Top = cover_height },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Child = CreateContent()
}
};
}
protected abstract Drawable CreateBackground();
protected abstract Drawable CreateContent();
protected abstract ScreenTitle CreateTitle();
}
}

View File

@ -11,13 +11,13 @@ using osu.Game.Graphics.UserInterface;
using osuTK;
using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header
namespace osu.Game.Overlays
{
public class ProfileHeaderTabControl : TabControl<string>
public class OverlayHeaderTabControl : TabControl<string>
{
private readonly Box bar;
private Color4 accentColour;
private Color4 accentColour = Color4.White;
public Color4 AccentColour
{
@ -32,7 +32,7 @@ namespace osu.Game.Overlays.Profile.Header
foreach (TabItem<string> tabItem in TabContainer)
{
((ProfileHeaderTabItem)tabItem).AccentColour = value;
((HeaderTabItem)tabItem).AccentColour = value;
}
}
}
@ -43,7 +43,7 @@ namespace osu.Game.Overlays.Profile.Header
set => TabContainer.Padding = value;
}
public ProfileHeaderTabControl()
public OverlayHeaderTabControl()
{
TabContainer.Masking = false;
TabContainer.Spacing = new Vector2(15, 0);
@ -59,15 +59,15 @@ namespace osu.Game.Overlays.Profile.Header
protected override Dropdown<string> CreateDropdown() => null;
protected override TabItem<string> CreateTabItem(string value) => new ProfileHeaderTabItem(value)
protected override TabItem<string> CreateTabItem(string value) => new HeaderTabItem(value)
{
AccentColour = AccentColour
};
private class ProfileHeaderTabItem : TabItem<string>
private class HeaderTabItem : TabItem<string>
{
private readonly OsuSpriteText text;
private readonly Drawable bar;
private readonly ExpandingBar bar;
private Color4 accentColour;
@ -86,13 +86,13 @@ namespace osu.Game.Overlays.Profile.Header
}
}
public ProfileHeaderTabItem(string value)
public HeaderTabItem(string value)
: base(value)
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new[]
Children = new Drawable[]
{
text = new OsuSpriteText
{
@ -102,12 +102,11 @@ namespace osu.Game.Overlays.Profile.Header
Text = value,
Font = OsuFont.GetFont()
},
bar = new Circle
bar = new ExpandingBar
{
RelativeSizeAxes = Axes.X,
Height = 0,
Origin = Anchor.CentreLeft,
Anchor = Anchor.BottomLeft,
Anchor = Anchor.BottomCentre,
ExpandedSize = 7.5f,
CollapsedSize = 0
},
new HoverClickSounds()
};
@ -138,7 +137,7 @@ namespace osu.Game.Overlays.Profile.Header
if (Active.Value || IsHovered)
{
text.FadeColour(Color4.White, 120, Easing.InQuad);
bar.ResizeHeightTo(7.5f, 120, Easing.InQuad);
bar.Expand();
if (Active.Value)
text.Font = text.Font.With(weight: FontWeight.Bold);
@ -146,7 +145,7 @@ namespace osu.Game.Overlays.Profile.Header
else
{
text.FadeColour(AccentColour, 120, Easing.InQuad);
bar.ResizeHeightTo(0, 120, Easing.InQuad);
bar.Collapse();
text.Font = text.Font.With(weight: FontWeight.Medium);
}
}

View File

@ -35,14 +35,14 @@ namespace osu.Game.Overlays.Profile.Header
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
iconColour = colours.CommunityUserGrayGreenLighter;
iconColour = colours.GreySeafoamLighter;
InternalChildren = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.CommunityUserGrayGreenDarker,
Colour = colours.GreySeafoamDark,
},
new FillFlowContainer
{

View File

@ -38,7 +38,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.CommunityUserGrayGreenDark
Colour = colours.GreySeafoam
},
new FillFlowContainer
{

View File

@ -27,8 +27,8 @@ namespace osu.Game.Overlays.Profile.Header.Components
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
IdleColour = colours.CommunityUserGrayGreen;
HoverColour = colours.CommunityUserGrayGreen.Darken(0.2f);
IdleColour = colours.GreySeafoamLight;
HoverColour = colours.GreySeafoamLight.Darken(0.2f);
Child = icon = new SpriteIcon
{

View File

@ -4,7 +4,6 @@
using System.Collections.Generic;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Shapes;
using osu.Game.Graphics;
using osu.Game.Graphics.Containers;
@ -12,10 +11,8 @@ using osuTK.Graphics;
namespace osu.Game.Overlays.Profile.Header.Components
{
public abstract class ProfileHeaderButton : OsuHoverContainer, IHasTooltip
public abstract class ProfileHeaderButton : OsuHoverContainer
{
public abstract string TooltipText { get; }
private readonly Box background;
private readonly Container content;

View File

@ -96,7 +96,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
if (ranks?.Length > 1)
{
graph.UpdateBallPosition(e.MousePosition.X);
graph.ShowBall();
graph.ShowBar();
}
return base.OnHover(e);
@ -114,7 +114,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
{
if (ranks?.Length > 1)
{
graph.HideBall();
graph.HideBar();
}
base.OnHoverLost(e);
@ -123,61 +123,64 @@ namespace osu.Game.Overlays.Profile.Header.Components
private class RankChartLineGraph : LineGraph
{
private readonly CircularContainer movingBall;
private readonly Container bar;
private readonly Box ballBg;
private readonly Box movingBar;
private readonly Box line;
public Action<int> OnBallMove;
public RankChartLineGraph()
{
Add(movingBar = new Box
Add(bar = new Container
{
Origin = Anchor.TopCentre,
RelativeSizeAxes = Axes.Y,
Width = 1.5f,
AutoSizeAxes = Axes.X,
Alpha = 0,
RelativePositionAxes = Axes.Both,
});
Add(movingBall = new CircularContainer
{
Origin = Anchor.Centre,
Size = new Vector2(18),
Alpha = 0,
Masking = true,
BorderThickness = 4,
RelativePositionAxes = Axes.Both,
Child = ballBg = new Box { RelativeSizeAxes = Axes.Both }
Children = new Drawable[]
{
line = new Box
{
Anchor = Anchor.Centre,
Origin = Anchor.Centre,
RelativeSizeAxes = Axes.Y,
Width = 1.5f,
},
movingBall = new CircularContainer
{
Anchor = Anchor.TopCentre,
Origin = Anchor.Centre,
Size = new Vector2(18),
Masking = true,
BorderThickness = 4,
RelativePositionAxes = Axes.Y,
Child = ballBg = new Box { RelativeSizeAxes = Axes.Both }
}
}
});
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
ballBg.Colour = colours.CommunityUserGrayGreenDarkest;
movingBall.BorderColour = colours.Yellow;
movingBar.Colour = colours.Yellow;
ballBg.Colour = colours.GreySeafoamDarker;
movingBall.BorderColour = line.Colour = colours.Yellow;
}
public void UpdateBallPosition(float mouseXPosition)
{
const int duration = 200;
int index = calculateIndex(mouseXPosition);
movingBall.Position = calculateBallPosition(index);
movingBar.X = movingBall.X;
Vector2 position = calculateBallPosition(index);
movingBall.MoveToY(position.Y, duration, Easing.OutQuint);
bar.MoveToX(position.X, duration, Easing.OutQuint);
OnBallMove.Invoke(index);
}
public void ShowBall()
{
movingBall.FadeIn(fade_duration);
movingBar.FadeIn(fade_duration);
}
public void ShowBar() => bar.FadeIn(fade_duration);
public void HideBall()
{
movingBall.FadeOut(fade_duration);
movingBar.FadeOut(fade_duration);
}
public void HideBar() => bar.FadeOut(fade_duration);
private int calculateIndex(float mouseXPosition) => (int)Math.Round(mouseXPosition / DrawWidth * (DefaultValueCount - 1));
@ -249,7 +252,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
background.Colour = colours.CommunityUserGrayGreenDarker;
background.Colour = colours.GreySeafoamDark;
}
public void Refresh()

View File

@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Profile.Header.Components
private void load(OsuColour colours)
{
background.Colour = colours.Pink;
iconContainer.Colour = colours.CommunityUserGrayGreenDark;
iconContainer.Colour = colours.GreySeafoam;
}
}
}

View File

@ -65,7 +65,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.CommunityUserGrayGreenDarkest,
Colour = colours.GreySeafoamDarker,
},
fillFlow = new FillFlowContainer
{

View File

@ -34,7 +34,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.CommunityUserGrayGreenDarkest,
Colour = colours.GreySeafoamDarker,
},
new Container //artificial shadow
{

View File

@ -41,7 +41,7 @@ namespace osu.Game.Overlays.Profile.Header
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.CommunityUserGrayGreenDarker,
Colour = colours.GreySeafoamDark,
},
new FillFlowContainer
{
@ -107,7 +107,7 @@ namespace osu.Game.Overlays.Profile.Header
RelativeSizeAxes = Axes.X,
Height = 1.5f,
Margin = new MarginPadding { Top = 10 },
Colour = colours.CommunityUserGrayGreenLighter,
Colour = colours.GreySeafoamLighter,
},
new Container
{
@ -125,7 +125,7 @@ namespace osu.Game.Overlays.Profile.Header
Margin = new MarginPadding { Left = 40 },
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
Colour = colours.CommunityUserGrayGreenLighter,
Colour = colours.GreySeafoamLighter,
}
}
},

View File

@ -15,124 +15,87 @@ using osu.Game.Users;
namespace osu.Game.Overlays.Profile
{
public class ProfileHeader : Container
public class ProfileHeader : OverlayHeader
{
private readonly UserCoverBackground coverContainer;
private readonly ProfileHeaderTabControl infoTabControl;
private UserCoverBackground coverContainer;
private const float cover_height = 150;
private const float cover_info_height = 75;
public Bindable<User> User = new Bindable<User>();
private CentreHeaderContainer centreHeaderContainer;
private DetailHeaderContainer detailHeaderContainer;
public ProfileHeader()
{
CentreHeaderContainer centreHeaderContainer;
DetailHeaderContainer detailHeaderContainer;
User.ValueChanged += e => updateDisplay(e.NewValue);
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.X,
Height = cover_height,
Masking = true,
Children = new Drawable[]
{
coverContainer = new UserCoverBackground
{
RelativeSizeAxes = Axes.Both,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(OsuColour.FromHex("222").Opacity(0.8f), OsuColour.FromHex("222").Opacity(0.2f))
},
}
},
new Container
{
Margin = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN },
Y = cover_height,
Height = cover_info_height,
RelativeSizeAxes = Axes.X,
Anchor = Anchor.TopLeft,
Origin = Anchor.BottomLeft,
Depth = -float.MaxValue,
Children = new Drawable[]
{
new ProfileHeaderTitle
{
X = -ScreenTitle.ICON_WIDTH,
},
infoTabControl = new ProfileHeaderTabControl
{
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
RelativeSizeAxes = Axes.X,
Height = cover_info_height - 30,
Margin = new MarginPadding { Left = -UserProfileOverlay.CONTENT_X_MARGIN },
Padding = new MarginPadding { Left = UserProfileOverlay.CONTENT_X_MARGIN }
}
}
},
new FillFlowContainer
{
Margin = new MarginPadding { Top = cover_height },
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new TopHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
centreHeaderContainer = new CentreHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
detailHeaderContainer = new DetailHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
new MedalHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
new BottomHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
}
}
};
infoTabControl.AddItem("Info");
infoTabControl.AddItem("Modding");
TabControl.AddItem("Info");
TabControl.AddItem("Modding");
centreHeaderContainer.DetailsVisible.BindValueChanged(visible => detailHeaderContainer.Expanded = visible.NewValue, true);
User.ValueChanged += e => updateDisplay(e.NewValue);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
infoTabControl.AccentColour = colours.CommunityUserGreen;
TabControl.AccentColour = colours.Seafoam;
}
public Bindable<User> User = new Bindable<User>();
protected override Drawable CreateBackground() =>
new Container
{
RelativeSizeAxes = Axes.Both,
Children = new Drawable[]
{
coverContainer = new UserCoverBackground
{
RelativeSizeAxes = Axes.Both,
},
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = ColourInfo.GradientVertical(OsuColour.FromHex("222").Opacity(0.8f), OsuColour.FromHex("222").Opacity(0.2f))
},
}
};
private void updateDisplay(User user)
protected override Drawable CreateContent() => new FillFlowContainer
{
coverContainer.User = user;
}
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
new TopHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
centreHeaderContainer = new CentreHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
detailHeaderContainer = new DetailHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
new MedalHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
new BottomHeaderContainer
{
RelativeSizeAxes = Axes.X,
User = { BindTarget = User },
},
}
};
protected override ScreenTitle CreateTitle() => new ProfileHeaderTitle();
private void updateDisplay(User user) => coverContainer.User = user;
private class ProfileHeaderTitle : ScreenTitle
{
@ -145,7 +108,7 @@ namespace osu.Game.Overlays.Profile
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
AccentColour = colours.CommunityUserGreen;
AccentColour = colours.Seafoam;
}
}
}

View File

@ -4,7 +4,6 @@
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Localisation;
using osu.Game.Beatmaps;
using osu.Game.Graphics;
@ -16,7 +15,7 @@ namespace osu.Game.Overlays.Profile.Sections
/// <summary>
/// Display artist/title/mapper information, commonly used as the left portion of a profile or score display row (see <see cref="DrawableProfileRow"/>).
/// </summary>
public class BeatmapMetadataContainer : OsuHoverContainer, IHasTooltip
public class BeatmapMetadataContainer : OsuHoverContainer
{
private readonly BeatmapInfo beatmap;
@ -27,8 +26,6 @@ namespace osu.Game.Overlays.Profile.Sections
TooltipText = $"{beatmap.Metadata.Artist} - {beatmap.Metadata.Title}";
}
public string TooltipText { get; }
[BackgroundDependencyLoader(true)]
private void load(BeatmapSetOverlay beatmapSetOverlay)
{

View File

@ -155,9 +155,11 @@ namespace osu.Game.Screens.Menu
protected override void LogoSuspending(OsuLogo logo)
{
logo.FadeOut(300, Easing.InSine)
.ScaleTo(0.2f, 300, Easing.InSine)
.OnComplete(l => buttons.SetOsuLogo(null));
var seq = logo.FadeOut(300, Easing.InSine)
.ScaleTo(0.2f, 300, Easing.InSine);
seq.OnComplete(_ => buttons.SetOsuLogo(null));
seq.OnAbort(_ => buttons.SetOsuLogo(null));
}
private void beatmap_ValueChanged(ValueChangedEvent<WorkingBeatmap> e)

View File

@ -252,6 +252,10 @@ namespace osu.Game.Screens.Play
if (!this.IsCurrentScreen()) return;
sampleRestart?.Play();
// if a restart has been requested, cancel any pending completion (user has shown intent to restart).
onCompletionEvent = null;
ValidForResume = false;
RestartRequested?.Invoke();
this.Exit();

View File

@ -6,7 +6,6 @@ using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Input.Events;
@ -72,9 +71,9 @@ namespace osu.Game.Users
game?.ShowUser(user.Id);
}
private class ClickableArea : OsuClickableContainer, IHasTooltip
private class ClickableArea : OsuClickableContainer
{
public string TooltipText => Enabled.Value ? @"View Profile" : null;
public override string TooltipText => Enabled.Value ? @"View Profile" : null;
protected override bool OnClick(ClickEvent e)
{

View File

@ -14,10 +14,10 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite" Version="2.2.4" />
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.4" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.2" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.502.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.514.0" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.518.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.523.0" />
<PackageReference Include="SharpCompress" Version="0.23.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="NUnit" Version="3.12.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />
<PackageReference Include="System.ComponentModel.Annotations" Version="4.5.0" />
</ItemGroup>

View File

@ -105,8 +105,8 @@
<PackageReference Include="Microsoft.EntityFrameworkCore.Sqlite.Core" Version="2.2.1" />
<PackageReference Include="Newtonsoft.Json" Version="12.0.1" />
<PackageReference Include="ppy.osu.Game.Resources" Version="2019.128.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.514.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.514.0" />
<PackageReference Include="ppy.osu.Framework" Version="2019.523.0" />
<PackageReference Include="ppy.osu.Framework.iOS" Version="2019.523.0" />
<PackageReference Include="SharpCompress" Version="0.22.0" />
<PackageReference Include="NUnit" Version="3.11.0" />
<PackageReference Include="SharpRaven" Version="2.4.0" />