mirror of
https://github.com/osukey/osukey.git
synced 2025-08-04 23:24:04 +09:00
Merge https://github.com/ppy/osu into osu-direct-search
This commit is contained in:
188
osu.Game/Overlays/Chat/ChannelListItem.cs
Normal file
188
osu.Game/Overlays/Chat/ChannelListItem.cs
Normal file
@ -0,0 +1,188 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Chat;
|
||||
|
||||
namespace osu.Game.Overlays.Chat
|
||||
{
|
||||
public class ChannelListItem : ClickableContainer, IFilterable
|
||||
{
|
||||
private const float width_padding = 5;
|
||||
private const float channel_width = 150;
|
||||
private const float text_size = 15;
|
||||
private const float transition_duration = 100;
|
||||
|
||||
private readonly Channel channel;
|
||||
|
||||
private readonly Bindable<bool> joinedBind = new Bindable<bool>();
|
||||
private readonly OsuSpriteText name;
|
||||
private readonly OsuSpriteText topic;
|
||||
private readonly TextAwesome joinedCheckmark;
|
||||
|
||||
private Color4 joinedColour;
|
||||
private Color4 topicColour;
|
||||
private Color4 hoverColour;
|
||||
|
||||
public string[] FilterTerms => new[] { channel.Name };
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
FadeTo(value ? 1f : 0f, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public Action<Channel> OnRequestJoin;
|
||||
public Action<Channel> OnRequestLeave;
|
||||
|
||||
public ChannelListItem(Channel channel)
|
||||
{
|
||||
this.channel = channel;
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Action = () => { (channel.Joined ? OnRequestLeave : OnRequestJoin)?.Invoke(channel); };
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Children = new[]
|
||||
{
|
||||
joinedCheckmark = new TextAwesome
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Icon = FontAwesome.fa_check_circle,
|
||||
TextSize = text_size,
|
||||
Shadow = false,
|
||||
Margin = new MarginPadding { Right = 10f },
|
||||
Alpha = 0f,
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Width = channel_width,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new[]
|
||||
{
|
||||
name = new OsuSpriteText
|
||||
{
|
||||
Text = channel.ToString(),
|
||||
TextSize = text_size,
|
||||
Font = @"Exo2.0-Bold",
|
||||
Shadow = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Width = 0.7f,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Left = width_padding },
|
||||
Children = new[]
|
||||
{
|
||||
topic = new OsuSpriteText
|
||||
{
|
||||
Text = channel.Topic,
|
||||
TextSize = text_size,
|
||||
Font = @"Exo2.0-SemiBold",
|
||||
Shadow = false,
|
||||
Alpha = 0.8f,
|
||||
},
|
||||
},
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Margin = new MarginPadding { Left = width_padding },
|
||||
Spacing = new Vector2(3f, 0f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new TextAwesome
|
||||
{
|
||||
Icon = FontAwesome.fa_user,
|
||||
TextSize = text_size - 2,
|
||||
Shadow = false,
|
||||
Margin = new MarginPadding { Top = 1 },
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = @"0",
|
||||
TextSize = text_size,
|
||||
Font = @"Exo2.0-SemiBold",
|
||||
Shadow = false,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
topicColour = colours.Gray9;
|
||||
joinedColour = colours.Blue;
|
||||
hoverColour = colours.Yellow;
|
||||
|
||||
joinedBind.ValueChanged += updateColour;
|
||||
joinedBind.BindTo(channel.Joined);
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
if (!channel.Joined.Value)
|
||||
name.FadeColour(hoverColour, 50, EasingTypes.OutQuint);
|
||||
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
if (!channel.Joined.Value)
|
||||
name.FadeColour(Color4.White, transition_duration);
|
||||
}
|
||||
|
||||
private void updateColour(bool joined)
|
||||
{
|
||||
if (joined)
|
||||
{
|
||||
name.FadeColour(Color4.White, transition_duration);
|
||||
joinedCheckmark.FadeTo(1f, transition_duration);
|
||||
topic.FadeTo(0.8f, transition_duration);
|
||||
topic.FadeColour(Color4.White, transition_duration);
|
||||
FadeColour(joinedColour, transition_duration);
|
||||
}
|
||||
else
|
||||
{
|
||||
joinedCheckmark.FadeTo(0f, transition_duration);
|
||||
topic.FadeTo(1f, transition_duration);
|
||||
topic.FadeColour(topicColour, transition_duration);
|
||||
FadeColour(Color4.White, transition_duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
63
osu.Game/Overlays/Chat/ChannelSection.cs
Normal file
63
osu.Game/Overlays/Chat/ChannelSection.cs
Normal file
@ -0,0 +1,63 @@
|
||||
// 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 OpenTK;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.Chat;
|
||||
|
||||
namespace osu.Game.Overlays.Chat
|
||||
{
|
||||
public class ChannelSection : Container, IHasFilterableChildren
|
||||
{
|
||||
private readonly OsuSpriteText header;
|
||||
|
||||
public readonly FillFlowContainer<ChannelListItem> ChannelFlow;
|
||||
|
||||
public IEnumerable<IFilterable> FilterableChildren => ChannelFlow.Children;
|
||||
public string[] FilterTerms => new[] { Header };
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
FadeTo(value ? 1f : 0f, 100);
|
||||
}
|
||||
}
|
||||
|
||||
public string Header
|
||||
{
|
||||
get { return header.Text; }
|
||||
set { header.Text = value.ToUpper(); }
|
||||
}
|
||||
|
||||
public IEnumerable<Channel> Channels
|
||||
{
|
||||
set { ChannelFlow.Children = value.Select(c => new ChannelListItem(c)); }
|
||||
}
|
||||
|
||||
public ChannelSection()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
AutoSizeAxes = Axes.Y;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
header = new OsuSpriteText
|
||||
{
|
||||
TextSize = 15,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
ChannelFlow = new FillFlowContainer<ChannelListItem>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Top = 25 },
|
||||
Spacing = new Vector2(0f, 5f),
|
||||
},
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
184
osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs
Normal file
184
osu.Game/Overlays/Chat/ChannelSelectionOverlay.cs
Normal file
@ -0,0 +1,184 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Chat;
|
||||
|
||||
namespace osu.Game.Overlays.Chat
|
||||
{
|
||||
public class ChannelSelectionOverlay : FocusedOverlayContainer
|
||||
{
|
||||
public static readonly float WIDTH_PADDING = 170;
|
||||
|
||||
private const float transition_duration = 500;
|
||||
|
||||
private readonly Box bg;
|
||||
private readonly Triangles triangles;
|
||||
private readonly Box headerBg;
|
||||
private readonly SearchTextBox search;
|
||||
private readonly SearchContainer<ChannelSection> sectionsFlow;
|
||||
|
||||
public Action<Channel> OnRequestJoin;
|
||||
public Action<Channel> OnRequestLeave;
|
||||
|
||||
public IEnumerable<ChannelSection> Sections
|
||||
{
|
||||
set
|
||||
{
|
||||
sectionsFlow.Children = value;
|
||||
|
||||
foreach (ChannelSection s in sectionsFlow.Children)
|
||||
{
|
||||
foreach (ChannelListItem c in s.ChannelFlow.Children)
|
||||
{
|
||||
c.OnRequestJoin = channel => { OnRequestJoin?.Invoke(channel); };
|
||||
c.OnRequestLeave = channel => { OnRequestLeave?.Invoke(channel); };
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ChannelSelectionOverlay()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
bg = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
triangles = new Triangles
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
TriangleScale = 5,
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = 85, Right = WIDTH_PADDING },
|
||||
Children = new[]
|
||||
{
|
||||
new ScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new[]
|
||||
{
|
||||
sectionsFlow = new SearchContainer<ChannelSection>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
LayoutDuration = 200,
|
||||
LayoutEasing = EasingTypes.OutQuint,
|
||||
Spacing = new Vector2(0f, 20f),
|
||||
Padding = new MarginPadding { Vertical = 20, Left = WIDTH_PADDING },
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
headerBg = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Spacing = new Vector2(0f, 10f),
|
||||
Padding = new MarginPadding { Top = 10f, Bottom = 10f, Left = WIDTH_PADDING, Right = WIDTH_PADDING },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = @"Chat Channels",
|
||||
TextSize = 20,
|
||||
Shadow = false,
|
||||
},
|
||||
search = new HeaderSearchTextBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
PlaceholderText = @"Search",
|
||||
Exit = Hide,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
search.Current.ValueChanged += newValue => sectionsFlow.SearchTerm = newValue;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
bg.Colour = colours.Gray3;
|
||||
triangles.ColourDark = colours.Gray3;
|
||||
triangles.ColourLight = OsuColour.FromHex(@"353535");
|
||||
|
||||
headerBg.Colour = colours.Gray2.Opacity(0.75f);
|
||||
}
|
||||
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
InputManager.ChangeFocus(search);
|
||||
base.OnFocus(state);
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
if (Alpha == 0) MoveToY(DrawHeight);
|
||||
|
||||
FadeIn(transition_duration, EasingTypes.OutQuint);
|
||||
MoveToY(0, transition_duration, EasingTypes.OutQuint);
|
||||
|
||||
search.HoldFocus = true;
|
||||
base.PopIn();
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
FadeOut(transition_duration, EasingTypes.InSine);
|
||||
MoveToY(DrawHeight, transition_duration, EasingTypes.InSine);
|
||||
|
||||
search.HoldFocus = false;
|
||||
base.PopOut();
|
||||
}
|
||||
|
||||
private class HeaderSearchTextBox : SearchTextBox
|
||||
{
|
||||
protected override Color4 BackgroundFocused => Color4.Black.Opacity(0.2f);
|
||||
protected override Color4 BackgroundUnfocused => Color4.Black.Opacity(0.2f);
|
||||
}
|
||||
}
|
||||
}
|
@ -14,6 +14,7 @@ using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Online.Chat;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Configuration;
|
||||
|
||||
namespace osu.Game.Overlays.Chat
|
||||
{
|
||||
@ -23,6 +24,8 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
private const float shear_width = 10;
|
||||
|
||||
public readonly Bindable<bool> ChannelSelectorActive = new Bindable<bool>();
|
||||
|
||||
public ChatTabControl()
|
||||
{
|
||||
TabContainer.Margin = new MarginPadding { Left = 50 };
|
||||
@ -37,6 +40,8 @@ namespace osu.Game.Overlays.Chat
|
||||
TextSize = 20,
|
||||
Padding = new MarginPadding(10),
|
||||
});
|
||||
|
||||
AddTabItem(new ChannelTabItem.ChannelSelectorTabItem(new Channel { Name = "+" }, ChannelSelectorActive));
|
||||
}
|
||||
|
||||
private class ChannelTabItem : TabItem<Channel>
|
||||
@ -49,6 +54,7 @@ namespace osu.Game.Overlays.Chat
|
||||
private readonly SpriteText textBold;
|
||||
private readonly Box box;
|
||||
private readonly Box highlightBox;
|
||||
private readonly TextAwesome icon;
|
||||
|
||||
public override bool Active
|
||||
{
|
||||
@ -114,6 +120,11 @@ namespace osu.Game.Overlays.Chat
|
||||
backgroundHover = colours.Gray7;
|
||||
|
||||
highlightBox.Colour = colours.Yellow;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
updateState();
|
||||
}
|
||||
@ -159,7 +170,7 @@ namespace osu.Game.Overlays.Chat
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new TextAwesome
|
||||
icon = new TextAwesome
|
||||
{
|
||||
Icon = FontAwesome.fa_hashtag,
|
||||
Anchor = Anchor.CentreLeft,
|
||||
@ -191,6 +202,67 @@ namespace osu.Game.Overlays.Chat
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
public class ChannelSelectorTabItem : ChannelTabItem
|
||||
{
|
||||
public override bool Active
|
||||
{
|
||||
get { return false; }
|
||||
// ReSharper disable once ValueParameterNotUsed
|
||||
set
|
||||
{
|
||||
// we basically never want this tab to become active.
|
||||
// this allows us to become a "toggle" tab.
|
||||
// is a bit hacky, to say the least.
|
||||
activeBindable.Value = !activeBindable.Value;
|
||||
base.Active = false;
|
||||
}
|
||||
}
|
||||
|
||||
private readonly Bindable<bool> activeBindable;
|
||||
|
||||
public ChannelSelectorTabItem(Channel value, Bindable<bool> active) : base(value)
|
||||
{
|
||||
activeBindable = active;
|
||||
activeBindable.ValueChanged += v => selectorUpdateState();
|
||||
|
||||
|
||||
Depth = float.MaxValue;
|
||||
Width = 45;
|
||||
|
||||
icon.Alpha = 0;
|
||||
|
||||
text.TextSize = 45;
|
||||
textBold.TextSize = 45;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private new void load(OsuColour colour)
|
||||
{
|
||||
backgroundInactive = colour.Gray2;
|
||||
backgroundActive = colour.Gray3;
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
selectorUpdateState();
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
selectorUpdateState();
|
||||
}
|
||||
|
||||
private void selectorUpdateState()
|
||||
{
|
||||
if (activeBindable.Value)
|
||||
fadeActive();
|
||||
else
|
||||
fadeInactive();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Online.Chat;
|
||||
@ -43,11 +44,15 @@ namespace osu.Game.Overlays.Chat
|
||||
channel.NewMessagesArrived += newMessagesArrived;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load()
|
||||
{
|
||||
newMessagesArrived(Channel.Messages);
|
||||
}
|
||||
|
||||
protected override void LoadComplete()
|
||||
{
|
||||
base.LoadComplete();
|
||||
|
||||
newMessagesArrived(Channel.Messages);
|
||||
scrollToEnd();
|
||||
}
|
||||
|
||||
@ -59,13 +64,13 @@ namespace osu.Game.Overlays.Chat
|
||||
|
||||
private void newMessagesArrived(IEnumerable<Message> newMessages)
|
||||
{
|
||||
if (!IsLoaded) return;
|
||||
|
||||
var displayMessages = newMessages.Skip(Math.Max(0, newMessages.Count() - Channel.MAX_HISTORY));
|
||||
|
||||
//up to last Channel.MAX_HISTORY messages
|
||||
flow.Add(displayMessages.Select(m => new ChatLine(m)));
|
||||
|
||||
if (!IsLoaded) return;
|
||||
|
||||
if (scroll.IsScrolledToEnd(10) || !flow.Children.Any())
|
||||
scrollToEnd();
|
||||
|
||||
|
@ -29,6 +29,7 @@ namespace osu.Game.Overlays
|
||||
public class ChatOverlay : FocusedOverlayContainer, IOnlineComponent
|
||||
{
|
||||
private const float textbox_height = 60;
|
||||
private const float channel_selection_min_height = 0.3f;
|
||||
|
||||
private ScheduledDelegate messageRequest;
|
||||
|
||||
@ -48,16 +49,21 @@ namespace osu.Game.Overlays
|
||||
|
||||
private readonly ChatTabControl channelTabs;
|
||||
|
||||
private readonly Container chatContainer;
|
||||
private readonly Box chatBackground;
|
||||
private readonly Box tabBackground;
|
||||
|
||||
private Bindable<double> chatHeight;
|
||||
|
||||
private readonly Container channelSelectionContainer;
|
||||
private readonly ChannelSelectionOverlay channelSelection;
|
||||
|
||||
protected override bool InternalContains(Vector2 screenSpacePos) => chatContainer.Contains(screenSpacePos) || channelSelection.State == Visibility.Visible && channelSelection.Contains(screenSpacePos);
|
||||
|
||||
public ChatOverlay()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
RelativePositionAxes = Axes.Both;
|
||||
Size = new Vector2(1, DEFAULT_HEIGHT);
|
||||
Anchor = Anchor.BottomLeft;
|
||||
Origin = Anchor.BottomLeft;
|
||||
|
||||
@ -65,87 +71,138 @@ namespace osu.Game.Overlays
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Container
|
||||
channelSelectionContainer = new Container
|
||||
{
|
||||
Name = @"chat area",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = TAB_AREA_HEIGHT },
|
||||
Children = new Drawable[]
|
||||
Height = 1f - DEFAULT_HEIGHT,
|
||||
Masking = true,
|
||||
Children = new[]
|
||||
{
|
||||
chatBackground = new Box
|
||||
channelSelection = new ChannelSelectionOverlay
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
currentChannelContainer = new Container
|
||||
},
|
||||
},
|
||||
chatContainer = new Container
|
||||
{
|
||||
Name = @"chat container",
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = DEFAULT_HEIGHT,
|
||||
Children = new[]
|
||||
{
|
||||
new Container
|
||||
{
|
||||
Name = @"chat area",
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding
|
||||
Padding = new MarginPadding { Top = TAB_AREA_HEIGHT },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Bottom = textbox_height + padding
|
||||
},
|
||||
chatBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
currentChannelContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Bottom = textbox_height + padding
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = textbox_height,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = padding * 2,
|
||||
Bottom = padding * 2,
|
||||
Left = ChatLine.LEFT_PADDING + padding * 2,
|
||||
Right = padding * 2,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
inputTextBox = new FocusedTextBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 1,
|
||||
PlaceholderText = "type your message",
|
||||
Exit = () => State = Visibility.Hidden,
|
||||
OnCommit = postMessage,
|
||||
ReleaseFocusOnCommit = false,
|
||||
HoldFocus = true,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Name = @"tabs area",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = textbox_height,
|
||||
Padding = new MarginPadding
|
||||
{
|
||||
Top = padding * 2,
|
||||
Bottom = padding * 2,
|
||||
Left = ChatLine.LEFT_PADDING + padding * 2,
|
||||
Right = padding * 2,
|
||||
},
|
||||
Height = TAB_AREA_HEIGHT,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
inputTextBox = new FocusedTextBox
|
||||
tabBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Height = 1,
|
||||
PlaceholderText = "type your message",
|
||||
Exit = () => State = Visibility.Hidden,
|
||||
OnCommit = postMessage,
|
||||
HoldFocus = true,
|
||||
}
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
channelTabs = new ChatTabControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
new Container
|
||||
{
|
||||
Name = @"tabs area",
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = TAB_AREA_HEIGHT,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
tabBackground = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = Color4.Black,
|
||||
},
|
||||
channelTabs = new ChatTabControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
},
|
||||
}
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
channelTabs.Current.ValueChanged += newChannel => CurrentChannel = newChannel;
|
||||
channelTabs.ChannelSelectorActive.ValueChanged += value => channelSelection.State = value ? Visibility.Visible : Visibility.Hidden;
|
||||
channelSelection.StateChanged += (overlay, state) =>
|
||||
{
|
||||
channelTabs.ChannelSelectorActive.Value = state == Visibility.Visible;
|
||||
|
||||
if (state == Visibility.Visible)
|
||||
{
|
||||
inputTextBox.HoldFocus = false;
|
||||
if (1f - chatHeight.Value < channel_selection_min_height)
|
||||
{
|
||||
chatContainer.ResizeHeightTo(1f - channel_selection_min_height, 800, EasingTypes.OutQuint);
|
||||
channelSelectionContainer.ResizeHeightTo(channel_selection_min_height, 800, EasingTypes.OutQuint);
|
||||
channelSelection.Show();
|
||||
chatHeight.Value = 1f - channel_selection_min_height;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
inputTextBox.HoldFocus = true;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
private double startDragChatHeight;
|
||||
|
||||
protected override bool OnDragStart(InputState state)
|
||||
{
|
||||
if (channelTabs.Hovering)
|
||||
return true;
|
||||
if (!channelTabs.Hovering)
|
||||
return base.OnDragStart(state);
|
||||
|
||||
return base.OnDragStart(state);
|
||||
startDragChatHeight = chatHeight.Value;
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override bool OnDrag(InputState state)
|
||||
{
|
||||
chatHeight.Value = Height - state.Mouse.Delta.Y / Parent.DrawSize.Y;
|
||||
Trace.Assert(state.Mouse.PositionMouseDown != null);
|
||||
|
||||
chatHeight.Value = startDragChatHeight - (state.Mouse.Position.Y - state.Mouse.PositionMouseDown.Value.Y) / Parent.DrawSize.Y;
|
||||
return base.OnDrag(state);
|
||||
}
|
||||
|
||||
@ -162,11 +219,15 @@ namespace osu.Game.Overlays
|
||||
}
|
||||
}
|
||||
|
||||
protected override bool OnFocus(InputState state)
|
||||
public override bool AcceptsFocus => true;
|
||||
|
||||
protected override bool OnClick(InputState state) => true;
|
||||
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
//this is necessary as inputTextBox is masked away and therefore can't get focus :(
|
||||
inputTextBox.TriggerFocus();
|
||||
return false;
|
||||
InputManager.ChangeFocus(inputTextBox);
|
||||
base.OnFocus(state);
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
@ -196,8 +257,9 @@ namespace osu.Game.Overlays
|
||||
chatHeight = config.GetBindable<double>(OsuSetting.ChatDisplayHeight);
|
||||
chatHeight.ValueChanged += h =>
|
||||
{
|
||||
Height = (float)h;
|
||||
tabBackground.FadeTo(Height == 1 ? 1 : 0.8f, 200);
|
||||
chatContainer.Height = (float)h;
|
||||
channelSelectionContainer.Height = 1f - (float)h;
|
||||
tabBackground.FadeTo(h == 1 ? 1 : 0.8f, 200);
|
||||
};
|
||||
chatHeight.TriggerChange();
|
||||
|
||||
@ -234,6 +296,16 @@ namespace osu.Game.Overlays
|
||||
addChannel(channels.Find(c => c.Name == @"#lazer"));
|
||||
addChannel(channels.Find(c => c.Name == @"#osu"));
|
||||
addChannel(channels.Find(c => c.Name == @"#lobby"));
|
||||
|
||||
channelSelection.OnRequestJoin = addChannel;
|
||||
channelSelection.Sections = new[]
|
||||
{
|
||||
new ChannelSection
|
||||
{
|
||||
Header = "All Channels",
|
||||
Channels = channels,
|
||||
},
|
||||
};
|
||||
});
|
||||
|
||||
messageRequest = Scheduler.AddDelayed(fetchNewMessages, 1000, true);
|
||||
@ -253,22 +325,32 @@ namespace osu.Game.Overlays
|
||||
|
||||
set
|
||||
{
|
||||
if (currentChannel == value) return;
|
||||
|
||||
if (currentChannel != null)
|
||||
currentChannelContainer.Clear(false);
|
||||
if (currentChannel == value || value == null) return;
|
||||
|
||||
currentChannel = value;
|
||||
|
||||
inputTextBox.Current.Disabled = currentChannel.ReadOnly;
|
||||
channelTabs.Current.Value = value;
|
||||
|
||||
var loaded = loadedChannels.Find(d => d.Channel == value);
|
||||
if (loaded == null)
|
||||
loadedChannels.Add(loaded = new DrawableChannel(currentChannel));
|
||||
{
|
||||
currentChannelContainer.FadeOut(500, EasingTypes.OutQuint);
|
||||
|
||||
inputTextBox.Current.Disabled = currentChannel.ReadOnly;
|
||||
|
||||
currentChannelContainer.Add(loaded);
|
||||
|
||||
channelTabs.Current.Value = value;
|
||||
loaded = new DrawableChannel(currentChannel);
|
||||
loadedChannels.Add(loaded);
|
||||
LoadComponentAsync(loaded, l =>
|
||||
{
|
||||
currentChannelContainer.Clear(false);
|
||||
currentChannelContainer.Add(l);
|
||||
currentChannelContainer.FadeIn(500, EasingTypes.OutQuint);
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
currentChannelContainer.Clear(false);
|
||||
currentChannelContainer.Add(loaded);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -295,6 +377,8 @@ namespace osu.Game.Overlays
|
||||
|
||||
if (CurrentChannel == null)
|
||||
CurrentChannel = channel;
|
||||
|
||||
channel.Joined.Value = true;
|
||||
}
|
||||
|
||||
private void fetchInitialMessages(Channel channel)
|
||||
|
@ -71,7 +71,7 @@ namespace osu.Game.Overlays.Dialog
|
||||
private void pressButtonAtIndex(int index)
|
||||
{
|
||||
if (index < Buttons.Count())
|
||||
Buttons.Skip(index).First().TriggerClick();
|
||||
Buttons.Skip(index).First().TriggerOnClick();
|
||||
}
|
||||
|
||||
protected override bool OnKeyDown(InputState state, KeyDownEventArgs args)
|
||||
@ -80,7 +80,7 @@ namespace osu.Game.Overlays.Dialog
|
||||
|
||||
if (args.Key == Key.Enter)
|
||||
{
|
||||
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerClick();
|
||||
Buttons.OfType<PopupDialogOkButton>().FirstOrDefault()?.TriggerOnClick();
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -5,117 +5,35 @@ using OpenTK;
|
||||
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;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public class FilterControl : Container
|
||||
public class FilterControl : SearchableListFilterControl<DirectSortCritera, RankStatus>
|
||||
{
|
||||
public static readonly float HEIGHT = 35 + 32 + 30 + padding * 2; // search + mode toggle buttons + sort tabs + padding
|
||||
private FillFlowContainer<RulesetToggleButton> modeButtons;
|
||||
|
||||
private const float padding = 10;
|
||||
|
||||
private readonly Box tabStrip;
|
||||
private readonly FillFlowContainer<RulesetToggleButton> modeButtons;
|
||||
|
||||
public readonly SearchTextBox Search;
|
||||
public readonly SortTabControl SortTabs;
|
||||
public readonly OsuEnumDropdown<RankStatus> RankStatusDropdown;
|
||||
public readonly Bindable<DirectOverlay.PanelDisplayStyle> DisplayStyle = new Bindable<DirectOverlay.PanelDisplayStyle>();
|
||||
|
||||
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || RankStatusDropdown.Contains(screenSpacePos);
|
||||
|
||||
public FilterControl()
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"384552");
|
||||
protected override DirectSortCritera DefaultTab => DirectSortCritera.Title;
|
||||
protected override Drawable CreateSupplementaryControls()
|
||||
{
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = HEIGHT;
|
||||
DisplayStyle.Value = DirectOverlay.PanelDisplayStyle.Grid;
|
||||
|
||||
Children = new Drawable[]
|
||||
modeButtons = new FillFlowContainer<RulesetToggleButton>
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"384552"),
|
||||
Alpha = 0.9f,
|
||||
},
|
||||
tabStrip = new Box
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.TopLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Search = new DirectSearchTextBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Top = padding },
|
||||
},
|
||||
modeButtons = new FillFlowContainer<RulesetToggleButton>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(padding, 0f),
|
||||
Margin = new MarginPadding { Top = padding },
|
||||
},
|
||||
SortTabs = new SortTabControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
},
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Spacing = new Vector2(10f, 0f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Margin = new MarginPadding { Top = HEIGHT - SlimEnumDropdown<DirectTab>.HEIGHT - padding, Right = DirectOverlay.WIDTH_PADDING },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(5f, 0f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new[]
|
||||
{
|
||||
new DisplayStyleToggleButton(FontAwesome.fa_th_large, DirectOverlay.PanelDisplayStyle.Grid, DisplayStyle),
|
||||
new DisplayStyleToggleButton(FontAwesome.fa_list_ul, DirectOverlay.PanelDisplayStyle.List, DisplayStyle),
|
||||
},
|
||||
},
|
||||
RankStatusDropdown = new SlimEnumDropdown<RankStatus>
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Width = 160f,
|
||||
},
|
||||
},
|
||||
},
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(10f, 0f),
|
||||
};
|
||||
|
||||
RankStatusDropdown.Current.Value = RankStatus.RankedApproved;
|
||||
SortTabs.Current.Value = SortCriteria.Title;
|
||||
SortTabs.Current.TriggerChange();
|
||||
return modeButtons;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(true)]
|
||||
private void load(OsuGame game, RulesetDatabase rulesets, OsuColour colours)
|
||||
{
|
||||
tabStrip.Colour = colours.Yellow;
|
||||
RankStatusDropdown.AccentColour = colours.BlueDark;
|
||||
DisplayStyleControl.Dropdown.AccentColour = colours.BlueDark;
|
||||
|
||||
var b = new Bindable<RulesetInfo>(); //backup bindable incase the game is null
|
||||
foreach (var r in rulesets.AllRulesets)
|
||||
@ -124,22 +42,6 @@ namespace osu.Game.Overlays.Direct
|
||||
}
|
||||
}
|
||||
|
||||
private class DirectSearchTextBox : SearchTextBox
|
||||
{
|
||||
protected override Color4 BackgroundUnfocused => backgroundColour;
|
||||
protected override Color4 BackgroundFocused => backgroundColour;
|
||||
|
||||
protected override bool AllowCommit => true;
|
||||
|
||||
private Color4 backgroundColour;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
backgroundColour = colours.Gray2.Opacity(0.9f);
|
||||
}
|
||||
}
|
||||
|
||||
private class RulesetToggleButton : ClickableContainer
|
||||
{
|
||||
private readonly TextAwesome icon;
|
||||
@ -190,46 +92,15 @@ namespace osu.Game.Overlays.Direct
|
||||
base.Dispose(isDisposing);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class DisplayStyleToggleButton : ClickableContainer
|
||||
{
|
||||
private readonly TextAwesome icon;
|
||||
private readonly DirectOverlay.PanelDisplayStyle style;
|
||||
private readonly Bindable<DirectOverlay.PanelDisplayStyle> bindable;
|
||||
|
||||
public DisplayStyleToggleButton(FontAwesome icon, DirectOverlay.PanelDisplayStyle style, Bindable<DirectOverlay.PanelDisplayStyle> bindable)
|
||||
{
|
||||
this.bindable = bindable;
|
||||
this.style = style;
|
||||
Size = new Vector2(SlimEnumDropdown<DirectTab>.HEIGHT);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
this.icon = new TextAwesome
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = icon,
|
||||
TextSize = 18,
|
||||
UseFullGlyphHeight = false,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
};
|
||||
|
||||
bindable.ValueChanged += Bindable_ValueChanged;
|
||||
Bindable_ValueChanged(bindable.Value);
|
||||
Action = () => bindable.Value = this.style;
|
||||
}
|
||||
|
||||
private void Bindable_ValueChanged(DirectOverlay.PanelDisplayStyle style)
|
||||
{
|
||||
icon.FadeTo(style == this.style ? 1.0f : 0.5f, 100);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
bindable.ValueChanged -= Bindable_ValueChanged;
|
||||
}
|
||||
}
|
||||
public enum DirectSortCritera
|
||||
{
|
||||
Title,
|
||||
Artist,
|
||||
Creator,
|
||||
Difficulty,
|
||||
Ranked,
|
||||
Rating,
|
||||
}
|
||||
}
|
||||
|
@ -2,113 +2,28 @@
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System.ComponentModel;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
using Container = osu.Framework.Graphics.Containers.Container;
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public class Header : Container
|
||||
public class Header : SearchableListHeader<DirectTab>
|
||||
{
|
||||
public static readonly float HEIGHT = 90;
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"252f3a");
|
||||
protected override float TabStripWidth => 298;
|
||||
|
||||
private readonly Box tabStrip;
|
||||
|
||||
public readonly OsuTabControl<DirectTab> Tabs;
|
||||
protected override DirectTab DefaultTab => DirectTab.Search;
|
||||
protected override Drawable CreateHeaderText() => new OsuSpriteText { Text = @"osu!direct", TextSize = 25 };
|
||||
protected override FontAwesome Icon => FontAwesome.fa_osu_chevron_down_o;
|
||||
|
||||
public Header()
|
||||
{
|
||||
Height = HEIGHT;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"252f3a"),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = DirectOverlay.WIDTH_PADDING, Right = DirectOverlay.WIDTH_PADDING },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Position = new Vector2(-35f, 5f),
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10f, 0f),
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new TextAwesome
|
||||
{
|
||||
TextSize = 25,
|
||||
Icon = FontAwesome.fa_osu_chevron_down_o,
|
||||
},
|
||||
new OsuSpriteText
|
||||
{
|
||||
TextSize = 25,
|
||||
Text = @"osu!direct",
|
||||
},
|
||||
},
|
||||
},
|
||||
tabStrip = new Box
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Width = 282, //todo: make this actually match the tab control's width instead of hardcoding
|
||||
Height = 1,
|
||||
},
|
||||
Tabs = new DirectTabControl
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Tabs.Current.Value = DirectTab.Search;
|
||||
Tabs.Current.TriggerChange();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
tabStrip.Colour = colours.Green;
|
||||
}
|
||||
|
||||
private class DirectTabControl : OsuTabControl<DirectTab>
|
||||
{
|
||||
protected override TabItem<DirectTab> CreateTabItem(DirectTab value) => new DirectTabItem(value);
|
||||
|
||||
public DirectTabControl()
|
||||
{
|
||||
Height = 25;
|
||||
AccentColour = Color4.White;
|
||||
}
|
||||
|
||||
private class DirectTabItem : OsuTabItem
|
||||
{
|
||||
public DirectTabItem(DirectTab value) : base(value)
|
||||
{
|
||||
Text.TextSize = 15;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum DirectTab
|
||||
|
@ -1,117 +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 System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public class SortTabControl : OsuTabControl<SortCriteria>
|
||||
{
|
||||
protected override TabItem<SortCriteria> CreateTabItem(SortCriteria value) => new SortTabItem(value);
|
||||
|
||||
public SortTabControl()
|
||||
{
|
||||
Height = 30;
|
||||
}
|
||||
|
||||
private class SortTabItem : TabItem<SortCriteria>
|
||||
{
|
||||
private const float transition_duration = 100;
|
||||
|
||||
private readonly Box box;
|
||||
|
||||
public override bool Active
|
||||
{
|
||||
get { return base.Active; }
|
||||
set
|
||||
{
|
||||
if (Active == value) return;
|
||||
|
||||
if (value)
|
||||
slideActive();
|
||||
else
|
||||
slideInactive();
|
||||
base.Active = value;
|
||||
}
|
||||
}
|
||||
|
||||
public SortTabItem(SortCriteria value) : base(value)
|
||||
{
|
||||
AutoSizeAxes = Axes.X;
|
||||
RelativeSizeAxes = Axes.Y;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Margin = new MarginPadding { Top = 8, Bottom = 8 },
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Text = (value as Enum).GetDescription() ?? value.ToString(),
|
||||
TextSize = 14,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
box = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 5,
|
||||
Scale = new Vector2(1f, 0f),
|
||||
Colour = Color4.White,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Anchor = Anchor.BottomLeft,
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
box.Colour = colours.Yellow;
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
if (!Active)
|
||||
slideActive();
|
||||
return true;
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
if (!Active)
|
||||
slideInactive();
|
||||
}
|
||||
|
||||
private void slideActive()
|
||||
{
|
||||
box.ScaleTo(new Vector2(1f), transition_duration);
|
||||
}
|
||||
|
||||
private void slideInactive()
|
||||
{
|
||||
box.ScaleTo(new Vector2(1f, 0f), transition_duration);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum SortCriteria
|
||||
{
|
||||
Title,
|
||||
Artist,
|
||||
Creator,
|
||||
Difficulty,
|
||||
Ranked,
|
||||
Rating,
|
||||
}
|
||||
}
|
@ -7,33 +7,35 @@ using OpenTK;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Database;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.Direct;
|
||||
|
||||
using Container = osu.Framework.Graphics.Containers.Container;
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
using OpenTK.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class DirectOverlay : WaveOverlayContainer
|
||||
public class DirectOverlay : SearchableListOverlay<DirectTab, DirectSortCritera, RankStatus>
|
||||
{
|
||||
public static readonly int WIDTH_PADDING = 80;
|
||||
private const float panel_padding = 10f;
|
||||
|
||||
private APIAccess api;
|
||||
private RulesetDatabase rulesets;
|
||||
|
||||
private readonly FilterControl filter;
|
||||
private readonly FillFlowContainer resultCountsContainer;
|
||||
private readonly OsuSpriteText resultCountsText;
|
||||
private readonly FillFlowContainer<DirectPanel> panels;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"485e74");
|
||||
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"465b71");
|
||||
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"3f5265");
|
||||
|
||||
protected override SearchableListHeader<DirectTab> CreateHeader() => new Header();
|
||||
protected override SearchableListFilterControl<DirectSortCritera, RankStatus> CreateFilterControl() => new FilterControl();
|
||||
|
||||
private IEnumerable<BeatmapSetInfo> beatmapSets;
|
||||
public IEnumerable<BeatmapSetInfo> BeatmapSets
|
||||
{
|
||||
@ -54,7 +56,7 @@ namespace osu.Game.Overlays
|
||||
return;
|
||||
}
|
||||
|
||||
recreatePanels(filter.DisplayStyle.Value);
|
||||
recreatePanels(Filter.DisplayStyleControl.DisplayStyle.Value);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,98 +84,41 @@ namespace osu.Game.Overlays
|
||||
ThirdWaveColour = OsuColour.FromHex(@"005774");
|
||||
FourthWaveColour = OsuColour.FromHex(@"003a4e");
|
||||
|
||||
Header header;
|
||||
Children = new Drawable[]
|
||||
ScrollFlow.Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
resultCountsContainer = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = OsuColour.FromHex(@"485e74"),
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Children = new[]
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Margin = new MarginPadding { Top = 5 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Triangles
|
||||
new OsuSpriteText
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
TriangleScale = 5,
|
||||
ColourLight = OsuColour.FromHex(@"465b71"),
|
||||
ColourDark = OsuColour.FromHex(@"3f5265"),
|
||||
Text = "Found ",
|
||||
TextSize = 15,
|
||||
},
|
||||
},
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Top = Header.HEIGHT + FilterControl.HEIGHT },
|
||||
Children = new[]
|
||||
{
|
||||
new ScrollContainer
|
||||
resultCountsText = new OsuSpriteText
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ScrollDraggerVisible = false,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
resultCountsContainer = new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Margin = new MarginPadding { Left = WIDTH_PADDING, Top = 6 },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "Found ",
|
||||
TextSize = 15,
|
||||
},
|
||||
resultCountsText = new OsuSpriteText
|
||||
{
|
||||
TextSize = 15,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
}
|
||||
},
|
||||
panels = new FillFlowContainer<DirectPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Top = panel_padding, Bottom = panel_padding, Left = WIDTH_PADDING, Right = WIDTH_PADDING },
|
||||
Spacing = new Vector2(panel_padding),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
TextSize = 15,
|
||||
Font = @"Exo2.0-Bold",
|
||||
},
|
||||
},
|
||||
}
|
||||
},
|
||||
filter = new FilterControl
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Margin = new MarginPadding { Top = Header.HEIGHT },
|
||||
},
|
||||
header = new Header
|
||||
panels = new FillFlowContainer<DirectPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Spacing = new Vector2(panel_padding),
|
||||
Margin = new MarginPadding { Top = 10 },
|
||||
},
|
||||
};
|
||||
|
||||
header.Tabs.Current.ValueChanged += tab => { if (tab != DirectTab.Search) filter.Search.Current.Value = string.Empty; };
|
||||
|
||||
filter.Search.Exit = Hide;
|
||||
filter.Search.Current.ValueChanged += text => { if (text != string.Empty) header.Tabs.Current.Value = DirectTab.Search; };
|
||||
filter.Search.OnCommit = (sender, text) => updateSets();
|
||||
filter.RankStatusDropdown.Current.ValueChanged += rankStatus => updateSets();
|
||||
filter.DisplayStyle.ValueChanged += recreatePanels;
|
||||
Header.Tabs.Current.ValueChanged += tab => { if (tab != DirectTab.Search) Filter.Search.Text = string.Empty; };
|
||||
Filter.Search.Current.ValueChanged += text => { if (text != string.Empty) Header.Tabs.Current.Value = DirectTab.Search; };
|
||||
Filter.Search.OnCommit = (sender, text) => updateSets();
|
||||
Filter.DisplayStyleControl.DisplayStyle.ValueChanged += recreatePanels;
|
||||
Filter.DisplayStyleControl.Dropdown.Current.ValueChanged += rankStatus => updateSets();
|
||||
|
||||
updateResultCounts();
|
||||
}
|
||||
@ -215,33 +160,13 @@ namespace osu.Game.Overlays
|
||||
BeatmapSets = null;
|
||||
getSetsRequest?.Cancel();
|
||||
|
||||
if (api == null || filter.Search.Text == string.Empty) return;
|
||||
if (api == null || Filter.Search.Text == string.Empty) return;
|
||||
|
||||
getSetsRequest = new GetBeatmapSetsRequest(filter.Search.Text, filter.RankStatusDropdown.Current.Value);
|
||||
getSetsRequest = new GetBeatmapSetsRequest(Filter.Search.Text, Filter.DisplayStyleControl.Dropdown.Current.Value);
|
||||
getSetsRequest.Success += r => BeatmapSets = r?.Select(response => response.ToSetInfo(rulesets));
|
||||
api.Queue(getSetsRequest);
|
||||
}
|
||||
|
||||
protected override bool OnFocus(InputState state)
|
||||
{
|
||||
filter.Search.TriggerFocus();
|
||||
return false;
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
base.PopIn();
|
||||
|
||||
filter.Search.HoldFocus = true;
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
|
||||
filter.Search.HoldFocus = false;
|
||||
}
|
||||
|
||||
public class ResultCounts
|
||||
{
|
||||
public readonly int Artists;
|
||||
@ -255,11 +180,5 @@ namespace osu.Game.Overlays
|
||||
Tags = tags;
|
||||
}
|
||||
}
|
||||
|
||||
public enum PanelDisplayStyle
|
||||
{
|
||||
Grid,
|
||||
List,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -66,7 +66,7 @@ namespace osu.Game.Overlays
|
||||
settingsSection.Bounding = true;
|
||||
FadeIn(transition_time, EasingTypes.OutQuint);
|
||||
|
||||
settingsSection.TriggerFocus();
|
||||
InputManager.ChangeFocus(settingsSection);
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
|
@ -16,7 +16,7 @@ using osu.Game.Rulesets.Mods;
|
||||
using osu.Game.Rulesets.UI;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Graphics.Cursor;
|
||||
|
||||
namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
@ -27,6 +27,7 @@ namespace osu.Game.Overlays.Mods
|
||||
public class ModButton : ModButtonEmpty, IHasTooltip
|
||||
{
|
||||
private ModIcon foregroundIcon;
|
||||
private ModIcon backgroundIcon;
|
||||
private readonly SpriteText text;
|
||||
private readonly Container<ModIcon> iconsContainer;
|
||||
private SampleChannel sampleOn, sampleOff;
|
||||
@ -35,38 +36,67 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
public string TooltipText => (SelectedMod?.Description ?? Mods.FirstOrDefault()?.Description) ?? string.Empty;
|
||||
|
||||
private int _selectedIndex = -1;
|
||||
private int selectedIndex
|
||||
private const EasingTypes mod_switch_easing = EasingTypes.InOutSine;
|
||||
private const double mod_switch_duration = 120;
|
||||
|
||||
// A selected index of -1 means not selected.
|
||||
private int selectedIndex = -1;
|
||||
|
||||
protected int SelectedIndex
|
||||
{
|
||||
get
|
||||
{
|
||||
return _selectedIndex;
|
||||
return selectedIndex;
|
||||
}
|
||||
set
|
||||
{
|
||||
if (value == _selectedIndex) return;
|
||||
_selectedIndex = value;
|
||||
if (value == selectedIndex) return;
|
||||
|
||||
int direction = value < selectedIndex ? -1 : 1;
|
||||
bool beforeSelected = Selected;
|
||||
|
||||
Mod modBefore = SelectedMod ?? Mods[0];
|
||||
|
||||
if (value >= Mods.Length)
|
||||
selectedIndex = -1;
|
||||
else if (value < -1)
|
||||
selectedIndex = Mods.Length - 1;
|
||||
else
|
||||
selectedIndex = value;
|
||||
|
||||
Mod modAfter = SelectedMod ?? Mods[0];
|
||||
|
||||
if (beforeSelected != Selected)
|
||||
{
|
||||
_selectedIndex = -1;
|
||||
}
|
||||
else if (value <= -2)
|
||||
{
|
||||
_selectedIndex = Mods.Length - 1;
|
||||
iconsContainer.RotateTo(Selected ? 5f : 0f, 300, EasingTypes.OutElastic);
|
||||
iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, EasingTypes.OutElastic);
|
||||
}
|
||||
|
||||
if (modBefore != modAfter)
|
||||
{
|
||||
const float rotate_angle = 16;
|
||||
|
||||
foregroundIcon.RotateTo(rotate_angle * direction, mod_switch_duration, mod_switch_easing);
|
||||
backgroundIcon.RotateTo(-rotate_angle * direction, mod_switch_duration, mod_switch_easing);
|
||||
|
||||
backgroundIcon.Icon = modAfter.Icon;
|
||||
using (iconsContainer.BeginDelayedSequence(mod_switch_duration, true))
|
||||
{
|
||||
foregroundIcon.RotateTo(-rotate_angle * direction);
|
||||
foregroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
|
||||
|
||||
backgroundIcon.RotateTo(rotate_angle * direction);
|
||||
backgroundIcon.RotateTo(0f, mod_switch_duration, mod_switch_easing);
|
||||
|
||||
iconsContainer.Schedule(() => displayMod(modAfter));
|
||||
}
|
||||
}
|
||||
|
||||
iconsContainer.RotateTo(Selected ? 5f : 0f, 300, EasingTypes.OutElastic);
|
||||
iconsContainer.ScaleTo(Selected ? 1.1f : 1f, 300, EasingTypes.OutElastic);
|
||||
foregroundIcon.Highlighted = Selected;
|
||||
|
||||
if (mod != null)
|
||||
displayMod(SelectedMod ?? Mods[0]);
|
||||
}
|
||||
}
|
||||
|
||||
public bool Selected => selectedIndex != -1;
|
||||
|
||||
public bool Selected => SelectedIndex != -1;
|
||||
|
||||
private Color4 selectedColour;
|
||||
public Color4 SelectedColour
|
||||
@ -117,7 +147,7 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
// the mods from Mod, only multiple if Mod is a MultiMod
|
||||
|
||||
public override Mod SelectedMod => Mods.ElementAtOrDefault(selectedIndex);
|
||||
public override Mod SelectedMod => Mods.ElementAtOrDefault(SelectedIndex);
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(AudioManager audio)
|
||||
@ -142,23 +172,25 @@ namespace osu.Game.Overlays.Mods
|
||||
|
||||
public void SelectNext()
|
||||
{
|
||||
(++selectedIndex == -1 ? sampleOff : sampleOn).Play();
|
||||
(++SelectedIndex == -1 ? sampleOff : sampleOn).Play();
|
||||
Action?.Invoke(SelectedMod);
|
||||
}
|
||||
|
||||
public void SelectPrevious()
|
||||
{
|
||||
(--selectedIndex == -1 ? sampleOff : sampleOn).Play();
|
||||
(--SelectedIndex == -1 ? sampleOff : sampleOn).Play();
|
||||
Action?.Invoke(SelectedMod);
|
||||
}
|
||||
|
||||
public void Deselect()
|
||||
{
|
||||
selectedIndex = -1;
|
||||
SelectedIndex = -1;
|
||||
}
|
||||
|
||||
private void displayMod(Mod mod)
|
||||
{
|
||||
if (backgroundIcon != null)
|
||||
backgroundIcon.Icon = foregroundIcon.Icon;
|
||||
foregroundIcon.Icon = mod.Icon;
|
||||
text.Text = mod.Name;
|
||||
}
|
||||
@ -170,17 +202,17 @@ namespace osu.Game.Overlays.Mods
|
||||
{
|
||||
iconsContainer.Add(new[]
|
||||
{
|
||||
new ModIcon(Mods[0])
|
||||
backgroundIcon = new ModIcon(Mods[1])
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.BottomRight,
|
||||
Anchor = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Position = new Vector2(1.5f),
|
||||
},
|
||||
foregroundIcon = new ModIcon(Mods[0])
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.BottomRight,
|
||||
Anchor = Anchor.BottomRight,
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Position = new Vector2(-1.5f),
|
||||
},
|
||||
|
73
osu.Game/Overlays/Music/CollectionsDropdown.cs
Normal file
73
osu.Game/Overlays/Music/CollectionsDropdown.cs
Normal file
@ -0,0 +1,73 @@
|
||||
// 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.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
private class CollectionsHeader : OsuDropdownHeader
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.Gray4;
|
||||
}
|
||||
|
||||
public CollectionsHeader()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
Height = 30;
|
||||
Icon.TextSize = 14;
|
||||
Icon.Margin = new MarginPadding(0);
|
||||
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
|
||||
EdgeEffect = new EdgeEffect
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class CollectionsMenu : OsuMenu
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Background.Colour = colours.Gray4;
|
||||
}
|
||||
|
||||
public CollectionsMenu()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
EdgeEffect = new EdgeEffect
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -3,10 +3,8 @@
|
||||
|
||||
using System.Collections.Generic;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
using OpenTK;
|
||||
@ -74,63 +72,5 @@ namespace osu.Game.Overlays.Music
|
||||
backgroundColour = colours.Gray2;
|
||||
}
|
||||
}
|
||||
|
||||
private 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;
|
||||
}
|
||||
|
||||
private class CollectionsHeader : OsuDropdownHeader
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
BackgroundColour = colours.Gray4;
|
||||
}
|
||||
|
||||
public CollectionsHeader()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
Height = 30;
|
||||
Icon.TextSize = 14;
|
||||
Icon.Margin = new MarginPadding(0);
|
||||
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 10, Right = 10 };
|
||||
EdgeEffect = new EdgeEffect
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
private class CollectionsMenu : OsuMenu
|
||||
{
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
Background.Colour = colours.Gray4;
|
||||
}
|
||||
|
||||
public CollectionsMenu()
|
||||
{
|
||||
CornerRadius = 5;
|
||||
EdgeEffect = new EdgeEffect
|
||||
{
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Colour = Color4.Black.Opacity(0.3f),
|
||||
Radius = 3,
|
||||
Offset = new Vector2(0f, 1f),
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Music
|
||||
private Color4 artistColour;
|
||||
|
||||
private TextAwesome handle;
|
||||
private Paragraph text;
|
||||
private TextFlowContainer text;
|
||||
private IEnumerable<SpriteText> titleSprites;
|
||||
private UnicodeBindableString titleBind;
|
||||
private UnicodeBindableString artistBind;
|
||||
@ -77,7 +77,7 @@ namespace osu.Game.Overlays.Music
|
||||
Margin = new MarginPadding { Left = 5 },
|
||||
Padding = new MarginPadding { Top = 2 },
|
||||
},
|
||||
text = new Paragraph
|
||||
text = new TextFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
@ -135,7 +135,7 @@ namespace osu.Game.Overlays.Music
|
||||
|
||||
private bool matching = true;
|
||||
|
||||
public bool MatchingCurrentFilter
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
|
@ -22,7 +22,7 @@ namespace osu.Game.Overlays.Music
|
||||
}
|
||||
}
|
||||
|
||||
public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingCurrentFilter)?.BeatmapSetInfo;
|
||||
public BeatmapSetInfo FirstVisibleSet => items.Children.FirstOrDefault(i => i.MatchingFilter)?.BeatmapSetInfo;
|
||||
|
||||
private void itemSelected(BeatmapSetInfo b)
|
||||
{
|
||||
@ -75,7 +75,7 @@ namespace osu.Game.Overlays.Music
|
||||
private class ItemSearchContainer : FillFlowContainer<PlaylistItem>, IHasFilterableChildren
|
||||
{
|
||||
public string[] FilterTerms => new string[] { };
|
||||
public bool MatchingCurrentFilter
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
|
@ -17,6 +17,7 @@ using osu.Game.Graphics;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Extensions;
|
||||
using osu.Framework.Input;
|
||||
|
||||
namespace osu.Game.Overlays.Music
|
||||
{
|
||||
@ -35,10 +36,12 @@ namespace osu.Game.Overlays.Music
|
||||
private readonly Bindable<WorkingBeatmap> beatmapBacking = new Bindable<WorkingBeatmap>();
|
||||
|
||||
public IEnumerable<BeatmapSetInfo> BeatmapSets;
|
||||
private InputManager inputManager;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours)
|
||||
private void load(OsuGameBase game, BeatmapDatabase beatmaps, OsuColour colours, UserInputManager inputManager)
|
||||
{
|
||||
this.inputManager = inputManager;
|
||||
this.beatmaps = beatmaps;
|
||||
trackManager = game.Audio.Track;
|
||||
|
||||
@ -100,7 +103,7 @@ namespace osu.Game.Overlays.Music
|
||||
protected override void PopIn()
|
||||
{
|
||||
filter.Search.HoldFocus = true;
|
||||
Schedule(() => filter.Search.TriggerFocus());
|
||||
Schedule(() => inputManager.ChangeFocus(filter.Search));
|
||||
|
||||
ResizeTo(new Vector2(1, playlist_height), transition_duration, EasingTypes.OutQuint);
|
||||
FadeIn(transition_duration, EasingTypes.OutQuint);
|
||||
|
@ -22,6 +22,7 @@ using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Threading;
|
||||
using osu.Game.Overlays.Music;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
@ -38,8 +39,8 @@ namespace osu.Game.Overlays
|
||||
private Drawable currentBackground;
|
||||
private DragBar progressBar;
|
||||
|
||||
private Button playButton;
|
||||
private Button playlistButton;
|
||||
private IconButton playButton;
|
||||
private IconButton playlistButton;
|
||||
|
||||
private SpriteText title, artist;
|
||||
|
||||
@ -143,7 +144,7 @@ namespace osu.Game.Overlays
|
||||
Anchor = Anchor.BottomCentre,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer<Button>
|
||||
new FillFlowContainer<IconButton>
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
@ -152,26 +153,26 @@ namespace osu.Game.Overlays
|
||||
Anchor = Anchor.Centre,
|
||||
Children = new[]
|
||||
{
|
||||
new Button
|
||||
new IconButton
|
||||
{
|
||||
Action = prev,
|
||||
Icon = FontAwesome.fa_step_backward,
|
||||
},
|
||||
playButton = new Button
|
||||
playButton = new IconButton
|
||||
{
|
||||
Scale = new Vector2(1.4f),
|
||||
IconScale = new Vector2(1.4f),
|
||||
Action = play,
|
||||
Icon = FontAwesome.fa_play_circle_o,
|
||||
},
|
||||
new Button
|
||||
new IconButton
|
||||
{
|
||||
Action = next,
|
||||
Icon = FontAwesome.fa_step_forward,
|
||||
},
|
||||
}
|
||||
},
|
||||
playlistButton = new Button
|
||||
playlistButton = new IconButton
|
||||
{
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.CentreRight,
|
||||
@ -266,24 +267,27 @@ namespace osu.Game.Overlays
|
||||
{
|
||||
progressBar.IsEnabled = beatmap != null;
|
||||
|
||||
bool audioEquals = beatmapBacking.Value?.BeatmapInfo?.AudioEquals(current?.BeatmapInfo) ?? false;
|
||||
TransformDirection direction = TransformDirection.None;
|
||||
|
||||
TransformDirection direction;
|
||||
|
||||
if (audioEquals)
|
||||
direction = TransformDirection.None;
|
||||
else if (queuedDirection.HasValue)
|
||||
if (current != null)
|
||||
{
|
||||
direction = queuedDirection.Value;
|
||||
queuedDirection = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
//figure out the best direction based on order in playlist.
|
||||
var last = current == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
|
||||
var next = beatmapBacking.Value == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmapBacking.Value.BeatmapSetInfo.ID).Count();
|
||||
bool audioEquals = beatmapBacking.Value?.BeatmapInfo?.AudioEquals(current.BeatmapInfo) ?? false;
|
||||
|
||||
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
||||
if (audioEquals)
|
||||
direction = TransformDirection.None;
|
||||
else if (queuedDirection.HasValue)
|
||||
{
|
||||
direction = queuedDirection.Value;
|
||||
queuedDirection = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
//figure out the best direction based on order in playlist.
|
||||
var last = playlist.BeatmapSets.TakeWhile(b => b.ID != current.BeatmapSetInfo.ID).Count();
|
||||
var next = beatmapBacking.Value == null ? -1 : playlist.BeatmapSets.TakeWhile(b => b.ID != beatmapBacking.Value.BeatmapSetInfo.ID).Count();
|
||||
|
||||
direction = last > next ? TransformDirection.Prev : TransformDirection.Next;
|
||||
}
|
||||
}
|
||||
|
||||
current = beatmapBacking.Value;
|
||||
@ -412,105 +416,5 @@ namespace osu.Game.Overlays
|
||||
sprite.Texture = beatmap?.Background ?? textures.Get(@"Backgrounds/bg4");
|
||||
}
|
||||
}
|
||||
|
||||
private class Button : ClickableContainer
|
||||
{
|
||||
private readonly TextAwesome icon;
|
||||
private readonly Box hover;
|
||||
private readonly Container content;
|
||||
|
||||
public FontAwesome Icon
|
||||
{
|
||||
get { return icon.Icon; }
|
||||
set { icon.Icon = value; }
|
||||
}
|
||||
|
||||
private const float button_size = 30;
|
||||
private Color4 flashColour;
|
||||
|
||||
public Vector2 IconScale
|
||||
{
|
||||
get { return icon.Scale; }
|
||||
set { icon.Scale = value; }
|
||||
}
|
||||
|
||||
public Button()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Origin = Anchor.Centre;
|
||||
Anchor = Anchor.Centre;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
content = new Container
|
||||
{
|
||||
Size = new Vector2(button_size),
|
||||
CornerRadius = 5,
|
||||
Masking = true,
|
||||
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre,
|
||||
EdgeEffect = new EdgeEffect
|
||||
{
|
||||
Colour = Color4.Black.Opacity(0.04f),
|
||||
Type = EdgeEffectType.Shadow,
|
||||
Radius = 5,
|
||||
},
|
||||
Children = new Drawable[]
|
||||
{
|
||||
hover = new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Alpha = 0,
|
||||
},
|
||||
icon = new TextAwesome
|
||||
{
|
||||
TextSize = 18,
|
||||
Origin = Anchor.Centre,
|
||||
Anchor = Anchor.Centre
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
hover.Colour = colours.Yellow.Opacity(0.6f);
|
||||
flashColour = colours.Yellow;
|
||||
}
|
||||
|
||||
protected override bool OnHover(InputState state)
|
||||
{
|
||||
hover.FadeIn(500, EasingTypes.OutQuint);
|
||||
return base.OnHover(state);
|
||||
}
|
||||
|
||||
protected override void OnHoverLost(InputState state)
|
||||
{
|
||||
hover.FadeOut(500, EasingTypes.OutQuint);
|
||||
base.OnHoverLost(state);
|
||||
}
|
||||
|
||||
protected override bool OnClick(InputState state)
|
||||
{
|
||||
hover.FlashColour(flashColour, 800, EasingTypes.OutQuint);
|
||||
return base.OnClick(state);
|
||||
}
|
||||
|
||||
protected override bool OnMouseDown(InputState state, MouseDownEventArgs args)
|
||||
{
|
||||
content.ScaleTo(0.75f, 2000, EasingTypes.OutQuint);
|
||||
return base.OnMouseDown(state, args);
|
||||
}
|
||||
|
||||
protected override bool OnMouseUp(InputState state, MouseUpEventArgs args)
|
||||
{
|
||||
content.ScaleTo(1, 1000, EasingTypes.OutElastic);
|
||||
return base.OnMouseUp(state, args);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
102
osu.Game/Overlays/SearchableList/DisplayStyleControl.cs
Normal file
102
osu.Game/Overlays/SearchableList/DisplayStyleControl.cs
Normal file
@ -0,0 +1,102 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using OpenTK;
|
||||
using osu.Framework.Configuration;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public class DisplayStyleControl<T> : Container
|
||||
{
|
||||
public readonly SlimEnumDropdown<T> Dropdown;
|
||||
public readonly Bindable<PanelDisplayStyle> DisplayStyle = new Bindable<PanelDisplayStyle>();
|
||||
|
||||
public DisplayStyleControl()
|
||||
{
|
||||
AutoSizeAxes = Axes.Both;
|
||||
|
||||
Children = new[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
Spacing = new Vector2(10f, 0f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Spacing = new Vector2(5f, 0f),
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new[]
|
||||
{
|
||||
new DisplayStyleToggleButton(FontAwesome.fa_th_large, PanelDisplayStyle.Grid, DisplayStyle),
|
||||
new DisplayStyleToggleButton(FontAwesome.fa_list_ul, PanelDisplayStyle.List, DisplayStyle),
|
||||
},
|
||||
},
|
||||
Dropdown = new SlimEnumDropdown<T>
|
||||
{
|
||||
RelativeSizeAxes = Axes.None,
|
||||
Width = 160f,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
DisplayStyle.Value = PanelDisplayStyle.Grid;
|
||||
}
|
||||
|
||||
private class DisplayStyleToggleButton : ClickableContainer
|
||||
{
|
||||
private readonly TextAwesome icon;
|
||||
private readonly PanelDisplayStyle style;
|
||||
private readonly Bindable<PanelDisplayStyle> bindable;
|
||||
|
||||
public DisplayStyleToggleButton(FontAwesome icon, PanelDisplayStyle style, Bindable<PanelDisplayStyle> bindable)
|
||||
{
|
||||
this.bindable = bindable;
|
||||
this.style = style;
|
||||
Size = new Vector2(25f);
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
this.icon = new TextAwesome
|
||||
{
|
||||
Anchor = Anchor.Centre,
|
||||
Origin = Anchor.Centre,
|
||||
Icon = icon,
|
||||
TextSize = 18,
|
||||
UseFullGlyphHeight = false,
|
||||
Alpha = 0.5f,
|
||||
},
|
||||
};
|
||||
|
||||
bindable.ValueChanged += Bindable_ValueChanged;
|
||||
Bindable_ValueChanged(bindable.Value);
|
||||
Action = () => bindable.Value = this.style;
|
||||
}
|
||||
|
||||
private void Bindable_ValueChanged(PanelDisplayStyle style)
|
||||
{
|
||||
icon.FadeTo(style == this.style ? 1.0f : 0.5f, 100);
|
||||
}
|
||||
|
||||
protected override void Dispose(bool isDisposing)
|
||||
{
|
||||
bindable.ValueChanged -= Bindable_ValueChanged;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum PanelDisplayStyle
|
||||
{
|
||||
Grid,
|
||||
List,
|
||||
}
|
||||
}
|
28
osu.Game/Overlays/SearchableList/HeaderTabControl.cs
Normal file
28
osu.Game/Overlays/SearchableList/HeaderTabControl.cs
Normal file
@ -0,0 +1,28 @@
|
||||
// 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.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public class HeaderTabControl<T> : OsuTabControl<T>
|
||||
{
|
||||
protected override TabItem<T> CreateTabItem(T value) => new HeaderTabItem(value);
|
||||
|
||||
public HeaderTabControl()
|
||||
{
|
||||
Height = 26;
|
||||
AccentColour = Color4.White;
|
||||
}
|
||||
|
||||
private class HeaderTabItem : OsuTabItem
|
||||
{
|
||||
public HeaderTabItem(T value) : base(value)
|
||||
{
|
||||
Text.TextSize = 16;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
137
osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs
Normal file
137
osu.Game/Overlays/SearchableList/SearchableListFilterControl.cs
Normal file
@ -0,0 +1,137 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Extensions.Color4Extensions;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public abstract class SearchableListFilterControl<T, U> : Container
|
||||
{
|
||||
private const float padding = 10;
|
||||
|
||||
private readonly Container filterContainer;
|
||||
private readonly Box tabStrip;
|
||||
|
||||
public readonly SearchTextBox Search;
|
||||
public readonly PageTabControl<T> Tabs;
|
||||
public readonly DisplayStyleControl<U> DisplayStyleControl;
|
||||
|
||||
protected abstract Color4 BackgroundColour { get; }
|
||||
protected abstract T DefaultTab { get; }
|
||||
protected virtual Drawable CreateSupplementaryControls() => null;
|
||||
|
||||
protected override bool InternalContains(Vector2 screenSpacePos) => base.InternalContains(screenSpacePos) || DisplayStyleControl.Dropdown.Contains(screenSpacePos);
|
||||
|
||||
protected SearchableListFilterControl()
|
||||
{
|
||||
if (!typeof(T).IsEnum)
|
||||
throw new InvalidOperationException("SearchableListFilterControl's sort tabs only support enums as the generic type argument");
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
|
||||
var controls = CreateSupplementaryControls();
|
||||
Container controlsContainer;
|
||||
Children = new Drawable[]
|
||||
{
|
||||
filterContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = BackgroundColour,
|
||||
Alpha = 0.9f,
|
||||
},
|
||||
tabStrip = new Box
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1,
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Top = padding, Horizontal = SearchableListOverlay.WIDTH_PADDING },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Search = new FilterSearchTextBox
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
controlsContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Top = controls != null ? padding : 0 },
|
||||
},
|
||||
Tabs = new PageTabControl<T>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
new Box //keep the tab strip part of autosize, but don't put it in the flow container
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
Height = 1,
|
||||
Colour = Color4.White.Opacity(0),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
DisplayStyleControl = new DisplayStyleControl<U>
|
||||
{
|
||||
Anchor = Anchor.TopRight,
|
||||
Origin = Anchor.TopRight,
|
||||
},
|
||||
};
|
||||
|
||||
if (controls != null) controlsContainer.Children = new[] { controls };
|
||||
|
||||
Tabs.Current.Value = DefaultTab;
|
||||
Tabs.Current.TriggerChange();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
tabStrip.Colour = colours.Yellow;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
Height = filterContainer.Height;
|
||||
DisplayStyleControl.Margin = new MarginPadding { Top = filterContainer.Height - 35, Right = SearchableListOverlay.WIDTH_PADDING };
|
||||
}
|
||||
|
||||
private class FilterSearchTextBox : SearchTextBox
|
||||
{
|
||||
protected override Color4 BackgroundUnfocused => backgroundColour;
|
||||
protected override Color4 BackgroundFocused => backgroundColour;
|
||||
protected override bool AllowCommit => true;
|
||||
|
||||
private Color4 backgroundColour;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
backgroundColour = colours.Gray2.Opacity(0.9f);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
93
osu.Game/Overlays/SearchableList/SearchableListHeader.cs
Normal file
93
osu.Game/Overlays/SearchableList/SearchableListHeader.cs
Normal file
@ -0,0 +1,93 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using System;
|
||||
using OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Game.Graphics;
|
||||
|
||||
namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public abstract class SearchableListHeader<T> : Container
|
||||
{
|
||||
private readonly Box tabStrip;
|
||||
|
||||
public readonly HeaderTabControl<T> Tabs;
|
||||
|
||||
protected abstract Color4 BackgroundColour { get; }
|
||||
protected abstract float TabStripWidth { get; } //can be removed once (if?) TabControl support auto sizing
|
||||
protected abstract T DefaultTab { get; }
|
||||
protected abstract Drawable CreateHeaderText();
|
||||
protected abstract FontAwesome Icon { get; }
|
||||
|
||||
protected SearchableListHeader()
|
||||
{
|
||||
if (!typeof(T).IsEnum)
|
||||
throw new InvalidOperationException("BrowseHeader only supports enums as the generic type argument");
|
||||
|
||||
RelativeSizeAxes = Axes.X;
|
||||
Height = 90;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = BackgroundColour,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Padding = new MarginPadding { Left = SearchableListOverlay.WIDTH_PADDING, Right = SearchableListOverlay.WIDTH_PADDING },
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new FillFlowContainer
|
||||
{
|
||||
Anchor = Anchor.CentreLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Position = new Vector2(-35f, 5f),
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Spacing = new Vector2(10f, 0f),
|
||||
Children = new[]
|
||||
{
|
||||
new TextAwesome
|
||||
{
|
||||
TextSize = 25,
|
||||
Icon = Icon,
|
||||
},
|
||||
CreateHeaderText(),
|
||||
},
|
||||
},
|
||||
tabStrip = new Box
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
Width = TabStripWidth,
|
||||
Height = 1,
|
||||
},
|
||||
Tabs = new HeaderTabControl<T>
|
||||
{
|
||||
Anchor = Anchor.BottomLeft,
|
||||
Origin = Anchor.BottomLeft,
|
||||
RelativeSizeAxes = Axes.X,
|
||||
},
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Tabs.Current.Value = DefaultTab;
|
||||
Tabs.Current.TriggerChange();
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
tabStrip.Colour = colours.Green;
|
||||
}
|
||||
}
|
||||
}
|
123
osu.Game/Overlays/SearchableList/SearchableListOverlay.cs
Normal file
123
osu.Game/Overlays/SearchableList/SearchableListOverlay.cs
Normal file
@ -0,0 +1,123 @@
|
||||
// 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.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Framework.Graphics.Sprites;
|
||||
using osu.Framework.Input;
|
||||
using osu.Game.Graphics.Backgrounds;
|
||||
|
||||
namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public abstract class SearchableListOverlay : WaveOverlayContainer
|
||||
{
|
||||
public static readonly float WIDTH_PADDING = 80;
|
||||
}
|
||||
|
||||
public abstract class SearchableListOverlay<T, U, S> : SearchableListOverlay
|
||||
{
|
||||
private readonly Container scrollContainer;
|
||||
|
||||
protected readonly SearchableListHeader<T> Header;
|
||||
protected readonly SearchableListFilterControl<U, S> Filter;
|
||||
protected readonly FillFlowContainer ScrollFlow;
|
||||
|
||||
protected abstract Color4 BackgroundColour { get; }
|
||||
protected abstract Color4 TrianglesColourLight { get; }
|
||||
protected abstract Color4 TrianglesColourDark { get; }
|
||||
protected abstract SearchableListHeader<T> CreateHeader();
|
||||
protected abstract SearchableListFilterControl<U, S> CreateFilterControl();
|
||||
|
||||
protected SearchableListOverlay()
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both;
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new Box
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Colour = BackgroundColour,
|
||||
},
|
||||
new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Masking = true,
|
||||
Children = new[]
|
||||
{
|
||||
new Triangles
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
TriangleScale = 5,
|
||||
ColourLight = TrianglesColourLight,
|
||||
ColourDark = TrianglesColourDark,
|
||||
},
|
||||
},
|
||||
},
|
||||
scrollContainer = new Container
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
Children = new[]
|
||||
{
|
||||
new ScrollContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.Both,
|
||||
ScrollbarVisible = false,
|
||||
Children = new[]
|
||||
{
|
||||
ScrollFlow = new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Padding = new MarginPadding { Horizontal = WIDTH_PADDING },
|
||||
Direction = FillDirection.Vertical,
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
new FillFlowContainer
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Direction = FillDirection.Vertical,
|
||||
AlwaysReceiveInput = true,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
Header = CreateHeader(),
|
||||
Filter = CreateFilterControl(),
|
||||
},
|
||||
},
|
||||
};
|
||||
|
||||
Filter.Search.Exit = Hide;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
|
||||
scrollContainer.Padding = new MarginPadding { Top = Header.Height + Filter.Height };
|
||||
}
|
||||
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
InputManager.ChangeFocus(Filter.Search);
|
||||
}
|
||||
|
||||
protected override void PopIn()
|
||||
{
|
||||
base.PopIn();
|
||||
|
||||
Filter.Search.HoldFocus = true;
|
||||
}
|
||||
|
||||
protected override void PopOut()
|
||||
{
|
||||
base.PopOut();
|
||||
|
||||
Filter.Search.HoldFocus = false;
|
||||
}
|
||||
}
|
||||
}
|
@ -7,12 +7,10 @@ using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.UserInterface;
|
||||
using osu.Game.Graphics.UserInterface;
|
||||
|
||||
namespace osu.Game.Overlays.Direct
|
||||
namespace osu.Game.Overlays.SearchableList
|
||||
{
|
||||
public class SlimEnumDropdown<T> : OsuEnumDropdown<T>
|
||||
{
|
||||
public const float HEIGHT = 25;
|
||||
|
||||
protected override DropdownHeader CreateHeader() => new SlimDropdownHeader { AccentColour = AccentColour };
|
||||
protected override Menu CreateMenu() => new SlimMenu();
|
||||
|
||||
@ -20,7 +18,7 @@ namespace osu.Game.Overlays.Direct
|
||||
{
|
||||
public SlimDropdownHeader()
|
||||
{
|
||||
Height = HEIGHT;
|
||||
Height = 25;
|
||||
Icon.TextSize = 16;
|
||||
Foreground.Padding = new MarginPadding { Top = 4, Bottom = 4, Left = 8, Right = 4 };
|
||||
}
|
@ -27,6 +27,11 @@ namespace osu.Game.Overlays.Settings.Sections.Gameplay
|
||||
LabelText = "up to",
|
||||
Bindable = config.GetBindable<double>(OsuSetting.DisplayStarsMaximum)
|
||||
},
|
||||
new SettingsEnumDropdown<SelectionRandomType>
|
||||
{
|
||||
LabelText = "Random beatmap selection",
|
||||
Bindable = config.GetBindable<SelectionRandomType>(OsuSetting.SelectionRandomType),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -51,9 +51,12 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
Spacing = new Vector2(0f, 5f);
|
||||
}
|
||||
|
||||
private InputManager inputManager;
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(OsuColour colours, APIAccess api)
|
||||
private void load(OsuColour colours, APIAccess api, UserInputManager inputManager)
|
||||
{
|
||||
this.inputManager = inputManager;
|
||||
this.colours = colours;
|
||||
api?.Register(this);
|
||||
}
|
||||
@ -160,13 +163,17 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
break;
|
||||
}
|
||||
|
||||
form?.TriggerFocus();
|
||||
if (form != null) inputManager.ChangeFocus(form);
|
||||
}
|
||||
|
||||
protected override bool OnFocus(InputState state)
|
||||
public override bool AcceptsFocus => true;
|
||||
|
||||
protected override bool OnClick(InputState state) => true;
|
||||
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
form?.TriggerFocus();
|
||||
return base.OnFocus(state);
|
||||
if (form != null) inputManager.ChangeFocus(form);
|
||||
base.OnFocus(state);
|
||||
}
|
||||
|
||||
private class LoginForm : FillFlowContainer
|
||||
@ -174,6 +181,7 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
private TextBox username;
|
||||
private TextBox password;
|
||||
private APIAccess api;
|
||||
private InputManager inputManager;
|
||||
|
||||
private void performLogin()
|
||||
{
|
||||
@ -182,8 +190,9 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader(permitNulls: true)]
|
||||
private void load(APIAccess api, OsuConfigManager config)
|
||||
private void load(APIAccess api, OsuConfigManager config, UserInputManager inputManager)
|
||||
{
|
||||
this.inputManager = inputManager;
|
||||
this.api = api;
|
||||
Direction = FillDirection.Vertical;
|
||||
Spacing = new Vector2(0, 5);
|
||||
@ -230,17 +239,13 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
};
|
||||
}
|
||||
|
||||
protected override bool OnFocus(InputState state)
|
||||
{
|
||||
Schedule(() =>
|
||||
{
|
||||
if (string.IsNullOrEmpty(username.Text))
|
||||
username.TriggerFocus();
|
||||
else
|
||||
password.TriggerFocus();
|
||||
});
|
||||
public override bool AcceptsFocus => true;
|
||||
|
||||
return base.OnFocus(state);
|
||||
protected override bool OnClick(InputState state) => true;
|
||||
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
Schedule(() => { inputManager.ChangeFocus(string.IsNullOrEmpty(username.Text) ? username : password); });
|
||||
}
|
||||
}
|
||||
|
||||
@ -340,8 +345,8 @@ namespace osu.Game.Overlays.Settings.Sections.General
|
||||
{
|
||||
public UserDropdownMenuItem(string text, UserAction current) : base(text, current)
|
||||
{
|
||||
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = UserDropdownHeader.LABEL_LEFT_MARGIN, Right = 5 };
|
||||
Chevron.Margin = new MarginPadding { Left = 2, Right = 3 };
|
||||
Foreground.Padding = new MarginPadding { Top = 5, Bottom = 5, Left = 10, Right = 5 };
|
||||
Label.Margin = new MarginPadding { Left = UserDropdownHeader.LABEL_LEFT_MARGIN - 11 };
|
||||
CornerRadius = 5;
|
||||
}
|
||||
}
|
||||
|
@ -14,14 +14,31 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
{
|
||||
protected override string Header => "Mouse";
|
||||
|
||||
private readonly BindableBool rawInputToggle = new BindableBool();
|
||||
private Bindable<string> activeInputHandlers;
|
||||
private SensitivitySetting sensitivity;
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuConfigManager osuConfig, FrameworkConfigManager config)
|
||||
{
|
||||
activeInputHandlers = config.GetBindable<string>(FrameworkSetting.ActiveInputHandlers);
|
||||
rawInputToggle.Value = activeInputHandlers.Value.Contains("Raw");
|
||||
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new SettingsCheckbox
|
||||
{
|
||||
LabelText = "Raw Input",
|
||||
Bindable = rawInputToggle
|
||||
},
|
||||
sensitivity = new SensitivitySetting
|
||||
{
|
||||
LabelText = "Cursor Sensitivity",
|
||||
Bindable = config.GetBindable<double>(FrameworkSetting.CursorSensitivity)
|
||||
},
|
||||
new SettingsEnumDropdown<ConfineMouseMode>
|
||||
{
|
||||
LabelText = "Confine mouse cursor",
|
||||
LabelText = "Confine mouse cursor to window",
|
||||
Bindable = config.GetBindable<ConfineMouseMode>(FrameworkSetting.ConfineMouseMode),
|
||||
},
|
||||
new SettingsCheckbox
|
||||
@ -35,11 +52,82 @@ namespace osu.Game.Overlays.Settings.Sections.Input
|
||||
Bindable = osuConfig.GetBindable<bool>(OsuSetting.MouseDisableButtons)
|
||||
},
|
||||
};
|
||||
|
||||
rawInputToggle.ValueChanged += enabled =>
|
||||
{
|
||||
// this is temporary until we support per-handler settings.
|
||||
const string raw_mouse_handler = @"OpenTKRawMouseHandler";
|
||||
const string standard_mouse_handler = @"OpenTKMouseHandler";
|
||||
|
||||
activeInputHandlers.Value = enabled ?
|
||||
activeInputHandlers.Value.Replace(standard_mouse_handler, raw_mouse_handler) :
|
||||
activeInputHandlers.Value.Replace(raw_mouse_handler, standard_mouse_handler);
|
||||
|
||||
sensitivity.Bindable.Disabled = !enabled;
|
||||
};
|
||||
|
||||
rawInputToggle.TriggerChange();
|
||||
}
|
||||
|
||||
private class SensitivitySetting : SettingsSlider<double, SensitivitySlider>
|
||||
{
|
||||
public override Bindable<double> Bindable
|
||||
{
|
||||
get { return ((SensitivitySlider)Control).Sensitivity; }
|
||||
|
||||
set
|
||||
{
|
||||
BindableDouble doubleValue = (BindableDouble)value;
|
||||
|
||||
// create a second layer of bindable so we can only handle state changes when not being dragged.
|
||||
((SensitivitySlider)Control).Sensitivity = doubleValue;
|
||||
|
||||
// this bindable will still act as the "interactive" bindable displayed during a drag.
|
||||
base.Bindable = new BindableDouble(doubleValue.Value)
|
||||
{
|
||||
MinValue = doubleValue.MinValue,
|
||||
MaxValue = doubleValue.MaxValue
|
||||
};
|
||||
|
||||
// one-way binding to update the sliderbar with changes from external actions.
|
||||
doubleValue.DisabledChanged += disabled => base.Bindable.Disabled = disabled;
|
||||
doubleValue.ValueChanged += newValue => base.Bindable.Value = newValue;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private class SensitivitySlider : OsuSliderBar<double>
|
||||
{
|
||||
public override string TooltipText => Current.Value.ToString(@"0.##x");
|
||||
public Bindable<double> Sensitivity;
|
||||
|
||||
public SensitivitySlider()
|
||||
{
|
||||
KeyboardStep = 0.01f;
|
||||
|
||||
Current.ValueChanged += newValue =>
|
||||
{
|
||||
if (!isDragging && Sensitivity != null)
|
||||
Sensitivity.Value = newValue;
|
||||
};
|
||||
}
|
||||
|
||||
private bool isDragging;
|
||||
|
||||
protected override bool OnDragStart(InputState state)
|
||||
{
|
||||
isDragging = true;
|
||||
return base.OnDragStart(state);
|
||||
}
|
||||
|
||||
protected override bool OnDragEnd(InputState state)
|
||||
{
|
||||
isDragging = false;
|
||||
Current.TriggerChange();
|
||||
|
||||
return base.OnDragEnd(state);
|
||||
}
|
||||
|
||||
public override string TooltipText => Current.Disabled ? "Enable raw input to adjust sensitivity" : Current.Value.ToString(@"0.##x");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -39,7 +39,7 @@ namespace osu.Game.Overlays.Settings
|
||||
// hold a reference to the provided bindable so we don't have to in every settings section.
|
||||
private Bindable<T> bindable;
|
||||
|
||||
public Bindable<T> Bindable
|
||||
public virtual Bindable<T> Bindable
|
||||
{
|
||||
get
|
||||
{
|
||||
@ -55,7 +55,7 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public string[] FilterTerms => new[] { LabelText };
|
||||
|
||||
public bool MatchingCurrentFilter
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
|
@ -24,7 +24,7 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
||||
public string[] FilterTerms => new[] { Header };
|
||||
public bool MatchingCurrentFilter
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
|
@ -20,7 +20,7 @@ namespace osu.Game.Overlays.Settings
|
||||
|
||||
public IEnumerable<IFilterable> FilterableChildren => Children.OfType<IFilterable>();
|
||||
public string[] FilterTerms => new[] { Header };
|
||||
public bool MatchingCurrentFilter
|
||||
public bool MatchingFilter
|
||||
{
|
||||
set
|
||||
{
|
||||
|
@ -134,13 +134,18 @@ namespace osu.Game.Overlays
|
||||
FadeTo(0, TRANSITION_LENGTH / 2);
|
||||
|
||||
searchTextBox.HoldFocus = false;
|
||||
searchTextBox.TriggerFocusLost();
|
||||
if (searchTextBox.HasFocus)
|
||||
InputManager.ChangeFocus(null);
|
||||
}
|
||||
|
||||
protected override bool OnFocus(InputState state)
|
||||
public override bool AcceptsFocus => true;
|
||||
|
||||
protected override bool OnClick(InputState state) => true;
|
||||
|
||||
protected override void OnFocus(InputState state)
|
||||
{
|
||||
searchTextBox.TriggerFocus(state);
|
||||
return false;
|
||||
InputManager.ChangeFocus(searchTextBox);
|
||||
base.OnFocus(state);
|
||||
}
|
||||
|
||||
private class SettingsSectionsContainer : SectionsContainer
|
||||
@ -158,7 +163,7 @@ namespace osu.Game.Overlays
|
||||
|
||||
public SettingsSectionsContainer()
|
||||
{
|
||||
ScrollContainer.ScrollDraggerVisible = false;
|
||||
ScrollContainer.ScrollbarVisible = false;
|
||||
Add(headerBackground = new Box
|
||||
{
|
||||
Colour = Color4.Black,
|
||||
|
31
osu.Game/Overlays/Social/FilterControl.cs
Normal file
31
osu.Game/Overlays/Social/FilterControl.cs
Normal file
@ -0,0 +1,31 @@
|
||||
// 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.Graphics;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
|
||||
namespace osu.Game.Overlays.Social
|
||||
{
|
||||
public class FilterControl : SearchableListFilterControl<SocialSortCriteria, SortDirection>
|
||||
{
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"47253a");
|
||||
protected override SocialSortCriteria DefaultTab => SocialSortCriteria.Rank;
|
||||
|
||||
public FilterControl()
|
||||
{
|
||||
Tabs.Margin = new MarginPadding { Top = 10 };
|
||||
}
|
||||
}
|
||||
|
||||
public enum SocialSortCriteria
|
||||
{
|
||||
Rank,
|
||||
//Location,
|
||||
//[Description("Time Zone")]
|
||||
//TimeZone,
|
||||
//[Description("World Map")]
|
||||
//WorldMap,
|
||||
}
|
||||
}
|
65
osu.Game/Overlays/Social/Header.cs
Normal file
65
osu.Game/Overlays/Social/Header.cs
Normal file
@ -0,0 +1,65 @@
|
||||
// Copyright (c) 2007-2017 ppy Pty Ltd <contact@ppy.sh>.
|
||||
// Licensed under the MIT Licence - https://raw.githubusercontent.com/ppy/osu/master/LICENCE
|
||||
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Game.Graphics.Sprites;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Framework.Allocation;
|
||||
using System.ComponentModel;
|
||||
|
||||
namespace osu.Game.Overlays.Social
|
||||
{
|
||||
public class Header : SearchableListHeader<SocialTab>
|
||||
{
|
||||
private OsuSpriteText browser;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"38202e");
|
||||
protected override float TabStripWidth => 438;
|
||||
protected override SocialTab DefaultTab => SocialTab.OnlinePlayers;
|
||||
protected override FontAwesome Icon => FontAwesome.fa_users;
|
||||
|
||||
protected override Drawable CreateHeaderText()
|
||||
{
|
||||
return new FillFlowContainer
|
||||
{
|
||||
AutoSizeAxes = Axes.Both,
|
||||
Direction = FillDirection.Horizontal,
|
||||
Children = new[]
|
||||
{
|
||||
new OsuSpriteText
|
||||
{
|
||||
Text = "social ",
|
||||
TextSize = 25,
|
||||
},
|
||||
browser = new OsuSpriteText
|
||||
{
|
||||
Text = "browser",
|
||||
TextSize = 25,
|
||||
Font = @"Exo2.0-Light",
|
||||
},
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(OsuColour colours)
|
||||
{
|
||||
browser.Colour = colours.Pink;
|
||||
}
|
||||
}
|
||||
|
||||
public enum SocialTab
|
||||
{
|
||||
[Description("Online Players")]
|
||||
OnlinePlayers,
|
||||
//[Description("Online Friends")]
|
||||
//OnlineFriends,
|
||||
//[Description("Online Team Members")]
|
||||
//OnlineTeamMembers,
|
||||
//[Description("Chat Channels")]
|
||||
//ChatChannels,
|
||||
}
|
||||
}
|
109
osu.Game/Overlays/SocialOverlay.cs
Normal file
109
osu.Game/Overlays/SocialOverlay.cs
Normal file
@ -0,0 +1,109 @@
|
||||
// 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 OpenTK;
|
||||
using OpenTK.Graphics;
|
||||
using osu.Framework.Graphics;
|
||||
using osu.Framework.Graphics.Containers;
|
||||
using osu.Game.Graphics;
|
||||
using osu.Game.Online.API;
|
||||
using osu.Game.Online.API.Requests;
|
||||
using osu.Game.Overlays.SearchableList;
|
||||
using osu.Game.Overlays.Social;
|
||||
using osu.Game.Users;
|
||||
|
||||
namespace osu.Game.Overlays
|
||||
{
|
||||
public class SocialOverlay : SearchableListOverlay<SocialTab, SocialSortCriteria, SortDirection>, IOnlineComponent
|
||||
{
|
||||
private readonly FillFlowContainer<UserPanel> panelFlow;
|
||||
|
||||
protected override Color4 BackgroundColour => OsuColour.FromHex(@"60284b");
|
||||
protected override Color4 TrianglesColourLight => OsuColour.FromHex(@"672b51");
|
||||
protected override Color4 TrianglesColourDark => OsuColour.FromHex(@"5c2648");
|
||||
|
||||
protected override SearchableListHeader<SocialTab> CreateHeader() => new Header();
|
||||
protected override SearchableListFilterControl<SocialSortCriteria, SortDirection> CreateFilterControl() => new FilterControl();
|
||||
|
||||
private IEnumerable<User> users;
|
||||
public IEnumerable<User> Users
|
||||
{
|
||||
get { return users; }
|
||||
set
|
||||
{
|
||||
if (users?.Equals(value) ?? false) return;
|
||||
users = value;
|
||||
|
||||
if (users == null)
|
||||
panelFlow.Clear();
|
||||
else
|
||||
{
|
||||
panelFlow.Children = users.Select(u =>
|
||||
{
|
||||
var p = new UserPanel(u) { Width = 300 };
|
||||
p.Status.BindTo(u.Status);
|
||||
return p;
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SocialOverlay()
|
||||
{
|
||||
FirstWaveColour = OsuColour.FromHex(@"cb5fa0");
|
||||
SecondWaveColour = OsuColour.FromHex(@"b04384");
|
||||
ThirdWaveColour = OsuColour.FromHex(@"9b2b6e");
|
||||
FourthWaveColour = OsuColour.FromHex(@"6d214d");
|
||||
|
||||
ScrollFlow.Children = new[]
|
||||
{
|
||||
panelFlow = new FillFlowContainer<UserPanel>
|
||||
{
|
||||
RelativeSizeAxes = Axes.X,
|
||||
AutoSizeAxes = Axes.Y,
|
||||
Margin = new MarginPadding { Top = 20 },
|
||||
Spacing = new Vector2(10f),
|
||||
},
|
||||
};
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(APIAccess api)
|
||||
{
|
||||
if (Users == null)
|
||||
reloadUsers(api);
|
||||
}
|
||||
|
||||
private void reloadUsers(APIAccess api)
|
||||
{
|
||||
Users = null;
|
||||
|
||||
// no this is not the correct data source, but it's something.
|
||||
var request = new GetUsersRequest();
|
||||
request.Success += res => Users = res.Select(e => e.User);
|
||||
api.Queue(request);
|
||||
}
|
||||
|
||||
public void APIStateChanged(APIAccess api, APIState state)
|
||||
{
|
||||
switch (state)
|
||||
{
|
||||
case APIState.Online:
|
||||
reloadUsers(api);
|
||||
break;
|
||||
default:
|
||||
Users = null;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public enum SortDirection
|
||||
{
|
||||
Descending,
|
||||
Ascending,
|
||||
}
|
||||
}
|
@ -63,6 +63,7 @@ namespace osu.Game.Overlays.Toolbar
|
||||
AutoSizeAxes = Axes.X,
|
||||
Children = new Drawable[]
|
||||
{
|
||||
new ToolbarSocialButton(),
|
||||
new ToolbarChatButton(),
|
||||
new ToolbarMusicButton(),
|
||||
new ToolbarButton
|
||||
|
22
osu.Game/Overlays/Toolbar/ToolbarSocialButton.cs
Normal file
22
osu.Game/Overlays/Toolbar/ToolbarSocialButton.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 ToolbarSocialButton : ToolbarOverlayToggleButton
|
||||
{
|
||||
public ToolbarSocialButton()
|
||||
{
|
||||
Icon = FontAwesome.fa_users;
|
||||
}
|
||||
|
||||
[BackgroundDependencyLoader]
|
||||
private void load(SocialOverlay chat)
|
||||
{
|
||||
StateContainer = chat;
|
||||
}
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user