implement main screen
This commit is contained in:
@@ -0,0 +1,22 @@
|
||||
namespace KernelPanic.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Contains cosmetic terminal boot-log copy for the main menu shell.
|
||||
/// </summary>
|
||||
public static class BootLogCopy
|
||||
{
|
||||
public static readonly string[] Lines =
|
||||
{
|
||||
"[ 0.000000] kernel-panic: booting userland shell",
|
||||
"[ 0.071004] cpu: isolating run scheduler",
|
||||
"[ 0.184331] entropy: wallet device mounted readonly",
|
||||
"[ 0.264700] tty1: spawning command menu",
|
||||
"[ 0.391226] units: probing installed distros",
|
||||
"[ 0.447801] collection: no render pass requested",
|
||||
"[ 0.521332] gacha: token api unavailable",
|
||||
"[ 0.684012] events: banner source disconnected",
|
||||
"[ 0.812445] ui: reduced motion preference loaded",
|
||||
"[ 1.000000] shell: ready"
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e05527a70e234c16af2f9089012721b8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,108 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using KernelPanic.Data;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace KernelPanic.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Renders the main menu's neofetch-style featured unit panel.
|
||||
/// </summary>
|
||||
[Serializable]
|
||||
public sealed class FeaturedUnitPanel
|
||||
{
|
||||
private const string EmptyAccent = "5cff91";
|
||||
private const string EmptyAscii = " _\n | |\n ___| |__\n / __| '_ \\\n \\__ \\ | | |\n |___/_| |_|";
|
||||
|
||||
[SerializeField] private List<DistroDefinition> featuredUnits = new();
|
||||
|
||||
private VisualElement panel;
|
||||
private Label titleLabel;
|
||||
private Label asciiLabel;
|
||||
private Label unitNameLabel;
|
||||
private Label languagesLabel;
|
||||
private Label passiveLabel;
|
||||
private Label bestWaveLabel;
|
||||
private Label emptyTitleLabel;
|
||||
private Label emptyHintLabel;
|
||||
private VisualElement populatedState;
|
||||
private VisualElement emptyState;
|
||||
private int selectedIndex;
|
||||
|
||||
public void Bind(VisualElement root)
|
||||
{
|
||||
panel = root.Q<VisualElement>("FeaturedUnitPanel");
|
||||
titleLabel = root.Q<Label>("FeaturedUnitTitle");
|
||||
asciiLabel = root.Q<Label>("FeaturedUnitAscii");
|
||||
unitNameLabel = root.Q<Label>("FeaturedUnitName");
|
||||
languagesLabel = root.Q<Label>("FeaturedUnitLanguages");
|
||||
passiveLabel = root.Q<Label>("FeaturedUnitPassive");
|
||||
bestWaveLabel = root.Q<Label>("FeaturedUnitBestWave");
|
||||
emptyTitleLabel = root.Q<Label>("FeaturedUnitEmptyTitle");
|
||||
emptyHintLabel = root.Q<Label>("FeaturedUnitEmptyHint");
|
||||
populatedState = root.Q<VisualElement>("FeaturedUnitPopulatedState");
|
||||
emptyState = root.Q<VisualElement>("FeaturedUnitEmptyState");
|
||||
}
|
||||
|
||||
public void Refresh()
|
||||
{
|
||||
if (featuredUnits == null || featuredUnits.Count == 0)
|
||||
{
|
||||
ShowEmptyState();
|
||||
return;
|
||||
}
|
||||
|
||||
selectedIndex = Mathf.Clamp(selectedIndex, 0, featuredUnits.Count - 1);
|
||||
ShowUnit(featuredUnits[selectedIndex]);
|
||||
}
|
||||
|
||||
public void SelectNext()
|
||||
{
|
||||
if (featuredUnits == null || featuredUnits.Count < 2)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
selectedIndex = (selectedIndex + 1) % featuredUnits.Count;
|
||||
Refresh();
|
||||
}
|
||||
|
||||
private void ShowEmptyState()
|
||||
{
|
||||
populatedState.AddToClassList("hidden");
|
||||
emptyState.RemoveFromClassList("hidden");
|
||||
|
||||
titleLabel.text = "neofetch";
|
||||
emptyTitleLabel.text = "no units installed";
|
||||
emptyHintLabel.text = "run: curl gacha.sh | sh";
|
||||
SetAccent(EmptyAccent);
|
||||
}
|
||||
|
||||
private void ShowUnit(DistroDefinition unit)
|
||||
{
|
||||
populatedState.RemoveFromClassList("hidden");
|
||||
emptyState.AddToClassList("hidden");
|
||||
|
||||
string displayName = string.IsNullOrWhiteSpace(unit.DisplayName) ? unit.name : unit.DisplayName;
|
||||
titleLabel.text = displayName;
|
||||
asciiLabel.text = EmptyAscii; // TODO: Replace with unit-specific ASCII copy when unit presentation data exists.
|
||||
unitNameLabel.text = displayName;
|
||||
languagesLabel.text = $"{unit.PrimaryLanguage} / {unit.SecondaryLanguage}";
|
||||
passiveLabel.text = string.IsNullOrWhiteSpace(unit.PassiveName) ? "--" : unit.PassiveName;
|
||||
bestWaveLabel.text = "--"; // TODO: Bind best-wave stats from SaveService when stats exist.
|
||||
SetAccent(ColorUtility.ToHtmlStringRGB(unit.AccentColor));
|
||||
}
|
||||
|
||||
private void SetAccent(string htmlColor)
|
||||
{
|
||||
string color = $"#{htmlColor}";
|
||||
Color parsedColor = ColorUtility.TryParseHtmlString(color, out Color parsed) ? parsed : Color.green;
|
||||
panel.style.borderTopColor = new StyleColor(parsedColor);
|
||||
panel.style.borderRightColor = new StyleColor(parsedColor);
|
||||
panel.style.borderBottomColor = new StyleColor(parsedColor);
|
||||
panel.style.borderLeftColor = new StyleColor(parsedColor);
|
||||
titleLabel.style.color = new StyleColor(parsedColor);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c7f7ef4e16694ed9bd746278b0ddc4d8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,454 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using KernelPanic.Core;
|
||||
using KernelPanic.Meta;
|
||||
using UnityEngine;
|
||||
using UnityEngine.TextCore.Text;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
#if UNITY_EDITOR
|
||||
using UnityEditor;
|
||||
#endif
|
||||
|
||||
namespace KernelPanic.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Binds the main menu terminal UI document and routes command activation between panels.
|
||||
/// </summary>
|
||||
[RequireComponent(typeof(UIDocument))]
|
||||
public sealed class MainMenuController : MonoBehaviour
|
||||
{
|
||||
private const string HiddenClassName = "hidden";
|
||||
private const string SelectedClassName = "selected";
|
||||
private const string CursorOnClassName = "cursor-on";
|
||||
private const float BootIntroSeconds = 1.5f;
|
||||
private static bool bootIntroPlayed;
|
||||
|
||||
[SerializeField] private FontAsset monospaceFont; // TODO: Assign a real monospace FontAsset when typography assets exist.
|
||||
[SerializeField] private FeaturedUnitPanel featuredUnitPanel = new();
|
||||
|
||||
private readonly List<CommandMenuEntry> commandEntries = new();
|
||||
private UIDocument document;
|
||||
private VisualElement root;
|
||||
private VisualElement shellRoot;
|
||||
private VisualElement bootIntroPanel;
|
||||
private VisualElement mainMenuPanel;
|
||||
private VisualElement collectionPanel;
|
||||
private VisualElement gachaPanel;
|
||||
private VisualElement settingsPanel;
|
||||
private VisualElement eventBanner;
|
||||
private VisualElement backgroundLogLayer;
|
||||
private Label appIdLabel;
|
||||
private Label entropyLabel;
|
||||
private Label pullTokensLabel;
|
||||
private Label titleCursorLabel;
|
||||
private Label promptCursorLabel;
|
||||
private Label bootIntroLogLabel;
|
||||
private Label backgroundLogLabel;
|
||||
private Button collectionBackButton;
|
||||
private Button gachaBackButton;
|
||||
private Button settingsBackButton;
|
||||
private EntropyWallet wallet;
|
||||
private GachaService gachaService;
|
||||
private IEventBannerSource eventBannerSource;
|
||||
private int selectedCommandIndex;
|
||||
private float backgroundScrollOffset;
|
||||
private float bootIntroElapsed;
|
||||
private int bootIntroCharacterCount;
|
||||
private bool suppressNextClick;
|
||||
private string bootIntroCopy;
|
||||
private IVisualElementScheduledItem blinkSchedule;
|
||||
private IVisualElementScheduledItem backgroundSchedule;
|
||||
private IVisualElementScheduledItem bootIntroSchedule;
|
||||
|
||||
public void Initialize(EntropyWallet initializedWallet)
|
||||
{
|
||||
wallet = initializedWallet ?? new EntropyWallet();
|
||||
RefreshCurrencyReadouts();
|
||||
}
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
document = GetComponent<UIDocument>();
|
||||
gachaService = new GachaService();
|
||||
Initialize(new EntropyWallet()); // TODO: Replace with persistent wallet service composition.
|
||||
BindElements();
|
||||
BindCommandEntries();
|
||||
RegisterCommandEntryCallbacks();
|
||||
featuredUnitPanel.Bind(root);
|
||||
ApplyOptionalFont();
|
||||
}
|
||||
|
||||
private void OnEnable()
|
||||
{
|
||||
RegisterCallbacks();
|
||||
root.Focus();
|
||||
shellRoot.EnableInClassList("reduced-motion", UIPreferences.ReducedMotion);
|
||||
RefreshStaticText();
|
||||
RefreshCurrencyReadouts();
|
||||
RefreshEventBanner();
|
||||
featuredUnitPanel.Refresh();
|
||||
SelectCommand(0);
|
||||
ShowMainMenu();
|
||||
StartAmbientSchedules();
|
||||
PlayBootIntroIfNeeded();
|
||||
}
|
||||
|
||||
private void OnDisable()
|
||||
{
|
||||
UnregisterCallbacks();
|
||||
blinkSchedule?.Pause();
|
||||
backgroundSchedule?.Pause();
|
||||
bootIntroSchedule?.Pause();
|
||||
}
|
||||
|
||||
private void BindElements()
|
||||
{
|
||||
root = document.rootVisualElement;
|
||||
shellRoot = root.Q<VisualElement>("ShellRoot");
|
||||
bootIntroPanel = root.Q<VisualElement>("BootIntroPanel");
|
||||
mainMenuPanel = root.Q<VisualElement>("MainMenuPanel");
|
||||
collectionPanel = root.Q<VisualElement>("CollectionPanel");
|
||||
gachaPanel = root.Q<VisualElement>("GachaPanel");
|
||||
settingsPanel = root.Q<VisualElement>("SettingsPanel");
|
||||
eventBanner = root.Q<VisualElement>("EventBanner");
|
||||
backgroundLogLayer = root.Q<VisualElement>("BackgroundLogLayer");
|
||||
|
||||
appIdLabel = root.Q<Label>("AppIdLabel");
|
||||
entropyLabel = root.Q<Label>("EntropyLabel");
|
||||
pullTokensLabel = root.Q<Label>("PullTokensLabel");
|
||||
titleCursorLabel = root.Q<Label>("TitleCursorLabel");
|
||||
promptCursorLabel = root.Q<Label>("PromptCursorLabel");
|
||||
bootIntroLogLabel = root.Q<Label>("BootIntroLogLabel");
|
||||
backgroundLogLabel = root.Q<Label>("BackgroundLogLabel");
|
||||
|
||||
collectionBackButton = root.Q<Button>("CollectionBackButton");
|
||||
gachaBackButton = root.Q<Button>("GachaBackButton");
|
||||
settingsBackButton = root.Q<Button>("SettingsBackButton");
|
||||
}
|
||||
|
||||
private void BindCommandEntries()
|
||||
{
|
||||
commandEntries.Clear();
|
||||
commandEntries.Add(new CommandMenuEntry(root.Q<VisualElement>("CommandStartRun"), HandleStartRunClicked));
|
||||
commandEntries.Add(new CommandMenuEntry(root.Q<VisualElement>("CommandCollection"), ShowCollection));
|
||||
commandEntries.Add(new CommandMenuEntry(root.Q<VisualElement>("CommandGacha"), ShowGacha));
|
||||
commandEntries.Add(new CommandMenuEntry(root.Q<VisualElement>("CommandSettings"), ShowSettings));
|
||||
commandEntries.Add(new CommandMenuEntry(root.Q<VisualElement>("CommandQuit"), HandleQuitClicked));
|
||||
}
|
||||
|
||||
private void ApplyOptionalFont()
|
||||
{
|
||||
if (monospaceFont == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
root.style.unityFontDefinition = new StyleFontDefinition(monospaceFont);
|
||||
}
|
||||
|
||||
private void RegisterCallbacks()
|
||||
{
|
||||
root.RegisterCallback<KeyDownEvent>(HandleKeyDown);
|
||||
root.RegisterCallback<PointerDownEvent>(HandlePointerDown);
|
||||
collectionBackButton.clicked += ShowMainMenu;
|
||||
gachaBackButton.clicked += ShowMainMenu;
|
||||
settingsBackButton.clicked += ShowMainMenu;
|
||||
}
|
||||
|
||||
private void UnregisterCallbacks()
|
||||
{
|
||||
root.UnregisterCallback<KeyDownEvent>(HandleKeyDown);
|
||||
root.UnregisterCallback<PointerDownEvent>(HandlePointerDown);
|
||||
collectionBackButton.clicked -= ShowMainMenu;
|
||||
gachaBackButton.clicked -= ShowMainMenu;
|
||||
settingsBackButton.clicked -= ShowMainMenu;
|
||||
}
|
||||
|
||||
private void RefreshStaticText()
|
||||
{
|
||||
appIdLabel.text = $"kernel-panic v{Application.version} - tty1";
|
||||
backgroundLogLabel.text = BuildBackgroundLog();
|
||||
bootIntroCopy = string.Join("\n", BootLogCopy.Lines);
|
||||
}
|
||||
|
||||
private void RegisterCommandEntryCallbacks()
|
||||
{
|
||||
for (int i = 0; i < commandEntries.Count; i++)
|
||||
{
|
||||
int index = i;
|
||||
commandEntries[i].Row.RegisterCallback<PointerEnterEvent>(_ => SelectCommand(index));
|
||||
commandEntries[i].Row.RegisterCallback<ClickEvent>(_ => HandleCommandClicked(index));
|
||||
}
|
||||
}
|
||||
|
||||
private void RefreshCurrencyReadouts()
|
||||
{
|
||||
if (entropyLabel == null || pullTokensLabel == null || gachaService == null || wallet == null)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
entropyLabel.text = $"entropy={wallet.Balance}";
|
||||
pullTokensLabel.text = $"pulls={gachaService.PullTokens}";
|
||||
}
|
||||
|
||||
private void RefreshEventBanner()
|
||||
{
|
||||
EventBannerContent banner = eventBannerSource?.GetBanner();
|
||||
if (banner == null || string.IsNullOrWhiteSpace(banner.Text))
|
||||
{
|
||||
eventBanner.AddToClassList(HiddenClassName);
|
||||
return;
|
||||
}
|
||||
|
||||
eventBanner.RemoveFromClassList(HiddenClassName);
|
||||
root.Q<Label>("EventBannerLabel").text = banner.RemainingTime.HasValue
|
||||
? $"{banner.Text} {banner.RemainingTime.Value:g}"
|
||||
: banner.Text;
|
||||
}
|
||||
|
||||
private void StartAmbientSchedules()
|
||||
{
|
||||
if (UIPreferences.ReducedMotion)
|
||||
{
|
||||
titleCursorLabel.AddToClassList(CursorOnClassName);
|
||||
promptCursorLabel.AddToClassList(CursorOnClassName);
|
||||
return;
|
||||
}
|
||||
|
||||
bool cursorVisible = true;
|
||||
blinkSchedule = root.schedule.Execute(() =>
|
||||
{
|
||||
cursorVisible = !cursorVisible;
|
||||
titleCursorLabel.EnableInClassList(CursorOnClassName, cursorVisible);
|
||||
promptCursorLabel.EnableInClassList(CursorOnClassName, cursorVisible);
|
||||
}).Every(480);
|
||||
|
||||
backgroundSchedule = root.schedule.Execute(() =>
|
||||
{
|
||||
backgroundScrollOffset = (backgroundScrollOffset + 0.35f) % 80f;
|
||||
backgroundLogLayer.style.translate = new Translate(0, -backgroundScrollOffset, 0);
|
||||
}).Every(33);
|
||||
}
|
||||
|
||||
private void PlayBootIntroIfNeeded()
|
||||
{
|
||||
if (bootIntroPlayed || UIPreferences.ReducedMotion)
|
||||
{
|
||||
CompleteBootIntro();
|
||||
return;
|
||||
}
|
||||
|
||||
bootIntroPlayed = true;
|
||||
bootIntroElapsed = 0f;
|
||||
bootIntroCharacterCount = 0;
|
||||
bootIntroLogLabel.text = string.Empty;
|
||||
bootIntroPanel.RemoveFromClassList(HiddenClassName);
|
||||
shellRoot.AddToClassList("boot-hidden");
|
||||
|
||||
bootIntroSchedule = root.schedule.Execute(UpdateBootIntro).Every(16);
|
||||
}
|
||||
|
||||
private void UpdateBootIntro()
|
||||
{
|
||||
bootIntroElapsed += 0.016f;
|
||||
int targetCount = Mathf.Clamp(Mathf.CeilToInt(bootIntroCopy.Length * (bootIntroElapsed / BootIntroSeconds)), 0, bootIntroCopy.Length);
|
||||
if (targetCount != bootIntroCharacterCount)
|
||||
{
|
||||
bootIntroCharacterCount = targetCount;
|
||||
bootIntroLogLabel.text = bootIntroCopy.Substring(0, bootIntroCharacterCount);
|
||||
}
|
||||
|
||||
if (bootIntroElapsed >= BootIntroSeconds)
|
||||
{
|
||||
CompleteBootIntro();
|
||||
}
|
||||
}
|
||||
|
||||
private void CompleteBootIntro()
|
||||
{
|
||||
bootIntroSchedule?.Pause();
|
||||
bootIntroPanel.AddToClassList(HiddenClassName);
|
||||
shellRoot.RemoveFromClassList("boot-hidden");
|
||||
shellRoot.AddToClassList("boot-visible");
|
||||
root.Focus();
|
||||
}
|
||||
|
||||
private bool SkipBootIntro()
|
||||
{
|
||||
if (bootIntroPanel.ClassListContains(HiddenClassName))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
CompleteBootIntro();
|
||||
return true;
|
||||
}
|
||||
|
||||
private void HandleKeyDown(KeyDownEvent evt)
|
||||
{
|
||||
if (SkipBootIntro())
|
||||
{
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.UpArrow)
|
||||
{
|
||||
SelectCommand(selectedCommandIndex - 1);
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.DownArrow)
|
||||
{
|
||||
SelectCommand(selectedCommandIndex + 1);
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.Return || evt.keyCode == KeyCode.KeypadEnter || evt.keyCode == KeyCode.Space)
|
||||
{
|
||||
ActivateCommand(selectedCommandIndex);
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
if (evt.keyCode == KeyCode.Tab)
|
||||
{
|
||||
featuredUnitPanel.SelectNext();
|
||||
evt.StopPropagation();
|
||||
return;
|
||||
}
|
||||
|
||||
int digitIndex = GetDigitCommandIndex(evt.keyCode);
|
||||
if (digitIndex >= 0)
|
||||
{
|
||||
SelectCommand(digitIndex);
|
||||
ActivateCommand(digitIndex);
|
||||
evt.StopPropagation();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandlePointerDown(PointerDownEvent evt)
|
||||
{
|
||||
root.Focus();
|
||||
suppressNextClick = SkipBootIntro();
|
||||
}
|
||||
|
||||
private static int GetDigitCommandIndex(KeyCode keyCode)
|
||||
{
|
||||
return keyCode switch
|
||||
{
|
||||
KeyCode.Alpha1 or KeyCode.Keypad1 => 0,
|
||||
KeyCode.Alpha2 or KeyCode.Keypad2 => 1,
|
||||
KeyCode.Alpha3 or KeyCode.Keypad3 => 2,
|
||||
KeyCode.Alpha4 or KeyCode.Keypad4 => 3,
|
||||
KeyCode.Alpha5 or KeyCode.Keypad5 => 4,
|
||||
_ => -1
|
||||
};
|
||||
}
|
||||
|
||||
private void SelectCommand(int index)
|
||||
{
|
||||
selectedCommandIndex = (index + commandEntries.Count) % commandEntries.Count;
|
||||
for (int i = 0; i < commandEntries.Count; i++)
|
||||
{
|
||||
commandEntries[i].SetSelected(i == selectedCommandIndex);
|
||||
}
|
||||
}
|
||||
|
||||
private void ActivateCommand(int index)
|
||||
{
|
||||
commandEntries[index].Activate();
|
||||
}
|
||||
|
||||
private void HandleCommandClicked(int index)
|
||||
{
|
||||
if (suppressNextClick)
|
||||
{
|
||||
suppressNextClick = false;
|
||||
return;
|
||||
}
|
||||
|
||||
ActivateCommand(index);
|
||||
}
|
||||
|
||||
private void HandleStartRunClicked()
|
||||
{
|
||||
SceneLoader.LoadGame();
|
||||
}
|
||||
|
||||
private void HandleQuitClicked()
|
||||
{
|
||||
#if UNITY_EDITOR
|
||||
EditorApplication.isPlaying = false;
|
||||
#else
|
||||
Application.Quit();
|
||||
#endif
|
||||
}
|
||||
|
||||
private void ShowMainMenu()
|
||||
{
|
||||
ShowPanel(mainMenuPanel);
|
||||
root.Focus();
|
||||
}
|
||||
|
||||
private void ShowCollection()
|
||||
{
|
||||
ShowPanel(collectionPanel);
|
||||
}
|
||||
|
||||
private void ShowGacha()
|
||||
{
|
||||
ShowPanel(gachaPanel);
|
||||
}
|
||||
|
||||
private void ShowSettings()
|
||||
{
|
||||
ShowPanel(settingsPanel);
|
||||
}
|
||||
|
||||
// TODO: Replace this direct toggle with a screen-stack/router when menu flows need history or transitions.
|
||||
private void ShowPanel(VisualElement activePanel)
|
||||
{
|
||||
mainMenuPanel.EnableInClassList(HiddenClassName, mainMenuPanel != activePanel);
|
||||
collectionPanel.EnableInClassList(HiddenClassName, collectionPanel != activePanel);
|
||||
gachaPanel.EnableInClassList(HiddenClassName, gachaPanel != activePanel);
|
||||
settingsPanel.EnableInClassList(HiddenClassName, settingsPanel != activePanel);
|
||||
}
|
||||
|
||||
private static string BuildBackgroundLog()
|
||||
{
|
||||
string block = string.Join("\n", BootLogCopy.Lines);
|
||||
return $"{block}\n{block}\n{block}\n{block}";
|
||||
}
|
||||
|
||||
private sealed class CommandMenuEntry
|
||||
{
|
||||
private readonly Label cursor;
|
||||
private readonly Action action;
|
||||
|
||||
public CommandMenuEntry(VisualElement row, Action action)
|
||||
{
|
||||
Row = row;
|
||||
this.action = action;
|
||||
cursor = row.Q<Label>(className: "command-cursor");
|
||||
}
|
||||
|
||||
public VisualElement Row { get; }
|
||||
|
||||
public void SetSelected(bool selected)
|
||||
{
|
||||
Row.EnableInClassList(SelectedClassName, selected);
|
||||
cursor.visible = selected;
|
||||
}
|
||||
|
||||
public void Activate()
|
||||
{
|
||||
action.Invoke();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 27a7f29e93cb4c55beac52f1e32a1bf5
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,10 @@
|
||||
namespace KernelPanic.UI
|
||||
{
|
||||
/// <summary>
|
||||
/// Stores UI-level accessibility preferences for runtime presentation.
|
||||
/// </summary>
|
||||
public static class UIPreferences
|
||||
{
|
||||
public static bool ReducedMotion { get; set; } // TODO: Persist with settings once settings storage exists.
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a1efef5d7a1b485493c2f30d64644898
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Reference in New Issue
Block a user