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
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();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user