mirror of
https://github.com/ppy/osu.git
synced 2025-03-21 21:47:20 +08:00
Merge remote-tracking branch 'smoogipooo/menu-mvvm' into menu-bar
# Conflicts: # osu-framework
This commit is contained in:
commit
fc4437b91a
@ -1 +1 @@
|
||||
Subproject commit a5fd0c82c8f86d41c80ac1b0b07727cb312330f1
|
||||
Subproject commit 8fe24d449fdcb975f5a799a40d92377116dd7d4f
|
@ -3,9 +3,8 @@
|
||||
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.Cursor;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
@ -67,9 +66,9 @@ namespace osu.Desktop.Tests.Visual
|
||||
);
|
||||
}
|
||||
|
||||
private class MyContextMenuContainer : Container, IHasContextMenu
|
||||
private class MyContextMenuContainer : Container, IHasOsuContextMenu
|
||||
{
|
||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
||||
public OsuContextMenuItem[] ContextMenuItems => new[]
|
||||
{
|
||||
new OsuContextMenuItem(@"Some option"),
|
||||
new OsuContextMenuItem(@"Highlighted option", MenuItemType.Highlighted),
|
||||
@ -81,16 +80,16 @@ namespace osu.Desktop.Tests.Visual
|
||||
};
|
||||
}
|
||||
|
||||
private class AnotherContextMenuContainer : Container, IHasContextMenu
|
||||
private class AnotherContextMenuContainer : Container, IHasOsuContextMenu
|
||||
{
|
||||
public ContextMenuItem[] ContextMenuItems => new ContextMenuItem[]
|
||||
public OsuContextMenuItem[] ContextMenuItems => new[]
|
||||
{
|
||||
new OsuContextMenuItem(@"Simple option"),
|
||||
new OsuContextMenuItem(@"Simple very very long option"),
|
||||
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted) { Action = () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted) { Action = () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive) { Action = () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive) { Action = () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint) },
|
||||
new OsuContextMenuItem(@"Change width", MenuItemType.Highlighted, () => this.ResizeWidthTo(Width * 2, 100, Easing.OutQuint)),
|
||||
new OsuContextMenuItem(@"Change height", MenuItemType.Highlighted, () => this.ResizeHeightTo(Height * 2, 100, Easing.OutQuint)),
|
||||
new OsuContextMenuItem(@"Change width back", MenuItemType.Destructive, () => this.ResizeWidthTo(Width / 2, 100, Easing.OutQuint)),
|
||||
new OsuContextMenuItem(@"Change height back", MenuItemType.Destructive, () => this.ResizeHeightTo(Height / 2, 100, Easing.OutQuint)),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
35
osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs
Normal file
35
osu.Game.Rulesets.Osu/Replays/OsuReplayInputHandler.cs
Normal file
@ -0,0 +1,35 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using OpenTK;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.Replays
|
||||
{
|
||||
public class OsuReplayInputHandler : FramedReplayInputHandler
|
||||
{
|
||||
public OsuReplayInputHandler(Replay replay)
|
||||
: base(replay)
|
||||
{
|
||||
}
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
List<OsuAction> actions = new List<OsuAction>();
|
||||
|
||||
if (CurrentFrame?.MouseLeft ?? false) actions.Add(OsuAction.LeftButton);
|
||||
if (CurrentFrame?.MouseRight ?? false) actions.Add(OsuAction.RightButton);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new ReplayState<OsuAction>
|
||||
{
|
||||
Mouse = new ReplayMouseState(ToScreenSpace(Position ?? Vector2.Zero)),
|
||||
PressedActions = actions
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
@ -10,9 +10,11 @@ using osu.Game.Rulesets.Osu.Beatmaps;
|
||||
using osu.Game.Rulesets.Osu.Judgements;
|
||||
using osu.Game.Rulesets.Osu.Objects;
|
||||
using osu.Game.Rulesets.Osu.Objects.Drawables;
|
||||
using osu.Game.Rulesets.Osu.Replays;
|
||||
using osu.Game.Rulesets.Osu.Scoring;
|
||||
using osu.Game.Rulesets.Scoring;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using osu.Game.Rulesets.Replays;
|
||||
|
||||
namespace osu.Game.Rulesets.Osu.UI
|
||||
{
|
||||
@ -49,6 +51,8 @@ namespace osu.Game.Rulesets.Osu.UI
|
||||
return null;
|
||||
}
|
||||
|
||||
protected override FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new OsuReplayInputHandler(replay);
|
||||
|
||||
protected override Vector2 GetPlayfieldAspectAdjust() => new Vector2(0.75f);
|
||||
}
|
||||
}
|
||||
|
@ -78,6 +78,7 @@
|
||||
<Compile Include="OsuDifficulty\Skills\Speed.cs" />
|
||||
<Compile Include="OsuDifficulty\Utils\History.cs" />
|
||||
<Compile Include="OsuInputManager.cs" />
|
||||
<Compile Include="Replays\OsuReplayInputHandler.cs" />
|
||||
<Compile Include="UI\Cursor\CursorTrail.cs" />
|
||||
<Compile Include="UI\Cursor\GameplayCursor.cs" />
|
||||
<Compile Include="UI\OsuSettings.cs" />
|
||||
|
@ -4,7 +4,6 @@
|
||||
using osu.Game.Rulesets.Replays;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.Taiko.Replays
|
||||
{
|
||||
@ -17,21 +16,18 @@ namespace osu.Game.Rulesets.Taiko.Replays
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
var keys = new List<Key>();
|
||||
var actions = new List<TaikoAction>();
|
||||
|
||||
if (CurrentFrame?.MouseRight1 == true)
|
||||
keys.Add(Key.F);
|
||||
actions.Add(TaikoAction.LeftCentre);
|
||||
if (CurrentFrame?.MouseRight2 == true)
|
||||
keys.Add(Key.J);
|
||||
actions.Add(TaikoAction.RightCentre);
|
||||
if (CurrentFrame?.MouseLeft1 == true)
|
||||
keys.Add(Key.D);
|
||||
actions.Add(TaikoAction.LeftRim);
|
||||
if (CurrentFrame?.MouseLeft2 == true)
|
||||
keys.Add(Key.K);
|
||||
actions.Add(TaikoAction.RightRim);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new InputState { Keyboard = new ReplayKeyboardState(keys) }
|
||||
};
|
||||
return new List<InputState> { new ReplayState<TaikoAction> { PressedActions = actions } };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
9
osu.Game/Graphics/Cursor/IHasOsuContextMenu.cs
Normal file
9
osu.Game/Graphics/Cursor/IHasOsuContextMenu.cs
Normal file
@ -0,0 +1,9 @@
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Graphics.Cursor
|
||||
{
|
||||
public interface IHasOsuContextMenu : IHasContextMenu<OsuContextMenuItem>
|
||||
{
|
||||
}
|
||||
}
|
@ -7,8 +7,8 @@ using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Graphics.Cursor
|
||||
{
|
||||
public class OsuContextMenuContainer : ContextMenuContainer
|
||||
public class OsuContextMenuContainer : ContextMenuContainer<OsuContextMenuItem>
|
||||
{
|
||||
protected override ContextMenu<ContextMenuItem> CreateContextMenu() => new OsuContextMenu<ContextMenuItem>();
|
||||
protected override Menu<OsuContextMenuItem> CreateMenu() => new OsuContextMenu<OsuContextMenuItem>();
|
||||
}
|
||||
}
|
@ -1,52 +1,145 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuContextMenu<TItem> : ContextMenu<TItem>
|
||||
where TItem : ContextMenuItem
|
||||
public class OsuContextMenu<TItem> : OsuMenu<TItem>
|
||||
where TItem : OsuContextMenuItem
|
||||
{
|
||||
protected override Menu<TItem> CreateMenu() => new CustomMenu();
|
||||
private const int fade_duration = 250;
|
||||
|
||||
public class CustomMenu : Menu<TItem>
|
||||
public OsuContextMenu()
|
||||
{
|
||||
private const int fade_duration = 250;
|
||||
|
||||
public CustomMenu()
|
||||
CornerRadius = 5;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.1f),
|
||||
Radius = 4,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.ContextMenuGray;
|
||||
}
|
||||
|
||||
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
|
||||
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
|
||||
|
||||
protected override MarginPadding ItemFlowContainerPadding => new MarginPadding { Vertical = DrawableOsuContextMenuItem.MARGIN_VERTICAL };
|
||||
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(TItem item) => new DrawableOsuContextMenuItem(this, item);
|
||||
|
||||
#region DrawableOsuContextMenuItem
|
||||
private class DrawableOsuContextMenuItem : DrawableMenuItem
|
||||
{
|
||||
private const int margin_horizontal = 17;
|
||||
private const int text_size = 17;
|
||||
private const int transition_length = 80;
|
||||
public const int MARGIN_VERTICAL = 4;
|
||||
|
||||
private SampleChannel sampleClick;
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
private OsuSpriteText text;
|
||||
private OsuSpriteText textBold;
|
||||
|
||||
public DrawableOsuContextMenuItem(Menu<TItem> menu, TItem item)
|
||||
: base(item)
|
||||
{
|
||||
CornerRadius = 5;
|
||||
ItemsContainer.Padding = new MarginPadding { Vertical = OsuContextMenuItem.MARGIN_VERTICAL };
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.1f),
|
||||
Radius = 4,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
private void load(AudioManager audio)
|
||||
{
|
||||
Background.Colour = colours.ContextMenuGray;
|
||||
sampleHover = audio.Sample.Get(@"UI/generic-hover");
|
||||
sampleClick = audio.Sample.Get(@"UI/generic-click");
|
||||
|
||||
BackgroundColour = Color4.Transparent;
|
||||
BackgroundColourHover = OsuColour.FromHex(@"172023");
|
||||
|
||||
updateTextColour();
|
||||
}
|
||||
|
||||
protected override void AnimateOpen() => this.FadeIn(fade_duration, Easing.OutQuint);
|
||||
protected override void AnimateClose() => this.FadeOut(fade_duration, Easing.OutQuint);
|
||||
|
||||
protected override void UpdateContentHeight()
|
||||
private void updateTextColour()
|
||||
{
|
||||
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
|
||||
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
|
||||
switch (Item.Type)
|
||||
{
|
||||
case MenuItemType.Standard:
|
||||
textBold.Colour = text.Colour = Color4.White;
|
||||
break;
|
||||
case MenuItemType.Destructive:
|
||||
textBold.Colour = text.Colour = Color4.Red;
|
||||
break;
|
||||
case MenuItemType.Highlighted:
|
||||
textBold.Colour = text.Colour = OsuColour.FromHex(@"ffcc22");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
sampleHover.Play();
|
||||
textBold.FadeIn(transition_length, Easing.OutQuint);
|
||||
text.FadeOut(transition_length, Easing.OutQuint);
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
textBold.FadeOut(transition_length, Easing.OutQuint);
|
||||
text.FadeIn(transition_length, Easing.OutQuint);
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
sampleClick.Play();
|
||||
return base.OnClick(state);
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new Container
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Text = Item.Text,
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
},
|
||||
textBold = new OsuSpriteText
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Text = Item.Text,
|
||||
Font = @"Exo2.0-Bold",
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
@ -1,114 +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 OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Audio;
|
||||
using osu.Framework.Audio.Sample;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using System;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuContextMenuItem : ContextMenuItem
|
||||
public class OsuContextMenuItem : MenuItem
|
||||
{
|
||||
private const int transition_length = 80;
|
||||
private const int margin_horizontal = 17;
|
||||
public const int MARGIN_VERTICAL = 4;
|
||||
private const int text_size = 17;
|
||||
public readonly MenuItemType Type;
|
||||
|
||||
private OsuSpriteText text;
|
||||
private OsuSpriteText textBold;
|
||||
|
||||
private SampleChannel sampleClick;
|
||||
private SampleChannel sampleHover;
|
||||
|
||||
private readonly MenuItemType type;
|
||||
|
||||
protected override Container CreateTextContainer(string title) => new Container
|
||||
public OsuContextMenuItem(string text, MenuItemType type = MenuItemType.Standard)
|
||||
: base(text)
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
text = new OsuSpriteText
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Text = title,
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
},
|
||||
textBold = new OsuSpriteText
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Alpha = 0,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.CentreLeft,
|
||||
TextSize = text_size,
|
||||
Text = title,
|
||||
Font = @"Exo2.0-Bold",
|
||||
Margin = new MarginPadding { Horizontal = margin_horizontal, Vertical = MARGIN_VERTICAL },
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
public OsuContextMenuItem(string title, MenuItemType type = MenuItemType.Standard) : base(title)
|
||||
{
|
||||
this.type = type;
|
||||
Type = type;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
public OsuContextMenuItem(string text, MenuItemType type, Action action)
|
||||
: base(text, action)
|
||||
{
|
||||
sampleHover = audio.Sample.Get(@"UI/generic-hover");
|
||||
sampleClick = audio.Sample.Get(@"UI/generic-click");
|
||||
|
||||
BackgroundColour = Color4.Transparent;
|
||||
BackgroundColourHover = OsuColour.FromHex(@"172023");
|
||||
|
||||
updateTextColour();
|
||||
}
|
||||
|
||||
private void updateTextColour()
|
||||
{
|
||||
switch (type)
|
||||
{
|
||||
case MenuItemType.Standard:
|
||||
textBold.Colour = text.Colour = Color4.White;
|
||||
break;
|
||||
case MenuItemType.Destructive:
|
||||
textBold.Colour = text.Colour = Color4.Red;
|
||||
break;
|
||||
case MenuItemType.Highlighted:
|
||||
textBold.Colour = text.Colour = OsuColour.FromHex(@"ffcc22");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
sampleHover.Play();
|
||||
textBold.FadeIn(transition_length, Easing.OutQuint);
|
||||
text.FadeOut(transition_length, Easing.OutQuint);
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
textBold.FadeOut(transition_length, Easing.OutQuint);
|
||||
text.FadeIn(transition_length, Easing.OutQuint);
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
sampleClick.Play();
|
||||
return base.OnClick(state);
|
||||
Type = type;
|
||||
}
|
||||
}
|
||||
}
|
@ -1,9 +1,9 @@
|
||||
// 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.Linq;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
@ -16,52 +16,118 @@ namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuDropdown<T> : Dropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new OsuDropdownHeader { AccentColour = AccentColour };
|
||||
|
||||
protected override Menu CreateMenu() => new OsuMenu();
|
||||
|
||||
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 MenuItems.OfType<OsuDropdownMenuItem>())
|
||||
item.AccentColour = value;
|
||||
}
|
||||
}
|
||||
public readonly Bindable<Color4?> AccentColour = new Bindable<Color4?>();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
if (accentColour == null)
|
||||
AccentColour = colours.PinkDarker;
|
||||
if (AccentColour.Value == null)
|
||||
AccentColour.Value = colours.PinkDarker;
|
||||
}
|
||||
|
||||
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value) => new OsuDropdownMenuItem(text, value) { AccentColour = AccentColour };
|
||||
|
||||
public class OsuDropdownMenuItem : DropdownMenuItem<T>
|
||||
protected override DropdownHeader CreateHeader()
|
||||
{
|
||||
public OsuDropdownMenuItem(string text, T current) : base(text, current)
|
||||
var newHeader = new OsuDropdownHeader();
|
||||
newHeader.AccentColour.BindTo(AccentColour);
|
||||
|
||||
return newHeader;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu()
|
||||
{
|
||||
var newMenu = new OsuDropdownMenu();
|
||||
newMenu.AccentColour.BindTo(AccentColour);
|
||||
|
||||
return newMenu;
|
||||
}
|
||||
|
||||
#region OsuDropdownMenu
|
||||
protected class OsuDropdownMenu : DropdownMenu
|
||||
{
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
public OsuDropdownMenu()
|
||||
{
|
||||
Foreground.Padding = new MarginPadding(2);
|
||||
CornerRadius = 4;
|
||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||
}
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 6;
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
|
||||
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
|
||||
|
||||
Children = new[]
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(5);
|
||||
|
||||
// todo: this uses the same styling as OsuMenu. hopefully we can just use OsuMenu in the future with some refactoring
|
||||
protected override void UpdateMenuHeight()
|
||||
{
|
||||
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
|
||||
this.ResizeHeightTo(State == MenuState.Opened ? actualHeight : 0, 300, Easing.OutQuint);
|
||||
}
|
||||
|
||||
public readonly Bindable<Color4?> AccentColour = new Bindable<Color4?>();
|
||||
|
||||
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(DropdownMenuItem<T> item)
|
||||
{
|
||||
var newItem = new DrawableOsuDropdownMenuItem(item);
|
||||
newItem.AccentColour.BindTo(AccentColour);
|
||||
|
||||
return newItem;
|
||||
}
|
||||
|
||||
#region DrawableOsuDropdownMenuItem
|
||||
protected class DrawableOsuDropdownMenuItem : DrawableDropdownMenuItem
|
||||
{
|
||||
public readonly Bindable<Color4?> AccentColour = new Bindable<Color4?>();
|
||||
|
||||
private SpriteIcon chevron;
|
||||
protected OsuSpriteText Label;
|
||||
|
||||
private Color4 nonAccentHoverColour;
|
||||
private Color4 nonAccentSelectedColour;
|
||||
|
||||
public DrawableOsuDropdownMenuItem(DropdownMenuItem<T> item)
|
||||
: base(item)
|
||||
{
|
||||
new FillFlowContainer
|
||||
Foreground.Padding = new MarginPadding(2);
|
||||
|
||||
Masking = true;
|
||||
CornerRadius = 6;
|
||||
|
||||
AccentColour.ValueChanged += updateAccent;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = Color4.Transparent;
|
||||
nonAccentHoverColour = colours.PinkDarker;
|
||||
nonAccentSelectedColour = Color4.Black.Opacity(0.5f);
|
||||
}
|
||||
|
||||
private void updateAccent(Color4? newValue)
|
||||
{
|
||||
BackgroundColourHover = newValue ?? nonAccentHoverColour;
|
||||
BackgroundColourSelected = newValue ?? nonAccentSelectedColour;
|
||||
UpdateBackgroundColour();
|
||||
UpdateForegroundColour();
|
||||
}
|
||||
|
||||
protected override void UpdateForegroundColour()
|
||||
{
|
||||
base.UpdateForegroundColour();
|
||||
chevron.Alpha = IsHovered ? 1 : 0;
|
||||
}
|
||||
|
||||
protected override Drawable CreateContent() => new FillFlowContainer
|
||||
{
|
||||
Direction = FillDirection.Horizontal,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Chevron = new SpriteIcon
|
||||
chevron = new SpriteIcon
|
||||
{
|
||||
AlwaysPresent = true,
|
||||
Icon = FontAwesome.fa_chevron_right,
|
||||
@ -72,47 +138,18 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
},
|
||||
Label = new OsuSpriteText {
|
||||
Text = text,
|
||||
Label = new OsuSpriteText
|
||||
{
|
||||
Text = Item.Text,
|
||||
Origin = Anchor.CentreLeft,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private Color4? accentColour;
|
||||
|
||||
protected readonly SpriteIcon Chevron;
|
||||
protected readonly OsuSpriteText Label;
|
||||
|
||||
protected override void FormatForeground(bool hover = false)
|
||||
{
|
||||
base.FormatForeground(hover);
|
||||
Chevron.Alpha = hover ? 1 : 0;
|
||||
}
|
||||
|
||||
public Color4 AccentColour
|
||||
{
|
||||
get { return accentColour.GetValueOrDefault(); }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
BackgroundColourHover = BackgroundColourSelected = value;
|
||||
FormatBackground();
|
||||
FormatForeground();
|
||||
}
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = Color4.Transparent;
|
||||
BackgroundColourHover = accentColour ?? colours.PinkDarker;
|
||||
BackgroundColourSelected = Color4.Black.Opacity(0.5f);
|
||||
};
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
#endregion
|
||||
|
||||
public class OsuDropdownHeader : DropdownHeader
|
||||
{
|
||||
@ -125,16 +162,7 @@ namespace osu.Game.Graphics.UserInterface
|
||||
|
||||
protected readonly SpriteIcon Icon;
|
||||
|
||||
private Color4? accentColour;
|
||||
public virtual Color4 AccentColour
|
||||
{
|
||||
get { return accentColour.GetValueOrDefault(); }
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
BackgroundColourHover = value;
|
||||
}
|
||||
}
|
||||
public readonly Bindable<Color4?> AccentColour = new Bindable<Color4?>();
|
||||
|
||||
public OsuDropdownHeader()
|
||||
{
|
||||
@ -161,13 +189,20 @@ namespace osu.Game.Graphics.UserInterface
|
||||
Size = new Vector2(20),
|
||||
}
|
||||
};
|
||||
|
||||
AccentColour.ValueChanged += accentColourChanged;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||
BackgroundColourHover = accentColour ?? colours.PinkDarker;
|
||||
BackgroundColourHover = AccentColour?.Value ?? colours.PinkDarker;
|
||||
}
|
||||
|
||||
private void accentColourChanged(Color4? newValue)
|
||||
{
|
||||
BackgroundColourHover = newValue ?? Color4.White;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,6 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
@ -9,24 +8,24 @@ using osu.Framework.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class OsuMenu : Menu
|
||||
public class OsuMenu<TItem> : Menu<TItem>
|
||||
where TItem : MenuItem
|
||||
{
|
||||
public OsuMenu()
|
||||
{
|
||||
CornerRadius = 4;
|
||||
Background.Colour = Color4.Black.Opacity(0.5f);
|
||||
|
||||
ItemsContainer.Padding = new MarginPadding(5);
|
||||
BackgroundColour = Color4.Black.Opacity(0.5f);
|
||||
}
|
||||
|
||||
protected override void AnimateOpen() => this.FadeIn(300, Easing.OutQuint);
|
||||
|
||||
protected override void AnimateClose() => this.FadeOut(300, Easing.OutQuint);
|
||||
|
||||
protected override void UpdateContentHeight()
|
||||
protected override void UpdateMenuHeight()
|
||||
{
|
||||
var actualHeight = (RelativeSizeAxes & Axes.Y) > 0 ? 1 : ContentHeight;
|
||||
this.ResizeTo(new Vector2(1, State == MenuState.Opened ? actualHeight : 0), 300, Easing.OutQuint);
|
||||
this.ResizeHeightTo(State == MenuState.Opened ? actualHeight : 0, 300, Easing.OutQuint);
|
||||
}
|
||||
|
||||
protected override MarginPadding ItemFlowContainerPadding => new MarginPadding(5);
|
||||
}
|
||||
}
|
||||
|
@ -48,9 +48,9 @@ namespace osu.Game.Graphics.UserInterface
|
||||
set
|
||||
{
|
||||
accentColour = value;
|
||||
var dropDown = Dropdown as OsuTabDropdown;
|
||||
if (dropDown != null)
|
||||
dropDown.AccentColour = value;
|
||||
var dropdown = Dropdown as OsuTabDropdown;
|
||||
if (dropdown != null)
|
||||
dropdown.AccentColour.Value = value;
|
||||
foreach (var item in TabContainer.Children.OfType<OsuTabItem>())
|
||||
item.AccentColour = value;
|
||||
}
|
||||
@ -140,57 +140,65 @@ namespace osu.Game.Graphics.UserInterface
|
||||
protected override void OnDeactivated() => fadeInactive();
|
||||
}
|
||||
|
||||
// todo: this needs to go
|
||||
private class OsuTabDropdown : OsuDropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new OsuTabDropdownHeader
|
||||
{
|
||||
AccentColour = AccentColour,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
};
|
||||
|
||||
protected override DropdownMenuItem<T> CreateMenuItem(string text, T value)
|
||||
{
|
||||
var item = base.CreateMenuItem(text, value);
|
||||
item.ForegroundColourHover = Color4.Black;
|
||||
return item;
|
||||
}
|
||||
|
||||
public OsuTabDropdown()
|
||||
{
|
||||
DropdownMenu.Anchor = Anchor.TopRight;
|
||||
DropdownMenu.Origin = Anchor.TopRight;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
DropdownMenu.Background.Colour = Color4.Black.Opacity(0.7f);
|
||||
DropdownMenu.MaxHeight = 400;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu()
|
||||
{
|
||||
var menu = new OsuTabDropdownMenu();
|
||||
menu.AccentColour.BindTo(AccentColour);
|
||||
return menu;
|
||||
}
|
||||
|
||||
protected override DropdownHeader CreateHeader()
|
||||
{
|
||||
var newHeader = new OsuTabDropdownHeader
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight
|
||||
};
|
||||
|
||||
newHeader.AccentColour.BindTo(AccentColour);
|
||||
|
||||
return newHeader;
|
||||
}
|
||||
|
||||
private class OsuTabDropdownMenu : OsuDropdownMenu
|
||||
{
|
||||
public OsuTabDropdownMenu()
|
||||
{
|
||||
Anchor = Anchor.TopRight;
|
||||
Origin = Anchor.TopRight;
|
||||
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||
MaxHeight = 400;
|
||||
}
|
||||
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(DropdownMenuItem<T> item)
|
||||
{
|
||||
var poop = new DrawableOsuTabDropdownMenuItem(this, item);
|
||||
poop.AccentColour.BindTo(AccentColour);
|
||||
return poop;
|
||||
}
|
||||
|
||||
private class DrawableOsuTabDropdownMenuItem : DrawableOsuDropdownMenuItem
|
||||
{
|
||||
public DrawableOsuTabDropdownMenuItem(Menu<DropdownMenuItem<T>> menu, DropdownMenuItem<T> item)
|
||||
: base(item)
|
||||
{
|
||||
ForegroundColourHover = Color4.Black;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
protected 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;
|
||||
@ -219,6 +227,25 @@ namespace osu.Game.Graphics.UserInterface
|
||||
};
|
||||
|
||||
Padding = new MarginPadding { Left = 5, Right = 5 };
|
||||
|
||||
AccentColour.ValueChanged += accentColourChanged;
|
||||
}
|
||||
|
||||
private void accentColourChanged(Color4? newValue)
|
||||
{
|
||||
Foreground.Colour = newValue ?? Color4.White;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
67
osu.Game/Graphics/UserInterface/ProgressBar.cs
Normal file
67
osu.Game/Graphics/UserInterface/ProgressBar.cs
Normal file
@ -0,0 +1,67 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Graphics.UserInterface
|
||||
{
|
||||
public class ProgressBar : SliderBar<double>
|
||||
{
|
||||
public Action<double> OnSeek;
|
||||
|
||||
private readonly Box fill;
|
||||
private readonly Box background;
|
||||
|
||||
public Color4 FillColour
|
||||
{
|
||||
set { fill.Colour = value; }
|
||||
}
|
||||
|
||||
public Color4 BackgroundColour
|
||||
{
|
||||
set
|
||||
{
|
||||
background.Alpha = 1;
|
||||
background.Colour = value;
|
||||
}
|
||||
}
|
||||
|
||||
public double EndTime
|
||||
{
|
||||
set { CurrentNumber.MaxValue = value; }
|
||||
}
|
||||
|
||||
public double CurrentTime
|
||||
{
|
||||
set { CurrentNumber.Value = value; }
|
||||
}
|
||||
|
||||
public ProgressBar()
|
||||
{
|
||||
CurrentNumber.MinValue = 0;
|
||||
CurrentNumber.MaxValue = 1;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
background = new Box
|
||||
{
|
||||
Alpha = 0,
|
||||
RelativeSizeAxes = Axes.Both
|
||||
},
|
||||
fill = new Box { RelativeSizeAxes = Axes.Y }
|
||||
};
|
||||
}
|
||||
|
||||
protected override void UpdateValue(float value)
|
||||
{
|
||||
fill.Width = value * UsableWidth;
|
||||
}
|
||||
|
||||
protected override void OnUserChange() => OnSeek?.Invoke(Current);
|
||||
}
|
||||
}
|
@ -2,6 +2,8 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Handlers;
|
||||
using osu.Framework.Platform;
|
||||
using OpenTK;
|
||||
@ -29,5 +31,18 @@ namespace osu.Game.Input.Handlers
|
||||
public override bool IsActive => true;
|
||||
|
||||
public override int Priority => 0;
|
||||
|
||||
public class ReplayState<T> : InputState
|
||||
where T : struct
|
||||
{
|
||||
public List<T> PressedActions;
|
||||
|
||||
public override InputState Clone()
|
||||
{
|
||||
var clone = (ReplayState<T>)base.Clone();
|
||||
clone.PressedActions = new List<T>(PressedActions);
|
||||
return clone;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -11,11 +11,11 @@ namespace osu.Game.Online.API
|
||||
/// An API request with a well-defined response type.
|
||||
/// </summary>
|
||||
/// <typeparam name="T">Type of the response (used for deserialisation).</typeparam>
|
||||
public class APIRequest<T> : APIRequest
|
||||
public abstract class APIRequest<T> : APIRequest
|
||||
{
|
||||
protected override WebRequest CreateWebRequest() => new JsonWebRequest<T>(Uri);
|
||||
|
||||
public APIRequest()
|
||||
protected APIRequest()
|
||||
{
|
||||
base.Success += onSuccess;
|
||||
}
|
||||
@ -28,10 +28,36 @@ namespace osu.Game.Online.API
|
||||
public new event APISuccessHandler<T> Success;
|
||||
}
|
||||
|
||||
public abstract class APIDownloadRequest : APIRequest
|
||||
{
|
||||
protected override WebRequest CreateWebRequest()
|
||||
{
|
||||
var request = new WebRequest(Uri);
|
||||
request.DownloadProgress += request_Progress;
|
||||
return request;
|
||||
}
|
||||
|
||||
private void request_Progress(WebRequest request, long current, long total) => API.Scheduler.Add(delegate { Progress?.Invoke(current, total); });
|
||||
|
||||
protected APIDownloadRequest()
|
||||
{
|
||||
base.Success += onSuccess;
|
||||
}
|
||||
|
||||
private void onSuccess()
|
||||
{
|
||||
Success?.Invoke(WebRequest.ResponseData);
|
||||
}
|
||||
|
||||
public event APIProgressHandler Progress;
|
||||
|
||||
public new event APISuccessHandler<byte[]> Success;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// AN API request with no specified response type.
|
||||
/// </summary>
|
||||
public class APIRequest
|
||||
public abstract class APIRequest
|
||||
{
|
||||
/// <summary>
|
||||
/// The maximum amount of time before this request will fail.
|
||||
@ -42,7 +68,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
protected virtual WebRequest CreateWebRequest() => new WebRequest(Uri);
|
||||
|
||||
protected virtual string Uri => $@"{api.Endpoint}/api/v2/{Target}";
|
||||
protected virtual string Uri => $@"{API.Endpoint}/api/v2/{Target}";
|
||||
|
||||
private double remainingTime => Math.Max(0, Timeout - (DateTime.Now.TotalMilliseconds() - (startTime ?? 0)));
|
||||
|
||||
@ -52,7 +78,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
public double StartTime => startTime ?? -1;
|
||||
|
||||
private APIAccess api;
|
||||
protected APIAccess API;
|
||||
protected WebRequest WebRequest;
|
||||
|
||||
public event APISuccessHandler Success;
|
||||
@ -64,7 +90,7 @@ namespace osu.Game.Online.API
|
||||
|
||||
public void Perform(APIAccess api)
|
||||
{
|
||||
this.api = api;
|
||||
API = api;
|
||||
|
||||
if (checkAndProcessFailure())
|
||||
return;
|
||||
@ -109,9 +135,9 @@ namespace osu.Game.Online.API
|
||||
/// <returns>Whether we are in a failed or cancelled state.</returns>
|
||||
private bool checkAndProcessFailure()
|
||||
{
|
||||
if (api == null || pendingFailure == null) return cancelled;
|
||||
if (API == null || pendingFailure == null) return cancelled;
|
||||
|
||||
api.Scheduler.Add(pendingFailure);
|
||||
API.Scheduler.Add(pendingFailure);
|
||||
pendingFailure = null;
|
||||
return true;
|
||||
}
|
||||
@ -119,5 +145,6 @@ namespace osu.Game.Online.API
|
||||
|
||||
public delegate void APIFailureHandler(Exception e);
|
||||
public delegate void APISuccessHandler();
|
||||
public delegate void APIProgressHandler(long current, long total);
|
||||
public delegate void APISuccessHandler<in T>(T content);
|
||||
}
|
||||
|
@ -46,6 +46,9 @@ namespace osu.Game.Online.API.Requests
|
||||
[JsonProperty(@"favourite_count")]
|
||||
private int favouriteCount { get; set; }
|
||||
|
||||
[JsonProperty(@"id")]
|
||||
private int onlineId { get; set; }
|
||||
|
||||
[JsonProperty(@"beatmaps")]
|
||||
private IEnumerable<GetBeatmapSetsBeatmapResponse> beatmaps { get; set; }
|
||||
|
||||
@ -53,6 +56,7 @@ namespace osu.Game.Online.API.Requests
|
||||
{
|
||||
return new BeatmapSetInfo
|
||||
{
|
||||
OnlineBeatmapSetID = onlineId,
|
||||
Metadata = this,
|
||||
OnlineInfo = new BeatmapSetOnlineInfo
|
||||
{
|
||||
|
@ -219,6 +219,7 @@ namespace osu.Game
|
||||
|
||||
dependencies.Cache(settings);
|
||||
dependencies.Cache(social);
|
||||
dependencies.Cache(direct);
|
||||
dependencies.Cache(chat);
|
||||
dependencies.Cache(userProfile);
|
||||
dependencies.Cache(musicController);
|
||||
|
@ -12,6 +12,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Framework.Input;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
@ -25,23 +26,11 @@ namespace osu.Game.Overlays.Direct
|
||||
public DirectGridPanel(BeatmapSetInfo beatmap) : base(beatmap)
|
||||
{
|
||||
Height = 140 + vertical_padding; //full height of all the elements plus vertical padding (autosize uses the image)
|
||||
CornerRadius = 4;
|
||||
Masking = true;
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
Radius = 3f,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
this.FadeInFromZero(200, Easing.Out);
|
||||
bottomPanel.LayoutDuration = 200;
|
||||
bottomPanel.LayoutEasing = Easing.Out;
|
||||
bottomPanel.Origin = Anchor.BottomLeft;
|
||||
@ -50,14 +39,10 @@ namespace osu.Game.Overlays.Direct
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, LocalisationEngine localisation)
|
||||
{
|
||||
Children = new[]
|
||||
Content.CornerRadius = 4;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
CreateBackground(),
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -185,7 +170,13 @@ namespace osu.Game.Overlays.Direct
|
||||
new Statistic(FontAwesome.fa_heart, SetInfo.OnlineInfo?.FavouriteCount ?? 0),
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
StartDownload();
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -28,35 +28,15 @@ namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = height;
|
||||
CornerRadius = 5;
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
Radius = 3f,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
};
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
this.FadeInFromZero(200, Easing.Out);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(LocalisationEngine localisation)
|
||||
{
|
||||
Children = new[]
|
||||
Content.CornerRadius = 5;
|
||||
|
||||
AddRange(new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
CreateBackground(),
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -144,10 +124,11 @@ namespace osu.Game.Overlays.Direct
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Size = new Vector2(height - vertical_padding * 2),
|
||||
Action = StartDownload
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
});
|
||||
}
|
||||
|
||||
private class DownloadButton : OsuClickableContainer
|
||||
|
@ -2,26 +2,213 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using System.IO;
|
||||
using System.Threading.Tasks;
|
||||
using OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Transforms;
|
||||
using osu.Game.Beatmaps;
|
||||
using osu.Game.Beatmaps.Drawables;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Framework.Logging;
|
||||
using osu.Game.Beatmaps.IO;
|
||||
using osu.Game.Overlays.Notifications;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public abstract class DirectPanel : Container
|
||||
{
|
||||
protected readonly BeatmapSetInfo SetInfo;
|
||||
public readonly BeatmapSetInfo SetInfo;
|
||||
|
||||
protected Box BlackBackground;
|
||||
|
||||
private const double hover_transition_time = 400;
|
||||
|
||||
private Container content;
|
||||
|
||||
private APIAccess api;
|
||||
private ProgressBar progressBar;
|
||||
private BeatmapManager beatmaps;
|
||||
private NotificationOverlay notifications;
|
||||
|
||||
protected override Container<Drawable> Content => content;
|
||||
|
||||
protected DirectPanel(BeatmapSetInfo setInfo)
|
||||
{
|
||||
SetInfo = setInfo;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(APIAccess api, BeatmapManager beatmaps, OsuColour colours, NotificationOverlay notifications)
|
||||
{
|
||||
this.api = api;
|
||||
this.beatmaps = beatmaps;
|
||||
this.notifications = notifications;
|
||||
|
||||
AddInternal(content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
Radius = 2f,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
},
|
||||
Children = new[]
|
||||
{
|
||||
// temporary blackness until the actual background loads.
|
||||
BlackBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
CreateBackground(),
|
||||
progressBar = new ProgressBar
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Height = 0,
|
||||
Alpha = 0,
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f),
|
||||
FillColour = colours.Blue,
|
||||
Depth = -1,
|
||||
},
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
content.FadeEdgeEffectTo(1f, hover_transition_time, Easing.OutQuint);
|
||||
content.TransformTo(content.PopulateTransform(new TransformEdgeEffectRadius(), 14, hover_transition_time, Easing.OutQuint));
|
||||
content.MoveToY(-4, hover_transition_time, Easing.OutQuint);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
content.FadeEdgeEffectTo(0.25f, hover_transition_time, Easing.OutQuint);
|
||||
content.TransformTo(content.PopulateTransform(new TransformEdgeEffectRadius(), 2, hover_transition_time, Easing.OutQuint));
|
||||
content.MoveToY(0, hover_transition_time, Easing.OutQuint);
|
||||
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
// this should eventually be moved to a more central place, like BeatmapManager.
|
||||
private DownloadBeatmapSetRequest downloadRequest;
|
||||
|
||||
protected void StartDownload()
|
||||
{
|
||||
if (api == null) return;
|
||||
|
||||
// we already have an active download running.
|
||||
if (downloadRequest != null)
|
||||
{
|
||||
content.MoveToX(-5, 50, Easing.OutSine).Then()
|
||||
.MoveToX(5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(-5, 100, Easing.InOutSine).Then()
|
||||
.MoveToX(0, 50, Easing.InSine).Then();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!api.LocalUser.Value.IsSupporter)
|
||||
{
|
||||
notifications.Post(new SimpleNotification
|
||||
{
|
||||
Icon = FontAwesome.fa_superpowers,
|
||||
Text = "You gotta be a supporter to download for now 'yo"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
progressBar.FadeIn(400, Easing.OutQuint);
|
||||
progressBar.ResizeHeightTo(4, 400, Easing.OutQuint);
|
||||
|
||||
progressBar.Current.Value = 0;
|
||||
|
||||
ProgressNotification downloadNotification = new ProgressNotification
|
||||
{
|
||||
Text = $"Downloading {SetInfo.Metadata.Artist} - {SetInfo.Metadata.Title}",
|
||||
};
|
||||
|
||||
downloadRequest = new DownloadBeatmapSetRequest(SetInfo);
|
||||
downloadRequest.Failure += e =>
|
||||
{
|
||||
progressBar.Current.Value = 0;
|
||||
progressBar.FadeOut(500);
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
Logger.Error(e, "Failed to get beatmap download information");
|
||||
|
||||
downloadRequest = null;
|
||||
};
|
||||
|
||||
downloadRequest.Progress += (current, total) =>
|
||||
{
|
||||
float progress = (float)current / total;
|
||||
|
||||
progressBar.Current.Value = progress;
|
||||
|
||||
downloadNotification.State = ProgressNotificationState.Active;
|
||||
downloadNotification.Progress = progress;
|
||||
};
|
||||
|
||||
downloadRequest.Success += data =>
|
||||
{
|
||||
progressBar.Current.Value = 1;
|
||||
progressBar.FadeOut(500);
|
||||
|
||||
downloadNotification.State = ProgressNotificationState.Completed;
|
||||
|
||||
using (var stream = new MemoryStream(data))
|
||||
using (var archive = new OszArchiveReader(stream))
|
||||
beatmaps.Import(archive);
|
||||
};
|
||||
|
||||
downloadNotification.CancelRequested += () =>
|
||||
{
|
||||
downloadRequest.Cancel();
|
||||
downloadRequest = null;
|
||||
return true;
|
||||
};
|
||||
|
||||
notifications.Post(downloadNotification);
|
||||
|
||||
// don't run in the main api queue as this is a long-running task.
|
||||
Task.Run(() => downloadRequest.Perform(api));
|
||||
}
|
||||
|
||||
public class DownloadBeatmapSetRequest : APIDownloadRequest
|
||||
{
|
||||
private readonly BeatmapSetInfo beatmapSet;
|
||||
|
||||
public DownloadBeatmapSetRequest(BeatmapSetInfo beatmapSet)
|
||||
{
|
||||
this.beatmapSet = beatmapSet;
|
||||
}
|
||||
|
||||
protected override string Target => $@"beatmapsets/{beatmapSet.OnlineBeatmapSetID}/download";
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
this.FadeInFromZero(200, Easing.Out);
|
||||
}
|
||||
|
||||
protected List<DifficultyIcon> GetDifficultyIcons()
|
||||
{
|
||||
var icons = new List<DifficultyIcon>();
|
||||
@ -38,7 +225,11 @@ namespace osu.Game.Overlays.Direct
|
||||
Origin = Anchor.Centre,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
FillMode = FillMode.Fill,
|
||||
OnLoadComplete = d => d.FadeInFromZero(400, Easing.Out),
|
||||
OnLoadComplete = d =>
|
||||
{
|
||||
d.FadeInFromZero(400, Easing.Out);
|
||||
BlackBackground.Delay(400).FadeOut();
|
||||
},
|
||||
})
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
@ -87,5 +278,30 @@ namespace osu.Game.Overlays.Direct
|
||||
Value = value;
|
||||
}
|
||||
}
|
||||
|
||||
private class TransformEdgeEffectRadius : Transform<float, Container>
|
||||
{
|
||||
/// <summary>
|
||||
/// Current value of the transformed colour in linear colour space.
|
||||
/// </summary>
|
||||
private float valueAt(double time)
|
||||
{
|
||||
if (time < StartTime) return StartValue;
|
||||
if (time >= EndTime) return EndValue;
|
||||
|
||||
return Interpolation.ValueAt(time, StartValue, EndValue, StartTime, EndTime, Easing);
|
||||
}
|
||||
|
||||
public override string TargetMember => "EdgeEffect.Colour";
|
||||
|
||||
protected override void Apply(Container c, double time)
|
||||
{
|
||||
EdgeEffectParameters e = c.EdgeEffect;
|
||||
e.Radius = valueAt(time);
|
||||
c.EdgeEffect = e;
|
||||
}
|
||||
|
||||
protected override void ReadIntoStartValue(Container d) => StartValue = d.EdgeEffect.Radius;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -36,7 +36,7 @@ namespace osu.Game.Overlays.Direct
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuGame game, RulesetStore rulesets, OsuColour colours)
|
||||
{
|
||||
DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;
|
||||
DisplayStyleControl.Dropdown.AccentColour.Value = colours.BlueDark;
|
||||
|
||||
Ruleset.BindTo(game?.Ruleset ?? new Bindable<RulesetInfo> { Value = rulesets.GetRuleset(0) });
|
||||
foreach (var r in rulesets.AllRulesets)
|
||||
|
@ -30,7 +30,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
private readonly FillFlowContainer resultCountsContainer;
|
||||
private readonly OsuSpriteText resultCountsText;
|
||||
private readonly FillFlowContainer<DirectPanel> panels;
|
||||
private FillFlowContainer<DirectPanel> panels;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74");
|
||||
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71");
|
||||
@ -48,17 +48,6 @@ namespace osu.Game.Overlays
|
||||
if (beatmapSets?.Equals(value) ?? false) return;
|
||||
beatmapSets = value;
|
||||
|
||||
if (BeatmapSets == null)
|
||||
{
|
||||
foreach (var p in panels.Children)
|
||||
{
|
||||
p.FadeOut(200);
|
||||
p.Expire();
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
}
|
||||
}
|
||||
@ -108,13 +97,6 @@ namespace osu.Game.Overlays
|
||||
},
|
||||
}
|
||||
},
|
||||
panels = new FillFlowContainer<DirectPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(panel_padding),
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
},
|
||||
};
|
||||
|
||||
Filter.Search.Current.ValueChanged += text => { if (text != string.Empty) Header.Tabs.Current.Value = DirectTab.Search; };
|
||||
@ -161,11 +143,19 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets)
|
||||
private void load(OsuColour colours, APIAccess api, RulesetStore rulesets, BeatmapManager beatmaps)
|
||||
{
|
||||
this.api = api;
|
||||
this.rulesets = rulesets;
|
||||
resultCountsContainer.Colour = colours.Yellow;
|
||||
|
||||
beatmaps.BeatmapSetAdded += setAdded;
|
||||
}
|
||||
|
||||
private void setAdded(BeatmapSetInfo set)
|
||||
{
|
||||
// if a new map was imported, we should remove it from search results (download completed etc.)
|
||||
panels?.FirstOrDefault(p => p.SetInfo.OnlineBeatmapSetID == set.OnlineBeatmapSetID)?.FadeOut(400).Expire();
|
||||
}
|
||||
|
||||
private void updateResultCounts()
|
||||
@ -185,18 +175,38 @@ namespace osu.Game.Overlays
|
||||
|
||||
private void recreatePanels(PanelDisplayStyle displayStyle)
|
||||
{
|
||||
if (panels != null)
|
||||
{
|
||||
panels.FadeOut(200);
|
||||
panels.Expire();
|
||||
panels = null;
|
||||
}
|
||||
|
||||
if (BeatmapSets == null) return;
|
||||
|
||||
panels.ChildrenEnumerable = BeatmapSets.Select<BeatmapSetInfo, DirectPanel>(b =>
|
||||
{
|
||||
switch (displayStyle)
|
||||
{
|
||||
case PanelDisplayStyle.Grid:
|
||||
return new DirectGridPanel(b) { Width = 400 };
|
||||
default:
|
||||
return new DirectListPanel(b);
|
||||
}
|
||||
});
|
||||
var newPanels = new FillFlowContainer<DirectPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(panel_padding),
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
ChildrenEnumerable = BeatmapSets.Select<BeatmapSetInfo, DirectPanel>(b =>
|
||||
{
|
||||
switch (displayStyle)
|
||||
{
|
||||
case PanelDisplayStyle.Grid:
|
||||
return new DirectGridPanel(b) { Width = 400 };
|
||||
default:
|
||||
return new DirectListPanel(b);
|
||||
}
|
||||
})
|
||||
};
|
||||
|
||||
LoadComponentAsync(newPanels, p =>
|
||||
{
|
||||
if (panels != null) ScrollFlow.Remove(panels);
|
||||
ScrollFlow.Add(panels = newPanels);
|
||||
});
|
||||
}
|
||||
|
||||
private GetBeatmapSetsRequest getSetsRequest;
|
||||
|
@ -15,13 +15,41 @@ namespace osu.Game.Overlays.Music
|
||||
{
|
||||
public class CollectionsDropdown<T> : OsuDropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new CollectionsHeader { AccentColour = AccentColour };
|
||||
protected override Menu CreateMenu() => new CollectionsMenu();
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
AccentColour = colours.Gray6;
|
||||
AccentColour.Value = colours.Gray6;
|
||||
}
|
||||
|
||||
protected override DropdownHeader CreateHeader()
|
||||
{
|
||||
var newHeader = new CollectionsHeader();
|
||||
newHeader.AccentColour.BindTo(AccentColour);
|
||||
|
||||
return newHeader;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new CollectionsMenu();
|
||||
|
||||
private class CollectionsMenu : OsuDropdownMenu
|
||||
{
|
||||
public CollectionsMenu()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.Gray4;
|
||||
}
|
||||
}
|
||||
|
||||
private class CollectionsHeader : OsuDropdownHeader
|
||||
@ -48,26 +76,5 @@ namespace osu.Game.Overlays.Music
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class CollectionsMenu : OsuMenu
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Background.Colour = colours.Gray4;
|
||||
}
|
||||
|
||||
public CollectionsMenu()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -15,7 +15,6 @@ using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Shapes;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Textures;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Localisation;
|
||||
using osu.Framework.Threading;
|
||||
@ -434,49 +433,5 @@ namespace osu.Game.Overlays
|
||||
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
||||
}
|
||||
}
|
||||
|
||||
private class ProgressBar : SliderBar<double>
|
||||
{
|
||||
public Action<double> OnSeek;
|
||||
|
||||
private readonly Box fill;
|
||||
|
||||
public Color4 FillColour
|
||||
{
|
||||
set { fill.Colour = value; }
|
||||
}
|
||||
|
||||
public double EndTime
|
||||
{
|
||||
set { CurrentNumber.MaxValue = value; }
|
||||
}
|
||||
|
||||
public double CurrentTime
|
||||
{
|
||||
set { CurrentNumber.Value = value; }
|
||||
}
|
||||
|
||||
public ProgressBar()
|
||||
{
|
||||
CurrentNumber.MinValue = 0;
|
||||
CurrentNumber.MaxValue = 1;
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
fill = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Y
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected override void UpdateValue(float value)
|
||||
{
|
||||
fill.Width = value * UsableWidth;
|
||||
}
|
||||
|
||||
protected override void OnUserChange() => OnSeek?.Invoke(Current);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -152,11 +152,14 @@ namespace osu.Game.Overlays.Notifications
|
||||
break;
|
||||
case ProgressNotificationState.Active:
|
||||
case ProgressNotificationState.Queued:
|
||||
State = ProgressNotificationState.Cancelled;
|
||||
if (CancelRequested?.Invoke() != false)
|
||||
State = ProgressNotificationState.Cancelled;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
public Func<bool> CancelRequested { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// The function to post completion notifications back to.
|
||||
/// </summary>
|
||||
|
@ -12,8 +12,15 @@ namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public class SlimEnumDropdown<T> : OsuEnumDropdown<T>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new SlimDropdownHeader { AccentColour = AccentColour };
|
||||
protected override Menu CreateMenu() => new SlimMenu();
|
||||
protected override DropdownHeader CreateHeader()
|
||||
{
|
||||
var newHeader = new SlimDropdownHeader();
|
||||
newHeader.AccentColour.BindTo(AccentColour);
|
||||
|
||||
return newHeader;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new SlimMenu();
|
||||
|
||||
private class SlimDropdownHeader : OsuDropdownHeader
|
||||
{
|
||||
@ -31,11 +38,11 @@ namespace osu.Game.Overlays.SearchableList
|
||||
}
|
||||
}
|
||||
|
||||
private class SlimMenu : OsuMenu
|
||||
private class SlimMenu : OsuDropdownMenu
|
||||
{
|
||||
public SlimMenu()
|
||||
{
|
||||
Background.Colour = Color4.Black.Opacity(0.7f);
|
||||
BackgroundColour = Color4.Black.Opacity(0.7f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -257,9 +257,15 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
|
||||
private class UserDropdown : OsuEnumDropdown<UserAction>
|
||||
{
|
||||
protected override DropdownHeader CreateHeader() => new UserDropdownHeader { AccentColour = AccentColour };
|
||||
protected override Menu CreateMenu() => new UserDropdownMenu();
|
||||
protected override DropdownMenuItem<UserAction> CreateMenuItem(string text, UserAction value) => new UserDropdownMenuItem(text, value) { AccentColour = AccentColour };
|
||||
protected override DropdownHeader CreateHeader()
|
||||
{
|
||||
var newHeader = new UserDropdownHeader();
|
||||
newHeader.AccentColour.BindTo(AccentColour);
|
||||
|
||||
return newHeader;
|
||||
}
|
||||
|
||||
protected override DropdownMenu CreateMenu() => new UserDropdownMenu();
|
||||
|
||||
public Color4 StatusColour
|
||||
{
|
||||
@ -274,7 +280,46 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
AccentColour = colours.Gray5;
|
||||
AccentColour.Value = colours.Gray5;
|
||||
}
|
||||
|
||||
private class UserDropdownMenu : OsuDropdownMenu
|
||||
{
|
||||
public UserDropdownMenu()
|
||||
{
|
||||
Masking = true;
|
||||
CornerRadius = 5;
|
||||
|
||||
Margin = new MarginPadding { Bottom = 5 };
|
||||
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Radius = 4,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.Gray3;
|
||||
}
|
||||
|
||||
protected override MarginPadding ItemFlowContainerPadding => new MarginPadding();
|
||||
|
||||
protected override DrawableMenuItem CreateDrawableMenuItem(DropdownMenuItem<UserAction> item) => new DrawableUserDropdownMenuItem(this, item);
|
||||
|
||||
private class DrawableUserDropdownMenuItem : DrawableOsuDropdownMenuItem
|
||||
{
|
||||
public DrawableUserDropdownMenuItem(Menu<DropdownMenuItem<UserAction>> menu, DropdownMenuItem<UserAction> item)
|
||||
: base(item)
|
||||
{
|
||||
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 };
|
||||
Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 };
|
||||
CornerRadius = 5;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class UserDropdownHeader : OsuDropdownHeader
|
||||
@ -324,38 +369,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
}
|
||||
}
|
||||
|
||||
private class UserDropdownMenu : OsuMenu
|
||||
{
|
||||
public UserDropdownMenu()
|
||||
{
|
||||
Margin = new MarginPadding { Bottom = 5 };
|
||||
CornerRadius = 5;
|
||||
ItemsContainer.Padding = new MarginPadding(0);
|
||||
Masking = true;
|
||||
EdgeEffect = new EdgeEffectParameters
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.25f),
|
||||
Radius = 4,
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Background.Colour = colours.Gray3;
|
||||
}
|
||||
}
|
||||
|
||||
private class UserDropdownMenuItem : OsuDropdownMenuItem
|
||||
{
|
||||
public UserDropdownMenuItem(string text, UserAction current) : base(text, current)
|
||||
{
|
||||
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 };
|
||||
Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 };
|
||||
CornerRadius = 5;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private enum UserAction
|
||||
|
@ -58,6 +58,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ToolbarDirectButton(),
|
||||
new ToolbarChatButton(),
|
||||
new ToolbarSocialButton(),
|
||||
new ToolbarMusicButton(),
|
||||
|
22
osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs
Normal file
22
osu.Game/Overlays/Toolbar/ToolbarDirectButton.cs
Normal file
@ -0,0 +1,22 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.Toolbar
|
||||
{
|
||||
internal class ToolbarDirectButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
public ToolbarDirectButton()
|
||||
{
|
||||
SetIcon(FontAwesome.fa_osu_chevron_down_o);
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(DirectOverlay direct)
|
||||
{
|
||||
StateContainer = direct;
|
||||
}
|
||||
}
|
||||
}
|
@ -3,7 +3,6 @@
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Extensions.IEnumerableExtensions;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.MathUtils;
|
||||
using osu.Game.Input.Handlers;
|
||||
@ -18,7 +17,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
/// The ReplayHandler will take a replay and handle the propagation of updates to the input stack.
|
||||
/// It handles logic of any frames which *must* be executed.
|
||||
/// </summary>
|
||||
public class FramedReplayInputHandler : ReplayInputHandler
|
||||
public abstract class FramedReplayInputHandler : ReplayInputHandler
|
||||
{
|
||||
private readonly Replay replay;
|
||||
|
||||
@ -31,7 +30,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
|
||||
private int nextFrameIndex => MathHelper.Clamp(currentFrameIndex + (currentDirection > 0 ? 1 : -1), 0, Frames.Count - 1);
|
||||
|
||||
public FramedReplayInputHandler(Replay replay)
|
||||
protected FramedReplayInputHandler(Replay replay)
|
||||
{
|
||||
this.replay = replay;
|
||||
}
|
||||
@ -51,7 +50,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
{
|
||||
}
|
||||
|
||||
private Vector2? position
|
||||
protected Vector2? Position
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -62,23 +61,7 @@ namespace osu.Game.Rulesets.Replays
|
||||
}
|
||||
}
|
||||
|
||||
public override List<InputState> GetPendingStates()
|
||||
{
|
||||
var buttons = new HashSet<MouseButton>();
|
||||
if (CurrentFrame?.MouseLeft ?? false)
|
||||
buttons.Add(MouseButton.Left);
|
||||
if (CurrentFrame?.MouseRight ?? false)
|
||||
buttons.Add(MouseButton.Right);
|
||||
|
||||
return new List<InputState>
|
||||
{
|
||||
new InputState
|
||||
{
|
||||
Mouse = new ReplayMouseState(ToScreenSpace(position ?? Vector2.Zero), buttons),
|
||||
Keyboard = new ReplayKeyboardState(new List<Key>())
|
||||
}
|
||||
};
|
||||
}
|
||||
public override List<InputState> GetPendingStates() => new List<InputState>();
|
||||
|
||||
public bool AtLastFrame => currentFrameIndex == Frames.Count - 1;
|
||||
public bool AtFirstFrame => currentFrameIndex == 0;
|
||||
@ -133,10 +116,9 @@ namespace osu.Game.Rulesets.Replays
|
||||
|
||||
protected class ReplayMouseState : MouseState
|
||||
{
|
||||
public ReplayMouseState(Vector2 position, IEnumerable<MouseButton> list)
|
||||
public ReplayMouseState(Vector2 position)
|
||||
{
|
||||
Position = position;
|
||||
list.ForEach(b => SetPressed(b, true));
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,6 @@ using osu.Game.Rulesets.Judgements;
|
||||
using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.Objects;
|
||||
using osu.Game.Rulesets.Objects.Drawables;
|
||||
using osu.Game.Screens.Play;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Diagnostics;
|
||||
@ -43,7 +42,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <summary>
|
||||
/// The input manager for this RulesetContainer.
|
||||
/// </summary>
|
||||
internal readonly PlayerInputManager InputManager = new PlayerInputManager();
|
||||
internal IHasReplayHandler ReplayInputManager => KeyBindingInputManager as IHasReplayHandler;
|
||||
|
||||
/// <summary>
|
||||
/// The key conversion input manager for this RulesetContainer.
|
||||
@ -58,7 +57,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <summary>
|
||||
/// Whether we have a replay loaded currently.
|
||||
/// </summary>
|
||||
public bool HasReplayLoaded => InputManager.ReplayInputHandler != null;
|
||||
public bool HasReplayLoaded => ReplayInputManager?.ReplayInputHandler != null;
|
||||
|
||||
public abstract IEnumerable<HitObject> Objects { get; }
|
||||
|
||||
@ -76,11 +75,7 @@ namespace osu.Game.Rulesets.UI
|
||||
internal RulesetContainer(Ruleset ruleset)
|
||||
{
|
||||
Ruleset = ruleset;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
KeyBindingInputManager = CreateInputManager();
|
||||
KeyBindingInputManager.RelativeSizeAxes = Axes.Both;
|
||||
}
|
||||
@ -102,7 +97,7 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <returns>The input manager.</returns>
|
||||
public abstract PassThroughInputManager CreateInputManager();
|
||||
|
||||
protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => new FramedReplayInputHandler(replay);
|
||||
protected virtual FramedReplayInputHandler CreateReplayInputHandler(Replay replay) => null;
|
||||
|
||||
public Replay Replay { get; private set; }
|
||||
|
||||
@ -112,8 +107,11 @@ namespace osu.Game.Rulesets.UI
|
||||
/// <param name="replay">The replay, null for local input.</param>
|
||||
public virtual void SetReplay(Replay replay)
|
||||
{
|
||||
if (ReplayInputManager == null)
|
||||
throw new InvalidOperationException($"A {nameof(KeyBindingInputManager)} which supports replay loading is not available");
|
||||
|
||||
Replay = replay;
|
||||
InputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
||||
ReplayInputManager.ReplayInputHandler = replay != null ? CreateReplayInputHandler(replay) : null;
|
||||
}
|
||||
}
|
||||
|
||||
@ -267,13 +265,12 @@ namespace osu.Game.Rulesets.UI
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
InputManager.Add(content = new Container
|
||||
KeyBindingInputManager.Add(content = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new[] { KeyBindingInputManager }
|
||||
});
|
||||
|
||||
AddInternal(InputManager);
|
||||
AddInternal(KeyBindingInputManager);
|
||||
KeyBindingInputManager.Add(Playfield = CreatePlayfield());
|
||||
|
||||
loadObjects();
|
||||
@ -283,8 +280,8 @@ namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
base.SetReplay(replay);
|
||||
|
||||
if (InputManager?.ReplayInputHandler != null)
|
||||
InputManager.ReplayInputHandler.ToScreenSpace = Playfield.ScaledContent.ToScreenSpace;
|
||||
if (ReplayInputManager?.ReplayInputHandler != null)
|
||||
ReplayInputManager.ReplayInputHandler.ToScreenSpace = input => Playfield.ScaledContent.ToScreenSpace(input);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
@ -1,20 +1,194 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Input.Bindings;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Input.Bindings;
|
||||
using osu.Game.Input.Handlers;
|
||||
using osu.Game.Screens.Play;
|
||||
using OpenTK.Input;
|
||||
|
||||
namespace osu.Game.Rulesets.UI
|
||||
{
|
||||
public abstract class RulesetInputManager<T> : DatabasedKeyBindingInputManager<T>, ICanAttachKeyCounter
|
||||
public abstract class RulesetInputManager<T> : DatabasedKeyBindingInputManager<T>, ICanAttachKeyCounter, IHasReplayHandler
|
||||
where T : struct
|
||||
{
|
||||
protected RulesetInputManager(RulesetInfo ruleset, int variant, SimultaneousBindingMode unique) : base(ruleset, variant, unique)
|
||||
{
|
||||
}
|
||||
|
||||
#region Action mapping (for replays)
|
||||
|
||||
private List<T> lastPressedActions = new List<T>();
|
||||
|
||||
protected override void HandleNewState(InputState state)
|
||||
{
|
||||
base.HandleNewState(state);
|
||||
|
||||
var replayState = state as ReplayInputHandler.ReplayState<T>;
|
||||
|
||||
if (replayState == null) return;
|
||||
|
||||
// Here we handle states specifically coming from a replay source.
|
||||
// These have extra action information rather than keyboard keys or mouse buttons.
|
||||
|
||||
List<T> newActions = replayState.PressedActions;
|
||||
|
||||
foreach (var released in lastPressedActions.Except(newActions))
|
||||
PropagateReleased(KeyBindingInputQueue, released);
|
||||
|
||||
foreach (var pressed in newActions.Except(lastPressedActions))
|
||||
PropagatePressed(KeyBindingInputQueue, pressed);
|
||||
|
||||
lastPressedActions = newActions;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region IHasReplayHandler
|
||||
|
||||
private ReplayInputHandler replayInputHandler;
|
||||
public ReplayInputHandler ReplayInputHandler
|
||||
{
|
||||
get
|
||||
{
|
||||
return replayInputHandler;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (replayInputHandler != null) RemoveHandler(replayInputHandler);
|
||||
|
||||
replayInputHandler = value;
|
||||
UseParentState = replayInputHandler == null;
|
||||
|
||||
if (replayInputHandler != null)
|
||||
AddHandler(replayInputHandler);
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Clock control
|
||||
|
||||
private ManualClock clock;
|
||||
private IFrameBasedClock parentClock;
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
//our clock will now be our parent's clock, but we want to replace this to allow manual control.
|
||||
parentClock = Clock;
|
||||
|
||||
Clock = new FramedClock(clock = new ManualClock
|
||||
{
|
||||
CurrentTime = parentClock.CurrentTime,
|
||||
Rate = parentClock.Rate,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether we are running up-to-date with our parent clock.
|
||||
/// If not, we will need to keep processing children until we catch up.
|
||||
/// </summary>
|
||||
private bool requireMoreUpdateLoops;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we are in a valid state (ie. should we keep processing children frames).
|
||||
/// This should be set to false when the replay is, for instance, waiting for future frames to arrive.
|
||||
/// </summary>
|
||||
private bool validState;
|
||||
|
||||
protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState;
|
||||
|
||||
private bool isAttached => replayInputHandler != null && !UseParentState;
|
||||
|
||||
private const int max_catch_up_updates_per_frame = 50;
|
||||
|
||||
public override bool UpdateSubTree()
|
||||
{
|
||||
requireMoreUpdateLoops = true;
|
||||
validState = true;
|
||||
|
||||
int loops = 0;
|
||||
|
||||
while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame)
|
||||
if (!base.UpdateSubTree())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (parentClock == null) return;
|
||||
|
||||
clock.Rate = parentClock.Rate;
|
||||
clock.IsRunning = parentClock.IsRunning;
|
||||
|
||||
if (!isAttached)
|
||||
{
|
||||
clock.CurrentTime = parentClock.CurrentTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
double? newTime = replayInputHandler.SetFrameFromTime(parentClock.CurrentTime);
|
||||
|
||||
if (newTime == null)
|
||||
{
|
||||
// we shouldn't execute for this time value. probably waiting on more replay data.
|
||||
validState = false;
|
||||
return;
|
||||
}
|
||||
|
||||
clock.CurrentTime = newTime.Value;
|
||||
}
|
||||
|
||||
requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime;
|
||||
base.Update();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Setting application (disables etc.)
|
||||
|
||||
private Bindable<bool> mouseDisabled;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
mouseDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableButtons);
|
||||
}
|
||||
|
||||
protected override void TransformState(InputState state)
|
||||
{
|
||||
base.TransformState(state);
|
||||
|
||||
// we don't want to transform the state if a replay is present (for now, at least).
|
||||
if (replayInputHandler != null) return;
|
||||
|
||||
var mouse = state.Mouse as Framework.Input.MouseState;
|
||||
|
||||
if (mouse != null)
|
||||
{
|
||||
if (mouseDisabled.Value)
|
||||
{
|
||||
mouse.SetPressed(MouseButton.Left, false);
|
||||
mouse.SetPressed(MouseButton.Right, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Key Counter Attachment
|
||||
|
||||
public void Attach(KeyCounterCollection keyCounter)
|
||||
{
|
||||
var receptor = new ActionReceptor(keyCounter);
|
||||
@ -35,10 +209,24 @@ namespace osu.Game.Rulesets.UI
|
||||
|
||||
public bool OnReleased(T action) => Target.Children.OfType<KeyCounterAction<T>>().Any(c => c.OnReleased(action));
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Expose the <see cref="ReplayInputHandler"/> in a capable <see cref="InputManager"/>.
|
||||
/// </summary>
|
||||
public interface IHasReplayHandler
|
||||
{
|
||||
ReplayInputHandler ReplayInputHandler { get; set; }
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Supports attaching a <see cref="KeyCounterCollection"/>.
|
||||
/// Keys will be populated automatically and a receptor will be injected inside.
|
||||
/// </summary>
|
||||
public interface ICanAttachKeyCounter
|
||||
{
|
||||
void Attach(KeyCounterCollection keyCounter);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,140 +0,0 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK.Input;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Input;
|
||||
using osu.Framework.Timing;
|
||||
using osu.Game.Configuration;
|
||||
using osu.Game.Input.Handlers;
|
||||
|
||||
namespace osu.Game.Screens.Play
|
||||
{
|
||||
public class PlayerInputManager : PassThroughInputManager
|
||||
{
|
||||
private ManualClock clock;
|
||||
private IFrameBasedClock parentClock;
|
||||
|
||||
private ReplayInputHandler replayInputHandler;
|
||||
public ReplayInputHandler ReplayInputHandler
|
||||
{
|
||||
get
|
||||
{
|
||||
return replayInputHandler;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (replayInputHandler != null) RemoveHandler(replayInputHandler);
|
||||
|
||||
replayInputHandler = value;
|
||||
UseParentState = replayInputHandler == null;
|
||||
|
||||
if (replayInputHandler != null)
|
||||
AddHandler(replayInputHandler);
|
||||
}
|
||||
}
|
||||
|
||||
private Bindable<bool> mouseDisabled;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager config)
|
||||
{
|
||||
mouseDisabled = config.GetBindable<bool>(OsuSetting.MouseDisableButtons);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
//our clock will now be our parent's clock, but we want to replace this to allow manual control.
|
||||
parentClock = Clock;
|
||||
|
||||
Clock = new FramedClock(clock = new ManualClock
|
||||
{
|
||||
CurrentTime = parentClock.CurrentTime,
|
||||
Rate = parentClock.Rate,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Whether we running up-to-date with our parent clock.
|
||||
/// If not, we will need to keep processing children until we catch up.
|
||||
/// </summary>
|
||||
private bool requireMoreUpdateLoops;
|
||||
|
||||
/// <summary>
|
||||
/// Whether we in a valid state (ie. should we keep processing children frames).
|
||||
/// This should be set to false when the replay is, for instance, waiting for future frames to arrive.
|
||||
/// </summary>
|
||||
private bool validState;
|
||||
|
||||
protected override bool RequiresChildrenUpdate => base.RequiresChildrenUpdate && validState;
|
||||
|
||||
private bool isAttached => replayInputHandler != null && !UseParentState;
|
||||
|
||||
private const int max_catch_up_updates_per_frame = 50;
|
||||
|
||||
public override bool UpdateSubTree()
|
||||
{
|
||||
requireMoreUpdateLoops = true;
|
||||
validState = true;
|
||||
|
||||
int loops = 0;
|
||||
|
||||
while (validState && requireMoreUpdateLoops && loops++ < max_catch_up_updates_per_frame)
|
||||
if (!base.UpdateSubTree())
|
||||
return false;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (parentClock == null) return;
|
||||
|
||||
clock.Rate = parentClock.Rate;
|
||||
clock.IsRunning = parentClock.IsRunning;
|
||||
|
||||
if (!isAttached)
|
||||
{
|
||||
clock.CurrentTime = parentClock.CurrentTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
double? newTime = replayInputHandler.SetFrameFromTime(parentClock.CurrentTime);
|
||||
|
||||
if (newTime == null)
|
||||
{
|
||||
// we shouldn't execute for this time value. probably waiting on more replay data.
|
||||
validState = false;
|
||||
return;
|
||||
}
|
||||
|
||||
clock.CurrentTime = newTime.Value;
|
||||
}
|
||||
|
||||
requireMoreUpdateLoops = clock.CurrentTime != parentClock.CurrentTime;
|
||||
base.Update();
|
||||
}
|
||||
|
||||
protected override void TransformState(InputState state)
|
||||
{
|
||||
base.TransformState(state);
|
||||
|
||||
// we don't want to transform the state if a replay is present (for now, at least).
|
||||
if (replayInputHandler != null) return;
|
||||
|
||||
var mouse = state.Mouse as Framework.Input.MouseState;
|
||||
|
||||
if (mouse != null)
|
||||
{
|
||||
if (mouseDisabled.Value)
|
||||
{
|
||||
mouse.SetPressed(MouseButton.Left, false);
|
||||
mouse.SetPressed(MouseButton.Right, false);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -84,6 +84,7 @@
|
||||
<Compile Include="Graphics\Containers\OsuClickableContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\OsuFocusedOverlayContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\OsuScrollContainer.cs" />
|
||||
<Compile Include="Graphics\Cursor\IHasOsuContextMenu.cs" />
|
||||
<Compile Include="Graphics\Cursor\OsuContextMenuContainer.cs" />
|
||||
<Compile Include="Graphics\Containers\OsuTextFlowContainer.cs" />
|
||||
<Compile Include="Graphics\UserInterface\IconButton.cs" />
|
||||
@ -116,6 +117,7 @@
|
||||
<Compile Include="Overlays\Music\PlaylistList.cs" />
|
||||
<Compile Include="Overlays\OnScreenDisplay.cs" />
|
||||
<Compile Include="Graphics\Containers\SectionsContainer.cs" />
|
||||
<Compile Include="Graphics\UserInterface\ProgressBar.cs" />
|
||||
<Compile Include="Overlays\Settings\Sections\Maintenance\GeneralSettings.cs" />
|
||||
<Compile Include="Overlays\Settings\SettingsHeader.cs" />
|
||||
<Compile Include="Overlays\Settings\Sections\Audio\MainMenuSettings.cs" />
|
||||
@ -129,6 +131,7 @@
|
||||
<Compile Include="Overlays\Profile\Sections\RanksSection.cs" />
|
||||
<Compile Include="Overlays\Profile\Sections\RecentSection.cs" />
|
||||
<Compile Include="Graphics\Containers\ConstrainedIconContainer.cs" />
|
||||
<Compile Include="Overlays\Toolbar\ToolbarDirectButton.cs" />
|
||||
<Compile Include="Rulesets\Mods\IApplicableToDifficulty.cs" />
|
||||
<Compile Include="Rulesets\UI\RulesetInputManager.cs" />
|
||||
<Compile Include="Screens\Play\KeyCounterAction.cs" />
|
||||
@ -321,7 +324,6 @@
|
||||
<Compile Include="Screens\Multiplayer\MatchCreate.cs" />
|
||||
<Compile Include="Screens\Play\FailOverlay.cs" />
|
||||
<Compile Include="Screens\Play\MenuOverlay.cs" />
|
||||
<Compile Include="Screens\Play\PlayerInputManager.cs" />
|
||||
<Compile Include="Screens\Play\PlayerLoader.cs" />
|
||||
<Compile Include="Screens\Play\ReplayPlayer.cs" />
|
||||
<Compile Include="Screens\Play\SkipButton.cs" />
|
||||
|
Loading…
x
Reference in New Issue
Block a user