Files
Ciarán Walsh 2a201837c7 Link to reagent ingredients on the same Guidebook page (#36700)
* Add in-page links for guidebook reagent recipes

* Add links to microwave recipes

* This function is too specific to be in Control extensions

* Better naming

* Wrap RichTextLabel instead of subclassing

* "Activate" is ambiguous
2025-05-09 10:06:26 +10:00

145 lines
4.2 KiB
C#
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System.Diagnostics.CodeAnalysis;
using System.Numerics;
using Content.Client.Guidebook.Controls;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
namespace Content.Client.UserInterface.ControlExtensions;
public static class ControlExtension
{
public static List<T> GetControlOfType<T>(this Control parent) where T : Control
{
return parent.GetControlOfType<T>(typeof(T).Name, false);
}
public static List<T> GetControlOfType<T>(this Control parent, string childType) where T : Control
{
return parent.GetControlOfType<T>(childType, false);
}
public static List<T> GetControlOfType<T>(this Control parent, bool fullTreeSearch) where T : Control
{
return parent.GetControlOfType<T>(typeof(T).Name, fullTreeSearch);
}
public static List<T> GetControlOfType<T>(this Control parent, string childType, bool fullTreeSearch) where T : Control
{
List<T> controlList = new List<T>();
foreach (var child in parent.Children)
{
var isType = child.GetType().Name == childType;
var hasChildren = child.ChildCount > 0;
var searchDeeper = hasChildren && !isType;
if (isType)
{
controlList.Add((T) child);
}
if (fullTreeSearch || searchDeeper)
{
controlList.AddRange(child.GetControlOfType<T>(childType, fullTreeSearch));
}
}
return controlList;
}
public static List<ISearchableControl> GetSearchableControls(this Control parent, bool fullTreeSearch = false)
{
List<ISearchableControl> controlList = new List<ISearchableControl>();
foreach (var child in parent.Children)
{
var hasChildren = child.ChildCount > 0;
var searchDeeper = hasChildren && child is not ISearchableControl;
if (child is ISearchableControl searchableChild)
{
controlList.Add(searchableChild);
}
if (fullTreeSearch || searchDeeper)
{
controlList.AddRange(child.GetSearchableControls(fullTreeSearch));
}
}
return controlList;
}
/// <summary>
/// Search the controls tree for a parent node of type T
/// E.g. to find the control implementing some event handling interface.
/// </summary>
public static bool TryGetParentHandler<T>(this Control child, [NotNullWhen(true)] out T? result)
{
for (var control = child; control is not null; control = control.Parent)
{
if (control is not T handler)
continue;
result = handler;
return true;
}
result = default;
return false;
}
/// <summary>
/// Find the controls offset relative to its closest ScrollContainer
/// Returns null if the control is not in the tree or not visible.
/// </summary>
public static Vector2? GetControlScrollPosition(this Control child)
{
if (!child.VisibleInTree)
return null;
var position = new Vector2();
var control = child;
while (control is not null)
{
// The scroll container's direct child is re-positioned while scrolling,
// so we need to ignore its position.
if (control.Parent is ScrollContainer)
break;
position += control.Position;
control = control.Parent;
}
return position;
}
public static bool ChildrenContainText(this Control parent, string search)
{
var labels = parent.GetControlOfType<Label>();
var richTextLabels = parent.GetControlOfType<RichTextLabel>();
foreach (var label in labels)
{
if (label.Text != null && label.Text.Contains(search, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
foreach (var label in richTextLabels)
{
var text = label.GetMessage();
if (text != null && text.Contains(search, StringComparison.OrdinalIgnoreCase))
{
return true;
}
}
return false;
}
}