Move runtime menu tabs onto Eve surfaces
This commit is contained in:
parent
bd84882d2b
commit
bf112a37df
3 changed files with 282 additions and 15 deletions
|
|
@ -34,6 +34,7 @@ RequireNoRendererLocalDebugPanels(root);
|
|||
RequireMainMenuSettingsCommit(root);
|
||||
RequireMainMenuSettingsShellUsesEveSurface(root);
|
||||
RequireSectorMapZoneDetailsUseEveSurface(root);
|
||||
RequireRuntimeMenuTabsUseEveSurface(root);
|
||||
RequirePlayerSettingsEveSurface(root);
|
||||
RequireMainMenuContinueRunState(root);
|
||||
RequirePropertiesPanelReadOnlyInspector(root);
|
||||
|
|
@ -500,6 +501,7 @@ Console.WriteLine("Renderer-local debug panels: obsolete uGUI field tester autho
|
|||
Console.WriteLine("Main-menu settings authority: player name, gameplay, and graphics settings return through typed player-settings commits");
|
||||
Console.WriteLine("Main-menu settings shell: settings/input/audio subpages lower through Eve UI Toolkit surfaces instead of PropertiesPanel buttons");
|
||||
Console.WriteLine("Sector-map zone details shell: zone inspection lowers through an Eve UI Toolkit surface instead of PropertiesPanel rows");
|
||||
Console.WriteLine("Runtime menu tab shell: tab navigation lowers through an Eve UI Toolkit surface instead of MenuTabButton click wiring");
|
||||
Console.WriteLine("Main-menu Continue authority: Continue selects typed run state instead of a null button");
|
||||
Console.WriteLine("PropertiesPanel inspector authority: dead generic reflection inspector path is deleted");
|
||||
Console.WriteLine("Typed behavior metadata authority: live heat/mining/thermotoggle payload kinds stay owned by package metadata");
|
||||
|
|
@ -2534,6 +2536,58 @@ static void RequireSectorMapZoneDetailsUseEveSurface(string root)
|
|||
}
|
||||
}
|
||||
|
||||
static void RequireRuntimeMenuTabsUseEveSurface(string root)
|
||||
{
|
||||
var menuPanelPath = Path.Combine(root, "Assets", "Scripts", "UI", "Menu", "MenuPanel.cs");
|
||||
if (!File.Exists(menuPanelPath))
|
||||
{
|
||||
throw new InvalidOperationException("Cannot verify runtime menu tab shell; MenuPanel.cs is missing.");
|
||||
}
|
||||
|
||||
var source = File.ReadAllText(menuPanelPath);
|
||||
var requiredSymbols = new[]
|
||||
{
|
||||
"MenuTabsSurfaceId",
|
||||
"RenderTabSurface(",
|
||||
"HandleTabSurfaceCommand(",
|
||||
"ResolveTabSurfaceDocument(",
|
||||
"BuildTabSurfaceDefinition(",
|
||||
"ResolveVisibleTabs(",
|
||||
"GetTabCommand(",
|
||||
"new EveUiToolkitSurfaceLowerer()",
|
||||
"TabButtons.gameObject.SetActive(false)"
|
||||
};
|
||||
|
||||
var missingSymbols = requiredSymbols
|
||||
.Where(symbol => !source.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
|
||||
if (missingSymbols.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"MenuPanel no longer lowers the runtime tab shell through Eve surfaces: " +
|
||||
string.Join(", ", missingSymbols));
|
||||
}
|
||||
|
||||
var forbiddenSymbols = new[]
|
||||
{
|
||||
"tabButton.Button.onClick.AddListener(",
|
||||
"tabButton.gameObject.SetActive(!tabButton.RequireDock || GameManager.DockedEntity != null);",
|
||||
"_tabs[MenuTab.Local].gameObject.SetActive("
|
||||
};
|
||||
|
||||
var hits = forbiddenSymbols
|
||||
.Where(symbol => source.Contains(symbol, StringComparison.Ordinal))
|
||||
.ToArray();
|
||||
|
||||
if (hits.Length > 0)
|
||||
{
|
||||
throw new InvalidOperationException(
|
||||
"MenuPanel still owns tab-shell behavior through the old MenuTabButton path: " +
|
||||
string.Join(", ", hits));
|
||||
}
|
||||
}
|
||||
|
||||
static void RequirePlayerSettingsEveSurface(string root)
|
||||
{
|
||||
var projectorPath = Path.Combine(root, "Aetheria.State", "AetheriaPlayerSettingsSurfaceProjector.cs");
|
||||
|
|
|
|||
|
|
@ -5,11 +5,20 @@
|
|||
using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UniRx.Triggers;
|
||||
using System.Linq;
|
||||
using GameCult.Eve.Surface;
|
||||
using GameCult.Eve.UnityUIToolkit;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
public class MenuPanel : MonoBehaviour
|
||||
{
|
||||
private const string MenuTabsSurfaceType = "surface-state";
|
||||
private const string MenuTabsSurfaceSchema = "gamecult.eve.surface.v1";
|
||||
private const string MenuTabsSurfaceProviderId = "aetheria";
|
||||
private const string MenuTabsSurfaceProviderKind = "runtime.menu";
|
||||
private const string MenuTabsSurfaceId = "aetheria.runtime_menu.tabs";
|
||||
|
||||
public ActionGameManager GameManager;
|
||||
public RectTransform TabButtons;
|
||||
public Color ActiveTabColor;
|
||||
|
|
@ -19,37 +28,43 @@ public class MenuPanel : MonoBehaviour
|
|||
|
||||
private Dictionary<MenuTab, MenuTabButton> _tabs = new Dictionary<MenuTab, MenuTabButton>();
|
||||
private MenuTabButton _current;
|
||||
private UIDocument _tabSurfaceDocument;
|
||||
|
||||
public MenuTab CurrentTab { get; private set; }
|
||||
|
||||
public void ShowTab(MenuTab tab)
|
||||
{
|
||||
gameObject.SetActive(true);
|
||||
|
||||
if (_current == _tabs[tab]) return;
|
||||
|
||||
if (!_tabs.TryGetValue(tab, out var next))
|
||||
return;
|
||||
|
||||
if (_current == next)
|
||||
{
|
||||
RenderTabSurface();
|
||||
return;
|
||||
}
|
||||
|
||||
if(_current != null)
|
||||
{
|
||||
_current.TabContents.SetActive(false);
|
||||
_current.Text.color = InactiveTabColor;
|
||||
}
|
||||
|
||||
CurrentTab = tab;
|
||||
_current = _tabs[tab];
|
||||
_current = next;
|
||||
|
||||
_current.TabContents.SetActive(true);
|
||||
_current.Text.color = ActiveTabColor;
|
||||
RenderTabSurface();
|
||||
|
||||
TabChanged?.Invoke(tab);
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
foreach (var tabButton in _tabs.Values)
|
||||
{
|
||||
tabButton.gameObject.SetActive(!tabButton.RequireDock || GameManager.DockedEntity != null);
|
||||
}
|
||||
_tabs[MenuTab.Local].gameObject.SetActive((GameManager.DockedEntity as OrbitalEntity)?.Story!=null);
|
||||
if (TabButtons != null)
|
||||
TabButtons.gameObject.SetActive(false);
|
||||
|
||||
RenderTabSurface();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
|
|
@ -57,12 +72,202 @@ public class MenuPanel : MonoBehaviour
|
|||
foreach (var tabButton in TabButtons.GetComponentsInChildren<MenuTabButton>())
|
||||
{
|
||||
tabButton.TabContents.SetActive(false);
|
||||
tabButton.Text.color = InactiveTabColor;
|
||||
_tabs.Add(tabButton.Tab, tabButton);
|
||||
tabButton.Button.onClick.AddListener(() => ShowTab(tabButton.Tab));
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
HideTabSurface();
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
if (_tabSurfaceDocument != null)
|
||||
{
|
||||
Destroy(_tabSurfaceDocument.gameObject);
|
||||
_tabSurfaceDocument = null;
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderTabSurface()
|
||||
{
|
||||
if (_tabs.Count == 0)
|
||||
return;
|
||||
|
||||
if (TabButtons != null)
|
||||
TabButtons.gameObject.SetActive(false);
|
||||
|
||||
var document = ResolveTabSurfaceDocument();
|
||||
document.gameObject.SetActive(true);
|
||||
|
||||
var root = document.rootVisualElement;
|
||||
root.Clear();
|
||||
root.style.flexGrow = 1;
|
||||
root.style.position = Position.Absolute;
|
||||
root.style.left = 0;
|
||||
root.style.top = 0;
|
||||
root.style.right = 0;
|
||||
root.style.bottom = 0;
|
||||
root.style.alignItems = Align.Center;
|
||||
root.style.justifyContent = Justify.FlexStart;
|
||||
root.style.paddingTop = 16;
|
||||
root.pickingMode = PickingMode.Ignore;
|
||||
|
||||
var shell = new VisualElement();
|
||||
shell.style.minWidth = 420;
|
||||
shell.style.maxWidth = 760;
|
||||
shell.style.backgroundColor = new Color(0.08f, 0.1f, 0.14f, 0.94f);
|
||||
shell.style.borderTopLeftRadius = 8;
|
||||
shell.style.borderTopRightRadius = 8;
|
||||
shell.style.borderBottomLeftRadius = 8;
|
||||
shell.style.borderBottomRightRadius = 8;
|
||||
shell.style.paddingLeft = 16;
|
||||
shell.style.paddingRight = 16;
|
||||
shell.style.paddingTop = 12;
|
||||
shell.style.paddingBottom = 12;
|
||||
shell.style.borderLeftWidth = 1;
|
||||
shell.style.borderRightWidth = 1;
|
||||
shell.style.borderTopWidth = 1;
|
||||
shell.style.borderBottomWidth = 1;
|
||||
shell.style.borderLeftColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
|
||||
shell.style.borderRightColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
|
||||
shell.style.borderTopColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
|
||||
shell.style.borderBottomColor = new Color(0.3f, 0.47f, 0.71f, 0.8f);
|
||||
shell.pickingMode = PickingMode.Position;
|
||||
root.Add(shell);
|
||||
|
||||
var lowerer = new EveUiToolkitSurfaceLowerer();
|
||||
shell.Add(lowerer.Lower(BuildTabSurfaceDefinition(), HandleTabSurfaceCommand));
|
||||
}
|
||||
|
||||
private void HandleTabSurfaceCommand(EveSurfaceCommandRequest request)
|
||||
{
|
||||
foreach (var tab in _tabs.Keys)
|
||||
{
|
||||
if (string.Equals(request.Command, GetTabCommand(tab), StringComparison.Ordinal))
|
||||
{
|
||||
ShowTab(tab);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogWarning($"Unknown runtime menu tab command: {request.Command}");
|
||||
}
|
||||
|
||||
private void HideTabSurface()
|
||||
{
|
||||
if (_tabSurfaceDocument == null)
|
||||
return;
|
||||
|
||||
_tabSurfaceDocument.rootVisualElement.Clear();
|
||||
_tabSurfaceDocument.gameObject.SetActive(false);
|
||||
}
|
||||
|
||||
private UIDocument ResolveTabSurfaceDocument()
|
||||
{
|
||||
if (_tabSurfaceDocument != null)
|
||||
return _tabSurfaceDocument;
|
||||
|
||||
var host = new GameObject("Aetheria Runtime Menu Tabs Surface");
|
||||
host.transform.SetParent(transform, false);
|
||||
var document = host.AddComponent<UIDocument>();
|
||||
document.sortingOrder = 1000;
|
||||
host.SetActive(false);
|
||||
_tabSurfaceDocument = document;
|
||||
return document;
|
||||
}
|
||||
|
||||
private EveSurfaceDocument BuildTabSurfaceDefinition()
|
||||
{
|
||||
var visibleTabs = ResolveVisibleTabs();
|
||||
var commands = visibleTabs
|
||||
.Select(tabButton => new EveCommandTemplate(
|
||||
GetTabCommand(tabButton.Tab),
|
||||
tabButton.Text?.text ?? tabButton.Tab.ToString(),
|
||||
"unity-uitoolkit"))
|
||||
.ToArray();
|
||||
|
||||
var buttons = visibleTabs
|
||||
.Select(tabButton =>
|
||||
{
|
||||
var label = tabButton.Text?.text ?? tabButton.Tab.ToString();
|
||||
if (tabButton.Tab == CurrentTab)
|
||||
label = $"{label} *";
|
||||
|
||||
return Button(
|
||||
$"{MenuTabsSurfaceId}.{tabButton.Tab.ToString().ToLowerInvariant()}",
|
||||
label,
|
||||
GetTabCommand(tabButton.Tab));
|
||||
})
|
||||
.ToArray();
|
||||
|
||||
return new EveSurfaceDocument(
|
||||
MenuTabsSurfaceType,
|
||||
MenuTabsSurfaceSchema,
|
||||
MenuTabsSurfaceProviderId,
|
||||
MenuTabsSurfaceProviderKind,
|
||||
"Runtime Menu Tabs",
|
||||
version: 1,
|
||||
DateTime.UtcNow.ToString("O"),
|
||||
new EveSurfaceTree(
|
||||
MenuTabsSurfaceId,
|
||||
Node(
|
||||
$"{MenuTabsSurfaceId}.root",
|
||||
"surface",
|
||||
Array.Empty<(string Key, string Value)>(),
|
||||
Text(
|
||||
$"{MenuTabsSurfaceId}.current",
|
||||
$"Current: {CurrentTab}"),
|
||||
ButtonRow($"{MenuTabsSurfaceId}.tabs", buttons)),
|
||||
Array.Empty<EveStyleToken>()),
|
||||
commands);
|
||||
}
|
||||
|
||||
private MenuTabButton[] ResolveVisibleTabs()
|
||||
{
|
||||
return _tabs.Values
|
||||
.Where(tabButton => !tabButton.RequireDock || GameManager.DockedEntity != null)
|
||||
.Where(tabButton => tabButton.Tab != MenuTab.Local || (GameManager.DockedEntity as OrbitalEntity)?.Story != null)
|
||||
.OrderBy(tabButton => (int)tabButton.Tab)
|
||||
.ToArray();
|
||||
}
|
||||
|
||||
private static string GetTabCommand(MenuTab tab)
|
||||
{
|
||||
return $"aetheria.runtime_menu.tab.{tab.ToString().ToLowerInvariant()}";
|
||||
}
|
||||
|
||||
private static EveSurfaceComponent Text(string id, string value)
|
||||
{
|
||||
return Node(id, "text", new[] { ("value", value) });
|
||||
}
|
||||
|
||||
private static EveSurfaceComponent Button(string id, string label, string command)
|
||||
{
|
||||
return Node(id, "control.button", new[] { ("label", label), ("command", command) });
|
||||
}
|
||||
|
||||
private static EveSurfaceComponent ButtonRow(
|
||||
string id,
|
||||
params EveSurfaceComponent[] children)
|
||||
{
|
||||
return Node(id, "row", Array.Empty<(string Key, string Value)>(), children);
|
||||
}
|
||||
|
||||
private static EveSurfaceComponent Node(
|
||||
string id,
|
||||
string kind,
|
||||
IEnumerable<(string Key, string Value)> props,
|
||||
params EveSurfaceComponent[] children)
|
||||
{
|
||||
return new EveSurfaceComponent(
|
||||
id,
|
||||
kind,
|
||||
props.ToDictionary(prop => prop.Key, prop => prop.Value, StringComparer.Ordinal),
|
||||
children ?? Array.Empty<EveSurfaceComponent>());
|
||||
}
|
||||
|
||||
// void Start()
|
||||
// {
|
||||
// ShowTab(MenuTab.Inventory);
|
||||
|
|
@ -76,4 +281,4 @@ public enum MenuTab
|
|||
Trade,
|
||||
Galaxy,
|
||||
Local
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -117,7 +117,9 @@ legacy catalog cache, and legacy UI paths should be migration-only or deleted.
|
|||
old `PropertiesPanel` button shell, even though typed rebinding controls and
|
||||
typed audio controls are still future work. Sector-map zone inspection now
|
||||
lowers through a local Eve/UI Toolkit surface as well instead of rebuilding
|
||||
`PropertiesPanel` rows on each zone click.
|
||||
`PropertiesPanel` rows on each zone click. The runtime in-game menu tab strip
|
||||
now lowers through a local Eve/UI Toolkit surface instead of wiring old
|
||||
`MenuTabButton` clicks.
|
||||
- The combat schematic HUD uses typed runtime catalog weapon facets for its
|
||||
static weapon icon strip; missing typed weapon facets no longer fall back to
|
||||
legacy `WeaponItemData`. Schematic weapon-row selection now uses typed
|
||||
|
|
@ -1552,6 +1554,9 @@ First Aetheria surfaces to publish:
|
|||
Toolkit surface. `SectorRenderer` still owns reveal/camera behavior, but
|
||||
zone inspection no longer rebuilds `PropertiesPanel` rows when the player
|
||||
clicks a zone.
|
||||
- Done: replace the runtime in-game menu tab strip with an Eve-owned UI
|
||||
Toolkit surface. `MenuPanel` still owns tab-content activation, but old
|
||||
`MenuTabButton` click wiring no longer owns tab navigation.
|
||||
- Done: move the shared `org.gamecult.eve.surface` and
|
||||
`org.gamecult.eve.unity-uitoolkit` packages into the Eve repo and retarget
|
||||
Aetheria to import them from there instead of carrying local staged
|
||||
|
|
@ -1913,6 +1918,9 @@ First Aetheria surfaces to publish:
|
|||
- Sector-map zone inspection now lowers through a shared UI Toolkit
|
||||
`UIDocument` host and a local Eve surface document instead of rebuilding
|
||||
`PropertiesPanel.AddProperty(...)` rows on each zone click.
|
||||
- Runtime in-game menu tab navigation now lowers through a shared UI Toolkit
|
||||
`UIDocument` host and a local Eve surface document instead of wiring
|
||||
`MenuTabButton` click handlers.
|
||||
- Keyboard display layout parsing is no longer JSON-backed:
|
||||
`InputDisplayLayout` builds its static ANSI-104 display projection from typed
|
||||
`InputLayout` rows/columns. The dead commented Ink `ToJson` write path and
|
||||
|
|
|
|||
Loading…
Reference in a new issue