diff --git a/.vscode/launch.json b/.vscode/launch.json index 0e07b0a067..b3b86da42f 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -2,46 +2,60 @@ "version": "0.2.0", "configurations": [ { - "name": "Launch VisualTests", + "name": "VisualTests (debug)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", "program": "${workspaceRoot}/osu.Desktop.VisualTests/bin/Debug/osu!.exe", - "args": [], "cwd": "${workspaceRoot}", - "preLaunchTask": "build", + "preLaunchTask": "Build (Debug)", "runtimeExecutable": null, "env": {}, "console": "internalConsole" }, { - "name": "Launch Desktop", + "name": "VisualTests (release)", + "windows": { + "type": "clr" + }, + "type": "mono", + "request": "launch", + "program": "${workspaceRoot}/osu.Desktop.VisualTests/bin/Release/osu!.exe", + "cwd": "${workspaceRoot}", + "preLaunchTask": "Build (Release)", + "runtimeExecutable": null, + "env": {}, + "console": "internalConsole" + }, + { + "name": "osu! (debug)", "windows": { "type": "clr" }, "type": "mono", "request": "launch", "program": "${workspaceRoot}/osu.Desktop/bin/Debug/osu!.exe", - "args": [], "cwd": "${workspaceRoot}", - "preLaunchTask": "build", + "preLaunchTask": "Build (Debug)", "runtimeExecutable": null, "env": {}, "console": "internalConsole" }, { - "name": "Attach", + "name": "osu! (release)", "windows": { - "type": "clr", - "request": "attach", - "processName": "osu!" + "type": "clr" }, "type": "mono", - "request": "attach", - "address": "localhost", - "port": 55555 + "request": "launch", + "program": "${workspaceRoot}/osu.Desktop/bin/Release/osu!.exe", + "cwd": "${workspaceRoot}", + "preLaunchTask": "Build (Release)", + "runtimeExecutable": null, + "env": {}, + "console": "internalConsole" } ] } \ No newline at end of file diff --git a/.vscode/tasks.json b/.vscode/tasks.json index 5eaeaa9899..f285ebde67 100644 --- a/.vscode/tasks.json +++ b/.vscode/tasks.json @@ -1,51 +1,50 @@ { // See https://go.microsoft.com/fwlink/?LinkId=733558 // for the documentation about the tasks.json format - "version": "0.1.0", - "taskSelector": "/t:", + "version": "2.0.0", + "problemMatcher": "$msCompile", + "isShellCommand": true, + "command": "msbuild", + "suppressTaskName": true, + "showOutput": "silent", + "args": [ + "/property:GenerateFullPaths=true", + "/property:DebugType=portable" + ], + "windows": { + "args": [ + "/property:GenerateFullPaths=true", + "/property:DebugType=portable", + "/m" //parallel compiling support. doesn't work well with mono atm + ] + }, "tasks": [ { - "taskName": "build", - "isShellCommand": true, - "showOutput": "silent", - "command": "msbuild", - "args": [ - "/property:GenerateFullPaths=true", - "/property:DebugType=portable" - ], - "windows": { - "args": [ - "/property:GenerateFullPaths=true", - "/property:DebugType=portable", - "/m" //parallel compiling support. doesn't work well with mono atm - ] - }, - // Use the standard MS compiler pattern to detect errors, warnings and infos - "problemMatcher": "$msCompile", + "taskName": "Build (Debug)", "isBuildCommand": true }, { - "taskName": "rebuild", - "isShellCommand": true, - "showOutput": "silent", - "command": "msbuild", + "taskName": "Build (Release)", "args": [ - // Ask msbuild to generate full paths for file names. - "/property:GenerateFullPaths=true", - "/property:DebugType=portable", - "/target:Clean,Build" - ], - "windows": { - "args": [ - "/property:GenerateFullPaths=true", - "/property:DebugType=portable", - "/target:Clean,Build", - "/m" //parallel compiling support. doesn't work well with mono atm - ] - }, - // Use the standard MS compiler pattern to detect errors, warnings and infos - "problemMatcher": "$msCompile", - "isBuildCommand": true + "/property:Configuration=Release" + ] + }, + { + "taskName": "Clean All", + "dependsOn": ["Clean (Debug)", "Clean (Release)"] + }, + { + "taskName": "Clean (Debug)", + "args": [ + "/target:Clean" + ] + }, + { + "taskName": "Clean (Release)", + "args": [ + "/target:Clean", + "/property:Configuration=Release" + ] } ] } \ No newline at end of file diff --git a/osu.Desktop.VisualTests/Tests/TestCaseManiaPlayfield.cs b/osu.Desktop.VisualTests/Tests/TestCaseManiaPlayfield.cs new file mode 100644 index 0000000000..2d4414d19f --- /dev/null +++ b/osu.Desktop.VisualTests/Tests/TestCaseManiaPlayfield.cs @@ -0,0 +1,70 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Extensions.IEnumerableExtensions; +using osu.Framework.Input; +using osu.Framework.Testing; +using osu.Framework.Graphics; +using osu.Game.Rulesets.Mania.UI; +using System.Linq; +using System; + +namespace osu.Desktop.VisualTests.Tests +{ + internal class TestCaseManiaPlayfield : TestCase + { + public override string Description => @"Mania playfield"; + + protected override double TimePerAction => 200; + + public override void Reset() + { + base.Reset(); + + const int max_columns = 10; + + Action createPlayfield = (cols, pos) => + { + Clear(); + Add(new ManiaPlayfield(cols) + { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + SpecialColumnPosition = pos + }); + }; + + for (int i = 1; i <= max_columns; i++) + { + int tempI = i; + + AddStep($"{i} column" + (i > 1 ? "s" : ""), () => createPlayfield(tempI, SpecialColumnPosition.Normal)); + + AddStep("Trigger keys down", () => ((ManiaPlayfield)Children.First()).Columns.Children.ForEach(triggerKeyDown)); + AddStep("Trigger keys up", () => ((ManiaPlayfield)Children.First()).Columns.Children.ForEach(triggerKeyUp)); + + AddStep("Left special style", () => createPlayfield(tempI, SpecialColumnPosition.Left)); + AddStep("Right special style", () => createPlayfield(tempI, SpecialColumnPosition.Right)); + } + + AddStep("Normal special style", () => createPlayfield(max_columns, SpecialColumnPosition.Normal)); + } + + private void triggerKeyDown(Column column) + { + column.TriggerKeyDown(new InputState(), new KeyDownEventArgs + { + Key = column.Key, + Repeat = false + }); + } + + private void triggerKeyUp(Column column) + { + column.TriggerKeyUp(new InputState(), new KeyUpEventArgs + { + Key = column.Key + }); + } + } +} diff --git a/osu.Desktop.VisualTests/Tests/TestCaseModSelectOverlay.cs b/osu.Desktop.VisualTests/Tests/TestCaseMods.cs similarity index 65% rename from osu.Desktop.VisualTests/Tests/TestCaseModSelectOverlay.cs rename to osu.Desktop.VisualTests/Tests/TestCaseMods.cs index d1c137191f..3f3a9d82f5 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseModSelectOverlay.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseMods.cs @@ -6,16 +6,21 @@ using osu.Framework.Graphics; using osu.Game.Overlays.Mods; using osu.Framework.Testing; using osu.Game.Database; +using osu.Game.Screens.Play.HUD; +using OpenTK; namespace osu.Desktop.VisualTests.Tests { - internal class TestCaseModSelectOverlay : TestCase + internal class TestCaseMods : TestCase { - public override string Description => @"Tests the mod select overlay"; + public override string Description => @"Mod select overlay and in-game display"; private ModSelectOverlay modSelect; + private ModDisplay modDisplay; + private RulesetDatabase rulesets; + [BackgroundDependencyLoader] private void load(RulesetDatabase rulesets) { @@ -33,6 +38,16 @@ namespace osu.Desktop.VisualTests.Tests Anchor = Anchor.BottomCentre, }); + Add(modDisplay = new ModDisplay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Position = new Vector2(0, 25), + }); + + modDisplay.Current.BindTo(modSelect.SelectedMods); + AddStep("Toggle", modSelect.ToggleVisibility); foreach (var ruleset in rulesets.AllRulesets) diff --git a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs index d8dac63980..cfa66f12ed 100644 --- a/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs +++ b/osu.Desktop.VisualTests/Tests/TestCaseScoreCounter.cs @@ -8,7 +8,7 @@ using osu.Framework.Graphics.Sprites; using osu.Framework.MathUtils; using osu.Framework.Testing; using osu.Game.Graphics.UserInterface; -using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play.HUD; namespace osu.Desktop.VisualTests.Tests { diff --git a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj index 135e4596c7..107072b3ea 100644 --- a/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj +++ b/osu.Desktop.VisualTests/osu.Desktop.VisualTests.csproj @@ -190,6 +190,7 @@ + @@ -211,7 +212,7 @@ - + diff --git a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs index 68458caeac..b402d3a010 100644 --- a/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs +++ b/osu.Game.Rulesets.Mania/Mods/ManiaMod.cs @@ -64,6 +64,7 @@ namespace osu.Game.Rulesets.Mania.Mods { public override string Name => "FadeIn"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden; + public override ModType Type => ModType.DifficultyIncrease; public override double ScoreMultiplier => 1; public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModFlashlight) }; diff --git a/osu.Game.Rulesets.Mania/UI/Column.cs b/osu.Game.Rulesets.Mania/UI/Column.cs new file mode 100644 index 0000000000..d2fccb2c58 --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/Column.cs @@ -0,0 +1,202 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + + +using OpenTK; +using OpenTK.Graphics; +using OpenTK.Input; +using osu.Framework.Extensions.Color4Extensions; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.Colour; +using osu.Framework.Input; +using osu.Game.Graphics; + +namespace osu.Game.Rulesets.Mania.UI +{ + public class Column : Container, IHasAccentColour + { + private const float key_size = 50; + + private const float key_icon_size = 10; + private const float key_icon_corner_radius = 3; + private const float key_icon_border_radius = 2; + + private const float hit_target_height = 10; + private const float hit_target_bar_height = 2; + + private const float column_width = 45; + private const float special_column_width = 70; + + public Key Key; + + private readonly Box background; + private readonly Container hitTargetBar; + private readonly Container keyIcon; + + public Column() + { + RelativeSizeAxes = Axes.Y; + Width = column_width; + + Children = new Drawable[] + { + background = new Box + { + Name = "Foreground", + RelativeSizeAxes = Axes.Both, + Alpha = 0.2f + }, + new FillFlowContainer + { + Name = "Key + hit target", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + AutoSizeAxes = Axes.Y, + Direction = FillDirection.Vertical, + Children = new[] + { + new Container + { + Name = "Key", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = key_size, + Children = new Drawable[] + { + new Box + { + Name = "Key gradient", + RelativeSizeAxes = Axes.Both, + ColourInfo = ColourInfo.GradientVertical(Color4.Black, Color4.Black.Opacity(0)), + Alpha = 0.5f + }, + keyIcon = new Container + { + Name = "Key icon", + Anchor = Anchor.Centre, + Origin = Anchor.Centre, + Size = new Vector2(key_icon_size), + Masking = true, + CornerRadius = key_icon_corner_radius, + BorderThickness = 2, + BorderColour = Color4.White, // Not true + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Alpha = 0, + AlwaysPresent = true + } + } + } + } + }, + new Container + { + Name = "Hit target", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = hit_target_height, + Children = new Drawable[] + { + new Box + { + Name = "Background", + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + hitTargetBar = new Container + { + Name = "Bar", + Anchor = Anchor.BottomCentre, + Origin = Anchor.BottomCentre, + RelativeSizeAxes = Axes.X, + Height = hit_target_bar_height, + Masking = true, + Children = new[] + { + new Box + { + RelativeSizeAxes = Axes.Both + } + } + } + } + } + } + } + }; + } + + private bool isSpecial; + public bool IsSpecial + { + get { return isSpecial; } + set + { + if (isSpecial == value) + return; + isSpecial = value; + + Width = isSpecial ? special_column_width : column_width; + } + } + + private Color4 accentColour; + public Color4 AccentColour + { + get { return accentColour; } + set + { + if (accentColour == value) + return; + accentColour = value; + + background.Colour = accentColour; + + hitTargetBar.EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Radius = 5, + Colour = accentColour.Opacity(0.5f), + }; + + keyIcon.EdgeEffect = new EdgeEffect + { + Type = EdgeEffectType.Glow, + Radius = 5, + Colour = accentColour.Opacity(0.5f), + }; + } + } + + protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) + { + if (args.Key == Key && !args.Repeat) + { + background.FadeTo(background.Alpha + 0.2f, 50, EasingTypes.OutQuint); + keyIcon.ScaleTo(1.4f, 50, EasingTypes.OutQuint); + } + + return false; + } + + protected override bool OnKeyUp(InputState state, KeyUpEventArgs args) + { + if (args.Key == Key) + { + background.FadeTo(0.2f, 800, EasingTypes.OutQuart); + keyIcon.ScaleTo(1f, 400, EasingTypes.OutQuart); + } + + return false; + } + } + +} diff --git a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs index 5eea3d70c0..fa55768382 100644 --- a/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs +++ b/osu.Game.Rulesets.Mania/UI/ManiaPlayfield.cs @@ -8,29 +8,153 @@ using osu.Game.Rulesets.UI; using OpenTK; using OpenTK.Graphics; using osu.Game.Rulesets.Mania.Judgements; +using osu.Framework.Graphics.Containers; +using System; +using osu.Framework.Graphics.Primitives; +using osu.Game.Graphics; +using osu.Framework.Allocation; +using OpenTK.Input; +using System.Linq; +using System.Collections.Generic; namespace osu.Game.Rulesets.Mania.UI { public class ManiaPlayfield : Playfield { - public ManiaPlayfield(int columns) + /// + /// 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... + /// + 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; + /// + /// The style to use for the special column. + /// + public SpecialColumnPosition SpecialColumnPosition { - Size = new Vector2(0.8f, 1f); - Anchor = Anchor.BottomCentre; - Origin = Anchor.BottomCentre; + get { return specialColumnPosition; } + set + { + if (IsLoaded) + throw new InvalidOperationException($"Setting {nameof(SpecialColumnPosition)} after the playfield is loaded requires re-creating the playfield."); + specialColumnPosition = value; + } + } - Add(new Box { RelativeSizeAxes = Axes.Both, Alpha = 0.5f }); + public readonly FlowContainer Columns; - for (int i = 0; i < columns; i++) - Add(new Box + private List normalColumnColours = new List(); + private Color4 specialColumnColour; + + private readonly int columnCount; + + public ManiaPlayfield(int columnCount) + { + this.columnCount = columnCount; + + if (columnCount <= 0) + throw new ArgumentException("Can't have zero or fewer columns."); + + Children = new Drawable[] + { + new Container { + Anchor = Anchor.Centre, + Origin = Anchor.Centre, RelativeSizeAxes = Axes.Y, - Size = new Vector2(2, 1), - RelativePositionAxes = Axes.Both, - Position = new Vector2((float)i / columns, 0), - Alpha = 0.5f, - Colour = Color4.Black - }); + AutoSizeAxes = Axes.X, + Children = new Drawable[] + { + new Box + { + RelativeSizeAxes = Axes.Both, + Colour = Color4.Black + }, + Columns = new FillFlowContainer + { + RelativeSizeAxes = Axes.Y, + AutoSizeAxes = Axes.X, + Direction = FillDirection.Horizontal, + Padding = new MarginPadding { Left = 1, Right = 1 }, + Spacing = new Vector2(1, 0) + } + } + } + }; + + for (int i = 0; i < columnCount; i++) + Columns.Add(new Column()); + } + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + normalColumnColours = new List + { + colours.RedDark, + colours.GreenDark + }; + + specialColumnColour = colours.BlueDark; + + // Set the special column + colour + key + for (int i = 0; i < columnCount; i++) + { + Column column = Columns.Children.ElementAt(i); + column.IsSpecial = isSpecialColumn(i); + + if (!column.IsSpecial) + continue; + + column.Key = Key.Space; + column.AccentColour = specialColumnColour; + } + + var nonSpecialColumns = Columns.Children.Where(c => !c.IsSpecial).ToList(); + + // We'll set the colours of the non-special columns in a separate loop, because the non-special + // column colours are mirrored across their centre and special styles mess with this + for (int i = 0; i < Math.Ceiling(nonSpecialColumns.Count / 2f); i++) + { + Color4 colour = normalColumnColours[i % normalColumnColours.Count]; + nonSpecialColumns[i].AccentColour = colour; + nonSpecialColumns[nonSpecialColumns.Count - 1 - i].AccentColour = colour; + } + + // We'll set the keys for non-special columns in another separate loop because it's not mirrored like the above colours + // Todo: This needs to go when we get to bindings and use Button1, ..., ButtonN instead + for (int i = 0; i < nonSpecialColumns.Count; i++) + { + Column column = nonSpecialColumns[i]; + + int keyOffset = default_keys.Length / 2 - nonSpecialColumns.Count / 2 + i; + if (keyOffset >= 0 && keyOffset < default_keys.Length) + column.Key = default_keys[keyOffset]; + else + // There is no default key defined for this column. Let's set this to Unknown for now + // however note that this will be gone after bindings are in place + column.Key = Key.Unknown; + } + } + + /// + /// Whether the column index is a special column for this playfield. + /// + /// The 0-based column index. + /// Whether the column is a special column. + private bool isSpecialColumn(int column) + { + switch (SpecialColumnPosition) + { + default: + case SpecialColumnPosition.Normal: + return columnCount % 2 == 1 && column == columnCount / 2; + case SpecialColumnPosition.Left: + return column == 0; + case SpecialColumnPosition.Right: + return column == columnCount - 1; + } } } -} \ No newline at end of file +} diff --git a/osu.Game.Rulesets.Mania/UI/SpecialColumnPosition.cs b/osu.Game.Rulesets.Mania/UI/SpecialColumnPosition.cs new file mode 100644 index 0000000000..7fd30e7d0d --- /dev/null +++ b/osu.Game.Rulesets.Mania/UI/SpecialColumnPosition.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +namespace osu.Game.Rulesets.Mania.UI +{ + public enum SpecialColumnPosition + { + /// + /// The special column will lie in the center of the columns. + /// + Normal, + /// + /// The special column will lie to the left of the columns. + /// + Left, + /// + /// The special column will lie to the right of the columns. + /// + Right + } +} diff --git a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj index facffa757c..e2c6ad9a9f 100644 --- a/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj +++ b/osu.Game.Rulesets.Mania/osu.Game.Rulesets.Mania.csproj @@ -56,10 +56,12 @@ + + diff --git a/osu.Game/Overlays/Mods/AssistedSection.cs b/osu.Game/Overlays/Mods/AssistedSection.cs index b4263fa309..b3cbb410e4 100644 --- a/osu.Game/Overlays/Mods/AssistedSection.cs +++ b/osu.Game/Overlays/Mods/AssistedSection.cs @@ -16,7 +16,6 @@ namespace osu.Game.Overlays.Mods [BackgroundDependencyLoader] private void load(OsuColour colours) { - ButtonColour = colours.Blue; SelectedColour = colours.BlueLight; } diff --git a/osu.Game/Overlays/Mods/DifficultyIncreaseSection.cs b/osu.Game/Overlays/Mods/DifficultyIncreaseSection.cs index 0a293416dc..fc759eb7d9 100644 --- a/osu.Game/Overlays/Mods/DifficultyIncreaseSection.cs +++ b/osu.Game/Overlays/Mods/DifficultyIncreaseSection.cs @@ -16,7 +16,6 @@ namespace osu.Game.Overlays.Mods [BackgroundDependencyLoader] private void load(OsuColour colours) { - ButtonColour = colours.Yellow; SelectedColour = colours.YellowLight; } diff --git a/osu.Game/Overlays/Mods/DifficultyReductionSection.cs b/osu.Game/Overlays/Mods/DifficultyReductionSection.cs index 3a373e6f09..dd3b5965f3 100644 --- a/osu.Game/Overlays/Mods/DifficultyReductionSection.cs +++ b/osu.Game/Overlays/Mods/DifficultyReductionSection.cs @@ -16,7 +16,6 @@ namespace osu.Game.Overlays.Mods [BackgroundDependencyLoader] private void load(OsuColour colours) { - ButtonColour = colours.Green; SelectedColour = colours.GreenLight; } diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index f380c19d8a..ce70144bc3 100644 --- a/osu.Game/Overlays/Mods/ModButton.cs +++ b/osu.Game/Overlays/Mods/ModButton.cs @@ -19,7 +19,11 @@ using System.Linq; namespace osu.Game.Overlays.Mods { - public class ModButton : FillFlowContainer + + /// + /// Represents a clickable button which can cycle through one of more mods. + /// + public class ModButton : ModButtonEmpty { private ModIcon foregroundIcon { get; set; } private readonly SpriteText text; @@ -51,7 +55,7 @@ namespace osu.Game.Overlays.Mods iconsContainer.RotateTo(Selected ? 5f : 0f, 300, EasingTypes.OutElastic); iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, EasingTypes.OutElastic); - foregroundIcon.Colour = Selected ? SelectedColour : ButtonColour; + foregroundIcon.Highlighted = Selected; if (mod != null) displayMod(SelectedMod ?? Mods[0]); @@ -60,23 +64,6 @@ namespace osu.Game.Overlays.Mods public bool Selected => selectedIndex != -1; - private Color4 buttonColour; - public Color4 ButtonColour - { - get - { - return buttonColour; - } - set - { - if (value == buttonColour) return; - buttonColour = value; - foreach (ModIcon icon in iconsContainer.Children) - { - icon.Colour = value; - } - } - } private Color4 selectedColour; public Color4 SelectedColour @@ -127,7 +114,7 @@ namespace osu.Game.Overlays.Mods // the mods from Mod, only multiple if Mod is a MultiMod - public Mod SelectedMod => Mods.ElementAtOrDefault(selectedIndex); + public override Mod SelectedMod => Mods.ElementAtOrDefault(selectedIndex); [BackgroundDependencyLoader] private void load(AudioManager audio) @@ -180,50 +167,35 @@ namespace osu.Game.Overlays.Mods { iconsContainer.Add(new[] { - new ModIcon + new ModIcon(Mods[0]) { Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, Position = new Vector2(1.5f), - Colour = ButtonColour }, - foregroundIcon = new ModIcon + foregroundIcon = new ModIcon(Mods[0]) { Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, Position = new Vector2(-1.5f), - Colour = ButtonColour }, }); } else { - iconsContainer.Add(foregroundIcon = new ModIcon + iconsContainer.Add(foregroundIcon = new ModIcon(Mod) { Origin = Anchor.Centre, Anchor = Anchor.Centre, AutoSizeAxes = Axes.Both, - Colour = ButtonColour }); } } - protected override void LoadComplete() + public ModButton(Mod mod) { - base.LoadComplete(); - foreach (ModIcon icon in iconsContainer.Children) - icon.Colour = ButtonColour; - } - - public ModButton(Mod m) - { - Direction = FillDirection.Vertical; - Spacing = new Vector2(0f, -5f); - Size = new Vector2(100f); - AlwaysPresent = true; - Children = new Drawable[] { new Container @@ -243,13 +215,14 @@ namespace osu.Game.Overlays.Mods }, text = new OsuSpriteText { + Y = 75, Origin = Anchor.TopCentre, Anchor = Anchor.TopCentre, TextSize = 18, }, }; - Mod = m; + Mod = mod; } } } diff --git a/osu.Game/Overlays/Mods/ModButtonEmpty.cs b/osu.Game/Overlays/Mods/ModButtonEmpty.cs new file mode 100644 index 0000000000..638c2a0e47 --- /dev/null +++ b/osu.Game/Overlays/Mods/ModButtonEmpty.cs @@ -0,0 +1,23 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK; +using osu.Framework.Graphics.Containers; +using osu.Game.Rulesets.Mods; + +namespace osu.Game.Overlays.Mods +{ + /// + /// A mod button used exclusively for providing an empty space the size of a mod button. + /// + public class ModButtonEmpty : Container + { + public virtual Mod SelectedMod => null; + + public ModButtonEmpty() + { + Size = new Vector2(100f); + AlwaysPresent = true; + } + } +} diff --git a/osu.Game/Overlays/Mods/ModSection.cs b/osu.Game/Overlays/Mods/ModSection.cs index c2af12f49e..40bd1e8b07 100644 --- a/osu.Game/Overlays/Mods/ModSection.cs +++ b/osu.Game/Overlays/Mods/ModSection.cs @@ -11,6 +11,8 @@ using osu.Framework.Input; using osu.Game.Graphics.Sprites; using osu.Game.Rulesets.Mods; using System; +using System.Linq; +using System.Collections.Generic; namespace osu.Game.Overlays.Mods { @@ -18,7 +20,7 @@ namespace osu.Game.Overlays.Mods { private readonly OsuSpriteText headerLabel; - public FillFlowContainer ButtonsContainer { get; } + public FillFlowContainer ButtonsContainer { get; } public Action Action; protected abstract Key[] ToggleKeys { get; } @@ -36,47 +38,30 @@ namespace osu.Game.Overlays.Mods } } + public IEnumerable SelectedMods => buttons.Select(b => b.SelectedMod).Where(m => m != null); + + public IEnumerable Mods + { + set + { + var modContainers = value.Select(m => + { + if (m == null) + return new ModButtonEmpty(); + else + return new ModButton(m) + { + SelectedColour = selectedColour, + Action = Action, + }; + }).ToArray(); + + ButtonsContainer.Children = modContainers; + buttons = modContainers.OfType().ToArray(); + } + } + private ModButton[] buttons = { }; - public ModButton[] Buttons - { - get - { - return buttons; - } - set - { - if (value == buttons) return; - buttons = value; - - foreach (ModButton button in value) - { - button.ButtonColour = ButtonColour; - button.SelectedColour = selectedColour; - button.Action = Action; - } - - ButtonsContainer.Children = value; - } - } - - private Color4 buttonsBolour = Color4.White; - public Color4 ButtonColour - { - get - { - return buttonsBolour; - } - set - { - if (value == buttonsBolour) return; - buttonsBolour = value; - - foreach (ModButton button in buttons) - { - button.ButtonColour = value; - } - } - } private Color4 selectedColour = Color4.White; public Color4 SelectedColour @@ -91,17 +76,15 @@ namespace osu.Game.Overlays.Mods selectedColour = value; foreach (ModButton button in buttons) - { button.SelectedColour = value; - } } } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) { var index = Array.IndexOf(ToggleKeys, args.Key); - if (index > -1 && index < Buttons.Length) - Buttons[index].SelectNext(); + if (index > -1 && index < buttons.Length) + buttons[index].SelectNext(); return base.OnKeyDown(state, args); } @@ -109,8 +92,18 @@ namespace osu.Game.Overlays.Mods public void DeselectAll() { foreach (ModButton button in buttons) - { button.Deselect(); + } + + public void DeselectTypes(Type[] modTypes) + { + foreach (var button in buttons) + { + Mod selected = button.SelectedMod; + if (selected == null) continue; + foreach (Type type in modTypes) + if (type.IsInstanceOfType(selected)) + button.Deselect(); } } @@ -127,7 +120,7 @@ namespace osu.Game.Overlays.Mods Position = new Vector2(0f, 0f), Font = @"Exo2.0-Bold" }, - ButtonsContainer = new FillFlowContainer + ButtonsContainer = new FillFlowContainer { AutoSizeAxes = Axes.Both, Origin = Anchor.BottomLeft, diff --git a/osu.Game/Overlays/Mods/ModSelectOverlay.cs b/osu.Game/Overlays/Mods/ModSelectOverlay.cs index dadfb808f7..2840ffd1e4 100644 --- a/osu.Game/Overlays/Mods/ModSelectOverlay.cs +++ b/osu.Game/Overlays/Mods/ModSelectOverlay.cs @@ -44,7 +44,7 @@ namespace osu.Game.Overlays.Mods var instance = newRuleset.CreateInstance(); foreach (ModSection section in modSectionsContainer.Children) - section.Buttons = instance.GetModsFor(section.ModType).Select(m => new ModButton(m)).ToArray(); + section.Mods = instance.GetModsFor(section.ModType); refreshSelectedMods(); } @@ -103,14 +103,7 @@ namespace osu.Game.Overlays.Mods { if (modTypes.Length == 0) return; foreach (ModSection section in modSectionsContainer.Children) - foreach (ModButton button in section.Buttons) - { - Mod selected = button.SelectedMod; - if (selected == null) continue; - foreach (Type type in modTypes) - if (type.IsInstanceOfType(selected)) - button.Deselect(); - } + section.DeselectTypes(modTypes); } private void modButtonPressed(Mod selectedMod) @@ -122,7 +115,7 @@ namespace osu.Game.Overlays.Mods private void refreshSelectedMods() { - SelectedMods.Value = modSectionsContainer.Children.SelectMany(s => s.Buttons.Select(x => x.SelectedMod).Where(x => x != null)).ToArray(); + SelectedMods.Value = modSectionsContainer.Children.SelectMany(s => s.SelectedMods).ToArray(); double multiplier = 1.0; bool ranked = true; diff --git a/osu.Game/Overlays/Options/OptionCheckbox.cs b/osu.Game/Overlays/Options/OptionCheckbox.cs new file mode 100644 index 0000000000..de7b138c3c --- /dev/null +++ b/osu.Game/Overlays/Options/OptionCheckbox.cs @@ -0,0 +1,21 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using osu.Framework.Graphics; +using osu.Game.Graphics.UserInterface; + +namespace osu.Game.Overlays.Options +{ + public class OptionCheckbox : OptionItem + { + private OsuCheckbox checkbox; + + protected override Drawable CreateControl() => checkbox = new OsuCheckbox(); + + public override string LabelText + { + get { return checkbox.LabelText; } + set { checkbox.LabelText = value; } + } + } +} diff --git a/osu.Game/Overlays/Options/OptionDropdown.cs b/osu.Game/Overlays/Options/OptionDropdown.cs index 6837e71c2c..1427eafe39 100644 --- a/osu.Game/Overlays/Options/OptionDropdown.cs +++ b/osu.Game/Overlays/Options/OptionDropdown.cs @@ -2,45 +2,18 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using System.Collections.Generic; -using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options { - public class OptionDropdown : FillFlowContainer + public class OptionDropdown : OptionItem { - private readonly Dropdown dropdown; - private readonly SpriteText text; + private Dropdown dropdown; - public string LabelText - { - get { return text.Text; } - set - { - text.Text = value; - text.Alpha = !string.IsNullOrEmpty(value) ? 1 : 0; - } - } - - public Bindable Bindable - { - get { return bindable; } - set - { - bindable = value; - dropdown.Current.BindTo(bindable); - } - } - - private Bindable bindable; - - private IEnumerable> items; + private IEnumerable> items = new KeyValuePair[] { }; public IEnumerable> Items { get @@ -55,30 +28,11 @@ namespace osu.Game.Overlays.Options } } - public OptionDropdown() + protected override Drawable CreateControl() => dropdown = new OsuDropdown { - Items = new KeyValuePair[0]; - - Direction = FillDirection.Vertical; - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Children = new Drawable[] - { - text = new OsuSpriteText { - Alpha = 0, - }, - dropdown = new OsuDropdown - { - Margin = new MarginPadding { Top = 5 }, - RelativeSizeAxes = Axes.X, - Items = Items, - } - }; - - dropdown.Current.DisabledChanged += disabled => - { - Alpha = disabled ? 0.3f : 1; - }; - } + Margin = new MarginPadding { Top = 5 }, + RelativeSizeAxes = Axes.X, + Items = Items, + }; } } diff --git a/osu.Game/Overlays/Options/OptionItem.cs b/osu.Game/Overlays/Options/OptionItem.cs new file mode 100644 index 0000000000..2124796089 --- /dev/null +++ b/osu.Game/Overlays/Options/OptionItem.cs @@ -0,0 +1,82 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using OpenTK.Graphics; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.Sprites; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.Sprites; + +namespace osu.Game.Overlays.Options +{ + public abstract class OptionItem : FillFlowContainer, IFilterable + { + protected abstract Drawable CreateControl(); + + protected Drawable Control { get; } + + private IHasCurrentValue controlWithCurrent => Control as IHasCurrentValue; + + private SpriteText text; + + public virtual string LabelText + { + get { return text?.Text ?? string.Empty; } + set + { + if (text == null) + { + // construct lazily for cases where the label is not needed (may be provided by the Control). + Add(text = new OsuSpriteText() { Depth = 1 }); + } + + text.Text = value; + } + } + + // hold a reference to the provided bindable so we don't have to in every options section. + private Bindable bindable; + + public Bindable Bindable + { + get + { + return bindable; + } + + set + { + bindable = value; + controlWithCurrent?.Current.BindTo(bindable); + } + } + + public string[] FilterTerms => new[] { LabelText }; + + public bool MatchingCurrentFilter + { + set + { + // probably needs a better transition. + FadeTo(value ? 1 : 0); + } + } + + protected OptionItem() + { + RelativeSizeAxes = Axes.X; + AutoSizeAxes = Axes.Y; + Padding = new MarginPadding { Right = 5 }; + + if ((Control = CreateControl()) != null) + { + if (controlWithCurrent != null) + controlWithCurrent.Current.DisabledChanged += disabled => { Colour = disabled ? Color4.Gray : Color4.White; }; + Add(Control); + } + } + } +} diff --git a/osu.Game/Overlays/Options/OptionLabel.cs b/osu.Game/Overlays/Options/OptionLabel.cs index 4b0f1e4ec0..3f3c569f3a 100644 --- a/osu.Game/Overlays/Options/OptionLabel.cs +++ b/osu.Game/Overlays/Options/OptionLabel.cs @@ -2,13 +2,15 @@ // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE using osu.Framework.Allocation; +using osu.Framework.Graphics; using osu.Game.Graphics; -using osu.Game.Graphics.Sprites; namespace osu.Game.Overlays.Options { - internal class OptionLabel : OsuSpriteText + internal class OptionLabel : OptionItem { + protected override Drawable CreateControl() => null; + [BackgroundDependencyLoader] private void load(OsuColour colour) { diff --git a/osu.Game/Overlays/Options/OptionSlider.cs b/osu.Game/Overlays/Options/OptionSlider.cs index 2d98bc991a..2cceb085a7 100644 --- a/osu.Game/Overlays/Options/OptionSlider.cs +++ b/osu.Game/Overlays/Options/OptionSlider.cs @@ -1,13 +1,9 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Framework.Graphics.Containers; using osu.Framework.Graphics.Primitives; -using osu.Framework.Graphics.Sprites; using osu.Framework.Graphics.UserInterface; -using osu.Game.Graphics.Sprites; using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options @@ -17,52 +13,14 @@ namespace osu.Game.Overlays.Options { } - public class OptionSlider : FillFlowContainer + public class OptionSlider : OptionItem where T : struct where U : SliderBar, new() { - private readonly SliderBar slider; - private readonly SpriteText text; - - public string LabelText + protected override Drawable CreateControl() => new U() { - get { return text.Text; } - set - { - text.Text = value; - text.Alpha = string.IsNullOrEmpty(value) ? 0 : 1; - } - } - - private Bindable bindable; - - public Bindable Bindable - { - set - { - bindable = value; - slider.Current.BindTo(bindable); - } - } - - public OptionSlider() - { - RelativeSizeAxes = Axes.X; - AutoSizeAxes = Axes.Y; - Padding = new MarginPadding { Right = 5 }; - - Children = new Drawable[] - { - text = new OsuSpriteText - { - Alpha = 0, - }, - slider = new U() - { - Margin = new MarginPadding { Top = 5, Bottom = 5 }, - RelativeSizeAxes = Axes.X - } - }; - } + Margin = new MarginPadding { Top = 5, Bottom = 5 }, + RelativeSizeAxes = Axes.X + }; } } diff --git a/osu.Game/Overlays/Options/OptionTextBox.cs b/osu.Game/Overlays/Options/OptionTextBox.cs index 4927122181..498f27796a 100644 --- a/osu.Game/Overlays/Options/OptionTextBox.cs +++ b/osu.Game/Overlays/Options/OptionTextBox.cs @@ -1,22 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using osu.Framework.Configuration; +using osu.Framework.Graphics; using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options { - public class OptionTextBox : OsuTextBox + public class OptionTextBox : OptionItem { - private Bindable bindable; - - public Bindable Bindable - { - set - { - bindable = value; - Current.BindTo(bindable); - } - } + protected override Drawable CreateControl() => new OsuTextBox(); } } diff --git a/osu.Game/Overlays/Options/Sections/Audio/MainMenuOptions.cs b/osu.Game/Overlays/Options/Sections/Audio/MainMenuOptions.cs index 9de74e1b02..b2d1235b97 100644 --- a/osu.Game/Overlays/Options/Sections/Audio/MainMenuOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Audio/MainMenuOptions.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.Audio { @@ -16,12 +15,12 @@ namespace osu.Game.Overlays.Options.Sections.Audio { Children = new[] { - new OsuCheckbox + new OptionCheckbox { LabelText = "Interface voices", Bindable = config.GetBindable(OsuConfig.MenuVoice) }, - new OsuCheckbox + new OptionCheckbox { LabelText = "osu! music theme", Bindable = config.GetBindable(OsuConfig.MenuMusic) @@ -29,4 +28,4 @@ namespace osu.Game.Overlays.Options.Sections.Audio }; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Options/Sections/Debug/GeneralOptions.cs b/osu.Game/Overlays/Options/Sections/Debug/GeneralOptions.cs index 34901e1dac..9258b8fbeb 100644 --- a/osu.Game/Overlays/Options/Sections/Debug/GeneralOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Debug/GeneralOptions.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.Debug { @@ -17,7 +16,7 @@ namespace osu.Game.Overlays.Options.Sections.Debug { Children = new Drawable[] { - new OsuCheckbox + new OptionCheckbox { LabelText = "Bypass caching", Bindable = config.GetBindable(FrameworkDebugConfig.BypassCaching) diff --git a/osu.Game/Overlays/Options/Sections/Gameplay/GeneralOptions.cs b/osu.Game/Overlays/Options/Sections/Gameplay/GeneralOptions.cs index c278b59a51..2598d95949 100644 --- a/osu.Game/Overlays/Options/Sections/Gameplay/GeneralOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Gameplay/GeneralOptions.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.Gameplay { @@ -22,12 +21,12 @@ namespace osu.Game.Overlays.Options.Sections.Gameplay LabelText = "Background dim", Bindable = config.GetBindable(OsuConfig.DimLevel) }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Show score overlay", Bindable = config.GetBindable(OsuConfig.ShowInterface) }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Always show key overlay", Bindable = config.GetBindable(OsuConfig.KeyOverlay) diff --git a/osu.Game/Overlays/Options/Sections/General/LanguageOptions.cs b/osu.Game/Overlays/Options/Sections/General/LanguageOptions.cs index 7bc1a54455..2778f2567d 100644 --- a/osu.Game/Overlays/Options/Sections/General/LanguageOptions.cs +++ b/osu.Game/Overlays/Options/Sections/General/LanguageOptions.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.General { @@ -17,7 +16,7 @@ namespace osu.Game.Overlays.Options.Sections.General { Children = new Drawable[] { - new OsuCheckbox + new OptionCheckbox { LabelText = "Prefer metadata in original language", Bindable = frameworkConfig.GetBindable(FrameworkConfig.ShowUnicode) diff --git a/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs b/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs index a5e38dd284..a3612a6396 100644 --- a/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs +++ b/osu.Game/Overlays/Options/Sections/General/LoginOptions.cs @@ -132,12 +132,12 @@ namespace osu.Game.Overlays.Options.Sections.General TabbableContentContainer = this, OnCommit = (sender, newText) => performLogin() }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Remember username", Bindable = config.GetBindable(OsuConfig.SaveUsername), }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Stay logged in", Bindable = config.GetBindable(OsuConfig.SavePassword), diff --git a/osu.Game/Overlays/Options/Sections/Graphics/DetailOptions.cs b/osu.Game/Overlays/Options/Sections/Graphics/DetailOptions.cs index d8906d74ba..6503a7ea90 100644 --- a/osu.Game/Overlays/Options/Sections/Graphics/DetailOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Graphics/DetailOptions.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.Graphics { @@ -17,12 +16,12 @@ namespace osu.Game.Overlays.Options.Sections.Graphics { Children = new Drawable[] { - new OsuCheckbox + new OptionCheckbox { LabelText = "Snaking in sliders", Bindable = config.GetBindable(OsuConfig.SnakingInSliders) }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Snaking out sliders", Bindable = config.GetBindable(OsuConfig.SnakingOutSliders) @@ -30,4 +29,4 @@ namespace osu.Game.Overlays.Options.Sections.Graphics }; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs b/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs index aed39ca764..1b4b0b3c7d 100644 --- a/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Graphics/LayoutOptions.cs @@ -4,7 +4,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.Graphics { @@ -29,7 +28,7 @@ namespace osu.Game.Overlays.Options.Sections.Graphics LabelText = "Screen mode", Bindable = config.GetBindable(FrameworkConfig.WindowMode), }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Letterboxing", Bindable = letterboxing, @@ -64,4 +63,4 @@ namespace osu.Game.Overlays.Options.Sections.Graphics } } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Options/Sections/Graphics/MainMenuOptions.cs b/osu.Game/Overlays/Options/Sections/Graphics/MainMenuOptions.cs index 83a2a382ad..6ebb8f263d 100644 --- a/osu.Game/Overlays/Options/Sections/Graphics/MainMenuOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Graphics/MainMenuOptions.cs @@ -3,7 +3,6 @@ using osu.Framework.Allocation; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.Graphics { @@ -16,7 +15,7 @@ namespace osu.Game.Overlays.Options.Sections.Graphics { Children = new[] { - new OsuCheckbox + new OptionCheckbox { LabelText = "Parallax", Bindable = config.GetBindable(OsuConfig.MenuParallax) @@ -24,4 +23,4 @@ namespace osu.Game.Overlays.Options.Sections.Graphics }; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Options/Sections/Graphics/RendererOptions.cs b/osu.Game/Overlays/Options/Sections/Graphics/RendererOptions.cs index 58bf2b7996..f11c18d3b4 100644 --- a/osu.Game/Overlays/Options/Sections/Graphics/RendererOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Graphics/RendererOptions.cs @@ -5,7 +5,6 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Game.Configuration; -using osu.Game.Graphics.UserInterface; namespace osu.Game.Overlays.Options.Sections.Graphics { @@ -25,7 +24,7 @@ namespace osu.Game.Overlays.Options.Sections.Graphics LabelText = "Frame limiter", Bindable = config.GetBindable(FrameworkConfig.FrameSync) }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Show FPS", Bindable = osuConfig.GetBindable(OsuConfig.ShowFpsDisplay) @@ -33,4 +32,4 @@ namespace osu.Game.Overlays.Options.Sections.Graphics }; } } -} \ No newline at end of file +} diff --git a/osu.Game/Overlays/Options/Sections/Input/MouseOptions.cs b/osu.Game/Overlays/Options/Sections/Input/MouseOptions.cs index 12789aa0ec..b4ce11e2bc 100644 --- a/osu.Game/Overlays/Options/Sections/Input/MouseOptions.cs +++ b/osu.Game/Overlays/Options/Sections/Input/MouseOptions.cs @@ -24,12 +24,12 @@ namespace osu.Game.Overlays.Options.Sections.Input LabelText = "Confine mouse cursor", Bindable = config.GetBindable(FrameworkConfig.ConfineMouseMode), }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Disable mouse wheel during gameplay", Bindable = osuConfig.GetBindable(OsuConfig.MouseDisableWheel) }, - new OsuCheckbox + new OptionCheckbox { LabelText = "Disable mouse buttons during gameplay", Bindable = osuConfig.GetBindable(OsuConfig.MouseDisableButtons) diff --git a/osu.Game/Rulesets/Mods/Mod.cs b/osu.Game/Rulesets/Mods/Mod.cs index a2846c1d2f..c00847b7d8 100644 --- a/osu.Game/Rulesets/Mods/Mod.cs +++ b/osu.Game/Rulesets/Mods/Mod.cs @@ -21,6 +21,11 @@ namespace osu.Game.Rulesets.Mods /// public virtual FontAwesome Icon => FontAwesome.fa_question; + /// + /// The type of this mod. + /// + public virtual ModType Type => ModType.Special; + /// /// The user readable description of this mod. /// diff --git a/osu.Game/Rulesets/Mods/ModDoubleTime.cs b/osu.Game/Rulesets/Mods/ModDoubleTime.cs index 377a4c2180..1aab56a9fc 100644 --- a/osu.Game/Rulesets/Mods/ModDoubleTime.cs +++ b/osu.Game/Rulesets/Mods/ModDoubleTime.cs @@ -11,6 +11,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Double Time"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_doubletime; + public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Zoooooooooom"; public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModHalfTime) }; diff --git a/osu.Game/Rulesets/Mods/ModEasy.cs b/osu.Game/Rulesets/Mods/ModEasy.cs index bef3f04af3..8eef9c70d6 100644 --- a/osu.Game/Rulesets/Mods/ModEasy.cs +++ b/osu.Game/Rulesets/Mods/ModEasy.cs @@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Easy"; 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."; public override double ScoreMultiplier => 0.5; public override bool Ranked => true; diff --git a/osu.Game/Rulesets/Mods/ModFlashlight.cs b/osu.Game/Rulesets/Mods/ModFlashlight.cs index 63c534dc7d..b5ad859172 100644 --- a/osu.Game/Rulesets/Mods/ModFlashlight.cs +++ b/osu.Game/Rulesets/Mods/ModFlashlight.cs @@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Flashlight"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_flashlight; + public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Restricted view area."; public override bool Ranked => true; } diff --git a/osu.Game/Rulesets/Mods/ModHalfTime.cs b/osu.Game/Rulesets/Mods/ModHalfTime.cs index 235fc7ad76..207a6ec2a1 100644 --- a/osu.Game/Rulesets/Mods/ModHalfTime.cs +++ b/osu.Game/Rulesets/Mods/ModHalfTime.cs @@ -11,6 +11,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Half Time"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_halftime; + public override ModType Type => ModType.DifficultyReduction; public override string Description => "Less zoom"; public override bool Ranked => true; public override Type[] IncompatibleMods => new[] { typeof(ModDoubleTime) }; diff --git a/osu.Game/Rulesets/Mods/ModHardRock.cs b/osu.Game/Rulesets/Mods/ModHardRock.cs index b729b5ae15..2516c02526 100644 --- a/osu.Game/Rulesets/Mods/ModHardRock.cs +++ b/osu.Game/Rulesets/Mods/ModHardRock.cs @@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Hard Rock"; 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..."; public override Type[] IncompatibleMods => new[] { typeof(ModEasy) }; } diff --git a/osu.Game/Rulesets/Mods/ModHidden.cs b/osu.Game/Rulesets/Mods/ModHidden.cs index 12c788ce54..89b9b3b62d 100644 --- a/osu.Game/Rulesets/Mods/ModHidden.cs +++ b/osu.Game/Rulesets/Mods/ModHidden.cs @@ -9,6 +9,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Hidden"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_hidden; + public override ModType Type => ModType.DifficultyIncrease; public override bool Ranked => true; } } \ No newline at end of file diff --git a/osu.Game/Rulesets/Mods/ModNoFail.cs b/osu.Game/Rulesets/Mods/ModNoFail.cs index 0c8726bbc1..613e1e1d4d 100644 --- a/osu.Game/Rulesets/Mods/ModNoFail.cs +++ b/osu.Game/Rulesets/Mods/ModNoFail.cs @@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "NoFail"; 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."; public override double ScoreMultiplier => 0.5; public override bool Ranked => true; diff --git a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs index a7dcbbc9ed..2bf0278046 100644 --- a/osu.Game/Rulesets/Mods/ModSuddenDeath.cs +++ b/osu.Game/Rulesets/Mods/ModSuddenDeath.cs @@ -10,6 +10,7 @@ namespace osu.Game.Rulesets.Mods { public override string Name => "Sudden Death"; public override FontAwesome Icon => FontAwesome.fa_osu_mod_suddendeath; + public override ModType Type => ModType.DifficultyIncrease; public override string Description => "Miss a note and fail."; public override double ScoreMultiplier => 1; public override bool Ranked => true; diff --git a/osu.Game/Rulesets/UI/HitRenderer.cs b/osu.Game/Rulesets/UI/HitRenderer.cs index 25d8bae205..69e0e73664 100644 --- a/osu.Game/Rulesets/UI/HitRenderer.cs +++ b/osu.Game/Rulesets/UI/HitRenderer.cs @@ -202,8 +202,6 @@ namespace osu.Game.Rulesets.UI protected HitRenderer(WorkingBeatmap beatmap) : base(beatmap) { - KeyConversionInputManager.Add(Playfield = CreatePlayfield()); - InputManager.Add(content = new Container { RelativeSizeAxes = Axes.Both, @@ -216,6 +214,8 @@ namespace osu.Game.Rulesets.UI [BackgroundDependencyLoader] private void load() { + KeyConversionInputManager.Add(Playfield = CreatePlayfield()); + loadObjects(); if (InputManager?.ReplayInputHandler != null) diff --git a/osu.Game/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index 8301796c1f..b23028098f 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -1,10 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using OpenTK.Graphics; +using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; using osu.Game.Graphics; +using osu.Game.Rulesets.Mods; namespace osu.Game.Rulesets.UI { @@ -13,72 +16,88 @@ namespace osu.Game.Rulesets.UI private readonly TextAwesome modIcon; private readonly TextAwesome background; - private float iconSize = 80; - public float IconSize - { - get - { - return iconSize; - } - set - { - iconSize = value; - reapplySize(); - } - } - - public new Color4 Colour - { - get - { - return background.Colour; - } - set - { - background.Colour = value; - } - } + private const float icon_size = 80; public FontAwesome Icon { - get - { - return modIcon.Icon; - } - set - { - modIcon.Icon = value; - } + get { return modIcon.Icon; } + set { modIcon.Icon = value; } } - private void reapplySize() - { - background.TextSize = iconSize; - modIcon.TextSize = iconSize - 35; - } + private readonly ModType type; - public ModIcon() + public ModIcon(Mod mod) { + if (mod == null) throw new ArgumentNullException(nameof(mod)); + + type = mod.Type; + Children = new Drawable[] { background = new TextAwesome { Origin = Anchor.Centre, Anchor = Anchor.Centre, + TextSize = icon_size, Icon = FontAwesome.fa_osu_mod_bg, Shadow = true, - TextSize = 20 }, modIcon = new TextAwesome { Origin = Anchor.Centre, Anchor = Anchor.Centre, Colour = OsuColour.Gray(84), - TextSize = 20 + TextSize = icon_size - 35, + Icon = mod.Icon }, }; + } - reapplySize(); + private Color4 backgroundColour; + private Color4 highlightedColour; + + [BackgroundDependencyLoader] + private void load(OsuColour colours) + { + switch (type) + { + default: + case ModType.DifficultyIncrease: + backgroundColour = colours.Yellow; + highlightedColour = colours.YellowLight; + break; + case ModType.DifficultyReduction: + backgroundColour = colours.Green; + highlightedColour = colours.GreenLight; + break; + case ModType.Special: + backgroundColour = colours.Blue; + highlightedColour = colours.BlueLight; + break; + } + + applyStyle(); + } + + private bool highlighted; + + public bool Highlighted + { + get + { + return highlighted; + } + + set + { + highlighted = value; + applyStyle(); + } + } + + private void applyStyle() + { + background.Colour = highlighted ? highlightedColour : backgroundColour; } } -} \ No newline at end of file +} diff --git a/osu.Game/Rulesets/UI/ComboCounter.cs b/osu.Game/Screens/Play/HUD/ComboCounter.cs similarity index 96% rename from osu.Game/Rulesets/UI/ComboCounter.cs rename to osu.Game/Screens/Play/HUD/ComboCounter.cs index d21059cbdb..a130bc2eab 100644 --- a/osu.Game/Rulesets/UI/ComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/ComboCounter.cs @@ -10,7 +10,7 @@ using osu.Framework.Graphics.Transforms; using osu.Framework.MathUtils; using osu.Game.Graphics.Sprites; -namespace osu.Game.Rulesets.UI +namespace osu.Game.Screens.Play.HUD { public abstract class ComboCounter : Container { diff --git a/osu.Game/Rulesets/UI/ComboResultCounter.cs b/osu.Game/Screens/Play/HUD/ComboResultCounter.cs similarity index 95% rename from osu.Game/Rulesets/UI/ComboResultCounter.cs rename to osu.Game/Screens/Play/HUD/ComboResultCounter.cs index 4b19b2c1ff..a1a166f944 100644 --- a/osu.Game/Rulesets/UI/ComboResultCounter.cs +++ b/osu.Game/Screens/Play/HUD/ComboResultCounter.cs @@ -1,13 +1,13 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE +using System; using osu.Framework.Graphics; using osu.Framework.Graphics.Transforms; using osu.Framework.MathUtils; using osu.Game.Graphics.UserInterface; -using System; -namespace osu.Game.Rulesets.UI +namespace osu.Game.Screens.Play.HUD { /// /// Used to display combo with a roll-up animation in results screen. diff --git a/osu.Game/Rulesets/UI/HealthDisplay.cs b/osu.Game/Screens/Play/HUD/HealthDisplay.cs similarity index 91% rename from osu.Game/Rulesets/UI/HealthDisplay.cs rename to osu.Game/Screens/Play/HUD/HealthDisplay.cs index 5c6b9d2fe3..a146172085 100644 --- a/osu.Game/Rulesets/UI/HealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/HealthDisplay.cs @@ -4,7 +4,7 @@ using osu.Framework.Configuration; using osu.Framework.Graphics.Containers; -namespace osu.Game.Rulesets.UI +namespace osu.Game.Screens.Play.HUD { public abstract class HealthDisplay : Container { diff --git a/osu.Game/Screens/Play/HUD/ModDisplay.cs b/osu.Game/Screens/Play/HUD/ModDisplay.cs new file mode 100644 index 0000000000..1b67d8dc66 --- /dev/null +++ b/osu.Game/Screens/Play/HUD/ModDisplay.cs @@ -0,0 +1,105 @@ +// Copyright (c) 2007-2017 ppy Pty Ltd . +// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE + +using System.Collections.Generic; +using System.Linq; +using osu.Framework.Configuration; +using osu.Framework.Graphics; +using osu.Framework.Graphics.Containers; +using osu.Framework.Graphics.Primitives; +using osu.Framework.Graphics.UserInterface; +using osu.Game.Graphics.Sprites; +using osu.Game.Rulesets.Mods; +using osu.Game.Rulesets.UI; +using OpenTK; +using osu.Framework.Input; + +namespace osu.Game.Screens.Play.HUD +{ + public class ModDisplay : Container, IHasCurrentValue> + { + private readonly Bindable> mods = new Bindable>(); + + public Bindable> Current => mods; + + private readonly FillFlowContainer iconsContainer; + + public ModDisplay() + { + Children = new Drawable[] + { + iconsContainer = new IconFlow + { + Anchor = Anchor.TopCentre, + Origin = Anchor.TopCentre, + AutoSizeAxes = Axes.Both, + Direction = FillDirection.Horizontal, + Margin = new MarginPadding { Left = 10, Right = 10 }, + }, + new OsuSpriteText + { + Anchor = Anchor.BottomCentre, + Origin = Anchor.TopCentre, + Text = @"/ UNRANKED /", + Font = @"Venera", + TextSize = 12, + } + }; + + mods.ValueChanged += mods => + { + iconsContainer.Clear(); + foreach (Mod mod in mods) + { + iconsContainer.Add(new ModIcon(mod) + { + AutoSizeAxes = Axes.Both, + Scale = new Vector2(0.6f), + + }); + } + + if (IsLoaded) + appearTransform(); + }; + } + + protected override void LoadComplete() + { + base.LoadComplete(); + appearTransform(); + } + + private void appearTransform() + { + iconsContainer.Flush(); + iconsContainer.FadeInFromZero(1000, EasingTypes.OutQuint); + expand(); + using (iconsContainer.BeginDelayedSequence(1200)) + contract(); + } + + private void expand() => iconsContainer.TransformSpacingTo(new Vector2(5, 0), 500, EasingTypes.OutQuint); + + private void contract() => iconsContainer.TransformSpacingTo(new Vector2(-25, 0), 500, EasingTypes.OutQuint); + + protected override bool OnHover(InputState state) + { + expand(); + return base.OnHover(state); + } + + protected override void OnHoverLost(InputState state) + { + contract(); + base.OnHoverLost(state); + } + + private class IconFlow : FillFlowContainer + { + // just reverses the depth of flow contents. + protected override IComparer DepthComparer => new ReverseCreationOrderDepthComparer(); + protected override IEnumerable FlowingChildren => base.FlowingChildren.Reverse(); + } + } +} diff --git a/osu.Game/Rulesets/UI/StandardComboCounter.cs b/osu.Game/Screens/Play/HUD/StandardComboCounter.cs similarity index 96% rename from osu.Game/Rulesets/UI/StandardComboCounter.cs rename to osu.Game/Screens/Play/HUD/StandardComboCounter.cs index ad05c83839..525e52d207 100644 --- a/osu.Game/Rulesets/UI/StandardComboCounter.cs +++ b/osu.Game/Screens/Play/HUD/StandardComboCounter.cs @@ -3,7 +3,7 @@ using OpenTK; -namespace osu.Game.Rulesets.UI +namespace osu.Game.Screens.Play.HUD { /// /// Uses the 'x' symbol and has a pop-out effect while rolling over. diff --git a/osu.Game/Rulesets/UI/StandardHealthDisplay.cs b/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs similarity index 96% rename from osu.Game/Rulesets/UI/StandardHealthDisplay.cs rename to osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs index 3d9a5489dc..7ba5dfe1b7 100644 --- a/osu.Game/Rulesets/UI/StandardHealthDisplay.cs +++ b/osu.Game/Screens/Play/HUD/StandardHealthDisplay.cs @@ -1,8 +1,7 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; -using OpenTK.Graphics; +using System; using osu.Framework.Extensions.Color4Extensions; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; @@ -10,9 +9,10 @@ using osu.Framework.Graphics.Sprites; using osu.Game.Graphics; using osu.Game.Rulesets.Judgements; using osu.Game.Rulesets.Objects.Drawables; -using System; +using OpenTK; +using OpenTK.Graphics; -namespace osu.Game.Rulesets.UI +namespace osu.Game.Screens.Play.HUD { public class StandardHealthDisplay : HealthDisplay, IHasAccentColour { diff --git a/osu.Game/Rulesets/UI/HudOverlay.cs b/osu.Game/Screens/Play/HUDOverlay.cs similarity index 85% rename from osu.Game/Rulesets/UI/HudOverlay.cs rename to osu.Game/Screens/Play/HUDOverlay.cs index 47cf157732..12e2cb197e 100644 --- a/osu.Game/Rulesets/UI/HudOverlay.cs +++ b/osu.Game/Screens/Play/HUDOverlay.cs @@ -5,18 +5,19 @@ using osu.Framework.Allocation; using osu.Framework.Configuration; using osu.Framework.Graphics; using osu.Framework.Graphics.Containers; +using osu.Framework.Input; using osu.Game.Configuration; using osu.Game.Graphics.UserInterface; -using osu.Game.Screens.Play; -using osu.Game.Rulesets.Scoring; -using osu.Framework.Input; -using OpenTK.Input; using osu.Game.Overlays; using osu.Game.Overlays.Notifications; +using osu.Game.Rulesets.Scoring; +using osu.Game.Rulesets.UI; +using osu.Game.Screens.Play.HUD; +using OpenTK.Input; -namespace osu.Game.Rulesets.UI +namespace osu.Game.Screens.Play { - public abstract class HudOverlay : Container + public abstract class HUDOverlay : Container { private const int duration = 100; @@ -27,6 +28,7 @@ namespace osu.Game.Rulesets.UI public readonly RollingCounter AccuracyCounter; public readonly HealthDisplay HealthDisplay; public readonly SongProgress Progress; + public readonly ModDisplay ModDisplay; private Bindable showKeyCounter; private Bindable showHud; @@ -39,8 +41,9 @@ namespace osu.Game.Rulesets.UI protected abstract ScoreCounter CreateScoreCounter(); protected abstract HealthDisplay CreateHealthDisplay(); protected abstract SongProgress CreateProgress(); + protected abstract ModDisplay CreateModsContainer(); - protected HudOverlay() + protected HUDOverlay() { RelativeSizeAxes = Axes.Both; @@ -56,6 +59,7 @@ namespace osu.Game.Rulesets.UI AccuracyCounter = CreateAccuracyCounter(), HealthDisplay = CreateHealthDisplay(), Progress = CreateProgress(), + ModDisplay = CreateModsContainer(), } }); } @@ -105,6 +109,11 @@ namespace osu.Game.Rulesets.UI public virtual void BindHitRenderer(HitRenderer hitRenderer) { hitRenderer.InputManager.Add(KeyCounter.GetReceptor()); + + // in the case a replay isn't loaded, we want some elements to only appear briefly. + if (!hitRenderer.HasReplayLoaded) + using (ModDisplay.BeginDelayedSequence(2000)) + ModDisplay.FadeOut(200); } protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) diff --git a/osu.Game/Screens/Play/Player.cs b/osu.Game/Screens/Play/Player.cs index 37b4cf5b45..534a224855 100644 --- a/osu.Game/Screens/Play/Player.cs +++ b/osu.Game/Screens/Play/Player.cs @@ -72,7 +72,7 @@ namespace osu.Game.Screens.Play private Container hitRendererContainer; - private HudOverlay hudOverlay; + private HUDOverlay hudOverlay; private PauseOverlay pauseOverlay; private FailOverlay failOverlay; @@ -154,7 +154,7 @@ namespace osu.Game.Screens.Play scoreProcessor = HitRenderer.CreateScoreProcessor(); - hudOverlay = new StandardHudOverlay() + hudOverlay = new StandardHUDOverlay() { Anchor = Anchor.Centre, Origin = Anchor.Centre @@ -169,6 +169,8 @@ namespace osu.Game.Screens.Play hudOverlay.Progress.AllowSeeking = HitRenderer.HasReplayLoaded; hudOverlay.Progress.OnSeek = pos => decoupledClock.Seek(pos); + hudOverlay.ModDisplay.Current.BindTo(Beatmap.Mods); + //bind HitRenderer to ScoreProcessor and ourselves (for a pass situation) HitRenderer.OnAllJudged += onCompletion; diff --git a/osu.Game/Rulesets/UI/StandardHudOverlay.cs b/osu.Game/Screens/Play/StandardHUDOverlay.cs similarity index 85% rename from osu.Game/Rulesets/UI/StandardHudOverlay.cs rename to osu.Game/Screens/Play/StandardHUDOverlay.cs index c68e29f98a..41f9ee1394 100644 --- a/osu.Game/Rulesets/UI/StandardHudOverlay.cs +++ b/osu.Game/Screens/Play/StandardHUDOverlay.cs @@ -1,18 +1,18 @@ // Copyright (c) 2007-2017 ppy Pty Ltd . // Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE -using OpenTK; using osu.Framework.Allocation; using osu.Framework.Graphics; using osu.Framework.Graphics.Primitives; using osu.Game.Graphics; using osu.Game.Graphics.UserInterface; using osu.Game.Rulesets.Scoring; -using osu.Game.Screens.Play; +using osu.Game.Screens.Play.HUD; +using OpenTK; -namespace osu.Game.Rulesets.UI +namespace osu.Game.Screens.Play { - public class StandardHudOverlay : HudOverlay + public class StandardHUDOverlay : HUDOverlay { protected override RollingCounter CreateAccuracyCounter() => new PercentageCounter { @@ -64,6 +64,14 @@ namespace osu.Game.Rulesets.UI RelativeSizeAxes = Axes.X, }; + protected override ModDisplay CreateModsContainer() => new ModDisplay + { + Anchor = Anchor.TopRight, + Origin = Anchor.TopRight, + AutoSizeAxes = Axes.Both, + Margin = new MarginPadding { Top = 20, Right = 10 }, + }; + [BackgroundDependencyLoader] private void load(OsuColour colours) { diff --git a/osu.Game/Screens/Select/PlaySongSelect.cs b/osu.Game/Screens/Select/PlaySongSelect.cs index c15900eb6d..315992c113 100644 --- a/osu.Game/Screens/Select/PlaySongSelect.cs +++ b/osu.Game/Screens/Select/PlaySongSelect.cs @@ -69,6 +69,13 @@ namespace osu.Game.Screens.Select base.OnResuming(last); } + protected override void OnSuspending(Screen next) + { + modSelect.Hide(); + + base.OnSuspending(next); + } + protected override bool OnExiting(Screen next) { if (modSelect.State == Visibility.Visible) diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 929811226f..bd9f087cf7 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -178,10 +178,9 @@ - - - - + + + @@ -228,7 +227,9 @@ + + @@ -254,7 +255,7 @@ - + @@ -279,8 +280,8 @@ - - + + @@ -371,8 +372,10 @@ + + @@ -390,6 +393,7 @@ + diff --git a/osu.sln.DotSettings b/osu.sln.DotSettings index bc2c347d0c..03d9e34805 100644 --- a/osu.sln.DotSettings +++ b/osu.sln.DotSettings @@ -182,6 +182,7 @@ GL GLSL HID + HUD ID IP IPC