osu/osu.Game/Online/Chat/StandAloneChatDisplay.cs

212 lines
6.5 KiB
C#

// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence.
// See the LICENCE file in the repository root for full licence text.
#nullable disable
using System;
using osu.Framework.Allocation;
using osu.Framework.Bindables;
using osu.Framework.Graphics;
using osu.Framework.Graphics.Containers;
using osu.Framework.Graphics.Shapes;
using osu.Framework.Graphics.UserInterface;
using osu.Framework.Input.Events;
using osu.Game.Graphics;
using osu.Game.Graphics.UserInterface;
using osu.Game.Overlays.Chat;
using osu.Game.Resources.Localisation.Web;
using osuTK.Graphics;
using osuTK.Input;
namespace osu.Game.Online.Chat
{
/// <summary>
/// Display a chat channel in an insolated region.
/// </summary>
public partial class StandAloneChatDisplay : CompositeDrawable
{
[Cached]
public readonly Bindable<Channel> Channel = new Bindable<Channel>();
protected readonly ChatTextBox TextBox;
private ChannelManager channelManager;
private StandAloneDrawableChannel drawableChannel;
private readonly bool postingTextBox;
protected readonly Box Background;
private const float text_box_height = 30;
/// <summary>
/// Construct a new instance.
/// </summary>
/// <param name="postingTextBox">Whether a textbox for posting new messages should be displayed.</param>
public StandAloneChatDisplay(bool postingTextBox = false)
{
const float corner_radius = 10;
this.postingTextBox = postingTextBox;
CornerRadius = corner_radius;
Masking = true;
InternalChildren = new Drawable[]
{
Background = new Box
{
Colour = Color4.Black,
Alpha = 0.8f,
RelativeSizeAxes = Axes.Both
},
};
if (postingTextBox)
{
AddInternal(TextBox = new ChatTextBox
{
RelativeSizeAxes = Axes.X,
Height = text_box_height,
PlaceholderText = ChatStrings.InputPlaceholder,
CornerRadius = corner_radius,
ReleaseFocusOnCommit = false,
HoldFocus = true,
Anchor = Anchor.BottomLeft,
Origin = Anchor.BottomLeft,
});
TextBox.OnCommit += postMessage;
}
Channel.BindValueChanged(channelChanged);
}
[BackgroundDependencyLoader(true)]
private void load(ChannelManager manager)
{
channelManager ??= manager;
}
protected virtual StandAloneDrawableChannel CreateDrawableChannel(Channel channel) =>
new StandAloneDrawableChannel(channel);
private void postMessage(TextBox sender, bool newText)
{
string text = TextBox.Text.Trim();
if (string.IsNullOrWhiteSpace(text))
return;
if (text[0] == '/')
channelManager?.PostCommand(text.Substring(1), Channel.Value);
else
channelManager?.PostMessage(text, target: Channel.Value);
TextBox.Text = string.Empty;
}
protected virtual ChatLine CreateMessage(Message message) => new StandAloneMessage(message);
private void channelChanged(ValueChangedEvent<Channel> e)
{
drawableChannel?.Expire();
if (e.OldValue != null)
TextBox?.Current.UnbindFrom(e.OldValue.TextBoxMessage);
if (e.NewValue == null) return;
TextBox?.Current.BindTo(e.NewValue.TextBoxMessage);
drawableChannel = CreateDrawableChannel(e.NewValue);
drawableChannel.CreateChatLineAction = CreateMessage;
drawableChannel.Padding = new MarginPadding { Bottom = postingTextBox ? text_box_height : 0 };
AddInternal(drawableChannel);
}
public partial class ChatTextBox : HistoryTextBox
{
protected override bool OnKeyDown(KeyDownEvent e)
{
// Chat text boxes are generally used in places where they retain focus, but shouldn't block interaction with other
// elements on the same screen.
if (!HoldFocus)
{
switch (e.Key)
{
case Key.Up:
case Key.Down:
return false;
}
}
return base.OnKeyDown(e);
}
protected override void LoadComplete()
{
base.LoadComplete();
BackgroundUnfocused = new Color4(10, 10, 10, 10);
BackgroundFocused = new Color4(10, 10, 10, 255);
}
protected override void OnFocusLost(FocusLostEvent e)
{
base.OnFocusLost(e);
FocusLost?.Invoke();
}
public Action FocusLost;
}
public partial class StandAloneDrawableChannel : DrawableChannel
{
public Func<Message, ChatLine> CreateChatLineAction;
public StandAloneDrawableChannel(Channel channel)
: base(channel)
{
}
protected override ChatLine CreateChatLine(Message m) => CreateChatLineAction(m);
protected override DaySeparator CreateDaySeparator(DateTimeOffset time) => new StandAloneDaySeparator(time);
}
protected partial class StandAloneDaySeparator : DaySeparator
{
protected override float TextSize => 14;
protected override float LineHeight => 1;
protected override float Spacing => 5;
protected override float DateAlign => 125;
public StandAloneDaySeparator(DateTimeOffset date)
: base(date)
{
}
[BackgroundDependencyLoader]
private void load(OsuColour colours)
{
Height = 25;
Colour = colours.Yellow;
}
}
protected partial class StandAloneMessage : ChatLine
{
protected override float FontSize => 15;
protected override float Spacing => 5;
protected override float UsernameWidth => 75;
public StandAloneMessage(Message message)
: base(message)
{
}
}
}
}