1
0
mirror of https://github.com/ppy/osu.git synced 2024-12-15 14:55:37 +08:00

Merge branch 'master' into beatmap_timinginfo

This commit is contained in:
Dean Herbert 2017-03-16 23:08:24 +09:00 committed by GitHub
commit 60fc782e93
59 changed files with 804 additions and 393 deletions

@ -1 +1 @@
Subproject commit 036b124eb2387dde29af56e06391c42063ec85e2
Subproject commit 53dfe2a110d732cca0e7df58c33eca368bc7ff61

View File

@ -8,6 +8,7 @@ using osu.Framework.MathUtils;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Screens.Select;
using osu.Game.Screens.Select.Filter;
namespace osu.Desktop.VisualTests.Tests
{
@ -39,10 +40,10 @@ namespace osu.Desktop.VisualTests.Tests
Add(songSelect = new PlaySongSelect());
AddButton(@"Sort by Artist", delegate { songSelect.Filter.Sort = FilterControl.SortMode.Artist; });
AddButton(@"Sort by Title", delegate { songSelect.Filter.Sort = FilterControl.SortMode.Title; });
AddButton(@"Sort by Author", delegate { songSelect.Filter.Sort = FilterControl.SortMode.Author; });
AddButton(@"Sort by Difficulty", delegate { songSelect.Filter.Sort = FilterControl.SortMode.Difficulty; });
AddButton(@"Sort by Artist", delegate { songSelect.FilterControl.Sort = SortMode.Artist; });
AddButton(@"Sort by Title", delegate { songSelect.FilterControl.Sort = SortMode.Title; });
AddButton(@"Sort by Author", delegate { songSelect.FilterControl.Sort = SortMode.Author; });
AddButton(@"Sort by Difficulty", delegate { songSelect.FilterControl.Sort = SortMode.Difficulty; });
}
protected override void Dispose(bool isDisposing)

View File

@ -0,0 +1,45 @@
// 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.Primitives;
using osu.Framework.Screens.Testing;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Select.Filter;
namespace osu.Desktop.VisualTests.Tests
{
public class TestCaseTabControl : TestCase
{
public override string Description => @"Filter for song select";
public override void Reset()
{
base.Reset();
OsuSpriteText text;
OsuTabControl<GroupMode> filter;
Add(filter = new OsuTabControl<GroupMode>
{
Margin = new MarginPadding(4),
Size = new Vector2(229, 24),
AutoSort = true
});
Add(text = new OsuSpriteText
{
Text = "None",
Margin = new MarginPadding(4),
Position = new Vector2(275, 5)
});
filter.PinTab(GroupMode.All);
filter.PinTab(GroupMode.RecentlyPlayed);
filter.ValueChanged += (sender, mode) =>
{
text.Text = "Currently Selected: " + mode.ToString();
};
}
}
}

View File

@ -193,6 +193,7 @@
<Compile Include="Tests\TestCaseMenuButtonSystem.cs" />
<Compile Include="Tests\TestCaseReplay.cs" />
<Compile Include="Tests\TestCaseScoreCounter.cs" />
<Compile Include="Tests\TestCaseTabControl.cs" />
<Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />

View File

@ -87,8 +87,8 @@ namespace osu.Game.Modes.Catch
new KeyCounterMouse(MouseButton.Right)
};
public override ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0) => null;
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new CatchDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor();
}
}

View File

@ -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 osu.Game.Modes.Catch.Judgements;
using osu.Game.Modes.Catch.Objects;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Catch
{
internal class CatchScoreProcessor : ScoreProcessor<CatchBaseHit, CatchJudgementInfo>
{
public CatchScoreProcessor()
{
}
public CatchScoreProcessor(HitRenderer<CatchBaseHit, CatchJudgementInfo> hitRenderer)
: base(hitRenderer)
{
}
protected override void UpdateCalculations(CatchJudgementInfo newJudgement)
{
}
}
}

View File

@ -17,11 +17,13 @@ namespace osu.Game.Modes.Catch.UI
{
}
public override ScoreProcessor CreateScoreProcessor() => new CatchScoreProcessor(this);
protected override IBeatmapConverter<CatchBaseHit> CreateBeatmapConverter() => new CatchBeatmapConverter();
protected override IBeatmapProcessor<CatchBaseHit> CreateBeatmapProcessor() => new CatchBeatmapProcessor();
protected override Playfield<CatchBaseHit, CatchJudgementInfo> CreatePlayfield() => new CatchPlayfield();
protected override Playfield<CatchBaseHit, CatchJudgementInfo> CreatePlayfield() => new CatchPlayfield();
protected override DrawableHitObject<CatchBaseHit, CatchJudgementInfo> GetVisualRepresentation(CatchBaseHit h) => null;
}

View File

@ -50,6 +50,7 @@
<Compile Include="Beatmaps\CatchBeatmapConverter.cs" />
<Compile Include="Beatmaps\CatchBeatmapProcessor.cs" />
<Compile Include="CatchDifficultyCalculator.cs" />
<Compile Include="CatchScoreProcessor.cs" />
<Compile Include="Judgements\CatchJudgementInfo.cs" />
<Compile Include="Objects\CatchBaseHit.cs" />
<Compile Include="Objects\Drawable\DrawableFruit.cs" />

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

View File

@ -102,8 +102,8 @@ namespace osu.Game.Modes.Mania
public override IEnumerable<KeyCounter> CreateGameplayKeys() => new KeyCounter[] { /* Todo: Should be keymod specific */ };
public override ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0) => null;
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new ManiaDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor();
}
}

View File

@ -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 osu.Game.Modes.Mania.Judgements;
using osu.Game.Modes.Mania.Objects;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Mania
{
internal class ManiaScoreProcessor : ScoreProcessor<ManiaBaseHit, ManiaJudgementInfo>
{
public ManiaScoreProcessor()
{
}
public ManiaScoreProcessor(HitRenderer<ManiaBaseHit, ManiaJudgementInfo> hitRenderer)
: base(hitRenderer)
{
}
protected override void UpdateCalculations(ManiaJudgementInfo newJudgement)
{
}
}
}

View File

@ -20,11 +20,13 @@ namespace osu.Game.Modes.Mania.UI
this.columns = columns;
}
public override ScoreProcessor CreateScoreProcessor() => new ManiaScoreProcessor(this);
protected override IBeatmapConverter<ManiaBaseHit> CreateBeatmapConverter() => new ManiaBeatmapConverter();
protected override IBeatmapProcessor<ManiaBaseHit> CreateBeatmapProcessor() => new ManiaBeatmapProcessor();
protected override Playfield<ManiaBaseHit, ManiaJudgementInfo> CreatePlayfield() => new ManiaPlayfield(columns);
protected override Playfield<ManiaBaseHit, ManiaJudgementInfo> CreatePlayfield() => new ManiaPlayfield(columns);
protected override DrawableHitObject<ManiaBaseHit, ManiaJudgementInfo> GetVisualRepresentation(ManiaBaseHit h) => null;
}

View File

@ -51,6 +51,7 @@
<Compile Include="Beatmaps\ManiaBeatmapProcessor.cs" />
<Compile Include="Judgements\ManiaJudgementInfo.cs" />
<Compile Include="ManiaDifficultyCalculator.cs" />
<Compile Include="ManiaScoreProcessor.cs" />
<Compile Include="Objects\Drawable\DrawableNote.cs" />
<Compile Include="Objects\HoldNote.cs" />
<Compile Include="Objects\ManiaBaseHit.cs" />

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

View File

@ -28,6 +28,10 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
public DrawableSlider(Slider s) : base(s)
{
// Since the DrawableSlider itself is just a container without a size we need to
// pass all input through.
AlwaysReceiveInput = true;
SliderBouncer bouncer1;
slider = s;
@ -91,10 +95,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
}
}
// Since the DrawableSlider itself is just a container without a size we need to
// pass all input through.
public override bool Contains(Vector2 screenSpacePos) => true;
private int currentRepeat;
protected override void Update()

View File

@ -24,6 +24,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
public DrawableSpinner(Spinner s) : base(s)
{
AlwaysReceiveInput = true;
Origin = Anchor.Centre;
Position = s.Position;
@ -69,8 +71,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables
disc.Scale = scaleToCircle;
}
public override bool Contains(Vector2 screenSpacePos) => true;
protected override void CheckJudgement(bool userTriggered)
{
if (Time.Current < HitObject.StartTime) return;

View File

@ -19,8 +19,6 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
{
public class SpinnerDisc : CircularContainer
{
public override bool Contains(Vector2 screenSpacePos) => true;
protected Sprite Disc;
public SRGBColour DiscColour
@ -101,6 +99,8 @@ namespace osu.Game.Modes.Osu.Objects.Drawables.Pieces
public SpinnerDisc()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
Children = new Drawable[]

View File

@ -95,8 +95,6 @@ namespace osu.Game.Modes.Osu
public override FontAwesome Icon => FontAwesome.fa_osu_osu_o;
public override ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0) => new OsuScoreProcessor(hitObjectCount);
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new OsuDifficultyCalculator(beatmap);
protected override PlayMode PlayMode => PlayMode.Osu;
@ -110,5 +108,7 @@ namespace osu.Game.Modes.Osu
new KeyCounterMouse(MouseButton.Left),
new KeyCounterMouse(MouseButton.Right)
};
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor();
}
}

View File

@ -1,22 +1,33 @@
// 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.Modes.Judgements;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Modes.Osu.Judgements;
using osu.Game.Modes.Osu.Objects;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Osu
{
internal class OsuScoreProcessor : ScoreProcessor
internal class OsuScoreProcessor : ScoreProcessor<OsuHitObject, OsuJudgementInfo>
{
public OsuScoreProcessor(int hitObjectCount = 0)
: base(hitObjectCount)
public OsuScoreProcessor()
{
}
public OsuScoreProcessor(HitRenderer<OsuHitObject, OsuJudgementInfo> hitRenderer)
: base(hitRenderer)
{
}
protected override void Reset()
{
base.Reset();
Health.Value = 1;
Accuracy.Value = 1;
}
protected override void UpdateCalculations(JudgementInfo judgement)
protected override void UpdateCalculations(OsuJudgementInfo judgement)
{
if (judgement != null)
{
@ -38,7 +49,7 @@ namespace osu.Game.Modes.Osu
foreach (var judgementInfo in Judgements)
{
var j = (OsuJudgementInfo)judgementInfo;
var j = judgementInfo;
score += j.ScoreValue;
maxScore += j.MaxScoreValue;
}

View File

@ -19,11 +19,13 @@ namespace osu.Game.Modes.Osu.UI
{
}
public override ScoreProcessor CreateScoreProcessor() => new OsuScoreProcessor(this);
protected override IBeatmapConverter<OsuHitObject> CreateBeatmapConverter() => new OsuBeatmapConverter();
protected override IBeatmapProcessor<OsuHitObject> CreateBeatmapProcessor() => new OsuBeatmapProcessor();
protected override Playfield<OsuHitObject, OsuJudgementInfo> CreatePlayfield() => new OsuPlayfield();
protected override Playfield<OsuHitObject, OsuJudgementInfo> CreatePlayfield() => new OsuPlayfield();
protected override KeyConversionInputManager CreateKeyConversionInputManager() => new OsuKeyConversionInputManager();

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

View File

@ -88,8 +88,8 @@ namespace osu.Game.Modes.Taiko
new KeyCounterKeyboard(Key.K)
};
public override ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0) => null;
public override DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap) => new TaikoDifficultyCalculator(beatmap);
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor();
}
}

View File

@ -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 osu.Game.Modes.Taiko.Judgements;
using osu.Game.Modes.Taiko.Objects;
using osu.Game.Modes.UI;
namespace osu.Game.Modes.Taiko
{
internal class TaikoScoreProcessor : ScoreProcessor<TaikoBaseHit, TaikoJudgementInfo>
{
public TaikoScoreProcessor()
{
}
public TaikoScoreProcessor(HitRenderer<TaikoBaseHit, TaikoJudgementInfo> hitRenderer)
: base(hitRenderer)
{
}
protected override void UpdateCalculations(TaikoJudgementInfo newJudgement)
{
}
}
}

View File

@ -17,11 +17,13 @@ namespace osu.Game.Modes.Taiko.UI
{
}
public override ScoreProcessor CreateScoreProcessor() => new TaikoScoreProcessor(this);
protected override IBeatmapConverter<TaikoBaseHit> CreateBeatmapConverter() => new TaikoBeatmapConverter();
protected override IBeatmapProcessor<TaikoBaseHit> CreateBeatmapProcessor() => new TaikoBeatmapProcessor();
protected override Playfield<TaikoBaseHit, TaikoJudgementInfo> CreatePlayfield() => new TaikoPlayfield();
protected override Playfield<TaikoBaseHit, TaikoJudgementInfo> CreatePlayfield() => new TaikoPlayfield();
protected override DrawableHitObject<TaikoBaseHit, TaikoJudgementInfo> GetVisualRepresentation(TaikoBaseHit h) => null;
}

View File

@ -54,6 +54,7 @@
<Compile Include="Objects\Drawable\DrawableTaikoHit.cs" />
<Compile Include="Objects\TaikoBaseHit.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="TaikoScoreProcessor.cs" />
<Compile Include="UI\TaikoHitRenderer.cs" />
<Compile Include="UI\TaikoPlayfield.cs" />
<Compile Include="TaikoRuleset.cs" />

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE

View File

@ -2,6 +2,7 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Collections.Generic;
using System.Linq;
using SQLite.Net.Attributes;
using SQLiteNetExtensions.Attributes;
@ -23,6 +24,8 @@ namespace osu.Game.Database
[OneToMany(CascadeOperations = CascadeOperation.All)]
public List<BeatmapInfo> Beatmaps { get; set; }
public float MaxStarDifficulty => Beatmaps.Max(b => b.StarDifficulty);
public bool DeletePending { get; set; }
public string Hash { get; set; }

View File

@ -39,9 +39,7 @@ namespace osu.Game.Database
using (SerializationReader sr = new SerializationReader(s))
{
var ruleset = Ruleset.GetRuleset((PlayMode)sr.ReadByte());
var processor = ruleset.CreateScoreProcessor();
score = processor.GetScore();
score = ruleset.CreateScoreProcessor().GetScore();
/* score.Pass = true;*/
var version = sr.ReadInt32();

View File

@ -18,10 +18,10 @@ namespace osu.Game.Graphics.Containers
private Bindable<bool> parallaxEnabled;
public override bool Contains(Vector2 screenSpacePos) => true;
public ParallaxContainer()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
AddInternal(content = new Container
{

View File

@ -18,7 +18,6 @@ namespace osu.Game.Graphics.Cursor
{
internal class CursorTrail : Drawable
{
public override bool Contains(Vector2 screenSpacePos) => true;
public override bool HandleInput => true;
private int currentIndex;
@ -59,6 +58,7 @@ namespace osu.Game.Graphics.Cursor
public CursorTrail()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
for (int i = 0; i < max_sprites; i++)

View File

@ -10,10 +10,9 @@ namespace osu.Game.Graphics.Processing
{
internal class RatioAdjust : Container
{
public override bool Contains(Vector2 screenSpacePos) => true;
public RatioAdjust()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
}

View File

@ -88,7 +88,7 @@ namespace osu.Game.Graphics.UserInterface
private bool didClick; // Used for making sure that the OnMouseDown animation can call instead of OnHoverLost's when clicking
public override bool Contains(Vector2 screenSpacePos) => backgroundContainer.Contains(screenSpacePos);
protected override bool InternalContains(Vector2 screenSpacePos) => backgroundContainer.Contains(screenSpacePos);
protected override bool OnClick(Framework.Input.InputState state)
{

View File

@ -21,6 +21,17 @@ namespace osu.Game.Graphics.UserInterface
set { label.Text = value; }
}
private Color4? accentColour;
public virtual Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
BackgroundColourHover = value;
}
}
public OsuDropDownHeader()
{
Foreground.Padding = new MarginPadding(4);
@ -30,7 +41,7 @@ namespace osu.Game.Graphics.UserInterface
CornerRadius = 4;
Height = 40;
Children = new[]
Foreground.Children = new Drawable[]
{
label = new OsuSpriteText
{
@ -51,7 +62,7 @@ namespace osu.Game.Graphics.UserInterface
private void load(OsuColour colours)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
BackgroundColourHover = colours.PinkDarker;
BackgroundColourHover = accentColour ?? colours.PinkDarker;
}
}
}

View File

@ -1,39 +1,61 @@
// 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.Transforms;
using osu.Framework.Graphics.UserInterface;
using System.Linq;
using osu.Framework.Allocation;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface;
namespace osu.Game.Graphics.UserInterface
{
public class OsuDropDownMenu<U> : DropDownMenu<U>
public class OsuDropDownMenu<T> : DropDownMenu<T>
{
protected override DropDownHeader CreateHeader() => new OsuDropDownHeader();
protected override DropDownHeader CreateHeader() => new OsuDropDownHeader { AccentColour = AccentColour };
private Color4? accentColour;
public virtual Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (Header != null)
((OsuDropDownHeader)Header).AccentColour = value;
foreach (var item in ItemList.OfType<OsuDropDownMenuItem<T>>())
item.AccentColour = value;
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.PinkDarker;
}
public OsuDropDownMenu()
{
ContentContainer.CornerRadius = 4;
ContentBackground.Colour = Color4.Black.Opacity(0.5f);
DropDownItemsContainer.Padding = new MarginPadding(5);
}
protected override void AnimateOpen()
{
ContentContainer.FadeIn(300, EasingTypes.OutQuint);
}
protected override void AnimateOpen() => ContentContainer.FadeIn(300, EasingTypes.OutQuint);
protected override void AnimateClose()
{
ContentContainer.FadeOut(300, EasingTypes.OutQuint);
}
protected override void AnimateClose() => ContentContainer.FadeOut(300, EasingTypes.OutQuint);
protected override void UpdateContentHeight()
{
ContentContainer.ResizeTo(State == DropDownMenuState.Opened ? new Vector2(1, ContentHeight) : new Vector2(1, 0), 300, EasingTypes.OutQuint);
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
ContentContainer.ResizeTo(new Vector2(1, State == DropDownMenuState.Opened ? actualHeight : 0), 300, EasingTypes.OutQuint);
}
protected override DropDownMenuItem<U> CreateDropDownItem(string key, U value) => new OsuDropDownMenuItem<U>(key, value);
protected override DropDownMenuItem<T> CreateDropDownItem(string key, T value) => new OsuDropDownMenuItem<T>(key, value) { AccentColour = AccentColour };
}
}

View File

@ -18,6 +18,9 @@ namespace osu.Game.Graphics.UserInterface
{
Foreground.Padding = new MarginPadding(2);
Masking = true;
CornerRadius = 6;
Children = new[]
{
new FillFlowContainer
@ -27,12 +30,15 @@ namespace osu.Game.Graphics.UserInterface
AutoSizeAxes = Axes.Y,
Children = new Drawable[]
{
new TextAwesome
chevron = new TextAwesome
{
AlwaysPresent = true,
Icon = FontAwesome.fa_chevron_right,
UseFullGlyphHeight = false,
Colour = Color4.Black,
TextSize = 12,
Margin = new MarginPadding { Right = 3 },
Alpha = 0.5f,
TextSize = 8,
Margin = new MarginPadding { Left = 3, Right = 3 },
Origin = Anchor.CentreLeft,
Anchor = Anchor.CentreLeft,
},
@ -46,11 +52,33 @@ namespace osu.Game.Graphics.UserInterface
};
}
private Color4? accentColour;
private TextAwesome chevron;
protected override void FormatForeground(bool hover = false)
{
base.FormatForeground(hover);
chevron.Alpha = hover ? 1 : 0;
}
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
BackgroundColourHover = BackgroundColourSelected = value;
FormatBackground();
FormatForeground();
}
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
BackgroundColour = Color4.Black.Opacity(0.5f);
BackgroundColourHover = colours.PinkDarker;
BackgroundColour = Color4.Transparent;
BackgroundColourHover = accentColour ?? colours.PinkDarker;
BackgroundColourSelected = Color4.Black.Opacity(0.5f);
}
}

View File

@ -0,0 +1,139 @@
// 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 OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions.Color4Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTabControl<T> : TabControl<T>
{
protected override DropDownMenu<T> CreateDropDownMenu() => new OsuTabDropDownMenu<T>();
protected override TabItem<T> CreateTabItem(T value) => new OsuTabItem<T> { Value = value };
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || DropDown.Contains(screenSpacePos);
public OsuTabControl()
{
if (!typeof(T).IsEnum)
throw new InvalidOperationException("OsuTabControl only supports enums as the generic type argument");
foreach (var val in (T[])Enum.GetValues(typeof(T)))
AddTab(val);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.Blue;
}
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
var dropDown = DropDown as OsuTabDropDownMenu<T>;
if (dropDown != null)
dropDown.AccentColour = value;
foreach (var item in TabContainer.Children.OfType<OsuTabItem<T>>())
item.AccentColour = value;
}
}
public class OsuTabDropDownMenu<T1> : OsuDropDownMenu<T1>
{
protected override DropDownHeader CreateHeader() => new OsuTabDropDownHeader
{
AccentColour = AccentColour,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
};
protected override DropDownMenuItem<T1> CreateDropDownItem(string key, T1 value)
{
var item = base.CreateDropDownItem(key, value);
item.ForegroundColourHover = Color4.Black;
return item;
}
public OsuTabDropDownMenu()
{
ContentContainer.Anchor = Anchor.TopRight;
ContentContainer.Origin = Anchor.TopRight;
RelativeSizeAxes = Axes.X;
ContentBackground.Colour = Color4.Black.Opacity(0.7f);
MaxDropDownHeight = 400;
}
public class OsuTabDropDownHeader : OsuDropDownHeader
{
public override Color4 AccentColour
{
get { return base.AccentColour; }
set
{
base.AccentColour = value;
Foreground.Colour = value;
}
}
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;
AutoSizeAxes = Axes.X;
BackgroundColour = Color4.Black.Opacity(0.5f);
Background.Height = 0.5f;
Background.CornerRadius = 5;
Background.Masking = true;
Foreground.RelativeSizeAxes = Axes.None;
Foreground.AutoSizeAxes = Axes.X;
Foreground.RelativeSizeAxes = Axes.Y;
Foreground.Margin = new MarginPadding(5);
Foreground.Children = new Drawable[]
{
new TextAwesome
{
Icon = FontAwesome.fa_ellipsis_h,
TextSize = 14,
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
};
Padding = new MarginPadding { Left = 5, Right = 5 };
}
}
}
}
}

View File

@ -0,0 +1,121 @@
// 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.Graphics;
using osu.Framework.Allocation;
using osu.Framework.Extensions;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transforms;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics.Sprites;
namespace osu.Game.Graphics.UserInterface
{
public class OsuTabItem<T> : TabItem<T>
{
private SpriteText text;
private Box box;
private Color4? accentColour;
public Color4 AccentColour
{
get { return accentColour.GetValueOrDefault(); }
set
{
accentColour = value;
if (!Active)
text.Colour = value;
}
}
public new T Value
{
get { return base.Value; }
set
{
base.Value = value;
text.Text = (value as Enum)?.GetDescription();
}
}
public override bool Active
{
get { return base.Active; }
set
{
if (Active == value) return;
if (value)
fadeActive();
else
fadeInactive();
base.Active = value;
}
}
private const float transition_length = 500;
private void fadeActive()
{
box.FadeIn(transition_length, EasingTypes.OutQuint);
text.FadeColour(Color4.White, transition_length, EasingTypes.OutQuint);
}
private void fadeInactive()
{
box.FadeOut(transition_length, EasingTypes.OutQuint);
text.FadeColour(AccentColour, transition_length, EasingTypes.OutQuint);
}
protected override bool OnHover(InputState state)
{
if (!Active)
fadeActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!Active)
fadeInactive();
}
public OsuTabItem()
{
AutoSizeAxes = Axes.X;
RelativeSizeAxes = Axes.Y;
Children = new Drawable[]
{
text = new OsuSpriteText
{
Margin = new MarginPadding(5),
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
TextSize = 14,
Font = @"Exo2.0-Bold", // Font should only turn bold when active?
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
if (accentColour == null)
AccentColour = colours.Blue;
}
}
}

View File

@ -158,7 +158,7 @@ namespace osu.Game.Graphics.UserInterface
}
}
public override bool Contains(Vector2 screenSpacePos) => IconLayer.Contains(screenSpacePos) || TextLayer.Contains(screenSpacePos);
protected override bool InternalContains(Vector2 screenSpacePos) => IconLayer.Contains(screenSpacePos) || TextLayer.Contains(screenSpacePos);
protected override bool OnHover(InputState state)
{

View File

@ -29,12 +29,12 @@ namespace osu.Game.Modes
public abstract IEnumerable<Mod> GetModsFor(ModType type);
public abstract ScoreProcessor CreateScoreProcessor(int hitObjectCount = 0);
public abstract HitRenderer CreateHitRendererWith(WorkingBeatmap beatmap);
public abstract DifficultyCalculator CreateDifficultyCalculator(Beatmap beatmap);
public abstract ScoreProcessor CreateScoreProcessor();
public static void Register(Ruleset ruleset) => availableRulesets.TryAdd(ruleset.PlayMode, ruleset.GetType());
protected abstract PlayMode PlayMode { get; }

View File

@ -5,6 +5,8 @@ using osu.Framework.Configuration;
using System;
using System.Collections.Generic;
using osu.Game.Modes.Judgements;
using osu.Game.Modes.UI;
using osu.Game.Modes.Objects;
namespace osu.Game.Modes
{
@ -28,11 +30,10 @@ namespace osu.Game.Modes
public readonly BindableInt Combo = new BindableInt();
/// <summary>
/// Are we allowed to fail?
/// Keeps track of the highest combo ever achieved in this play.
/// This is handled automatically by ScoreProcessor.
/// </summary>
protected bool CanFail => true;
protected bool HasFailed { get; private set; }
public readonly BindableInt HighestCombo = new BindableInt();
/// <summary>
/// Called when we reach a failing health of zero.
@ -40,24 +41,48 @@ namespace osu.Game.Modes
public event Action Failed;
/// <summary>
/// Keeps track of the highest combo ever achieved in this play.
/// This is handled automatically by ScoreProcessor.
/// Notifies subscribers that the score is in a failed state.
/// </summary>
public readonly BindableInt HighestCombo = new BindableInt();
protected void TriggerFailed()
{
Failed?.Invoke();
}
}
public readonly List<JudgementInfo> Judgements;
public abstract class ScoreProcessor<TObject, TJudgement> : ScoreProcessor
where TObject : HitObject
where TJudgement : JudgementInfo
{
/// <summary>
/// All judgements held by this ScoreProcessor.
/// </summary>
protected List<TJudgement> Judgements;
/// <summary>
/// Initializes a new instance of the <see cref="ScoreProcessor"/> class.
/// Are we allowed to fail?
/// </summary>
/// <param name="hitObjectCount">Number of HitObjects. It is used for specifying Judgements collection Capacity</param>
protected ScoreProcessor(int hitObjectCount = 0)
protected bool CanFail => true;
/// <summary>
/// Whether this ScoreProcessor has already triggered the failed event.
/// </summary>
protected bool HasFailed { get; private set; }
protected ScoreProcessor()
{
Combo.ValueChanged += delegate { HighestCombo.Value = Math.Max(HighestCombo.Value, Combo.Value); };
Judgements = new List<JudgementInfo>(hitObjectCount);
Reset();
}
public void AddJudgement(JudgementInfo judgement)
protected ScoreProcessor(HitRenderer<TObject, TJudgement> hitRenderer)
: this()
{
Judgements = new List<TJudgement>(hitRenderer.Beatmap.HitObjects.Count);
hitRenderer.OnJudgement += addJudgement;
}
private void addJudgement(TJudgement judgement)
{
Judgements.Add(judgement);
@ -67,14 +92,19 @@ namespace osu.Game.Modes
if (Health.Value == Health.MinValue && !HasFailed)
{
HasFailed = true;
Failed?.Invoke();
TriggerFailed();
}
}
/// <summary>
/// Resets this ScoreProcessor to a stale state.
/// </summary>
protected virtual void Reset() { }
/// <summary>
/// Update any values that potentially need post-processing on a judgement change.
/// </summary>
/// <param name="newJudgement">A new JudgementInfo that triggered this calculation. May be null.</param>
protected abstract void UpdateCalculations(JudgementInfo newJudgement);
protected abstract void UpdateCalculations(TJudgement newJudgement);
}
}

View File

@ -25,14 +25,6 @@ namespace osu.Game.Modes.UI
/// </summary>
public abstract class HitRenderer : Container
{
/// <summary>
/// The event that's fired when a hit object is judged.
/// </summary>
public event Action<JudgementInfo> OnJudgement;
/// <summary>
/// The event that's fired when all hit objects have been judged.
/// </summary>
public event Action OnAllJudged;
/// <summary>
@ -57,17 +49,16 @@ namespace osu.Game.Modes.UI
}
/// <summary>
/// Triggers a judgement for further processing.
/// Checks whether all HitObjects have been judged, and invokes OnAllJudged.
/// </summary>
/// <param name="j">The judgement to trigger.</param>
protected void TriggerOnJudgement(JudgementInfo j)
protected void CheckAllJudged()
{
OnJudgement?.Invoke(j);
if (AllObjectsJudged)
OnAllJudged?.Invoke();
}
public abstract ScoreProcessor CreateScoreProcessor();
/// <summary>
/// Creates a key conversion input manager.
/// </summary>
@ -141,6 +132,8 @@ namespace osu.Game.Modes.UI
where TObject : HitObject
where TJudgement : JudgementInfo
{
public event Action<TJudgement> OnJudgement;
protected override Container<Drawable> Content => content;
protected override bool AllObjectsJudged => Playfield.HitObjects.Children.All(h => h.Judgement.Result.HasValue);
@ -197,8 +190,10 @@ namespace osu.Game.Modes.UI
/// <param name="judgedObject">The object that Judgement has been updated for.</param>
private void onJudgement(DrawableHitObject<TObject, TJudgement> judgedObject)
{
TriggerOnJudgement(judgedObject.Judgement);
OnJudgement?.Invoke(judgedObject.Judgement);
Playfield.OnJudgement(judgedObject);
CheckAllJudged();
}
/// <summary>

View File

@ -18,7 +18,6 @@ namespace osu.Game.Modes.UI
/// The HitObjects contained in this Playfield.
/// </summary>
public HitObjectContainer<DrawableHitObject<TObject, TJudgement>> HitObjects;
public override bool Contains(Vector2 screenSpacePos) => true;
internal Container<Drawable> ScaledContent;
@ -31,6 +30,8 @@ namespace osu.Game.Modes.UI
/// <param name="customWidth">Whether we want our internal coordinate system to be scaled to a specified width.</param>
protected Playfield(float? customWidth = null)
{
AlwaysReceiveInput = true;
AddInternal(ScaledContent = new ScaledContainer
{
CustomWidth = customWidth,
@ -77,12 +78,18 @@ namespace osu.Game.Modes.UI
//dividing by the customwidth will effectively scale our content to the required container size.
protected override Vector2 DrawScale => CustomWidth.HasValue ? new Vector2(DrawSize.X / CustomWidth.Value) : base.DrawScale;
public override bool Contains(Vector2 screenSpacePos) => true;
public ScaledContainer()
{
AlwaysReceiveInput = true;
}
}
public class HitObjectContainer<U> : Container<U> where U : Drawable
{
public override bool Contains(Vector2 screenSpacePos) => true;
public HitObjectContainer()
{
AlwaysReceiveInput = true;
}
}
}
}

View File

@ -35,10 +35,10 @@ namespace osu.Game.Overlays.Toolbar
private const float alpha_hovering = 0.8f;
private const float alpha_normal = 0.6f;
public override bool Contains(Vector2 screenSpacePos) => true;
public Toolbar()
{
AlwaysReceiveInput = true;
Children = new Drawable[]
{
new ToolbarBackground(),
@ -63,8 +63,9 @@ namespace osu.Game.Overlays.Toolbar
}
}
},
new PassThroughFlowContainer
new FillFlowContainer
{
AlwaysReceiveInput = true,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Direction = FillDirection.Horizontal,
@ -144,11 +145,5 @@ namespace osu.Game.Overlays.Toolbar
MoveToY(-DrawSize.Y, transition_time, EasingTypes.OutQuint);
FadeOut(transition_time);
}
private class PassThroughFlowContainer : FillFlowContainer
{
//needed to get input to the login overlay.
public override bool Contains(Vector2 screenSpacePos) => true;
}
}
}

View File

@ -15,10 +15,10 @@ namespace osu.Game.Overlays.Toolbar
public override RectangleF BoundingBox => button.BoundingBox;
public override bool Contains(Vector2 screenSpacePos) => true;
public ToolbarUserArea()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Y;
AutoSizeAxes = Axes.X;

View File

@ -35,10 +35,7 @@ namespace osu.Game.Screens.Menu
private Key triggerKey;
private SampleChannel sampleClick;
public override bool Contains(Vector2 screenSpacePos)
{
return box.Contains(screenSpacePos);
}
protected override bool InternalContains(Vector2 screenSpacePos) => box.Contains(screenSpacePos);
public Button(string text, string internalName, FontAwesome symbol, Color4 colour, Action clickAction = null, float extraWidth = 0, Key triggerKey = Key.Unknown)
{

View File

@ -50,10 +50,7 @@ namespace osu.Game.Screens.Menu
}
}
public override bool Contains(Vector2 screenSpacePos)
{
return logoContainer.Contains(screenSpacePos);
}
protected override bool InternalContains(Vector2 screenSpacePos) => logoContainer.Contains(screenSpacePos);
public bool Ripple
{

View File

@ -4,7 +4,6 @@
using System.Linq;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Input;
@ -14,6 +13,8 @@ namespace osu.Game.Screens.Play
{
public KeyCounterCollection()
{
AlwaysReceiveInput = true;
Direction = FillDirection.Horizontal;
AutoSizeAxes = Axes.Both;
}
@ -33,8 +34,6 @@ namespace osu.Game.Screens.Play
counter.ResetCount();
}
public override bool Contains(Vector2 screenSpacePos) => true;
//further: change default values here and in KeyCounter if needed, instead of passing them in every constructor
private bool isCounting;
public bool IsCounting
@ -111,12 +110,11 @@ namespace osu.Game.Screens.Play
public Receptor(KeyCounterCollection target)
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
this.target = target;
}
public override bool Contains(Vector2 screenSpacePos) => true;
public override bool HandleInput => true;
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args) => target.Children.Any(c => c.TriggerKeyDown(state, args));

View File

@ -2,7 +2,6 @@
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Input;
using OpenTK;
using OpenTK.Input;
namespace osu.Game.Screens.Play
@ -13,6 +12,7 @@ namespace osu.Game.Screens.Play
public KeyCounterMouse(MouseButton button) : base(getStringRepresentation(button))
{
AlwaysReceiveInput = true;
Button = button;
}
@ -29,8 +29,6 @@ namespace osu.Game.Screens.Play
}
}
public override bool Contains(Vector2 screenSpacePos) => true;
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
{
if (args.Button == Button) IsLit = true;

View File

@ -70,7 +70,6 @@ namespace osu.Game.Screens.Play
private FillFlowContainer retryCounterContainer;
public override bool Contains(Vector2 screenSpacePos) => true;
public override bool HandleInput => State == Visibility.Visible;
protected override void PopIn() => FadeIn(transition_duration, EasingTypes.In);
@ -217,6 +216,7 @@ namespace osu.Game.Screens.Play
public PauseOverlay()
{
AlwaysReceiveInput = true;
RelativeSizeAxes = Axes.Both;
}
}

View File

@ -108,10 +108,13 @@ namespace osu.Game.Screens.Play
});
ruleset = Ruleset.GetRuleset(Beatmap.PlayMode);
hitRenderer = ruleset.CreateHitRendererWith(Beatmap);
scoreProcessor = hitRenderer.CreateScoreProcessor();
hudOverlay = new StandardHudOverlay();
hudOverlay.KeyCounter.Add(ruleset.CreateGameplayKeys());
hudOverlay.BindProcessor(scoreProcessor = ruleset.CreateScoreProcessor(beatmap.HitObjects.Count));
hudOverlay.BindProcessor(scoreProcessor);
pauseOverlay = new PauseOverlay
{
@ -125,7 +128,6 @@ namespace osu.Game.Screens.Play
OnQuit = Exit
};
hitRenderer = ruleset.CreateHitRendererWith(Beatmap);
if (ReplayInputHandler != null)
hitRenderer.InputManager.ReplayInputHandler = ReplayInputHandler;
@ -133,7 +135,6 @@ namespace osu.Game.Screens.Play
hudOverlay.BindHitRenderer(hitRenderer);
//bind HitRenderer to ScoreProcessor and ourselves (for a pass situation)
hitRenderer.OnJudgement += scoreProcessor.AddJudgement;
hitRenderer.OnAllJudged += onPass;
//bind ScoreProcessor to ourselves (for a fail situation)

View File

@ -15,6 +15,7 @@ using OpenTK.Input;
using System.Collections;
using osu.Framework.MathUtils;
using System.Diagnostics;
using osu.Game.Screens.Select.Filter;
namespace osu.Game.Screens.Select
{
@ -157,46 +158,26 @@ namespace osu.Game.Screens.Select
ScrollTo(selectedY, animated);
}
public void Sort(FilterControl.SortMode mode)
public void Sort(SortMode mode)
{
List<BeatmapGroup> sortedGroups = new List<BeatmapGroup>(groups);
switch (mode)
{
case FilterControl.SortMode.Artist:
case SortMode.Artist:
sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Artist, y.BeatmapSet.Metadata.Artist, StringComparison.InvariantCultureIgnoreCase));
break;
case FilterControl.SortMode.Title:
case SortMode.Title:
sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Title, y.BeatmapSet.Metadata.Title, StringComparison.InvariantCultureIgnoreCase));
break;
case FilterControl.SortMode.Author:
case SortMode.Author:
sortedGroups.Sort((x, y) => string.Compare(x.BeatmapSet.Metadata.Author, y.BeatmapSet.Metadata.Author, StringComparison.InvariantCultureIgnoreCase));
break;
case FilterControl.SortMode.Difficulty:
sortedGroups.Sort((x, y) =>
{
float xAverage = 0, yAverage = 0;
int counter = 0;
foreach (BeatmapInfo set in x.BeatmapSet.Beatmaps)
{
xAverage += set.StarDifficulty;
counter++;
}
xAverage /= counter;
counter = 0;
foreach (BeatmapInfo set in y.BeatmapSet.Beatmaps)
{
yAverage += set.StarDifficulty;
counter++;
}
yAverage /= counter;
if (xAverage > yAverage)
return 1;
else
return -1;
});
case SortMode.Difficulty:
sortedGroups.Sort((x, y) => x.BeatmapSet.MaxStarDifficulty.CompareTo(y.BeatmapSet.MaxStarDifficulty));
break;
default:
throw new NotImplementedException();
Sort(SortMode.Artist); // Temporary
break;
}
scrollableContent.Clear(false);

View File

@ -0,0 +1,41 @@
// 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.ComponentModel;
namespace osu.Game.Screens.Select.Filter
{
public enum GroupMode
{
[Description("All")]
All,
[Description("Artist")]
Artist,
[Description("Author")]
Author,
[Description("BPM")]
BPM,
[Description("Collections")]
Collections,
[Description("Date Added")]
DateAdded,
[Description("Difficulty")]
Difficulty,
[Description("Favorites")]
Favorites,
[Description("Length")]
Length,
[Description("My Maps")]
MyMaps,
[Description("No Grouping")]
NoGrouping,
[Description("Rank Achieved")]
RankAchieved,
[Description("Ranked Status")]
RankedStatus,
[Description("Recently Played")]
RecentlyPlayed,
[Description("Title")]
Title
}
}

View File

@ -0,0 +1,27 @@
// 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.ComponentModel;
namespace osu.Game.Screens.Select.Filter
{
public enum SortMode
{
[Description("Artist")]
Artist,
[Description("Author")]
Author,
[Description("BPM")]
BPM,
[Description("Date Added")]
DateAdded,
[Description("Difficulty")]
Difficulty,
[Description("Length")]
Length,
[Description("Rank Achieved")]
RankAchieved,
[Description("Title")]
Title
}
}

View File

@ -9,9 +9,12 @@ using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Input;
using osu.Framework.Graphics.UserInterface;
using osu.Game.Graphics;
using osu.Game.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Select.Filter;
using Container = osu.Framework.Graphics.Containers.Container;
using osu.Framework.Input;
namespace osu.Game.Screens.Select
{
@ -20,10 +23,17 @@ namespace osu.Game.Screens.Select
public Action FilterChanged;
public string Search => searchTextBox.Text;
private OsuTabControl<SortMode> sortTabs;
private TabControl<GroupMode> groupTabs;
private SortMode sort = SortMode.Title;
public SortMode Sort {
public SortMode Sort
{
get { return sort; }
set {
set
{
if (sort != value)
{
sort = value;
@ -32,10 +42,26 @@ namespace osu.Game.Screens.Select
}
}
private GroupMode group = GroupMode.All;
public GroupMode Group
{
get { return group; }
set
{
if (group != value)
{
group = value;
FilterChanged?.Invoke();
}
}
}
public Action Exit;
private SearchTextBox searchTextBox;
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || groupTabs.Contains(screenSpacePos) || sortTabs.Contains(screenSpacePos);
public FilterControl()
{
Children = new Drawable[]
@ -46,18 +72,18 @@ namespace osu.Game.Screens.Select
Alpha = 0.8f,
RelativeSizeAxes = Axes.Both,
},
new FillFlowContainer
new Container
{
Padding = new MarginPadding(20),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
AlwaysReceiveInput = true,
RelativeSizeAxes = Axes.Both,
Width = 0.5f,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Width = 0.4f, // TODO: InnerWidth property or something
Direction = FillDirection.Vertical,
Children = new Drawable[]
{
searchTextBox = new SearchTextBox {
searchTextBox = new SearchTextBox
{
RelativeSizeAxes = Axes.X,
OnChange = (sender, newText) =>
{
@ -66,10 +92,59 @@ namespace osu.Game.Screens.Select
},
Exit = () => Exit?.Invoke(),
},
new GroupSortTabs()
new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Colour = OsuColour.Gray(80),
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
new FillFlowContainer
{
Anchor = Anchor.BottomRight,
Origin = Anchor.BottomRight,
Direction = FillDirection.Horizontal,
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
AlwaysReceiveInput = true,
Children = new Drawable[]
{
groupTabs = new OsuTabControl<GroupMode>
{
RelativeSizeAxes = Axes.X,
Height = 24,
Width = 0.5f,
AutoSort = true
},
//spriteText = new OsuSpriteText
//{
// Font = @"Exo2.0-Bold",
// Text = "Sort results by",
// TextSize = 14,
// Margin = new MarginPadding
// {
// Top = 5,
// Bottom = 5
// },
//},
sortTabs = new OsuTabControl<SortMode>()
{
RelativeSizeAxes = Axes.X,
Width = 0.5f,
Height = 24,
AutoSort = true,
}
}
},
}
}
};
groupTabs.PinTab(GroupMode.All);
groupTabs.PinTab(GroupMode.RecentlyPlayed);
groupTabs.ValueChanged += (sender, value) => Group = value;
sortTabs.ValueChanged += (sender, value) => Sort = value;
}
public void Deactivate()
@ -83,208 +158,18 @@ namespace osu.Game.Screens.Select
searchTextBox.HoldFocus = true;
}
private class TabItem : ClickableContainer
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
public string Text
{
get { return text.Text; }
set { text.Text = value; }
}
private void fadeActive()
{
box.FadeIn(300);
text.FadeColour(Color4.White, 300);
}
private void fadeInactive()
{
box.FadeOut(300);
text.FadeColour(fadeColour, 300);
}
private bool active;
public bool Active
{
get { return active; }
set
{
active = value;
if (active)
fadeActive();
else
fadeInactive();
}
}
private SpriteText text;
private Box box;
private Color4 fadeColour;
protected override bool OnHover(InputState state)
{
if (!active)
fadeActive();
return true;
}
protected override void OnHoverLost(InputState state)
{
if (!active)
fadeInactive();
}
public TabItem()
{
AutoSizeAxes = Axes.Both;
Children = new Drawable[]
{
text = new OsuSpriteText
{
Margin = new MarginPadding(5),
TextSize = 14,
Font = @"Exo2.0-Bold",
},
box = new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Alpha = 0,
Colour = Color4.White,
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
text.Colour = colours.Blue;
fadeColour = colours.Blue;
}
sortTabs.AccentColour = colours.GreenLight;
}
private class GroupSortTabs : Container
{
private TextAwesome groupsEllipsis, sortEllipsis;
private SpriteText sortLabel;
public GroupSortTabs()
{
RelativeSizeAxes = Axes.X;
AutoSizeAxes = Axes.Y;
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.X,
Height = 1,
Colour = OsuColour.Gray(80),
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Children = new Drawable[]
{
new TabItem
{
Text = "All",
Active = true,
},
new TabItem
{
Text = "Recently Played",
Active = false,
},
new TabItem
{
Text = "Collections",
Active = false,
},
groupsEllipsis = new TextAwesome
{
Icon = FontAwesome.fa_ellipsis_h,
Origin = Anchor.TopLeft,
TextSize = 14,
Margin = new MarginPadding { Top = 5, Bottom = 5 },
}
}
},
new FillFlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FillDirection.Horizontal,
Spacing = new Vector2(10, 0),
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Children = new Drawable[]
{
sortLabel = new OsuSpriteText
{
Font = @"Exo2.0-Bold",
Text = "Sort results by",
TextSize = 14,
Margin = new MarginPadding { Top = 5, Bottom = 5 },
},
new TabItem
{
Text = "Artist",
Active = true,
},
sortEllipsis = new TextAwesome
{
Icon = FontAwesome.fa_ellipsis_h,
Origin = Anchor.TopLeft,
TextSize = 14,
Margin = new MarginPadding { Top = 5, Bottom = 5 },
}
}
},
};
}
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args) => true;
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
groupsEllipsis.Colour = colours.Blue;
sortLabel.Colour = colours.GreenLight;
sortEllipsis.Colour = colours.GreenLight;
}
}
public enum SortMode
{
Artist,
BPM,
Author,
DateAdded,
Difficulty,
Length,
RankAchieved,
Title
}
protected override bool OnMouseMove(InputState state) => true;
public enum GroupMode
{
NoGrouping,
Artist,
BPM,
Author,
DateAdded,
Difficulty,
Length,
RankAchieved,
Title,
Collections,
Favorites,
MyMaps,
RankedStatus,
RecentlyPlayed
}
protected override bool OnClick(InputState state) => true;
protected override bool OnDragStart(InputState state) => true;
}
}

View File

@ -26,8 +26,6 @@ namespace osu.Game.Screens.Select
private const float padding = 80;
public override bool Contains(Vector2 screenSpacePos) => true;
public Action OnBack;
public Action OnStart;
@ -69,6 +67,8 @@ namespace osu.Game.Screens.Select
public Footer()
{
AlwaysReceiveInput = true;
const float bottom_tool_height = 50;
RelativeSizeAxes = Axes.X;

View File

@ -83,7 +83,7 @@ namespace osu.Game.Screens.Select.Options
return false;
}
public override bool Contains(Vector2 screenSpacePos) => box.Contains(screenSpacePos);
protected override bool InternalContains(Vector2 screenSpacePos) => box.Contains(screenSpacePos);
public BeatmapOptionsButton()
{

View File

@ -56,31 +56,16 @@ namespace osu.Game.Screens.Select
protected virtual bool ShowFooter => true;
/// <summary>
/// Can be null if <see cref="ShowFooter"/> == false
/// Can be null if <see cref="ShowFooter"/> is false.
/// </summary>
protected readonly BeatmapOptionsOverlay BeatmapOptions;
/// <summary>
/// Can be null if <see cref="ShowFooter"/> == false
/// Can be null if <see cref="ShowFooter"/> is false.
/// </summary>
protected readonly Footer Footer;
private FilterControl filter;
public FilterControl Filter
{
get
{
return filter;
}
private set
{
if (filter != value)
{
filter = value;
filterChanged();
}
}
}
public readonly FilterControl FilterControl;
protected SongSelect()
{
@ -109,7 +94,7 @@ namespace osu.Game.Screens.Select
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
});
Add(filter = new FilterControl
Add(FilterControl = new FilterControl
{
RelativeSizeAxes = Axes.X,
Height = filter_height,
@ -198,9 +183,9 @@ namespace osu.Game.Screens.Select
filterTask = Scheduler.AddDelayed(() =>
{
filterTask = null;
var search = filter.Search;
var search = FilterControl.Search;
BeatmapGroup newSelection = null;
carousel.Sort(filter.Sort);
carousel.Sort(FilterControl.Sort);
foreach (var beatmapGroup in carousel)
{
var set = beatmapGroup.BeatmapSet;
@ -257,7 +242,7 @@ namespace osu.Game.Screens.Select
beatmapInfoWedge.State = Visibility.Visible;
filter.Activate();
FilterControl.Activate();
}
protected override void OnResuming(Screen last)
@ -270,7 +255,7 @@ namespace osu.Game.Screens.Select
Content.ScaleTo(1, 250, EasingTypes.OutSine);
filter.Activate();
FilterControl.Activate();
}
protected override void OnSuspending(Screen next)
@ -279,7 +264,7 @@ namespace osu.Game.Screens.Select
Content.FadeOut(250);
filter.Deactivate();
FilterControl.Deactivate();
base.OnSuspending(next);
}
@ -289,7 +274,7 @@ namespace osu.Game.Screens.Select
Content.FadeOut(100);
filter.Deactivate();
FilterControl.Deactivate();
return base.OnExiting(next);
}

View File

@ -120,7 +120,7 @@
<Compile Include="Modes\Objects\Legacy\LegacyHitObjectType.cs" />
<Compile Include="Modes\Replay.cs" />
<Compile Include="Modes\Score.cs" />
<Compile Include="Modes\ScoreProcesssor.cs" />
<Compile Include="Modes\ScoreProcessor.cs" />
<Compile Include="Modes\UI\HealthDisplay.cs" />
<Compile Include="Modes\UI\HudOverlay.cs" />
<Compile Include="Modes\UI\StandardHealthDisplay.cs" />
@ -197,6 +197,8 @@
<Compile Include="Screens\Play\SkipButton.cs" />
<Compile Include="Modes\UI\StandardComboCounter.cs" />
<Compile Include="Screens\Select\CarouselContainer.cs" />
<Compile Include="Screens\Select\Filter\GroupMode.cs" />
<Compile Include="Screens\Select\Filter\SortMode.cs" />
<Compile Include="Screens\Select\MatchSongSelect.cs" />
<Compile Include="Screens\OsuGameScreen.cs" />
<Compile Include="Beatmaps\Drawables\BeatmapGroup.cs" />
@ -348,6 +350,8 @@
<Compile Include="Overlays\WaveOverlayContainer.cs" />
<Compile Include="Screens\Select\Options\BeatmapOptionsButton.cs" />
<Compile Include="Screens\Select\Options\BeatmapOptionsOverlay.cs" />
<Compile Include="Graphics\UserInterface\OsuTabControl.cs" />
<Compile Include="Graphics\UserInterface\OsuTabItem.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="$(SolutionDir)\osu-framework\osu.Framework\osu.Framework.csproj">

View File

@ -1,4 +1,5 @@
<?xml version="1.0" encoding="utf-8"?>
<!--
Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE