Merge pull request #6281 from mizipzor/tab-completion
Added tab completion to in-game and lobby chat.
This commit is contained in:
1
AUTHORS
1
AUTHORS
@@ -19,6 +19,7 @@ Previous developers included:
|
|||||||
Also thanks to:
|
Also thanks to:
|
||||||
* Adam Valy (Tschokky)
|
* Adam Valy (Tschokky)
|
||||||
* Akseli Virtanen (RAGEQUIT)
|
* Akseli Virtanen (RAGEQUIT)
|
||||||
|
* Alexander Fast (mizipzor)
|
||||||
* Allen262
|
* Allen262
|
||||||
* Andrew Aldridge (i80and)
|
* Andrew Aldridge (i80and)
|
||||||
* Andrew Perkins
|
* Andrew Perkins
|
||||||
|
|||||||
@@ -30,6 +30,7 @@ namespace OpenRA.Widgets
|
|||||||
public Func<bool> OnEnterKey = () => false;
|
public Func<bool> OnEnterKey = () => false;
|
||||||
public Func<bool> OnTabKey = () => false;
|
public Func<bool> OnTabKey = () => false;
|
||||||
public Func<bool> OnEscKey = () => false;
|
public Func<bool> OnEscKey = () => false;
|
||||||
|
public Func<bool> OnAltKey = () => false;
|
||||||
public Action OnLoseFocus = () => { };
|
public Action OnLoseFocus = () => { };
|
||||||
public Action OnTextEdited = () => { };
|
public Action OnTextEdited = () => { };
|
||||||
public int CursorPosition { get; set; }
|
public int CursorPosition { get; set; }
|
||||||
@@ -121,6 +122,9 @@ namespace OpenRA.Widgets
|
|||||||
if (e.Key == Keycode.ESCAPE && OnEscKey())
|
if (e.Key == Keycode.ESCAPE && OnEscKey())
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
if (e.Key == Keycode.LALT && OnAltKey())
|
||||||
|
return true;
|
||||||
|
|
||||||
if (e.Key == Keycode.LEFT)
|
if (e.Key == Keycode.LEFT)
|
||||||
{
|
{
|
||||||
if (CursorPosition > 0)
|
if (CursorPosition > 0)
|
||||||
|
|||||||
@@ -8,6 +8,7 @@
|
|||||||
*/
|
*/
|
||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Drawing;
|
using System.Drawing;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
@@ -30,6 +31,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
readonly List<INotifyChat> chatTraits;
|
readonly List<INotifyChat> chatTraits;
|
||||||
|
|
||||||
|
readonly List<string> commandNames;
|
||||||
|
readonly List<string> playerNames;
|
||||||
|
|
||||||
bool teamChat;
|
bool teamChat;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[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));
|
var disableTeamChat = world.LocalPlayer == null || world.LobbyInfo.IsSinglePlayer || !players.Any(p => p.IsAlliedWith(world.LocalPlayer));
|
||||||
teamChat = !disableTeamChat;
|
teamChat = !disableTeamChat;
|
||||||
|
|
||||||
|
commandNames = chatTraits.OfType<ChatCommands>().SelectMany(x => x.Commands.Keys).Select(x => "/" + x).ToList();
|
||||||
|
playerNames = orderManager.LobbyInfo.Clients.Select(c => c.Name).ToList();
|
||||||
|
|
||||||
var chatPanel = (ContainerWidget)widget;
|
var chatPanel = (ContainerWidget)widget;
|
||||||
chatOverlay = chatPanel.Get<ContainerWidget>("CHAT_OVERLAY");
|
chatOverlay = chatPanel.Get<ContainerWidget>("CHAT_OVERLAY");
|
||||||
chatOverlayDisplay = chatOverlay.Get<ChatDisplayWidget>("CHAT_DISPLAY");
|
chatOverlayDisplay = chatOverlay.Get<ChatDisplayWidget>("CHAT_DISPLAY");
|
||||||
@@ -57,7 +64,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
chatMode.IsDisabled = () => disableTeamChat;
|
chatMode.IsDisabled = () => disableTeamChat;
|
||||||
|
|
||||||
chatText = chatChrome.Get<TextFieldWidget>("CHAT_TEXTFIELD");
|
chatText = chatChrome.Get<TextFieldWidget>("CHAT_TEXTFIELD");
|
||||||
chatText.OnTabKey = () =>
|
chatText.OnAltKey = () =>
|
||||||
{
|
{
|
||||||
if (!disableTeamChat)
|
if (!disableTeamChat)
|
||||||
teamChat ^= true;
|
teamChat ^= true;
|
||||||
@@ -71,18 +78,23 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
orderManager.IssueOrder(Order.Chat(team, chatText.Text.Trim()));
|
orderManager.IssueOrder(Order.Chat(team, chatText.Text.Trim()));
|
||||||
else
|
else
|
||||||
if (chatTraits != null)
|
if (chatTraits != null)
|
||||||
chatTraits.All(x => x.OnChat(orderManager.LocalClient.Name, chatText.Text.Trim()));
|
{
|
||||||
|
var text = chatText.Text.Trim();
|
||||||
|
foreach (var trait in chatTraits)
|
||||||
|
trait.OnChat(orderManager.LocalClient.Name, text);
|
||||||
|
}
|
||||||
|
|
||||||
CloseChat();
|
CloseChat();
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
chatText.OnTabKey = AutoCompleteText;
|
||||||
|
|
||||||
chatText.OnEscKey = () => { CloseChat(); return true; };
|
chatText.OnEscKey = () => { CloseChat(); return true; };
|
||||||
|
|
||||||
var chatClose = chatChrome.Get<ButtonWidget>("CHAT_CLOSE");
|
var chatClose = chatChrome.Get<ButtonWidget>("CHAT_CLOSE");
|
||||||
chatClose.OnClick += () => CloseChat();
|
chatClose.OnClick += CloseChat;
|
||||||
|
|
||||||
chatPanel.OnKeyPress = (e) =>
|
chatPanel.OnKeyPress = e =>
|
||||||
{
|
{
|
||||||
if (e.Event == KeyInputEvent.Up)
|
if (e.Event == KeyInputEvent.Up)
|
||||||
return false;
|
return false;
|
||||||
@@ -166,5 +178,43 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
Sound.PlayNotification(modRules, null, "Sounds", "ChatLine", null);
|
Sound.PlayNotification(modRules, null, "Sounds", "ChatLine", null);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AutoCompleteText()
|
||||||
|
{
|
||||||
|
if (string.IsNullOrEmpty(chatText.Text))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (chatText.Text.LastOrDefault() == ' ')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var suggestion = "";
|
||||||
|
|
||||||
|
if (chatText.Text.StartsWith("/"))
|
||||||
|
{
|
||||||
|
suggestion = commandNames.FirstOrDefault(x => x.StartsWith(chatText.Text));
|
||||||
|
if (suggestion == null)
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
var oneWord = !chatText.Text.Contains(' ');
|
||||||
|
var toComplete = oneWord
|
||||||
|
? chatText.Text
|
||||||
|
: chatText.Text.Substring(chatText.Text.LastIndexOf(' ') + 1);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -35,18 +35,23 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
enum PanelType { Players, Options, Kick, ForceStart }
|
enum PanelType { Players, Options, Kick, ForceStart }
|
||||||
PanelType panel = PanelType.Players;
|
PanelType panel = PanelType.Players;
|
||||||
|
|
||||||
Widget lobby;
|
readonly Widget lobby;
|
||||||
|
readonly Widget editablePlayerTemplate;
|
||||||
|
readonly Widget nonEditablePlayerTemplate;
|
||||||
|
readonly Widget emptySlotTemplate;
|
||||||
|
readonly Widget editableSpectatorTemplate;
|
||||||
|
readonly Widget nonEditableSpectatorTemplate;
|
||||||
|
readonly Widget newSpectatorTemplate;
|
||||||
|
|
||||||
Widget editablePlayerTemplate, nonEditablePlayerTemplate, emptySlotTemplate,
|
readonly ScrollPanelWidget chatPanel;
|
||||||
editableSpectatorTemplate, nonEditableSpectatorTemplate, newSpectatorTemplate;
|
readonly Widget chatTemplate;
|
||||||
|
|
||||||
ScrollPanelWidget chatPanel;
|
readonly ScrollPanelWidget players;
|
||||||
Widget chatTemplate;
|
readonly Dictionary<string, string> countryNames;
|
||||||
|
|
||||||
ScrollPanelWidget players;
|
readonly ColorPreviewManagerWidget colorPreview;
|
||||||
Dictionary<string, string> countryNames;
|
|
||||||
|
|
||||||
ColorPreviewManagerWidget colorPreview;
|
List<string> playerNames;
|
||||||
|
|
||||||
// Listen for connection failures
|
// Listen for connection failures
|
||||||
void ConnectionStateChanged(OrderManager om)
|
void ConnectionStateChanged(OrderManager om)
|
||||||
@@ -498,13 +503,13 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
chatTextField.Text = "";
|
chatTextField.Text = "";
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
chatTextField.OnAltKey = () =>
|
||||||
chatTextField.OnTabKey = () =>
|
|
||||||
{
|
{
|
||||||
teamChat ^= true;
|
teamChat ^= true;
|
||||||
chatLabel.Text = teamChat ? "Team:" : "Chat:";
|
chatLabel.Text = teamChat ? "Team:" : "Chat:";
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
|
chatTextField.OnTabKey = AutoCompleteText;
|
||||||
|
|
||||||
chatPanel = lobby.Get<ScrollPanelWidget>("CHAT_DISPLAY");
|
chatPanel = lobby.Get<ScrollPanelWidget>("CHAT_DISPLAY");
|
||||||
chatTemplate = chatPanel.Get("CHAT_TEMPLATE");
|
chatTemplate = chatPanel.Get("CHAT_TEMPLATE");
|
||||||
@@ -764,6 +769,8 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
|
|
||||||
while (players.Children.Count > idx)
|
while (players.Children.Count > idx)
|
||||||
players.RemoveChild(players.Children[idx]);
|
players.RemoveChild(players.Children[idx]);
|
||||||
|
|
||||||
|
playerNames = orderManager.LobbyInfo.Clients.Select(c => c.Name).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
void OnGameStart()
|
void OnGameStart()
|
||||||
@@ -772,6 +779,35 @@ namespace OpenRA.Mods.RA.Widgets.Logic
|
|||||||
onStart();
|
onStart();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool AutoCompleteText()
|
||||||
|
{
|
||||||
|
var chatText = lobby.Get<TextFieldWidget>("CHAT_TEXTFIELD");
|
||||||
|
if (chatText == null || string.IsNullOrEmpty(chatText.Text))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (chatText.Text.LastOrDefault() == ' ')
|
||||||
|
return false;
|
||||||
|
|
||||||
|
var suggestion = "";
|
||||||
|
var oneWord = !chatText.Text.Contains(' ');
|
||||||
|
var toComplete = oneWord
|
||||||
|
? chatText.Text
|
||||||
|
: chatText.Text.Substring(chatText.Text.LastIndexOf(' ') + 1);
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
class DropDownOption
|
class DropDownOption
|
||||||
{
|
{
|
||||||
public string Title;
|
public string Title;
|
||||||
|
|||||||
Reference in New Issue
Block a user