Rework chat line templates and logic
- Extract chat line templates and logic so they can be reused across widgets - Make text notification styling entirely template driven (by removing chat color configuration and making color optional for `TextNotification`) - Add a new TextNotificationsDisplay widget (based on and replacing ChatDisplayWidget) - Add timestamp support to text notifications
This commit is contained in:
committed by
Matthias Mailänder
parent
8416dc3f2d
commit
9e92340ea7
@@ -21,16 +21,18 @@ namespace OpenRA
|
|||||||
public readonly TextNotificationPool Pool;
|
public readonly TextNotificationPool Pool;
|
||||||
public readonly string Prefix;
|
public readonly string Prefix;
|
||||||
public readonly string Text;
|
public readonly string Text;
|
||||||
public readonly Color PrefixColor;
|
public readonly Color? PrefixColor;
|
||||||
public readonly Color TextColor;
|
public readonly Color? TextColor;
|
||||||
|
public readonly DateTime Time;
|
||||||
|
|
||||||
public TextNotification(TextNotificationPool pool, string prefix, string text, Color prefixColor, Color textColor)
|
public TextNotification(TextNotificationPool pool, string prefix, string text, Color? prefixColor, Color? textColor)
|
||||||
{
|
{
|
||||||
Pool = pool;
|
Pool = pool;
|
||||||
Prefix = prefix;
|
Prefix = prefix;
|
||||||
Text = text;
|
Text = text;
|
||||||
PrefixColor = prefixColor;
|
PrefixColor = prefixColor;
|
||||||
TextColor = textColor;
|
TextColor = textColor;
|
||||||
|
Time = DateTime.Now;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool CanIncrementOnDuplicate()
|
public bool CanIncrementOnDuplicate()
|
||||||
@@ -38,19 +40,17 @@ namespace OpenRA
|
|||||||
return Pool == TextNotificationPool.Feedback || Pool == TextNotificationPool.System;
|
return Pool == TextNotificationPool.Feedback || Pool == TextNotificationPool.System;
|
||||||
}
|
}
|
||||||
|
|
||||||
public bool Equals(TextNotification other)
|
public static bool operator ==(TextNotification me, TextNotification other) { return me.GetHashCode() == other.GetHashCode(); }
|
||||||
{
|
|
||||||
return other != null && other.GetHashCode() == GetHashCode();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override bool Equals(object obj)
|
public static bool operator !=(TextNotification me, TextNotification other) { return !(me == other); }
|
||||||
{
|
|
||||||
return obj is TextNotification && Equals((TextNotification)obj);
|
public bool Equals(TextNotification other) { return other == this; }
|
||||||
}
|
|
||||||
|
public override bool Equals(object obj) { return obj is TextNotification notification && Equals(notification); }
|
||||||
|
|
||||||
public override int GetHashCode()
|
public override int GetHashCode()
|
||||||
{
|
{
|
||||||
return string.Format("{0}{1}{2}", Prefix, Text, Pool).GetHashCode();
|
return HashCode.Combine(Prefix, Text, (int)Pool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -16,33 +16,29 @@ namespace OpenRA
|
|||||||
{
|
{
|
||||||
public static class TextNotificationsManager
|
public static class TextNotificationsManager
|
||||||
{
|
{
|
||||||
static Color systemMessageColor = Color.White;
|
static readonly string SystemMessageLabel;
|
||||||
static Color chatMessageColor = Color.White;
|
|
||||||
static string systemMessageLabel;
|
|
||||||
|
|
||||||
public static long ChatDisabledUntil { get; internal set; }
|
public static long ChatDisabledUntil { get; internal set; }
|
||||||
|
|
||||||
static TextNotificationsManager()
|
static TextNotificationsManager()
|
||||||
{
|
{
|
||||||
ChromeMetrics.TryGet("ChatMessageColor", out chatMessageColor);
|
if (!ChromeMetrics.TryGet("SystemMessageLabel", out SystemMessageLabel))
|
||||||
ChromeMetrics.TryGet("SystemMessageColor", out systemMessageColor);
|
SystemMessageLabel = "Battlefield Control";
|
||||||
if (!ChromeMetrics.TryGet("SystemMessageLabel", out systemMessageLabel))
|
|
||||||
systemMessageLabel = "Battlefield Control";
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddFeedbackLine(string text)
|
public static void AddFeedbackLine(string text)
|
||||||
{
|
{
|
||||||
AddTextNotification(TextNotificationPool.Feedback, systemMessageLabel, text, systemMessageColor, systemMessageColor);
|
AddTextNotification(TextNotificationPool.Feedback, SystemMessageLabel, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddSystemLine(string text)
|
public static void AddSystemLine(string text)
|
||||||
{
|
{
|
||||||
AddSystemLine(systemMessageLabel, text);
|
AddSystemLine(SystemMessageLabel, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddSystemLine(string prefix, string text)
|
public static void AddSystemLine(string prefix, string text)
|
||||||
{
|
{
|
||||||
AddTextNotification(TextNotificationPool.System, prefix, text, systemMessageColor, systemMessageColor);
|
AddTextNotification(TextNotificationPool.System, prefix, text);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void AddChatLine(string prefix, string text, Color? prefixColor = null, Color? textColor = null)
|
public static void AddChatLine(string prefix, string text, Color? prefixColor = null, Color? textColor = null)
|
||||||
@@ -58,7 +54,7 @@ namespace OpenRA
|
|||||||
static void AddTextNotification(TextNotificationPool pool, string prefix, string text, Color? prefixColor = null, Color? textColor = null)
|
static void AddTextNotification(TextNotificationPool pool, string prefix, string text, Color? prefixColor = null, Color? textColor = null)
|
||||||
{
|
{
|
||||||
if (IsPoolEnabled(pool))
|
if (IsPoolEnabled(pool))
|
||||||
Game.OrderManager.AddTextNotification(new TextNotification(pool, prefix, text, prefixColor ?? chatMessageColor, textColor ?? chatMessageColor));
|
Game.OrderManager.AddTextNotification(new TextNotification(pool, prefix, text, prefixColor, textColor));
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool IsPoolEnabled(TextNotificationPool pool)
|
static bool IsPoolEnabled(TextNotificationPool pool)
|
||||||
|
|||||||
@@ -1,143 +0,0 @@
|
|||||||
#region Copyright & License Information
|
|
||||||
/*
|
|
||||||
* Copyright 2007-2021 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, either version 3 of
|
|
||||||
* the License, or (at your option) any later version. For more
|
|
||||||
* information, see COPYING.
|
|
||||||
*/
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Linq;
|
|
||||||
using OpenRA.Primitives;
|
|
||||||
using OpenRA.Widgets;
|
|
||||||
|
|
||||||
namespace OpenRA.Mods.Common.Widgets
|
|
||||||
{
|
|
||||||
public class ChatDisplayWidget : Widget
|
|
||||||
{
|
|
||||||
public readonly int RemoveTime = 0;
|
|
||||||
public readonly bool UseContrast = false;
|
|
||||||
public readonly bool UseShadow = false;
|
|
||||||
public readonly Color BackgroundColorDark = ChromeMetrics.Get<Color>("TextContrastColorDark");
|
|
||||||
public readonly Color BackgroundColorLight = ChromeMetrics.Get<Color>("TextContrastColorLight");
|
|
||||||
public string Notification = "";
|
|
||||||
public readonly int TextLineBoxHeight = 16;
|
|
||||||
public readonly int Space = 4;
|
|
||||||
|
|
||||||
const int LogLength = 9;
|
|
||||||
List<TextNotification> recentLines = new List<TextNotification>();
|
|
||||||
List<int> lineExpirations = new List<int>();
|
|
||||||
|
|
||||||
public override Rectangle EventBounds => Rectangle.Empty;
|
|
||||||
|
|
||||||
public override void Draw()
|
|
||||||
{
|
|
||||||
var pos = RenderOrigin;
|
|
||||||
var chatLogArea = new Rectangle(pos.X, pos.Y, Bounds.Width, Bounds.Height);
|
|
||||||
var chatPos = new int2(chatLogArea.X + 5, chatLogArea.Bottom - 8);
|
|
||||||
|
|
||||||
var font = Game.Renderer.Fonts["Regular"];
|
|
||||||
Game.Renderer.EnableScissor(chatLogArea);
|
|
||||||
|
|
||||||
foreach (var line in recentLines.AsEnumerable().Reverse())
|
|
||||||
{
|
|
||||||
var lineHeight = TextLineBoxHeight;
|
|
||||||
var inset = 0;
|
|
||||||
string name = null;
|
|
||||||
|
|
||||||
if (!string.IsNullOrEmpty(line.Prefix))
|
|
||||||
{
|
|
||||||
name = line.Prefix + ":";
|
|
||||||
inset = font.Measure(name).X + 5;
|
|
||||||
}
|
|
||||||
|
|
||||||
var text = WidgetUtils.WrapText(line.Text, chatLogArea.Width - inset - 6, font);
|
|
||||||
var textSize = font.Measure(text).Y;
|
|
||||||
var offset = font.TopOffset;
|
|
||||||
|
|
||||||
if (chatPos.Y - font.TopOffset < pos.Y)
|
|
||||||
break;
|
|
||||||
|
|
||||||
var textLineHeight = lineHeight;
|
|
||||||
|
|
||||||
var dh = textSize - textLineHeight;
|
|
||||||
if (dh > 0)
|
|
||||||
textLineHeight += dh;
|
|
||||||
|
|
||||||
var textOffset = textLineHeight - (textLineHeight - textSize - offset) / 2;
|
|
||||||
var textPos = new int2(chatPos.X + inset, chatPos.Y - textOffset);
|
|
||||||
|
|
||||||
if (name != null)
|
|
||||||
{
|
|
||||||
var nameSize = font.Measure(name).Y;
|
|
||||||
var namePos = chatPos.WithY(chatPos.Y - (textLineHeight - (lineHeight - nameSize - offset) / 2));
|
|
||||||
|
|
||||||
if (UseContrast)
|
|
||||||
font.DrawTextWithContrast(name, namePos,
|
|
||||||
line.PrefixColor, BackgroundColorDark, BackgroundColorLight, 1);
|
|
||||||
else if (UseShadow)
|
|
||||||
font.DrawTextWithShadow(name, namePos,
|
|
||||||
line.PrefixColor, BackgroundColorDark, BackgroundColorLight, 1);
|
|
||||||
else
|
|
||||||
font.DrawText(name, namePos, line.PrefixColor);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (UseContrast)
|
|
||||||
font.DrawTextWithContrast(text, textPos,
|
|
||||||
line.TextColor, Color.Black, 1);
|
|
||||||
else if (UseShadow)
|
|
||||||
font.DrawTextWithShadow(text, textPos,
|
|
||||||
line.TextColor, Color.Black, 1);
|
|
||||||
else
|
|
||||||
font.DrawText(text, textPos, Color.White);
|
|
||||||
|
|
||||||
chatPos = chatPos.WithY(chatPos.Y - Space - textLineHeight);
|
|
||||||
}
|
|
||||||
|
|
||||||
Game.Renderer.DisableScissor();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void AddLine(TextNotification chatLine)
|
|
||||||
{
|
|
||||||
recentLines.Add(chatLine);
|
|
||||||
lineExpirations.Add(Game.LocalTick + RemoveTime);
|
|
||||||
|
|
||||||
if (Notification != null)
|
|
||||||
Game.Sound.Play(SoundType.UI, Notification);
|
|
||||||
|
|
||||||
while (recentLines.Count > LogLength)
|
|
||||||
RemoveLine();
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveMostRecentLine()
|
|
||||||
{
|
|
||||||
if (recentLines.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
recentLines.RemoveAt(recentLines.Count - 1);
|
|
||||||
lineExpirations.RemoveAt(lineExpirations.Count - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RemoveLine()
|
|
||||||
{
|
|
||||||
if (recentLines.Count == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
recentLines.RemoveAt(0);
|
|
||||||
lineExpirations.RemoveAt(0);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Tick()
|
|
||||||
{
|
|
||||||
if (RemoveTime == 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
// This takes advantage of the fact that recentLines is ordered by expiration, from sooner to later
|
|
||||||
while (recentLines.Count > 0 && Game.LocalTick >= lineExpirations[0])
|
|
||||||
RemoveLine();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -25,15 +25,16 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
readonly OrderManager orderManager;
|
readonly OrderManager orderManager;
|
||||||
readonly Ruleset modRules;
|
readonly Ruleset modRules;
|
||||||
|
readonly World world;
|
||||||
|
|
||||||
readonly ContainerWidget chatOverlay;
|
readonly ContainerWidget chatOverlay;
|
||||||
readonly ChatDisplayWidget chatOverlayDisplay;
|
readonly TextNotificationsDisplayWidget chatOverlayDisplay;
|
||||||
|
|
||||||
readonly ContainerWidget chatChrome;
|
readonly ContainerWidget chatChrome;
|
||||||
readonly ScrollPanelWidget chatScrollPanel;
|
readonly ScrollPanelWidget chatScrollPanel;
|
||||||
readonly ContainerWidget chatTemplate;
|
|
||||||
readonly TextFieldWidget chatText;
|
readonly TextFieldWidget chatText;
|
||||||
readonly CachedTransform<int, string> chatDisabledLabel;
|
readonly CachedTransform<int, string> chatDisabledLabel;
|
||||||
|
readonly Dictionary<TextNotificationPool, Widget> templates = new Dictionary<TextNotificationPool, Widget>();
|
||||||
|
|
||||||
readonly TabCompletionLogic tabCompletion = new TabCompletionLogic();
|
readonly TabCompletionLogic tabCompletion = new TabCompletionLogic();
|
||||||
|
|
||||||
@@ -43,11 +44,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
int repetitions;
|
int repetitions;
|
||||||
bool chatEnabled;
|
bool chatEnabled;
|
||||||
|
|
||||||
|
readonly bool isMenuChat;
|
||||||
|
|
||||||
[ObjectCreator.UseCtor]
|
[ObjectCreator.UseCtor]
|
||||||
public IngameChatLogic(Widget widget, OrderManager orderManager, World world, ModData modData, bool isMenuChat, Dictionary<string, MiniYaml> logicArgs)
|
public IngameChatLogic(Widget widget, OrderManager orderManager, World world, ModData modData, bool isMenuChat, Dictionary<string, MiniYaml> logicArgs)
|
||||||
{
|
{
|
||||||
this.orderManager = orderManager;
|
this.orderManager = orderManager;
|
||||||
modRules = modData.DefaultRules;
|
modRules = modData.DefaultRules;
|
||||||
|
this.isMenuChat = isMenuChat;
|
||||||
|
this.world = world;
|
||||||
|
|
||||||
var chatTraits = world.WorldActor.TraitsImplementing<INotifyChat>().ToArray();
|
var chatTraits = world.WorldActor.TraitsImplementing<INotifyChat>().ToArray();
|
||||||
var players = world.Players.Where(p => p != world.LocalPlayer && !p.NonCombatant && !p.IsBot);
|
var players = world.Players.Where(p => p != world.LocalPlayer && !p.NonCombatant && !p.IsBot);
|
||||||
@@ -59,11 +64,20 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
tabCompletion.Commands = chatTraits.OfType<ChatCommands>().SelectMany(x => x.Commands.Keys).ToList();
|
tabCompletion.Commands = chatTraits.OfType<ChatCommands>().SelectMany(x => x.Commands.Keys).ToList();
|
||||||
tabCompletion.Names = orderManager.LobbyInfo.Clients.Select(c => c.Name).Distinct().ToList();
|
tabCompletion.Names = orderManager.LobbyInfo.Clients.Select(c => c.Name).Distinct().ToList();
|
||||||
|
|
||||||
|
if (logicArgs.TryGetValue("Templates", out var templateIds))
|
||||||
|
{
|
||||||
|
foreach (var item in templateIds.Nodes)
|
||||||
|
{
|
||||||
|
var key = FieldLoader.GetValue<TextNotificationPool>("key", item.Key);
|
||||||
|
templates[key] = Ui.LoadWidget(item.Value.Value, null, new WidgetArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var chatPanel = (ContainerWidget)widget;
|
var chatPanel = (ContainerWidget)widget;
|
||||||
chatOverlay = chatPanel.GetOrNull<ContainerWidget>("CHAT_OVERLAY");
|
chatOverlay = chatPanel.GetOrNull<ContainerWidget>("CHAT_OVERLAY");
|
||||||
if (chatOverlay != null)
|
if (chatOverlay != null)
|
||||||
{
|
{
|
||||||
chatOverlayDisplay = chatOverlay.Get<ChatDisplayWidget>("CHAT_DISPLAY");
|
chatOverlayDisplay = chatOverlay.Get<TextNotificationsDisplayWidget>("CHAT_DISPLAY");
|
||||||
chatOverlay.Visible = false;
|
chatOverlay.Visible = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -194,14 +208,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
}
|
}
|
||||||
|
|
||||||
chatScrollPanel = chatChrome.Get<ScrollPanelWidget>("CHAT_SCROLLPANEL");
|
chatScrollPanel = chatChrome.Get<ScrollPanelWidget>("CHAT_SCROLLPANEL");
|
||||||
chatTemplate = chatScrollPanel.Get<ContainerWidget>("CHAT_TEMPLATE");
|
|
||||||
chatScrollPanel.RemoveChildren();
|
chatScrollPanel.RemoveChildren();
|
||||||
chatScrollPanel.ScrollToBottom();
|
chatScrollPanel.ScrollToBottom();
|
||||||
|
|
||||||
foreach (var chatLine in orderManager.NotificationsCache)
|
foreach (var chatLine in orderManager.NotificationsCache)
|
||||||
AddChatLine(chatLine, true);
|
AddChatLine(chatLine, true);
|
||||||
|
|
||||||
orderManager.AddTextNotification += AddChatLineWrapper;
|
orderManager.AddTextNotification += AddNotificationWrapper;
|
||||||
|
|
||||||
chatText.IsDisabled = () => !chatEnabled || (world.IsReplay && !Game.Settings.Debug.EnableDebugCommandsInReplays);
|
chatText.IsDisabled = () => !chatEnabled || (world.IsReplay && !Game.Settings.Debug.EnableDebugCommandsInReplays);
|
||||||
|
|
||||||
@@ -248,7 +261,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
Ui.ResetTooltips();
|
Ui.ResetTooltips();
|
||||||
}
|
}
|
||||||
|
|
||||||
public void AddChatLineWrapper(TextNotification chatLine)
|
public void AddNotificationWrapper(TextNotification chatLine)
|
||||||
{
|
{
|
||||||
var chatLineToDisplay = chatLine;
|
var chatLineToDisplay = chatLine;
|
||||||
|
|
||||||
@@ -263,53 +276,27 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
chatLine.TextColor);
|
chatLine.TextColor);
|
||||||
|
|
||||||
chatScrollPanel.RemoveChild(chatScrollPanel.Children[chatScrollPanel.Children.Count - 1]);
|
chatScrollPanel.RemoveChild(chatScrollPanel.Children[chatScrollPanel.Children.Count - 1]);
|
||||||
chatOverlayDisplay?.RemoveMostRecentLine();
|
chatOverlayDisplay?.RemoveMostRecentNotification();
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
repetitions = 0;
|
repetitions = 0;
|
||||||
|
|
||||||
lastLine = chatLine;
|
lastLine = chatLine;
|
||||||
|
|
||||||
chatOverlayDisplay?.AddLine(chatLineToDisplay);
|
chatOverlayDisplay?.AddNotification(chatLineToDisplay);
|
||||||
|
|
||||||
// HACK: Force disable the chat notification sound for the in-menu chat dialog
|
// HACK: Force disable the chat notification sound for the in-menu chat dialog
|
||||||
// This works around our inability to disable the sounds for the in-game dialog when it is hidden
|
// This works around our inability to disable the sounds for the in-game dialog when it is hidden
|
||||||
AddChatLine(chatLineToDisplay, chatOverlay == null);
|
AddChatLine(chatLineToDisplay, chatOverlay == null);
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddChatLine(TextNotification chatLine, bool suppressSound)
|
void AddChatLine(TextNotification notification, bool suppressSound)
|
||||||
{
|
{
|
||||||
var template = chatTemplate.Clone();
|
var chatLine = templates[notification.Pool].Clone();
|
||||||
var nameLabel = template.Get<LabelWidget>("NAME");
|
WidgetUtils.SetupTextNotification(chatLine, notification, chatScrollPanel.Bounds.Width - chatScrollPanel.ScrollbarWidth, isMenuChat && !world.IsReplay);
|
||||||
var textLabel = template.Get<LabelWidget>("TEXT");
|
|
||||||
|
|
||||||
var name = "";
|
|
||||||
if (!string.IsNullOrEmpty(chatLine.Prefix))
|
|
||||||
name = chatLine.Prefix + ":";
|
|
||||||
|
|
||||||
var font = Game.Renderer.Fonts[nameLabel.Font];
|
|
||||||
var nameSize = font.Measure(chatLine.Prefix);
|
|
||||||
|
|
||||||
nameLabel.GetColor = () => chatLine.PrefixColor;
|
|
||||||
nameLabel.GetText = () => name;
|
|
||||||
nameLabel.Bounds.Width = nameSize.X;
|
|
||||||
|
|
||||||
textLabel.GetColor = () => chatLine.TextColor;
|
|
||||||
textLabel.Bounds.X += nameSize.X;
|
|
||||||
textLabel.Bounds.Width -= nameSize.X;
|
|
||||||
|
|
||||||
// Hack around our hacky wordwrap behavior: need to resize the widget to fit the text
|
|
||||||
var text = WidgetUtils.WrapText(chatLine.Text, textLabel.Bounds.Width, font);
|
|
||||||
textLabel.GetText = () => text;
|
|
||||||
var dh = font.Measure(text).Y - textLabel.Bounds.Height;
|
|
||||||
if (dh > 0)
|
|
||||||
{
|
|
||||||
textLabel.Bounds.Height += dh;
|
|
||||||
template.Bounds.Height += dh;
|
|
||||||
}
|
|
||||||
|
|
||||||
var scrolledToBottom = chatScrollPanel.ScrolledToBottom;
|
var scrolledToBottom = chatScrollPanel.ScrolledToBottom;
|
||||||
chatScrollPanel.AddChild(template);
|
chatScrollPanel.AddChild(chatLine);
|
||||||
if (scrolledToBottom)
|
if (scrolledToBottom)
|
||||||
chatScrollPanel.ScrollToBottom(smooth: true);
|
chatScrollPanel.ScrollToBottom(smooth: true);
|
||||||
|
|
||||||
@@ -343,7 +330,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
{
|
{
|
||||||
if (!disposed)
|
if (!disposed)
|
||||||
{
|
{
|
||||||
orderManager.AddTextNotification -= AddChatLineWrapper;
|
orderManager.AddTextNotification -= AddNotificationWrapper;
|
||||||
disposed = true;
|
disposed = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,7 +45,7 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
readonly Widget newSpectatorTemplate;
|
readonly Widget newSpectatorTemplate;
|
||||||
|
|
||||||
readonly ScrollPanelWidget lobbyChatPanel;
|
readonly ScrollPanelWidget lobbyChatPanel;
|
||||||
readonly Widget chatTemplate;
|
readonly Dictionary<TextNotificationPool, Widget> chatTemplates = new Dictionary<TextNotificationPool, Widget>();
|
||||||
readonly TextFieldWidget chatTextField;
|
readonly TextFieldWidget chatTextField;
|
||||||
readonly CachedTransform<int, string> chatDisabledLabel;
|
readonly CachedTransform<int, string> chatDisabledLabel;
|
||||||
|
|
||||||
@@ -398,6 +398,15 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
if (skirmishMode)
|
if (skirmishMode)
|
||||||
disconnectButton.Text = "Back";
|
disconnectButton.Text = "Back";
|
||||||
|
|
||||||
|
if (logicArgs.TryGetValue("ChatTemplates", out var templateIds))
|
||||||
|
{
|
||||||
|
foreach (var item in templateIds.Nodes)
|
||||||
|
{
|
||||||
|
var key = FieldLoader.GetValue<TextNotificationPool>("key", item.Key);
|
||||||
|
chatTemplates[key] = Ui.LoadWidget(item.Value.Value, null, new WidgetArgs());
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
var chatMode = lobby.Get<ButtonWidget>("CHAT_MODE");
|
var chatMode = lobby.Get<ButtonWidget>("CHAT_MODE");
|
||||||
chatMode.GetText = () => teamChat ? "Team" : "All";
|
chatMode.GetText = () => teamChat ? "Team" : "All";
|
||||||
chatMode.OnClick = () => teamChat ^= true;
|
chatMode.OnClick = () => teamChat ^= true;
|
||||||
@@ -442,7 +451,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
chatDisabledLabel = new CachedTransform<int, string>(x => x > 0 ? $"Chat available in {x} seconds..." : "Chat Disabled");
|
chatDisabledLabel = new CachedTransform<int, string>(x => x > 0 ? $"Chat available in {x} seconds..." : "Chat Disabled");
|
||||||
|
|
||||||
lobbyChatPanel = lobby.Get<ScrollPanelWidget>("CHAT_DISPLAY");
|
lobbyChatPanel = lobby.Get<ScrollPanelWidget>("CHAT_DISPLAY");
|
||||||
chatTemplate = lobbyChatPanel.Get("CHAT_TEMPLATE");
|
|
||||||
lobbyChatPanel.RemoveChildren();
|
lobbyChatPanel.RemoveChildren();
|
||||||
|
|
||||||
var settingsButton = lobby.GetOrNull<ButtonWidget>("SETTINGS_BUTTON");
|
var settingsButton = lobby.GetOrNull<ButtonWidget>("SETTINGS_BUTTON");
|
||||||
@@ -510,13 +518,13 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void AddChatLine(TextNotification chatLine)
|
void AddChatLine(TextNotification notification)
|
||||||
{
|
{
|
||||||
var template = (ContainerWidget)chatTemplate.Clone();
|
var chatLine = chatTemplates[notification.Pool].Clone();
|
||||||
LobbyUtils.SetupChatLine(template, DateTime.Now, chatLine);
|
WidgetUtils.SetupTextNotification(chatLine, notification, lobbyChatPanel.Bounds.Width - lobbyChatPanel.ScrollbarWidth, true);
|
||||||
|
|
||||||
var scrolledToBottom = lobbyChatPanel.ScrolledToBottom;
|
var scrolledToBottom = lobbyChatPanel.ScrolledToBottom;
|
||||||
lobbyChatPanel.AddChild(template);
|
lobbyChatPanel.AddChild(chatLine);
|
||||||
if (scrolledToBottom)
|
if (scrolledToBottom)
|
||||||
lobbyChatPanel.ScrollToBottom(smooth: true);
|
lobbyChatPanel.ScrollToBottom(smooth: true);
|
||||||
|
|
||||||
|
|||||||
@@ -648,37 +648,6 @@ namespace OpenRA.Mods.Common.Widgets.Logic
|
|||||||
HideChildWidget(parent, "STATUS_IMAGE");
|
HideChildWidget(parent, "STATUS_IMAGE");
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void SetupChatLine(ContainerWidget template, DateTime time, TextNotification chatLine)
|
|
||||||
{
|
|
||||||
var nameLabel = template.Get<LabelWidget>("NAME");
|
|
||||||
var timeLabel = template.Get<LabelWidget>("TIME");
|
|
||||||
var textLabel = template.Get<LabelWidget>("TEXT");
|
|
||||||
|
|
||||||
var nameText = chatLine.Prefix + ":";
|
|
||||||
var font = Game.Renderer.Fonts[nameLabel.Font];
|
|
||||||
var nameSize = font.Measure(nameText);
|
|
||||||
|
|
||||||
timeLabel.GetText = () => $"{time.Hour:D2}:{time.Minute:D2}";
|
|
||||||
|
|
||||||
nameLabel.GetColor = () => chatLine.PrefixColor;
|
|
||||||
nameLabel.GetText = () => nameText;
|
|
||||||
nameLabel.Bounds.Width = nameSize.X;
|
|
||||||
|
|
||||||
textLabel.GetColor = () => chatLine.TextColor;
|
|
||||||
textLabel.Bounds.X += nameSize.X;
|
|
||||||
textLabel.Bounds.Width -= nameSize.X;
|
|
||||||
|
|
||||||
// Hack around our hacky wordwrap behavior: need to resize the widget to fit the text
|
|
||||||
var text = WidgetUtils.WrapText(chatLine.Text, textLabel.Bounds.Width, font);
|
|
||||||
textLabel.GetText = () => text;
|
|
||||||
var dh = font.Measure(text).Y - textLabel.Bounds.Height;
|
|
||||||
if (dh > 0)
|
|
||||||
{
|
|
||||||
textLabel.Bounds.Height += dh;
|
|
||||||
template.Bounds.Height += dh;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static void HideChildWidget(Widget parent, string widgetId)
|
static void HideChildWidget(Widget parent, string widgetId)
|
||||||
{
|
{
|
||||||
var widget = parent.GetOrNull(widgetId);
|
var widget = parent.GetOrNull(widgetId);
|
||||||
|
|||||||
136
OpenRA.Mods.Common/Widgets/TextNotificationsDisplayWidget.cs
Normal file
136
OpenRA.Mods.Common/Widgets/TextNotificationsDisplayWidget.cs
Normal file
@@ -0,0 +1,136 @@
|
|||||||
|
#region Copyright & License Information
|
||||||
|
/*
|
||||||
|
* Copyright 2007-2021 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, either version 3 of
|
||||||
|
* the License, or (at your option) any later version. For more
|
||||||
|
* information, see COPYING.
|
||||||
|
*/
|
||||||
|
#endregion
|
||||||
|
|
||||||
|
using System;
|
||||||
|
using System.Collections.Generic;
|
||||||
|
using OpenRA.Primitives;
|
||||||
|
using OpenRA.Widgets;
|
||||||
|
|
||||||
|
namespace OpenRA.Mods.Common.Widgets
|
||||||
|
{
|
||||||
|
public class TextNotificationsDisplayWidget : Widget
|
||||||
|
{
|
||||||
|
public readonly int RemoveTime = 0;
|
||||||
|
public readonly int ItemSpacing = 4;
|
||||||
|
public readonly int BottomSpacing = 0;
|
||||||
|
public readonly int LogLength = 8;
|
||||||
|
public readonly bool HideOverflow = true;
|
||||||
|
|
||||||
|
public string ChatTemplate = "CHAT_LINE_TEMPLATE";
|
||||||
|
public string SystemTemplate = "SYSTEM_LINE_TEMPLATE";
|
||||||
|
public string MissionTemplate = "SYSTEM_LINE_TEMPLATE";
|
||||||
|
public string FeedbackTemplate = "SYSTEM_LINE_TEMPLATE";
|
||||||
|
readonly Dictionary<TextNotificationPool, Widget> templates = new Dictionary<TextNotificationPool, Widget>();
|
||||||
|
|
||||||
|
readonly List<int> expirations = new List<int>();
|
||||||
|
|
||||||
|
Rectangle overflowDrawBounds = Rectangle.Empty;
|
||||||
|
public override Rectangle EventBounds => Rectangle.Empty;
|
||||||
|
|
||||||
|
public override void Initialize(WidgetArgs args)
|
||||||
|
{
|
||||||
|
base.Initialize(args);
|
||||||
|
|
||||||
|
templates.Add(TextNotificationPool.Chat, Ui.LoadWidget(ChatTemplate, null, new WidgetArgs()));
|
||||||
|
templates.Add(TextNotificationPool.System, Ui.LoadWidget(SystemTemplate, null, new WidgetArgs()));
|
||||||
|
templates.Add(TextNotificationPool.Mission, Ui.LoadWidget(MissionTemplate, null, new WidgetArgs()));
|
||||||
|
templates.Add(TextNotificationPool.Feedback, Ui.LoadWidget(FeedbackTemplate, null, new WidgetArgs()));
|
||||||
|
|
||||||
|
// HACK: Assume that all templates use the same font
|
||||||
|
var lineHeight = Game.Renderer.Fonts[templates[TextNotificationPool.Chat].Get<LabelWidget>("TEXT").Font].Measure("").Y;
|
||||||
|
var wholeLines = (int)Math.Floor((double)((Bounds.Height - BottomSpacing) / lineHeight));
|
||||||
|
var visibleChildrenHeight = wholeLines * lineHeight;
|
||||||
|
|
||||||
|
overflowDrawBounds = new Rectangle(RenderOrigin.X, RenderOrigin.Y, Bounds.Width, Bounds.Height);
|
||||||
|
overflowDrawBounds.Y += Bounds.Height - visibleChildrenHeight;
|
||||||
|
overflowDrawBounds.Height = visibleChildrenHeight;
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void DrawOuter()
|
||||||
|
{
|
||||||
|
if (!IsVisible() || Children.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var mostRecentMessageOverflows = Bounds.Height < Children[Children.Count - 1].Bounds.Height;
|
||||||
|
|
||||||
|
if (mostRecentMessageOverflows && HideOverflow)
|
||||||
|
Game.Renderer.EnableScissor(overflowDrawBounds);
|
||||||
|
|
||||||
|
for (var i = Children.Count - 1; i >= 0; i--)
|
||||||
|
{
|
||||||
|
if (Bounds.Contains(Children[i].Bounds) || !HideOverflow || mostRecentMessageOverflows)
|
||||||
|
Children[i].DrawOuter();
|
||||||
|
|
||||||
|
if (mostRecentMessageOverflows)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mostRecentMessageOverflows && HideOverflow)
|
||||||
|
Game.Renderer.DisableScissor();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void AddNotification(TextNotification notification)
|
||||||
|
{
|
||||||
|
var notificationWidget = templates[notification.Pool].Clone();
|
||||||
|
WidgetUtils.SetupTextNotification(notificationWidget, notification, Bounds.Width, false);
|
||||||
|
|
||||||
|
if (Children.Count == 0)
|
||||||
|
notificationWidget.Bounds.Y = Bounds.Bottom - notificationWidget.Bounds.Height - BottomSpacing;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
foreach (var line in Children)
|
||||||
|
line.Bounds.Y -= notificationWidget.Bounds.Height + ItemSpacing;
|
||||||
|
|
||||||
|
var lastLine = Children[Children.Count - 1];
|
||||||
|
notificationWidget.Bounds.Y = lastLine.Bounds.Bottom + ItemSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
AddChild(notificationWidget);
|
||||||
|
expirations.Add(Game.LocalTick + RemoveTime);
|
||||||
|
|
||||||
|
while (Children.Count > LogLength)
|
||||||
|
RemoveNotification();
|
||||||
|
}
|
||||||
|
|
||||||
|
public void RemoveMostRecentNotification()
|
||||||
|
{
|
||||||
|
if (Children.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
var mostRecentChild = Children[Children.Count - 1];
|
||||||
|
|
||||||
|
RemoveChild(mostRecentChild);
|
||||||
|
expirations.RemoveAt(expirations.Count - 1);
|
||||||
|
|
||||||
|
for (var i = Children.Count - 1; i >= 0; i--)
|
||||||
|
Children[i].Bounds.Y += mostRecentChild.Bounds.Height + ItemSpacing;
|
||||||
|
}
|
||||||
|
|
||||||
|
private void RemoveNotification()
|
||||||
|
{
|
||||||
|
if (Children.Count == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
RemoveChild(Children[0]);
|
||||||
|
expirations.RemoveAt(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override void Tick()
|
||||||
|
{
|
||||||
|
if (RemoveTime == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// This takes advantage of the fact that recentLines is ordered by expiration, from sooner to later
|
||||||
|
while (Children.Count > 0 && Game.LocalTick >= expirations[0])
|
||||||
|
RemoveNotification();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -364,6 +364,62 @@ namespace OpenRA.Mods.Common.Widgets
|
|||||||
return name.Update((p.PlayerName, p.WinState, clientState));
|
return name.Update((p.PlayerName, p.WinState, clientState));
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static void SetupTextNotification(Widget notificationWidget, TextNotification notification, int boxWidth, bool withTimestamp)
|
||||||
|
{
|
||||||
|
var timeLabel = notificationWidget.GetOrNull<LabelWidget>("TIME");
|
||||||
|
var prefixLabel = notificationWidget.GetOrNull<LabelWidget>("PREFIX");
|
||||||
|
var textLabel = notificationWidget.Get<LabelWidget>("TEXT");
|
||||||
|
|
||||||
|
var textFont = Game.Renderer.Fonts[textLabel.Font];
|
||||||
|
var textWidth = boxWidth - notificationWidget.Bounds.X - textLabel.Bounds.X;
|
||||||
|
|
||||||
|
var hasPrefix = !string.IsNullOrEmpty(notification.Prefix) && prefixLabel != null;
|
||||||
|
var timeOffset = 0;
|
||||||
|
|
||||||
|
if (withTimestamp && timeLabel != null)
|
||||||
|
{
|
||||||
|
var time = $"{notification.Time.Hour:D2}:{notification.Time.Minute:D2}";
|
||||||
|
timeOffset = timeLabel.Bounds.Width + timeLabel.Bounds.X;
|
||||||
|
|
||||||
|
timeLabel.GetText = () => time;
|
||||||
|
|
||||||
|
textWidth -= timeOffset;
|
||||||
|
textLabel.Bounds.X += timeOffset;
|
||||||
|
|
||||||
|
if (hasPrefix)
|
||||||
|
prefixLabel.Bounds.X += timeOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (hasPrefix)
|
||||||
|
{
|
||||||
|
var prefix = notification.Prefix + ":";
|
||||||
|
var prefixSize = Game.Renderer.Fonts[prefixLabel.Font].Measure(prefix);
|
||||||
|
var prefixOffset = prefixSize.X + prefixLabel.Bounds.X;
|
||||||
|
|
||||||
|
prefixLabel.GetColor = () => notification.PrefixColor ?? prefixLabel.TextColor;
|
||||||
|
prefixLabel.GetText = () => prefix;
|
||||||
|
prefixLabel.Bounds.Width = prefixSize.X;
|
||||||
|
|
||||||
|
textWidth -= prefixOffset;
|
||||||
|
textLabel.Bounds.X += prefixOffset - timeOffset;
|
||||||
|
}
|
||||||
|
|
||||||
|
textLabel.GetColor = () => notification.TextColor ?? textLabel.TextColor;
|
||||||
|
textLabel.Bounds.Width = textWidth;
|
||||||
|
|
||||||
|
// Hack around our hacky wordwrap behavior: need to resize the widget to fit the text
|
||||||
|
var text = WrapText(notification.Text, textLabel.Bounds.Width, textFont);
|
||||||
|
textLabel.GetText = () => text;
|
||||||
|
var dh = textFont.Measure(text).Y - textLabel.Bounds.Height;
|
||||||
|
if (dh > 0)
|
||||||
|
{
|
||||||
|
textLabel.Bounds.Height += dh;
|
||||||
|
notificationWidget.Bounds.Height += dh;
|
||||||
|
}
|
||||||
|
|
||||||
|
notificationWidget.Bounds.Width = boxWidth - notificationWidget.Bounds.X;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class CachedTransform<T, U>
|
public class CachedTransform<T, U>
|
||||||
|
|||||||
@@ -6,17 +6,22 @@ Container@CHAT_PANEL:
|
|||||||
Logic: IngameChatLogic
|
Logic: IngameChatLogic
|
||||||
OpenTeamChatKey: OpenTeamChat
|
OpenTeamChatKey: OpenTeamChat
|
||||||
OpenGeneralChatKey: OpenGeneralChat
|
OpenGeneralChatKey: OpenGeneralChat
|
||||||
|
Templates:
|
||||||
|
Chat: CHAT_LINE_TEMPLATE
|
||||||
|
System: SYSTEM_LINE_TEMPLATE
|
||||||
|
Mission: SYSTEM_LINE_TEMPLATE
|
||||||
|
Feedback: SYSTEM_LINE_TEMPLATE
|
||||||
Children:
|
Children:
|
||||||
Container@CHAT_OVERLAY:
|
Container@CHAT_OVERLAY:
|
||||||
Width: PARENT_RIGHT - 24
|
Width: PARENT_RIGHT - 24
|
||||||
Height: PARENT_BOTTOM - 25
|
Height: PARENT_BOTTOM - 30
|
||||||
Visible: false
|
Visible: false
|
||||||
Children:
|
Children:
|
||||||
ChatDisplay@CHAT_DISPLAY:
|
TextNotificationsDisplay@CHAT_DISPLAY:
|
||||||
Width: PARENT_RIGHT
|
Width: PARENT_RIGHT
|
||||||
Height: PARENT_BOTTOM
|
Height: PARENT_BOTTOM
|
||||||
RemoveTime: 250
|
RemoveTime: 250
|
||||||
UseShadow: True
|
BottomSpacing: 3
|
||||||
Container@CHAT_CHROME:
|
Container@CHAT_CHROME:
|
||||||
Width: PARENT_RIGHT
|
Width: PARENT_RIGHT
|
||||||
Height: PARENT_BOTTOM
|
Height: PARENT_BOTTOM
|
||||||
@@ -59,20 +64,3 @@ Container@CHAT_PANEL:
|
|||||||
TopBottomSpacing: 3
|
TopBottomSpacing: 3
|
||||||
ItemSpacing: 4
|
ItemSpacing: 4
|
||||||
Align: Bottom
|
Align: Bottom
|
||||||
Children:
|
|
||||||
Container@CHAT_TEMPLATE:
|
|
||||||
X: 2
|
|
||||||
Width: PARENT_RIGHT - 27
|
|
||||||
Height: 16
|
|
||||||
Children:
|
|
||||||
Label@NAME:
|
|
||||||
X: 3
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@TEXT:
|
|
||||||
X: 12
|
|
||||||
Width: PARENT_RIGHT - 17
|
|
||||||
Height: 16
|
|
||||||
WordWrap: true
|
|
||||||
Shadow: True
|
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ Container@CHAT_CONTAINER:
|
|||||||
Width: PARENT_RIGHT
|
Width: PARENT_RIGHT
|
||||||
Height: PARENT_BOTTOM - 20
|
Height: PARENT_BOTTOM - 20
|
||||||
Logic: IngameChatLogic
|
Logic: IngameChatLogic
|
||||||
|
Templates:
|
||||||
|
Chat: CHAT_LINE_TEMPLATE
|
||||||
|
System: SYSTEM_LINE_TEMPLATE
|
||||||
|
Mission: SYSTEM_LINE_TEMPLATE
|
||||||
|
Feedback: SYSTEM_LINE_TEMPLATE
|
||||||
Children:
|
Children:
|
||||||
Container@CHAT_CHROME:
|
Container@CHAT_CHROME:
|
||||||
X: 15
|
X: 15
|
||||||
@@ -28,20 +33,3 @@ Container@CHAT_CONTAINER:
|
|||||||
Height: PARENT_BOTTOM - 30
|
Height: PARENT_BOTTOM - 30
|
||||||
TopBottomSpacing: 3
|
TopBottomSpacing: 3
|
||||||
ItemSpacing: 2
|
ItemSpacing: 2
|
||||||
Children:
|
|
||||||
Container@CHAT_TEMPLATE:
|
|
||||||
X: 2
|
|
||||||
Width: PARENT_RIGHT - 27
|
|
||||||
Height: 16
|
|
||||||
Children:
|
|
||||||
Label@NAME:
|
|
||||||
X: 3
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@TEXT:
|
|
||||||
X: 12
|
|
||||||
Width: PARENT_RIGHT - 17
|
|
||||||
Height: 16
|
|
||||||
WordWrap: true
|
|
||||||
Shadow: True
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
Container@SERVER_LOBBY:
|
Container@SERVER_LOBBY:
|
||||||
Logic: LobbyLogic
|
Logic: LobbyLogic
|
||||||
|
ChatTemplates:
|
||||||
|
Chat: CHAT_LINE_TEMPLATE
|
||||||
|
System: SYSTEM_LINE_TEMPLATE
|
||||||
|
Mission: SYSTEM_LINE_TEMPLATE
|
||||||
|
Feedback: SYSTEM_LINE_TEMPLATE
|
||||||
X: (WINDOW_RIGHT - WIDTH) / 2
|
X: (WINDOW_RIGHT - WIDTH) / 2
|
||||||
Y: (WINDOW_BOTTOM - 560) / 2
|
Y: (WINDOW_BOTTOM - 560) / 2
|
||||||
Width: 900
|
Width: 900
|
||||||
@@ -99,29 +104,6 @@ Container@SERVER_LOBBY:
|
|||||||
Height: PARENT_BOTTOM - 30
|
Height: PARENT_BOTTOM - 30
|
||||||
TopBottomSpacing: 3
|
TopBottomSpacing: 3
|
||||||
ItemSpacing: 2
|
ItemSpacing: 2
|
||||||
Children:
|
|
||||||
Container@CHAT_TEMPLATE:
|
|
||||||
Width: PARENT_RIGHT - 27
|
|
||||||
Height: 16
|
|
||||||
X: 2
|
|
||||||
Y: 0
|
|
||||||
Children:
|
|
||||||
Label@TIME:
|
|
||||||
X: 3
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@NAME:
|
|
||||||
X: 45
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@TEXT:
|
|
||||||
X: 55
|
|
||||||
Width: PARENT_RIGHT - 60
|
|
||||||
Height: 16
|
|
||||||
WordWrap: true
|
|
||||||
Shadow: True
|
|
||||||
Button@CHAT_MODE:
|
Button@CHAT_MODE:
|
||||||
Y: PARENT_BOTTOM - HEIGHT
|
Y: PARENT_BOTTOM - HEIGHT
|
||||||
Width: 50
|
Width: 50
|
||||||
|
|||||||
@@ -138,6 +138,7 @@ ChromeLayout:
|
|||||||
cnc|chrome/assetbrowser.yaml
|
cnc|chrome/assetbrowser.yaml
|
||||||
cnc|chrome/missionbrowser.yaml
|
cnc|chrome/missionbrowser.yaml
|
||||||
cnc|chrome/editor.yaml
|
cnc|chrome/editor.yaml
|
||||||
|
common|chrome/text-notifications.yaml
|
||||||
|
|
||||||
Voices:
|
Voices:
|
||||||
cnc|audio/voices.yaml
|
cnc|audio/voices.yaml
|
||||||
|
|||||||
@@ -6,17 +6,22 @@ Container@CHAT_PANEL:
|
|||||||
Logic: IngameChatLogic
|
Logic: IngameChatLogic
|
||||||
OpenTeamChatKey: OpenTeamChat
|
OpenTeamChatKey: OpenTeamChat
|
||||||
OpenGeneralChatKey: OpenGeneralChat
|
OpenGeneralChatKey: OpenGeneralChat
|
||||||
|
Templates:
|
||||||
|
Chat: CHAT_LINE_TEMPLATE
|
||||||
|
System: SYSTEM_LINE_TEMPLATE
|
||||||
|
Mission: SYSTEM_LINE_TEMPLATE
|
||||||
|
Feedback: SYSTEM_LINE_TEMPLATE
|
||||||
Children:
|
Children:
|
||||||
Container@CHAT_OVERLAY:
|
Container@CHAT_OVERLAY:
|
||||||
Width: PARENT_RIGHT - 24
|
Width: PARENT_RIGHT - 24
|
||||||
Height: PARENT_BOTTOM - 25
|
Height: PARENT_BOTTOM - 30
|
||||||
Visible: false
|
Visible: false
|
||||||
Children:
|
Children:
|
||||||
ChatDisplay@CHAT_DISPLAY:
|
TextNotificationsDisplay@CHAT_DISPLAY:
|
||||||
Width: PARENT_RIGHT
|
Width: PARENT_RIGHT
|
||||||
Height: PARENT_BOTTOM
|
Height: PARENT_BOTTOM
|
||||||
RemoveTime: 250
|
RemoveTime: 250
|
||||||
UseShadow: True
|
BottomSpacing: 3
|
||||||
Container@CHAT_CHROME:
|
Container@CHAT_CHROME:
|
||||||
Width: PARENT_RIGHT
|
Width: PARENT_RIGHT
|
||||||
Height: PARENT_BOTTOM
|
Height: PARENT_BOTTOM
|
||||||
@@ -54,20 +59,3 @@ Container@CHAT_PANEL:
|
|||||||
TopBottomSpacing: 3
|
TopBottomSpacing: 3
|
||||||
ItemSpacing: 4
|
ItemSpacing: 4
|
||||||
Align: Bottom
|
Align: Bottom
|
||||||
Children:
|
|
||||||
Container@CHAT_TEMPLATE:
|
|
||||||
X: 2
|
|
||||||
Width: PARENT_RIGHT - 27
|
|
||||||
Height: 16
|
|
||||||
Children:
|
|
||||||
Label@NAME:
|
|
||||||
X: 3
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@TEXT:
|
|
||||||
X: 12
|
|
||||||
Width: PARENT_RIGHT - 17
|
|
||||||
Height: 16
|
|
||||||
WordWrap: true
|
|
||||||
Shadow: True
|
|
||||||
|
|||||||
@@ -3,6 +3,11 @@ Container@CHAT_CONTAINER:
|
|||||||
Width: PARENT_RIGHT
|
Width: PARENT_RIGHT
|
||||||
Height: PARENT_BOTTOM - 100
|
Height: PARENT_BOTTOM - 100
|
||||||
Logic: IngameChatLogic
|
Logic: IngameChatLogic
|
||||||
|
Templates:
|
||||||
|
Chat: CHAT_LINE_TEMPLATE
|
||||||
|
System: SYSTEM_LINE_TEMPLATE
|
||||||
|
Mission: SYSTEM_LINE_TEMPLATE
|
||||||
|
Feedback: SYSTEM_LINE_TEMPLATE
|
||||||
Children:
|
Children:
|
||||||
Container@CHAT_CHROME:
|
Container@CHAT_CHROME:
|
||||||
X: 20
|
X: 20
|
||||||
@@ -28,20 +33,3 @@ Container@CHAT_CONTAINER:
|
|||||||
Height: PARENT_BOTTOM - 30
|
Height: PARENT_BOTTOM - 30
|
||||||
TopBottomSpacing: 3
|
TopBottomSpacing: 3
|
||||||
ItemSpacing: 2
|
ItemSpacing: 2
|
||||||
Children:
|
|
||||||
Container@CHAT_TEMPLATE:
|
|
||||||
X: 2
|
|
||||||
Width: PARENT_RIGHT - 27
|
|
||||||
Height: 16
|
|
||||||
Children:
|
|
||||||
Label@NAME:
|
|
||||||
X: 3
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@TEXT:
|
|
||||||
X: 12
|
|
||||||
Width: PARENT_RIGHT - 17
|
|
||||||
Height: 16
|
|
||||||
WordWrap: true
|
|
||||||
Shadow: True
|
|
||||||
|
|||||||
@@ -1,5 +1,10 @@
|
|||||||
Background@SERVER_LOBBY:
|
Background@SERVER_LOBBY:
|
||||||
Logic: LobbyLogic
|
Logic: LobbyLogic
|
||||||
|
ChatTemplates:
|
||||||
|
Chat: CHAT_LINE_TEMPLATE
|
||||||
|
System: SYSTEM_LINE_TEMPLATE
|
||||||
|
Mission: SYSTEM_LINE_TEMPLATE
|
||||||
|
Feedback: SYSTEM_LINE_TEMPLATE
|
||||||
X: (WINDOW_RIGHT - WIDTH) / 2
|
X: (WINDOW_RIGHT - WIDTH) / 2
|
||||||
Y: (WINDOW_BOTTOM - HEIGHT) / 2
|
Y: (WINDOW_BOTTOM - HEIGHT) / 2
|
||||||
Width: 900
|
Width: 900
|
||||||
@@ -103,28 +108,6 @@ Background@SERVER_LOBBY:
|
|||||||
Height: PARENT_BOTTOM - 30
|
Height: PARENT_BOTTOM - 30
|
||||||
TopBottomSpacing: 2
|
TopBottomSpacing: 2
|
||||||
ItemSpacing: 2
|
ItemSpacing: 2
|
||||||
Children:
|
|
||||||
Container@CHAT_TEMPLATE:
|
|
||||||
X: 2
|
|
||||||
Width: PARENT_RIGHT - 27
|
|
||||||
Height: 16
|
|
||||||
Children:
|
|
||||||
Label@TIME:
|
|
||||||
X: 3
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@NAME:
|
|
||||||
X: 45
|
|
||||||
Width: 50
|
|
||||||
Height: 16
|
|
||||||
Shadow: True
|
|
||||||
Label@TEXT:
|
|
||||||
X: 55
|
|
||||||
Width: PARENT_RIGHT - 60
|
|
||||||
Height: 16
|
|
||||||
WordWrap: true
|
|
||||||
Shadow: True
|
|
||||||
Button@CHAT_MODE:
|
Button@CHAT_MODE:
|
||||||
Y: PARENT_BOTTOM - HEIGHT
|
Y: PARENT_BOTTOM - HEIGHT
|
||||||
Width: 50
|
Width: 50
|
||||||
|
|||||||
39
mods/common/chrome/text-notifications.yaml
Normal file
39
mods/common/chrome/text-notifications.yaml
Normal file
@@ -0,0 +1,39 @@
|
|||||||
|
Container@CHAT_LINE_TEMPLATE:
|
||||||
|
Width: PARENT_RIGHT
|
||||||
|
Height: 16
|
||||||
|
Children:
|
||||||
|
Label@TIME:
|
||||||
|
X: 5
|
||||||
|
Width: 37
|
||||||
|
Height: 16
|
||||||
|
Shadow: True
|
||||||
|
Label@PREFIX:
|
||||||
|
X: 5
|
||||||
|
Height: 16
|
||||||
|
Shadow: True
|
||||||
|
Label@TEXT:
|
||||||
|
X: 5
|
||||||
|
Height: 16
|
||||||
|
WordWrap: True
|
||||||
|
Shadow: True
|
||||||
|
|
||||||
|
Container@SYSTEM_LINE_TEMPLATE:
|
||||||
|
Width: PARENT_RIGHT
|
||||||
|
Height: 16
|
||||||
|
Children:
|
||||||
|
Label@TIME:
|
||||||
|
X: 5
|
||||||
|
Width: 37
|
||||||
|
Height: 16
|
||||||
|
Shadow: True
|
||||||
|
Label@PREFIX:
|
||||||
|
X: 5
|
||||||
|
Height: 16
|
||||||
|
Shadow: True
|
||||||
|
TextColor: FFFF00
|
||||||
|
Label@TEXT:
|
||||||
|
X: 5
|
||||||
|
Height: 16
|
||||||
|
WordWrap: True
|
||||||
|
Shadow: True
|
||||||
|
TextColor: FFFF00
|
||||||
@@ -49,8 +49,6 @@ Metrics:
|
|||||||
ChatLineSound: ChatLine
|
ChatLineSound: ChatLine
|
||||||
ClickDisabledSound: ClickDisabledSound
|
ClickDisabledSound: ClickDisabledSound
|
||||||
ClickSound: ClickSound
|
ClickSound: ClickSound
|
||||||
ChatMessageColor: FFFFFF
|
|
||||||
SystemMessageColor: FFFF00
|
|
||||||
NormalSelectionColor: FFFFFF
|
NormalSelectionColor: FFFFFF
|
||||||
AltSelectionColor: 00FFFF
|
AltSelectionColor: 00FFFF
|
||||||
CtrlSelectionColor: FFFF00
|
CtrlSelectionColor: FFFF00
|
||||||
|
|||||||
@@ -117,6 +117,7 @@ ChromeLayout:
|
|||||||
common|chrome/replaybrowser.yaml
|
common|chrome/replaybrowser.yaml
|
||||||
common|chrome/gamesave-browser.yaml
|
common|chrome/gamesave-browser.yaml
|
||||||
common|chrome/gamesave-loading.yaml
|
common|chrome/gamesave-loading.yaml
|
||||||
|
common|chrome/text-notifications.yaml
|
||||||
|
|
||||||
Weapons:
|
Weapons:
|
||||||
d2k|weapons/debris.yaml
|
d2k|weapons/debris.yaml
|
||||||
|
|||||||
@@ -134,6 +134,7 @@ ChromeLayout:
|
|||||||
common|chrome/confirmation-dialogs.yaml
|
common|chrome/confirmation-dialogs.yaml
|
||||||
common|chrome/editor.yaml
|
common|chrome/editor.yaml
|
||||||
common|chrome/playerprofile.yaml
|
common|chrome/playerprofile.yaml
|
||||||
|
common|chrome/text-notifications.yaml
|
||||||
|
|
||||||
Weapons:
|
Weapons:
|
||||||
ra|weapons/explosions.yaml
|
ra|weapons/explosions.yaml
|
||||||
|
|||||||
@@ -180,6 +180,7 @@ ChromeLayout:
|
|||||||
common|chrome/missionbrowser.yaml
|
common|chrome/missionbrowser.yaml
|
||||||
common|chrome/confirmation-dialogs.yaml
|
common|chrome/confirmation-dialogs.yaml
|
||||||
common|chrome/editor.yaml
|
common|chrome/editor.yaml
|
||||||
|
common|chrome/text-notifications.yaml
|
||||||
|
|
||||||
Voices:
|
Voices:
|
||||||
ts|audio/voices.yaml
|
ts|audio/voices.yaml
|
||||||
|
|||||||
Reference in New Issue
Block a user