diff --git a/osu.Game/Overlays/Mods/ModButton.cs b/osu.Game/Overlays/Mods/ModButton.cs index e3d26cba06..b07bb7d2fb 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; @@ -116,7 +120,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) @@ -198,13 +202,8 @@ namespace osu.Game.Overlays.Mods buttonColour = foregroundIcon.Colour; } - public ModButton(Mod m) + public ModButton(Mod mod) { - Direction = FillDirection.Vertical; - Spacing = new Vector2(0f, -5f); - Size = new Vector2(100f); - AlwaysPresent = true; - Children = new Drawable[] { new Container @@ -224,13 +223,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 b70323fb63..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,28 +38,31 @@ namespace osu.Game.Overlays.Mods } } - private ModButton[] buttons = { }; - public ModButton[] Buttons + public IEnumerable SelectedMods => buttons.Select(b => b.SelectedMod).Where(m => m != null); + + public IEnumerable Mods { - get - { - return buttons; - } set { - if (value == buttons) return; - buttons = value; - - foreach (ModButton button in value) + var modContainers = value.Select(m => { - button.SelectedColour = selectedColour; - button.Action = Action; - } + if (m == null) + return new ModButtonEmpty(); + else + return new ModButton(m) + { + SelectedColour = selectedColour, + Action = Action, + }; + }).ToArray(); - ButtonsContainer.Children = value; + ButtonsContainer.Children = modContainers; + buttons = modContainers.OfType().ToArray(); } } + private ModButton[] buttons = { }; + private Color4 selectedColour = Color4.White; public Color4 SelectedColour { @@ -71,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); } @@ -89,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(); } } @@ -107,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/Rulesets/UI/ModIcon.cs b/osu.Game/Rulesets/UI/ModIcon.cs index 19efdb0175..497c71f0d5 100644 --- a/osu.Game/Rulesets/UI/ModIcon.cs +++ b/osu.Game/Rulesets/UI/ModIcon.cs @@ -1,6 +1,7 @@ // 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.Graphics; using osu.Framework.Graphics.Containers; @@ -42,6 +43,8 @@ namespace osu.Game.Rulesets.UI public ModIcon(Mod mod) { + if (mod == null) throw new ArgumentNullException(nameof(mod)); + Children = new Drawable[] { background = new TextAwesome @@ -59,7 +62,7 @@ namespace osu.Game.Rulesets.UI Anchor = Anchor.Centre, Colour = OsuColour.Gray(84), TextSize = 20, - Icon = (mod != null) ? mod.Icon : FontAwesome.fa_question, + Icon = mod.Icon }, }; @@ -74,7 +77,7 @@ namespace osu.Game.Rulesets.UI private Color4 getBackgroundColourFromMod(Mod mod) { - switch (mod?.Type) + switch (mod.Type) { case ModType.DifficultyIncrease: return OsuColour.FromHex(@"ffcc22"); @@ -87,4 +90,4 @@ namespace osu.Game.Rulesets.UI } } } -} \ No newline at end of file +} diff --git a/osu.Game/osu.Game.csproj b/osu.Game/osu.Game.csproj index 98f9a8a52b..c06ba0b1ea 100644 --- a/osu.Game/osu.Game.csproj +++ b/osu.Game/osu.Game.csproj @@ -391,6 +391,7 @@ +