mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
This commit is contained in:
parent
5a2fddab89
commit
9aa1121410
28 changed files with 616 additions and 719 deletions
2
Luna
2
Luna
|
|
@ -1 +1 @@
|
||||||
Subproject commit 2e984d9c21370c778d172ab955def18c0dbe8c7d
|
Subproject commit cb294f476476f7a3d8b56a0072dbd300b3d54c4f
|
||||||
|
|
@ -10,7 +10,7 @@ public sealed class SelectTab(Logger log) : EventBase<SelectTab.Arguments, Selec
|
||||||
public enum Priority
|
public enum Priority
|
||||||
{
|
{
|
||||||
/// <seealso cref="UI.Tabs.ConfigTabBar.OnSelectTab"/>
|
/// <seealso cref="UI.Tabs.ConfigTabBar.OnSelectTab"/>
|
||||||
ConfigTabBar = 0,
|
MainTabBar = 0,
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary> The arguments for a SelectTab event. </summary>
|
/// <summary> The arguments for a SelectTab event. </summary>
|
||||||
|
|
|
||||||
|
|
@ -10,6 +10,7 @@ using Penumbra.UI;
|
||||||
using Penumbra.UI.ResourceWatcher;
|
using Penumbra.UI.ResourceWatcher;
|
||||||
using Penumbra.UI.Tabs;
|
using Penumbra.UI.Tabs;
|
||||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||||
|
using TabType = Penumbra.Api.Enums.TabType;
|
||||||
|
|
||||||
namespace Penumbra;
|
namespace Penumbra;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -134,7 +134,7 @@ public class Penumbra : IDalamudPlugin
|
||||||
AsyncTask.Run(() =>
|
AsyncTask.Run(() =>
|
||||||
{
|
{
|
||||||
var system = _services.GetService<PenumbraWindowSystem>();
|
var system = _services.GetService<PenumbraWindowSystem>();
|
||||||
system.Window.Setup(this, _services.GetService<ConfigTabBar>());
|
system.Window.Setup(this, _services.GetService<MainTabBar>());
|
||||||
_services.GetService<CommandHandler>();
|
_services.GetService<CommandHandler>();
|
||||||
if (!_disposed)
|
if (!_disposed)
|
||||||
{
|
{
|
||||||
|
|
@ -199,8 +199,12 @@ public class Penumbra : IDalamudPlugin
|
||||||
{
|
{
|
||||||
ReadOnlySpan<string> relevantPlugins =
|
ReadOnlySpan<string> relevantPlugins =
|
||||||
[
|
[
|
||||||
"Glamourer", "MareSynchronos", "CustomizePlus", "SimpleHeels", "VfxEditor", "heliosphere-plugin", "Ktisis", "Brio", "DynamicBridge",
|
"Glamourer", "CustomizePlus", "SimpleHeels",
|
||||||
"IllusioVitae", "Aetherment", "LoporritSync", "GagSpeak", "ProjectGagSpeak", "RoleplayingVoiceDalamud", "AQuestReborn",
|
"Ktisis", "Brio",
|
||||||
|
"heliosphere-plugin", "VfxEditor", "IllusioVitae", "Aetherment",
|
||||||
|
"DynamicBridge", "GagSpeak", "ProjectGagSpeak", "RoleplayingVoiceDalamud", "AQuestReborn",
|
||||||
|
"MareSynchronos", "LoporritSync", "KittenSync", "Snowcloak", "LightlessSync", "Sphene", "XivSync", "MareSempiterne" /* PlayerSync */, "AnatoliIliou", "LaciSynchroni"
|
||||||
|
|
||||||
];
|
];
|
||||||
var plugins = _services.GetService<IDalamudPluginInterface>().InstalledPlugins
|
var plugins = _services.GetService<IDalamudPluginInterface>().InstalledPlugins
|
||||||
.GroupBy(p => p.InternalName)
|
.GroupBy(p => p.InternalName)
|
||||||
|
|
|
||||||
|
|
@ -14,6 +14,7 @@ using Penumbra.UI;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
using Penumbra.UI.ResourceWatcher;
|
using Penumbra.UI.ResourceWatcher;
|
||||||
using Penumbra.UI.Tabs;
|
using Penumbra.UI.Tabs;
|
||||||
|
using TabType = Penumbra.Api.Enums.TabType;
|
||||||
|
|
||||||
namespace Penumbra.Services;
|
namespace Penumbra.Services;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -4,7 +4,6 @@ using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Text;
|
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
|
|
@ -25,6 +24,7 @@ using Penumbra.Mods.SubMods;
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
using Penumbra.UI.ModsTab;
|
using Penumbra.UI.ModsTab;
|
||||||
|
using ITab = OtterGui.Widgets.ITab;
|
||||||
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
using MouseWheelType = OtterGui.Widgets.MouseWheelType;
|
||||||
|
|
||||||
namespace Penumbra.UI.AdvancedWindow;
|
namespace Penumbra.UI.AdvancedWindow;
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,10 @@
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using Penumbra.Api.Enums;
|
|
||||||
using Penumbra.Services;
|
using Penumbra.Services;
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
using Penumbra.UI.Tabs;
|
using Penumbra.UI.Tabs;
|
||||||
|
using TabType = Penumbra.Api.Enums.TabType;
|
||||||
|
|
||||||
namespace Penumbra.UI;
|
namespace Penumbra.UI;
|
||||||
|
|
||||||
|
|
@ -14,7 +14,7 @@ public sealed class ConfigWindow : Window
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly ValidityChecker _validityChecker;
|
private readonly ValidityChecker _validityChecker;
|
||||||
private Penumbra? _penumbra;
|
private Penumbra? _penumbra;
|
||||||
private ConfigTabBar _configTabs = null!;
|
private MainTabBar _configTabs = null!;
|
||||||
private string? _lastException;
|
private string? _lastException;
|
||||||
|
|
||||||
public ConfigWindow(IDalamudPluginInterface pi, Configuration config, ValidityChecker checker,
|
public ConfigWindow(IDalamudPluginInterface pi, Configuration config, ValidityChecker checker,
|
||||||
|
|
@ -32,15 +32,15 @@ public sealed class ConfigWindow : Window
|
||||||
|
|
||||||
public void OpenSettings()
|
public void OpenSettings()
|
||||||
{
|
{
|
||||||
_configTabs.SelectTab = TabType.Settings;
|
_configTabs.NextTab = TabType.Settings;
|
||||||
IsOpen = true;
|
IsOpen = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Setup(Penumbra penumbra, ConfigTabBar configTabs)
|
public void Setup(Penumbra penumbra, MainTabBar configTabs)
|
||||||
{
|
{
|
||||||
_penumbra = penumbra;
|
_penumbra = penumbra;
|
||||||
_configTabs = configTabs;
|
_configTabs = configTabs;
|
||||||
_configTabs.SelectTab = _config.Ephemeral.SelectedTab;
|
_configTabs.NextTab = _config.Ephemeral.SelectedTab;
|
||||||
}
|
}
|
||||||
|
|
||||||
public override bool DrawConditions()
|
public override bool DrawConditions()
|
||||||
|
|
@ -98,12 +98,7 @@ public sealed class ConfigWindow : Window
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
var type = _configTabs.Draw();
|
_configTabs.Draw();
|
||||||
if (type != _config.Ephemeral.SelectedTab)
|
|
||||||
{
|
|
||||||
_config.Ephemeral.SelectedTab = type;
|
|
||||||
_config.Ephemeral.Save();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
_lastException = null;
|
_lastException = null;
|
||||||
|
|
|
||||||
|
|
@ -15,18 +15,18 @@ public class IncognitoService(TutorialService tutorial, Configuration config) :
|
||||||
var color = ColorId.FolderExpanded.Value();
|
var color = ColorId.FolderExpanded.Value();
|
||||||
using (ImStyleBorder.Frame.Push(color))
|
using (ImStyleBorder.Frame.Push(color))
|
||||||
{
|
{
|
||||||
var tt = IncognitoMode ? "Toggle incognito mode off."u8 : "Toggle incognito mode on."u8;
|
var tt = IncognitoMode ? "Toggle incognito mode off."u8 : "Toggle incognito mode on."u8;
|
||||||
var icon = IncognitoMode ? LunaStyle.IncognitoOn : LunaStyle.IncognitoOff;
|
var icon = IncognitoMode ? LunaStyle.IncognitoOn : LunaStyle.IncognitoOff;
|
||||||
if (ImEx.Icon.Button(icon, tt, size: new Vector2(width, Im.Style.FrameHeight), textColor: color) && hold)
|
if (ImEx.Icon.Button(icon, tt, size: new Vector2(width, Im.Style.FrameHeight), textColor: color) && hold)
|
||||||
{
|
{
|
||||||
config.Ephemeral.IncognitoMode = !IncognitoMode;
|
config.Ephemeral.IncognitoMode = !IncognitoMode;
|
||||||
config.Ephemeral.Save();
|
config.Ephemeral.Save();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!hold)
|
|
||||||
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"\nHold {config.IncognitoModifier} while clicking to toggle.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!hold)
|
||||||
|
Im.Tooltip.OnHover(HoveredFlags.AllowWhenDisabled, $"\nHold {config.IncognitoModifier} while clicking to toggle.");
|
||||||
|
|
||||||
tutorial.OpenTutorial(BasicTutorialSteps.Incognito);
|
tutorial.OpenTutorial(BasicTutorialSteps.Incognito);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,6 @@ using Luna;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Services;
|
using OtterGui.Services;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Penumbra.GameData.Data;
|
using Penumbra.GameData.Data;
|
||||||
using Penumbra.GameData.Enums;
|
using Penumbra.GameData.Enums;
|
||||||
using Penumbra.GameData.Structs;
|
using Penumbra.GameData.Structs;
|
||||||
|
|
@ -23,7 +22,7 @@ public class ModPanelChangedItemsTab(
|
||||||
ImGuiCacheService cacheService,
|
ImGuiCacheService cacheService,
|
||||||
Configuration config,
|
Configuration config,
|
||||||
ModDataEditor dataEditor)
|
ModDataEditor dataEditor)
|
||||||
: ITab, Luna.IUiService
|
: ITab<ModPanelTab>
|
||||||
{
|
{
|
||||||
private readonly ImGuiCacheService.CacheId _cacheId = cacheService.GetNewId();
|
private readonly ImGuiCacheService.CacheId _cacheId = cacheService.GetNewId();
|
||||||
|
|
||||||
|
|
@ -209,6 +208,9 @@ public class ModPanelChangedItemsTab(
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Changed Items"u8;
|
=> "Changed Items"u8;
|
||||||
|
|
||||||
|
public ModPanelTab Identifier
|
||||||
|
=> ModPanelTab.ChangedItems;
|
||||||
|
|
||||||
public bool IsVisible
|
public bool IsVisible
|
||||||
=> selector.Selected!.ChangedItems.Count > 0;
|
=> selector.Selected!.ChangedItems.Count > 0;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,6 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface.Utility;
|
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using OtterGui.Raii;
|
using Luna;
|
||||||
using OtterGui.Text;
|
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
|
|
@ -11,7 +8,7 @@ using Penumbra.UI.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.ModsTab;
|
namespace Penumbra.UI.ModsTab;
|
||||||
|
|
||||||
public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSelector selector) : ITab, Luna.IUiService
|
public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSelector selector) : ITab<ModPanelTab>
|
||||||
{
|
{
|
||||||
private enum ModState
|
private enum ModState
|
||||||
{
|
{
|
||||||
|
|
@ -24,19 +21,22 @@ public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSele
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Collections"u8;
|
=> "Collections"u8;
|
||||||
|
|
||||||
|
public ModPanelTab Identifier
|
||||||
|
=> ModPanelTab.Collections;
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
{
|
{
|
||||||
var (direct, inherited) = CountUsage(selector.Selected!);
|
var (direct, inherited) = CountUsage(selector.Selected!);
|
||||||
Im.Line.New();
|
Im.Line.New();
|
||||||
if (direct == 1)
|
switch (direct)
|
||||||
ImUtf8.Text("This Mod is directly configured in 1 collection."u8);
|
{
|
||||||
else if (direct == 0)
|
case 1: Im.Text("This Mod is directly configured in 1 collection."u8); break;
|
||||||
ImUtf8.Text("This mod is entirely unused."u8, Colors.RegexWarningBorder);
|
case 0: Im.Text("This mod is entirely unused."u8, Colors.RegexWarningBorder); break;
|
||||||
else
|
default: Im.Text($"This Mod is directly configured in {direct} collections."); break;
|
||||||
ImUtf8.Text($"This Mod is directly configured in {direct} collections.");
|
}
|
||||||
if (inherited > 0)
|
if (inherited > 0)
|
||||||
ImUtf8.Text($"It is also implicitly used in {inherited} {(inherited == 1 ? "collection" : "collections")} through inheritance.");
|
Im.Text($"It is also implicitly used in {inherited} {(inherited == 1 ? "collection" : "collections")} through inheritance.");
|
||||||
|
|
||||||
Im.Line.New();
|
Im.Line.New();
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
|
|
@ -45,7 +45,7 @@ public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSele
|
||||||
if (!table)
|
if (!table)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var size = ImUtf8.CalcTextSize(ToText(ModState.Unconfigured)).X + 20 * Im.Style.GlobalScale;
|
var size = Im.Font.CalculateSize(ToText(ModState.Unconfigured)).X + 20 * Im.Style.GlobalScale;
|
||||||
var collectionSize = 200 * Im.Style.GlobalScale;
|
var collectionSize = 200 * Im.Style.GlobalScale;
|
||||||
table.SetupColumn("Collection"u8, TableColumnFlags.WidthFixed, collectionSize);
|
table.SetupColumn("Collection"u8, TableColumnFlags.WidthFixed, collectionSize);
|
||||||
table.SetupColumn("State"u8, TableColumnFlags.WidthFixed, size);
|
table.SetupColumn("State"u8, TableColumnFlags.WidthFixed, size);
|
||||||
|
|
@ -54,21 +54,21 @@ public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSele
|
||||||
ImGui.TableHeadersRow();
|
ImGui.TableHeadersRow();
|
||||||
foreach (var (idx, (collection, parent, color, state)) in _cache.Index())
|
foreach (var (idx, (collection, parent, color, state)) in _cache.Index())
|
||||||
{
|
{
|
||||||
using var id = ImUtf8.PushId(idx);
|
using var id = Im.Id.Push(idx);
|
||||||
ImUtf8.DrawTableColumn(collection.Identity.Name);
|
table.DrawColumn(collection.Identity.Name);
|
||||||
|
|
||||||
ImGui.TableNextColumn();
|
table.NextColumn();
|
||||||
ImUtf8.Text(ToText(state), color);
|
Im.Text(ToText(state), color);
|
||||||
|
|
||||||
using (var context = ImUtf8.PopupContextItem("Context"u8))
|
using (var context = Im.Popup.BeginContextItem("Context"u8))
|
||||||
{
|
{
|
||||||
if (context)
|
if (context)
|
||||||
{
|
{
|
||||||
ImUtf8.Text(collection.Identity.Name);
|
Im.Text(collection.Identity.Name);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
using (ImRaii.Disabled(state is ModState.Enabled && parent == collection))
|
using (Im.Disabled(state is ModState.Enabled && parent == collection))
|
||||||
{
|
{
|
||||||
if (ImUtf8.MenuItem("Enable"u8))
|
if (Im.Menu.Item("Enable"u8))
|
||||||
{
|
{
|
||||||
if (parent != collection)
|
if (parent != collection)
|
||||||
manager.Editor.SetModInheritance(collection, selector.Selected!, false);
|
manager.Editor.SetModInheritance(collection, selector.Selected!, false);
|
||||||
|
|
@ -76,9 +76,9 @@ public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSele
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (ImRaii.Disabled(state is ModState.Disabled && parent == collection))
|
using (Im.Disabled(state is ModState.Disabled && parent == collection))
|
||||||
{
|
{
|
||||||
if (ImUtf8.MenuItem("Disable"u8))
|
if (Im.Menu.Item("Disable"u8))
|
||||||
{
|
{
|
||||||
if (parent != collection)
|
if (parent != collection)
|
||||||
manager.Editor.SetModInheritance(collection, selector.Selected!, false);
|
manager.Editor.SetModInheritance(collection, selector.Selected!, false);
|
||||||
|
|
@ -86,15 +86,15 @@ public class ModPanelCollectionsTab(CollectionManager manager, ModFileSystemSele
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
using (ImRaii.Disabled(parent != collection))
|
using (Im.Disabled(parent != collection))
|
||||||
{
|
{
|
||||||
if (ImUtf8.MenuItem("Inherit"u8))
|
if (Im.Menu.Item("Inherit"u8))
|
||||||
manager.Editor.SetModInheritance(collection, selector.Selected!, true);
|
manager.Editor.SetModInheritance(collection, selector.Selected!, true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ImUtf8.DrawTableColumn(parent == collection ? string.Empty : parent.Identity.Name);
|
table.DrawColumn(parent == collection ? StringU8.Empty : parent.Identity.Name);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -13,11 +13,14 @@ using Penumbra.UI.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.ModsTab;
|
namespace Penumbra.UI.ModsTab;
|
||||||
|
|
||||||
public class ModPanelConflictsTab(CollectionManager collectionManager, ModFileSystemSelector selector) : ITab, IUiService
|
public class ModPanelConflictsTab(CollectionManager collectionManager, ModFileSystemSelector selector) : ITab<ModPanelTab>
|
||||||
{
|
{
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Conflicts"u8;
|
=> "Conflicts"u8;
|
||||||
|
|
||||||
|
public ModPanelTab Identifier
|
||||||
|
=> ModPanelTab.Conflicts;
|
||||||
|
|
||||||
public bool IsVisible
|
public bool IsVisible
|
||||||
=> collectionManager.Active.Current.Conflicts(selector.Selected!).Any(c => !GetPriority(c).IsHidden);
|
=> collectionManager.Active.Current.Conflicts(selector.Selected!).Any(c => !GetPriority(c).IsHidden);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using OtterGui.Raii;
|
using Luna;
|
||||||
using OtterGui;
|
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
|
|
||||||
|
|
@ -12,23 +11,25 @@ public class ModPanelDescriptionTab(
|
||||||
TutorialService tutorial,
|
TutorialService tutorial,
|
||||||
ModManager modManager,
|
ModManager modManager,
|
||||||
PredefinedTagManager predefinedTagsConfig)
|
PredefinedTagManager predefinedTagsConfig)
|
||||||
: ITab, Luna.IUiService
|
: ITab<ModPanelTab>
|
||||||
{
|
{
|
||||||
private readonly TagButtons _localTags = new();
|
private readonly TagButtons _localTags = new();
|
||||||
private readonly TagButtons _modTags = new();
|
private readonly TagButtons _modTags = new();
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Description"u8;
|
=> "Description"u8;
|
||||||
|
|
||||||
|
public ModPanelTab Identifier
|
||||||
|
=> ModPanelTab.Description;
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
{
|
{
|
||||||
using var child = ImRaii.Child("##description");
|
using var child = Im.Child.Begin("##description"u8);
|
||||||
if (!child)
|
if (!child)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
ImGui.Dummy(ImEx.ScaledVector(2));
|
Im.ScaledDummy(2, 2);
|
||||||
|
Im.ScaledDummy(2, 2);
|
||||||
ImGui.Dummy(ImEx.ScaledVector(2));
|
|
||||||
var (predefinedTagsEnabled, predefinedTagButtonOffset) = predefinedTagsConfig.Enabled
|
var (predefinedTagsEnabled, predefinedTagButtonOffset) = predefinedTagsConfig.Enabled
|
||||||
? (true, Im.Style.FrameHeight + Im.Style.WindowPadding.X + (ImGui.GetScrollMaxY() > 0 ? Im.Style.ScrollbarSize : 0))
|
? (true, Im.Style.FrameHeight + Im.Style.WindowPadding.X + (ImGui.GetScrollMaxY() > 0 ? Im.Style.ScrollbarSize : 0))
|
||||||
: (false, 0);
|
: (false, 0);
|
||||||
|
|
@ -49,9 +50,9 @@ public class ModPanelDescriptionTab(
|
||||||
selector.Selected!.ModTags, out _, false,
|
selector.Selected!.ModTags, out _, false,
|
||||||
ImGui.CalcTextSize("Local ").X - ImGui.CalcTextSize("Mod ").X);
|
ImGui.CalcTextSize("Local ").X - ImGui.CalcTextSize("Mod ").X);
|
||||||
|
|
||||||
ImGui.Dummy(ImEx.ScaledVector(2));
|
Im.ScaledDummy(2, 2);
|
||||||
Im.Separator();
|
Im.Separator();
|
||||||
|
|
||||||
ImGuiUtil.TextWrapped(selector.Selected!.Description);
|
Im.TextWrapped(selector.Selected!.Description);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,370 +1,335 @@
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Components;
|
using Dalamud.Interface.ImGuiNotification;
|
||||||
using Dalamud.Interface.ImGuiNotification;
|
using ImSharp;
|
||||||
using Dalamud.Bindings.ImGui;
|
using Luna;
|
||||||
using ImSharp;
|
using OtterGui.Widgets;
|
||||||
using Luna;
|
using Penumbra.Mods;
|
||||||
using OtterGui;
|
using Penumbra.Mods.Editor;
|
||||||
using OtterGui.Raii;
|
using Penumbra.Mods.Manager;
|
||||||
using OtterGui.Widgets;
|
using Penumbra.Services;
|
||||||
using OtterGui.Text;
|
using Penumbra.UI.ModsTab.Groups;
|
||||||
using Penumbra.Mods;
|
|
||||||
using Penumbra.Mods.Editor;
|
namespace Penumbra.UI.ModsTab;
|
||||||
using Penumbra.Mods.Manager;
|
|
||||||
using Penumbra.Services;
|
public class ModPanelEditTab(
|
||||||
using Penumbra.Mods.Settings;
|
ModManager modManager,
|
||||||
using Penumbra.UI.ModsTab.Groups;
|
ModFileSystemSelector selector,
|
||||||
|
ModFileSystem fileSystem,
|
||||||
namespace Penumbra.UI.ModsTab;
|
Services.MessageService messager,
|
||||||
|
FilenameService filenames,
|
||||||
public class ModPanelEditTab(
|
ModExportManager modExportManager,
|
||||||
ModManager modManager,
|
Configuration config,
|
||||||
ModFileSystemSelector selector,
|
PredefinedTagManager predefinedTagManager,
|
||||||
ModFileSystem fileSystem,
|
ModGroupEditDrawer groupEditDrawer,
|
||||||
Services.MessageService messager,
|
DescriptionEditPopup descriptionPopup,
|
||||||
FilenameService filenames,
|
AddGroupDrawer addGroupDrawer)
|
||||||
ModExportManager modExportManager,
|
: ITab<ModPanelTab>
|
||||||
Configuration config,
|
{
|
||||||
PredefinedTagManager predefinedTagManager,
|
private readonly TagButtons _modTags = new();
|
||||||
ModGroupEditDrawer groupEditDrawer,
|
|
||||||
DescriptionEditPopup descriptionPopup,
|
private ModFileSystem.Leaf _leaf = null!;
|
||||||
AddGroupDrawer addGroupDrawer)
|
private Mod _mod = null!;
|
||||||
: ITab, IUiService
|
|
||||||
{
|
public ReadOnlySpan<byte> Label
|
||||||
private readonly TagButtons _modTags = new();
|
=> "Edit Mod"u8;
|
||||||
|
|
||||||
private ModFileSystem.Leaf _leaf = null!;
|
public ModPanelTab Identifier
|
||||||
private Mod _mod = null!;
|
=> ModPanelTab.Edit;
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public void DrawContent()
|
||||||
=> "Edit Mod"u8;
|
{
|
||||||
|
using var child = Im.Child.Begin("##editChild"u8, Im.ContentRegion.Available);
|
||||||
public void DrawContent()
|
if (!child)
|
||||||
{
|
return;
|
||||||
using var child = ImRaii.Child("##editChild", -Vector2.One);
|
|
||||||
if (!child)
|
_leaf = selector.SelectedLeaf!;
|
||||||
return;
|
_mod = selector.Selected!;
|
||||||
|
|
||||||
_leaf = selector.SelectedLeaf!;
|
EditButtons();
|
||||||
_mod = selector.Selected!;
|
EditRegularMeta();
|
||||||
|
UiHelpers.DefaultLineSpace();
|
||||||
EditButtons();
|
EditLocalData();
|
||||||
EditRegularMeta();
|
UiHelpers.DefaultLineSpace();
|
||||||
UiHelpers.DefaultLineSpace();
|
|
||||||
EditLocalData();
|
if (Input.Text("Mod Path"u8, Input.Path, Input.None, _leaf.FullName(), out var newPath, UiHelpers.InputTextWidth.X))
|
||||||
UiHelpers.DefaultLineSpace();
|
try
|
||||||
|
{
|
||||||
if (Input.Text("Mod Path", Input.Path, Input.None, _leaf.FullName(), out var newPath, 256, UiHelpers.InputTextWidth.X))
|
fileSystem.RenameAndMove(_leaf, newPath);
|
||||||
try
|
}
|
||||||
{
|
catch (Exception e)
|
||||||
fileSystem.RenameAndMove(_leaf, newPath);
|
{
|
||||||
}
|
messager.NotificationMessage(e.Message, NotificationType.Warning, false);
|
||||||
catch (Exception e)
|
}
|
||||||
{
|
|
||||||
messager.NotificationMessage(e.Message, NotificationType.Warning, false);
|
UiHelpers.DefaultLineSpace();
|
||||||
}
|
|
||||||
|
FeatureChecker.DrawFeatureFlagInput(modManager.DataEditor, _mod, UiHelpers.InputTextWidth.X);
|
||||||
UiHelpers.DefaultLineSpace();
|
|
||||||
|
UiHelpers.DefaultLineSpace();
|
||||||
FeatureChecker.DrawFeatureFlagInput(modManager.DataEditor, _mod, UiHelpers.InputTextWidth.X);
|
var sharedTagsEnabled = predefinedTagManager.Enabled;
|
||||||
|
var sharedTagButtonOffset = sharedTagsEnabled ? Im.Style.FrameHeight + Im.Style.FramePadding.X : 0;
|
||||||
UiHelpers.DefaultLineSpace();
|
var tagIdx = _modTags.Draw("Mod Tags: ", "Edit tags by clicking them, or add new tags. Empty tags are removed.", _mod.ModTags,
|
||||||
var sharedTagsEnabled = predefinedTagManager.Enabled;
|
out var editedTag, rightEndOffset: sharedTagButtonOffset);
|
||||||
var sharedTagButtonOffset = sharedTagsEnabled ? Im.Style.FrameHeight + Im.Style.FramePadding.X : 0;
|
if (tagIdx >= 0)
|
||||||
var tagIdx = _modTags.Draw("Mod Tags: ", "Edit tags by clicking them, or add new tags. Empty tags are removed.", _mod.ModTags,
|
modManager.DataEditor.ChangeModTag(_mod, tagIdx, editedTag);
|
||||||
out var editedTag, rightEndOffset: sharedTagButtonOffset);
|
|
||||||
if (tagIdx >= 0)
|
if (sharedTagsEnabled)
|
||||||
modManager.DataEditor.ChangeModTag(_mod, tagIdx, editedTag);
|
predefinedTagManager.DrawAddFromSharedTagsAndUpdateTags(selector.Selected!.LocalTags, selector.Selected!.ModTags, false,
|
||||||
|
selector.Selected!);
|
||||||
if (sharedTagsEnabled)
|
|
||||||
predefinedTagManager.DrawAddFromSharedTagsAndUpdateTags(selector.Selected!.LocalTags, selector.Selected!.ModTags, false,
|
|
||||||
selector.Selected!);
|
UiHelpers.DefaultLineSpace();
|
||||||
|
addGroupDrawer.Draw(_mod, UiHelpers.InputTextWidth.X);
|
||||||
|
UiHelpers.DefaultLineSpace();
|
||||||
UiHelpers.DefaultLineSpace();
|
|
||||||
addGroupDrawer.Draw(_mod, UiHelpers.InputTextWidth.X);
|
groupEditDrawer.Draw(_mod);
|
||||||
UiHelpers.DefaultLineSpace();
|
descriptionPopup.Draw();
|
||||||
|
}
|
||||||
groupEditDrawer.Draw(_mod);
|
|
||||||
descriptionPopup.Draw();
|
public void Reset()
|
||||||
}
|
{
|
||||||
|
MoveDirectory.Reset();
|
||||||
public void Reset()
|
Input.Reset();
|
||||||
{
|
}
|
||||||
MoveDirectory.Reset();
|
|
||||||
Input.Reset();
|
/// <summary> The general edit row for non-detailed mod edits. </summary>
|
||||||
}
|
private void EditButtons()
|
||||||
|
{
|
||||||
/// <summary> The general edit row for non-detailed mod edits. </summary>
|
var buttonSize = new Vector2(150 * Im.Style.GlobalScale, 0);
|
||||||
private void EditButtons()
|
var folderExists = Directory.Exists(_mod.ModPath.FullName);
|
||||||
{
|
if (ImEx.Button("Open Mod Directory"u8, buttonSize, folderExists
|
||||||
var buttonSize = new Vector2(150 * Im.Style.GlobalScale, 0);
|
? $"Open \"{_mod.ModPath.FullName}\" in the file explorer of your choice."
|
||||||
var folderExists = Directory.Exists(_mod.ModPath.FullName);
|
: $"Mod directory \"{_mod.ModPath.FullName}\" does not exist.", !folderExists))
|
||||||
var tt = folderExists
|
Process.Start(new ProcessStartInfo(_mod.ModPath.FullName) { UseShellExecute = true });
|
||||||
? $"Open \"{_mod.ModPath.FullName}\" in the file explorer of your choice."
|
|
||||||
: $"Mod directory \"{_mod.ModPath.FullName}\" does not exist.";
|
Im.Line.Same();
|
||||||
if (ImGuiUtil.DrawDisabledButton("Open Mod Directory", buttonSize, tt, !folderExists))
|
if (ImEx.Button("Reload Mod"u8, buttonSize, "Reload the current mod from its files.\n"u8
|
||||||
Process.Start(new ProcessStartInfo(_mod.ModPath.FullName) { UseShellExecute = true });
|
+ "If the mod directory or meta file do not exist anymore or if the new mod name is empty, the mod is deleted instead."u8,
|
||||||
|
false))
|
||||||
Im.Line.Same();
|
modManager.ReloadMod(_mod);
|
||||||
if (ImGuiUtil.DrawDisabledButton("Reload Mod", buttonSize, "Reload the current mod from its files.\n"
|
|
||||||
+ "If the mod directory or meta file do not exist anymore or if the new mod name is empty, the mod is deleted instead.",
|
BackupButtons(buttonSize);
|
||||||
false))
|
MoveDirectory.Draw(modManager, _mod, buttonSize);
|
||||||
modManager.ReloadMod(_mod);
|
|
||||||
|
UiHelpers.DefaultLineSpace();
|
||||||
BackupButtons(buttonSize);
|
}
|
||||||
MoveDirectory.Draw(modManager, _mod, buttonSize);
|
|
||||||
|
private void BackupButtons(Vector2 buttonSize)
|
||||||
UiHelpers.DefaultLineSpace();
|
{
|
||||||
}
|
var backup = new ModBackup(modExportManager, _mod);
|
||||||
|
if (ImEx.Button("Export Mod"u8, buttonSize, ModBackup.CreatingBackup
|
||||||
private void BackupButtons(Vector2 buttonSize)
|
? "Already exporting a mod."
|
||||||
{
|
: backup.Exists
|
||||||
var backup = new ModBackup(modExportManager, _mod);
|
? $"Overwrite current exported mod \"{backup.Name}\" with current mod."
|
||||||
var tt = ModBackup.CreatingBackup
|
: $"Create exported archive of current mod at \"{backup.Name}\".", ModBackup.CreatingBackup))
|
||||||
? "Already exporting a mod."
|
backup.CreateAsync();
|
||||||
: backup.Exists
|
|
||||||
? $"Overwrite current exported mod \"{backup.Name}\" with current mod."
|
if (Im.Item.RightClicked())
|
||||||
: $"Create exported archive of current mod at \"{backup.Name}\".";
|
Im.Popup.Open("context"u8);
|
||||||
if (ImUtf8.ButtonEx("Export Mod"u8, tt, buttonSize, ModBackup.CreatingBackup))
|
|
||||||
backup.CreateAsync();
|
Im.Line.Same();
|
||||||
|
if (ImEx.Button("Delete Export"u8, buttonSize, backup.Exists
|
||||||
if (Im.Item.RightClicked())
|
? $"Delete existing mod export \"{backup.Name}\" (hold {config.DeleteModModifier} while clicking)."
|
||||||
ImUtf8.OpenPopup("context"u8);
|
: $"Exported mod \"{backup.Name}\" does not exist.", !backup.Exists || !config.DeleteModModifier.IsActive()))
|
||||||
|
backup.Delete();
|
||||||
Im.Line.Same();
|
|
||||||
tt = backup.Exists
|
Im.Line.Same();
|
||||||
? $"Delete existing mod export \"{backup.Name}\" (hold {config.DeleteModModifier} while clicking)."
|
if (ImEx.Button("Restore From Export"u8, buttonSize, backup.Exists
|
||||||
: $"Exported mod \"{backup.Name}\" does not exist.";
|
? $"Restore mod from exported file \"{backup.Name}\" (hold {config.DeleteModModifier} while clicking)."
|
||||||
if (ImUtf8.ButtonEx("Delete Export"u8, tt, buttonSize, !backup.Exists || !config.DeleteModModifier.IsActive()))
|
: $"Exported mod \"{backup.Name}\" does not exist.", !backup.Exists || !config.DeleteModModifier.IsActive()))
|
||||||
backup.Delete();
|
backup.Restore(modManager);
|
||||||
|
if (backup.Exists)
|
||||||
tt = backup.Exists
|
{
|
||||||
? $"Restore mod from exported file \"{backup.Name}\" (hold {config.DeleteModModifier} while clicking)."
|
Im.Line.Same();
|
||||||
: $"Exported mod \"{backup.Name}\" does not exist.";
|
ImEx.Icon.Draw(FontAwesomeIcon.CheckCircle.Icon());
|
||||||
Im.Line.Same();
|
Im.Tooltip.OnHover($"Export exists in \"{backup.Name}\".");
|
||||||
if (ImUtf8.ButtonEx("Restore From Export"u8, tt, buttonSize, !backup.Exists || !config.DeleteModModifier.IsActive()))
|
}
|
||||||
backup.Restore(modManager);
|
|
||||||
if (backup.Exists)
|
using var context = Im.Popup.Begin("context"u8);
|
||||||
{
|
if (!context)
|
||||||
Im.Line.Same();
|
return;
|
||||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
|
||||||
{
|
if (Im.Selectable("Open Backup Directory"u8))
|
||||||
ImUtf8.Text(FontAwesomeIcon.CheckCircle.ToIconString());
|
Process.Start(new ProcessStartInfo(modExportManager.ExportDirectory.FullName) { UseShellExecute = true });
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Tooltip.OnHover($"Export exists in \"{backup.Name}\".");
|
/// <summary> Anything about editing the regular meta information about the mod. </summary>
|
||||||
}
|
private void EditRegularMeta()
|
||||||
|
{
|
||||||
using var context = ImUtf8.Popup("context"u8);
|
if (Input.Text("Name"u8, Input.Name, Input.None, _mod.Name, out var newName, UiHelpers.InputTextWidth.X))
|
||||||
if (!context)
|
modManager.DataEditor.ChangeModName(_mod, newName);
|
||||||
return;
|
|
||||||
|
if (Input.Text("Author"u8, Input.Author, Input.None, _mod.Author, out var newAuthor, UiHelpers.InputTextWidth.X))
|
||||||
if (ImUtf8.Selectable("Open Backup Directory"u8))
|
modManager.DataEditor.ChangeModAuthor(_mod, newAuthor);
|
||||||
Process.Start(new ProcessStartInfo(modExportManager.ExportDirectory.FullName) { UseShellExecute = true });
|
|
||||||
}
|
if (Input.Text("Version"u8, Input.Version, Input.None, _mod.Version, out var newVersion,
|
||||||
|
UiHelpers.InputTextWidth.X))
|
||||||
/// <summary> Anything about editing the regular meta information about the mod. </summary>
|
modManager.DataEditor.ChangeModVersion(_mod, newVersion);
|
||||||
private void EditRegularMeta()
|
|
||||||
{
|
if (Input.Text("Website"u8, Input.Website, Input.None, _mod.Website, out var newWebsite,
|
||||||
if (Input.Text("Name", Input.Name, Input.None, _mod.Name, out var newName, 256, UiHelpers.InputTextWidth.X))
|
UiHelpers.InputTextWidth.X))
|
||||||
modManager.DataEditor.ChangeModName(_mod, newName);
|
modManager.DataEditor.ChangeModWebsite(_mod, newWebsite);
|
||||||
|
|
||||||
if (Input.Text("Author", Input.Author, Input.None, _mod.Author, out var newAuthor, 256, UiHelpers.InputTextWidth.X))
|
using var style = ImStyleDouble.ItemSpacing.Push(new Vector2(Im.Style.GlobalScale * 3));
|
||||||
modManager.DataEditor.ChangeModAuthor(_mod, newAuthor);
|
|
||||||
|
var reducedSize = new Vector2(UiHelpers.InputTextMinusButton3, 0);
|
||||||
if (Input.Text("Version", Input.Version, Input.None, _mod.Version, out var newVersion, 32,
|
if (Im.Button("Edit Description"u8, reducedSize))
|
||||||
UiHelpers.InputTextWidth.X))
|
descriptionPopup.Open(_mod);
|
||||||
modManager.DataEditor.ChangeModVersion(_mod, newVersion);
|
|
||||||
|
|
||||||
if (Input.Text("Website", Input.Website, Input.None, _mod.Website, out var newWebsite, 256,
|
Im.Line.Same();
|
||||||
UiHelpers.InputTextWidth.X))
|
var fileExists = File.Exists(filenames.ModMetaPath(_mod));
|
||||||
modManager.DataEditor.ChangeModWebsite(_mod, newWebsite);
|
var tt = fileExists
|
||||||
|
? "Open the metadata json file in the text editor of your choice."u8
|
||||||
using var style = ImStyleDouble.ItemSpacing.Push(new Vector2(Im.Style.GlobalScale * 3));
|
: "The metadata json file does not exist."u8;
|
||||||
|
using (Im.Id.Push("meta"))
|
||||||
var reducedSize = new Vector2(UiHelpers.InputTextMinusButton3, 0);
|
{
|
||||||
if (ImGui.Button("Edit Description", reducedSize))
|
if (ImEx.Icon.Button(LunaStyle.FileExportIcon, tt, !fileExists))
|
||||||
descriptionPopup.Open(_mod);
|
Process.Start(new ProcessStartInfo(filenames.ModMetaPath(_mod)) { UseShellExecute = true });
|
||||||
|
}
|
||||||
|
|
||||||
Im.Line.Same();
|
DrawOpenDefaultMod();
|
||||||
var fileExists = File.Exists(filenames.ModMetaPath(_mod));
|
}
|
||||||
var tt = fileExists
|
|
||||||
? "Open the metadata json file in the text editor of your choice."
|
private void EditLocalData()
|
||||||
: "The metadata json file does not exist.";
|
{
|
||||||
if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.FileExport.ToIconString()}##metaFile", UiHelpers.IconButtonSize, tt,
|
DrawImportDate();
|
||||||
!fileExists, true))
|
DrawOpenLocalData();
|
||||||
Process.Start(new ProcessStartInfo(filenames.ModMetaPath(_mod)) { UseShellExecute = true });
|
}
|
||||||
|
|
||||||
DrawOpenDefaultMod();
|
private void DrawImportDate()
|
||||||
}
|
{
|
||||||
|
ImEx.TextFramed($"{DateTimeOffset.FromUnixTimeMilliseconds(_mod.ImportDate).ToLocalTime():yyyy/MM/dd HH:mm}",
|
||||||
private void EditLocalData()
|
new Vector2(UiHelpers.InputTextMinusButton3, 0), ImGuiColor.FrameBackground.Get(0.5f));
|
||||||
{
|
Im.Line.Same(0, 3 * Im.Style.GlobalScale);
|
||||||
DrawImportDate();
|
|
||||||
DrawOpenLocalData();
|
var canRefresh = config.DeleteModModifier.IsActive();
|
||||||
}
|
if (ImEx.Icon.Button(LunaStyle.RefreshIcon, canRefresh
|
||||||
|
? "Reset the import date to the current date and time."u8
|
||||||
private void DrawImportDate()
|
: $"Reset the import date to the current date and time.\nHold {config.DeleteModModifier} while clicking to refresh.",
|
||||||
{
|
!canRefresh))
|
||||||
ImEx.TextFramed($"{DateTimeOffset.FromUnixTimeMilliseconds(_mod.ImportDate).ToLocalTime():yyyy/MM/dd HH:mm}",
|
modManager.DataEditor.ResetModImportDate(_mod);
|
||||||
new Vector2(UiHelpers.InputTextMinusButton3, 0), ImGuiColor.FrameBackground.Get(0.5f));
|
Im.Line.SameInner();
|
||||||
Im.Line.Same(0, 3 * Im.Style.GlobalScale);
|
Im.Text("Import Date"u8);
|
||||||
|
}
|
||||||
var canRefresh = config.DeleteModModifier.IsActive();
|
|
||||||
var tt = canRefresh
|
private void DrawOpenLocalData()
|
||||||
? "Reset the import date to the current date and time."
|
{
|
||||||
: $"Reset the import date to the current date and time.\nHold {config.DeleteModModifier} while clicking to refresh.";
|
var file = filenames.LocalDataFile(_mod);
|
||||||
|
var fileExists = File.Exists(file);
|
||||||
if (ImUtf8.IconButton(FontAwesomeIcon.Sync, tt, disabled: !canRefresh))
|
var tt = fileExists
|
||||||
modManager.DataEditor.ResetModImportDate(_mod);
|
? "Open the local mod data file in the text editor of your choice."u8
|
||||||
Im.Line.SameInner();
|
: "The local mod data file does not exist."u8;
|
||||||
ImUtf8.Text("Import Date"u8);
|
if (ImEx.Button("Open Local Data"u8, UiHelpers.InputTextWidth, tt, !fileExists))
|
||||||
}
|
Process.Start(new ProcessStartInfo(file) { UseShellExecute = true });
|
||||||
|
}
|
||||||
private void DrawOpenLocalData()
|
|
||||||
{
|
private void DrawOpenDefaultMod()
|
||||||
var file = filenames.LocalDataFile(_mod);
|
{
|
||||||
var fileExists = File.Exists(file);
|
var file = filenames.OptionGroupFile(_mod, -1, false);
|
||||||
var tt = fileExists
|
var fileExists = File.Exists(file);
|
||||||
? "Open the local mod data file in the text editor of your choice."u8
|
var tt = fileExists
|
||||||
: "The local mod data file does not exist."u8;
|
? "Open the default mod data file in the text editor of your choice."u8
|
||||||
if (ImUtf8.ButtonEx("Open Local Data"u8, tt, UiHelpers.InputTextWidth, !fileExists))
|
: "The default mod data file does not exist."u8;
|
||||||
Process.Start(new ProcessStartInfo(file) { UseShellExecute = true });
|
if (ImEx.Button("Open Default Data"u8, UiHelpers.InputTextWidth, tt, !fileExists))
|
||||||
}
|
Process.Start(new ProcessStartInfo(file) { UseShellExecute = true });
|
||||||
|
}
|
||||||
private void DrawOpenDefaultMod()
|
|
||||||
{
|
|
||||||
var file = filenames.OptionGroupFile(_mod, -1, false);
|
/// <summary> A text input for the new directory name and a button to apply the move. </summary>
|
||||||
var fileExists = File.Exists(file);
|
private static class MoveDirectory
|
||||||
var tt = fileExists
|
{
|
||||||
? "Open the default mod data file in the text editor of your choice."
|
private static string? _currentModDirectory;
|
||||||
: "The default mod data file does not exist.";
|
private static NewDirectoryState _state = NewDirectoryState.Identical;
|
||||||
if (ImGuiUtil.DrawDisabledButton("Open Default Data", UiHelpers.InputTextWidth, tt, !fileExists))
|
|
||||||
Process.Start(new ProcessStartInfo(file) { UseShellExecute = true });
|
public static void Reset()
|
||||||
}
|
{
|
||||||
|
_currentModDirectory = null;
|
||||||
|
_state = NewDirectoryState.Identical;
|
||||||
/// <summary> A text input for the new directory name and a button to apply the move. </summary>
|
}
|
||||||
private static class MoveDirectory
|
|
||||||
{
|
public static void Draw(ModManager modManager, Mod mod, Vector2 buttonSize)
|
||||||
private static string? _currentModDirectory;
|
{
|
||||||
private static NewDirectoryState _state = NewDirectoryState.Identical;
|
Im.Item.SetNextWidth(buttonSize.X * 2 + Im.Style.ItemSpacing.X);
|
||||||
|
var tmp = _currentModDirectory ?? mod.ModPath.Name;
|
||||||
public static void Reset()
|
if (Im.Input.Text("##newModMove"u8, ref tmp))
|
||||||
{
|
{
|
||||||
_currentModDirectory = null;
|
_currentModDirectory = tmp;
|
||||||
_state = NewDirectoryState.Identical;
|
_state = modManager.NewDirectoryValid(mod.ModPath.Name, _currentModDirectory, out _);
|
||||||
}
|
}
|
||||||
|
|
||||||
public static void Draw(ModManager modManager, Mod mod, Vector2 buttonSize)
|
var (disabled, tt) = _state switch
|
||||||
{
|
{
|
||||||
Im.Item.SetNextWidth(buttonSize.X * 2 + Im.Style.ItemSpacing.X);
|
NewDirectoryState.Identical => (true, "Current directory name is identical to new one."),
|
||||||
var tmp = _currentModDirectory ?? mod.ModPath.Name;
|
NewDirectoryState.Empty => (true, "Please enter a new directory name first."),
|
||||||
if (ImGui.InputText("##newModMove", ref tmp, 64))
|
NewDirectoryState.NonExisting => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
||||||
{
|
NewDirectoryState.ExistsEmpty => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
||||||
_currentModDirectory = tmp;
|
NewDirectoryState.ExistsNonEmpty => (true, $"{_currentModDirectory} already exists and is not empty."),
|
||||||
_state = modManager.NewDirectoryValid(mod.ModPath.Name, _currentModDirectory, out _);
|
NewDirectoryState.ExistsAsFile => (true, $"{_currentModDirectory} exists as a file."),
|
||||||
}
|
NewDirectoryState.ContainsInvalidSymbols => (true,
|
||||||
|
$"{_currentModDirectory} contains invalid symbols for FFXIV."),
|
||||||
var (disabled, tt) = _state switch
|
_ => (true, "Unknown error."),
|
||||||
{
|
};
|
||||||
NewDirectoryState.Identical => (true, "Current directory name is identical to new one."),
|
Im.Line.Same();
|
||||||
NewDirectoryState.Empty => (true, "Please enter a new directory name first."),
|
if (ImEx.Button("Rename Mod Directory"u8, buttonSize, tt, disabled) && _currentModDirectory is not null)
|
||||||
NewDirectoryState.NonExisting => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
{
|
||||||
NewDirectoryState.ExistsEmpty => (false, $"Move mod from {mod.ModPath.Name} to {_currentModDirectory}."),
|
modManager.MoveModDirectory(mod, _currentModDirectory);
|
||||||
NewDirectoryState.ExistsNonEmpty => (true, $"{_currentModDirectory} already exists and is not empty."),
|
Reset();
|
||||||
NewDirectoryState.ExistsAsFile => (true, $"{_currentModDirectory} exists as a file."),
|
}
|
||||||
NewDirectoryState.ContainsInvalidSymbols => (true,
|
|
||||||
$"{_currentModDirectory} contains invalid symbols for FFXIV."),
|
Im.Line.Same();
|
||||||
_ => (true, "Unknown error."),
|
if (LunaStyle.DrawAlignedHelpMarker())
|
||||||
};
|
Im.Tooltip.Set(
|
||||||
Im.Line.Same();
|
"The mod directory name is used to correspond stored settings and sort orders, otherwise it has no influence on anything that is displayed.\n"u8
|
||||||
if (ImGuiUtil.DrawDisabledButton("Rename Mod Directory", buttonSize, tt, disabled) && _currentModDirectory != null)
|
+ "This can currently not be used on pre-existing folders and does not support merges or overwriting."u8);
|
||||||
{
|
}
|
||||||
modManager.MoveModDirectory(mod, _currentModDirectory);
|
}
|
||||||
Reset();
|
|
||||||
}
|
/// <summary> Handles input text and integers in separate fields without buffers for every single one. </summary>
|
||||||
|
private static class Input
|
||||||
Im.Line.Same();
|
{
|
||||||
ImGuiComponents.HelpMarker(
|
// Special field indices to reuse the same string buffer.
|
||||||
"The mod directory name is used to correspond stored settings and sort orders, otherwise it has no influence on anything that is displayed.\n"
|
public const int None = -1;
|
||||||
+ "This can currently not be used on pre-existing folders and does not support merges or overwriting.");
|
public const int Name = -2;
|
||||||
}
|
public const int Author = -3;
|
||||||
}
|
public const int Version = -4;
|
||||||
|
public const int Website = -5;
|
||||||
/// <summary> Handles input text and integers in separate fields without buffers for every single one. </summary>
|
public const int Path = -6;
|
||||||
private static class Input
|
|
||||||
{
|
// Temporary strings
|
||||||
// Special field indices to reuse the same string buffer.
|
private static string? _currentEdit;
|
||||||
public const int None = -1;
|
private static int _currentField = None;
|
||||||
public const int Name = -2;
|
private static int _optionIndex = None;
|
||||||
public const int Author = -3;
|
|
||||||
public const int Version = -4;
|
public static void Reset()
|
||||||
public const int Website = -5;
|
{
|
||||||
public const int Path = -6;
|
_currentEdit = null;
|
||||||
public const int Description = -7;
|
_currentField = None;
|
||||||
|
_optionIndex = None;
|
||||||
// Temporary strings
|
}
|
||||||
private static string? _currentEdit;
|
|
||||||
private static ModPriority? _currentGroupPriority;
|
public static bool Text(ReadOnlySpan<byte> label, int field, int option, string oldValue, out string value, float width)
|
||||||
private static int _currentField = None;
|
{
|
||||||
private static int _optionIndex = None;
|
var tmp = field == _currentField && option == _optionIndex ? _currentEdit ?? oldValue : oldValue;
|
||||||
|
Im.Item.SetNextWidth(width);
|
||||||
public static void Reset()
|
|
||||||
{
|
if (Im.Input.Text(label, ref tmp))
|
||||||
_currentEdit = null;
|
{
|
||||||
_currentGroupPriority = null;
|
_currentEdit = tmp;
|
||||||
_currentField = None;
|
_optionIndex = option;
|
||||||
_optionIndex = None;
|
_currentField = field;
|
||||||
}
|
}
|
||||||
|
|
||||||
public static bool Text(string label, int field, int option, string oldValue, out string value, uint maxLength, float width)
|
if (Im.Item.DeactivatedAfterEdit && _currentEdit is not null)
|
||||||
{
|
{
|
||||||
var tmp = field == _currentField && option == _optionIndex ? _currentEdit ?? oldValue : oldValue;
|
var ret = _currentEdit != oldValue;
|
||||||
Im.Item.SetNextWidth(width);
|
value = _currentEdit;
|
||||||
|
Reset();
|
||||||
if (ImGui.InputText(label, ref tmp))
|
return ret;
|
||||||
{
|
}
|
||||||
_currentEdit = tmp;
|
|
||||||
_optionIndex = option;
|
value = string.Empty;
|
||||||
_currentField = field;
|
return false;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (ImGui.IsItemDeactivatedAfterEdit() && _currentEdit != null)
|
}
|
||||||
{
|
|
||||||
var ret = _currentEdit != oldValue;
|
|
||||||
value = _currentEdit;
|
|
||||||
Reset();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = string.Empty;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
public static bool Priority(string label, int field, int option, ModPriority oldValue, out ModPriority value, float width)
|
|
||||||
{
|
|
||||||
var tmp = (field == _currentField && option == _optionIndex ? _currentGroupPriority ?? oldValue : oldValue).Value;
|
|
||||||
Im.Item.SetNextWidth(width);
|
|
||||||
if (ImGui.InputInt(label, ref tmp, 0, 0))
|
|
||||||
{
|
|
||||||
_currentGroupPriority = new ModPriority(tmp);
|
|
||||||
_optionIndex = option;
|
|
||||||
_currentField = field;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ImGui.IsItemDeactivatedAfterEdit() && _currentGroupPriority != null)
|
|
||||||
{
|
|
||||||
var ret = _currentGroupPriority != oldValue;
|
|
||||||
value = _currentGroupPriority.Value;
|
|
||||||
Reset();
|
|
||||||
return ret;
|
|
||||||
}
|
|
||||||
|
|
||||||
value = ModPriority.Default;
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
|
||||||
|
|
@ -1,8 +1,8 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
using Luna;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Penumbra.UI.Classes;
|
using Penumbra.UI.Classes;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.Communication;
|
using Penumbra.Communication;
|
||||||
|
|
@ -22,7 +22,7 @@ public class ModPanelSettingsTab(
|
||||||
CommunicatorService communicator,
|
CommunicatorService communicator,
|
||||||
ModGroupDrawer modGroupDrawer,
|
ModGroupDrawer modGroupDrawer,
|
||||||
Configuration config)
|
Configuration config)
|
||||||
: ITab, Luna.IUiService
|
: ITab<ModPanelTab>
|
||||||
{
|
{
|
||||||
private bool _inherited;
|
private bool _inherited;
|
||||||
private bool _temporary;
|
private bool _temporary;
|
||||||
|
|
@ -31,8 +31,11 @@ public class ModPanelSettingsTab(
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Settings"u8;
|
=> "Settings"u8;
|
||||||
|
|
||||||
|
public ModPanelTab Identifier
|
||||||
|
=> ModPanelTab.Settings;
|
||||||
|
|
||||||
public void DrawHeader()
|
public void PostTabButton()
|
||||||
=> tutorial.OpenTutorial(BasicTutorialSteps.ModOptions);
|
=> tutorial.OpenTutorial(BasicTutorialSteps.ModOptions);
|
||||||
|
|
||||||
public void Reset()
|
public void Reset()
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,5 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
|
||||||
using Dalamud.Interface;
|
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using OtterGui;
|
|
||||||
using OtterGui.Raii;
|
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
using Penumbra.UI.AdvancedWindow;
|
using Penumbra.UI.AdvancedWindow;
|
||||||
|
|
@ -12,138 +7,88 @@ using ImGuiColor = ImSharp.ImGuiColor;
|
||||||
|
|
||||||
namespace Penumbra.UI.ModsTab;
|
namespace Penumbra.UI.ModsTab;
|
||||||
|
|
||||||
public class ModPanelTabBar : IUiService
|
public enum ModPanelTab
|
||||||
{
|
{
|
||||||
private enum ModPanelTabType
|
Description,
|
||||||
{
|
Settings,
|
||||||
Description,
|
ChangedItems,
|
||||||
Settings,
|
Conflicts,
|
||||||
ChangedItems,
|
Collections,
|
||||||
Conflicts,
|
Edit,
|
||||||
Collections,
|
};
|
||||||
Edit,
|
|
||||||
};
|
|
||||||
|
|
||||||
public readonly ModPanelSettingsTab Settings;
|
public class ModPanelTabBar : TabBar<ModPanelTab>
|
||||||
public readonly ModPanelDescriptionTab Description;
|
{
|
||||||
public readonly ModPanelCollectionsTab Collections;
|
public readonly ModPanelSettingsTab Settings;
|
||||||
public readonly ModPanelConflictsTab Conflicts;
|
public readonly ModPanelEditTab Edit;
|
||||||
public readonly ModPanelChangedItemsTab ChangedItems;
|
private readonly ModManager _modManager;
|
||||||
public readonly ModPanelEditTab Edit;
|
private readonly TutorialService _tutorial;
|
||||||
private readonly ModEditWindowFactory _modEditWindowFactory;
|
|
||||||
private readonly ModManager _modManager;
|
|
||||||
private readonly TutorialService _tutorial;
|
|
||||||
|
|
||||||
public readonly ITab[] Tabs;
|
private Mod? _lastMod;
|
||||||
private ModPanelTabType _preferredTab = ModPanelTabType.Settings;
|
|
||||||
private Mod? _lastMod;
|
|
||||||
|
|
||||||
public ModPanelTabBar(ModEditWindowFactory modEditWindowFactory, ModPanelSettingsTab settings, ModPanelDescriptionTab description,
|
public ModPanelTabBar(ModEditWindowFactory modEditWindowFactory, ModPanelSettingsTab settings, ModPanelDescriptionTab description,
|
||||||
ModPanelConflictsTab conflicts, ModPanelChangedItemsTab changedItems, ModPanelEditTab edit, ModManager modManager,
|
ModPanelConflictsTab conflicts, ModPanelChangedItemsTab changedItems, ModPanelEditTab edit, ModManager modManager,
|
||||||
TutorialService tutorial, ModPanelCollectionsTab collections)
|
TutorialService tutorial, ModPanelCollectionsTab collections, Logger log)
|
||||||
|
: base(nameof(ModPanelTabBar), log, settings, description, conflicts, changedItems, collections, edit)
|
||||||
{
|
{
|
||||||
_modEditWindowFactory = modEditWindowFactory;
|
Flags = TabBarFlags.NoTooltip;
|
||||||
Settings = settings;
|
Settings = settings;
|
||||||
Description = description;
|
Edit = edit;
|
||||||
Conflicts = conflicts;
|
_modManager = modManager;
|
||||||
ChangedItems = changedItems;
|
_tutorial = tutorial;
|
||||||
Edit = edit;
|
Buttons.AddButton(new AdvancedEditingButton(this, modEditWindowFactory), 0);
|
||||||
_modManager = modManager;
|
}
|
||||||
_tutorial = tutorial;
|
|
||||||
Collections = collections;
|
|
||||||
|
|
||||||
Tabs =
|
private sealed class AdvancedEditingButton(ModPanelTabBar parent, ModEditWindowFactory editFactory) : BaseButton
|
||||||
[
|
{
|
||||||
Settings,
|
public override ReadOnlySpan<byte> Label
|
||||||
Description,
|
=> "Advanced Editing"u8;
|
||||||
Conflicts,
|
|
||||||
ChangedItems,
|
public override void OnClick()
|
||||||
Collections,
|
{
|
||||||
Edit,
|
if (parent._lastMod is { } mod)
|
||||||
];
|
editFactory.OpenForMod(mod);
|
||||||
|
}
|
||||||
|
|
||||||
|
public override bool HasTooltip
|
||||||
|
=> true;
|
||||||
|
|
||||||
|
public override void DrawTooltip()
|
||||||
|
=> Im.Text(
|
||||||
|
"Clicking this will open a new window in which you can\nedit the following things per option for this mod:\n\n"u8
|
||||||
|
+ "\t\t- file redirections\n"u8
|
||||||
|
+ "\t\t- file swaps\n"u8
|
||||||
|
+ "\t\t- metadata manipulations\n"u8
|
||||||
|
+ "\t\t- model materials\n"u8
|
||||||
|
+ "\t\t- duplicates\n"u8
|
||||||
|
+ "\t\t- textures"u8);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void Draw(Mod mod)
|
public void Draw(Mod mod)
|
||||||
{
|
{
|
||||||
var tabBarHeight = ImGui.GetCursorPosY();
|
var tabBarHeight = Im.Cursor.Y;
|
||||||
if (_lastMod != mod)
|
_lastMod = mod;
|
||||||
{
|
base.Draw();
|
||||||
_lastMod = mod;
|
|
||||||
TabBar.Draw(string.Empty, ImGuiTabBarFlags.NoTooltip, ToLabel(_preferredTab), out _, () => DrawAdvancedEditingButton(mod), Tabs);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
TabBar.Draw(string.Empty, ImGuiTabBarFlags.NoTooltip, ReadOnlySpan<byte>.Empty, out var label, () => DrawAdvancedEditingButton(mod),
|
|
||||||
Tabs);
|
|
||||||
_preferredTab = ToType(label);
|
|
||||||
}
|
|
||||||
|
|
||||||
DrawFavoriteButton(mod, tabBarHeight);
|
DrawFavoriteButton(mod, tabBarHeight);
|
||||||
}
|
}
|
||||||
|
|
||||||
private ReadOnlySpan<byte> ToLabel(ModPanelTabType type)
|
|
||||||
=> type switch
|
|
||||||
{
|
|
||||||
ModPanelTabType.Description => Description.Label,
|
|
||||||
ModPanelTabType.Settings => Settings.Label,
|
|
||||||
ModPanelTabType.ChangedItems => ChangedItems.Label,
|
|
||||||
ModPanelTabType.Conflicts => Conflicts.Label,
|
|
||||||
ModPanelTabType.Collections => Collections.Label,
|
|
||||||
ModPanelTabType.Edit => Edit.Label,
|
|
||||||
_ => ReadOnlySpan<byte>.Empty,
|
|
||||||
};
|
|
||||||
|
|
||||||
private ModPanelTabType ToType(ReadOnlySpan<byte> label)
|
|
||||||
{
|
|
||||||
if (label == Description.Label)
|
|
||||||
return ModPanelTabType.Description;
|
|
||||||
if (label == Settings.Label)
|
|
||||||
return ModPanelTabType.Settings;
|
|
||||||
if (label == ChangedItems.Label)
|
|
||||||
return ModPanelTabType.ChangedItems;
|
|
||||||
if (label == Conflicts.Label)
|
|
||||||
return ModPanelTabType.Conflicts;
|
|
||||||
if (label == Collections.Label)
|
|
||||||
return ModPanelTabType.Collections;
|
|
||||||
if (label == Edit.Label)
|
|
||||||
return ModPanelTabType.Edit;
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawAdvancedEditingButton(Mod mod)
|
|
||||||
{
|
|
||||||
if (ImGui.TabItemButton("Advanced Editing", ImGuiTabItemFlags.Trailing | ImGuiTabItemFlags.NoTooltip))
|
|
||||||
{
|
|
||||||
_modEditWindowFactory.OpenForMod(mod);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGuiUtil.HoverTooltip(
|
|
||||||
"Clicking this will open a new window in which you can\nedit the following things per option for this mod:\n\n"
|
|
||||||
+ "\t\t- file redirections\n"
|
|
||||||
+ "\t\t- file swaps\n"
|
|
||||||
+ "\t\t- metadata manipulations\n"
|
|
||||||
+ "\t\t- model materials\n"
|
|
||||||
+ "\t\t- duplicates\n"
|
|
||||||
+ "\t\t- textures");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void DrawFavoriteButton(Mod mod, float height)
|
private void DrawFavoriteButton(Mod mod, float height)
|
||||||
{
|
{
|
||||||
var size = ImEx.Icon.CalculateSize(LunaStyle.FavoriteIcon) + Im.Style.FramePadding * 2;
|
var size = ImEx.Icon.CalculateSize(LunaStyle.FavoriteIcon) + Im.Style.FramePadding * 2;
|
||||||
var newPos = new Vector2(ImGui.GetWindowWidth() - size.X - Im.Style.ItemSpacing.X, height);
|
var newPos = new Vector2(Im.Window.Width - size.X - Im.Style.ItemSpacing.X, height);
|
||||||
if (ImGui.GetScrollMaxX() > 0)
|
if (Im.Scroll.MaximumX > 0)
|
||||||
newPos.X += ImGui.GetScrollX();
|
newPos.X += Im.Scroll.X;
|
||||||
|
|
||||||
var rectUpper = ImGui.GetWindowPos() + newPos;
|
var rectUpper = Im.Window.Position + newPos;
|
||||||
var color = ImGui.IsMouseHoveringRect(rectUpper, rectUpper + size) ? Im.Style[ImGuiColor.Text] :
|
var color = Im.Mouse.IsHoveringRectangle(rectUpper, rectUpper + size) ? Im.Style[ImGuiColor.Text] :
|
||||||
mod.Favorite ? LunaStyle.FavoriteColor : Im.Style[ImGuiColor.TextDisabled];
|
mod.Favorite ? LunaStyle.FavoriteColor : Im.Style[ImGuiColor.TextDisabled];
|
||||||
using var c = ImGuiColor.Text.Push(color)
|
using var c = ImGuiColor.Text.Push(color)
|
||||||
.Push(ImGuiColor.Button, Vector4.Zero)
|
.Push(ImGuiColor.Button, Vector4.Zero)
|
||||||
.Push(ImGuiColor.ButtonHovered, Vector4.Zero)
|
.Push(ImGuiColor.ButtonHovered, Vector4.Zero)
|
||||||
.Push(ImGuiColor.ButtonActive, Vector4.Zero);
|
.Push(ImGuiColor.ButtonActive, Vector4.Zero);
|
||||||
|
|
||||||
ImGui.SetCursorPos(newPos);
|
Im.Cursor.Position = newPos;
|
||||||
if (ImEx.Icon.Button(LunaStyle.FavoriteIcon))
|
if (ImEx.Icon.Button(LunaStyle.FavoriteIcon))
|
||||||
_modManager.DataEditor.ChangeModFavorite(mod, !mod.Favorite);
|
_modManager.DataEditor.ChangeModFavorite(mod, !mod.Favorite);
|
||||||
|
|
||||||
|
|
@ -151,6 +96,6 @@ public class ModPanelTabBar : IUiService
|
||||||
_tutorial.OpenTutorial(BasicTutorialSteps.Favorites);
|
_tutorial.OpenTutorial(BasicTutorialSteps.Favorites);
|
||||||
|
|
||||||
if (hovered)
|
if (hovered)
|
||||||
ImGui.SetTooltip("Favorite");
|
Im.Tooltip.Set("Favorite"u8);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,7 +2,7 @@ using Dalamud.Bindings.ImGui;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
using FFXIVClientStructs.FFXIV.Client.Game.Object;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using OtterGui.Widgets;
|
using Luna;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
|
|
@ -16,7 +16,7 @@ using Penumbra.UI.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.ResourceWatcher;
|
namespace Penumbra.UI.ResourceWatcher;
|
||||||
|
|
||||||
public sealed class ResourceWatcher : IDisposable, ITab, Luna.IUiService
|
public sealed class ResourceWatcher : IDisposable, ITab<TabType>
|
||||||
{
|
{
|
||||||
public const int DefaultMaxEntries = 1024;
|
public const int DefaultMaxEntries = 1024;
|
||||||
public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction;
|
public const RecordType AllRecords = RecordType.Request | RecordType.ResourceLoad | RecordType.FileLoad | RecordType.Destruction;
|
||||||
|
|
@ -96,6 +96,9 @@ public sealed class ResourceWatcher : IDisposable, ITab, Luna.IUiService
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Resource Logger"u8;
|
=> "Resource Logger"u8;
|
||||||
|
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.ResourceWatcher;
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
{
|
{
|
||||||
UpdateRecords();
|
UpdateRecords();
|
||||||
|
|
|
||||||
|
|
@ -2,10 +2,7 @@ using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using Luna;
|
using Luna;
|
||||||
using OtterGui;
|
|
||||||
using OtterGui.Raii;
|
|
||||||
using OtterGui.Table;
|
using OtterGui.Table;
|
||||||
using OtterGui.Text;
|
|
||||||
using Penumbra.Enums;
|
using Penumbra.Enums;
|
||||||
using Penumbra.Interop.Structs;
|
using Penumbra.Interop.Structs;
|
||||||
using Penumbra.String;
|
using Penumbra.String;
|
||||||
|
|
@ -54,16 +51,16 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
=> DrawByteString(item.Path, 280 * Im.Style.GlobalScale);
|
=> DrawByteString(item.Path, 280 * Im.Style.GlobalScale);
|
||||||
}
|
}
|
||||||
|
|
||||||
private static unsafe void DrawByteString(CiByteString path, float length)
|
private static void DrawByteString(CiByteString path, float length)
|
||||||
{
|
{
|
||||||
if (path.IsEmpty)
|
if (path.IsEmpty)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
var size = ImUtf8.CalcTextSize(path.Span);
|
var size = Im.Font.CalculateSize(path.Span);
|
||||||
var clicked = false;
|
var clicked = false;
|
||||||
if (size.X <= length)
|
if (size.X <= length)
|
||||||
{
|
{
|
||||||
clicked = ImUtf8.Selectable(path.Span);
|
clicked = Im.Selectable(path.Span);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
|
@ -71,10 +68,11 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
using (Im.Group())
|
using (Im.Group())
|
||||||
{
|
{
|
||||||
CiByteString shortPath;
|
CiByteString shortPath;
|
||||||
if (fileName != -1)
|
var icon = FontAwesomeIcon.EllipsisH.Icon();
|
||||||
|
if (fileName is not -1)
|
||||||
{
|
{
|
||||||
using var font = ImRaii.PushFont(UiBuilder.IconFont);
|
using var font = AwesomeIcon.Font.Push();
|
||||||
clicked = ImUtf8.Selectable(FontAwesomeIcon.EllipsisH.ToIconString());
|
clicked = Im.Selectable(icon.Span);
|
||||||
Im.Line.SameInner();
|
Im.Line.SameInner();
|
||||||
shortPath = path.Substring(fileName, path.Length - fileName);
|
shortPath = path.Substring(fileName, path.Length - fileName);
|
||||||
}
|
}
|
||||||
|
|
@ -83,14 +81,14 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
shortPath = path;
|
shortPath = path;
|
||||||
}
|
}
|
||||||
|
|
||||||
clicked |= ImUtf8.Selectable(shortPath.Span, false, ImGuiSelectableFlags.AllowItemOverlap);
|
clicked |= Im.Selectable(shortPath.Span, false, SelectableFlags.AllowOverlap);
|
||||||
}
|
}
|
||||||
|
|
||||||
Im.Tooltip.OnHover(path.Span);
|
Im.Tooltip.OnHover(path.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (clicked)
|
if (clicked)
|
||||||
ImUtf8.SetClipboardText(path.Span);
|
Im.Clipboard.Set(path.Span);
|
||||||
}
|
}
|
||||||
|
|
||||||
private sealed class RecordTypeColumn : ColumnFlags<RecordType, Record>
|
private sealed class RecordTypeColumn : ColumnFlags<RecordType, Record>
|
||||||
|
|
@ -153,13 +151,13 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
public override float Width
|
public override float Width
|
||||||
=> UiBuilder.MonoFont.GetCharAdvance('0') * 17;
|
=> UiBuilder.MonoFont.GetCharAdvance('0') * 17;
|
||||||
|
|
||||||
public override unsafe string ToName(Record item)
|
public override string ToName(Record item)
|
||||||
=> item.Crc64 != 0 ? $"{item.Crc64:X16}" : string.Empty;
|
=> item.Crc64 is not 0 ? $"{item.Crc64:X16}" : string.Empty;
|
||||||
|
|
||||||
public override unsafe void DrawColumn(Record item, int _)
|
public override unsafe void DrawColumn(Record item, int _)
|
||||||
{
|
{
|
||||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont, item.Handle != null);
|
using var font = item.Handle is null ? null : Im.Font.PushMono();
|
||||||
ImUtf8.Text(ToName(item));
|
Im.Text(ToName(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -334,17 +332,17 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
var (icon, color, tt) = item.LoadState switch
|
var (icon, color, tt) = item.LoadState switch
|
||||||
{
|
{
|
||||||
LoadState.Success => (FontAwesomeIcon.CheckCircle, ColorId.IncreasedMetaValue.Value(),
|
LoadState.Success => (FontAwesomeIcon.CheckCircle, ColorId.IncreasedMetaValue.Value(),
|
||||||
$"Successfully loaded ({(byte)item.LoadState})."),
|
new StringU8($"Successfully loaded ({(byte)item.LoadState}).")),
|
||||||
LoadState.FailedSubResource => (FontAwesomeIcon.ExclamationCircle, ColorId.DecreasedMetaValue.Value(),
|
LoadState.FailedSubResource => (FontAwesomeIcon.ExclamationCircle, ColorId.DecreasedMetaValue.Value(),
|
||||||
$"Dependencies failed to load ({(byte)item.LoadState})."),
|
new StringU8($"Dependencies failed to load ({(byte)item.LoadState}).")),
|
||||||
<= LoadState.Constructed => (FontAwesomeIcon.QuestionCircle, ColorId.UndefinedMod.Value(),
|
<= LoadState.Constructed => (FontAwesomeIcon.QuestionCircle, ColorId.UndefinedMod.Value(),
|
||||||
$"Not yet loaded ({(byte)item.LoadState})."),
|
new StringU8($"Not yet loaded ({(byte)item.LoadState}).")),
|
||||||
< LoadState.Success => (FontAwesomeIcon.Clock, ColorId.FolderLine.Value(), $"Loading asynchronously ({(byte)item.LoadState})."),
|
< LoadState.Success => (FontAwesomeIcon.Clock, ColorId.FolderLine.Value(), new StringU8($"Loading asynchronously ({(byte)item.LoadState}).")),
|
||||||
> LoadState.Success => (FontAwesomeIcon.Times, ColorId.DecreasedMetaValue.Value(),
|
> LoadState.Success => (FontAwesomeIcon.Times, ColorId.DecreasedMetaValue.Value(),
|
||||||
$"Failed to load ({(byte)item.LoadState})."),
|
new StringU8($"Failed to load ({(byte)item.LoadState}).")),
|
||||||
};
|
};
|
||||||
ImEx.Icon.Draw(icon.Icon(), color);
|
ImEx.Icon.Draw(icon.Icon(), color);
|
||||||
ImGuiUtil.HoverTooltip(tt);
|
Im.Tooltip.OnHover(tt);
|
||||||
}
|
}
|
||||||
|
|
||||||
public override int Compare(Record lhs, Record rhs)
|
public override int Compare(Record lhs, Record rhs)
|
||||||
|
|
@ -361,8 +359,8 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
|
|
||||||
public override unsafe void DrawColumn(Record item, int _)
|
public override unsafe void DrawColumn(Record item, int _)
|
||||||
{
|
{
|
||||||
using var font = ImRaii.PushFont(UiBuilder.MonoFont, item.Handle != null);
|
using var font = item.Handle is null ? null : Im.Font.PushMono();
|
||||||
ImGuiUtil.RightAlign(ToName(item));
|
ImEx.TextRightAligned(ToName(item));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -447,7 +445,7 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
=> 30 * Im.Style.GlobalScale;
|
=> 30 * Im.Style.GlobalScale;
|
||||||
|
|
||||||
public override void DrawColumn(Record item, int _)
|
public override void DrawColumn(Record item, int _)
|
||||||
=> ImGuiUtil.RightAlign(item.RefCount.ToString());
|
=> ImEx.TextRightAligned($"{item.RefCount}");
|
||||||
|
|
||||||
public override int Compare(Record lhs, Record rhs)
|
public override int Compare(Record lhs, Record rhs)
|
||||||
=> lhs.RefCount.CompareTo(rhs.RefCount);
|
=> lhs.RefCount.CompareTo(rhs.RefCount);
|
||||||
|
|
@ -462,7 +460,7 @@ internal sealed class ResourceWatcherTable : Table<Record>
|
||||||
=> item.OsThreadId.ToString();
|
=> item.OsThreadId.ToString();
|
||||||
|
|
||||||
public override void DrawColumn(Record item, int _)
|
public override void DrawColumn(Record item, int _)
|
||||||
=> ImGuiUtil.RightAlign(ToName(item));
|
=> ImEx.TextRightAligned($"{item.OsThreadId}");
|
||||||
|
|
||||||
public override int Compare(Record lhs, Record rhs)
|
public override int Compare(Record lhs, Record rhs)
|
||||||
=> lhs.OsThreadId.CompareTo(rhs.OsThreadId);
|
=> lhs.OsThreadId.CompareTo(rhs.OsThreadId);
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
using Luna;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.Communication;
|
using Penumbra.Communication;
|
||||||
|
|
@ -15,19 +15,22 @@ using Penumbra.UI.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class ChangedItemsTab(
|
public sealed class ChangedItemsTab(
|
||||||
CollectionManager collectionManager,
|
CollectionManager collectionManager,
|
||||||
CollectionSelectHeader collectionHeader,
|
CollectionSelectHeader collectionHeader,
|
||||||
ChangedItemDrawer drawer,
|
ChangedItemDrawer drawer,
|
||||||
CommunicatorService communicator)
|
CommunicatorService communicator)
|
||||||
: ITab, Luna.IUiService
|
: ITab<TabType>
|
||||||
{
|
{
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Changed Items"u8;
|
=> "Changed Items"u8;
|
||||||
|
|
||||||
private string _changedItemFilter = string.Empty;
|
public TabType Identifier
|
||||||
private string _changedItemModFilter = string.Empty;
|
=> TabType.ChangedItems;
|
||||||
private Vector2 _buttonSize;
|
|
||||||
|
private string _changedItemFilter = string.Empty;
|
||||||
|
private string _changedItemModFilter = string.Empty;
|
||||||
|
private Vector2 _buttonSize;
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
{
|
{
|
||||||
|
|
@ -105,7 +108,7 @@ public class ChangedItemsTab(
|
||||||
if (ImUtf8.Selectable(first.Name, false, ImGuiSelectableFlags.None, _buttonSize with { X = 0 })
|
if (ImUtf8.Selectable(first.Name, false, ImGuiSelectableFlags.None, _buttonSize with { X = 0 })
|
||||||
&& ImGui.GetIO().KeyCtrl
|
&& ImGui.GetIO().KeyCtrl
|
||||||
&& first is Mod mod)
|
&& first is Mod mod)
|
||||||
communicator.SelectTab.Invoke(new SelectTab.Arguments(TabType.Mods, mod));
|
communicator.SelectTab.Invoke(new SelectTab.Arguments(Api.Enums.TabType.Mods, mod));
|
||||||
|
|
||||||
if (!Im.Item.Hovered())
|
if (!Im.Item.Hovered())
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -2,8 +2,9 @@ using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Game.ClientState.Objects;
|
using Dalamud.Game.ClientState.Objects;
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
using Luna;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Widgets;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.Mods.Manager;
|
using Penumbra.Mods.Manager;
|
||||||
|
|
@ -12,7 +13,7 @@ using Penumbra.UI.CollectionTab;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public sealed class CollectionsTab : IDisposable, ITab, Luna.IUiService
|
public sealed class CollectionsTab : ITab<TabType>, IDisposable
|
||||||
{
|
{
|
||||||
private readonly EphemeralConfig _config;
|
private readonly EphemeralConfig _config;
|
||||||
private readonly CollectionSelector _selector;
|
private readonly CollectionSelector _selector;
|
||||||
|
|
@ -38,6 +39,9 @@ public sealed class CollectionsTab : IDisposable, ITab, Luna.IUiService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.Collections;
|
||||||
|
|
||||||
public CollectionsTab(IDalamudPluginInterface pi, Configuration configuration, CommunicatorService communicator, IncognitoService incognito,
|
public CollectionsTab(IDalamudPluginInterface pi, Configuration configuration, CommunicatorService communicator, IncognitoService incognito,
|
||||||
CollectionManager collectionManager, ModStorage modStorage, ActorManager actors, ITargetManager targets, TutorialService tutorial, SaveService saveService)
|
CollectionManager collectionManager, ModStorage modStorage, ActorManager actors, ITargetManager targets, TutorialService tutorial, SaveService saveService)
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,113 +0,0 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Penumbra.Api.Enums;
|
|
||||||
using Penumbra.Communication;
|
|
||||||
using Penumbra.Services;
|
|
||||||
using Penumbra.UI.Tabs.Debug;
|
|
||||||
using Watcher = Penumbra.UI.ResourceWatcher.ResourceWatcher;
|
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
|
||||||
|
|
||||||
public class ConfigTabBar : IDisposable, Luna.IUiService
|
|
||||||
{
|
|
||||||
private readonly CommunicatorService _communicator;
|
|
||||||
|
|
||||||
public readonly SettingsTab Settings;
|
|
||||||
public readonly ModsTab Mods;
|
|
||||||
public readonly CollectionsTab Collections;
|
|
||||||
public readonly ChangedItemsTab ChangedItems;
|
|
||||||
public readonly EffectiveTab Effective;
|
|
||||||
public readonly DebugTab Debug;
|
|
||||||
public readonly ResourceTab Resource;
|
|
||||||
public readonly Watcher Watcher;
|
|
||||||
public readonly OnScreenTab OnScreen;
|
|
||||||
public readonly MessagesTab Messages;
|
|
||||||
|
|
||||||
public readonly ITab[] Tabs;
|
|
||||||
|
|
||||||
/// <summary> The tab to select on the next Draw call, if any. </summary>
|
|
||||||
public TabType SelectTab = TabType.None;
|
|
||||||
|
|
||||||
public ConfigTabBar(CommunicatorService communicator, SettingsTab settings, ModsTab mods, CollectionsTab collections,
|
|
||||||
ChangedItemsTab changedItems, EffectiveTab effective, DebugTab debug, ResourceTab resource, Watcher watcher,
|
|
||||||
OnScreenTab onScreen, MessagesTab messages)
|
|
||||||
{
|
|
||||||
_communicator = communicator;
|
|
||||||
|
|
||||||
Settings = settings;
|
|
||||||
Mods = mods;
|
|
||||||
Collections = collections;
|
|
||||||
ChangedItems = changedItems;
|
|
||||||
Effective = effective;
|
|
||||||
Debug = debug;
|
|
||||||
Resource = resource;
|
|
||||||
Watcher = watcher;
|
|
||||||
OnScreen = onScreen;
|
|
||||||
Messages = messages;
|
|
||||||
Tabs =
|
|
||||||
[
|
|
||||||
Settings,
|
|
||||||
Collections,
|
|
||||||
Mods,
|
|
||||||
ChangedItems,
|
|
||||||
Effective,
|
|
||||||
OnScreen,
|
|
||||||
Debug,
|
|
||||||
Resource,
|
|
||||||
Watcher,
|
|
||||||
Messages,
|
|
||||||
];
|
|
||||||
_communicator.SelectTab.Subscribe(OnSelectTab, Communication.SelectTab.Priority.ConfigTabBar);
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Dispose()
|
|
||||||
=> _communicator.SelectTab.Unsubscribe(OnSelectTab);
|
|
||||||
|
|
||||||
public TabType Draw()
|
|
||||||
{
|
|
||||||
if (TabBar.Draw(string.Empty, ImGuiTabBarFlags.NoTooltip, ToLabel(SelectTab), out var currentLabel, () => { }, Tabs))
|
|
||||||
SelectTab = TabType.None;
|
|
||||||
|
|
||||||
return FromLabel(currentLabel);
|
|
||||||
}
|
|
||||||
|
|
||||||
private ReadOnlySpan<byte> ToLabel(TabType type)
|
|
||||||
=> type switch
|
|
||||||
{
|
|
||||||
TabType.Settings => Settings.Label,
|
|
||||||
TabType.Mods => Mods.Label,
|
|
||||||
TabType.Collections => Collections.Label,
|
|
||||||
TabType.ChangedItems => ChangedItems.Label,
|
|
||||||
TabType.EffectiveChanges => Effective.Label,
|
|
||||||
TabType.OnScreen => OnScreen.Label,
|
|
||||||
TabType.ResourceWatcher => Watcher.Label,
|
|
||||||
TabType.Debug => Debug.Label,
|
|
||||||
TabType.ResourceManager => Resource.Label,
|
|
||||||
TabType.Messages => Messages.Label,
|
|
||||||
_ => ReadOnlySpan<byte>.Empty,
|
|
||||||
};
|
|
||||||
|
|
||||||
private TabType FromLabel(ReadOnlySpan<byte> label)
|
|
||||||
{
|
|
||||||
// @formatter:off
|
|
||||||
if (label == Mods.Label) return TabType.Mods;
|
|
||||||
if (label == Collections.Label) return TabType.Collections;
|
|
||||||
if (label == Settings.Label) return TabType.Settings;
|
|
||||||
if (label == ChangedItems.Label) return TabType.ChangedItems;
|
|
||||||
if (label == Effective.Label) return TabType.EffectiveChanges;
|
|
||||||
if (label == OnScreen.Label) return TabType.OnScreen;
|
|
||||||
if (label == Messages.Label) return TabType.Messages;
|
|
||||||
if (label == Watcher.Label) return TabType.ResourceWatcher;
|
|
||||||
if (label == Debug.Label) return TabType.Debug;
|
|
||||||
if (label == Resource.Label) return TabType.ResourceManager;
|
|
||||||
// @formatter:on
|
|
||||||
return TabType.None;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnSelectTab(in SelectTab.Arguments arguments)
|
|
||||||
{
|
|
||||||
SelectTab = arguments.Tab;
|
|
||||||
if (arguments.Mod is not null)
|
|
||||||
Mods.SelectMod = arguments.Mod;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
@ -14,8 +14,8 @@ using Luna;
|
||||||
using Microsoft.Extensions.DependencyInjection;
|
using Microsoft.Extensions.DependencyInjection;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
|
||||||
using Penumbra.Api;
|
using Penumbra.Api;
|
||||||
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
using Penumbra.GameData.Actors;
|
using Penumbra.GameData.Actors;
|
||||||
using Penumbra.GameData.DataContainers;
|
using Penumbra.GameData.DataContainers;
|
||||||
|
|
@ -67,7 +67,7 @@ public class Diagnostics(ServiceManager provider) : IUiService
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public class DebugTab : Window, ITab
|
public sealed class DebugTab : Window, ITab<TabType>
|
||||||
{
|
{
|
||||||
private readonly Configuration _config;
|
private readonly Configuration _config;
|
||||||
private readonly CollectionManager _collectionManager;
|
private readonly CollectionManager _collectionManager;
|
||||||
|
|
@ -173,6 +173,9 @@ public class DebugTab : Window, ITab
|
||||||
public bool IsVisible
|
public bool IsVisible
|
||||||
=> _config is { DebugMode: true, Ephemeral.DebugSeparateWindow: false };
|
=> _config is { DebugMode: true, Ephemeral.DebugSeparateWindow: false };
|
||||||
|
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.Debug;
|
||||||
|
|
||||||
#if DEBUG
|
#if DEBUG
|
||||||
private const string DebugVersionString = "(Debug)";
|
private const string DebugVersionString = "(Debug)";
|
||||||
#else
|
#else
|
||||||
|
|
|
||||||
|
|
@ -1,10 +1,11 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
using Luna;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Collections.Cache;
|
using Penumbra.Collections.Cache;
|
||||||
using Penumbra.Collections.Manager;
|
using Penumbra.Collections.Manager;
|
||||||
|
|
@ -15,12 +16,15 @@ using Penumbra.UI.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class EffectiveTab(CollectionManager collectionManager, CollectionSelectHeader collectionHeader)
|
public sealed class EffectiveTab(CollectionManager collectionManager, CollectionSelectHeader collectionHeader)
|
||||||
: ITab, Luna.IUiService
|
: ITab<TabType>
|
||||||
{
|
{
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Effective Changes"u8;
|
=> "Effective Changes"u8;
|
||||||
|
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.EffectiveChanges;
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
{
|
{
|
||||||
SetupEffectiveSizes();
|
SetupEffectiveSizes();
|
||||||
|
|
|
||||||
55
Penumbra/UI/Tabs/MainTabBar.cs
Normal file
55
Penumbra/UI/Tabs/MainTabBar.cs
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
using Luna;
|
||||||
|
using Penumbra.Api.Enums;
|
||||||
|
using Penumbra.Communication;
|
||||||
|
using Penumbra.Services;
|
||||||
|
using Penumbra.UI.Tabs.Debug;
|
||||||
|
using Watcher = Penumbra.UI.ResourceWatcher.ResourceWatcher;
|
||||||
|
|
||||||
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
|
public sealed class MainTabBar : TabBar<TabType>, IDisposable
|
||||||
|
{
|
||||||
|
public readonly ModsTab Mods;
|
||||||
|
private readonly EphemeralConfig _config;
|
||||||
|
private readonly SelectTab _selectTab;
|
||||||
|
|
||||||
|
public MainTabBar(Logger log,
|
||||||
|
SettingsTab settings,
|
||||||
|
ModsTab mods,
|
||||||
|
CollectionsTab collections,
|
||||||
|
ChangedItemsTab changedItems,
|
||||||
|
EffectiveTab effectiveChanges,
|
||||||
|
DebugTab debug,
|
||||||
|
ResourceTab resources,
|
||||||
|
Watcher watcher,
|
||||||
|
OnScreenTab onScreen,
|
||||||
|
MessagesTab messages, EphemeralConfig config, CommunicatorService communicator)
|
||||||
|
: base(nameof(MainTabBar), log, settings, collections, mods, changedItems, effectiveChanges, onScreen,
|
||||||
|
resources, watcher, debug, messages)
|
||||||
|
{
|
||||||
|
Mods = mods;
|
||||||
|
_config = config;
|
||||||
|
_selectTab = communicator.SelectTab;
|
||||||
|
|
||||||
|
_selectTab.Subscribe(OnSelectTab, SelectTab.Priority.MainTabBar);
|
||||||
|
TabSelected.Subscribe(OnTabSelected, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnSelectTab(in SelectTab.Arguments arguments)
|
||||||
|
{
|
||||||
|
NextTab = arguments.Tab;
|
||||||
|
if (arguments.Mod is not null)
|
||||||
|
Mods.SelectMod = arguments.Mod;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void Dispose()
|
||||||
|
{
|
||||||
|
_selectTab.Unsubscribe(OnSelectTab);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void OnTabSelected(in TabType type)
|
||||||
|
{
|
||||||
|
_config.SelectedTab = type;
|
||||||
|
_config.Save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
using OtterGui.Widgets;
|
using Luna;
|
||||||
using Penumbra.Services;
|
using Penumbra.Api.Enums;
|
||||||
|
using MessageService = Penumbra.Services.MessageService;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class MessagesTab(MessageService messages) : ITab, Luna.IUiService
|
public sealed class MessagesTab(MessageService messages) : ITab<TabType>
|
||||||
{
|
{
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Messages"u8;
|
=> "Messages"u8;
|
||||||
|
|
@ -13,4 +14,7 @@ public class MessagesTab(MessageService messages) : ITab, Luna.IUiService
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
=> messages.DrawNotificationLog();
|
=> messages.DrawNotificationLog();
|
||||||
|
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.Messages;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ using Dalamud.Interface;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using FFXIVClientStructs.FFXIV.Client.Game;
|
using FFXIVClientStructs.FFXIV.Client.Game;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
using OtterGui.Widgets;
|
using Luna;
|
||||||
using Penumbra.Api.Enums;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Interop.Services;
|
using Penumbra.Interop.Services;
|
||||||
using Penumbra.Mods;
|
using Penumbra.Mods;
|
||||||
|
|
@ -19,7 +19,7 @@ using Penumbra.GameData.Interop;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class ModsTab(
|
public sealed class ModsTab(
|
||||||
ModManager modManager,
|
ModManager modManager,
|
||||||
CollectionManager collectionManager,
|
CollectionManager collectionManager,
|
||||||
ModFileSystemSelector selector,
|
ModFileSystemSelector selector,
|
||||||
|
|
@ -31,7 +31,7 @@ public class ModsTab(
|
||||||
CollectionSelectHeader collectionHeader,
|
CollectionSelectHeader collectionHeader,
|
||||||
ITargetManager targets,
|
ITargetManager targets,
|
||||||
ObjectManager objects)
|
ObjectManager objects)
|
||||||
: ITab, Luna.IUiService
|
: ITab<TabType>
|
||||||
{
|
{
|
||||||
private readonly ActiveCollections _activeCollections = collectionManager.Active;
|
private readonly ActiveCollections _activeCollections = collectionManager.Active;
|
||||||
|
|
||||||
|
|
@ -41,7 +41,10 @@ public class ModsTab(
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Mods"u8;
|
=> "Mods"u8;
|
||||||
|
|
||||||
public void DrawHeader()
|
public TabType Identifier
|
||||||
|
=> TabType.Mods;
|
||||||
|
|
||||||
|
public void PostTabButton()
|
||||||
=> tutorial.OpenTutorial(BasicTutorialSteps.Mods);
|
=> tutorial.OpenTutorial(BasicTutorialSteps.Mods);
|
||||||
|
|
||||||
public Mod SelectMod
|
public Mod SelectMod
|
||||||
|
|
@ -60,7 +63,8 @@ public class ModsTab(
|
||||||
collectionHeader.Draw(false);
|
collectionHeader.Draw(false);
|
||||||
|
|
||||||
using var style = ImStyleDouble.ItemSpacing.Push(Vector2.Zero);
|
using var style = ImStyleDouble.ItemSpacing.Push(Vector2.Zero);
|
||||||
using (var child = ImRaii.Child("##ModsTabMod", Im.ContentRegion.Available with { Y = config.HideRedrawBar ? 0 : -Im.Style.FrameHeight },
|
using (var child = ImRaii.Child("##ModsTabMod",
|
||||||
|
Im.ContentRegion.Available with { Y = config.HideRedrawBar ? 0 : -Im.Style.FrameHeight },
|
||||||
true, ImGuiWindowFlags.HorizontalScrollbar))
|
true, ImGuiWindowFlags.HorizontalScrollbar))
|
||||||
{
|
{
|
||||||
style.Pop();
|
style.Pop();
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,10 @@
|
||||||
using OtterGui.Widgets;
|
using Luna;
|
||||||
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.UI.AdvancedWindow;
|
using Penumbra.UI.AdvancedWindow;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class OnScreenTab(ResourceTreeViewerFactory resourceTreeViewerFactory) : ITab, Luna.IUiService
|
public sealed class OnScreenTab(ResourceTreeViewerFactory resourceTreeViewerFactory) : ITab<TabType>
|
||||||
{
|
{
|
||||||
private readonly ResourceTreeViewer _viewer = resourceTreeViewerFactory.Create(0, delegate { }, delegate { });
|
private readonly ResourceTreeViewer _viewer = resourceTreeViewerFactory.Create(0, delegate { }, delegate { });
|
||||||
|
|
||||||
|
|
@ -12,4 +13,7 @@ public class OnScreenTab(ResourceTreeViewerFactory resourceTreeViewerFactory) :
|
||||||
|
|
||||||
public void DrawContent()
|
public void DrawContent()
|
||||||
=> _viewer.Draw();
|
=> _viewer.Draw();
|
||||||
|
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.OnScreen;
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -4,17 +4,21 @@ using FFXIVClientStructs.FFXIV.Client.System.Resource;
|
||||||
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
using FFXIVClientStructs.FFXIV.Client.System.Resource.Handle;
|
||||||
using FFXIVClientStructs.STD;
|
using FFXIVClientStructs.STD;
|
||||||
using ImSharp;
|
using ImSharp;
|
||||||
|
using Luna;
|
||||||
using OtterGui;
|
using OtterGui;
|
||||||
using OtterGui.Raii;
|
using OtterGui.Raii;
|
||||||
using OtterGui.Widgets;
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Interop.Hooks.ResourceLoading;
|
using Penumbra.Interop.Hooks.ResourceLoading;
|
||||||
using Penumbra.String.Classes;
|
using Penumbra.String.Classes;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class ResourceTab(Configuration config, ResourceManagerService resourceManager, ISigScanner sigScanner)
|
public sealed class ResourceTab(Configuration config, ResourceManagerService resourceManager, ISigScanner sigScanner)
|
||||||
: ITab, Luna.IUiService
|
: ITab<TabType>
|
||||||
{
|
{
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.ResourceManager;
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Resource Manager"u8;
|
=> "Resource Manager"u8;
|
||||||
|
|
||||||
|
|
@ -52,7 +56,8 @@ public class ResourceTab(Configuration config, ResourceManagerService resourceMa
|
||||||
private string _resourceManagerFilter = string.Empty;
|
private string _resourceManagerFilter = string.Empty;
|
||||||
|
|
||||||
/// <summary> Draw a single resource map. </summary>
|
/// <summary> Draw a single resource map. </summary>
|
||||||
private unsafe void DrawResourceMap(ResourceCategory category, uint ext, StdMap<uint, FFXIVClientStructs.Interop.Pointer<ResourceHandle>>* map)
|
private unsafe void DrawResourceMap(ResourceCategory category, uint ext,
|
||||||
|
StdMap<uint, FFXIVClientStructs.Interop.Pointer<ResourceHandle>>* map)
|
||||||
{
|
{
|
||||||
if (map == null)
|
if (map == null)
|
||||||
return;
|
return;
|
||||||
|
|
|
||||||
|
|
@ -1,7 +1,6 @@
|
||||||
using Dalamud.Bindings.ImGui;
|
using Dalamud.Bindings.ImGui;
|
||||||
using Dalamud.Interface;
|
using Dalamud.Interface;
|
||||||
using Dalamud.Interface.Components;
|
using Dalamud.Interface.Components;
|
||||||
using Dalamud.Interface.Utility;
|
|
||||||
using Dalamud.Plugin;
|
using Dalamud.Plugin;
|
||||||
using Dalamud.Plugin.Services;
|
using Dalamud.Plugin.Services;
|
||||||
using Dalamud.Utility;
|
using Dalamud.Utility;
|
||||||
|
|
@ -12,6 +11,7 @@ using OtterGui.Raii;
|
||||||
using OtterGui.Text;
|
using OtterGui.Text;
|
||||||
using OtterGui.Widgets;
|
using OtterGui.Widgets;
|
||||||
using Penumbra.Api;
|
using Penumbra.Api;
|
||||||
|
using Penumbra.Api.Enums;
|
||||||
using Penumbra.Collections;
|
using Penumbra.Collections;
|
||||||
using Penumbra.Interop;
|
using Penumbra.Interop;
|
||||||
using Penumbra.Interop.Hooks.PostProcessing;
|
using Penumbra.Interop.Hooks.PostProcessing;
|
||||||
|
|
@ -23,10 +23,13 @@ using Penumbra.UI.ModsTab;
|
||||||
|
|
||||||
namespace Penumbra.UI.Tabs;
|
namespace Penumbra.UI.Tabs;
|
||||||
|
|
||||||
public class SettingsTab : ITab, IUiService
|
public sealed class SettingsTab : ITab<TabType>
|
||||||
{
|
{
|
||||||
public const int RootDirectoryMaxLength = 64;
|
public const int RootDirectoryMaxLength = 64;
|
||||||
|
|
||||||
|
public TabType Identifier
|
||||||
|
=> TabType.Settings;
|
||||||
|
|
||||||
public ReadOnlySpan<byte> Label
|
public ReadOnlySpan<byte> Label
|
||||||
=> "Settings"u8;
|
=> "Settings"u8;
|
||||||
|
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue