mirror of
https://github.com/ppy/osu.git
synced 2026-05-15 19:34:54 +08:00
Compare commits
243 Commits
v2017.823.0
...
0.1.0
+1
-1
Submodule osu-framework updated: 1ba1e8ef1e...4e7ea6af4f
@@ -1,17 +1,14 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using NUnit.Framework;
|
||||
using osu.Framework.Desktop.Platform;
|
||||
using osu.Framework.Testing;
|
||||
using osu.Game;
|
||||
|
||||
namespace osu.Desktop.Tests.Visual
|
||||
{
|
||||
[TestFixture]
|
||||
public abstract class OsuTestCase : TestCase
|
||||
{
|
||||
[Test]
|
||||
public override void RunTest()
|
||||
{
|
||||
using (var host = new HeadlessGameHost(realtime: false))
|
||||
|
||||
@@ -69,28 +69,28 @@ namespace osu.Desktop.Tests.Visual
|
||||
|
||||
private class MyContextMenuContainer : Container, IHasContextMenu
|
||||
{
|
||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
{
|
||||
new OsuContextMenuItem(@"Some option"),
|
||||
new OsuContextMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
||||
new OsuContextMenuItem(@"Another option"),
|
||||
new OsuContextMenuItem(@"Choose me please"),
|
||||
new OsuContextMenuItem(@"And me too"),
|
||||
new OsuContextMenuItem(@"Trying to fill"),
|
||||
new OsuContextMenuItem(@"Destructive option", MenuItemType.Destructive),
|
||||
new OsuMenuItem(@"Some option"),
|
||||
new OsuMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
||||
new OsuMenuItem(@"Another option"),
|
||||
new OsuMenuItem(@"Choose me please"),
|
||||
new OsuMenuItem(@"And me too"),
|
||||
new OsuMenuItem(@"Trying to fill"),
|
||||
new OsuMenuItem(@"Destructive option", MenuItemType.Destructive),
|
||||
};
|
||||
}
|
||||
|
||||
private class AnotherContextMenuContainer : Container, IHasContextMenu
|
||||
{
|
||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
{
|
||||
new OsuContextMenuItem(@"Simple option"),
|
||||
new OsuContextMenuItem(@"Simple very very long option"),
|
||||
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint) },
|
||||
new OsuMenuItem(@"Simple option"),
|
||||
new OsuMenuItem(@"Simple very very long option"),
|
||||
new OsuMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
|
||||
new OsuMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
|
||||
new OsuMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
|
||||
new OsuMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -41,12 +41,14 @@ namespace osu.Desktop.Tests.Visual
|
||||
{
|
||||
new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 578332,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"OrVid",
|
||||
Artist = @"An",
|
||||
Author = @"RLC",
|
||||
Source = @"",
|
||||
Tags = @"acuticnotes an-fillnote revid tear tearvid encrpted encryption axi axivid quad her hervid recoll",
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
@@ -71,12 +73,14 @@ namespace osu.Desktop.Tests.Visual
|
||||
},
|
||||
new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 599627,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"tiny lamp",
|
||||
Artist = @"fhana",
|
||||
Author = @"Sotarks",
|
||||
Source = @"ぎんぎつね",
|
||||
Tags = @"lantis junichi sato yuxuki waga kevin mitsunaga towana gingitsune opening op full ver version kalibe collab collaboration",
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
@@ -101,12 +105,14 @@ namespace osu.Desktop.Tests.Visual
|
||||
},
|
||||
new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 513268,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"At Gwanghwamun",
|
||||
Artist = @"KYUHYUN",
|
||||
Author = @"Cerulean Veyron",
|
||||
Source = @"",
|
||||
Tags = @"soul ballad kh super junior sj suju 슈퍼주니어 kt뮤직 sm엔터테인먼트 s.m.entertainment kt music 1st mini album ep",
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
@@ -146,12 +152,14 @@ namespace osu.Desktop.Tests.Visual
|
||||
},
|
||||
new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = 586841,
|
||||
Metadata = new BeatmapMetadata
|
||||
{
|
||||
Title = @"RHAPSODY OF BLUE SKY",
|
||||
Artist = @"fhana",
|
||||
Author = @"[Kamiya]",
|
||||
Source = @"小林さんちのメイドラゴン",
|
||||
Tags = @"kobayashi san chi no maidragon aozora no opening anime maid dragon oblivion karen dynamix imoutosan pata-mon gxytcgxytc",
|
||||
},
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
|
||||
@@ -0,0 +1,84 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Screens.Edit.Menus;
|
||||
|
||||
namespace osu.Desktop.Tests.Visual
|
||||
{
|
||||
public class TestCaseEditorMenuBar : OsuTestCase
|
||||
{
|
||||
public TestCaseEditorMenuBar()
|
||||
{
|
||||
Add(new EditorMenuBar
|
||||
{
|
||||
Anchor = Anchor.TopCentre,
|
||||
Origin = Anchor.TopCentre,
|
||||
Y = 50,
|
||||
Items = new[]
|
||||
{
|
||||
new EditorMenuBarItem("File")
|
||||
{
|
||||
Items = new[]
|
||||
{
|
||||
new EditorMenuItem("Clear All Notes"),
|
||||
new EditorMenuItem("Open Difficulty..."),
|
||||
new EditorMenuItem("Save"),
|
||||
new EditorMenuItem("Create a new Difficulty..."),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Revert to Saved"),
|
||||
new EditorMenuItem("Revert to Saved (Full)"),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Test Beatmap"),
|
||||
new EditorMenuItem("Open AiMod"),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Upload Beatmap..."),
|
||||
new EditorMenuItem("Export Package"),
|
||||
new EditorMenuItem("Export Map Package"),
|
||||
new EditorMenuItem("Import from..."),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Open Song Folder"),
|
||||
new EditorMenuItem("Open .osu in Notepad"),
|
||||
new EditorMenuItem("Open .osb in Notepad"),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Exit"),
|
||||
}
|
||||
},
|
||||
new EditorMenuBarItem("Timing")
|
||||
{
|
||||
Items = new[]
|
||||
{
|
||||
new EditorMenuItem("Time Signature"),
|
||||
new EditorMenuItem("Metronome Clicks"),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Add Timing Section"),
|
||||
new EditorMenuItem("Add Inheriting Section"),
|
||||
new EditorMenuItem("Reset Current Section"),
|
||||
new EditorMenuItem("Delete Timing Section"),
|
||||
new EditorMenuItem("Resnap Current Section"),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Timing Setup"),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Resnap All Notes", MenuItemType.Destructive),
|
||||
new EditorMenuItem("Move all notes in time...", MenuItemType.Destructive),
|
||||
new EditorMenuItem("Recalculate Slider Lengths", MenuItemType.Destructive),
|
||||
new EditorMenuItem("Delete All Timing Sections", MenuItemType.Destructive),
|
||||
new EditorMenuItemSpacer(),
|
||||
new EditorMenuItem("Set Current Position as Preview Point"),
|
||||
}
|
||||
},
|
||||
new EditorMenuBarItem("Testing")
|
||||
{
|
||||
Items = new[]
|
||||
{
|
||||
new EditorMenuItem("Item 1"),
|
||||
new EditorMenuItem("Item 2"),
|
||||
new EditorMenuItem("Item 3"),
|
||||
}
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,13 +1,13 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Osu.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Screens.Select.Leaderboards;
|
||||
using osu.Game.Users;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Desktop.Tests.Visual
|
||||
{
|
||||
@@ -24,7 +24,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.XH,
|
||||
Accuracy = 100,
|
||||
Accuracy = 1,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -42,7 +42,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.X,
|
||||
Accuracy = 100,
|
||||
Accuracy = 1,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -60,7 +60,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.SH,
|
||||
Accuracy = 100,
|
||||
Accuracy = 1,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -78,7 +78,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.S,
|
||||
Accuracy = 100,
|
||||
Accuracy = 1,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -96,7 +96,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.A,
|
||||
Accuracy = 100,
|
||||
Accuracy = 1,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -114,7 +114,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.B,
|
||||
Accuracy = 98.26,
|
||||
Accuracy = 0.9826,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -132,7 +132,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.C,
|
||||
Accuracy = 96.54,
|
||||
Accuracy = 0.9654,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -150,7 +150,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.F,
|
||||
Accuracy = 60.25,
|
||||
Accuracy = 0.6025,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -168,7 +168,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.F,
|
||||
Accuracy = 51.40,
|
||||
Accuracy = 0.5140,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
@@ -186,7 +186,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
new Score
|
||||
{
|
||||
Rank = ScoreRank.F,
|
||||
Accuracy = 42.22,
|
||||
Accuracy = 0.4222,
|
||||
MaxCombo = 244,
|
||||
TotalScore = 1707827,
|
||||
Mods = new Mod[] { new OsuModHidden(), new OsuModHardRock(), },
|
||||
|
||||
@@ -32,7 +32,7 @@ namespace osu.Desktop.Tests.Visual
|
||||
backingDatabase.CreateTable<StoreVersion>();
|
||||
|
||||
rulesets = new RulesetStore(backingDatabase);
|
||||
manager = new BeatmapManager(storage, null, backingDatabase, rulesets);
|
||||
manager = new BeatmapManager(storage, null, backingDatabase, rulesets, null);
|
||||
|
||||
for (int i = 0; i < 100; i += 10)
|
||||
manager.Import(createTestBeatmapSet(i));
|
||||
|
||||
@@ -87,6 +87,7 @@
|
||||
<Compile Include="Visual\TestCaseManiaHitObjects.cs" />
|
||||
<Compile Include="Visual\TestCaseManiaPlayfield.cs" />
|
||||
<Compile Include="Visual\TestCaseMedalOverlay.cs" />
|
||||
<Compile Include="Visual\TestCaseEditorMenuBar.cs" />
|
||||
<Compile Include="Visual\TestCaseMenuButtonSystem.cs" />
|
||||
<Compile Include="Visual\TestCaseMenuOverlays.cs" />
|
||||
<Compile Include="Visual\TestCaseMods.cs" />
|
||||
|
||||
@@ -93,8 +93,6 @@ namespace osu.Game.Rulesets.Catch
|
||||
}
|
||||
}
|
||||
|
||||
public override Mod GetAutoplayMod() => new ModAutoplay();
|
||||
|
||||
public override string Description => "osu!catch";
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_fruits_o };
|
||||
|
||||
@@ -105,8 +105,6 @@ namespace osu.Game.Rulesets.Mania
|
||||
}
|
||||
}
|
||||
|
||||
public override Mod GetAutoplayMod() => new ModAutoplay();
|
||||
|
||||
public override string Description => "osu!mania";
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_mania_o };
|
||||
|
||||
@@ -68,6 +68,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public class ManiaModFadeIn : Mod
|
||||
{
|
||||
public override string Name => "FadeIn";
|
||||
public override string ShortenedName => "FI";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override double ScoreMultiplier => 1;
|
||||
@@ -78,12 +79,14 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public class ManiaModRandom : Mod
|
||||
{
|
||||
public override string Name => "Random";
|
||||
public override string ShortenedName => "RD";
|
||||
public override string Description => @"Shuffle around the notes!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
}
|
||||
|
||||
public abstract class ManiaKeyMod : Mod
|
||||
{
|
||||
public override string ShortenedName => Name;
|
||||
public abstract int KeyCount { get; }
|
||||
public override double ScoreMultiplier => 1; // TODO: Implement the mania key mod score multiplier
|
||||
public override bool Ranked => true;
|
||||
@@ -146,6 +149,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public class ManiaModKeyCoop : Mod
|
||||
{
|
||||
public override string Name => "KeyCoop";
|
||||
public override string ShortenedName => "2P";
|
||||
public override string Description => @"Double the key amount, double the fun!";
|
||||
public override double ScoreMultiplier => 1;
|
||||
public override bool Ranked => true;
|
||||
|
||||
@@ -15,6 +15,7 @@ namespace osu.Game.Rulesets.Mania.Mods
|
||||
public class ManiaModGravity : Mod, IGenerateSpeedAdjustments
|
||||
{
|
||||
public override string Name => "Gravity";
|
||||
public override string ShortenedName => "GR";
|
||||
|
||||
public override double ScoreMultiplier => 0;
|
||||
|
||||
|
||||
@@ -198,7 +198,7 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
if (action == Action)
|
||||
{
|
||||
background.FadeTo(background.Alpha + 0.2f, 50, Easing.OutQuint);
|
||||
background.FadeTo(0.6f, 50, Easing.OutQuint);
|
||||
keyIcon.ScaleTo(1.4f, 50, Easing.OutQuint);
|
||||
}
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using OpenTK.Input;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Configuration;
|
||||
@@ -25,12 +24,6 @@ namespace osu.Game.Rulesets.Mania.UI
|
||||
{
|
||||
public const float HIT_TARGET_POSITION = 50;
|
||||
|
||||
/// <summary>
|
||||
/// Default column keys, expanding outwards from the middle as more column are added.
|
||||
/// E.g. 2 columns use FJ, 4 columns use DFJK, 6 use SDFJKL, etc...
|
||||
/// </summary>
|
||||
private static readonly Key[] default_keys = { Key.A, Key.S, Key.D, Key.F, Key.J, Key.K, Key.L, Key.Semicolon };
|
||||
|
||||
private SpecialColumnPosition specialColumnPosition;
|
||||
/// <summary>
|
||||
/// The style to use for the special column.
|
||||
|
||||
@@ -96,6 +96,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public class OsuModSpunOut : Mod
|
||||
{
|
||||
public override string Name => "Spun Out";
|
||||
public override string ShortenedName => "SO";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_spunout;
|
||||
public override string Description => @"Spinners will be automatically completed";
|
||||
public override double ScoreMultiplier => 0.9;
|
||||
@@ -106,6 +107,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public class OsuModAutopilot : Mod
|
||||
{
|
||||
public override string Name => "Autopilot";
|
||||
public override string ShortenedName => "AP";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_autopilot;
|
||||
public override string Description => @"Automatic cursor movement - just follow the rhythm.";
|
||||
public override double ScoreMultiplier => 0;
|
||||
@@ -126,6 +128,7 @@ namespace osu.Game.Rulesets.Osu.Mods
|
||||
public class OsuModTarget : Mod
|
||||
{
|
||||
public override string Name => "Target";
|
||||
public override string ShortenedName => "TP";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_target;
|
||||
public override string Description => @"";
|
||||
public override double ScoreMultiplier => 1;
|
||||
|
||||
@@ -112,8 +112,6 @@ namespace osu.Game.Rulesets.Osu
|
||||
}
|
||||
}
|
||||
|
||||
public override Mod GetAutoplayMod() => new OsuModAutoplay();
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_osu_o };
|
||||
|
||||
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new OsuDifficultyCalculator(beatmap);
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Replays
|
||||
{
|
||||
public class OsuReplayInputHandler : FramedReplayInputHandler
|
||||
{
|
||||
public OsuReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
List<OsuAction> actions = new List<OsuAction>();
|
||||
|
||||
if (CurrentFrame?.MouseLeft ?? false) actions.Add(OsuAction.LeftButton);
|
||||
if (CurrentFrame?.MouseRight ?? false) actions.Add(OsuAction.RightButton);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new ReplayState<OsuAction>
|
||||
{
|
||||
Mouse = new ReplayMouseState(ToScreenSpace(Position ?? Vector2.Zero)),
|
||||
PressedActions = actions
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,11 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
@@ -14,6 +17,8 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
{
|
||||
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgement>
|
||||
{
|
||||
public readonly Bindable<ScoringMode> Mode = new Bindable<ScoringMode>(ScoringMode.Exponential);
|
||||
|
||||
public OsuScoreProcessor()
|
||||
{
|
||||
}
|
||||
@@ -23,6 +28,35 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
{
|
||||
}
|
||||
|
||||
private float hpDrainRate;
|
||||
|
||||
private int totalAccurateJudgements;
|
||||
|
||||
private readonly Dictionary<OsuScoreResult, int> scoreResultCounts = new Dictionary<OsuScoreResult, int>();
|
||||
private readonly Dictionary<ComboResult, int> comboResultCounts = new Dictionary<ComboResult, int>();
|
||||
|
||||
private double comboMaxScore;
|
||||
|
||||
protected override void ComputeTargets(Beatmap<OsuHitObject> beatmap)
|
||||
{
|
||||
hpDrainRate = beatmap.BeatmapInfo.Difficulty.DrainRate;
|
||||
totalAccurateJudgements = beatmap.HitObjects.Count;
|
||||
|
||||
foreach (var h in beatmap.HitObjects)
|
||||
{
|
||||
if (h != null)
|
||||
{
|
||||
// TODO: add support for other object types.
|
||||
AddJudgement(new OsuJudgement
|
||||
{
|
||||
MaxScore = OsuScoreResult.Hit300,
|
||||
Score = OsuScoreResult.Hit300,
|
||||
Result = HitResult.Hit
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Reset()
|
||||
{
|
||||
base.Reset();
|
||||
@@ -34,9 +68,6 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
comboResultCounts.Clear();
|
||||
}
|
||||
|
||||
private readonly Dictionary<OsuScoreResult, int> scoreResultCounts = new Dictionary<OsuScoreResult, int>();
|
||||
private readonly Dictionary<ComboResult, int> comboResultCounts = new Dictionary<ComboResult, int>();
|
||||
|
||||
public override void PopulateScore(Score score)
|
||||
{
|
||||
base.PopulateScore(score);
|
||||
@@ -57,28 +88,75 @@ namespace osu.Game.Rulesets.Osu.Scoring
|
||||
comboResultCounts[judgement.Combo] = comboResultCounts.GetOrDefault(judgement.Combo) + 1;
|
||||
}
|
||||
|
||||
switch (judgement.Result)
|
||||
switch (judgement.Score)
|
||||
{
|
||||
case HitResult.Hit:
|
||||
Health.Value += 0.1f;
|
||||
case OsuScoreResult.Hit300:
|
||||
Health.Value += (10.2 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
case HitResult.Miss:
|
||||
Health.Value -= 0.2f;
|
||||
|
||||
case OsuScoreResult.Hit100:
|
||||
Health.Value += (8 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
|
||||
case OsuScoreResult.Hit50:
|
||||
Health.Value += (4 - hpDrainRate) * 0.02;
|
||||
break;
|
||||
|
||||
case OsuScoreResult.SliderTick:
|
||||
Health.Value += Math.Max(7 - hpDrainRate, 0) * 0.01;
|
||||
break;
|
||||
|
||||
case OsuScoreResult.Miss:
|
||||
Health.Value -= hpDrainRate * 0.04;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
int score = 0;
|
||||
int maxScore = 0;
|
||||
calculateScore();
|
||||
}
|
||||
|
||||
private void calculateScore()
|
||||
{
|
||||
int baseScore = 0;
|
||||
double comboScore = 0;
|
||||
|
||||
int baseMaxScore = 0;
|
||||
|
||||
foreach (var j in Judgements)
|
||||
{
|
||||
score += j.ScoreValue;
|
||||
maxScore += j.MaxScoreValue;
|
||||
baseScore += j.ScoreValue;
|
||||
baseMaxScore += j.MaxScoreValue;
|
||||
|
||||
comboScore += j.ScoreValue * (1 + Combo.Value / 10d);
|
||||
}
|
||||
|
||||
TotalScore.Value = score;
|
||||
Accuracy.Value = (double)score / maxScore;
|
||||
Accuracy.Value = (double)baseScore / baseMaxScore;
|
||||
|
||||
if (comboScore > comboMaxScore)
|
||||
comboMaxScore = comboScore;
|
||||
|
||||
if (baseScore == 0)
|
||||
TotalScore.Value = 0;
|
||||
else
|
||||
{
|
||||
// temporary to make scoring feel more like score v1 without being score v1.
|
||||
float exponentialFactor = Mode.Value == ScoringMode.Exponential ? (float)Judgements.Count / 100 : 1;
|
||||
|
||||
TotalScore.Value =
|
||||
(int)
|
||||
(
|
||||
exponentialFactor *
|
||||
700000 * comboScore / comboMaxScore +
|
||||
300000 * Math.Pow(Accuracy.Value, 10) * ((double)Judgements.Count / totalAccurateJudgements) +
|
||||
0 /* bonusScore */
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
public enum ScoringMode
|
||||
{
|
||||
Standardised,
|
||||
Exponential
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -10,9 +10,11 @@ using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
@@ -49,6 +51,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuReplayInputHandler(replay);
|
||||
|
||||
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
<Compile Include="OsuDifficulty\Skills\Speed.cs" />
|
||||
<Compile Include="OsuDifficulty\Utils\History.cs" />
|
||||
<Compile Include="OsuInputManager.cs" />
|
||||
<Compile Include="Replays\OsuReplayInputHandler.cs" />
|
||||
<Compile Include="UI\Cursor\CursorTrail.cs" />
|
||||
<Compile Include="UI\Cursor\GameplayCursor.cs" />
|
||||
<Compile Include="UI\OsuSettings.cs" />
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Replays
|
||||
{
|
||||
@@ -17,21 +16,18 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
var keys = new List<Key>();
|
||||
var actions = new List<TaikoAction>();
|
||||
|
||||
if (CurrentFrame?.MouseRight1 == true)
|
||||
keys.Add(Key.F);
|
||||
actions.Add(TaikoAction.LeftCentre);
|
||||
if (CurrentFrame?.MouseRight2 == true)
|
||||
keys.Add(Key.J);
|
||||
actions.Add(TaikoAction.RightCentre);
|
||||
if (CurrentFrame?.MouseLeft1 == true)
|
||||
keys.Add(Key.D);
|
||||
actions.Add(TaikoAction.LeftRim);
|
||||
if (CurrentFrame?.MouseLeft2 == true)
|
||||
keys.Add(Key.K);
|
||||
actions.Add(TaikoAction.RightRim);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new InputState { Keyboard = new ReplayKeyboardState(keys) }
|
||||
};
|
||||
return new List<InputState> { new ReplayState<TaikoAction> { PressedActions = actions } };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -268,6 +268,7 @@ namespace osu.Game.Rulesets.Taiko.Scoring
|
||||
base.Reset();
|
||||
|
||||
Health.Value = 0;
|
||||
Accuracy.Value = 1;
|
||||
|
||||
bonusScore = 0;
|
||||
comboPortion = 0;
|
||||
|
||||
@@ -95,8 +95,6 @@ namespace osu.Game.Rulesets.Taiko
|
||||
}
|
||||
}
|
||||
|
||||
public override Mod GetAutoplayMod() => new TaikoModAutoplay();
|
||||
|
||||
public override string Description => "osu!taiko";
|
||||
|
||||
public override Drawable CreateIcon() => new SpriteIcon { Icon = FontAwesome.fa_osu_taiko_o };
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace osu.Game.Beatmaps
|
||||
public class Beatmap<T>
|
||||
where T : HitObject
|
||||
{
|
||||
public BeatmapInfo BeatmapInfo;
|
||||
public BeatmapInfo BeatmapInfo = new BeatmapInfo();
|
||||
public ControlPointInfo ControlPointInfo = new ControlPointInfo();
|
||||
public List<BreakPeriod> Breaks = new List<BreakPeriod>();
|
||||
public readonly List<Color4> ComboColors = new List<Color4>
|
||||
@@ -33,7 +33,7 @@ namespace osu.Game.Beatmaps
|
||||
/// <summary>
|
||||
/// The HitObjects this Beatmap contains.
|
||||
/// </summary>
|
||||
public List<T> HitObjects;
|
||||
public List<T> HitObjects = new List<T>();
|
||||
|
||||
/// <summary>
|
||||
/// Total amount of break time in the beatmap.
|
||||
@@ -44,12 +44,13 @@ namespace osu.Game.Beatmaps
|
||||
/// Constructs a new beatmap.
|
||||
/// </summary>
|
||||
/// <param name="original">The original beatmap to use the parameters of.</param>
|
||||
public Beatmap(Beatmap original = null)
|
||||
public Beatmap(Beatmap<T> original = null)
|
||||
{
|
||||
BeatmapInfo = original?.BeatmapInfo.DeepClone() ?? BeatmapInfo;
|
||||
ControlPointInfo = original?.ControlPointInfo ?? ControlPointInfo;
|
||||
Breaks = original?.Breaks ?? Breaks;
|
||||
ComboColors = original?.ComboColors ?? ComboColors;
|
||||
HitObjects = original?.HitObjects ?? HitObjects;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -65,7 +66,6 @@ namespace osu.Game.Beatmaps
|
||||
public Beatmap(Beatmap original = null)
|
||||
: base(original)
|
||||
{
|
||||
HitObjects = original?.HitObjects;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,6 +52,8 @@ namespace osu.Game.Beatmaps
|
||||
[JsonProperty("file_sha2")]
|
||||
public string Hash { get; set; }
|
||||
|
||||
public bool Hidden { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// MD5 is kept for legacy support (matching against replays, osu-web-10 etc.).
|
||||
/// </summary>
|
||||
|
||||
@@ -20,6 +20,9 @@ using osu.Game.IPC;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Rulesets;
|
||||
using SQLite.Net;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using System.Threading.Tasks;
|
||||
using osu.Game.Online.API;
|
||||
|
||||
namespace osu.Game.Beatmaps
|
||||
{
|
||||
@@ -33,11 +36,21 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a single difficulty has been hidden.
|
||||
/// </summary>
|
||||
public event Action<BeatmapInfo> BeatmapHidden;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a <see cref="BeatmapSetInfo"/> is removed from the database.
|
||||
/// </summary>
|
||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||
|
||||
/// <summary>
|
||||
/// Fired when a single difficulty has been restored.
|
||||
/// </summary>
|
||||
public event Action<BeatmapInfo> BeatmapRestored;
|
||||
|
||||
/// <summary>
|
||||
/// A default representation of a WorkingBeatmap to use when no beatmap is available.
|
||||
/// </summary>
|
||||
@@ -53,6 +66,10 @@ namespace osu.Game.Beatmaps
|
||||
|
||||
private readonly BeatmapStore beatmaps;
|
||||
|
||||
private readonly APIAccess api;
|
||||
|
||||
private readonly List<DownloadBeatmapSetRequest> currentDownloads = new List<DownloadBeatmapSetRequest>();
|
||||
|
||||
// ReSharper disable once NotAccessedField.Local (we should keep a reference to this so it is not finalised)
|
||||
private BeatmapIPCChannel ipc;
|
||||
|
||||
@@ -66,16 +83,19 @@ namespace osu.Game.Beatmaps
|
||||
/// </summary>
|
||||
public Func<Storage> GetStableStorage { private get; set; }
|
||||
|
||||
public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, IIpcHost importHost = null)
|
||||
public BeatmapManager(Storage storage, FileStore files, SQLiteConnection connection, RulesetStore rulesets, APIAccess api, IIpcHost importHost = null)
|
||||
{
|
||||
beatmaps = new BeatmapStore(connection);
|
||||
beatmaps.BeatmapSetAdded += s => BeatmapSetAdded?.Invoke(s);
|
||||
beatmaps.BeatmapSetRemoved += s => BeatmapSetRemoved?.Invoke(s);
|
||||
beatmaps.BeatmapHidden += b => BeatmapHidden?.Invoke(b);
|
||||
beatmaps.BeatmapRestored += b => BeatmapRestored?.Invoke(b);
|
||||
|
||||
this.storage = storage;
|
||||
this.files = files;
|
||||
this.connection = connection;
|
||||
this.rulesets = rulesets;
|
||||
this.api = api;
|
||||
|
||||
if (importHost != null)
|
||||
ipc = new BeatmapIPCChannel(importHost, this);
|
||||
@@ -162,24 +182,102 @@ namespace osu.Game.Beatmaps
|
||||
// If we have an ID then we already exist in the database.
|
||||
if (beatmapSetInfo.ID != 0) return;
|
||||
|
||||
lock (beatmaps)
|
||||
beatmaps.Add(beatmapSetInfo);
|
||||
beatmaps.Add(beatmapSetInfo);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Downloads a beatmap.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSetInfo">The <see cref="BeatmapSetInfo"/> to be downloaded.</param>
|
||||
/// <returns>A new <see cref="DownloadBeatmapSetRequest"/>, or an existing one if a download is already in progress.</returns>
|
||||
public DownloadBeatmapSetRequest Download(BeatmapSetInfo beatmapSetInfo)
|
||||
{
|
||||
var existing = GetExistingDownload(beatmapSetInfo);
|
||||
|
||||
if (existing != null) return existing;
|
||||
|
||||
if (api == null) return null;
|
||||
|
||||
ProgressNotification downloadNotification = new ProgressNotification
|
||||
{
|
||||
Text = $"Downloading {beatmapSetInfo.Metadata.Artist} - {beatmapSetInfo.Metadata.Title}",
|
||||
};
|
||||
|
||||
var request = new DownloadBeatmapSetRequest(beatmapSetInfo);
|
||||
|
||||
request.DownloadProgressed += progress =>
|
||||
{
|
||||
downloadNotification.State = ProgressNotificationState.Active;
|
||||
downloadNotification.Progress = progress;
|
||||
};
|
||||
|
||||
request.Success += data =>
|
||||
{
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
|
||||
using (var stream = new MemoryStream(data))
|
||||
using (var archive = new OszArchiveReader(stream))
|
||||
Import(archive);
|
||||
|
||||
currentDownloads.Remove(request);
|
||||
};
|
||||
|
||||
request.Failure += data =>
|
||||
{
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
Logger.Error(data, "Failed to get beatmap download information");
|
||||
currentDownloads.Remove(request);
|
||||
};
|
||||
|
||||
downloadNotification.CancelRequested += () =>
|
||||
{
|
||||
request.Cancel();
|
||||
currentDownloads.Remove(request);
|
||||
downloadNotification.State = ProgressNotificationState.Cancelled;
|
||||
return true;
|
||||
};
|
||||
|
||||
currentDownloads.Add(request);
|
||||
PostNotification?.Invoke(downloadNotification);
|
||||
|
||||
// don't run in the main api queue as this is a long-running task.
|
||||
Task.Run(() => request.Perform(api));
|
||||
|
||||
return request;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get an existing download request if it exists.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The <see cref="BeatmapSetInfo"/> whose download request is wanted.</param>
|
||||
/// <returns>The <see cref="DownloadBeatmapSetRequest"/> object if it exists, or null.</returns>
|
||||
public DownloadBeatmapSetRequest GetExistingDownload(BeatmapSetInfo beatmap) => currentDownloads.Find(d => d.BeatmapSet.OnlineBeatmapSetID == beatmap.OnlineBeatmapSetID);
|
||||
|
||||
/// <summary>
|
||||
/// Delete a beatmap from the manager.
|
||||
/// Is a no-op for already deleted beatmaps.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||
/// <param name="beatmapSet">The beatmap set to delete.</param>
|
||||
public void Delete(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
lock (beatmaps)
|
||||
if (!beatmaps.Delete(beatmapSet)) return;
|
||||
if (!beatmaps.Delete(beatmapSet)) return;
|
||||
|
||||
if (!beatmapSet.Protected)
|
||||
files.Dereference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a beatmap difficulty.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap difficulty to hide.</param>
|
||||
public void Hide(BeatmapInfo beatmap) => beatmaps.Hide(beatmap);
|
||||
|
||||
/// <summary>
|
||||
/// Restore a beatmap difficulty.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap difficulty to restore.</param>
|
||||
public void Restore(BeatmapInfo beatmap) => beatmaps.Restore(beatmap);
|
||||
|
||||
/// <summary>
|
||||
/// Returns a <see cref="BeatmapSetInfo"/> to a usable state if it has previously been deleted but not yet purged.
|
||||
/// Is a no-op for already usable beatmaps.
|
||||
@@ -187,8 +285,7 @@ namespace osu.Game.Beatmaps
|
||||
/// <param name="beatmapSet">The beatmap to restore.</param>
|
||||
public void Undelete(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
lock (beatmaps)
|
||||
if (!beatmaps.Undelete(beatmapSet)) return;
|
||||
if (!beatmaps.Undelete(beatmapSet)) return;
|
||||
|
||||
if (!beatmapSet.Protected)
|
||||
files.Reference(beatmapSet.Files.Select(f => f.FileInfo).ToArray());
|
||||
@@ -248,6 +345,13 @@ namespace osu.Game.Beatmaps
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Refresh an existing instance of a <see cref="BeatmapSetInfo"/> from the store.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">A stale instance.</param>
|
||||
/// <returns>A fresh instance.</returns>
|
||||
public BeatmapSetInfo Refresh(BeatmapSetInfo beatmapSet) => QueryBeatmapSet(s => s.ID == beatmapSet.ID);
|
||||
|
||||
/// <summary>
|
||||
/// Perform a lookup query on available <see cref="BeatmapSetInfo"/>s.
|
||||
/// </summary>
|
||||
@@ -255,7 +359,7 @@ namespace osu.Game.Beatmaps
|
||||
/// <returns>Results from the provided query.</returns>
|
||||
public List<BeatmapSetInfo> QueryBeatmapSets(Expression<Func<BeatmapSetInfo, bool>> query)
|
||||
{
|
||||
lock (beatmaps) return beatmaps.QueryAndPopulate(query);
|
||||
return beatmaps.QueryAndPopulate(query);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -265,15 +369,12 @@ namespace osu.Game.Beatmaps
|
||||
/// <returns>The first result for the provided query, or null if no results were found.</returns>
|
||||
public BeatmapInfo QueryBeatmap(Func<BeatmapInfo, bool> query)
|
||||
{
|
||||
lock (beatmaps)
|
||||
{
|
||||
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
|
||||
BeatmapInfo set = beatmaps.Query<BeatmapInfo>().FirstOrDefault(query);
|
||||
|
||||
if (set != null)
|
||||
beatmaps.Populate(set);
|
||||
if (set != null)
|
||||
beatmaps.Populate(set);
|
||||
|
||||
return set;
|
||||
}
|
||||
return set;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -16,11 +16,14 @@ namespace osu.Game.Beatmaps
|
||||
public event Action<BeatmapSetInfo> BeatmapSetAdded;
|
||||
public event Action<BeatmapSetInfo> BeatmapSetRemoved;
|
||||
|
||||
public event Action<BeatmapInfo> BeatmapHidden;
|
||||
public event Action<BeatmapInfo> BeatmapRestored;
|
||||
|
||||
/// <summary>
|
||||
/// The current version of this store. Used for migrations (see <see cref="PerformMigration(int, int)"/>).
|
||||
/// The initial version is 1.
|
||||
/// </summary>
|
||||
protected override int StoreVersion => 3;
|
||||
protected override int StoreVersion => 4;
|
||||
|
||||
public BeatmapStore(SQLiteConnection connection)
|
||||
: base(connection)
|
||||
@@ -81,6 +84,10 @@ namespace osu.Game.Beatmaps
|
||||
// Added MD5Hash column to BeatmapInfo
|
||||
Connection.MigrateTable<BeatmapInfo>();
|
||||
break;
|
||||
case 4:
|
||||
// Added Hidden column to BeatmapInfo
|
||||
Connection.MigrateTable<BeatmapInfo>();
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -100,7 +107,7 @@ namespace osu.Game.Beatmaps
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Delete a <see cref="BeatmapSetInfo"/> to the database.
|
||||
/// Delete a <see cref="BeatmapSetInfo"/> from the database.
|
||||
/// </summary>
|
||||
/// <param name="beatmapSet">The beatmap to delete.</param>
|
||||
/// <returns>Whether the beatmap's <see cref="BeatmapSetInfo.DeletePending"/> was changed.</returns>
|
||||
@@ -131,6 +138,38 @@ namespace osu.Game.Beatmaps
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Hide a <see cref="BeatmapInfo"/> in the database.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap to hide.</param>
|
||||
/// <returns>Whether the beatmap's <see cref="BeatmapInfo.Hidden"/> was changed.</returns>
|
||||
public bool Hide(BeatmapInfo beatmap)
|
||||
{
|
||||
if (beatmap.Hidden) return false;
|
||||
|
||||
beatmap.Hidden = true;
|
||||
Connection.Update(beatmap);
|
||||
|
||||
BeatmapHidden?.Invoke(beatmap);
|
||||
return true;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Restore a previously hidden <see cref="BeatmapInfo"/>.
|
||||
/// </summary>
|
||||
/// <param name="beatmap">The beatmap to restore.</param>
|
||||
/// <returns>Whether the beatmap's <see cref="BeatmapInfo.Hidden"/> was changed.</returns>
|
||||
public bool Restore(BeatmapInfo beatmap)
|
||||
{
|
||||
if (!beatmap.Hidden) return false;
|
||||
|
||||
beatmap.Hidden = false;
|
||||
Connection.Update(beatmap);
|
||||
|
||||
BeatmapRestored?.Invoke(beatmap);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void cleanupPendingDeletions()
|
||||
{
|
||||
Connection.RunInTransaction(() =>
|
||||
|
||||
@@ -11,6 +11,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
public class BeatmapGroup : IStateful<BeatmapGroupState>
|
||||
{
|
||||
public event Action<BeatmapGroupState> StateChanged;
|
||||
|
||||
public BeatmapPanel SelectedPanel;
|
||||
|
||||
/// <summary>
|
||||
@@ -23,19 +25,26 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
/// </summary>
|
||||
public Action<BeatmapInfo> StartRequested;
|
||||
|
||||
public BeatmapSetHeader Header;
|
||||
public Action<BeatmapSetInfo> DeleteRequested;
|
||||
|
||||
private BeatmapGroupState state;
|
||||
public Action<BeatmapSetInfo> RestoreHiddenRequested;
|
||||
|
||||
public Action<BeatmapInfo> HideDifficultyRequested;
|
||||
|
||||
public BeatmapSetHeader Header;
|
||||
|
||||
public List<BeatmapPanel> BeatmapPanels;
|
||||
|
||||
public BeatmapSetInfo BeatmapSet;
|
||||
|
||||
private BeatmapGroupState state;
|
||||
public BeatmapGroupState State
|
||||
{
|
||||
get { return state; }
|
||||
set
|
||||
{
|
||||
state = value;
|
||||
|
||||
switch (value)
|
||||
{
|
||||
case BeatmapGroupState.Expanded:
|
||||
@@ -54,7 +63,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
panel.State = PanelSelectedState.Hidden;
|
||||
break;
|
||||
}
|
||||
state = value;
|
||||
|
||||
StateChanged?.Invoke(state);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -66,14 +76,17 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
Header = new BeatmapSetHeader(beatmap)
|
||||
{
|
||||
GainedSelection = headerGainedSelection,
|
||||
DeleteRequested = b => DeleteRequested(b),
|
||||
RestoreHiddenRequested = b => RestoreHiddenRequested(b),
|
||||
RelativeSizeAxes = Axes.X,
|
||||
};
|
||||
|
||||
BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.OrderBy(b => b.StarDifficulty).ToList();
|
||||
BeatmapSet.Beatmaps = BeatmapSet.Beatmaps.Where(b => !b.Hidden).OrderBy(b => b.StarDifficulty).ToList();
|
||||
BeatmapPanels = BeatmapSet.Beatmaps.Select(b => new BeatmapPanel(b)
|
||||
{
|
||||
Alpha = 0,
|
||||
GainedSelection = panelGainedSelection,
|
||||
HideRequested = p => HideDifficultyRequested?.Invoke(p),
|
||||
StartRequested = p => { StartRequested?.Invoke(p.Beatmap); },
|
||||
RelativeSizeAxes = Axes.X,
|
||||
}).ToList();
|
||||
@@ -81,6 +94,7 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
Header.AddDifficultyIcons(BeatmapPanels);
|
||||
}
|
||||
|
||||
|
||||
private void headerGainedSelection(BeatmapSetHeader panel)
|
||||
{
|
||||
State = BeatmapGroupState.Expanded;
|
||||
|
||||
@@ -5,6 +5,7 @@ using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
@@ -14,16 +15,20 @@ using OpenTK.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
public class BeatmapPanel : Panel
|
||||
public class BeatmapPanel : Panel, IHasContextMenu
|
||||
{
|
||||
public BeatmapInfo Beatmap;
|
||||
private readonly Sprite background;
|
||||
|
||||
public Action<BeatmapPanel> GainedSelection;
|
||||
public Action<BeatmapPanel> StartRequested;
|
||||
public Action<BeatmapPanel> EditRequested;
|
||||
public Action<BeatmapInfo> HideRequested;
|
||||
|
||||
private readonly Triangles triangles;
|
||||
private readonly StarCounter starCounter;
|
||||
|
||||
@@ -148,5 +153,12 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public MenuItem[] ContextMenuItems => new MenuItem[]
|
||||
{
|
||||
new OsuMenuItem("Play", MenuItemType.Highlighted, () => StartRequested?.Invoke(this)),
|
||||
new OsuMenuItem("Edit", MenuItemType.Standard, () => EditRequested?.Invoke(this)),
|
||||
new OsuMenuItem("Hide", MenuItemType.Destructive, () => HideRequested?.Invoke(Beatmap)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -3,22 +3,31 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Colour;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
public class BeatmapSetHeader : Panel
|
||||
public class BeatmapSetHeader : Panel, IHasContextMenu
|
||||
{
|
||||
public Action<BeatmapSetHeader> GainedSelection;
|
||||
|
||||
public Action<BeatmapSetInfo> DeleteRequested;
|
||||
|
||||
public Action<BeatmapSetInfo> RestoreHiddenRequested;
|
||||
|
||||
private readonly SpriteText title;
|
||||
private readonly SpriteText artist;
|
||||
|
||||
@@ -148,5 +157,23 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
foreach (var p in panels)
|
||||
difficultyIcons.Add(new DifficultyIcon(p.Beatmap));
|
||||
}
|
||||
|
||||
public MenuItem[] ContextMenuItems
|
||||
{
|
||||
get
|
||||
{
|
||||
List<MenuItem> items = new List<MenuItem>();
|
||||
|
||||
if (State == PanelSelectedState.NotSelected)
|
||||
items.Add(new OsuMenuItem("Expand", MenuItemType.Highlighted, () => State = PanelSelectedState.Selected));
|
||||
|
||||
if (beatmap.BeatmapSetInfo.Beatmaps.Any(b => b.Hidden))
|
||||
items.Add(new OsuMenuItem("Restore all hidden", MenuItemType.Standard, () => RestoreHiddenRequested?.Invoke(beatmap.BeatmapSetInfo)));
|
||||
|
||||
items.Add(new OsuMenuItem("Delete", MenuItemType.Destructive, () => DeleteRequested?.Invoke(beatmap.BeatmapSetInfo)));
|
||||
|
||||
return items.ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -33,7 +33,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
Normal,
|
||||
Hard,
|
||||
Insane,
|
||||
Expert
|
||||
Expert,
|
||||
ExpertPlus
|
||||
}
|
||||
|
||||
private DifficultyRating getDifficultyRating(BeatmapInfo beatmap)
|
||||
@@ -44,7 +45,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
if (rating < 2.25) return DifficultyRating.Normal;
|
||||
if (rating < 3.75) return DifficultyRating.Hard;
|
||||
if (rating < 5.25) return DifficultyRating.Insane;
|
||||
return DifficultyRating.Expert;
|
||||
if (rating < 6.75) return DifficultyRating.Expert;
|
||||
return DifficultyRating.ExpertPlus;
|
||||
}
|
||||
|
||||
private Color4 getColour(BeatmapInfo beatmap)
|
||||
@@ -55,12 +57,14 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
return palette.Green;
|
||||
default:
|
||||
case DifficultyRating.Normal:
|
||||
return palette.Yellow;
|
||||
return palette.Blue;
|
||||
case DifficultyRating.Hard:
|
||||
return palette.Pink;
|
||||
return palette.Yellow;
|
||||
case DifficultyRating.Insane:
|
||||
return palette.Purple;
|
||||
return palette.Pink;
|
||||
case DifficultyRating.Expert:
|
||||
return palette.Purple;
|
||||
case DifficultyRating.ExpertPlus:
|
||||
return palette.Gray0;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@@ -15,6 +16,8 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
{
|
||||
public const float MAX_HEIGHT = 80;
|
||||
|
||||
public event Action<PanelSelectedState> StateChanged;
|
||||
|
||||
public override bool RemoveWhenNotAlive => false;
|
||||
|
||||
private readonly Container nestedContainer;
|
||||
@@ -77,11 +80,15 @@ namespace osu.Game.Beatmaps.Drawables
|
||||
|
||||
set
|
||||
{
|
||||
if (state == value) return;
|
||||
if (state == value)
|
||||
return;
|
||||
|
||||
var last = state;
|
||||
state = value;
|
||||
|
||||
ApplyState(last);
|
||||
|
||||
StateChanged?.Invoke(State);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -7,7 +7,6 @@ using osu.Framework.Audio.Track;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Game.Rulesets;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
@@ -42,10 +41,7 @@ namespace osu.Game.Beatmaps
|
||||
this.game = game;
|
||||
}
|
||||
|
||||
protected override Beatmap GetBeatmap() => new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>(),
|
||||
};
|
||||
protected override Beatmap GetBeatmap() => new Beatmap();
|
||||
|
||||
protected override Texture GetBackground() => game.Textures.Get(@"Backgrounds/bg4");
|
||||
|
||||
@@ -59,8 +55,6 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
public override IEnumerable<Mod> GetModsFor(ModType type) => new Mod[] { };
|
||||
|
||||
public override Mod GetAutoplayMod() => new ModAutoplay();
|
||||
|
||||
public override RulesetContainer CreateRulesetContainerWith(WorkingBeatmap beatmap, bool isForCurrentRuleset)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
|
||||
namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
@@ -21,7 +20,7 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
string line;
|
||||
do { line = stream.ReadLine()?.Trim(); }
|
||||
while (line != null && line.Length == 0);
|
||||
while (line != null && line.Length == 0);
|
||||
|
||||
if (line == null || !decoders.ContainsKey(line))
|
||||
throw new IOException(@"Unknown file format");
|
||||
@@ -47,7 +46,6 @@ namespace osu.Game.Beatmaps.Formats
|
||||
{
|
||||
var beatmap = new Beatmap
|
||||
{
|
||||
HitObjects = new List<HitObject>(),
|
||||
BeatmapInfo = new BeatmapInfo
|
||||
{
|
||||
Metadata = new BeatmapMetadata(),
|
||||
|
||||
@@ -54,7 +54,7 @@ namespace osu.Game.Beatmaps
|
||||
{
|
||||
if (beatmap != null) return beatmap;
|
||||
|
||||
beatmap = GetBeatmap();
|
||||
beatmap = GetBeatmap() ?? new Beatmap();
|
||||
|
||||
// use the database-backed info.
|
||||
beatmap.BeatmapInfo = BeatmapInfo;
|
||||
|
||||
@@ -19,12 +19,12 @@ namespace osu.Game.Graphics.Containers
|
||||
samplePopIn = audio.Sample.Get(@"UI/melodic-5");
|
||||
samplePopOut = audio.Sample.Get(@"UI/melodic-4");
|
||||
|
||||
StateChanged += OsuFocusedOverlayContainer_StateChanged;
|
||||
StateChanged += onStateChanged;
|
||||
}
|
||||
|
||||
private void OsuFocusedOverlayContainer_StateChanged(VisibilityContainer arg1, Visibility arg2)
|
||||
private void onStateChanged(Visibility visibility)
|
||||
{
|
||||
switch (arg2)
|
||||
switch (visibility)
|
||||
{
|
||||
case Visibility.Visible:
|
||||
samplePopIn?.Play();
|
||||
|
||||
@@ -9,6 +9,6 @@ namespace osu.Game.Graphics.Cursor
|
||||
{
|
||||
public class OsuContextMenuContainer : ContextMenuContainer
|
||||
{
|
||||
protected override ContextMenu<ContextMenuItem> CreateContextMenu() => new OsuContextMenu<ContextMenuItem>();
|
||||
protected override Menu CreateMenu() => new OsuContextMenu();
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using osu.Framework;
|
||||
using osu.Framework.Graphics;
|
||||
@@ -35,6 +36,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
private class BreadcrumbTabItem : OsuTabItem, IStateful<Visibility>
|
||||
{
|
||||
public event Action<Visibility> StateChanged;
|
||||
|
||||
public readonly SpriteIcon Chevron;
|
||||
|
||||
//don't allow clicking between transitions and don't make the chevron clickable
|
||||
@@ -42,6 +45,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
public override bool HandleInput => State == Visibility.Visible;
|
||||
|
||||
private Visibility state;
|
||||
|
||||
public Visibility State
|
||||
{
|
||||
get { return state; }
|
||||
@@ -62,6 +66,8 @@ namespace osu.Game.Graphics.UserInterface
|
||||
this.FadeOut(transition_duration, Easing.OutQuint);
|
||||
this.ScaleTo(new Vector2(0.8f, 1f), transition_duration, Easing.OutQuint);
|
||||
}
|
||||
|
||||
StateChanged?.Invoke(State);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,52 +1,39 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuContextMenu<TItem> : ContextMenu<TItem>
|
||||
where TItem : ContextMenuItem
|
||||
public class OsuContextMenu : OsuMenu
|
||||
{
|
||||
protected override Menu<TItem> CreateMenu() => new CustomMenu();
|
||||
private const int fade_duration = 250;
|
||||
|
||||
public class CustomMenu : Menu<TItem>
|
||||
public OsuContextMenu()
|
||||
: base(Direction.Vertical)
|
||||
{
|
||||
private const int fade_duration = 250;
|
||||
|
||||
public CustomMenu()
|
||||
MaskingContainer.CornerRadius = 5;
|
||||
MaskingContainer.EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
CornerRadius = 5;
|
||||
ItemsContainer.Padding = new MarginPadding { Vertical = OsuContextMenuItem.MARGIN_VERTICAL };
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.1f),
|
||||
Radius = 4,
|
||||
};
|
||||
}
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.1f),
|
||||
Radius = 4,
|
||||
};
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Background.Colour = colours.ContextMenuGray;
|
||||
}
|
||||
|
||||
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
|
||||
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
|
||||
|
||||
protected override void UpdateContentHeight()
|
||||
{
|
||||
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
|
||||
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
|
||||
}
|
||||
ItemsContainer.Padding = new MarginPadding { Vertical = DrawableOsuMenuItem.MARGIN_VERTICAL };
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.ContextMenuGray;
|
||||
}
|
||||
|
||||
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
|
||||
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
@@ -1,114 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuContextMenuItem : ContextMenuItem
|
||||
{
|
||||
private const int transition_length = 80;
|
||||
private const int margin_horizontal = 17;
|
||||
public const int MARGIN_VERTICAL = 4;
|
||||
private const int text_size = 17;
|
||||
|
||||
private OsuSpriteText text;
|
||||
private OsuSpriteText textBold;
|
||||
|
||||
private SampleChannel sampleClick;
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
private readonly MenuItemType type;
|
||||
|
||||
protected override Container CreateTextContainer(string title) => new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Text = title,
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
},
|
||||
textBold = new OsuSpriteText
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Text = title,
|
||||
Font = @"Exo2.0-Bold",
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public OsuContextMenuItem(string title, MenuItemType type = MenuItemType.Standard) : base(title)
|
||||
{
|
||||
this.type = type;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
sampleHover = audio.Sample.Get(@"UI/generic-hover");
|
||||
sampleClick = audio.Sample.Get(@"UI/generic-click");
|
||||
|
||||
BackgroundColour = Color4.Transparent;
|
||||
BackgroundColourHover = OsuColour.FromHex(@"172023");
|
||||
|
||||
updateTextColour();
|
||||
}
|
||||
|
||||
private void updateTextColour()
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MenuItemType.Standard:
|
||||
textBold.Colour = text.Colour = Color4.White;
|
||||
break;
|
||||
case MenuItemType.Destructive:
|
||||
textBold.Colour = text.Colour = Color4.Red;
|
||||
break;
|
||||
case MenuItemType.Highlighted:
|
||||
textBold.Colour = text.Colour = OsuColour.FromHex(@"ffcc22");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
sampleHover.Play();
|
||||
textBold.FadeIn(transition_length, Easing.OutQuint);
|
||||
text.FadeOut(transition_length, Easing.OutQuint);
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
textBold.FadeOut(transition_length, Easing.OutQuint);
|
||||
text.FadeIn(transition_length, Easing.OutQuint);
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
sampleClick.Play();
|
||||
return base.OnClick(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -14,107 +14,185 @@ using OpenTK;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuDropdown<T> : Dropdown<T>
|
||||
public class OsuDropdown<T> : Dropdown<T>, IHasAccentColour
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader { AccentColour = AccentColour };
|
||||
|
||||
protected override Menu CreateMenu() => new OsuMenu();
|
||||
|
||||
private Color4? accentColour;
|
||||
public virtual Color4 AccentColour
|
||||
private Color4 accentColour;
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour.GetValueOrDefault(); }
|
||||
get { return accentColour; }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
if (Header != null)
|
||||
((OsuDropdownHeader)Header).AccentColour = value;
|
||||
foreach (var item in MenuItems.OfType<OsuDropdownMenuItem>())
|
||||
item.AccentColour = value;
|
||||
updateAccentColour();
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
if (accentColour == null)
|
||||
AccentColour = colours.PinkDarker;
|
||||
if (accentColour == default(Color4))
|
||||
accentColour = colours.PinkDarker;
|
||||
updateAccentColour();
|
||||
|
||||
}
|
||||
|
||||
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value) => new OsuDropdownMenuItem(text, value) { AccentColour = AccentColour };
|
||||
|
||||
public class OsuDropdownMenuItem : DropdownMenuItem<T>
|
||||
private void updateAccentColour()
|
||||
{
|
||||
public OsuDropdownMenuItem(string text, T current) : base(text, current)
|
||||
var header = Header as IHasAccentColour;
|
||||
if (header != null) header.AccentColour = accentColour;
|
||||
|
||||
var menu = Menu as IHasAccentColour;
|
||||
if (menu != null) menu.AccentColour = accentColour;
|
||||
}
|
||||
|
||||
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader();
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new OsuDropdownMenu();
|
||||
|
||||
#region OsuDropdownMenu
|
||||
protected class OsuDropdownMenu : DropdownMenu, IHasAccentColour
|
||||
{
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
public OsuDropdownMenu()
|
||||
{
|
||||
Foreground.Padding = new MarginPadding(2);
|
||||
CornerRadius = 4;
|
||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 6;
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
ItemsContainer.Padding = new MarginPadding(5);
|
||||
}
|
||||
|
||||
Children = new[]
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
|
||||
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
|
||||
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
protected override void UpdateSize(Vector2 newSize)
|
||||
{
|
||||
if (Direction == Direction.Vertical)
|
||||
{
|
||||
new FillFlowContainer
|
||||
Width = newSize.X;
|
||||
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
|
||||
}
|
||||
else
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Chevron = new SpriteIcon
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Icon = FontAwesome.fa_chevron_right,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.5f,
|
||||
Size = new Vector2(8),
|
||||
Margin = new MarginPadding { Left = 3, Right = 3 },
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
},
|
||||
Label = new OsuSpriteText {
|
||||
Text = text,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
}
|
||||
}
|
||||
Height = newSize.Y;
|
||||
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Color4? accentColour;
|
||||
|
||||
protected readonly SpriteIcon Chevron;
|
||||
protected readonly OsuSpriteText Label;
|
||||
|
||||
protected override void FormatForeground(bool hover = false)
|
||||
{
|
||||
base.FormatForeground(hover);
|
||||
Chevron.Alpha = hover ? 1 : 0;
|
||||
}
|
||||
|
||||
private Color4 accentColour;
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour.GetValueOrDefault(); }
|
||||
get { return accentColour; }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
BackgroundColourHover = BackgroundColourSelected = value;
|
||||
FormatBackground();
|
||||
FormatForeground();
|
||||
foreach (var c in Children.OfType<IHasAccentColour>())
|
||||
c.AccentColour = value;
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = Color4.Transparent;
|
||||
BackgroundColourHover = accentColour ?? colours.PinkDarker;
|
||||
BackgroundColourSelected = Color4.Black.Opacity(0.5f);
|
||||
}
|
||||
}
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuDropdownMenuItem(item) { AccentColour = accentColour };
|
||||
|
||||
public class OsuDropdownHeader : DropdownHeader
|
||||
#region DrawableOsuDropdownMenuItem
|
||||
protected class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem, IHasAccentColour
|
||||
{
|
||||
private Color4? accentColour;
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour ?? nonAccentSelectedColour; }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
updateColours();
|
||||
}
|
||||
}
|
||||
|
||||
private void updateColours()
|
||||
{
|
||||
BackgroundColourHover = accentColour ?? nonAccentHoverColour;
|
||||
BackgroundColourSelected = accentColour ?? nonAccentSelectedColour;
|
||||
UpdateBackgroundColour();
|
||||
UpdateForegroundColour();
|
||||
}
|
||||
|
||||
private Color4 nonAccentHoverColour;
|
||||
private Color4 nonAccentSelectedColour;
|
||||
|
||||
public DrawableOsuDropdownMenuItem(MenuItem item)
|
||||
: base(item)
|
||||
{
|
||||
Foreground.Padding = new MarginPadding(2);
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 6;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = Color4.Transparent;
|
||||
|
||||
nonAccentHoverColour = colours.PinkDarker;
|
||||
nonAccentSelectedColour = Color4.Black.Opacity(0.5f);
|
||||
updateColours();
|
||||
}
|
||||
|
||||
protected override void UpdateForegroundColour()
|
||||
{
|
||||
base.UpdateForegroundColour();
|
||||
|
||||
var content = Foreground.Children.FirstOrDefault() as Content;
|
||||
if (content != null) content.Chevron.Alpha = IsHovered ? 1 : 0;
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new Content();
|
||||
|
||||
protected new class Content : FillFlowContainer, IHasText
|
||||
{
|
||||
public string Text
|
||||
{
|
||||
get { return Label.Text; }
|
||||
set { Label.Text = value; }
|
||||
}
|
||||
|
||||
public readonly OsuSpriteText Label;
|
||||
public readonly SpriteIcon Chevron;
|
||||
|
||||
public Content()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
Direction = FillDirection.Horizontal;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Chevron = new SpriteIcon
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Icon = FontAwesome.fa_chevron_right,
|
||||
Colour = Color4.Black,
|
||||
Alpha = 0.5f,
|
||||
Size = new Vector2(8),
|
||||
Margin = new MarginPadding { Left = 3, Right = 3 },
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
},
|
||||
Label = new OsuSpriteText
|
||||
{
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
public class OsuDropdownHeader : DropdownHeader, IHasAccentColour
|
||||
{
|
||||
protected readonly SpriteText Text;
|
||||
protected override string Label
|
||||
@@ -125,14 +203,14 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected readonly SpriteIcon Icon;
|
||||
|
||||
private Color4? accentColour;
|
||||
private Color4 accentColour;
|
||||
public virtual Color4 AccentColour
|
||||
{
|
||||
get { return accentColour.GetValueOrDefault(); }
|
||||
get { return accentColour; }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
BackgroundColourHover = value;
|
||||
BackgroundColourHover = accentColour;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -167,7 +245,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||
BackgroundColourHover = accentColour ?? colours.PinkDarker;
|
||||
BackgroundColourHover = colours.PinkDarker;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,32 +1,170 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuMenu : Menu
|
||||
{
|
||||
public OsuMenu()
|
||||
public OsuMenu(Direction direction, bool topLevelMenu = false)
|
||||
: base(direction, topLevelMenu)
|
||||
{
|
||||
CornerRadius = 4;
|
||||
Background.Colour = Color4.Black.Opacity(0.5f);
|
||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||
|
||||
MaskingContainer.CornerRadius = 4;
|
||||
ItemsContainer.Padding = new MarginPadding(5);
|
||||
}
|
||||
|
||||
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
|
||||
|
||||
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
|
||||
|
||||
protected override void UpdateContentHeight()
|
||||
protected override void UpdateSize(Vector2 newSize)
|
||||
{
|
||||
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
|
||||
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
|
||||
if (Direction == Direction.Vertical)
|
||||
{
|
||||
Width = newSize.X;
|
||||
this.ResizeHeightTo(newSize.Y, 300, Easing.OutQuint);
|
||||
}
|
||||
else
|
||||
{
|
||||
Height = newSize.Y;
|
||||
this.ResizeWidthTo(newSize.X, 300, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuMenuItem(item);
|
||||
|
||||
protected override Menu CreateSubMenu() => new OsuMenu(Direction.Vertical)
|
||||
{
|
||||
Anchor = Direction == Direction.Horizontal ? Anchor.BottomLeft : Anchor.TopRight
|
||||
};
|
||||
|
||||
protected class DrawableOsuMenuItem : DrawableMenuItem
|
||||
{
|
||||
private const int margin_horizontal = 17;
|
||||
private const int text_size = 17;
|
||||
private const int transition_length = 80;
|
||||
public const int MARGIN_VERTICAL = 4;
|
||||
|
||||
private SampleChannel sampleClick;
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
private TextContainer text;
|
||||
|
||||
public DrawableOsuMenuItem(MenuItem item)
|
||||
: base(item)
|
||||
{
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
sampleHover = audio.Sample.Get(@"UI/generic-hover");
|
||||
sampleClick = audio.Sample.Get(@"UI/generic-click");
|
||||
|
||||
BackgroundColour = Color4.Transparent;
|
||||
BackgroundColourHover = OsuColour.FromHex(@"172023");
|
||||
|
||||
updateTextColour();
|
||||
}
|
||||
|
||||
private void updateTextColour()
|
||||
{
|
||||
switch ((Item as OsuMenuItem)?.Type)
|
||||
{
|
||||
default:
|
||||
case MenuItemType.Standard:
|
||||
text.Colour = Color4.White;
|
||||
break;
|
||||
case MenuItemType.Destructive:
|
||||
text.Colour = Color4.Red;
|
||||
break;
|
||||
case MenuItemType.Highlighted:
|
||||
text.Colour = OsuColour.FromHex(@"ffcc22");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
sampleHover.Play();
|
||||
text.BoldText.FadeIn(transition_length, Easing.OutQuint);
|
||||
text.NormalText.FadeOut(transition_length, Easing.OutQuint);
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
text.BoldText.FadeOut(transition_length, Easing.OutQuint);
|
||||
text.NormalText.FadeIn(transition_length, Easing.OutQuint);
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
sampleClick.Play();
|
||||
return base.OnClick(state);
|
||||
}
|
||||
|
||||
protected sealed override Drawable CreateContent() => text = CreateTextContainer();
|
||||
protected virtual TextContainer CreateTextContainer() => new TextContainer();
|
||||
|
||||
protected class TextContainer : Container, IHasText
|
||||
{
|
||||
public string Text
|
||||
{
|
||||
get { return NormalText.Text; }
|
||||
set
|
||||
{
|
||||
NormalText.Text = value;
|
||||
BoldText.Text = value;
|
||||
}
|
||||
}
|
||||
|
||||
public readonly SpriteText NormalText;
|
||||
public readonly SpriteText BoldText;
|
||||
|
||||
public TextContainer()
|
||||
{
|
||||
Anchor = Anchor.CentreLeft;
|
||||
Origin = Anchor.CentreLeft;
|
||||
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
NormalText = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
},
|
||||
BoldText = new OsuSpriteText
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Font = @"Exo2.0-Bold",
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,25 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuMenuItem : MenuItem
|
||||
{
|
||||
public readonly MenuItemType Type;
|
||||
|
||||
public OsuMenuItem(string text, MenuItemType type = MenuItemType.Standard)
|
||||
: base(text)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
|
||||
public OsuMenuItem(string text, MenuItemType type, Action action)
|
||||
: base(text, action)
|
||||
{
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,11 +1,16 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Platform;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
@@ -15,6 +20,49 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
public override bool AllowClipboardExport => false;
|
||||
|
||||
private readonly CapsWarning warning;
|
||||
|
||||
private GameHost host;
|
||||
|
||||
public OsuPasswordTextBox()
|
||||
{
|
||||
Add(warning = new CapsWarning
|
||||
{
|
||||
Size = new Vector2(20),
|
||||
Origin = Anchor.CentreRight,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Margin = new MarginPadding { Right = 10 },
|
||||
Alpha = 0,
|
||||
});
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(GameHost host)
|
||||
{
|
||||
this.host = host;
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
{
|
||||
if (args.Key == Key.CapsLock)
|
||||
updateCapsWarning(host.CapsLockEnabled);
|
||||
return base.OnKeyDown(state, args);
|
||||
}
|
||||
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
updateCapsWarning(host.CapsLockEnabled);
|
||||
base.OnFocus(state);
|
||||
}
|
||||
|
||||
protected override void OnFocusLost(InputState state)
|
||||
{
|
||||
updateCapsWarning(false);
|
||||
base.OnFocusLost(state);
|
||||
}
|
||||
|
||||
private void updateCapsWarning(bool visible) => warning.FadeTo(visible ? 1 : 0, 250, Easing.OutQuint);
|
||||
|
||||
public class PasswordMaskChar : Container
|
||||
{
|
||||
private readonly CircularContainer circle;
|
||||
@@ -51,5 +99,21 @@ namespace osu.Game.Graphics.UserInterface
|
||||
circle.ResizeTo(new Vector2(0.8f), 500, Easing.OutQuint);
|
||||
}
|
||||
}
|
||||
|
||||
private class CapsWarning : SpriteIcon, IHasTooltip
|
||||
{
|
||||
public string TooltipText => @"Caps lock is active";
|
||||
|
||||
public CapsWarning()
|
||||
{
|
||||
Icon = FontAwesome.fa_warning;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colour)
|
||||
{
|
||||
Colour = colour.YellowLight;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -37,34 +37,34 @@ namespace osu.Game.Graphics.UserInterface
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
if (accentColour == null)
|
||||
if (accentColour == default(Color4))
|
||||
AccentColour = colours.Blue;
|
||||
}
|
||||
|
||||
private Color4? accentColour;
|
||||
private Color4 accentColour;
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour.GetValueOrDefault(); }
|
||||
get { return accentColour; }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
var dropDown = Dropdown as OsuTabDropdown;
|
||||
if (dropDown != null)
|
||||
dropDown.AccentColour = value;
|
||||
foreach (var item in TabContainer.Children.OfType<OsuTabItem>())
|
||||
item.AccentColour = value;
|
||||
var dropdown = Dropdown as IHasAccentColour;
|
||||
if (dropdown != null)
|
||||
dropdown.AccentColour = value;
|
||||
foreach (var i in TabContainer.Children.OfType<IHasAccentColour>())
|
||||
i.AccentColour = value;
|
||||
}
|
||||
}
|
||||
|
||||
public class OsuTabItem : TabItem<T>
|
||||
public class OsuTabItem : TabItem<T>, IHasAccentColour
|
||||
{
|
||||
protected readonly SpriteText Text;
|
||||
private readonly Box box;
|
||||
|
||||
private Color4? accentColour;
|
||||
private Color4 accentColour;
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour.GetValueOrDefault(); }
|
||||
get { return accentColour; }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
@@ -103,7 +103,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
if (accentColour == null)
|
||||
if (accentColour == default(Color4))
|
||||
AccentColour = colours.Blue;
|
||||
}
|
||||
|
||||
@@ -140,38 +140,55 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected override void OnDeactivated() => fadeInactive();
|
||||
}
|
||||
|
||||
// todo: this needs to go
|
||||
private class OsuTabDropdown : OsuDropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
};
|
||||
|
||||
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value)
|
||||
{
|
||||
var item = base.CreateMenuItem(text, value);
|
||||
item.ForegroundColourHover = Color4.Black;
|
||||
return item;
|
||||
}
|
||||
|
||||
public OsuTabDropdown()
|
||||
{
|
||||
DropdownMenu.Anchor = Anchor.TopRight;
|
||||
DropdownMenu.Origin = Anchor.TopRight;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
DropdownMenu.Background.Colour = Color4.Black.Opacity(0.7f);
|
||||
DropdownMenu.MaxHeight = 400;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new OsuTabDropdownMenu();
|
||||
|
||||
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight
|
||||
};
|
||||
|
||||
private class OsuTabDropdownMenu : OsuDropdownMenu
|
||||
{
|
||||
public OsuTabDropdownMenu()
|
||||
{
|
||||
Anchor = Anchor.TopRight;
|
||||
Origin = Anchor.TopRight;
|
||||
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||
MaxHeight = 400;
|
||||
}
|
||||
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableOsuTabDropdownMenuItem(item) { AccentColour = AccentColour };
|
||||
|
||||
private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem
|
||||
{
|
||||
public DrawableOsuTabDropdownMenuItem(MenuItem item)
|
||||
: base(item)
|
||||
{
|
||||
ForegroundColourHover = Color4.Black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected class OsuTabDropdownHeader : OsuDropdownHeader
|
||||
{
|
||||
public override Color4 AccentColour
|
||||
{
|
||||
get { return base.AccentColour; }
|
||||
get
|
||||
{
|
||||
return base.AccentColour;
|
||||
}
|
||||
|
||||
set
|
||||
{
|
||||
base.AccentColour = value;
|
||||
@@ -179,18 +196,6 @@ namespace osu.Game.Graphics.UserInterface
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
Foreground.Colour = BackgroundColour;
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
Foreground.Colour = BackgroundColourHover;
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
public OsuTabDropdownHeader()
|
||||
{
|
||||
RelativeSizeAxes = Axes.None;
|
||||
@@ -220,6 +225,18 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
Padding = new MarginPadding { Left = 5, Right = 5 };
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
Foreground.Colour = BackgroundColour;
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
Foreground.Colour = BackgroundColourHover;
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class ProgressBar : SliderBar<double>
|
||||
{
|
||||
public Action<double> OnSeek;
|
||||
|
||||
private readonly Box fill;
|
||||
private readonly Box background;
|
||||
|
||||
public Color4 FillColour
|
||||
{
|
||||
set { fill.Colour = value; }
|
||||
}
|
||||
|
||||
public Color4 BackgroundColour
|
||||
{
|
||||
set
|
||||
{
|
||||
background.Alpha = 1;
|
||||
background.Colour = value;
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTime
|
||||
{
|
||||
set { CurrentNumber.MaxValue = value; }
|
||||
}
|
||||
|
||||
public double CurrentTime
|
||||
{
|
||||
set { CurrentNumber.Value = value; }
|
||||
}
|
||||
|
||||
public ProgressBar()
|
||||
{
|
||||
CurrentNumber.MinValue = 0;
|
||||
CurrentNumber.MaxValue = 1;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
fill = new Box { RelativeSizeAxes = Axes.Y }
|
||||
};
|
||||
}
|
||||
|
||||
protected override void UpdateValue(float value)
|
||||
{
|
||||
fill.Width = value * UsableWidth;
|
||||
}
|
||||
|
||||
protected override void OnUserChange() => OnSeek?.Invoke(Current);
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,8 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Handlers;
|
||||
using osu.Framework.Platform;
|
||||
using OpenTK;
|
||||
@@ -29,5 +31,18 @@ namespace osu.Game.Input.Handlers
|
||||
public override bool IsActive => true;
|
||||
|
||||
public override int Priority => 0;
|
||||
|
||||
public class ReplayState<T> : InputState
|
||||
where T : struct
|
||||
{
|
||||
public List<T> PressedActions;
|
||||
|
||||
public override InputState Clone()
|
||||
{
|
||||
var clone = (ReplayState<T>)base.Clone();
|
||||
clone.PressedActions = new List<T>(PressedActions);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,11 +11,11 @@ namespace osu.Game.Online.API
|
||||
/// An API request with a well-defined response type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the response (used for deserialisation).</typeparam>
|
||||
public class APIRequest<T> : APIRequest
|
||||
public abstract class APIRequest<T> : APIRequest
|
||||
{
|
||||
protected override WebRequest CreateWebRequest() => new JsonWebRequest<T>(Uri);
|
||||
|
||||
public APIRequest()
|
||||
protected APIRequest()
|
||||
{
|
||||
base.Success += onSuccess;
|
||||
}
|
||||
@@ -28,10 +28,36 @@ namespace osu.Game.Online.API
|
||||
public new event APISuccessHandler<T> Success;
|
||||
}
|
||||
|
||||
public abstract class APIDownloadRequest : APIRequest
|
||||
{
|
||||
protected override WebRequest CreateWebRequest()
|
||||
{
|
||||
var request = new WebRequest(Uri);
|
||||
request.DownloadProgress += request_Progress;
|
||||
return request;
|
||||
}
|
||||
|
||||
private void request_Progress(WebRequest request, long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); });
|
||||
|
||||
protected APIDownloadRequest()
|
||||
{
|
||||
base.Success += onSuccess;
|
||||
}
|
||||
|
||||
private void onSuccess()
|
||||
{
|
||||
Success?.Invoke(WebRequest.ResponseData);
|
||||
}
|
||||
|
||||
public event APIProgressHandler Progress;
|
||||
|
||||
public new event APISuccessHandler<byte[]> Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AN API request with no specified response type.
|
||||
/// </summary>
|
||||
public class APIRequest
|
||||
public abstract class APIRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum amount of time before this request will fail.
|
||||
@@ -42,7 +68,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
protected virtual WebRequest CreateWebRequest() => new WebRequest(Uri);
|
||||
|
||||
protected virtual string Uri => $@"{api.Endpoint}/api/v2/{Target}";
|
||||
protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}";
|
||||
|
||||
private double remainingTime => Math.Max(0, Timeout - (DateTime.Now.TotalMilliseconds() - (startTime ?? 0)));
|
||||
|
||||
@@ -52,7 +78,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
public double StartTime => startTime ?? -1;
|
||||
|
||||
private APIAccess api;
|
||||
protected APIAccess API;
|
||||
protected WebRequest WebRequest;
|
||||
|
||||
public event APISuccessHandler Success;
|
||||
@@ -64,7 +90,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
public void Perform(APIAccess api)
|
||||
{
|
||||
this.api = api;
|
||||
API = api;
|
||||
|
||||
if (checkAndProcessFailure())
|
||||
return;
|
||||
@@ -109,9 +135,9 @@ namespace osu.Game.Online.API
|
||||
/// <returns>Whether we are in a failed or cancelled state.</returns>
|
||||
private bool checkAndProcessFailure()
|
||||
{
|
||||
if (api == null || pendingFailure == null) return cancelled;
|
||||
if (API == null || pendingFailure == null) return cancelled;
|
||||
|
||||
api.Scheduler.Add(pendingFailure);
|
||||
API.Scheduler.Add(pendingFailure);
|
||||
pendingFailure = null;
|
||||
return true;
|
||||
}
|
||||
@@ -119,5 +145,6 @@ namespace osu.Game.Online.API
|
||||
|
||||
public delegate void APIFailureHandler(Exception e);
|
||||
public delegate void APISuccessHandler();
|
||||
public delegate void APIProgressHandler(long current, long total);
|
||||
public delegate void APISuccessHandler<in T>(T content);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
public class DownloadBeatmapSetRequest : APIDownloadRequest
|
||||
{
|
||||
public readonly BeatmapSetInfo BeatmapSet;
|
||||
|
||||
public Action<float> DownloadProgressed;
|
||||
|
||||
public DownloadBeatmapSetRequest(BeatmapSetInfo set)
|
||||
{
|
||||
BeatmapSet = set;
|
||||
|
||||
Progress += (current, total) => DownloadProgressed?.Invoke((float) current / total);
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmapsets/{BeatmapSet.OnlineBeatmapSetID}/download";
|
||||
}
|
||||
}
|
||||
@@ -46,6 +46,9 @@ namespace osu.Game.Online.API.Requests
|
||||
[JsonProperty(@"favourite_count")]
|
||||
private int favouriteCount { get; set; }
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
private int onlineId { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmaps")]
|
||||
private IEnumerable<GetBeatmapSetsBeatmapResponse> beatmaps { get; set; }
|
||||
|
||||
@@ -53,6 +56,7 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = onlineId,
|
||||
Metadata = this,
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Framework.IO.Network;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Users;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
|
||||
namespace osu.Game.Online.API.Requests
|
||||
@@ -16,6 +20,14 @@ namespace osu.Game.Online.API.Requests
|
||||
public GetScoresRequest(BeatmapInfo beatmap)
|
||||
{
|
||||
this.beatmap = beatmap;
|
||||
|
||||
Success += onSuccess;
|
||||
}
|
||||
|
||||
private void onSuccess(GetScoresResponse r)
|
||||
{
|
||||
foreach (OnlineScore score in r.Scores)
|
||||
score.ApplyBeatmap(beatmap);
|
||||
}
|
||||
|
||||
protected override WebRequest CreateWebRequest()
|
||||
@@ -32,6 +44,88 @@ namespace osu.Game.Online.API.Requests
|
||||
public class GetScoresResponse
|
||||
{
|
||||
[JsonProperty(@"scores")]
|
||||
public IEnumerable<Score> Scores;
|
||||
public IEnumerable<OnlineScore> Scores;
|
||||
}
|
||||
}
|
||||
|
||||
public class OnlineScore : Score
|
||||
{
|
||||
[JsonProperty(@"score")]
|
||||
private double totalScore
|
||||
{
|
||||
set { TotalScore = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"max_combo")]
|
||||
private int maxCombo
|
||||
{
|
||||
set { MaxCombo = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
private User user
|
||||
{
|
||||
set { User = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"replay_data")]
|
||||
private Replay replay
|
||||
{
|
||||
set { Replay = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"score_id")]
|
||||
private long onlineScoreID
|
||||
{
|
||||
set { OnlineScoreID = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
private DateTimeOffset date
|
||||
{
|
||||
set { Date = value; }
|
||||
}
|
||||
|
||||
[JsonProperty(@"statistics")]
|
||||
private Dictionary<string, dynamic> jsonStats
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var kvp in value)
|
||||
{
|
||||
string key = kvp.Key;
|
||||
switch (key)
|
||||
{
|
||||
case @"count_300":
|
||||
key = @"300";
|
||||
break;
|
||||
case @"count_100":
|
||||
key = @"100";
|
||||
break;
|
||||
case @"count_50":
|
||||
key = @"50";
|
||||
break;
|
||||
case @"count_miss":
|
||||
key = @"x";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
Statistics.Add(key, kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
private string[] modStrings { get; set; }
|
||||
|
||||
public void ApplyBeatmap(BeatmapInfo beatmap)
|
||||
{
|
||||
Beatmap = beatmap;
|
||||
Ruleset = beatmap.Ruleset;
|
||||
|
||||
// Evaluate the mod string
|
||||
Mods = Ruleset.CreateInstance().GetAllMods().Where(mod => modStrings.Contains(mod.ShortenedName)).ToArray();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ namespace osu.Game.Online.Chat
|
||||
|
||||
public Bindable<bool> Joined = new Bindable<bool>();
|
||||
|
||||
public bool ReadOnly => Name != "#lazer";
|
||||
public bool ReadOnly => false;
|
||||
|
||||
public const int MAX_HISTORY = 300;
|
||||
|
||||
|
||||
+33
-13
@@ -219,20 +219,37 @@ namespace osu.Game
|
||||
|
||||
dependencies.Cache(settings);
|
||||
dependencies.Cache(social);
|
||||
dependencies.Cache(direct);
|
||||
dependencies.Cache(chat);
|
||||
dependencies.Cache(userProfile);
|
||||
dependencies.Cache(musicController);
|
||||
dependencies.Cache(notificationOverlay);
|
||||
dependencies.Cache(dialogOverlay);
|
||||
|
||||
// ensure both overlays aren't presented at the same time
|
||||
chat.StateChanged += (container, state) => social.State = state == Visibility.Visible ? Visibility.Hidden : social.State;
|
||||
social.StateChanged += (container, state) => chat.State = state == Visibility.Visible ? Visibility.Hidden : chat.State;
|
||||
// ensure only one of these overlays are open at once.
|
||||
var singleDisplayOverlays = new OverlayContainer[] { chat, social, direct };
|
||||
foreach (var overlay in singleDisplayOverlays)
|
||||
{
|
||||
overlay.StateChanged += state =>
|
||||
{
|
||||
if (state == Visibility.Hidden) return;
|
||||
|
||||
foreach (var c in singleDisplayOverlays)
|
||||
{
|
||||
if (c == overlay) continue;
|
||||
c.State = Visibility.Hidden;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
LoadComponentAsync(Toolbar = new Toolbar
|
||||
{
|
||||
Depth = -4,
|
||||
OnHome = delegate { intro?.ChildScreen?.MakeCurrent(); },
|
||||
OnHome = delegate
|
||||
{
|
||||
hideAllOverlays();
|
||||
intro?.ChildScreen?.MakeCurrent();
|
||||
},
|
||||
}, overlayContent.Add);
|
||||
|
||||
settings.StateChanged += delegate
|
||||
@@ -297,6 +314,16 @@ namespace osu.Game
|
||||
private OsuScreen currentScreen;
|
||||
private FrameworkConfigManager frameworkConfig;
|
||||
|
||||
private void hideAllOverlays()
|
||||
{
|
||||
settings.State = Visibility.Hidden;
|
||||
chat.State = Visibility.Hidden;
|
||||
direct.State = Visibility.Hidden;
|
||||
social.State = Visibility.Hidden;
|
||||
userProfile.State = Visibility.Hidden;
|
||||
notificationOverlay.State = Visibility.Hidden;
|
||||
}
|
||||
|
||||
private void screenChanged(Screen newScreen)
|
||||
{
|
||||
currentScreen = newScreen as OsuScreen;
|
||||
@@ -310,19 +337,12 @@ namespace osu.Game
|
||||
//central game screen change logic.
|
||||
if (!currentScreen.ShowOverlays)
|
||||
{
|
||||
settings.State = Visibility.Hidden;
|
||||
Toolbar.State = Visibility.Hidden;
|
||||
hideAllOverlays();
|
||||
musicController.State = Visibility.Hidden;
|
||||
chat.State = Visibility.Hidden;
|
||||
direct.State = Visibility.Hidden;
|
||||
social.State = Visibility.Hidden;
|
||||
userProfile.State = Visibility.Hidden;
|
||||
notificationOverlay.State = Visibility.Hidden;
|
||||
Toolbar.State = Visibility.Hidden;
|
||||
}
|
||||
else
|
||||
{
|
||||
Toolbar.State = Visibility.Visible;
|
||||
}
|
||||
|
||||
ScreenChanged?.Invoke(newScreen);
|
||||
}
|
||||
|
||||
+9
-13
@@ -106,9 +106,15 @@ namespace osu.Game
|
||||
|
||||
connection.CreateTable<StoreVersion>();
|
||||
|
||||
dependencies.Cache(API = new APIAccess
|
||||
{
|
||||
Username = LocalConfig.Get<string>(OsuSetting.Username),
|
||||
Token = LocalConfig.Get<string>(OsuSetting.Token)
|
||||
});
|
||||
|
||||
dependencies.Cache(RulesetStore = new RulesetStore(connection));
|
||||
dependencies.Cache(FileStore = new FileStore(connection, Host.Storage));
|
||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, Host));
|
||||
dependencies.Cache(BeatmapManager = new BeatmapManager(Host.Storage, FileStore, connection, RulesetStore, API, Host));
|
||||
dependencies.Cache(ScoreStore = new ScoreStore(Host.Storage, connection, Host, BeatmapManager, RulesetStore));
|
||||
dependencies.Cache(KeyBindingStore = new KeyBindingStore(connection, RulesetStore));
|
||||
dependencies.Cache(new OsuColour());
|
||||
@@ -144,22 +150,12 @@ namespace osu.Game
|
||||
Beatmap = new NonNullableBindable<WorkingBeatmap>(defaultBeatmap);
|
||||
BeatmapManager.DefaultBeatmap = defaultBeatmap;
|
||||
|
||||
dependencies.Cache(API = new APIAccess
|
||||
{
|
||||
Username = LocalConfig.Get<string>(OsuSetting.Username),
|
||||
Token = LocalConfig.Get<string>(OsuSetting.Token)
|
||||
});
|
||||
|
||||
Beatmap.ValueChanged += b =>
|
||||
{
|
||||
// compare to last baetmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
|
||||
// compare to last beatmap as sometimes the two may share a track representation (optimisation, see WorkingBeatmap.TransferTo)
|
||||
if (lastBeatmap?.Track != b.Track)
|
||||
{
|
||||
// this disposal is done to stop the audio track.
|
||||
// it may not be exactly what we want for cases beatmaps are reused, as it will
|
||||
// trigger a fresh load of contained resources.
|
||||
lastBeatmap?.Dispose();
|
||||
|
||||
lastBeatmap?.Track?.Dispose();
|
||||
Audio.Track.AddItem(b.Track);
|
||||
}
|
||||
|
||||
|
||||
@@ -76,7 +76,6 @@ namespace osu.Game.Overlays.Chat
|
||||
Size = new Vector2(text_size),
|
||||
Shadow = false,
|
||||
Margin = new MarginPadding { Right = 10f },
|
||||
Alpha = 0f,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -109,7 +108,6 @@ namespace osu.Game.Overlays.Chat
|
||||
TextSize = text_size,
|
||||
Font = @"Exo2.0-SemiBold",
|
||||
Shadow = false,
|
||||
Alpha = 0.8f,
|
||||
},
|
||||
},
|
||||
},
|
||||
@@ -151,6 +149,9 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
joinedBind.ValueChanged += updateColour;
|
||||
joinedBind.BindTo(channel.Joined);
|
||||
|
||||
joinedBind.TriggerChange();
|
||||
FinishTransforms(true);
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
|
||||
@@ -16,15 +16,16 @@ using osu.Game.Online.Chat;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
using System;
|
||||
|
||||
namespace osu.Game.Overlays.Chat
|
||||
{
|
||||
public class ChatTabControl : OsuTabControl<Channel>
|
||||
{
|
||||
protected override TabItem<Channel> CreateTabItem(Channel value) => new ChannelTabItem(value);
|
||||
|
||||
private const float shear_width = 10;
|
||||
|
||||
public Action<Channel> OnRequestLeave;
|
||||
|
||||
public readonly Bindable<bool> ChannelSelectorActive = new Bindable<bool>();
|
||||
|
||||
private readonly ChannelTabItem.ChannelSelectorTabItem selectorTab;
|
||||
@@ -49,6 +50,20 @@ namespace osu.Game.Overlays.Chat
|
||||
ChannelSelectorActive.BindTo(selectorTab.Active);
|
||||
}
|
||||
|
||||
protected override void AddTabItem(TabItem<Channel> item, bool addToDropdown = true)
|
||||
{
|
||||
if (selectorTab.Depth < float.MaxValue)
|
||||
// performTabSort might've made selectorTab's position wonky, fix it
|
||||
TabContainer.ChangeChildDepth(selectorTab, float.MaxValue);
|
||||
|
||||
base.AddTabItem(item, addToDropdown);
|
||||
|
||||
if (SelectedTab == null)
|
||||
SelectTab(item);
|
||||
}
|
||||
|
||||
protected override TabItem<Channel> CreateTabItem(Channel value) => new ChannelTabItem(value) { OnRequestClose = tabCloseRequested };
|
||||
|
||||
protected override void SelectTab(TabItem<Channel> tab)
|
||||
{
|
||||
if (tab is ChannelTabItem.ChannelSelectorTabItem)
|
||||
@@ -62,18 +77,38 @@ namespace osu.Game.Overlays.Chat
|
||||
base.SelectTab(tab);
|
||||
}
|
||||
|
||||
private void tabCloseRequested(TabItem<Channel> tab)
|
||||
{
|
||||
int totalTabs = TabContainer.Count - 1; // account for selectorTab
|
||||
int currentIndex = MathHelper.Clamp(TabContainer.IndexOf(tab), 1, totalTabs);
|
||||
|
||||
if (tab == SelectedTab && totalTabs > 1)
|
||||
// Select the tab after tab-to-be-removed's index, or the tab before if current == last
|
||||
SelectTab(TabContainer[currentIndex == totalTabs ? currentIndex - 1 : currentIndex + 1]);
|
||||
else if (totalTabs == 1 && !selectorTab.Active)
|
||||
// Open channel selection overlay if all channel tabs will be closed after removing this tab
|
||||
SelectTab(selectorTab);
|
||||
|
||||
OnRequestLeave?.Invoke(tab.Value);
|
||||
}
|
||||
|
||||
private class ChannelTabItem : TabItem<Channel>
|
||||
{
|
||||
private Color4 backgroundInactive;
|
||||
private Color4 backgroundHover;
|
||||
private Color4 backgroundActive;
|
||||
|
||||
public override bool IsRemovable => !Pinned;
|
||||
|
||||
private readonly SpriteText text;
|
||||
private readonly SpriteText textBold;
|
||||
private readonly ClickableContainer closeButton;
|
||||
private readonly Box box;
|
||||
private readonly Box highlightBox;
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public Action<ChannelTabItem> OnRequestClose;
|
||||
|
||||
private void updateState()
|
||||
{
|
||||
if (Active)
|
||||
@@ -108,6 +143,9 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
if (IsRemovable)
|
||||
closeButton.FadeIn(200, Easing.OutQuint);
|
||||
|
||||
if (!Active)
|
||||
box.FadeColour(backgroundHover, transition_length, Easing.OutQuint);
|
||||
return true;
|
||||
@@ -115,6 +153,7 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
closeButton.FadeOut(200, Easing.OutQuint);
|
||||
updateState();
|
||||
}
|
||||
|
||||
@@ -204,13 +243,69 @@ namespace osu.Game.Overlays.Chat
|
||||
Font = @"Exo2.0-Bold",
|
||||
TextSize = 18,
|
||||
},
|
||||
}
|
||||
}
|
||||
closeButton = new CloseButton
|
||||
{
|
||||
Alpha = 0,
|
||||
Margin = new MarginPadding { Right = 20 },
|
||||
Origin = Anchor.CentreRight,
|
||||
Anchor = Anchor.CentreRight,
|
||||
Action = delegate
|
||||
{
|
||||
if (IsRemovable) OnRequestClose?.Invoke(this);
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
public class CloseButton : ClickableContainer
|
||||
{
|
||||
private readonly SpriteIcon icon;
|
||||
|
||||
public CloseButton()
|
||||
{
|
||||
Size = new Vector2(20);
|
||||
|
||||
Child = icon = new SpriteIcon
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Scale = new Vector2(0.75f),
|
||||
Icon = FontAwesome.fa_close,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
icon.ScaleTo(0.5f, 1000, Easing.OutQuint);
|
||||
return base.OnMouseDown(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||
{
|
||||
icon.ScaleTo(0.75f, 1000, Easing.OutElastic);
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
icon.FadeColour(Color4.Red, 200, Easing.OutQuint);
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
icon.FadeColour(Color4.White, 200, Easing.OutQuint);
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
}
|
||||
|
||||
public class ChannelSelectorTabItem : ChannelTabItem
|
||||
{
|
||||
public override bool IsRemovable => false;
|
||||
|
||||
public ChannelSelectorTabItem(Channel value) : base(value)
|
||||
{
|
||||
Depth = float.MaxValue;
|
||||
|
||||
@@ -160,6 +160,7 @@ namespace osu.Game.Overlays
|
||||
channelTabs = new ChatTabControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
OnRequestLeave = removeChannel,
|
||||
},
|
||||
}
|
||||
},
|
||||
@@ -169,7 +170,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
|
||||
channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden;
|
||||
channelSelection.StateChanged += (overlay, state) =>
|
||||
channelSelection.StateChanged += state =>
|
||||
{
|
||||
channelTabs.ChannelSelectorActive.Value = state == Visibility.Visible;
|
||||
|
||||
@@ -305,6 +306,7 @@ namespace osu.Game.Overlays
|
||||
addChannel(channels.Find(c => c.Name == @"#lobby"));
|
||||
|
||||
channelSelection.OnRequestJoin = addChannel;
|
||||
channelSelection.OnRequestLeave = removeChannel;
|
||||
channelSelection.Sections = new[]
|
||||
{
|
||||
new ChannelSection
|
||||
@@ -332,7 +334,15 @@ namespace osu.Game.Overlays
|
||||
|
||||
set
|
||||
{
|
||||
if (currentChannel == value || value == null) return;
|
||||
if (currentChannel == value) return;
|
||||
|
||||
if (value == null)
|
||||
{
|
||||
currentChannel = null;
|
||||
textbox.Current.Disabled = true;
|
||||
currentChannelContainer.Clear(false);
|
||||
return;
|
||||
}
|
||||
|
||||
currentChannel = value;
|
||||
|
||||
@@ -391,6 +401,19 @@ namespace osu.Game.Overlays
|
||||
channel.Joined.Value = true;
|
||||
}
|
||||
|
||||
private void removeChannel(Channel channel)
|
||||
{
|
||||
if (channel == null) return;
|
||||
|
||||
if (channel == CurrentChannel) CurrentChannel = null;
|
||||
|
||||
careChannels.Remove(channel);
|
||||
loadedChannels.Remove(loadedChannels.Find(c => c.Channel == channel));
|
||||
channelTabs.RemoveItem(channel);
|
||||
|
||||
channel.Joined.Value = false;
|
||||
}
|
||||
|
||||
private void fetchInitialMessages(Channel channel)
|
||||
{
|
||||
var req = new GetMessagesRequest(new List<Channel> { channel }, null);
|
||||
|
||||
@@ -26,7 +26,7 @@ namespace osu.Game.Overlays
|
||||
dialogContainer.Add(currentDialog);
|
||||
|
||||
currentDialog.Show();
|
||||
currentDialog.StateChanged += onDialogOnStateChanged;
|
||||
currentDialog.StateChanged += state => onDialogOnStateChanged(dialog, state);
|
||||
State = Visibility.Visible;
|
||||
}
|
||||
|
||||
|
||||
@@ -12,6 +12,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Framework.Input;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
@@ -25,23 +26,11 @@ namespace osu.Game.Overlays.Direct
|
||||
public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap)
|
||||
{
|
||||
Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image)
|
||||
CornerRadius = 4;
|
||||
Masking = true;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
Radius = 3f,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
this.FadeInFromZero(200, Easing.Out);
|
||||
bottomPanel.LayoutDuration = 200;
|
||||
bottomPanel.LayoutEasing = Easing.Out;
|
||||
bottomPanel.Origin = Anchor.BottomLeft;
|
||||
@@ -50,14 +39,10 @@ namespace osu.Game.Overlays.Direct
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, LocalisationEngine localisation)
|
||||
{
|
||||
Children = new[]
|
||||
Content.CornerRadius = 4;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
CreateBackground(),
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@@ -185,7 +170,13 @@ namespace osu.Game.Overlays.Direct
|
||||
new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
StartDownload();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -28,35 +28,15 @@ namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
Radius = 3f,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
this.FadeInFromZero(200, Easing.Out);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(LocalisationEngine localisation)
|
||||
{
|
||||
Children = new[]
|
||||
Content.CornerRadius = 5;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
CreateBackground(),
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@@ -144,10 +124,11 @@ namespace osu.Game.Overlays.Direct
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Size = new Vector2(height - vertical_padding * 2),
|
||||
Action = StartDownload
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private class DownloadButton : OsuClickableContainer
|
||||
|
||||
@@ -2,26 +2,179 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using OpenTK;
|
||||
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.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
using osu.Game.Online.API.Requests;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public abstract class DirectPanel : Container
|
||||
{
|
||||
protected readonly BeatmapSetInfo SetInfo;
|
||||
public readonly BeatmapSetInfo SetInfo;
|
||||
|
||||
protected Box BlackBackground;
|
||||
|
||||
private const double hover_transition_time = 400;
|
||||
|
||||
private Container content;
|
||||
|
||||
private APIAccess api;
|
||||
private ProgressBar progressBar;
|
||||
private BeatmapManager beatmaps;
|
||||
private NotificationOverlay notifications;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected DirectPanel(BeatmapSetInfo setInfo)
|
||||
{
|
||||
SetInfo = setInfo;
|
||||
}
|
||||
|
||||
private readonly EdgeEffectParameters edgeEffectNormal = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
Radius = 2f,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
};
|
||||
|
||||
private readonly EdgeEffectParameters edgeEffectHovered = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Offset = new Vector2(0f, 5f),
|
||||
Radius = 10f,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
};
|
||||
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(APIAccess api, BeatmapManager beatmaps, OsuColour colours, NotificationOverlay notifications)
|
||||
{
|
||||
this.api = api;
|
||||
this.beatmaps = beatmaps;
|
||||
this.notifications = notifications;
|
||||
|
||||
AddInternal(content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
EdgeEffect = edgeEffectNormal,
|
||||
Children = new[]
|
||||
{
|
||||
// temporary blackness until the actual background loads.
|
||||
BlackBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
CreateBackground(),
|
||||
progressBar = new ProgressBar
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Height = 0,
|
||||
Alpha = 0,
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f),
|
||||
FillColour = colours.Blue,
|
||||
Depth = -1,
|
||||
},
|
||||
}
|
||||
});
|
||||
|
||||
var downloadRequest = beatmaps.GetExistingDownload(SetInfo);
|
||||
|
||||
if (downloadRequest != null)
|
||||
attachDownload(downloadRequest);
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
content.TweenEdgeEffectTo(edgeEffectHovered, hover_transition_time, Easing.OutQuint);
|
||||
content.MoveToY(-4, hover_transition_time, Easing.OutQuint);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
content.TweenEdgeEffectTo(edgeEffectNormal, hover_transition_time, Easing.OutQuint);
|
||||
content.MoveToY(0, hover_transition_time, Easing.OutQuint);
|
||||
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
protected void StartDownload()
|
||||
{
|
||||
if (!api.LocalUser.Value.IsSupporter)
|
||||
{
|
||||
notifications.Post(new SimpleNotification
|
||||
{
|
||||
Icon = FontAwesome.fa_superpowers,
|
||||
Text = "You gotta be a supporter to download for now 'yo"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
if (beatmaps.GetExistingDownload(SetInfo) != null)
|
||||
{
|
||||
// we already have an active download running.
|
||||
content.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(0, 50, Easing.InSine).Then();
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
var request = beatmaps.Download(SetInfo);
|
||||
|
||||
attachDownload(request);
|
||||
}
|
||||
|
||||
private void attachDownload(DownloadBeatmapSetRequest request)
|
||||
{
|
||||
progressBar.FadeIn(400, Easing.OutQuint);
|
||||
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
|
||||
|
||||
progressBar.Current.Value = 0;
|
||||
|
||||
request.Failure += e =>
|
||||
{
|
||||
progressBar.Current.Value = 0;
|
||||
progressBar.FadeOut(500);
|
||||
Logger.Error(e, "Failed to get beatmap download information");
|
||||
};
|
||||
|
||||
request.DownloadProgressed += progress => progressBar.Current.Value = progress;
|
||||
|
||||
request.Success += data =>
|
||||
{
|
||||
progressBar.Current.Value = 1;
|
||||
progressBar.FadeOut(500);
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
this.FadeInFromZero(200, Easing.Out);
|
||||
}
|
||||
|
||||
protected List<DifficultyIcon> GetDifficultyIcons()
|
||||
{
|
||||
var icons = new List<DifficultyIcon>();
|
||||
@@ -38,7 +191,11 @@ namespace osu.Game.Overlays.Direct
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
||||
OnLoadComplete = d =>
|
||||
{
|
||||
d.FadeInFromZero(400, Easing.Out);
|
||||
BlackBackground.Delay(400).FadeOut();
|
||||
},
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
|
||||
@@ -27,10 +27,11 @@ namespace osu.Game.Overlays
|
||||
|
||||
private APIAccess api;
|
||||
private RulesetStore rulesets;
|
||||
private BeatmapManager beatmaps;
|
||||
|
||||
private readonly FillFlowContainer resultCountsContainer;
|
||||
private readonly OsuSpriteText resultCountsText;
|
||||
private readonly FillFlowContainer<DirectPanel> panels;
|
||||
private FillFlowContainer<DirectPanel> panels;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74");
|
||||
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71");
|
||||
@@ -46,20 +47,26 @@ namespace osu.Game.Overlays
|
||||
set
|
||||
{
|
||||
if (beatmapSets?.Equals(value) ?? false) return;
|
||||
|
||||
beatmapSets = value;
|
||||
|
||||
if (BeatmapSets == null)
|
||||
{
|
||||
foreach (var p in panels.Children)
|
||||
{
|
||||
p.FadeOut(200);
|
||||
p.Expire();
|
||||
}
|
||||
if (beatmapSets == null) return;
|
||||
|
||||
return;
|
||||
var artists = new List<string>();
|
||||
var songs = new List<string>();
|
||||
var tags = new List<string>();
|
||||
foreach (var s in beatmapSets)
|
||||
{
|
||||
artists.Add(s.Metadata.Artist);
|
||||
songs.Add(s.Metadata.Title);
|
||||
tags.AddRange(s.Metadata.Tags.Split(' '));
|
||||
}
|
||||
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags));
|
||||
|
||||
if (beatmapSets.Any() && panels == null)
|
||||
// real use case? currently only seems to be for test case
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -108,13 +115,6 @@ namespace osu.Game.Overlays
|
||||
},
|
||||
}
|
||||
},
|
||||
panels = new FillFlowContainer<DirectPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(panel_padding),
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
},
|
||||
};
|
||||
|
||||
Filter.Search.Current.ValueChanged += text => { if (text != string.Empty) Header.Tabs.Current.Value = DirectTab.Search; };
|
||||
@@ -161,11 +161,22 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets)
|
||||
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps)
|
||||
{
|
||||
this.api = api;
|
||||
this.rulesets = rulesets;
|
||||
this.beatmaps = beatmaps;
|
||||
|
||||
resultCountsContainer.Colour = colours.Yellow;
|
||||
|
||||
beatmaps.BeatmapSetAdded += setAdded;
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo set)
|
||||
{
|
||||
// if a new map was imported, we should remove it from search results (download completed etc.)
|
||||
panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire();
|
||||
BeatmapSets = BeatmapSets?.Where(b => b.OnlineBeatmapSetID != set.OnlineBeatmapSetID);
|
||||
}
|
||||
|
||||
private void updateResultCounts()
|
||||
@@ -185,18 +196,38 @@ namespace osu.Game.Overlays
|
||||
|
||||
private void recreatePanels(PanelDisplayStyle displayStyle)
|
||||
{
|
||||
if (panels != null)
|
||||
{
|
||||
panels.FadeOut(200);
|
||||
panels.Expire();
|
||||
panels = null;
|
||||
}
|
||||
|
||||
if (BeatmapSets == null) return;
|
||||
|
||||
panels.ChildrenEnumerable = BeatmapSets.Select<BeatmapSetInfo, DirectPanel>(b =>
|
||||
{
|
||||
switch (displayStyle)
|
||||
{
|
||||
case PanelDisplayStyle.Grid:
|
||||
return new DirectGridPanel(b) { Width = 400 };
|
||||
default:
|
||||
return new DirectListPanel(b);
|
||||
}
|
||||
});
|
||||
var newPanels = new FillFlowContainer<DirectPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(panel_padding),
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
ChildrenEnumerable = BeatmapSets.Select<BeatmapSetInfo, DirectPanel>(b =>
|
||||
{
|
||||
switch (displayStyle)
|
||||
{
|
||||
case PanelDisplayStyle.Grid:
|
||||
return new DirectGridPanel(b) { Width = 400 };
|
||||
default:
|
||||
return new DirectListPanel(b);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
LoadComponentAsync(newPanels, p =>
|
||||
{
|
||||
if (panels != null) ScrollFlow.Remove(panels);
|
||||
ScrollFlow.Add(panels = newPanels);
|
||||
});
|
||||
}
|
||||
|
||||
private GetBeatmapSetsRequest getSetsRequest;
|
||||
@@ -227,20 +258,11 @@ namespace osu.Game.Overlays
|
||||
|
||||
getSetsRequest.Success += r =>
|
||||
{
|
||||
BeatmapSets = r?.Select(response => response.ToBeatmapSet(rulesets));
|
||||
if (BeatmapSets == null) return;
|
||||
BeatmapSets = r?.
|
||||
Select(response => response.ToBeatmapSet(rulesets)).
|
||||
Where(b => beatmaps.QueryBeatmapSet(q => q.OnlineBeatmapSetID == b.OnlineBeatmapSetID) == null);
|
||||
|
||||
var artists = new List<string>();
|
||||
var songs = new List<string>();
|
||||
var tags = new List<string>();
|
||||
foreach (var s in BeatmapSets)
|
||||
{
|
||||
artists.Add(s.Metadata.Artist);
|
||||
songs.Add(s.Metadata.Title);
|
||||
tags.AddRange(s.Metadata.Tags.Split(' '));
|
||||
}
|
||||
|
||||
ResultAmounts = new ResultCounts(distinctCount(artists), distinctCount(songs), distinctCount(tags));
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
};
|
||||
|
||||
api.Queue(getSetsRequest);
|
||||
|
||||
@@ -122,14 +122,14 @@ namespace osu.Game.Overlays.KeyBinding
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
this.FadeEdgeEffectTo<Container>(1, transition_time, Easing.OutQuint);
|
||||
FadeEdgeEffectTo(1, transition_time, Easing.OutQuint);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
this.FadeEdgeEffectTo<Container>(0, transition_time, Easing.OutQuint);
|
||||
FadeEdgeEffectTo(0, transition_time, Easing.OutQuint);
|
||||
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
@@ -53,7 +53,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
private const float hidden_width = 120;
|
||||
|
||||
private void keyBindingOverlay_StateChanged(VisibilityContainer container, Visibility visibility)
|
||||
private void keyBindingOverlay_StateChanged(Visibility visibility)
|
||||
{
|
||||
switch (visibility)
|
||||
{
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework;
|
||||
using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
@@ -19,6 +20,8 @@ namespace osu.Game.Overlays.MedalSplash
|
||||
private const float scale_when_unlocked = 0.76f;
|
||||
private const float scale_when_full = 0.6f;
|
||||
|
||||
public event Action<DisplayState> StateChanged;
|
||||
|
||||
private readonly Medal medal;
|
||||
private readonly Container medalContainer;
|
||||
private readonly Sprite medalSprite, medalGlow;
|
||||
@@ -132,6 +135,8 @@ namespace osu.Game.Overlays.MedalSplash
|
||||
|
||||
state = value;
|
||||
updateState();
|
||||
|
||||
StateChanged?.Invoke(State);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -15,15 +15,37 @@ namespace osu.Game.Overlays.Music
|
||||
{
|
||||
public class CollectionsDropdown<T> : OsuDropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
|
||||
protected override Menu CreateMenu() => new CollectionsMenu();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
AccentColour = colours.Gray6;
|
||||
}
|
||||
|
||||
protected override DropdownHeader CreateHeader() => new CollectionsHeader();
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new CollectionsMenu();
|
||||
|
||||
private class CollectionsMenu : OsuDropdownMenu
|
||||
{
|
||||
public CollectionsMenu()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.Gray4;
|
||||
}
|
||||
}
|
||||
|
||||
private class CollectionsHeader : OsuDropdownHeader
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
@@ -48,26 +70,5 @@ namespace osu.Game.Overlays.Music
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class CollectionsMenu : OsuMenu
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Background.Colour = colours.Gray4;
|
||||
}
|
||||
|
||||
public CollectionsMenu()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
@@ -16,7 +17,7 @@ using OpenTK;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
{
|
||||
internal class PlaylistItem : Container, IFilterable
|
||||
internal class PlaylistItem : Container, IFilterable, IDraggable
|
||||
{
|
||||
private const float fade_duration = 100;
|
||||
|
||||
@@ -33,6 +34,8 @@ namespace osu.Game.Overlays.Music
|
||||
|
||||
public Action<BeatmapSetInfo> OnSelect;
|
||||
|
||||
public bool IsDraggable => handle.IsHovered;
|
||||
|
||||
private bool selected;
|
||||
public bool Selected
|
||||
{
|
||||
@@ -68,15 +71,9 @@ namespace osu.Game.Overlays.Music
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
handle = new SpriteIcon
|
||||
handle = new PlaylistItemHandle
|
||||
{
|
||||
Anchor = Anchor.TopLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
Size = new Vector2(12),
|
||||
Colour = colours.Gray5,
|
||||
Icon = FontAwesome.fa_bars,
|
||||
Alpha = 0f,
|
||||
Margin = new MarginPadding { Left = 5, Top = 2 },
|
||||
Colour = colours.Gray5
|
||||
},
|
||||
text = new OsuTextFlowContainer
|
||||
{
|
||||
@@ -114,19 +111,19 @@ namespace osu.Game.Overlays.Music
|
||||
});
|
||||
}
|
||||
|
||||
protected override bool OnHover(Framework.Input.InputState state)
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
handle.FadeIn(fade_duration);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(Framework.Input.InputState state)
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
handle.FadeOut(fade_duration);
|
||||
}
|
||||
|
||||
protected override bool OnClick(Framework.Input.InputState state)
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
OnSelect?.Invoke(BeatmapSetInfo);
|
||||
return true;
|
||||
@@ -148,5 +145,27 @@ namespace osu.Game.Overlays.Music
|
||||
this.FadeTo(matching ? 1 : 0, 200);
|
||||
}
|
||||
}
|
||||
|
||||
private class PlaylistItemHandle : SpriteIcon
|
||||
{
|
||||
|
||||
public PlaylistItemHandle()
|
||||
{
|
||||
Anchor = Anchor.TopLeft;
|
||||
Origin = Anchor.TopLeft;
|
||||
Size = new Vector2(12);
|
||||
Icon = FontAwesome.fa_bars;
|
||||
Alpha = 0f;
|
||||
Margin = new MarginPadding { Left = 5, Top = 2 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public interface IDraggable : IDrawable
|
||||
{
|
||||
/// <summary>
|
||||
/// Whether this <see cref="IDraggable"/> can be dragged in its current state.
|
||||
/// </summary>
|
||||
bool IsDraggable { get; }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -4,105 +4,252 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics.Containers;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
{
|
||||
internal class PlaylistList : Container
|
||||
internal class PlaylistList : CompositeDrawable
|
||||
{
|
||||
private readonly FillFlowContainer<PlaylistItem> items;
|
||||
|
||||
public IEnumerable<BeatmapSetInfo> BeatmapSets
|
||||
{
|
||||
set
|
||||
{
|
||||
items.Children = value.Select(item => new PlaylistItem(item) { OnSelect = itemSelected }).ToList();
|
||||
}
|
||||
}
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
|
||||
|
||||
private void itemSelected(BeatmapSetInfo b)
|
||||
{
|
||||
OnSelect?.Invoke(b);
|
||||
}
|
||||
|
||||
public Action<BeatmapSetInfo> OnSelect;
|
||||
|
||||
private readonly SearchContainer search;
|
||||
|
||||
public void Filter(string searchTerm) => search.SearchTerm = searchTerm;
|
||||
|
||||
public BeatmapSetInfo SelectedItem
|
||||
{
|
||||
get { return items.Children.FirstOrDefault(i => i.Selected)?.BeatmapSetInfo; }
|
||||
set
|
||||
{
|
||||
foreach (PlaylistItem s in items.Children)
|
||||
s.Selected = s.BeatmapSetInfo.ID == value?.ID;
|
||||
}
|
||||
}
|
||||
private readonly ItemsScrollContainer items;
|
||||
|
||||
public PlaylistList()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
InternalChild = items = new ItemsScrollContainer
|
||||
{
|
||||
new OsuScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
search = new SearchContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
items = new ItemSearchContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
},
|
||||
}
|
||||
}
|
||||
},
|
||||
},
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
OnSelect = set => OnSelect?.Invoke(set)
|
||||
};
|
||||
}
|
||||
|
||||
public void AddBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||
public new MarginPadding Padding
|
||||
{
|
||||
items.Add(new PlaylistItem(beatmapSet) { OnSelect = itemSelected });
|
||||
get { return base.Padding; }
|
||||
set { base.Padding = value; }
|
||||
}
|
||||
|
||||
public void RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||
public IEnumerable<BeatmapSetInfo> BeatmapSets { set { items.Sets = value; } }
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => items.FirstVisibleSet;
|
||||
public BeatmapSetInfo NextSet => items.NextSet;
|
||||
public BeatmapSetInfo PreviousSet => items.PreviousSet;
|
||||
|
||||
public BeatmapSetInfo SelectedSet
|
||||
{
|
||||
PlaylistItem itemToRemove = items.Children.FirstOrDefault(item => item.BeatmapSetInfo.ID == beatmapSet.ID);
|
||||
if (itemToRemove != null) items.Remove(itemToRemove);
|
||||
get { return items.SelectedSet; }
|
||||
set { items.SelectedSet = value; }
|
||||
}
|
||||
|
||||
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
||||
public void AddBeatmapSet(BeatmapSetInfo beatmapSet) => items.AddBeatmapSet(beatmapSet);
|
||||
public bool RemoveBeatmapSet(BeatmapSetInfo beatmapSet) => items.RemoveBeatmapSet(beatmapSet);
|
||||
|
||||
public void Filter(string searchTerm) => items.SearchTerm = searchTerm;
|
||||
|
||||
private class ItemsScrollContainer : OsuScrollContainer
|
||||
{
|
||||
public string[] FilterTerms => new string[] { };
|
||||
public bool MatchingFilter
|
||||
public Action<BeatmapSetInfo> OnSelect;
|
||||
|
||||
private readonly SearchContainer search;
|
||||
private readonly FillFlowContainer<PlaylistItem> items;
|
||||
|
||||
public ItemsScrollContainer()
|
||||
{
|
||||
Children = new Drawable[]
|
||||
{
|
||||
search = new SearchContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
items = new ItemSearchContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
},
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public IEnumerable<BeatmapSetInfo> Sets
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
InvalidateLayout();
|
||||
items.Clear();
|
||||
value.ForEach(AddBeatmapSet);
|
||||
}
|
||||
}
|
||||
|
||||
public IEnumerable<IFilterable> FilterableChildren => Children;
|
||||
|
||||
public ItemSearchContainer()
|
||||
public string SearchTerm
|
||||
{
|
||||
LayoutDuration = 200;
|
||||
LayoutEasing = Easing.OutQuint;
|
||||
get { return search.SearchTerm; }
|
||||
set { search.SearchTerm = value; }
|
||||
}
|
||||
|
||||
public void AddBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
items.Add(new PlaylistItem(beatmapSet)
|
||||
{
|
||||
OnSelect = set => OnSelect?.Invoke(set),
|
||||
Depth = items.Count
|
||||
});
|
||||
}
|
||||
|
||||
public bool RemoveBeatmapSet(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
var itemToRemove = items.FirstOrDefault(i => i.BeatmapSetInfo.ID == beatmapSet.ID);
|
||||
if (itemToRemove == null)
|
||||
return false;
|
||||
return items.Remove(itemToRemove);
|
||||
}
|
||||
|
||||
public BeatmapSetInfo SelectedSet
|
||||
{
|
||||
get { return items.FirstOrDefault(i => i.Selected)?.BeatmapSetInfo; }
|
||||
set
|
||||
{
|
||||
foreach (PlaylistItem s in items.Children)
|
||||
s.Selected = s.BeatmapSetInfo.ID == value?.ID;
|
||||
}
|
||||
}
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => items.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
|
||||
public BeatmapSetInfo NextSet => (items.SkipWhile(i => !i.Selected).Skip(1).FirstOrDefault() ?? items.FirstOrDefault())?.BeatmapSetInfo;
|
||||
public BeatmapSetInfo PreviousSet => (items.TakeWhile(i => !i.Selected).LastOrDefault() ?? items.LastOrDefault())?.BeatmapSetInfo;
|
||||
|
||||
private Vector2 nativeDragPosition;
|
||||
private PlaylistItem draggedItem;
|
||||
|
||||
protected override bool OnDragStart(InputState state)
|
||||
{
|
||||
nativeDragPosition = state.Mouse.NativeState.Position;
|
||||
draggedItem = items.FirstOrDefault(d => d.IsDraggable);
|
||||
return draggedItem != null || base.OnDragStart(state);
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
nativeDragPosition = state.Mouse.NativeState.Position;
|
||||
if (draggedItem == null)
|
||||
return base.OnDrag(state);
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDragEnd(InputState state)
|
||||
{
|
||||
nativeDragPosition = state.Mouse.NativeState.Position;
|
||||
var handled = draggedItem != null || base.OnDragEnd(state);
|
||||
draggedItem = null;
|
||||
|
||||
return handled;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
if (draggedItem == null)
|
||||
return;
|
||||
|
||||
updateScrollPosition();
|
||||
updateDragPosition();
|
||||
}
|
||||
|
||||
private void updateScrollPosition()
|
||||
{
|
||||
const float start_offset = 10;
|
||||
const double max_power = 50;
|
||||
const double exp_base = 1.05;
|
||||
|
||||
var localPos = ToLocalSpace(nativeDragPosition);
|
||||
|
||||
if (localPos.Y < start_offset)
|
||||
{
|
||||
if (Current <= 0)
|
||||
return;
|
||||
|
||||
var power = Math.Min(max_power, Math.Abs(start_offset - localPos.Y));
|
||||
ScrollBy(-(float)Math.Pow(exp_base, power));
|
||||
}
|
||||
else if (localPos.Y > DrawHeight - start_offset)
|
||||
{
|
||||
if (IsScrolledToEnd())
|
||||
return;
|
||||
|
||||
var power = Math.Min(max_power, Math.Abs(DrawHeight - start_offset - localPos.Y));
|
||||
ScrollBy((float)Math.Pow(exp_base, power));
|
||||
}
|
||||
}
|
||||
|
||||
private void updateDragPosition()
|
||||
{
|
||||
var itemsPos = items.ToLocalSpace(nativeDragPosition);
|
||||
|
||||
int srcIndex = (int)draggedItem.Depth;
|
||||
|
||||
// Find the last item with position < mouse position. Note we can't directly use
|
||||
// the item positions as they are being transformed
|
||||
float heightAccumulator = 0;
|
||||
int dstIndex = 0;
|
||||
for (; dstIndex < items.Count; dstIndex++)
|
||||
{
|
||||
// Using BoundingBox here takes care of scale, paddings, etc...
|
||||
heightAccumulator += items[dstIndex].BoundingBox.Height;
|
||||
if (heightAccumulator > itemsPos.Y)
|
||||
break;
|
||||
}
|
||||
|
||||
dstIndex = MathHelper.Clamp(dstIndex, 0, items.Count - 1);
|
||||
|
||||
if (srcIndex == dstIndex)
|
||||
return;
|
||||
|
||||
if (srcIndex < dstIndex)
|
||||
{
|
||||
for (int i = srcIndex + 1; i <= dstIndex; i++)
|
||||
items.ChangeChildDepth(items[i], i - 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
for (int i = dstIndex; i < srcIndex; i++)
|
||||
items.ChangeChildDepth(items[i], i + 1);
|
||||
}
|
||||
|
||||
items.ChangeChildDepth(draggedItem, dstIndex);
|
||||
}
|
||||
|
||||
|
||||
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
||||
{
|
||||
public string[] FilterTerms => new string[] { };
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
if (value)
|
||||
InvalidateLayout();
|
||||
}
|
||||
}
|
||||
|
||||
// Compare with reversed ChildID and Depth
|
||||
protected override int Compare(Drawable x, Drawable y) => base.Compare(y, x);
|
||||
|
||||
public IEnumerable<IFilterable> FilterableChildren => Children;
|
||||
|
||||
public ItemSearchContainer()
|
||||
{
|
||||
LayoutDuration = 200;
|
||||
LayoutEasing = Easing.OutQuint;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +92,7 @@ namespace osu.Game.Overlays.Music
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
beatmapBacking.ValueChanged += b => list.SelectedItem = b?.BeatmapSetInfo;
|
||||
beatmapBacking.ValueChanged += b => list.SelectedSet = b?.BeatmapSetInfo;
|
||||
beatmapBacking.TriggerChange();
|
||||
}
|
||||
|
||||
@@ -126,24 +126,24 @@ namespace osu.Game.Overlays.Music
|
||||
|
||||
public void PlayPrevious()
|
||||
{
|
||||
var currentID = beatmapBacking.Value?.BeatmapSetInfo.ID ?? -1;
|
||||
var available = BeatmapSets.Reverse();
|
||||
|
||||
var playable = available.SkipWhile(b => b.ID != currentID).Skip(1).FirstOrDefault() ?? available.FirstOrDefault();
|
||||
var playable = list.PreviousSet;
|
||||
|
||||
if (playable != null)
|
||||
{
|
||||
playSpecified(playable.Beatmaps[0]);
|
||||
list.SelectedSet = playable;
|
||||
}
|
||||
}
|
||||
|
||||
public void PlayNext()
|
||||
{
|
||||
var currentID = beatmapBacking.Value?.BeatmapSetInfo.ID ?? -1;
|
||||
var available = BeatmapSets;
|
||||
|
||||
var playable = available.SkipWhile(b => b.ID != currentID).Skip(1).FirstOrDefault() ?? available.FirstOrDefault();
|
||||
var playable = list.NextSet;
|
||||
|
||||
if (playable != null)
|
||||
{
|
||||
playSpecified(playable.Beatmaps[0]);
|
||||
list.SelectedSet = playable;
|
||||
}
|
||||
}
|
||||
|
||||
private void playSpecified(BeatmapInfo info)
|
||||
|
||||
@@ -15,7 +15,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Threading;
|
||||
@@ -205,7 +204,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
beatmapBacking.BindTo(game.Beatmap);
|
||||
|
||||
playlist.StateChanged += (c, s) => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
|
||||
playlist.StateChanged += s => playlistButton.FadeColour(s == Visibility.Visible ? colours.Yellow : Color4.White, 200, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
@@ -349,23 +348,23 @@ namespace osu.Game.Overlays
|
||||
|
||||
playerContainer.Add(new AsyncLoadWrapper(new Background(beatmap)
|
||||
{
|
||||
OnLoadComplete = d =>
|
||||
OnLoadComplete = newBackground =>
|
||||
{
|
||||
switch (direction)
|
||||
{
|
||||
case TransformDirection.Next:
|
||||
d.Position = new Vector2(400, 0);
|
||||
d.MoveToX(0, 500, Easing.OutCubic);
|
||||
newBackground.Position = new Vector2(400, 0);
|
||||
newBackground.MoveToX(0, 500, Easing.OutCubic);
|
||||
currentBackground.MoveToX(-400, 500, Easing.OutCubic);
|
||||
break;
|
||||
case TransformDirection.Prev:
|
||||
d.Position = new Vector2(-400, 0);
|
||||
d.MoveToX(0, 500, Easing.OutCubic);
|
||||
newBackground.Position = new Vector2(-400, 0);
|
||||
newBackground.MoveToX(0, 500, Easing.OutCubic);
|
||||
currentBackground.MoveToX(400, 500, Easing.OutCubic);
|
||||
break;
|
||||
}
|
||||
currentBackground.Expire();
|
||||
currentBackground = d;
|
||||
currentBackground = newBackground;
|
||||
}
|
||||
})
|
||||
{
|
||||
@@ -434,49 +433,5 @@ namespace osu.Game.Overlays
|
||||
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
||||
}
|
||||
}
|
||||
|
||||
private class ProgressBar : SliderBar<double>
|
||||
{
|
||||
public Action<double> OnSeek;
|
||||
|
||||
private readonly Box fill;
|
||||
|
||||
public Color4 FillColour
|
||||
{
|
||||
set { fill.Colour = value; }
|
||||
}
|
||||
|
||||
public double EndTime
|
||||
{
|
||||
set { CurrentNumber.MaxValue = value; }
|
||||
}
|
||||
|
||||
public double CurrentTime
|
||||
{
|
||||
set { CurrentNumber.Value = value; }
|
||||
}
|
||||
|
||||
public ProgressBar()
|
||||
{
|
||||
CurrentNumber.MinValue = 0;
|
||||
CurrentNumber.MaxValue = 1;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fill = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void UpdateValue(float value)
|
||||
{
|
||||
fill.Width = value * UsableWidth;
|
||||
}
|
||||
|
||||
protected override void OnUserChange() => OnSeek?.Invoke(Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -152,11 +152,14 @@ namespace osu.Game.Overlays.Notifications
|
||||
break;
|
||||
case ProgressNotificationState.Active:
|
||||
case ProgressNotificationState.Queued:
|
||||
State = ProgressNotificationState.Cancelled;
|
||||
if (CancelRequested?.Invoke() != false)
|
||||
State = ProgressNotificationState.Cancelled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Func<bool> CancelRequested { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The function to post completion notifications back to.
|
||||
/// </summary>
|
||||
|
||||
@@ -12,8 +12,9 @@ namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public class SlimEnumDropdown<T> : OsuEnumDropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new SlimDropdownHeader { AccentColour = AccentColour };
|
||||
protected override Menu CreateMenu() => new SlimMenu();
|
||||
protected override DropdownHeader CreateHeader() => new SlimDropdownHeader();
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new SlimMenu();
|
||||
|
||||
private class SlimDropdownHeader : OsuDropdownHeader
|
||||
{
|
||||
@@ -31,11 +32,11 @@ namespace osu.Game.Overlays.SearchableList
|
||||
}
|
||||
}
|
||||
|
||||
private class SlimMenu : OsuMenu
|
||||
private class SlimMenu : OsuDropdownMenu
|
||||
{
|
||||
public SlimMenu()
|
||||
{
|
||||
Background.Colour = Color4.Black.Opacity(0.7f);
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -257,9 +257,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
|
||||
private class UserDropdown : OsuEnumDropdown<UserAction>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new UserDropdownHeader { AccentColour = AccentColour };
|
||||
protected override Menu CreateMenu() => new UserDropdownMenu();
|
||||
protected override DropdownMenuItem<UserAction> CreateMenuItem(string text, UserAction value) => new UserDropdownMenuItem(text, value) { AccentColour = AccentColour };
|
||||
protected override DropdownHeader CreateHeader() => new UserDropdownHeader();
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new UserDropdownMenu();
|
||||
|
||||
public Color4 StatusColour
|
||||
{
|
||||
@@ -277,6 +277,49 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
AccentColour = colours.Gray5;
|
||||
}
|
||||
|
||||
private class UserDropdownMenu : OsuDropdownMenu
|
||||
{
|
||||
public UserDropdownMenu()
|
||||
{
|
||||
Masking = true;
|
||||
CornerRadius = 5;
|
||||
|
||||
Margin = new MarginPadding { Bottom = 5 };
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Radius = 4,
|
||||
};
|
||||
|
||||
ItemsContainer.Padding = new MarginPadding();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.Gray3;
|
||||
}
|
||||
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(MenuItem item) => new DrawableUserDropdownMenuItem(item);
|
||||
|
||||
private class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem
|
||||
{
|
||||
public DrawableUserDropdownMenuItem(MenuItem item)
|
||||
: base(item)
|
||||
{
|
||||
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 };
|
||||
CornerRadius = 5;
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new Content
|
||||
{
|
||||
Label = { Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 } }
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class UserDropdownHeader : OsuDropdownHeader
|
||||
{
|
||||
public const float LABEL_LEFT_MARGIN = 20;
|
||||
@@ -324,38 +367,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
}
|
||||
}
|
||||
|
||||
private class UserDropdownMenu : OsuMenu
|
||||
{
|
||||
public UserDropdownMenu()
|
||||
{
|
||||
Margin = new MarginPadding { Bottom = 5 };
|
||||
CornerRadius = 5;
|
||||
ItemsContainer.Padding = new MarginPadding(0);
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Radius = 4,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Background.Colour = colours.Gray3;
|
||||
}
|
||||
}
|
||||
|
||||
private class UserDropdownMenuItem : OsuDropdownMenuItem
|
||||
{
|
||||
public UserDropdownMenuItem(string text, UserAction current) : base(text, current)
|
||||
{
|
||||
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 };
|
||||
Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 };
|
||||
CornerRadius = 5;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum UserAction
|
||||
|
||||
@@ -13,6 +13,7 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
{
|
||||
private OsuButton importButton;
|
||||
private OsuButton deleteButton;
|
||||
private OsuButton restoreButton;
|
||||
|
||||
protected override string Header => "General";
|
||||
|
||||
@@ -41,6 +42,20 @@ namespace osu.Game.Overlays.Settings.Sections.Maintenance
|
||||
Task.Run(() => beatmaps.DeleteAll()).ContinueWith(t => Schedule(() => deleteButton.Enabled.Value = true));
|
||||
}
|
||||
},
|
||||
restoreButton = new OsuButton
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Text = "Restore all hidden difficulties",
|
||||
Action = () =>
|
||||
{
|
||||
restoreButton.Enabled.Value = false;
|
||||
Task.Run(() =>
|
||||
{
|
||||
foreach (var b in beatmaps.QueryBeatmaps(b => b.Hidden))
|
||||
beatmaps.Restore(b);
|
||||
}).ContinueWith(t => Schedule(() => restoreButton.Enabled.Value = true));
|
||||
}
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Framework;
|
||||
using OpenTK;
|
||||
@@ -19,6 +20,9 @@ namespace osu.Game.Overlays.Settings
|
||||
private readonly FillFlowContainer<SidebarButton> content;
|
||||
internal const float DEFAULT_WIDTH = ToolbarButton.WIDTH;
|
||||
internal const int EXPANDED_WIDTH = 200;
|
||||
|
||||
public event Action<ExpandedState> StateChanged;
|
||||
|
||||
protected override Container<SidebarButton> Content => content;
|
||||
|
||||
public Sidebar()
|
||||
@@ -102,6 +106,8 @@ namespace osu.Game.Overlays.Settings
|
||||
this.ResizeTo(new Vector2(EXPANDED_WIDTH, Height), 500, Easing.OutQuint);
|
||||
break;
|
||||
}
|
||||
|
||||
StateChanged?.Invoke(State);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -58,6 +58,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ToolbarDirectButton(),
|
||||
new ToolbarChatButton(),
|
||||
new ToolbarSocialButton(),
|
||||
new ToolbarMusicButton(),
|
||||
|
||||
@@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
internal class ToolbarDirectButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
public ToolbarDirectButton()
|
||||
{
|
||||
SetIcon(FontAwesome.fa_osu_chevron_down_o);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(DirectOverlay direct)
|
||||
{
|
||||
StateContainer = direct;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
stateContainer.StateChanged -= stateChanged;
|
||||
}
|
||||
|
||||
private void stateChanged(VisibilityContainer c, Visibility state)
|
||||
private void stateChanged(Visibility state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
|
||||
@@ -167,6 +167,8 @@ namespace osu.Game.Overlays
|
||||
|
||||
private class Wave : Container, IStateful<Visibility>
|
||||
{
|
||||
public event Action<Visibility> StateChanged;
|
||||
|
||||
public float FinalPosition;
|
||||
|
||||
public Wave()
|
||||
@@ -200,6 +202,7 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
private Visibility state;
|
||||
|
||||
public Visibility State
|
||||
{
|
||||
get { return state; }
|
||||
@@ -216,6 +219,8 @@ namespace osu.Game.Overlays
|
||||
this.MoveToY(FinalPosition, APPEAR_DURATION, easing_show);
|
||||
break;
|
||||
}
|
||||
|
||||
StateChanged?.Invoke(State);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,11 @@ namespace osu.Game.Rulesets.Mods
|
||||
/// </summary>
|
||||
public abstract string Name { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The shortened name of this mod.
|
||||
/// </summary>
|
||||
public abstract string ShortenedName { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The icon of this mod.
|
||||
/// </summary>
|
||||
|
||||
@@ -24,6 +24,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public class ModAutoplay : Mod
|
||||
{
|
||||
public override string Name => "Autoplay";
|
||||
public override string ShortenedName => "AT";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_auto;
|
||||
public override string Description => "Watch a perfect automated play through the song";
|
||||
public override double ScoreMultiplier => 0;
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public class ModCinema : ModAutoplay
|
||||
{
|
||||
public override string Name => "Cinema";
|
||||
public override string ShortenedName => "CN";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_cinema;
|
||||
}
|
||||
}
|
||||
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModDaycore : ModHalfTime
|
||||
{
|
||||
public override string Name => "Daycore";
|
||||
public override string ShortenedName => "DC";
|
||||
public override FontAwesome Icon => FontAwesome.fa_question;
|
||||
public override string Description => "whoaaaaa";
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public class ModDoubleTime : Mod, IApplicableToClock
|
||||
{
|
||||
public override string Name => "Double Time";
|
||||
public override string ShortenedName => "DT";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_doubletime;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Zoooooooooom";
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModEasy : Mod, IApplicableToDifficulty
|
||||
{
|
||||
public override string Name => "Easy";
|
||||
public override string ShortenedName => "EZ";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_easy;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => "Reduces overall difficulty - larger circles, more forgiving HP drain, less accuracy required.";
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModFlashlight : Mod
|
||||
{
|
||||
public override string Name => "Flashlight";
|
||||
public override string ShortenedName => "FL";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_flashlight;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Restricted view area.";
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModHalfTime : Mod, IApplicableToClock
|
||||
{
|
||||
public override string Name => "Half Time";
|
||||
public override string ShortenedName => "HT";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_halftime;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => "Less zoom";
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModHardRock : Mod, IApplicableToDifficulty
|
||||
{
|
||||
public override string Name => "Hard Rock";
|
||||
public override string ShortenedName => "HR";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hardrock;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Everything just got a bit harder...";
|
||||
|
||||
@@ -8,6 +8,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModHidden : Mod
|
||||
{
|
||||
public override string Name => "Hidden";
|
||||
public override string ShortenedName => "HD";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override bool Ranked => true;
|
||||
|
||||
@@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModNightcore : ModDoubleTime
|
||||
{
|
||||
public override string Name => "Nightcore";
|
||||
public override string ShortenedName => "NC";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nightcore;
|
||||
public override string Description => "uguuuuuuuu";
|
||||
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModNoFail : Mod
|
||||
{
|
||||
public override string Name => "NoFail";
|
||||
public override string ShortenedName => "NF";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_nofail;
|
||||
public override ModType Type => ModType.DifficultyReduction;
|
||||
public override string Description => "You can't fail, no matter what.";
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModPerfect : ModSuddenDeath
|
||||
{
|
||||
public override string Name => "Perfect";
|
||||
public override string ShortenedName => "PF";
|
||||
public override string Description => "SS or quit.";
|
||||
}
|
||||
}
|
||||
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModRelax : Mod
|
||||
{
|
||||
public override string Name => "Relax";
|
||||
public override string ShortenedName => "RX";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_relax;
|
||||
public override double ScoreMultiplier => 0;
|
||||
public override Type[] IncompatibleMods => new[] { typeof(ModAutoplay), typeof(ModNoFail), typeof(ModSuddenDeath) };
|
||||
|
||||
@@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public abstract class ModSuddenDeath : Mod
|
||||
{
|
||||
public override string Name => "Sudden Death";
|
||||
public override string ShortenedName => "SD";
|
||||
public override FontAwesome Icon => FontAwesome.fa_osu_mod_suddendeath;
|
||||
public override ModType Type => ModType.DifficultyIncrease;
|
||||
public override string Description => "Miss a note and fail.";
|
||||
|
||||
@@ -6,6 +6,7 @@ namespace osu.Game.Rulesets.Mods
|
||||
public class MultiMod : Mod
|
||||
{
|
||||
public override string Name => string.Empty;
|
||||
public override string ShortenedName => string.Empty;
|
||||
public override string Description => string.Empty;
|
||||
public override double ScoreMultiplier => 0.0;
|
||||
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Input.Handlers;
|
||||
@@ -18,7 +17,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
/// The ReplayHandler will take a replay and handle the propagation of updates to the input stack.
|
||||
/// It handles logic of any frames which *must* be executed.
|
||||
/// </summary>
|
||||
public class FramedReplayInputHandler : ReplayInputHandler
|
||||
public abstract class FramedReplayInputHandler : ReplayInputHandler
|
||||
{
|
||||
private readonly Replay replay;
|
||||
|
||||
@@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
|
||||
private int nextFrameIndex => MathHelper.Clamp(currentFrameIndex + (currentDirection > 0 ? 1 : -1), 0, Frames.Count - 1);
|
||||
|
||||
public FramedReplayInputHandler(Replay replay)
|
||||
protected FramedReplayInputHandler(Replay replay)
|
||||
{
|
||||
this.replay = replay;
|
||||
}
|
||||
@@ -51,7 +50,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
{
|
||||
}
|
||||
|
||||
private Vector2? position
|
||||
protected Vector2? Position
|
||||
{
|
||||
get
|
||||
{
|
||||
@@ -62,23 +61,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
}
|
||||
}
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
var buttons = new HashSet<MouseButton>();
|
||||
if (CurrentFrame?.MouseLeft ?? false)
|
||||
buttons.Add(MouseButton.Left);
|
||||
if (CurrentFrame?.MouseRight ?? false)
|
||||
buttons.Add(MouseButton.Right);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new InputState
|
||||
{
|
||||
Mouse = new ReplayMouseState(ToScreenSpace(position ?? Vector2.Zero), buttons),
|
||||
Keyboard = new ReplayKeyboardState(new List<Key>())
|
||||
}
|
||||
};
|
||||
}
|
||||
public override List<InputState> GetPendingStates() => new List<InputState>();
|
||||
|
||||
public bool AtLastFrame => currentFrameIndex == Frames.Count - 1;
|
||||
public bool AtFirstFrame => currentFrameIndex == 0;
|
||||
@@ -133,10 +116,9 @@ namespace osu.Game.Rulesets.Replays
|
||||
|
||||
protected class ReplayMouseState : MouseState
|
||||
{
|
||||
public ReplayMouseState(Vector2 position, IEnumerable<MouseButton> list)
|
||||
public ReplayMouseState(Vector2 position)
|
||||
{
|
||||
Position = position;
|
||||
list.ForEach(b => SetPressed(b, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,15 +1,17 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays.Settings;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
|
||||
namespace osu.Game.Rulesets
|
||||
{
|
||||
@@ -19,9 +21,18 @@ namespace osu.Game.Rulesets
|
||||
|
||||
public virtual IEnumerable<BeatmapStatistic> GetBeatmapStatistics(WorkingBeatmap beatmap) => new BeatmapStatistic[] { };
|
||||
|
||||
public IEnumerable<Mod> GetAllMods() => Enum.GetValues(typeof(ModType)).Cast<ModType>()
|
||||
// Get all mod types as an IEnumerable<ModType>
|
||||
.SelectMany(GetModsFor)
|
||||
// Confine all mods of each mod type into a single IEnumerable<Mod>
|
||||
.Where(mod => mod != null)
|
||||
// Filter out all null mods
|
||||
.SelectMany(mod => (mod as MultiMod)?.Mods ?? new[] { mod });
|
||||
// Resolve MultiMods as their .Mods property
|
||||
|
||||
public abstract IEnumerable<Mod> GetModsFor(ModType type);
|
||||
|
||||
public abstract Mod GetAutoplayMod();
|
||||
public Mod GetAutoplayMod() => GetAllMods().First(mod => mod is ModAutoplay);
|
||||
|
||||
protected Ruleset(RulesetInfo rulesetInfo)
|
||||
{
|
||||
|
||||
@@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Users;
|
||||
@@ -15,70 +14,30 @@ namespace osu.Game.Rulesets.Scoring
|
||||
{
|
||||
public ScoreRank Rank { get; set; }
|
||||
|
||||
[JsonProperty(@"score")]
|
||||
public double TotalScore { get; set; }
|
||||
|
||||
public double Accuracy { get; set; }
|
||||
|
||||
public double Health { get; set; } = 1;
|
||||
|
||||
[JsonProperty(@"max_combo")]
|
||||
public int MaxCombo { get; set; }
|
||||
|
||||
public int Combo { get; set; }
|
||||
|
||||
[JsonProperty(@"mods")]
|
||||
protected string[] ModStrings { get; set; } //todo: parse to Mod objects
|
||||
|
||||
public RulesetInfo Ruleset { get; set; }
|
||||
|
||||
public Mod[] Mods { get; set; }
|
||||
|
||||
[JsonProperty(@"user")]
|
||||
public User User;
|
||||
|
||||
[JsonProperty(@"replay_data")]
|
||||
public Replay Replay;
|
||||
|
||||
public BeatmapInfo Beatmap;
|
||||
|
||||
[JsonProperty(@"score_id")]
|
||||
public long OnlineScoreID;
|
||||
|
||||
[JsonProperty(@"created_at")]
|
||||
public DateTimeOffset Date;
|
||||
|
||||
[JsonProperty(@"statistics")]
|
||||
private Dictionary<string, dynamic> jsonStats
|
||||
{
|
||||
set
|
||||
{
|
||||
foreach (var kvp in value)
|
||||
{
|
||||
string key = kvp.Key;
|
||||
switch (key)
|
||||
{
|
||||
case @"count_300":
|
||||
key = @"300";
|
||||
break;
|
||||
case @"count_100":
|
||||
key = @"100";
|
||||
break;
|
||||
case @"count_50":
|
||||
key = @"50";
|
||||
break;
|
||||
case @"count_miss":
|
||||
key = @"x";
|
||||
break;
|
||||
default:
|
||||
continue;
|
||||
}
|
||||
|
||||
Statistics.Add(key, kvp.Value);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public Dictionary<string, dynamic> Statistics = new Dictionary<string, dynamic>();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@ namespace osu.Game.Rulesets.UI
|
||||
private readonly SpriteIcon modIcon;
|
||||
private readonly SpriteIcon background;
|
||||
|
||||
private const float icon_size = 80;
|
||||
private const float background_size = 80;
|
||||
|
||||
public FontAwesome Icon
|
||||
{
|
||||
@@ -39,7 +39,7 @@ namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Size = new Vector2(icon_size),
|
||||
Size = new Vector2(background_size),
|
||||
Icon = FontAwesome.fa_osu_mod_bg,
|
||||
Shadow = true,
|
||||
},
|
||||
@@ -48,7 +48,7 @@ namespace osu.Game.Rulesets.UI
|
||||
Origin = Anchor.TopCentre,
|
||||
Anchor = Anchor.TopCentre,
|
||||
Colour = OsuColour.Gray(84),
|
||||
Size = new Vector2(icon_size - 35),
|
||||
Size = new Vector2(background_size - 35),
|
||||
Y = 25,
|
||||
Icon = mod.Icon
|
||||
},
|
||||
|
||||
@@ -9,7 +9,6 @@ using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Screens.Play;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@@ -43,7 +42,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <summary>
|
||||
/// The input manager for this RulesetContainer.
|
||||
/// </summary>
|
||||
internal readonly PlayerInputManager InputManager = new PlayerInputManager();
|
||||
internal IHasReplayHandler ReplayInputManager => KeyBindingInputManager as IHasReplayHandler;
|
||||
|
||||
/// <summary>
|
||||
/// The key conversion input manager for this RulesetContainer.
|
||||
@@ -58,7 +57,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <summary>
|
||||
/// Whether we have a replay loaded currently.
|
||||
/// </summary>
|
||||
public bool HasReplayLoaded => InputManager.ReplayInputHandler != null;
|
||||
public bool HasReplayLoaded => ReplayInputManager?.ReplayInputHandler != null;
|
||||
|
||||
public abstract IEnumerable<HitObject> Objects { get; }
|
||||
|
||||
@@ -102,7 +101,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <returns>The input manager.</returns>
|
||||
public abstract PassThroughInputManager CreateInputManager();
|
||||
|
||||
protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new FramedReplayInputHandler(replay);
|
||||
protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => null;
|
||||
|
||||
public Replay Replay { get; private set; }
|
||||
|
||||
@@ -112,8 +111,11 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <param name="replay">The replay, null for local input.</param>
|
||||
public virtual void SetReplay(Replay replay)
|
||||
{
|
||||
if (ReplayInputManager == null)
|
||||
throw new InvalidOperationException($"A {nameof(KeyBindingInputManager)} which supports replay loading is not available");
|
||||
|
||||
Replay = replay;
|
||||
InputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
||||
ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,13 +269,12 @@ namespace osu.Game.Rulesets.UI
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InputManager.Add(content = new Container
|
||||
KeyBindingInputManager.Add(content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new[] { KeyBindingInputManager }
|
||||
});
|
||||
|
||||
AddInternal(InputManager);
|
||||
AddInternal(KeyBindingInputManager);
|
||||
KeyBindingInputManager.Add(Playfield = CreatePlayfield());
|
||||
|
||||
loadObjects();
|
||||
@@ -283,8 +284,8 @@ namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
base.SetReplay(replay);
|
||||
|
||||
if (InputManager?.ReplayInputHandler != null)
|
||||
InputManager.ReplayInputHandler.ToScreenSpace = Playfield.ScaledContent.ToScreenSpace;
|
||||
if (ReplayInputManager?.ReplayInputHandler != null)
|
||||
ReplayInputManager.ReplayInputHandler.ToScreenSpace = input => Playfield.ScaledContent.ToScreenSpace(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user