Now that was a lot of work.

This commit is contained in:
Ottermandias 2024-04-26 18:43:45 +02:00
parent 297be487b5
commit 1e5ed1c414
44 changed files with 1182 additions and 766 deletions

View file

@ -17,6 +17,7 @@ using Penumbra.Mods.Groups;
using Penumbra.Mods.ItemSwap;
using Penumbra.Mods.Manager;
using Penumbra.Mods.Settings;
using Penumbra.Mods.SubMods;
using Penumbra.Services;
using Penumbra.UI.Classes;
@ -264,9 +265,10 @@ public class ItemSwapTab : IDisposable, ITab
return;
_modManager.AddMod(newDir);
if (!_swapData.WriteMod(_modManager, _modManager[^1],
var mod = _modManager[^1];
if (!_swapData.WriteMod(_modManager, mod, mod.Default,
_useFileSwaps ? ItemSwapContainer.WriteType.UseSwaps : ItemSwapContainer.WriteType.NoSwaps))
_modManager.DeleteMod(_modManager[^1]);
_modManager.DeleteMod(mod);
}
private void CreateOption()
@ -276,7 +278,7 @@ public class ItemSwapTab : IDisposable, ITab
var groupCreated = false;
var dirCreated = false;
var optionCreated = -1;
IModOption? createdOption = null;
DirectoryInfo? optionFolderName = null;
try
{
@ -290,22 +292,22 @@ public class ItemSwapTab : IDisposable, ITab
{
if (_selectedGroup == null)
{
_modManager.OptionEditor.AddModGroup(_mod, GroupType.Multi, _newGroupName);
_selectedGroup = _mod.Groups.Last();
if (_modManager.OptionEditor.AddModGroup(_mod, GroupType.Multi, _newGroupName) is not { } group)
throw new Exception($"Failure creating option group.");
_selectedGroup = group;
groupCreated = true;
}
var optionIdx = _modManager.OptionEditor.AddOption(_mod, _mod.Groups.IndexOf(_selectedGroup), _newOptionName);
if (optionIdx < 0)
if (_modManager.OptionEditor.AddOption(_selectedGroup, _newOptionName) is not { } option)
throw new Exception($"Failure creating mod option.");
optionCreated = optionIdx;
createdOption = option;
optionFolderName = Directory.CreateDirectory(optionFolderName.FullName);
dirCreated = true;
if (!_swapData.WriteMod(_modManager, _mod,
_useFileSwaps ? ItemSwapContainer.WriteType.UseSwaps : ItemSwapContainer.WriteType.NoSwaps,
optionFolderName,
_mod.Groups.IndexOf(_selectedGroup), optionIdx))
// #TODO ModOption <> DataContainer
if (!_swapData.WriteMod(_modManager, _mod, (IModDataContainer)option,
_useFileSwaps ? ItemSwapContainer.WriteType.UseSwaps : ItemSwapContainer.WriteType.NoSwaps, optionFolderName))
throw new Exception("Failure writing files for mod swap.");
}
}
@ -314,12 +316,12 @@ public class ItemSwapTab : IDisposable, ITab
Penumbra.Messager.NotificationMessage(e, "Could not create new Swap Option.", NotificationType.Error, false);
try
{
if (optionCreated >= 0 && _selectedGroup != null)
_modManager.OptionEditor.DeleteOption(_mod, _mod.Groups.IndexOf(_selectedGroup), optionCreated);
if (createdOption != null)
_modManager.OptionEditor.DeleteOption(createdOption);
if (groupCreated)
{
_modManager.OptionEditor.DeleteModGroup(_mod, _mod.Groups.IndexOf(_selectedGroup!));
_modManager.OptionEditor.DeleteModGroup(_selectedGroup!);
_selectedGroup = null;
}
@ -717,7 +719,8 @@ public class ItemSwapTab : IDisposable, ITab
_dirty = true;
}
private void OnModOptionChange(ModOptionChangeType type, Mod mod, int a, int b, int c)
private void OnModOptionChange(ModOptionChangeType type, Mod mod, IModGroup? group, IModOption? option, IModDataContainer? container,
int fromIdx)
{
if (type is ModOptionChangeType.PrepareChange or ModOptionChangeType.GroupAdded or ModOptionChangeType.OptionAdded || mod != _mod)
return;

View file

@ -27,7 +27,7 @@ public partial class ModEditWindow
private const string GenderTooltip = "Gender";
private const string ObjectTypeTooltip = "Object Type";
private const string SecondaryIdTooltip = "Secondary ID";
private const string PrimaryIDTooltip = "Primary ID";
private const string PrimaryIdTooltipShort = "Primary ID";
private const string VariantIdTooltip = "Variant ID";
private const string EstTypeTooltip = "EST Type";
private const string RacialTribeTooltip = "Racial Tribe";
@ -45,7 +45,7 @@ public partial class ModEditWindow
var tt = setsEqual ? "No changes staged." : "Apply the currently staged changes to the option.";
ImGui.NewLine();
if (ImGuiUtil.DrawDisabledButton("Apply Changes", Vector2.Zero, tt, setsEqual))
_editor.MetaEditor.Apply(_editor.Mod!, _editor.GroupIdx, _editor.DataIdx);
_editor.MetaEditor.Apply(_editor.Option!);
ImGui.SameLine();
tt = setsEqual ? "No changes staged." : "Revert all currently staged changes.";
@ -477,7 +477,7 @@ public partial class ModEditWindow
ImGui.TableNextColumn();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);
ImGui.TextUnformatted(meta.PrimaryId.ToString());
ImGuiUtil.HoverTooltip(PrimaryIDTooltip);
ImGuiUtil.HoverTooltip(PrimaryIdTooltipShort);
ImGui.TableNextColumn();
ImGui.SetCursorPosX(ImGui.GetCursorPosX() + ImGui.GetStyle().FramePadding.X);

View file

@ -455,7 +455,7 @@ public partial class ModEditWindow : Window, IDisposable
var tt = setsEqual ? "No changes staged." : "Apply the currently staged changes to the option.";
ImGui.NewLine();
if (ImGuiUtil.DrawDisabledButton("Apply Changes", Vector2.Zero, tt, setsEqual))
_editor.SwapEditor.Apply(_editor.Mod!, _editor.GroupIdx, _editor.DataIdx);
_editor.SwapEditor.Apply(_editor.Option!);
ImGui.SameLine();
tt = setsEqual ? "No changes staged." : "Revert all currently staged changes.";
@ -627,7 +627,7 @@ public partial class ModEditWindow : Window, IDisposable
public void Dispose()
{
_communicator.ModPathChanged.Unsubscribe(OnModPathChange);
_editor?.Dispose();
_editor.Dispose();
_materialTab.Dispose();
_modelTab.Dispose();
_shaderPackageTab.Dispose();

View file

@ -15,6 +15,7 @@ using Penumbra.Services;
using Penumbra.UI.AdvancedWindow;
using Penumbra.Mods.Groups;
using Penumbra.Mods.Settings;
using Penumbra.Mods.SubMods;
namespace Penumbra.UI.ModsTab;
@ -248,13 +249,13 @@ public class ModPanelEditTab(
ImGui.SameLine();
var nameValid = ModOptionEditor.VerifyFileName(mod, null, _newGroupName, false);
var nameValid = ModGroupEditor.VerifyFileName(mod, null, _newGroupName, false);
tt = nameValid ? "Add new option group to the mod." : "Can not add a group of this name.";
if (!ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Plus.ToIconString(), UiHelpers.IconButtonSize,
tt, !nameValid, true))
return;
modManager.OptionEditor.AddModGroup(mod, GroupType.Single, _newGroupName);
modManager.OptionEditor.SingleEditor.AddModGroup(mod, _newGroupName);
Reset();
}
}
@ -364,9 +365,9 @@ public class ModPanelEditTab(
break;
case >= 0:
if (_newDescriptionOptionIdx < 0)
modManager.OptionEditor.ChangeGroupDescription(_mod, _newDescriptionIdx, _newDescription);
modManager.OptionEditor.ChangeGroupDescription(_mod.Groups[_newDescriptionIdx], _newDescription);
else
modManager.OptionEditor.ChangeOptionDescription(_mod, _newDescriptionIdx, _newDescriptionOptionIdx,
modManager.OptionEditor.ChangeOptionDescription(_mod.Groups[_newDescriptionIdx].Options[_newDescriptionOptionIdx],
_newDescription);
break;
@ -396,18 +397,18 @@ public class ModPanelEditTab(
.Push(ImGuiStyleVar.ItemSpacing, _itemSpacing);
if (Input.Text("##Name", groupIdx, Input.None, group.Name, out var newGroupName, 256, UiHelpers.InputTextWidth.X))
_modManager.OptionEditor.RenameModGroup(_mod, groupIdx, newGroupName);
_modManager.OptionEditor.RenameModGroup(group, newGroupName);
ImGuiUtil.HoverTooltip("Group Name");
ImGui.SameLine();
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), UiHelpers.IconButtonSize,
"Delete this option group.\nHold Control while clicking to delete.", !ImGui.GetIO().KeyCtrl, true))
_delayedActions.Enqueue(() => _modManager.OptionEditor.DeleteModGroup(_mod, groupIdx));
_delayedActions.Enqueue(() => _modManager.OptionEditor.DeleteModGroup(group));
ImGui.SameLine();
if (Input.Priority("##Priority", groupIdx, Input.None, group.Priority, out var priority, 50 * UiHelpers.Scale))
_modManager.OptionEditor.ChangeGroupPriority(_mod, groupIdx, priority);
_modManager.OptionEditor.ChangeGroupPriority(group, priority);
ImGuiUtil.HoverTooltip("Group Priority");
@ -417,7 +418,7 @@ public class ModPanelEditTab(
var tt = groupIdx == 0 ? "Can not move this group further upwards." : $"Move this group up to group {groupIdx}.";
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.ArrowUp.ToIconString(), UiHelpers.IconButtonSize,
tt, groupIdx == 0, true))
_delayedActions.Enqueue(() => _modManager.OptionEditor.MoveModGroup(_mod, groupIdx, groupIdx - 1));
_delayedActions.Enqueue(() => _modManager.OptionEditor.MoveModGroup(group, groupIdx - 1));
ImGui.SameLine();
tt = groupIdx == _mod.Groups.Count - 1
@ -425,7 +426,7 @@ public class ModPanelEditTab(
: $"Move this group down to group {groupIdx + 2}.";
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.ArrowDown.ToIconString(), UiHelpers.IconButtonSize,
tt, groupIdx == _mod.Groups.Count - 1, true))
_delayedActions.Enqueue(() => _modManager.OptionEditor.MoveModGroup(_mod, groupIdx, groupIdx + 1));
_delayedActions.Enqueue(() => _modManager.OptionEditor.MoveModGroup(group, groupIdx + 1));
ImGui.SameLine();
@ -452,17 +453,17 @@ public class ModPanelEditTab(
{
private const string DragDropLabel = "##DragOption";
private static int _newOptionNameIdx = -1;
private static string _newOptionName = string.Empty;
private static int _dragDropGroupIdx = -1;
private static int _dragDropOptionIdx = -1;
private static int _newOptionNameIdx = -1;
private static string _newOptionName = string.Empty;
private static IModGroup? _dragDropGroup;
private static IModOption? _dragDropOption;
public static void Reset()
{
_newOptionNameIdx = -1;
_newOptionName = string.Empty;
_dragDropGroupIdx = -1;
_dragDropOptionIdx = -1;
_newOptionNameIdx = -1;
_newOptionName = string.Empty;
_dragDropGroup = null;
_dragDropOption = null;
}
public static void Draw(ModPanelEditTab panel, int groupIdx)
@ -482,7 +483,7 @@ public class ModPanelEditTab(
switch (panel._mod.Groups[groupIdx])
{
case SingleModGroup single:
case SingleModGroup single:
for (var optionIdx = 0; optionIdx < single.OptionData.Count; ++optionIdx)
EditOption(panel, single, groupIdx, optionIdx);
break;
@ -491,6 +492,7 @@ public class ModPanelEditTab(
EditOption(panel, multi, groupIdx, optionIdx);
break;
}
DrawNewOption(panel, groupIdx, UiHelpers.IconButtonSize);
}
@ -502,8 +504,8 @@ public class ModPanelEditTab(
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
ImGui.Selectable($"Option #{optionIdx + 1}");
Source(group, groupIdx, optionIdx);
Target(panel, group, groupIdx, optionIdx);
Source(option);
Target(panel, group, optionIdx);
ImGui.TableNextColumn();
@ -511,7 +513,7 @@ public class ModPanelEditTab(
if (group.Type == GroupType.Single)
{
if (ImGui.RadioButton("##default", group.DefaultSettings.AsIndex == optionIdx))
panel._modManager.OptionEditor.ChangeModGroupDefaultOption(panel._mod, groupIdx, Setting.Single(optionIdx));
panel._modManager.OptionEditor.ChangeModGroupDefaultOption(group, Setting.Single(optionIdx));
ImGuiUtil.HoverTooltip($"Set {option.Name} as the default choice for this group.");
}
@ -519,15 +521,14 @@ public class ModPanelEditTab(
{
var isDefaultOption = group.DefaultSettings.HasFlag(optionIdx);
if (ImGui.Checkbox("##default", ref isDefaultOption))
panel._modManager.OptionEditor.ChangeModGroupDefaultOption(panel._mod, groupIdx,
group.DefaultSettings.SetBit(optionIdx, isDefaultOption));
panel._modManager.OptionEditor.ChangeModGroupDefaultOption(group, group.DefaultSettings.SetBit(optionIdx, isDefaultOption));
ImGuiUtil.HoverTooltip($"{(isDefaultOption ? "Disable" : "Enable")} {option.Name} per default in this group.");
}
ImGui.TableNextColumn();
if (Input.Text("##Name", groupIdx, optionIdx, option.Name, out var newOptionName, 256, -1))
panel._modManager.OptionEditor.RenameOption(panel._mod, groupIdx, optionIdx, newOptionName);
panel._modManager.OptionEditor.RenameOption(option, newOptionName);
ImGui.TableNextColumn();
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Edit.ToIconString(), UiHelpers.IconButtonSize, "Edit option description.",
@ -537,15 +538,15 @@ public class ModPanelEditTab(
ImGui.TableNextColumn();
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Trash.ToIconString(), UiHelpers.IconButtonSize,
"Delete this option.\nHold Control while clicking to delete.", !ImGui.GetIO().KeyCtrl, true))
panel._delayedActions.Enqueue(() => panel._modManager.OptionEditor.DeleteOption(panel._mod, groupIdx, optionIdx));
panel._delayedActions.Enqueue(() => panel._modManager.OptionEditor.DeleteOption(option));
ImGui.TableNextColumn();
if (group is not MultiModGroup multi)
if (option is not MultiSubMod multi)
return;
if (Input.Priority("##Priority", groupIdx, optionIdx, multi.OptionData[optionIdx].Priority, out var priority,
if (Input.Priority("##Priority", groupIdx, optionIdx, multi.Priority, out var priority,
50 * UiHelpers.Scale))
panel._modManager.OptionEditor.ChangeOptionPriority(panel._mod, groupIdx, optionIdx, priority);
panel._modManager.OptionEditor.MultiEditor.ChangeOptionPriority(multi, priority);
ImGuiUtil.HoverTooltip("Option priority.");
}
@ -564,7 +565,7 @@ public class ModPanelEditTab(
ImGui.TableNextColumn();
ImGui.AlignTextToFramePadding();
ImGui.Selectable($"Option #{count + 1}");
Target(panel, group, groupIdx, count);
Target(panel, group, count);
ImGui.TableNextColumn();
ImGui.TableNextColumn();
ImGui.SetNextItemWidth(-1);
@ -585,14 +586,14 @@ public class ModPanelEditTab(
tt, !(canAddGroup && validName), true))
return;
panel._modManager.OptionEditor.AddOption(mod, groupIdx, _newOptionName);
panel._modManager.OptionEditor.AddOption(group, _newOptionName);
_newOptionName = string.Empty;
}
// Handle drag and drop to move options inside a group or into another group.
private static void Source(IModGroup group, int groupIdx, int optionIdx)
private static void Source(IModOption option)
{
if (group is not ITexToolsGroup)
if (option.Group is not ITexToolsGroup)
return;
using var source = ImRaii.DragDropSource();
@ -601,14 +602,14 @@ public class ModPanelEditTab(
if (ImGui.SetDragDropPayload(DragDropLabel, IntPtr.Zero, 0))
{
_dragDropGroupIdx = groupIdx;
_dragDropOptionIdx = optionIdx;
_dragDropGroup = option.Group;
_dragDropOption = option;
}
ImGui.TextUnformatted($"Dragging option {group.Options[optionIdx].Name} from group {group.Name}...");
ImGui.TextUnformatted($"Dragging option {option.Name} from group {option.Group.Name}...");
}
private static void Target(ModPanelEditTab panel, IModGroup group, int groupIdx, int optionIdx)
private static void Target(ModPanelEditTab panel, IModGroup group, int optionIdx)
{
if (group is not ITexToolsGroup)
return;
@ -617,39 +618,53 @@ public class ModPanelEditTab(
if (!target.Success || !ImGuiUtil.IsDropping(DragDropLabel))
return;
if (_dragDropGroupIdx >= 0 && _dragDropOptionIdx >= 0)
if (_dragDropGroup != null && _dragDropOption != null)
{
if (_dragDropGroupIdx == groupIdx)
if (_dragDropGroup == group)
{
var sourceOption = _dragDropOptionIdx;
var sourceOption = _dragDropOption;
panel._delayedActions.Enqueue(
() => panel._modManager.OptionEditor.MoveOption(panel._mod, groupIdx, sourceOption, optionIdx));
() => panel._modManager.OptionEditor.MoveOption(sourceOption, optionIdx));
}
else
{
// Move from one group to another by deleting, then adding, then moving the option.
var sourceGroupIdx = _dragDropGroupIdx;
var sourceOption = _dragDropOptionIdx;
var sourceGroup = panel._mod.Groups[sourceGroupIdx];
var currentCount = group.DataContainers.Count;
var option = ((ITexToolsGroup) sourceGroup).OptionData[_dragDropOptionIdx];
var sourceOption = _dragDropOption;
panel._delayedActions.Enqueue(() =>
{
panel._modManager.OptionEditor.DeleteOption(panel._mod, sourceGroupIdx, sourceOption);
panel._modManager.OptionEditor.AddOption(panel._mod, groupIdx, option);
panel._modManager.OptionEditor.MoveOption(panel._mod, groupIdx, currentCount, optionIdx);
panel._modManager.OptionEditor.DeleteOption(sourceOption);
if (panel._modManager.OptionEditor.AddOption(group, sourceOption) is { } newOption)
panel._modManager.OptionEditor.MoveOption(newOption, optionIdx);
});
}
}
_dragDropGroupIdx = -1;
_dragDropOptionIdx = -1;
_dragDropGroup = null;
_dragDropOption = null;
}
}
/// <summary> Draw a combo to select single or multi group and switch between them. </summary>
private void DrawGroupCombo(IModGroup group, int groupIdx)
{
ImGui.SetNextItemWidth(UiHelpers.InputTextWidth.X - 2 * UiHelpers.IconButtonSize.X - 2 * ImGui.GetStyle().ItemSpacing.X);
using var combo = ImRaii.Combo("##GroupType", GroupTypeName(group.Type));
if (!combo)
return;
if (ImGui.Selectable(GroupTypeName(GroupType.Single), group.Type == GroupType.Single) && group is MultiModGroup m)
_modManager.OptionEditor.MultiEditor.ChangeToSingle(m);
var canSwitchToMulti = group.Options.Count <= IModGroup.MaxMultiOptions;
using var style = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, !canSwitchToMulti);
if (ImGui.Selectable(GroupTypeName(GroupType.Multi), group.Type == GroupType.Multi) && canSwitchToMulti && group is SingleModGroup s)
_modManager.OptionEditor.SingleEditor.ChangeToMulti(s);
style.Pop();
if (!canSwitchToMulti)
ImGuiUtil.HoverTooltip($"Can not convert group to multi group since it has more than {IModGroup.MaxMultiOptions} options.");
return;
static string GroupTypeName(GroupType type)
=> type switch
{
@ -657,23 +672,6 @@ public class ModPanelEditTab(
GroupType.Multi => "Multi Group",
_ => "Unknown",
};
ImGui.SetNextItemWidth(UiHelpers.InputTextWidth.X - 2 * UiHelpers.IconButtonSize.X - 2 * ImGui.GetStyle().ItemSpacing.X);
using var combo = ImRaii.Combo("##GroupType", GroupTypeName(group.Type));
if (!combo)
return;
if (ImGui.Selectable(GroupTypeName(GroupType.Single), group.Type == GroupType.Single))
_modManager.OptionEditor.ChangeModGroupType(_mod, groupIdx, GroupType.Single);
var canSwitchToMulti = group.Options.Count <= IModGroup.MaxMultiOptions;
using var style = ImRaii.PushStyle(ImGuiStyleVar.Alpha, 0.5f, !canSwitchToMulti);
if (ImGui.Selectable(GroupTypeName(GroupType.Multi), group.Type == GroupType.Multi) && canSwitchToMulti)
_modManager.OptionEditor.ChangeModGroupType(_mod, groupIdx, GroupType.Multi);
style.Pop();
if (!canSwitchToMulti)
ImGuiUtil.HoverTooltip($"Can not convert group to multi group since it has more than {IModGroup.MaxMultiOptions} options.");
}
/// <summary> Handles input text and integers in separate fields without buffers for every single one. </summary>