Overhaul the IRC implementation.

* Simplified UI plumbing.
* Improves handling of errors and kicks.
* Persists chat history between session.
* Fixes leaks of the old widget tree when exiting.
* A few small UI polish improvements.
This commit is contained in:
Paul Chote
2015-10-09 23:03:32 +01:00
parent 386f252736
commit a3fe2b3d35
21 changed files with 657 additions and 453 deletions

View File

@@ -0,0 +1,163 @@
#region Copyright & License Information
/*
* Copyright 2007-2015 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
* available to you under the terms of the GNU General Public License
* as published by the Free Software Foundation. For more information,
* see COPYING.
*/
#endregion
using System;
using System.Collections;
using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Threading;
using OpenRA.Chat;
using OpenRA.Widgets;
namespace OpenRA.Mods.Common.Widgets.Logic
{
class GlobalChatLogic : IDisposable
{
readonly ScrollPanelWidget historyPanel;
readonly LabelWidget historyTemplate;
readonly ScrollPanelWidget nicknamePanel;
readonly Widget nicknameTemplate;
readonly TextFieldWidget inputBox;
[ObjectCreator.UseCtor]
public GlobalChatLogic(Widget widget)
{
historyPanel = widget.Get<ScrollPanelWidget>("HISTORY_PANEL");
historyTemplate = historyPanel.Get<LabelWidget>("HISTORY_TEMPLATE");
nicknamePanel = widget.Get<ScrollPanelWidget>("NICKNAME_PANEL");
nicknameTemplate = nicknamePanel.Get("NICKNAME_TEMPLATE");
historyPanel.Bind(Game.GlobalChat.History, MakeHistoryWidget, HistoryWidgetEquals, true);
nicknamePanel.Bind(Game.GlobalChat.Users, MakeUserWidget, UserWidgetEquals, false);
inputBox = widget.Get<TextFieldWidget>("CHAT_TEXTFIELD");
inputBox.IsDisabled = () => Game.GlobalChat.ConnectionStatus != ChatConnectionStatus.Joined;
inputBox.OnEnterKey = EnterPressed;
// Set a random default nick
if (Game.Settings.Chat.Nickname == new ChatSettings().Nickname)
Game.Settings.Chat.Nickname += Game.CosmeticRandom.Next(100, 999);
var nicknameBox = widget.Get<TextFieldWidget>("NICKNAME_TEXTFIELD");
nicknameBox.Text = Game.GlobalChat.SanitizedName(Game.Settings.Chat.Nickname);
nicknameBox.OnTextEdited = () =>
{
nicknameBox.Text = Game.GlobalChat.SanitizedName(nicknameBox.Text);
};
var connectPanel = widget.Get("GLOBALCHAT_CONNECT_PANEL");
connectPanel.IsVisible = () => Game.GlobalChat.ConnectionStatus == ChatConnectionStatus.Disconnected;
var disconnectButton = widget.Get<ButtonWidget>("DISCONNECT_BUTTON");
disconnectButton.OnClick = Game.GlobalChat.Disconnect;
var connectAutomaticallyCheckBox = connectPanel.Get<CheckboxWidget>("CONNECT_AUTOMATICALLY_CHECKBOX");
connectAutomaticallyCheckBox.IsChecked = () => Game.Settings.Chat.ConnectAutomatically;
connectAutomaticallyCheckBox.OnClick = () => { Game.Settings.Chat.ConnectAutomatically ^= true; Game.Settings.Save(); };
var connectButton = connectPanel.Get<ButtonWidget>("CONNECT_BUTTON");
connectButton.IsDisabled = () => !Game.GlobalChat.IsValidNickname(nicknameBox.Text);
connectButton.OnClick = () =>
{
Game.Settings.Chat.Nickname = nicknameBox.Text;
Game.Settings.Save();
Game.GlobalChat.Connect();
};
var mainPanel = widget.Get("GLOBALCHAT_MAIN_PANEL");
mainPanel.IsVisible = () => Game.GlobalChat.ConnectionStatus != ChatConnectionStatus.Disconnected;
mainPanel.Get<LabelWidget>("CHANNEL_TOPIC").GetText = () => Game.GlobalChat.Topic;
if (Game.Settings.Chat.ConnectAutomatically && Game.GlobalChat.IsValidNickname(Game.Settings.Chat.Nickname))
Game.GlobalChat.Connect();
}
Widget MakeHistoryWidget(object o)
{
var message = (ChatMessage)o;
var widget = (LabelWidget)historyTemplate.Clone();
var font = Game.Renderer.Fonts[widget.Font];
var color = message.Type == ChatMessageType.Notification ?
ChromeMetrics.Get<Color>("GlobalChatNotificationColor") :
ChromeMetrics.Get<Color>("GlobalChatTextColor");
var display = WidgetUtils.WrapText(message.ToString(), widget.Bounds.Width, font);
widget.Bounds.Height = font.Measure(display).Y;
widget.GetText = () => display;
widget.GetColor = () => color;
widget.Id = message.UID;
return widget;
}
bool HistoryWidgetEquals(Widget widget, object o)
{
return ((LabelWidget)widget).Id == ((ChatMessage)o).UID;
}
Widget MakeUserWidget(object o)
{
var nick = (string)o;
var client = Game.GlobalChat.Users[nick];
var item = nicknameTemplate.Clone();
item.Id = client.Name;
item.IsVisible = () => true;
var name = item.Get<LabelWidget>("NICK");
name.GetText = () => client.Name;
name.IsVisible = () => true;
// TODO: Add custom image for voice
var indicator = item.Get<ImageWidget>("INDICATOR");
indicator.IsVisible = () => client.IsOp || client.IsVoiced;
indicator.GetImageName = () => client.IsOp || client.IsVoiced ? "admin" : "";
return item;
}
bool UserWidgetEquals(Widget widget, object o)
{
var nick = (string)o;
return widget.Id == nick;
}
bool EnterPressed()
{
if (inputBox.Text.Length == 0)
return true;
if (inputBox.Text.StartsWith("/nick "))
{
var nick = inputBox.Text.Replace("/nick ", string.Empty);
Game.GlobalChat.TrySetNickname(nick);
}
else
Game.GlobalChat.SendMessage(inputBox.Text);
inputBox.Text = "";
return true;
}
bool disposed;
public void Dispose()
{
if (disposed)
return;
historyPanel.Unbind();
nicknamePanel.Unbind();
disposed = true;
}
}
}