Files
LuaCsForBarotraumaEP/Barotrauma/BarotraumaClient/ClientSource/Items/Components/Signal/Terminal.cs
2025-03-12 12:56:27 +00:00

184 lines
6.8 KiB
C#

using Barotrauma.Extensions;
using Barotrauma.Networking;
using Microsoft.Xna.Framework;
using System.Collections.Generic;
using System.Linq;
using System.Xml.Linq;
namespace Barotrauma.Items.Components
{
partial class Terminal : ItemComponent, IClientSerializable, IServerSerializable
{
private readonly struct ClientEventData : IEventData
{
public readonly string Text;
public ClientEventData(string text)
{
Text = text;
}
}
private GUIListBox historyBox;
private GUITextBlock fillerBlock;
private GUITextBox inputBox;
private GUILayoutGroup layoutGroup;
private bool shouldSelectInputBox;
private readonly List<GUIComponent> inputElements = new List<GUIComponent>();
partial void InitProjSpecific(XElement element)
{
float marginMultiplier = element.GetAttributeFloat("marginmultiplier", 1.0f);
layoutGroup = new GUILayoutGroup(new RectTransform(GuiFrame.Rect.Size - GUIStyle.ItemFrameMargin.Multiply(marginMultiplier), GuiFrame.RectTransform, Anchor.Center) { AbsoluteOffset = GUIStyle.ItemFrameOffset.Multiply(marginMultiplier) })
{
ChildAnchor = Anchor.TopCenter,
RelativeSpacing = 0.02f,
Stretch = true
};
historyBox = new GUIListBox(new RectTransform(new Vector2(1, .9f), layoutGroup.RectTransform), style: null)
{
AutoHideScrollBar = this.AutoHideScrollbar
};
inputElements.Add(CreateFillerBlock());
inputElements.Add(new GUIFrame(new RectTransform(new Vector2(0.9f, 0.01f), layoutGroup.RectTransform), style: "HorizontalLine"));
inputBox = new GUITextBox(new RectTransform(new Vector2(1, .1f), layoutGroup.RectTransform), textColor: TextColor)
{
MaxTextLength = MaxMessageLength,
OverflowClip = true,
OnEnterPressed = (GUITextBox textBox, string text) =>
{
if (GameMain.NetworkMember == null)
{
SendOutput(text);
}
else
{
item.CreateClientEvent(this, new ClientEventData(text));
}
textBox.Text = string.Empty;
return true;
}
};
inputElements.Add(inputBox);
RefreshInputElements();
}
/// <summary>
/// Refreshes the visibility of the input box and the layout of the UI depending on whether the terminal is readonly or not.
/// </summary>
private void RefreshInputElements()
{
foreach (var inputElement in inputElements)
{
inputElement.Visible = !_readonly;
inputElement.IgnoreLayoutGroups = !inputElement.Visible;
}
layoutGroup?.Recalculate();
}
// Create fillerBlock to cover historyBox so new values appear at the bottom of historyBox
// This could be removed if GUIListBox supported aligning its children
public GUIComponent CreateFillerBlock()
{
fillerBlock = new GUITextBlock(new RectTransform(new Vector2(1, 1), historyBox.Content.RectTransform, anchor: Anchor.TopCenter), string.Empty)
{
CanBeFocused = false
};
return fillerBlock;
}
private void SendOutput(string input)
{
if (input.Length > MaxMessageLength)
{
input = input.Substring(0, MaxMessageLength);
}
OutputValue = input;
ShowOnDisplay(input, addToHistory: true, TextColor, isWelcomeMessage: false);
item.SendSignal(input, "signal_out");
}
partial void ShowOnDisplay(string input, bool addToHistory, Color color, bool isWelcomeMessage)
{
if (addToHistory)
{
messageHistory.Add(new TerminalMessage(input, color, isWelcomeMessage));
while (messageHistory.Count > MaxMessages)
{
messageHistory.RemoveAt(0);
}
while (historyBox.Content.CountChildren > MaxMessages)
{
historyBox.RemoveChild(historyBox.Content.Children.First());
}
}
GUITextBlock newBlock = new GUITextBlock(
new RectTransform(new Vector2(1, 0), historyBox.Content.RectTransform, anchor: Anchor.TopCenter),
LineStartSymbol + TextManager.Get(input).Fallback(input),
textColor: color, wrap: true, font: UseMonospaceFont ? GUIStyle.MonospacedFont : GUIStyle.Font)
{
CanBeFocused = false
};
if (fillerBlock != null)
{
float y = fillerBlock.RectTransform.RelativeSize.Y - newBlock.RectTransform.RelativeSize.Y;
if (y > 0)
{
fillerBlock.RectTransform.RelativeSize = new Vector2(1, y);
}
else
{
historyBox.RemoveChild(fillerBlock);
fillerBlock = null;
}
}
historyBox.RecalculateChildren();
historyBox.UpdateScrollBarSize();
if (AutoScrollToBottom)
{
historyBox.ScrollBar.BarScrollValue = 1;
}
}
public override bool Select(Character character)
{
shouldSelectInputBox = true;
return base.Select(character);
}
// This method is overrided instead of the UpdateHUD method because this ensures the input box is selected
// even when the terminal component is selected for the very first time. Doing the input box selection in the
// UpdateHUD method only selects the input box on every terminal selection except for the very first time.
public override void AddToGUIUpdateList(int order = 0)
{
base.AddToGUIUpdateList(order: order);
if (shouldSelectInputBox && !Readonly)
{
inputBox.Select();
shouldSelectInputBox = false;
}
}
public void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData = null)
{
if (TryExtractEventData(extraData, out ClientEventData eventData))
{
msg.WriteString(eventData.Text);
}
}
public void ClientEventRead(IReadMessage msg, float sendingTime)
{
SendOutput(msg.ReadString());
}
}
}