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
This commit is contained in:
Ciarán Walsh
2025-05-09 01:06:26 +01:00
committed by GitHub
parent 7bec148634
commit 2a201837c7
9 changed files with 287 additions and 56 deletions

View File

@@ -1,3 +1,4 @@
using System.Diagnostics;
using System.Linq;
using Content.Client.Guidebook.RichText;
using Content.Client.UserInterface.ControlExtensions;
@@ -6,6 +7,7 @@ using Content.Client.UserInterface.Controls.FancyTree;
using Content.Client.UserInterface.Systems.Info;
using Content.Shared.Guidebook;
using Robust.Client.AutoGenerated;
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
using Robust.Client.UserInterface.XAML;
using Robust.Shared.ContentPack;
@@ -14,7 +16,7 @@ using Robust.Shared.Prototypes;
namespace Content.Client.Guidebook.Controls;
[GenerateTypedNameReferences]
public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler, IAnchorClickHandler
{
[Dependency] private readonly DocumentParsingManager _parsingMan = default!;
[Dependency] private readonly IResourceManager _resourceManager = default!;
@@ -53,6 +55,38 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
ShowGuide(entry);
}
public void HandleAnchor(IPrototypeLinkControl prototypeLinkControl)
{
var prototype = prototypeLinkControl.LinkedPrototype;
if (prototype == null)
return;
var (linkableControls, _) = GetLinkableControlsAndLinks(EntryContainer);
foreach (var linkableControl in linkableControls)
{
if (linkableControl.RepresentedPrototype != prototype)
continue;
if (linkableControl is not Control control)
return;
// Check if the target item is currently filtered out
if (!control.Visible)
control.Visible = true;
UserInterfaceManager.DeferAction(() =>
{
if (control.GetControlScrollPosition() is not {} position)
return;
Scroll.HScrollTarget = position.X;
Scroll.VScrollTarget = position.Y;
});
break;
}
}
private void OnSelectionChanged(TreeItem? item)
{
if (item != null && item.Metadata is GuideEntry entry)
@@ -94,6 +128,23 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
}
LastEntry = entry.Id;
var (linkableControls, linkControls) = GetLinkableControlsAndLinks(EntryContainer);
HashSet<IPrototype> availablePrototypeLinks = new();
foreach (var linkableControl in linkableControls)
{
var prototype = linkableControl.RepresentedPrototype;
if (prototype != null)
availablePrototypeLinks.Add(prototype);
}
foreach (var linkControl in linkControls)
{
var prototype = linkControl.LinkedPrototype;
if (prototype != null && availablePrototypeLinks.Contains(prototype))
linkControl.EnablePrototypeLink();
}
}
public void UpdateGuides(
@@ -209,4 +260,30 @@ public sealed partial class GuidebookWindow : FancyWindow, ILinkClickHandler
}
}
}
private static (List<IPrototypeRepresentationControl>, List<IPrototypeLinkControl>) GetLinkableControlsAndLinks(Control parent)
{
List<IPrototypeRepresentationControl> linkableList = new();
List<IPrototypeLinkControl> linkList = new();
foreach (var child in parent.Children)
{
var hasChildren = child.ChildCount > 0;
if (child is IPrototypeLinkControl linkChild)
linkList.Add(linkChild);
else if (child is IPrototypeRepresentationControl linkableChild)
linkableList.Add(linkableChild);
if (!hasChildren)
continue;
var (childLinkableList, childLinkList) = GetLinkableControlsAndLinks(child);
linkableList.AddRange(childLinkableList);
linkList.AddRange(childLinkList);
}
return (linkableList, linkList);
}
}