1
0
mirror of https://github.com/ppy/osu.git synced 2025-01-14 02:22:56 +08:00

Merge remote-tracking branch 'upstream/master' into login-updates

This commit is contained in:
Dean Herbert 2017-02-03 12:48:52 +09:00
commit a6fd7f46c3
28 changed files with 1140 additions and 487 deletions

@ -1 +1 @@
Subproject commit b10125a7334c07221503163a289522bddf6b793d
Subproject commit 16a01c7381e3ee8ef6b4fe863ba9232deba04c29

View File

@ -13,6 +13,7 @@ using OpenTK.Graphics;
using osu.Framework.MathUtils;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations;
using osu.Game.Screens.Play;
namespace osu.Desktop.VisualTests.Tests
{

View File

@ -0,0 +1,27 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.GameModes.Testing;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Sprites;
using osu.Game.Graphics.UserInterface;
using osu.Game.Screens.Menu;
using osu.Game.Screens.Play;
using OpenTK.Graphics;
namespace osu.Desktop.VisualTests.Tests
{
class TestCaseTwoLayerButton : TestCase
{
public override string Name => @"TwoLayerButton";
public override string Description => @"Back and skip and what not";
public override void Reset()
{
base.Reset();
Add(new BackButton());
Add(new SkipButton());
}
}
}

View File

@ -183,6 +183,7 @@
<Compile Include="Tests\TestCaseScoreCounter.cs" />
<Compile Include="Tests\TestCaseTextAwesome.cs" />
<Compile Include="Tests\TestCasePlaySongSelect.cs" />
<Compile Include="Tests\TestCaseTwoLayerButton.cs" />
<Compile Include="VisualTestGame.cs" />
<Compile Include="Platform\TestStorage.cs" />
<Compile Include="Tests\TestCaseOptions.cs" />

View File

@ -4,6 +4,7 @@
using System;
using System.IO;
using System.Linq;
using System.Threading;
using osu.Desktop.Beatmaps.IO;
using osu.Framework;
using osu.Framework.Desktop;
@ -26,16 +27,22 @@ namespace osu.Desktop
{
LegacyFilesystemReader.Register();
// Back up the cwd before DesktopGameHost changes it
var cwd = Environment.CurrentDirectory;
using (DesktopGameHost host = Host.GetSuitableHost(@"osu", true))
{
if (!host.IsPrimaryInstance)
{
var importer = new BeatmapImporter(host);
// Restore the cwd so relative paths given at the command line work correctly
Directory.SetCurrentDirectory(cwd);
foreach (var file in args)
if (!importer.Import(file).Wait(1000))
{
Console.WriteLine(@"Importing {0}", file);
if (!importer.Import(Path.GetFullPath(file)).Wait(3000))
throw new TimeoutException(@"IPC took too long to send");
Console.WriteLine(@"Sent import requests to running instance");
}
}
else
{

View File

@ -7,6 +7,7 @@ using osu.Game.Modes.UI;
using OpenTK;
using OpenTK.Input;
using osu.Framework.Graphics.Primitives;
using osu.Game.Screens.Play;
namespace osu.Game.Modes.Osu.UI
{

View File

@ -31,31 +31,32 @@ namespace osu.Game.Beatmaps.Drawables
public List<BeatmapPanel> BeatmapPanels;
public BeatmapSetInfo BeatmapSet;
public BeatmapGroupState State
{
get { return state; }
set
{
state = value;
switch (state)
switch (value)
{
case BeatmapGroupState.Expanded:
foreach (BeatmapPanel panel in BeatmapPanels)
panel.FadeIn(250);
Header.State = PanelSelectedState.Selected;
if (SelectedPanel != null)
SelectedPanel.State = PanelSelectedState.Selected;
foreach (BeatmapPanel panel in BeatmapPanels)
panel.State = panel == SelectedPanel ? PanelSelectedState.Selected : PanelSelectedState.NotSelected;
break;
case BeatmapGroupState.Collapsed:
Header.State = PanelSelectedState.NotSelected;
if (SelectedPanel != null)
SelectedPanel.State = PanelSelectedState.NotSelected;
foreach (BeatmapPanel panel in BeatmapPanels)
panel.FadeOut(300, EasingTypes.OutQuint);
panel.State = PanelSelectedState.Hidden;
break;
case BeatmapGroupState.Hidden:
Header.State = PanelSelectedState.Hidden;
foreach (BeatmapPanel panel in BeatmapPanels)
panel.State = PanelSelectedState.Hidden;
break;
}
state = value;
}
}
@ -75,6 +76,7 @@ namespace osu.Game.Beatmaps.Drawables
RelativeSizeAxes = Axes.X,
}).ToList();
BeatmapSet = set;
Header.AddDifficultyIcons(BeatmapPanels);
}
@ -111,5 +113,6 @@ namespace osu.Game.Beatmaps.Drawables
{
Collapsed,
Expanded,
Hidden,
}
}

View File

@ -2,14 +2,11 @@
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Colour;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.MathUtils;
using osu.Game.Database;
using osu.Game.Graphics;
using osu.Game.Graphics.Backgrounds;
@ -17,7 +14,6 @@ using osu.Game.Graphics.UserInterface;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Input;
using osu.Game.Modes;
namespace osu.Game.Beatmaps.Drawables
{
@ -33,6 +29,7 @@ namespace osu.Game.Beatmaps.Drawables
protected override void Selected()
{
base.Selected();
GainedSelection?.Invoke(this);
background.ColourInfo = ColourInfo.GradientVertical(

View File

@ -68,12 +68,6 @@ namespace osu.Game.Beatmaps.Drawables
};
}
protected override void LoadComplete()
{
base.LoadComplete();
FadeInFromZero(250);
}
protected override void Selected()
{
base.Selected();

View File

@ -55,6 +55,7 @@ namespace osu.Game.Beatmaps.Drawables
{
switch (state)
{
case PanelSelectedState.Hidden:
case PanelSelectedState.NotSelected:
Deselected();
break;
@ -62,6 +63,11 @@ namespace osu.Game.Beatmaps.Drawables
Selected();
break;
}
if (state == PanelSelectedState.Hidden)
FadeOut(300, EasingTypes.OutQuint);
else
FadeIn(250);
}
private PanelSelectedState state = PanelSelectedState.NotSelected;
@ -112,6 +118,7 @@ namespace osu.Game.Beatmaps.Drawables
enum PanelSelectedState
{
Hidden,
NotSelected,
Selected
}

View File

@ -3,6 +3,7 @@
using OpenTK;
using osu.Framework.Allocation;
using osu.Framework.Configuration;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Cursor;
@ -10,6 +11,8 @@ using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using osu.Framework.Graphics.Transformations;
using osu.Framework.Input;
using osu.Game.Configuration;
using System;
namespace osu.Game.Graphics.Cursor
{
@ -38,6 +41,8 @@ namespace osu.Game.Graphics.Cursor
class OsuCursor : Container
{
private BindableDouble cursorScale;
private Sprite sprite;
public OsuCursor()
{
Origin = Anchor.Centre;
@ -45,15 +50,24 @@ namespace osu.Game.Graphics.Cursor
}
[BackgroundDependencyLoader]
private void load(TextureStore textures)
private void load(TextureStore textures, OsuConfigManager config)
{
cursorScale = (BindableDouble)config.GetBindable<double>(OsuConfig.CursorSize);
Children = new Drawable[]
{
new Sprite
sprite = new Sprite
{
Scale = new Vector2((float)cursorScale),
Texture = textures.Get(@"Cursor/cursor")
}
};
cursorScale.ValueChanged += scaleChanged;
}
private void scaleChanged(object sender, EventArgs e)
{
sprite.Scale = new Vector2((float)cursorScale);
}
}
}

View File

@ -3,163 +3,26 @@
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Sample;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transformations;
using osu.Framework.Input;
namespace osu.Game.Graphics.UserInterface
{
// Basic back button as it was on stable (kinda). No skinning possible for now
public class BackButton : ClickableContainer
public class BackButton : TwoLayerButton
{
private TextAwesome icon;
private Box leftBox;
private Box rightBox;
private const double transform_time = 600;
private const int pulse_length = 250;
private const float shear = 0.15f;
public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50);
public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50);
private AudioSample sampleClick;
public BackButton()
{
Size = SIZE_RETRACTED;
}
public override bool Contains(Vector2 screenSpacePos) => leftBox.Contains(screenSpacePos) || rightBox.Contains(screenSpacePos);
protected override bool OnHover(InputState state)
{
icon.ClearTransformations();
ResizeTo(SIZE_EXTENDED, transform_time, EasingTypes.OutElastic);
int duration = 0; //(int)(Game.Audio.BeatLength / 2);
if (duration == 0) duration = pulse_length;
double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
double startTime = Time.Current + offset;
// basic pulse
icon.Transforms.Add(new TransformScale
{
StartValue = new Vector2(1.1f),
EndValue = Vector2.One,
StartTime = startTime,
EndTime = startTime + duration,
Easing = EasingTypes.Out,
LoopCount = -1,
LoopDelay = duration
});
return true;
}
protected override void OnHoverLost(InputState state)
{
icon.ClearTransformations();
ResizeTo(SIZE_RETRACTED, transform_time, EasingTypes.OutElastic);
int duration = 0; //(int)(Game.Audio.BeatLength);
if (duration == 0) duration = pulse_length * 2;
double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
double startTime = Time.Current + offset;
// slow pulse
icon.Transforms.Add(new TransformScale
{
StartValue = new Vector2(1.1f),
EndValue = Vector2.One,
StartTime = startTime,
EndTime = startTime + duration,
Easing = EasingTypes.Out,
LoopCount = -1,
LoopDelay = duration
});
Text = @"Back";
Icon = FontAwesome.fa_osu_left_o;
Anchor = Anchor.BottomLeft;
Origin = Anchor.BottomLeft;
}
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
{
sampleClick = audio.Sample.Get(@"Menu/menuback");
Children = new Drawable[]
{
new Container
{
RelativeSizeAxes = Axes.Both,
Width = 0.4f,
Children = new Drawable[]
{
leftBox = new Box
{
RelativeSizeAxes = Axes.Both,
Colour = colours.PinkDark,
Shear = new Vector2(shear, 0),
},
icon = new TextAwesome
{
Anchor = Anchor.Centre,
TextSize = 25,
Icon = FontAwesome.fa_osu_left_o
},
}
},
new Container
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
RelativeSizeAxes = Axes.Both,
Width = 0.6f,
Children = new Drawable[]
{
rightBox = new Box
{
Colour = colours.Pink,
Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft,
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
EdgeSmoothness = new Vector2(1.5f, 0),
},
new SpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Text = @"Back",
}
}
}
};
}
protected override bool OnClick(InputState state)
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Colour = Color4.White.Opacity(0.5f),
};
Add(flash);
flash.FadeOutFromOne(200);
flash.Expire();
sampleClick.Play();
return base.OnClick(state);
ActivationSound = audio.Sample.Get(@"Menu/menuback");
Colour = colours.Pink;
HoverColour = colours.PinkDark;
}
}
}

View File

@ -0,0 +1,237 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Audio.Sample;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Transformations;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
{
public class TwoLayerButton : ClickableContainer
{
private TextAwesome icon;
public Box IconLayer;
public Box TextLayer;
private const int transform_time = 600;
private const int pulse_length = 250;
private const float shear = 0.1f;
public static readonly Vector2 SIZE_EXTENDED = new Vector2(140, 50);
public static readonly Vector2 SIZE_RETRACTED = new Vector2(100, 50);
public AudioSample ActivationSound;
private SpriteText text;
public Color4 HoverColour;
private Container c1;
private Container c2;
public Color4 Colour
{
set
{
TextLayer.Colour = value;
IconLayer.Colour = value;
}
}
public override Anchor Origin
{
get
{
return base.Origin;
}
set
{
base.Origin = value;
c1.Origin = c1.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopLeft : Anchor.TopRight;
c2.Origin = c2.Anchor = (value & Anchor.x2) > 0 ? Anchor.TopRight : Anchor.TopLeft;
Margin = new MarginPadding
{
Right = (value & Anchor.x2) > 0 ? -SIZE_RETRACTED.X * shear * 0.5f : 0
};
c1.Depth = (value & Anchor.x2) > 0 ? 0 : 1;
c2.Depth = (value & Anchor.x2) > 0 ? 1 : 0;
}
}
public TwoLayerButton()
{
Size = SIZE_RETRACTED;
Children = new Drawable[]
{
c2 = new Container
{
RelativeSizeAxes = Axes.Both,
Width = 0.4f,
Children = new Drawable[]
{
new Container {
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
EdgeEffect = new EdgeEffect {
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
Children = new [] {
IconLayer = new Box
{
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(1.5f, 0),
},
}
},
icon = new TextAwesome
{
Anchor = Anchor.Centre,
TextSize = 25,
},
}
},
c1 = new Container
{
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
RelativeSizeAxes = Axes.Both,
Width = 0.6f,
Children = new Drawable[]
{
new Container {
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Masking = true,
EdgeEffect = new EdgeEffect {
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.2f),
Offset = new Vector2(2, 0),
Radius = 2,
},
Children = new [] {
TextLayer = new Box
{
Origin = Anchor.TopLeft,
Anchor = Anchor.TopLeft,
RelativeSizeAxes = Axes.Both,
EdgeSmoothness = new Vector2(1.5f, 0),
},
}
},
text = new SpriteText
{
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
}
}
},
};
}
public FontAwesome Icon
{
set
{
icon.Icon = value;
}
}
public string Text
{
set
{
text.Text = value;
}
}
public override bool Contains(Vector2 screenSpacePos) => IconLayer.Contains(screenSpacePos) || TextLayer.Contains(screenSpacePos);
protected override bool OnHover(InputState state)
{
icon.ClearTransformations();
ResizeTo(SIZE_EXTENDED, transform_time, EasingTypes.OutElastic);
int duration = 0; //(int)(Game.Audio.BeatLength / 2);
if (duration == 0) duration = pulse_length;
IconLayer.FadeColour(HoverColour, transform_time, EasingTypes.OutElastic);
double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
double startTime = Time.Current + offset;
// basic pulse
icon.Transforms.Add(new TransformScale
{
StartValue = new Vector2(1.1f),
EndValue = Vector2.One,
StartTime = startTime,
EndTime = startTime + duration,
Easing = EasingTypes.Out,
LoopCount = -1,
LoopDelay = duration
});
return true;
}
protected override void OnHoverLost(InputState state)
{
icon.ClearTransformations();
ResizeTo(SIZE_RETRACTED, transform_time, EasingTypes.OutElastic);
IconLayer.FadeColour(TextLayer.Colour, transform_time, EasingTypes.OutElastic);
int duration = 0; //(int)(Game.Audio.BeatLength);
if (duration == 0) duration = pulse_length * 2;
double offset = 0; //(1 - Game.Audio.SyncBeatProgress) * duration;
double startTime = Time.Current + offset;
// slow pulse
icon.Transforms.Add(new TransformScale
{
StartValue = new Vector2(1.1f),
EndValue = Vector2.One,
StartTime = startTime,
EndTime = startTime + duration,
Easing = EasingTypes.Out,
LoopCount = -1,
LoopDelay = duration
});
}
protected override bool OnClick(InputState state)
{
var flash = new Box
{
RelativeSizeAxes = Axes.Both,
Shear = new Vector2(shear, 0),
Colour = Color4.White.Opacity(0.5f),
};
Add(flash);
flash.Alpha = 1;
flash.FadeOut(500, EasingTypes.OutQuint);
flash.Expire();
ActivationSound.Play();
return base.OnClick(state);
}
}
}

View File

@ -8,6 +8,7 @@ using osu.Game.Graphics.UserInterface;
using osu.Game.Modes.Objects;
using OpenTK;
using osu.Framework.Graphics.Primitives;
using osu.Game.Screens.Play;
namespace osu.Game.Modes.UI
{

View File

@ -1,212 +1,212 @@
using System;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using osu.Game.Graphics;
using osu.Framework.Input;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Containers;
using System;
using OpenTK;
using OpenTK.Input;
using OpenTK.Graphics;
using osu.Game.Graphics;
using osu.Framework.Input;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transformations;
using System.Threading.Tasks;
namespace osu.Game.Overlays.Pause
{
public class PauseOverlay : OverlayContainer
{
private const int transition_duration = 200;
private const int button_height = 70;
private const float background_alpha = 0.75f;
public Action OnResume;
public Action OnRetry;
public Action OnQuit;
public int Retries
{
set
{
namespace osu.Game.Overlays.Pause
{
public class PauseOverlay : OverlayContainer
{
private const int transition_duration = 200;
private const int button_height = 70;
private const float background_alpha = 0.75f;
public Action OnResume;
public Action OnRetry;
public Action OnQuit;
public int Retries
{
set
{
if (retryCounterContainer != null)
{
// "You've retried 1,065 times in this session"
// "You've retried 1 time in this session"
// "You've retried 1 time in this session"
retryCounterContainer.Children = new Drawable[]
{
new SpriteText
{
Text = "You've retried ",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new SpriteText
{
Text = String.Format("{0:n0}", value),
Font = @"Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new SpriteText
{
Text = $" time{((value == 1) ? "" : "s")} in this session",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
{
new SpriteText
{
Text = "You've retried ",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new SpriteText
{
Text = String.Format("{0:n0}", value),
Font = @"Exo2.0-Bold",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
},
new SpriteText
{
Text = $" time{((value == 1) ? "" : "s")} in this session",
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f),
TextSize = 18
}
};
}
}
}
private FlowContainer retryCounterContainer;
public override bool Contains(Vector2 screenSpacePos) => true;
public override bool HandleInput => State == Visibility.Visible;
protected override void PopIn() => FadeIn(transition_duration, EasingTypes.In);
protected override void PopOut() => FadeOut(transition_duration, EasingTypes.In);
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.Escape)
{
}
}
}
private FlowContainer retryCounterContainer;
public override bool Contains(Vector2 screenSpacePos) => true;
public override bool HandleInput => State == Visibility.Visible;
protected override void PopIn() => FadeIn(transition_duration, EasingTypes.In);
protected override void PopOut() => FadeOut(transition_duration, EasingTypes.In);
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.Escape)
{
if (State == Visibility.Hidden) return false;
resume();
return true;
}
return base.OnKeyDown(state, args);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
return true;
}
return base.OnKeyDown(state, args);
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = background_alpha,
},
new FlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FlowDirection.VerticalOnly,
Spacing = new Vector2(0f, 50f),
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Children = new Drawable[]
{
new FlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FlowDirection.VerticalOnly,
Spacing = new Vector2(0f, 20f),
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Children = new Drawable[]
{
new SpriteText
{
Text = @"paused",
Font = @"Exo2.0-Medium",
Spacing = new Vector2(5, 0),
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
TextSize = 30,
Colour = colours.Yellow,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
},
new SpriteText
{
Text = @"you're not going to do what i think you're going to do, are ya?",
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
}
}
},
new FlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Masking = true,
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.6f),
Radius = 50
},
Children = new Drawable[]
{
new ResumeButton
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = resume
},
new RetryButton
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
OnRetry?.Invoke();
Hide();
}
},
new QuitButton
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
OnQuit?.Invoke();
Hide();
}
}
}
},
retryCounterContainer = new FlowContainer
{
AutoSizeAxes = Axes.Both,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre
}
}
},
new PauseProgressBar
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Width = 1f
Children = new Drawable[]
{
new Box
{
RelativeSizeAxes = Axes.Both,
Colour = Color4.Black,
Alpha = background_alpha,
},
new FlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Direction = FlowDirection.VerticalOnly,
Spacing = new Vector2(0f, 50f),
Origin = Anchor.Centre,
Anchor = Anchor.Centre,
Children = new Drawable[]
{
new FlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FlowDirection.VerticalOnly,
Spacing = new Vector2(0f, 20f),
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Children = new Drawable[]
{
new SpriteText
{
Text = @"paused",
Font = @"Exo2.0-Medium",
Spacing = new Vector2(5, 0),
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
TextSize = 30,
Colour = colours.Yellow,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
},
new SpriteText
{
Text = @"you're not going to do what i think you're going to do, are ya?",
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Shadow = true,
ShadowColour = new Color4(0, 0, 0, 0.25f)
}
}
},
new FlowContainer
{
RelativeSizeAxes = Axes.X,
AutoSizeAxes = Axes.Y,
Masking = true,
EdgeEffect = new EdgeEffect
{
Type = EdgeEffectType.Shadow,
Colour = Color4.Black.Opacity(0.6f),
Radius = 50
},
Children = new Drawable[]
{
new ResumeButton
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = resume
},
new RetryButton
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
OnRetry?.Invoke();
Hide();
}
},
new QuitButton
{
RelativeSizeAxes = Axes.X,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre,
Height = button_height,
Action = delegate
{
OnQuit?.Invoke();
Hide();
}
}
}
},
retryCounterContainer = new FlowContainer
{
AutoSizeAxes = Axes.Both,
Origin = Anchor.TopCentre,
Anchor = Anchor.TopCentre
}
}
},
new PauseProgressBar
{
Origin = Anchor.BottomCentre,
Anchor = Anchor.BottomCentre,
Width = 1f
}
};
};
Retries = 0;
}
private void resume()
}
private void resume()
{
OnResume?.Invoke();
Hide();
}
OnResume?.Invoke();
Hide();
}
public PauseOverlay()
{
RelativeSizeAxes = Axes.Both;
}
}
}
}
}

View File

@ -22,17 +22,19 @@ namespace osu.Game.Screens.Backgrounds
{
return beatmap;
}
set
{
if (beatmap == value)
if (beatmap == value && beatmap != null)
return;
beatmap = value;
Schedule(() =>
{
Background newBackground = new BeatmapBackground(beatmap);
Background newBackground;
if (beatmap == null)
newBackground = new Background(@"Backgrounds/bg1");
else
newBackground = new BeatmapBackground(beatmap);
newBackground.Preload(Game, delegate
{
@ -84,7 +86,6 @@ namespace osu.Game.Screens.Backgrounds
{
Sprite.Texture = beatmap.Background;
}
}
}
}

View File

@ -99,7 +99,7 @@ namespace osu.Game.Screens.Menu
{
Action = onOsuLogo,
Origin = Anchor.Centre,
Anchor = Anchor.Centre
Anchor = Anchor.Centre,
}
};

View File

@ -1,16 +1,15 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Graphics;
using osu.Framework;
using osu.Framework.Allocation;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.Textures;
using OpenTK;
using OpenTK.Graphics;
namespace osu.Game.Graphics.UserInterface
namespace osu.Game.Screens.Play
{
public abstract class KeyCounter : Container
{

View File

@ -2,11 +2,11 @@
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Graphics.Containers;
namespace osu.Game.Graphics.UserInterface
namespace osu.Game.Screens.Play
{
public class KeyCounterCollection : FlowContainer<KeyCounter>
{

View File

@ -1,11 +1,11 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK.Input;
using osu.Framework.Graphics;
using osu.Framework.Input;
using OpenTK.Input;
namespace osu.Game.Graphics.UserInterface
namespace osu.Game.Screens.Play
{
public class KeyCounterKeyboard : KeyCounter
{

View File

@ -1,12 +1,12 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using OpenTK.Input;
using osu.Framework.Graphics;
using osu.Framework.Input;
using OpenTK;
using OpenTK.Input;
namespace osu.Game.Graphics.UserInterface
namespace osu.Game.Screens.Play
{
public class KeyCounterMouse : KeyCounter
{

View File

@ -1,22 +1,16 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using System.Linq;
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Audio.Track;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Graphics;
using osu.Framework.Input;
using osu.Framework.Platform;
using osu.Framework.Timing;
using osu.Game.Database;
using osu.Game.Modes;
using osu.Game.Modes.Objects;
using osu.Game.Modes.Objects.Drawables;
using osu.Game.Screens.Backgrounds;
using OpenTK.Input;
using MouseState = osu.Framework.Input.MouseState;
using OpenTK;
using osu.Framework.GameModes;
using osu.Game.Modes.UI;
@ -25,6 +19,8 @@ using osu.Game.Configuration;
using osu.Game.Overlays.Pause;
using osu.Framework.Configuration;
using System;
using System.Linq;
using osu.Game.Beatmaps;
using OpenTK.Graphics;
using osu.Framework.Graphics.Containers;
@ -65,6 +61,7 @@ namespace osu.Game.Screens.Play
private ScoreProcessor scoreProcessor;
private HitRenderer hitRenderer;
private Bindable<int> dimLevel;
private SkipButton skipButton;
private ScoreOverlay scoreOverlay;
private PauseOverlay pauseOverlay;
@ -149,6 +146,7 @@ namespace osu.Game.Screens.Play
Children = new Drawable[]
{
hitRenderer,
skipButton = new SkipButton { Alpha = 0 },
}
},
scoreOverlay,
@ -156,6 +154,33 @@ namespace osu.Game.Screens.Play
};
}
private void initializeSkipButton()
{
const double skip_required_cutoff = 3000;
const double fade_time = 300;
double firstHitObject = Beatmap.Beatmap.HitObjects.First().StartTime;
if (firstHitObject < skip_required_cutoff)
{
skipButton.Alpha = 0;
skipButton.Expire();
return;
}
skipButton.FadeInFromZero(fade_time);
skipButton.Action = () =>
{
sourceClock.Seek(firstHitObject - skip_required_cutoff - fade_time);
skipButton.Action = null;
};
skipButton.Delay(firstHitObject - skip_required_cutoff - fade_time);
skipButton.FadeOut(fade_time);
skipButton.Expire();
}
public void Pause(bool force = false)
{
if (canPause || force)
@ -220,6 +245,7 @@ namespace osu.Game.Screens.Play
Schedule(() =>
{
sourceClock.Start();
initializeSkipButton();
});
}
@ -252,7 +278,7 @@ namespace osu.Game.Screens.Play
protected override void OnEntering(GameMode last)
{
base.OnEntering(last);
(Background as BackgroundModeBeatmap)?.BlurTo(Vector2.Zero, 1000);
Background?.FadeTo((100f- dimLevel)/100, 1000);

View File

@ -0,0 +1,32 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using osu.Framework.Allocation;
using osu.Framework.Audio;
using osu.Framework.Graphics;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
namespace osu.Game.Screens.Play
{
public class SkipButton : TwoLayerButton
{
private readonly double skipDestination;
public SkipButton()
{
Text = @"Skip";
Icon = FontAwesome.fa_osu_right_o;
Anchor = Anchor.BottomRight;
Origin = Anchor.BottomRight;
}
[BackgroundDependencyLoader]
private void load(AudioManager audio, OsuColour colours)
{
ActivationSound = audio.Sample.Get(@"Menu/menuhit");
Colour = colours.Yellow;
HoverColour = colours.YellowDark;
}
}
}

View File

@ -1,26 +1,27 @@
//Copyright (c) 2007-2016 ppy Pty Ltd <contact@ppy.sh>.
//Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
using OpenTK;
using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transformations;
using osu.Game.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Lists;
using osu.Game.Beatmaps.Drawables;
using OpenTK;
using osu.Framework.Caching;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Transformations;
using osu.Game.Database;
using System;
using System.Collections.Generic;
using System.Linq;
using osu.Framework.Extensions.IEnumerableExtensions;
using osu.Framework.Lists;
using osu.Game.Beatmaps.Drawables;
using osu.Framework.Timing;
using osu.Framework.Input;
using OpenTK.Input;
using osu.Framework.MathUtils;
using System.Collections;
using osu.Framework.MathUtils;
namespace osu.Game.Screens.Select
{
class CarouselContainer : ScrollContainer
class CarouselContainer : ScrollContainer, IEnumerable<BeatmapGroup>
{
private Container<Panel> scrollableContent;
private List<BeatmapGroup> groups = new List<BeatmapGroup>();
@ -28,29 +29,29 @@ namespace osu.Game.Screens.Select
public BeatmapGroup SelectedGroup { get; private set; }
public BeatmapPanel SelectedPanel { get; private set; }
private List<float> yPositions = new List<float>();
private CarouselLifetimeList<Panel> Lifetime;
public CarouselContainer()
{
DistanceDecayJump = 0.01;
Add(scrollableContent = new Container<Panel>(Lifetime = new CarouselLifetimeList<Panel>(DepthComparer))
{
RelativeSizeAxes = Axes.X,
});
}
internal class CarouselLifetimeList<T> : LifetimeList<Panel>
{
public CarouselLifetimeList(IComparer<Panel> comparer)
: base(comparer)
{
}
public int StartIndex;
private List<float> yPositions = new List<float>();
private CarouselLifetimeList<Panel> Lifetime;
public CarouselContainer()
{
DistanceDecayJump = 0.01;
Add(scrollableContent = new Container<Panel>(Lifetime = new CarouselLifetimeList<Panel>(DepthComparer))
{
RelativeSizeAxes = Axes.X,
});
}
internal class CarouselLifetimeList<T> : LifetimeList<Panel>
{
public CarouselLifetimeList(IComparer<Panel> comparer)
: base(comparer)
{
}
public int StartIndex;
public int EndIndex;
public override bool Update(FrameTimeInfo time)
{
bool anyAliveChanged = false;
@ -76,9 +77,9 @@ namespace osu.Game.Screens.Select
}
return anyAliveChanged;
}
}
}
}
public void AddGroup(BeatmapGroup group)
{
group.State = BeatmapGroupState.Collapsed;
@ -96,10 +97,10 @@ namespace osu.Game.Screens.Select
computeYPositions();
}
private void movePanel(Panel panel, bool advance, ref float currentY)
private void movePanel(Panel panel, bool advance, bool animated, ref float currentY)
{
yPositions.Add(currentY);
panel.MoveToY(currentY, 750, EasingTypes.OutExpo);
panel.MoveToY(currentY, animated && (panel.IsOnScreen || panel.State != PanelSelectedState.Hidden) ? 750 : 0, EasingTypes.OutExpo);
if (advance)
currentY += panel.DrawHeight + 5;
@ -109,7 +110,7 @@ namespace osu.Game.Screens.Select
/// Computes the target Y positions for every panel in the carousel.
/// </summary>
/// <returns>The Y position of the currently selected panel.</returns>
private float computeYPositions()
private float computeYPositions(bool animated = true)
{
yPositions.Clear();
@ -118,7 +119,7 @@ namespace osu.Game.Screens.Select
foreach (BeatmapGroup group in groups)
{
movePanel(group.Header, true, ref currentY);
movePanel(group.Header, group.State != BeatmapGroupState.Hidden, animated, ref currentY);
if (group.State == BeatmapGroupState.Expanded)
{
@ -136,7 +137,7 @@ namespace osu.Game.Screens.Select
if (panel.Alpha == 0)
panel.MoveToY(headerY);
movePanel(panel, true, ref currentY);
movePanel(panel, true, animated, ref currentY);
}
}
else
@ -146,7 +147,7 @@ namespace osu.Game.Screens.Select
foreach (BeatmapPanel panel in group.BeatmapPanels)
{
panel.MoveToX(0, 500, EasingTypes.OutExpo);
movePanel(panel, false, ref currentY);
movePanel(panel, false, animated, ref currentY);
}
}
}
@ -157,30 +158,30 @@ namespace osu.Game.Screens.Select
return selectedY;
}
public void SelectBeatmap(BeatmapInfo beatmap)
public void SelectBeatmap(BeatmapInfo beatmap, bool animated = true)
{
foreach (BeatmapGroup group in groups)
{
var panel = group.BeatmapPanels.FirstOrDefault(p => p.Beatmap.Equals(beatmap));
if (panel != null)
{
SelectGroup(group, panel);
SelectGroup(group, panel, animated);
return;
}
}
}
public void SelectGroup(BeatmapGroup group, BeatmapPanel panel)
public void SelectGroup(BeatmapGroup group, BeatmapPanel panel, bool animated = true)
{
if (SelectedGroup != null && SelectedGroup != group)
if (SelectedGroup != null && SelectedGroup != group && SelectedGroup.State != BeatmapGroupState.Hidden)
SelectedGroup.State = BeatmapGroupState.Collapsed;
SelectedGroup = group;
panel.State = PanelSelectedState.Selected;
SelectedPanel = panel;
float selectedY = computeYPositions();
ScrollTo(selectedY);
float selectedY = computeYPositions(animated);
ScrollTo(selectedY, animated);
}
private static float offsetX(float dist, float halfHeight)
@ -201,7 +202,9 @@ namespace osu.Game.Screens.Select
/// <param name="halfHeight">Half the draw height of the carousel container.</param>
private void updatePanel(Panel p, float halfHeight)
{
float panelDrawY = p.Position.Y - Current + p.DrawHeight / 2;
var height = p.IsVisible ? p.DrawHeight : 0;
float panelDrawY = p.Position.Y - Current + height / 2;
float dist = Math.Abs(1f - panelDrawY / halfHeight);
// Setting the origin position serves as an additive position on top of potential
@ -223,11 +226,11 @@ namespace osu.Game.Screens.Select
float drawHeight = DrawHeight;
float halfHeight = drawHeight / 2;
foreach (Panel p in Lifetime.AliveItems)
{
float panelPosY = p.Position.Y;
p.IsOnScreen = panelPosY >= Current - p.DrawHeight && panelPosY <= Current + drawHeight;
updatePanel(p, halfHeight);
foreach (Panel p in Lifetime.AliveItems)
{
float panelPosY = p.Position.Y;
p.IsOnScreen = panelPosY >= Current - p.DrawHeight && panelPosY <= Current + drawHeight;
updatePanel(p, halfHeight);
}
// Determine range of indices for items that are now definitely on screen to be added
@ -243,7 +246,8 @@ namespace osu.Game.Screens.Select
for (int i = firstIndex; i < lastIndex; ++i)
{
Panel p = Lifetime[i];
p.IsOnScreen = true;
if (p.State != PanelSelectedState.Hidden)
p.IsOnScreen = true; //we don't want to update the on-screen state of hidden pannels as they have incorrect (stacked) y values.
updatePanel(p, halfHeight);
}
}
@ -271,34 +275,50 @@ namespace osu.Game.Screens.Select
break;
}
if (direction != 0)
if (direction == 0)
return base.OnKeyDown(state, args);
if (!skipDifficulties)
{
int index = SelectedGroup.BeatmapPanels.IndexOf(SelectedPanel) + direction;
int i = SelectedGroup.BeatmapPanels.IndexOf(SelectedPanel) + direction;
if (!skipDifficulties && index >= 0 && index < SelectedGroup.BeatmapPanels.Count)
//changing difficulty panel, not set.
SelectGroup(SelectedGroup, SelectedGroup.BeatmapPanels[index]);
else
if (i >= 0 && i < SelectedGroup.BeatmapPanels.Count)
{
index = (groups.IndexOf(SelectedGroup) + direction + groups.Count) % groups.Count;
SelectBeatmap(groups[index].BeatmapPanels.First().Beatmap);
//changing difficulty panel, not set.
SelectGroup(SelectedGroup, SelectedGroup.BeatmapPanels[i]);
return true;
}
return true;
}
return base.OnKeyDown(state, args);
}
public void SelectRandom()
{
if (groups.Count < 1)
return;
BeatmapGroup group = groups[RNG.Next(groups.Count)];
BeatmapPanel panel = group?.BeatmapPanels.First();
if (panel == null)
return;
SelectGroup(group, panel);
int startIndex = groups.IndexOf(SelectedGroup);
int index = startIndex;
do
{
index = (index + direction + groups.Count) % groups.Count;
if (groups[index].State != BeatmapGroupState.Hidden)
{
SelectBeatmap(groups[index].BeatmapPanels.First().Beatmap);
return true;
}
} while (index != startIndex);
return true;
}
public void SelectRandom()
{
if (groups.Count < 1)
return;
BeatmapGroup group = groups[RNG.Next(groups.Count)];
BeatmapPanel panel = group?.BeatmapPanels.First();
if (panel == null)
return;
SelectGroup(group, panel);
}
public IEnumerator<BeatmapGroup> GetEnumerator() => groups.GetEnumerator();
IEnumerator IEnumerable.GetEnumerator() => GetEnumerator();
}
}

View File

@ -0,0 +1,279 @@
using System;
using OpenTK;
using OpenTK.Graphics;
using osu.Framework.Allocation;
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.Framework.Input;
using osu.Game.Graphics;
namespace osu.Game.Screens.Select
{
public class FilterControl : Container
{
public Action FilterChanged;
public string Search => searchTextBox.Text;
public SortMode Sort { get; private set; } = SortMode.Title;
public Action Exit;
private SearchTextBox searchTextBox;
public FilterControl()
{
AutoSizeAxes = Axes.Y;
Children = new Drawable[]
{
new Box
{
Colour = Color4.Black,
Alpha = 0.6f,
RelativeSizeAxes = Axes.Both,
},
new FlowContainer
{
Padding = new MarginPadding(20),
AutoSizeAxes = Axes.Y,
RelativeSizeAxes = Axes.X,
Anchor = Anchor.TopRight,
Origin = Anchor.TopRight,
Width = 0.4f, // TODO: InnerWidth property or something
Direction = FlowDirection.VerticalOnly,
Children = new Drawable[]
{
searchTextBox = new SearchTextBox { RelativeSizeAxes = Axes.X },
new GroupSortTabs()
}
}
};
searchTextBox.OnChange += (TextBox sender, bool newText) =>
{
if (newText)
FilterChanged?.Invoke();
};
searchTextBox.Exit = () => Exit?.Invoke();
}
public void Deactivate()
{
searchTextBox.GrabFocus = false;
searchTextBox.TriggerFocusLost();
}
public void Activate()
{
searchTextBox.GrabFocus = true;
}
private class TabItem : ClickableContainer
{
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 SpriteText
{
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;
}
}
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 FlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FlowDirection.HorizontalOnly,
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,
TextSize = 14,
Margin = new MarginPadding { Top = 5, Bottom = 5 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
}
},
new FlowContainer
{
AutoSizeAxes = Axes.Both,
Direction = FlowDirection.HorizontalOnly,
Spacing = new Vector2(10, 0),
Origin = Anchor.TopRight,
Anchor = Anchor.TopRight,
Children = new Drawable[]
{
sortLabel = new SpriteText
{
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,
TextSize = 14,
Margin = new MarginPadding { Top = 5, Bottom = 5 },
Origin = Anchor.BottomLeft,
Anchor = Anchor.BottomLeft,
}
}
},
};
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
groupsEllipsis.Colour = colours.Blue;
sortLabel.Colour = colours.GreenLight;
sortEllipsis.Colour = colours.GreenLight;
}
}
public enum SortMode
{
Arist,
BPM,
Creator,
DateAdded,
Difficulty,
Length,
RankAchieved,
Title
}
public enum GroupMode
{
NoGrouping,
Arist,
BPM,
Creator,
DateAdded,
Difficulty,
Length,
RankAchieved,
Title,
Collections,
Favorites,
MyMaps,
RankedStatus,
RecentlyPlayed
}
}
}

View File

@ -29,6 +29,9 @@ using osu.Game.Graphics.Containers;
using osu.Game.Graphics;
using osu.Framework.Input;
using OpenTK.Input;
using osu.Game.Graphics;
using System.Collections.Generic;
using osu.Framework.Threading;
namespace osu.Game.Screens.Select
{
@ -50,6 +53,8 @@ namespace osu.Game.Screens.Select
private AudioSample sampleChangeDifficulty;
private AudioSample sampleChangeBeatmap;
private List<BeatmapGroup> beatmapGroups;
private Footer footer;
@ -82,10 +87,11 @@ namespace osu.Game.Screens.Select
}
Player player;
FilterControl filter;
private void start()
{
if (player != null)
if (player != null || Beatmap == null)
return;
//in the future we may want to move this logic to a PlayerLoader gamemode or similar, so we can rely on the SongSelect transition
@ -111,7 +117,8 @@ namespace osu.Game.Screens.Select
OsuGame osuGame, OsuColour colours)
{
const float carouselWidth = 640;
const float bottomToolHeight = 50;
beatmapGroups = new List<BeatmapGroup>();
Children = new Drawable[]
{
new ParallaxContainer
@ -134,6 +141,13 @@ namespace osu.Game.Screens.Select
Anchor = Anchor.CentreRight,
Origin = Anchor.CentreRight,
},
filter = new FilterControl
{
Position = wedged_container_start_position,
RelativeSizeAxes = Axes.X,
FilterChanged = filterChanged,
Exit = Exit,
},
beatmapInfoWedge = new BeatmapInfoWedge
{
Alpha = 0,
@ -174,9 +188,43 @@ namespace osu.Game.Screens.Select
Task.Factory.StartNew(() => addBeatmapSets(game, initialAddSetsTask.Token), initialAddSetsTask.Token);
}
private ScheduledDelegate filterTask;
private void filterChanged()
{
filterTask?.Cancel();
filterTask = Scheduler.AddDelayed(() =>
{
filterTask = null;
var search = filter.Search;
BeatmapGroup newSelection = null;
foreach (var beatmapGroup in carousel)
{
var set = beatmapGroup.BeatmapSet;
bool match = string.IsNullOrEmpty(search)
|| (set.Metadata.Artist ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1
|| (set.Metadata.ArtistUnicode ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1
|| (set.Metadata.Title ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1
|| (set.Metadata.TitleUnicode ?? "").IndexOf(search, StringComparison.InvariantCultureIgnoreCase) != -1;
if (match)
{
beatmapGroup.State = BeatmapGroupState.Collapsed;
if (newSelection == null || beatmapGroup.BeatmapSet.OnlineBeatmapSetID == Beatmap.BeatmapSetInfo.OnlineBeatmapSetID)
newSelection = beatmapGroup;
}
else
{
beatmapGroup.State = BeatmapGroupState.Hidden;
}
}
if (newSelection != null)
carousel.SelectBeatmap(newSelection.BeatmapSet.Beatmaps[0], false);
}, 250);
}
private void onDatabaseOnBeatmapSetAdded(BeatmapSetInfo s)
{
Schedule(() => addBeatmapSet(s, Game));
Schedule(() => addBeatmapSet(s, Game, true));
}
protected override void OnEntering(GameMode last)
@ -190,6 +238,8 @@ namespace osu.Game.Screens.Select
beatmapInfoWedge.MoveToX(wedged_container_start_position.X - 50);
beatmapInfoWedge.MoveToX(wedged_container_start_position.X, 800, EasingTypes.OutQuint);
filter.Activate();
}
protected override void OnResuming(GameMode last)
@ -203,6 +253,8 @@ namespace osu.Game.Screens.Select
Content.FadeIn(250);
Content.ScaleTo(1, 250, EasingTypes.OutSine);
filter.Activate();
}
protected override void OnSuspending(GameMode next)
@ -210,6 +262,8 @@ namespace osu.Game.Screens.Select
Content.ScaleTo(1.1f, 250, EasingTypes.InSine);
Content.FadeOut(250);
filter.Deactivate();
base.OnSuspending(next);
}
@ -219,6 +273,8 @@ namespace osu.Game.Screens.Select
beatmapInfoWedge.RotateTo(10, 800, EasingTypes.InQuint);
Content.FadeOut(100);
filter.Deactivate();
return base.OnExiting(next);
}
@ -239,18 +295,15 @@ namespace osu.Game.Screens.Select
private void changeBackground(WorkingBeatmap beatmap)
{
if (beatmap == null)
return;
var backgroundModeBeatmap = Background as BackgroundModeBeatmap;
if (backgroundModeBeatmap != null)
{
backgroundModeBeatmap.Beatmap = beatmap;
// TODO: Remove this once we have non-nullable Beatmap
(Background as BackgroundModeBeatmap)?.BlurTo(BACKGROUND_BLUR, 1000);
backgroundModeBeatmap.BlurTo(BACKGROUND_BLUR, 1000);
}
beatmapInfoWedge.UpdateBeatmap(beatmap);
if (beatmap != null)
beatmapInfoWedge.UpdateBeatmap(beatmap);
}
/// <summary>
@ -262,11 +315,9 @@ namespace osu.Game.Screens.Select
//todo: change background in selectionChanged instead; support per-difficulty backgrounds.
changeBackground(beatmap);
selectBeatmap(beatmap.BeatmapInfo);
carousel.SelectBeatmap(beatmap.BeatmapInfo);
}
private void selectBeatmap(BeatmapInfo beatmap) => carousel.SelectBeatmap(beatmap);
/// <summary>
/// selection has been changed as the result of interaction with the carousel.
/// </summary>
@ -301,7 +352,7 @@ namespace osu.Game.Screens.Select
}
}
private void addBeatmapSet(BeatmapSetInfo beatmapSet, BaseGame game)
private void addBeatmapSet(BeatmapSetInfo beatmapSet, BaseGame game, bool select = false)
{
beatmapSet = database.GetWithChildren<BeatmapSetInfo>(beatmapSet.ID);
beatmapSet.Beatmaps.ForEach(b =>
@ -314,7 +365,7 @@ namespace osu.Game.Screens.Select
var beatmap = new WorkingBeatmap(beatmapSet.Beatmaps.FirstOrDefault(), beatmapSet, database);
var group = new BeatmapGroup(beatmap)
var group = new BeatmapGroup(beatmap, beatmapSet)
{
SelectionChanged = selectionChanged,
StartRequested = b => start()
@ -324,9 +375,11 @@ namespace osu.Game.Screens.Select
//this likely won't scale so well, but allows us to completely async the loading flow.
Task.WhenAll(group.BeatmapPanels.Select(panel => panel.Preload(game))).ContinueWith(task => Schedule(delegate
{
beatmapGroups.Add(group);
carousel.AddGroup(group);
if (Beatmap == null)
if (Beatmap == null || select)
carousel.SelectBeatmap(beatmapSet.Beatmaps.First());
else
{

View File

@ -0,0 +1,86 @@
using System;
using System.Linq;
using OpenTK;
using OpenTK.Graphics;
using OpenTK.Input;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Primitives;
using osu.Framework.Graphics.Sprites;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input;
using osu.Game.Graphics;
namespace osu.Game.Screens.Select
{
public class SearchTextBox : TextBox
{
protected override Color4 BackgroundUnfocused => new Color4(10, 10, 10, 255);
protected override Color4 BackgroundFocused => new Color4(10, 10, 10, 255);
public Action Exit;
public bool GrabFocus = false;
private SpriteText placeholder;
protected override string InternalText
{
get { return base.InternalText; }
set
{
base.InternalText = value;
if (placeholder != null)
{
if (string.IsNullOrEmpty(value))
placeholder.Text = "type to search";
else
placeholder.Text = string.Empty;
}
}
}
public SearchTextBox()
{
Height = 35;
TextContainer.Padding = new MarginPadding(5);
Add(new Drawable[]
{
placeholder = new SpriteText
{
Font = @"Exo2.0-MediumItalic",
Text = "type to search",
Colour = new Color4(180, 180, 180, 255),
Anchor = Anchor.CentreLeft,
Origin = Anchor.CentreLeft,
Margin = new MarginPadding { Left = 10 },
},
new TextAwesome
{
Icon = FontAwesome.fa_search,
Origin = Anchor.CentreRight,
Anchor = Anchor.CentreRight,
Margin = new MarginPadding { Right = 10 },
}
});
}
protected override void Update()
{
if (GrabFocus && !HasFocus && IsVisible)
TriggerFocus();
base.Update();
}
protected override void OnFocusLost(InputState state)
{
if (state.Keyboard.Keys.Any(key => key == Key.Escape))
Exit?.Invoke();
base.OnFocusLost(state);
}
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
{
if (args.Key == Key.Left || args.Key == Key.Right || args.Key == Key.Enter)
return false;
return base.OnKeyDown(state, args);
}
}
}

View File

@ -68,6 +68,7 @@
<Compile Include="Graphics\Cursor\CursorTrail.cs" />
<Compile Include="Graphics\UserInterface\BackButton.cs" />
<Compile Include="Graphics\UserInterface\OsuTextBox.cs" />
<Compile Include="Graphics\UserInterface\TwoLayerButton.cs" />
<Compile Include="Modes\Objects\HitObjectParser.cs" />
<Compile Include="Modes\Score.cs" />
<Compile Include="Modes\ScoreProcesssor.cs" />
@ -121,6 +122,7 @@
<Compile Include="Screens\Multiplayer\MatchCreate.cs" />
<Compile Include="Screens\Play\FailDialog.cs" />
<Compile Include="Screens\Play\PlayerInputManager.cs" />
<Compile Include="Screens\Play\SkipButton.cs" />
<Compile Include="Screens\Select\CarouselContainer.cs" />
<Compile Include="Screens\Select\MatchSongSelect.cs" />
<Compile Include="Screens\OsuGameMode.cs" />
@ -148,10 +150,10 @@
<Compile Include="Graphics\Cursor\OsuCursorContainer.cs" />
<Compile Include="Graphics\Processing\RatioAdjust.cs" />
<Compile Include="Graphics\TextAwesome.cs" />
<Compile Include="Graphics\UserInterface\KeyCounter.cs" />
<Compile Include="Graphics\UserInterface\KeyCounterKeyboard.cs" />
<Compile Include="Graphics\UserInterface\KeyCounterCollection.cs" />
<Compile Include="Graphics\UserInterface\KeyCounterMouse.cs" />
<Compile Include="Screens\Play\KeyCounter.cs" />
<Compile Include="Screens\Play\KeyCounterKeyboard.cs" />
<Compile Include="Screens\Play\KeyCounterCollection.cs" />
<Compile Include="Screens\Play\KeyCounterMouse.cs" />
<Compile Include="Graphics\UserInterface\PercentageCounter.cs" />
<Compile Include="Graphics\UserInterface\ScoreCounter.cs" />
<Compile Include="Graphics\UserInterface\StarCounter.cs" />
@ -237,6 +239,8 @@
<Compile Include="Configuration\ScreenshotFormat.cs" />
<Compile Include="Configuration\ConfineMouseMode.cs" />
<Compile Include="Graphics\OsuColour.cs" />
<Compile Include="Screens\Select\FilterControl.cs" />
<Compile Include="Screens\Select\SearchTextBox.cs" />
<Compile Include="Screens\Select\FooterButton.cs" />
<Compile Include="Screens\Select\Footer.cs" />
<Compile Include="Overlays\Pause\PauseButton.cs" />
@ -274,4 +278,4 @@
<Target Name="AfterBuild">
</Target>
-->
</Project>
</Project>