From 034625c2eadaa1cc2c75322202a60865a529747f Mon Sep 17 00:00:00 2001 From: Alexander Fast Date: Tue, 19 Aug 2014 17:10:04 +0200 Subject: [PATCH] Added tab completion to in-game chat. Both player names and chat commands can be completed. Names of local players and bots are not candidates for completion. If a completed name is the first word ": " is appended to the end. The hotkey for toggling team/all chat has been moved to left Alt. --- OpenRA.Game/Widgets/TextFieldWidget.cs | 4 ++ .../Widgets/Logic/IngameChatLogic.cs | 55 ++++++++++++++++++- 2 files changed, 57 insertions(+), 2 deletions(-) diff --git a/OpenRA.Game/Widgets/TextFieldWidget.cs b/OpenRA.Game/Widgets/TextFieldWidget.cs index 2f955a2ef9..90ad72861d 100644 --- a/OpenRA.Game/Widgets/TextFieldWidget.cs +++ b/OpenRA.Game/Widgets/TextFieldWidget.cs @@ -30,6 +30,7 @@ namespace OpenRA.Widgets public Func OnEnterKey = () => false; public Func OnTabKey = () => false; public Func OnEscKey = () => false; + public Func OnAltKey = () => false; public Action OnLoseFocus = () => { }; public Action OnTextEdited = () => { }; public int CursorPosition { get; set; } @@ -121,6 +122,9 @@ namespace OpenRA.Widgets if (e.Key == Keycode.ESCAPE && OnEscKey()) return true; + if (e.Key == Keycode.LALT && OnAltKey()) + return true; + if (e.Key == Keycode.LEFT) { if (CursorPosition > 0) diff --git a/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs b/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs index 76159a33ca..8f9c289b6c 100644 --- a/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs +++ b/OpenRA.Mods.RA/Widgets/Logic/IngameChatLogic.cs @@ -8,6 +8,7 @@ */ #endregion +using System; using System.Collections.Generic; using System.Drawing; using System.Linq; @@ -30,6 +31,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic readonly List chatTraits; + readonly List commandNames; + readonly List playerNames; + bool teamChat; [ObjectCreator.UseCtor] @@ -43,6 +47,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic var disableTeamChat = world.LocalPlayer == null || world.LobbyInfo.IsSinglePlayer || !players.Any(p => p.IsAlliedWith(world.LocalPlayer)); teamChat = !disableTeamChat; + commandNames = chatTraits.OfType().SelectMany(x => x.Commands.Keys).Select(x => "/" + x).ToList(); + playerNames = players.Select(x => x.PlayerName).ToList(); + var chatPanel = (ContainerWidget)widget; chatOverlay = chatPanel.Get("CHAT_OVERLAY"); chatOverlayDisplay = chatOverlay.Get("CHAT_DISPLAY"); @@ -57,7 +64,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic chatMode.IsDisabled = () => disableTeamChat; chatText = chatChrome.Get("CHAT_TEXTFIELD"); - chatText.OnTabKey = () => + chatText.OnAltKey = () => { if (!disableTeamChat) teamChat ^= true; @@ -76,6 +83,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic CloseChat(); return true; }; + chatText.OnTabKey = () => AutoCompleteText(); chatText.OnEscKey = () => { CloseChat(); return true; }; @@ -166,5 +174,48 @@ namespace OpenRA.Mods.RA.Widgets.Logic Sound.PlayNotification(modRules, null, "Sounds", "ChatLine", null); } + + bool AutoCompleteText() + { + if (string.IsNullOrEmpty(chatText.Text)) + return false; + + string suggestion; + + if (chatText.Text.StartsWith("/")) + { + suggestion = commandNames.FirstOrDefault(x => x.StartsWith(chatText.Text)); + if (suggestion == null) + return false; + } + else + { + string toComplete; + bool oneWord; + if (chatText.Text.Contains(' ')) + { + toComplete = chatText.Text.Substring(chatText.Text.LastIndexOf(' ') + 1); + oneWord = false; + } + else + { + toComplete = chatText.Text; + oneWord = true; + } + + suggestion = playerNames.FirstOrDefault(x => x.StartsWith(toComplete, StringComparison.InvariantCultureIgnoreCase)); + if (suggestion == null) + return false; + + if (oneWord) + suggestion += ": "; + else + suggestion = chatText.Text.Substring(0, chatText.Text.Length - toComplete.Length) + suggestion; + } + + chatText.Text = suggestion; + chatText.CursorPosition = chatText.Text.Length; + return true; + } } -} \ No newline at end of file +}