Initial commit: OpenRA game engine
Fork from OpenRA/OpenRA with one-click launch script (start-ra.cmd) Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
138
OpenRA.Mods.Common/Widgets/TextNotificationsDisplayWidget.cs
Normal file
138
OpenRA.Mods.Common/Widgets/TextNotificationsDisplayWidget.cs
Normal file
@@ -0,0 +1,138 @@
|
||||
#region Copyright & License Information
|
||||
/*
|
||||
* Copyright (c) The OpenRA Developers and Contributors
|
||||
* 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 DisplayDurationMs = 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 = "CHAT_LINE_TEMPLATE";
|
||||
public string FeedbackTemplate = "TRANSIENT_LINE_TEMPLATE";
|
||||
public string TransientsTemplate = "TRANSIENT_LINE_TEMPLATE";
|
||||
readonly Dictionary<TextNotificationPool, Widget> templates = [];
|
||||
|
||||
readonly List<long> expirations = [];
|
||||
|
||||
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, []));
|
||||
templates.Add(TextNotificationPool.System, Ui.LoadWidget(SystemTemplate, null, []));
|
||||
templates.Add(TextNotificationPool.Mission, Ui.LoadWidget(MissionTemplate, null, []));
|
||||
templates.Add(TextNotificationPool.Feedback, Ui.LoadWidget(FeedbackTemplate, null, []));
|
||||
templates.Add(TextNotificationPool.Transients, Ui.LoadWidget(TransientsTemplate, null, []));
|
||||
|
||||
// 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;
|
||||
|
||||
var y = RenderOrigin.Y + Bounds.Height - visibleChildrenHeight;
|
||||
overflowDrawBounds = new Rectangle(RenderOrigin.X, y, Bounds.Width, visibleChildrenHeight);
|
||||
}
|
||||
|
||||
public override void DrawOuter()
|
||||
{
|
||||
if (!IsVisible() || Children.Count == 0)
|
||||
return;
|
||||
|
||||
var mostRecentMessageOverflows = Bounds.Height < Children[^1].Bounds.Height;
|
||||
|
||||
if (mostRecentMessageOverflows && HideOverflow)
|
||||
Game.Renderer.EnableScissor(overflowDrawBounds);
|
||||
|
||||
var bounds = Bounds.ToRectangle();
|
||||
for (var i = Children.Count - 1; i >= 0; i--)
|
||||
{
|
||||
if (!HideOverflow || mostRecentMessageOverflows || bounds.Contains(Children[i].Bounds.ToRectangle()))
|
||||
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[^1];
|
||||
notificationWidget.Bounds.Y = lastLine.Bounds.Bottom + ItemSpacing;
|
||||
}
|
||||
|
||||
AddChild(notificationWidget);
|
||||
expirations.Add(Game.RunTime + DisplayDurationMs);
|
||||
|
||||
while (Children.Count > LogLength)
|
||||
RemoveNotification();
|
||||
}
|
||||
|
||||
public void RemoveMostRecentNotification()
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
return;
|
||||
|
||||
var mostRecentChild = Children[^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;
|
||||
}
|
||||
|
||||
void RemoveNotification()
|
||||
{
|
||||
if (Children.Count == 0)
|
||||
return;
|
||||
|
||||
RemoveChild(Children[0]);
|
||||
expirations.RemoveAt(0);
|
||||
}
|
||||
|
||||
public override void Tick()
|
||||
{
|
||||
if (DisplayDurationMs == 0)
|
||||
return;
|
||||
|
||||
// This takes advantage of the fact that recentLines is ordered by expiration, from sooner to later
|
||||
while (Children.Count > 0 && Game.RunTime >= expirations[0])
|
||||
RemoveNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user