// Copyright (c) ppy Pty Ltd . Licensed under the MIT Licence. // See the LICENCE file in the repository root for full licence text. 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.Sprites; using osu.Framework.Graphics.UserInterface; using osu.Game.Graphics; using osu.Game.Graphics.Sprites; using osu.Game.Online.Chat; using osu.Game.Resources.Localisation.Web; using osuTK; namespace osu.Game.Overlays.Chat { public partial class ChatTextBar : Container { public const float HEIGHT = 40; public readonly BindableBool ShowSearch = new BindableBool(); public event Action? OnChatMessageCommitted; public event Action? OnSearchTermsChanged; public void TextBoxTakeFocus() => chatTextBox.TakeFocus(); public void TextBoxKillFocus() => chatTextBox.KillFocus(); [Resolved] private Bindable currentChannel { get; set; } = null!; private Container chattingTextContainer = null!; private OsuSpriteText chattingText = null!; private Container searchIconContainer = null!; private ChatTextBox chatTextBox = null!; private const float chatting_text_width = 220; private const float search_icon_width = 40; private const float padding = 5; [BackgroundDependencyLoader] private void load(OverlayColourProvider colourProvider) { RelativeSizeAxes = Axes.X; Height = HEIGHT; Children = new Drawable[] { new Box { RelativeSizeAxes = Axes.Both, Colour = colourProvider.Background5, }, new GridContainer { RelativeSizeAxes = Axes.Both, ColumnDimensions = new[] { new Dimension(GridSizeMode.AutoSize), new Dimension(GridSizeMode.AutoSize), new Dimension(), }, Content = new[] { new Drawable[] { chattingTextContainer = new Container { RelativeSizeAxes = Axes.Y, Width = chatting_text_width, Masking = true, Padding = new MarginPadding { Horizontal = padding }, Child = chattingText = new TruncatingSpriteText { MaxWidth = chatting_text_width - padding * 2, Font = OsuFont.Torus, Colour = colourProvider.Background1, Anchor = Anchor.CentreRight, Origin = Anchor.CentreRight, }, }, searchIconContainer = new Container { RelativeSizeAxes = Axes.Y, Width = search_icon_width, Child = new SpriteIcon { Icon = FontAwesome.Solid.Search, Origin = Anchor.CentreRight, Anchor = Anchor.CentreRight, Size = new Vector2(OsuFont.DEFAULT_FONT_SIZE), Margin = new MarginPadding { Right = 2 }, }, }, new Container { RelativeSizeAxes = Axes.Both, Padding = new MarginPadding { Right = padding }, Child = chatTextBox = new ChatTextBox { FontSize = OsuFont.DEFAULT_FONT_SIZE, Anchor = Anchor.CentreLeft, Origin = Anchor.CentreLeft, RelativeSizeAxes = Axes.X, ShowSearch = { BindTarget = ShowSearch }, HoldFocus = true, ReleaseFocusOnCommit = false, }, }, }, }, }, }; } protected override void LoadComplete() { base.LoadComplete(); chatTextBox.Current.ValueChanged += chatTextBoxChange; chatTextBox.OnCommit += chatTextBoxCommit; ShowSearch.BindValueChanged(change => { bool showSearch = change.NewValue; chattingTextContainer.FadeTo(showSearch ? 0 : 1); searchIconContainer.FadeTo(showSearch ? 1 : 0); if (showSearch) OnSearchTermsChanged?.Invoke(chatTextBox.Current.Value); }, true); currentChannel.BindValueChanged(change => { Channel newChannel = change.NewValue; switch (newChannel?.Type) { case null: chattingText.Text = string.Empty; break; case ChannelType.PM: chattingText.Text = ChatStrings.TalkingWith(newChannel.Name); break; default: chattingText.Text = ChatStrings.TalkingIn(newChannel.Name); break; } if (change.OldValue != null) chatTextBox.Current.UnbindFrom(change.OldValue.TextBoxMessage); if (newChannel != null) { // change length limit first before binding to avoid accidentally truncating pending message from new channel. chatTextBox.LengthLimit = newChannel.MessageLengthLimit; chatTextBox.Current.BindTo(newChannel.TextBoxMessage); } }, true); } private void chatTextBoxChange(ValueChangedEvent change) { if (ShowSearch.Value) OnSearchTermsChanged?.Invoke(change.NewValue); } private void chatTextBoxCommit(TextBox sender, bool newText) { if (ShowSearch.Value) return; OnChatMessageCommitted?.Invoke(sender.Text); sender.Text = string.Empty; } } }