2 using Microsoft.Xna.Framework;
4 using System.Collections.Generic;
5 using System.ComponentModel;
10 partial class CustomInterface
12 private readonly List<GUIComponent> uiElements =
new List<GUIComponent>();
13 private GUILayoutGroup uiElementContainer;
15 private bool readingNetworkEvent;
17 private Point ElementMaxSize =>
new Point(uiElementContainer.Rect.Width, (
int)(65 * GUI.yScale));
21 partial
void InitProjSpecific()
29 var visibleElements = customInterfaceElementList.Where(ciElement => !
string.IsNullOrEmpty(ciElement.Label));
32 AbsoluteOffset = GUIStyle.ItemFrameOffset
34 childAnchor: customInterfaceElementList.Count > 1 ?
Anchor.TopCenter :
Anchor.Center)
36 RelativeSpacing = 0.05f,
37 Stretch = visibleElements.Count() > 2,
40 float elementSize = Math.Min(1.0f / visibleElements.Count(), 1);
41 foreach (CustomInterfaceElement ciElement
in visibleElements)
43 if (ciElement.HasPropertyName)
45 var layoutGroup =
new GUILayoutGroup(
new RectTransform(
new Vector2(1.0f, elementSize), uiElementContainer.RectTransform), isHorizontal:
true)
47 RelativeSpacing = 0.02f,
51 TextManager.Get(ciElement.Label).Fallback(ciElement.Label));
52 if (!ciElement.IsNumberInput)
54 var textBox =
new GUITextBox(
new RectTransform(
new Vector2(0.5f, 1.0f), layoutGroup.RectTransform), ciElement.Signal, style:
"GUITextBoxNoIcon")
61 textBox.RectTransform.MinSize = textBox.Frame.RectTransform.MinSize =
new Point(0, 0);
62 textBox.RectTransform.MaxSize = textBox.Frame.RectTransform.MaxSize =
new Point(
int.MaxValue,
int.MaxValue);
63 textBox.OnDeselected += (tb, key) =>
67 TextChanged(tb.UserData as CustomInterfaceElement, textBox.Text);
71 item.CreateClientEvent(
this);
75 textBox.OnEnterPressed += (tb, text) =>
80 uiElements.Add(textBox);
87 TryParseFloatInvariantCulture(ciElement.Signal, out
float floatSignal);
88 TryParseFloatInvariantCulture(ciElement.NumberInputMin, out
float numberInputMin);
89 TryParseFloatInvariantCulture(ciElement.NumberInputMax, out
float numberInputMax);
90 TryParseFloatInvariantCulture(ciElement.NumberInputStep, out
float numberInputStep);
94 MinValueFloat = numberInputMin,
95 MaxValueFloat = numberInputMax,
96 FloatValue = Math.Clamp(floatSignal, numberInputMin, numberInputMax),
97 DecimalsToDisplay = ciElement.NumberInputDecimalPlaces,
98 ValueStep = numberInputStep,
99 OnValueChanged = (ni) =>
103 ValueChanged(ni.UserData as CustomInterfaceElement, ni.FloatValue);
105 else if (!readingNetworkEvent)
107 item.CreateClientEvent(
this);
112 else if (ciElement.NumberType ==
NumberType.Int)
114 int.TryParse(ciElement.Signal, out
int intSignal);
115 int.TryParse(ciElement.NumberInputMin, out
int numberInputMin);
116 int.TryParse(ciElement.NumberInputMax, out
int numberInputMax);
117 TryParseFloatInvariantCulture(ciElement.NumberInputStep, out
float numberInputStep);
120 UserData = ciElement,
121 MinValueInt = numberInputMin,
122 MaxValueInt = numberInputMax,
123 IntValue = Math.Clamp(intSignal, numberInputMin, numberInputMax),
124 ValueStep = numberInputStep,
125 OnValueChanged = (ni) =>
129 ValueChanged(ni.UserData as CustomInterfaceElement, ni.IntValue);
131 else if (!readingNetworkEvent)
133 item.CreateClientEvent(
this);
140 DebugConsole.LogError($
"Error creating a CustomInterface component: unexpected NumberType \"{(ciElement.NumberType.HasValue ? ciElement.NumberType.Value.ToString() : "none
")}\"",
143 if (numberInput !=
null)
148 uiElements.Add(numberInput);
152 else if (ciElement.ContinuousSignal)
154 var tickBox =
new GUITickBox(
new RectTransform(
new Vector2(1.0f, elementSize), uiElementContainer.RectTransform)
156 MaxSize = ElementMaxSize
157 }, TextManager.Get(ciElement.Label).Fallback(ciElement.Label))
165 TickBoxToggled(tBox.UserData as CustomInterfaceElement, tBox.Selected);
167 else if (!readingNetworkEvent)
169 item.CreateClientEvent(
this);
174 tickBox.RectTransform.MinSize =
new Point(0, 0);
175 tickBox.RectTransform.MaxSize =
new Point(
int.MaxValue,
int.MaxValue);
176 uiElements.Add(tickBox);
180 var btn =
new GUIButton(
new RectTransform(
new Vector2(1.0f, elementSize), uiElementContainer.RectTransform),
181 TextManager.Get(ciElement.Label).Fallback(ciElement.Label), style:
"DeviceButton")
187 CustomInterfaceElement btnElement = userdata as CustomInterfaceElement;
190 ButtonClicked(btnElement);
192 else if (!readingNetworkEvent)
194 item.CreateClientEvent(
this,
new EventData(btnElement));
200 btn.RectTransform.MinSize = btn.Frame.RectTransform.MinSize =
new Point(0, 0);
201 btn.RectTransform.MaxSize = btn.Frame.RectTransform.MaxSize = ElementMaxSize;
210 base.CreateEditingHUD(editor);
212 if (customInterfaceElementList.Count > 0)
214 PropertyDescriptorCollection properties = TypeDescriptor.GetProperties(customInterfaceElementList[0]);
215 PropertyDescriptor labelProperty = properties.Find(
"Label",
false);
216 PropertyDescriptor signalProperty = properties.Find(
"Signal",
false);
217 for (
int i = 0; i < customInterfaceElementList.Count; i++)
221 customInterfaceElementList[i].
Label,
"Label #" + (i + 1),
"");
224 customInterfaceElementList[i].
Signal,
"Signal #" + (i + 1),
"");
229 public void HighlightElement(
int index, Color color,
float duration,
float pulsateAmount = 0.0f)
231 if (index < 0 || index >= uiElements.Count) {
return; }
232 uiElements[index].Flash(color, duration);
234 if (pulsateAmount > 0.0f)
236 if (uiElements[index] is
GUIButton button)
238 button.Frame.Pulsate(Vector2.One, Vector2.One * (1.0f + pulsateAmount), duration);
239 button.Frame.RectTransform.SetPosition(
Anchor.Center);
243 uiElements[index].Pulsate(Vector2.One, Vector2.One * (1.0f + pulsateAmount), duration);
250 bool elementVisibilityChanged =
false;
251 int visibleElementCount = 0;
252 foreach (var uiElement
in uiElements)
254 if (uiElement.UserData is not CustomInterfaceElement element) {
continue; }
255 bool visible =
Screen.
Selected ==
GameMain.
SubEditorScreen || element.StatusEffects.Any() || element.HasPropertyName || (element.Connection !=
null && element.Connection.Wires.Count > 0);
256 if (visible) { visibleElementCount++; }
257 if (uiElement.Visible != visible)
259 uiElement.Visible = visible;
260 uiElement.IgnoreLayoutGroups = !uiElement.Visible;
261 elementVisibilityChanged =
true;
265 if (elementVisibilityChanged)
267 uiElementContainer.Stretch = visibleElementCount > 2;
268 uiElementContainer.ChildAnchor = visibleElementCount > 1 ?
Anchor.TopCenter :
Anchor.Center;
269 float elementSize = Math.Min(1.0f / visibleElementCount, 1);
270 foreach (var uiElement
in uiElements)
272 uiElement.RectTransform.RelativeSize =
new Vector2(1.0f, elementSize);
275 uiElementContainer.Recalculate();
279 partial
void UpdateLabelsProjSpecific()
281 for (
int i = 0; i < labels.Length && i < uiElements.Count; i++)
285 button.Text = CreateLabelText(i);
286 button.TextBlock.Wrap = button.Text.Contains(
' ');
290 tickBox.Text = CreateLabelText(i);
291 tickBox.TextBlock.Wrap = tickBox.Text.Contains(
' ');
295 var textBlock = uiElements[i].Parent.GetChild<
GUITextBlock>();
296 textBlock.
Text = CreateLabelText(i);
297 textBlock.Wrap = textBlock.Text.Contains(
' ');
301 LocalizedString CreateLabelText(
int elementIndex)
303 var label = customInterfaceElementList[elementIndex].Label;
304 return string.IsNullOrWhiteSpace(label) ?
305 TextManager.GetWithVariable(
"connection.signaloutx",
"[num]", (elementIndex + 1).ToString()) :
306 TextManager.Get(label).Fallback(label);
309 uiElementContainer.Recalculate();
310 var textBlocks =
new List<GUITextBlock>();
311 foreach (GUIComponent element
in uiElementContainer.Children)
313 if (element is GUIButton btn)
315 if (btn.TextBlock.TextSize.Y > btn.Rect.Height - btn.TextBlock.Padding.Y - btn.TextBlock.Padding.W)
317 btn.RectTransform.RelativeSize =
new Vector2(btn.RectTransform.RelativeSize.X, btn.RectTransform.RelativeSize.Y * 1.5f);
319 textBlocks.Add(btn.TextBlock);
321 else if (element is GUITickBox tickBox)
323 textBlocks.Add(tickBox.TextBlock);
325 else if (element is GUILayoutGroup)
327 textBlocks.Add(element.GetChild<GUITextBlock>());
330 uiElementContainer.Recalculate();
331 GUITextBlock.AutoScaleAndNormalize(textBlocks);
334 partial
void UpdateSignalsProjSpecific()
336 if (signals ==
null) {
return; }
337 for (
int i = 0; i < signals.Length && i < uiElements.Count; i++)
339 string signal = customInterfaceElementList[i].Signal;
340 if (uiElements[i] is GUITextBox tb)
342 tb.Text = Screen.Selected is { IsEditor:
true } ?
344 TextManager.Get(signal).Fallback(signal).Value;
346 else if (uiElements[i] is GUINumberInput ni)
350 int.TryParse(signal, out
int value);
360 for (
int i = 0; i < customInterfaceElementList.Count; i++)
362 var element = customInterfaceElementList[i];
363 if (element.HasPropertyName)
365 if (!element.IsNumberInput)
371 switch (element.NumberType)
383 else if (element.ContinuousSignal)
396 readingNetworkEvent =
true;
399 for (
int i = 0; i < customInterfaceElementList.Count; i++)
401 var element = customInterfaceElementList[i];
402 if (element.HasPropertyName)
405 if (!element.IsNumberInput)
407 TextChanged(element, newValue);
411 switch (element.NumberType)
413 case NumberType.Int when
int.TryParse(newValue, out
int value):
414 ValueChanged(element, value);
416 case NumberType.Float when TryParseFloatInvariantCulture(newValue, out
float value):
417 ValueChanged(element, value);
425 if (element.ContinuousSignal)
427 ((
GUITickBox)uiElements[i]).Selected = elementState;
428 TickBoxToggled(element, elementState);
430 else if (elementState)
432 ButtonClicked(element);
437 UpdateSignalsProjSpecific();
441 readingNetworkEvent =
false;
RectTransform RectTransform
OnSelectedHandler OnSelected
static SubEditorScreen SubEditorScreen
void ClientEventWrite(IWriteMessage msg, NetEntityEvent.IData extraData=null)
override void CreateEditingHUD(SerializableEntityEditor editor)
override void UpdateHUDComponentSpecific(Character character, float deltaTime, Camera cam)
void ClientEventRead(IReadMessage msg, float sendingTime)
override bool RecreateGUIOnResolutionChange
void HighlightElement(int index, Color color, float duration, float pulsateAmount=0.0f)
override void CreateGUI()
Overload this method and implement. The method is automatically called when the resolution changes.
Defines a point in the event that GoTo actions can jump to.
ContentPackage? ContentPackage
GUIComponent CreateStringField(ISerializableEntity entity, SerializableProperty property, string value, LocalizedString displayName, LocalizedString toolTip)
void WriteString(string val)
void WriteBoolean(bool val)