mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-13 12:14:17 +01:00
Merge branch 'refs/heads/AeAstralis/tagging'
This commit is contained in:
commit
5b9309a311
8 changed files with 317 additions and 102 deletions
|
|
@ -45,19 +45,19 @@ public sealed class Mod : IMod
|
|||
public string Description { get; internal set; } = string.Empty;
|
||||
public string Version { get; internal set; } = string.Empty;
|
||||
public string Website { get; internal set; } = string.Empty;
|
||||
public IReadOnlyList<string> ModTags { get; internal set; } = Array.Empty<string>();
|
||||
public IReadOnlyList<string> ModTags { get; internal set; } = [];
|
||||
|
||||
|
||||
// Local Data
|
||||
public long ImportDate { get; internal set; } = DateTimeOffset.UnixEpoch.ToUnixTimeMilliseconds();
|
||||
public IReadOnlyList<string> LocalTags { get; internal set; } = Array.Empty<string>();
|
||||
public IReadOnlyList<string> LocalTags { get; internal set; } = [];
|
||||
public string Note { get; internal set; } = string.Empty;
|
||||
public bool Favorite { get; internal set; } = false;
|
||||
|
||||
|
||||
// Options
|
||||
public readonly SubMod Default;
|
||||
public readonly List<IModGroup> Groups = new();
|
||||
public readonly List<IModGroup> Groups = [];
|
||||
|
||||
ISubMod IMod.Default
|
||||
=> Default;
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@ public class FilenameService(DalamudPluginInterface pi) : IService
|
|||
public readonly string EphemeralConfigFile = Path.Combine(pi.ConfigDirectory.FullName, "ephemeral_config.json");
|
||||
public readonly string FilesystemFile = Path.Combine(pi.ConfigDirectory.FullName, "sort_order.json");
|
||||
public readonly string ActiveCollectionsFile = Path.Combine(pi.ConfigDirectory.FullName, "active_collections.json");
|
||||
public readonly string PredefinedTagFile = Path.Combine(pi.ConfigDirectory.FullName, "predefined_tags.json");
|
||||
|
||||
public readonly string CrashHandlerExe =
|
||||
Path.Combine(pi.AssemblyLocation.DirectoryName!, "Penumbra.CrashHandler.exe");
|
||||
|
|
@ -43,7 +44,7 @@ public class FilenameService(DalamudPluginInterface pi) : IService
|
|||
get
|
||||
{
|
||||
var directory = new DirectoryInfo(CollectionDirectory);
|
||||
return directory.Exists ? directory.EnumerateFiles("*.json") : Array.Empty<FileInfo>();
|
||||
return directory.Exists ? directory.EnumerateFiles("*.json") : [];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -53,7 +54,7 @@ public class FilenameService(DalamudPluginInterface pi) : IService
|
|||
get
|
||||
{
|
||||
var directory = new DirectoryInfo(LocalDataDirectory);
|
||||
return directory.Exists ? directory.EnumerateFiles("*.json") : Array.Empty<FileInfo>();
|
||||
return directory.Exists ? directory.EnumerateFiles("*.json") : [];
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,8 @@ public enum ColorId
|
|||
ResTreePlayer,
|
||||
ResTreeNetworked,
|
||||
ResTreeNonNetworked,
|
||||
PredefinedTagAdd,
|
||||
PredefinedTagRemove,
|
||||
}
|
||||
|
||||
public static class Colors
|
||||
|
|
@ -73,6 +75,8 @@ public static class Colors
|
|||
ColorId.ResTreePlayer => ( 0xFFC0FFC0, "On-Screen: Other Players", "Other players and what they own, in the On-Screen tab." ),
|
||||
ColorId.ResTreeNetworked => ( 0xFFFFFFFF, "On-Screen: Non-Players (Networked)", "Non-player entities handled by the game server, in the On-Screen tab." ),
|
||||
ColorId.ResTreeNonNetworked => ( 0xFFC0C0FF, "On-Screen: Non-Players (Local)", "Non-player entities handled locally, in the On-Screen tab." ),
|
||||
ColorId.PredefinedTagAdd => ( 0xFF44AA44, "Predefined Tags: Add Tag", "A predefined tag that is not present on the current mod and can be added." ),
|
||||
ColorId.PredefinedTagRemove => ( 0xFF2222AA, "Predefined Tags: Remove Tag", "A predefined tag that is already present on the current mod and can be removed." ),
|
||||
_ => throw new ArgumentOutOfRangeException( nameof( color ), color, null ),
|
||||
// @formatter:on
|
||||
};
|
||||
|
|
|
|||
|
|
@ -7,20 +7,15 @@ using Penumbra.Mods.Manager;
|
|||
|
||||
namespace Penumbra.UI.ModsTab;
|
||||
|
||||
public class ModPanelDescriptionTab : ITab
|
||||
public class ModPanelDescriptionTab(
|
||||
ModFileSystemSelector selector,
|
||||
TutorialService tutorial,
|
||||
ModManager modManager,
|
||||
PredefinedTagManager predefinedTagsConfig)
|
||||
: ITab
|
||||
{
|
||||
private readonly ModFileSystemSelector _selector;
|
||||
private readonly TutorialService _tutorial;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly TagButtons _localTags = new();
|
||||
private readonly TagButtons _modTags = new();
|
||||
|
||||
public ModPanelDescriptionTab(ModFileSystemSelector selector, TutorialService tutorial, ModManager modManager)
|
||||
{
|
||||
_selector = selector;
|
||||
_tutorial = tutorial;
|
||||
_modManager = modManager;
|
||||
}
|
||||
private readonly TagButtons _localTags = new();
|
||||
private readonly TagButtons _modTags = new();
|
||||
|
||||
public ReadOnlySpan<byte> Label
|
||||
=> "Description"u8;
|
||||
|
|
@ -34,22 +29,29 @@ public class ModPanelDescriptionTab : ITab
|
|||
ImGui.Dummy(ImGuiHelpers.ScaledVector2(2));
|
||||
|
||||
ImGui.Dummy(ImGuiHelpers.ScaledVector2(2));
|
||||
var (predefinedTagsEnabled, predefinedTagButtonOffset) = predefinedTagsConfig.Count > 0
|
||||
? (true, ImGui.GetFrameHeight() + ImGui.GetStyle().WindowPadding.X + (ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ScrollbarSize : 0))
|
||||
: (false, 0);
|
||||
var tagIdx = _localTags.Draw("Local Tags: ",
|
||||
"Custom tags you can set personally that will not be exported to the mod data but only set for you.\n"
|
||||
+ "If the mod already contains a local tag in its own tags, the local tag will be ignored.", _selector.Selected!.LocalTags,
|
||||
out var editedTag);
|
||||
_tutorial.OpenTutorial(BasicTutorialSteps.Tags);
|
||||
+ "If the mod already contains a local tag in its own tags, the local tag will be ignored.", selector.Selected!.LocalTags,
|
||||
out var editedTag, rightEndOffset: predefinedTagButtonOffset);
|
||||
tutorial.OpenTutorial(BasicTutorialSteps.Tags);
|
||||
if (tagIdx >= 0)
|
||||
_modManager.DataEditor.ChangeLocalTag(_selector.Selected!, tagIdx, editedTag);
|
||||
modManager.DataEditor.ChangeLocalTag(selector.Selected!, tagIdx, editedTag);
|
||||
|
||||
if (_selector.Selected!.ModTags.Count > 0)
|
||||
if (predefinedTagsEnabled)
|
||||
predefinedTagsConfig.DrawAddFromSharedTagsAndUpdateTags(selector.Selected!.LocalTags, selector.Selected!.ModTags, true,
|
||||
selector.Selected!);
|
||||
|
||||
if (selector.Selected!.ModTags.Count > 0)
|
||||
_modTags.Draw("Mod Tags: ", "Tags assigned by the mod creator and saved with the mod data. To edit these, look at Edit Mod.",
|
||||
_selector.Selected!.ModTags, out var _, false,
|
||||
selector.Selected!.ModTags, out _, false,
|
||||
ImGui.CalcTextSize("Local ").X - ImGui.CalcTextSize("Mod ").X);
|
||||
|
||||
ImGui.Dummy(ImGuiHelpers.ScaledVector2(2));
|
||||
ImGui.Separator();
|
||||
|
||||
ImGuiUtil.TextWrapped(_selector.Selected!.Description);
|
||||
ImGuiUtil.TextWrapped(selector.Selected!.Description);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -17,17 +17,20 @@ using Penumbra.UI.AdvancedWindow;
|
|||
|
||||
namespace Penumbra.UI.ModsTab;
|
||||
|
||||
public class ModPanelEditTab : ITab
|
||||
public class ModPanelEditTab(
|
||||
ModManager modManager,
|
||||
ModFileSystemSelector selector,
|
||||
ModFileSystem fileSystem,
|
||||
Services.MessageService messager,
|
||||
ModEditWindow editWindow,
|
||||
ModEditor editor,
|
||||
FilenameService filenames,
|
||||
ModExportManager modExportManager,
|
||||
Configuration config,
|
||||
PredefinedTagManager predefinedTagManager)
|
||||
: ITab
|
||||
{
|
||||
private readonly Services.MessageService _messager;
|
||||
private readonly FilenameService _filenames;
|
||||
private readonly ModManager _modManager;
|
||||
private readonly ModExportManager _modExportManager;
|
||||
private readonly ModFileSystem _fileSystem;
|
||||
private readonly ModFileSystemSelector _selector;
|
||||
private readonly ModEditWindow _editWindow;
|
||||
private readonly ModEditor _editor;
|
||||
private readonly Configuration _config;
|
||||
private readonly ModManager _modManager = modManager;
|
||||
|
||||
private readonly TagButtons _modTags = new();
|
||||
|
||||
|
|
@ -36,20 +39,6 @@ public class ModPanelEditTab : ITab
|
|||
private ModFileSystem.Leaf _leaf = null!;
|
||||
private Mod _mod = null!;
|
||||
|
||||
public ModPanelEditTab(ModManager modManager, ModFileSystemSelector selector, ModFileSystem fileSystem, Services.MessageService messager,
|
||||
ModEditWindow editWindow, ModEditor editor, FilenameService filenames, ModExportManager modExportManager, Configuration config)
|
||||
{
|
||||
_modManager = modManager;
|
||||
_selector = selector;
|
||||
_fileSystem = fileSystem;
|
||||
_messager = messager;
|
||||
_editWindow = editWindow;
|
||||
_editor = editor;
|
||||
_filenames = filenames;
|
||||
_modExportManager = modExportManager;
|
||||
_config = config;
|
||||
}
|
||||
|
||||
public ReadOnlySpan<byte> Label
|
||||
=> "Edit Mod"u8;
|
||||
|
||||
|
|
@ -59,8 +48,8 @@ public class ModPanelEditTab : ITab
|
|||
if (!child)
|
||||
return;
|
||||
|
||||
_leaf = _selector.SelectedLeaf!;
|
||||
_mod = _selector.Selected!;
|
||||
_leaf = selector.SelectedLeaf!;
|
||||
_mod = selector.Selected!;
|
||||
|
||||
_cellPadding = ImGui.GetStyle().CellPadding with { X = 2 * UiHelpers.Scale };
|
||||
_itemSpacing = ImGui.GetStyle().CellPadding with { X = 4 * UiHelpers.Scale };
|
||||
|
|
@ -72,21 +61,27 @@ public class ModPanelEditTab : ITab
|
|||
if (Input.Text("Mod Path", Input.Path, Input.None, _leaf.FullName(), out var newPath, 256, UiHelpers.InputTextWidth.X))
|
||||
try
|
||||
{
|
||||
_fileSystem.RenameAndMove(_leaf, newPath);
|
||||
fileSystem.RenameAndMove(_leaf, newPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
_messager.NotificationMessage(e.Message, NotificationType.Warning, false);
|
||||
messager.NotificationMessage(e.Message, NotificationType.Warning, false);
|
||||
}
|
||||
|
||||
UiHelpers.DefaultLineSpace();
|
||||
var sharedTagsEnabled = predefinedTagManager.Count > 0;
|
||||
var sharedTagButtonOffset = sharedTagsEnabled ? ImGui.GetFrameHeight() + ImGui.GetStyle().FramePadding.X : 0;
|
||||
var tagIdx = _modTags.Draw("Mod Tags: ", "Edit tags by clicking them, or add new tags. Empty tags are removed.", _mod.ModTags,
|
||||
out var editedTag);
|
||||
out var editedTag, rightEndOffset: sharedTagButtonOffset);
|
||||
if (tagIdx >= 0)
|
||||
_modManager.DataEditor.ChangeModTag(_mod, tagIdx, editedTag);
|
||||
|
||||
if (sharedTagsEnabled)
|
||||
predefinedTagManager.DrawAddFromSharedTagsAndUpdateTags(selector.Selected!.LocalTags, selector.Selected!.ModTags, false,
|
||||
selector.Selected!);
|
||||
|
||||
UiHelpers.DefaultLineSpace();
|
||||
AddOptionGroup.Draw(_filenames, _modManager, _mod, _config.ReplaceNonAsciiOnImport);
|
||||
AddOptionGroup.Draw(filenames, _modManager, _mod, config.ReplaceNonAsciiOnImport);
|
||||
UiHelpers.DefaultLineSpace();
|
||||
|
||||
for (var groupIdx = 0; groupIdx < _mod.Groups.Count; ++groupIdx)
|
||||
|
|
@ -134,11 +129,11 @@ public class ModPanelEditTab : ITab
|
|||
{
|
||||
if (ImGui.Button("Update Bibo Material", buttonSize))
|
||||
{
|
||||
_editor.LoadMod(_mod);
|
||||
_editor.MdlMaterialEditor.ReplaceAllMaterials("bibo", "b");
|
||||
_editor.MdlMaterialEditor.ReplaceAllMaterials("bibopube", "c");
|
||||
_editor.MdlMaterialEditor.SaveAllModels(_editor.Compactor);
|
||||
_editWindow.UpdateModels();
|
||||
editor.LoadMod(_mod);
|
||||
editor.MdlMaterialEditor.ReplaceAllMaterials("bibo", "b");
|
||||
editor.MdlMaterialEditor.ReplaceAllMaterials("bibopube", "c");
|
||||
editor.MdlMaterialEditor.SaveAllModels(editor.Compactor);
|
||||
editWindow.UpdateModels();
|
||||
}
|
||||
|
||||
ImGuiUtil.HoverTooltip(
|
||||
|
|
@ -150,7 +145,7 @@ public class ModPanelEditTab : ITab
|
|||
|
||||
private void BackupButtons(Vector2 buttonSize)
|
||||
{
|
||||
var backup = new ModBackup(_modExportManager, _mod);
|
||||
var backup = new ModBackup(modExportManager, _mod);
|
||||
var tt = ModBackup.CreatingBackup
|
||||
? "Already exporting a mod."
|
||||
: backup.Exists
|
||||
|
|
@ -161,16 +156,16 @@ public class ModPanelEditTab : ITab
|
|||
|
||||
ImGui.SameLine();
|
||||
tt = backup.Exists
|
||||
? $"Delete existing mod export \"{backup.Name}\" (hold {_config.DeleteModModifier} while clicking)."
|
||||
? $"Delete existing mod export \"{backup.Name}\" (hold {config.DeleteModModifier} while clicking)."
|
||||
: $"Exported mod \"{backup.Name}\" does not exist.";
|
||||
if (ImGuiUtil.DrawDisabledButton("Delete Export", buttonSize, tt, !backup.Exists || !_config.DeleteModModifier.IsActive()))
|
||||
if (ImGuiUtil.DrawDisabledButton("Delete Export", buttonSize, tt, !backup.Exists || !config.DeleteModModifier.IsActive()))
|
||||
backup.Delete();
|
||||
|
||||
tt = backup.Exists
|
||||
? $"Restore mod from exported file \"{backup.Name}\" (hold {_config.DeleteModModifier} while clicking)."
|
||||
? $"Restore mod from exported file \"{backup.Name}\" (hold {config.DeleteModModifier} while clicking)."
|
||||
: $"Exported mod \"{backup.Name}\" does not exist.";
|
||||
ImGui.SameLine();
|
||||
if (ImGuiUtil.DrawDisabledButton("Restore From Export", buttonSize, tt, !backup.Exists || !_config.DeleteModModifier.IsActive()))
|
||||
if (ImGuiUtil.DrawDisabledButton("Restore From Export", buttonSize, tt, !backup.Exists || !config.DeleteModModifier.IsActive()))
|
||||
backup.Restore(_modManager);
|
||||
if (backup.Exists)
|
||||
{
|
||||
|
|
@ -208,13 +203,13 @@ public class ModPanelEditTab : ITab
|
|||
_delayedActions.Enqueue(() => DescriptionEdit.OpenPopup(_mod, Input.Description));
|
||||
|
||||
ImGui.SameLine();
|
||||
var fileExists = File.Exists(_filenames.ModMetaPath(_mod));
|
||||
var fileExists = File.Exists(filenames.ModMetaPath(_mod));
|
||||
var tt = fileExists
|
||||
? "Open the metadata json file in the text editor of your choice."
|
||||
: "The metadata json file does not exist.";
|
||||
if (ImGuiUtil.DrawDisabledButton($"{FontAwesomeIcon.FileExport.ToIconString()}##metaFile", UiHelpers.IconButtonSize, tt,
|
||||
!fileExists, true))
|
||||
Process.Start(new ProcessStartInfo(_filenames.ModMetaPath(_mod)) { UseShellExecute = true });
|
||||
Process.Start(new ProcessStartInfo(filenames.ModMetaPath(_mod)) { UseShellExecute = true });
|
||||
}
|
||||
|
||||
/// <summary> Do some edits outside of iterations. </summary>
|
||||
|
|
@ -438,7 +433,7 @@ public class ModPanelEditTab : ITab
|
|||
_delayedActions.Enqueue(() => DescriptionEdit.OpenPopup(_mod, groupIdx));
|
||||
|
||||
ImGui.SameLine();
|
||||
var fileName = _filenames.OptionGroupFile(_mod, groupIdx, _config.ReplaceNonAsciiOnImport);
|
||||
var fileName = filenames.OptionGroupFile(_mod, groupIdx, config.ReplaceNonAsciiOnImport);
|
||||
var fileExists = File.Exists(fileName);
|
||||
tt = fileExists
|
||||
? $"Open the {group.Name} json file in the text editor of your choice."
|
||||
|
|
|
|||
194
Penumbra/UI/PredefinedTagManager.cs
Normal file
194
Penumbra/UI/PredefinedTagManager.cs
Normal file
|
|
@ -0,0 +1,194 @@
|
|||
using Dalamud.Interface;
|
||||
using Dalamud.Interface.Internal.Notifications;
|
||||
using ImGuiNET;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Linq;
|
||||
using OtterGui;
|
||||
using OtterGui.Classes;
|
||||
using OtterGui.Raii;
|
||||
using Penumbra.Mods.Manager;
|
||||
using Penumbra.Services;
|
||||
using Penumbra.UI.Classes;
|
||||
using ErrorEventArgs = Newtonsoft.Json.Serialization.ErrorEventArgs;
|
||||
|
||||
namespace Penumbra.UI;
|
||||
|
||||
public sealed class PredefinedTagManager : ISavable, IReadOnlyList<string>
|
||||
{
|
||||
public const int Version = 1;
|
||||
|
||||
public record struct TagData
|
||||
{ }
|
||||
|
||||
private readonly ModManager _modManager;
|
||||
private readonly SaveService _saveService;
|
||||
|
||||
private bool _isListOpen = false;
|
||||
private uint _enabledColor;
|
||||
private uint _disabledColor;
|
||||
|
||||
private readonly SortedList<string, TagData> _predefinedTags = [];
|
||||
|
||||
public PredefinedTagManager(ModManager modManager, SaveService saveService)
|
||||
{
|
||||
_modManager = modManager;
|
||||
_saveService = saveService;
|
||||
Load();
|
||||
}
|
||||
|
||||
public string ToFilename(FilenameService fileNames)
|
||||
=> fileNames.PredefinedTagFile;
|
||||
|
||||
public void Save(StreamWriter writer)
|
||||
{
|
||||
using var jWriter = new JsonTextWriter(writer);
|
||||
jWriter.Formatting = Formatting.Indented;
|
||||
var jObj = new JObject()
|
||||
{
|
||||
["Version"] = Version,
|
||||
["Tags"] = JObject.FromObject(_predefinedTags),
|
||||
};
|
||||
jObj.WriteTo(jWriter);
|
||||
}
|
||||
|
||||
public void Save()
|
||||
=> _saveService.DelaySave(this, TimeSpan.FromSeconds(5));
|
||||
|
||||
private void Load()
|
||||
{
|
||||
if (!File.Exists(_saveService.FileNames.PredefinedTagFile))
|
||||
return;
|
||||
|
||||
try
|
||||
{
|
||||
var text = File.ReadAllText(_saveService.FileNames.PredefinedTagFile);
|
||||
var jObj = JObject.Parse(text);
|
||||
var version = jObj["Version"]?.ToObject<int>() ?? 0;
|
||||
switch (version)
|
||||
{
|
||||
case 1:
|
||||
var tags = jObj["Tags"]?.ToObject<Dictionary<string, TagData>>() ?? [];
|
||||
foreach (var (tag, data) in tags)
|
||||
_predefinedTags.TryAdd(tag, data);
|
||||
break;
|
||||
default:
|
||||
throw new Exception($"Invalid version {version}.");
|
||||
}
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Penumbra.Messager.NotificationMessage(ex,
|
||||
"Error reading predefined tags Configuration, reverting to default.",
|
||||
"Error reading predefined tags Configuration", NotificationType.Error);
|
||||
}
|
||||
}
|
||||
|
||||
public void ChangeSharedTag(int tagIdx, string tag)
|
||||
{
|
||||
if (tagIdx < 0 || tagIdx > _predefinedTags.Count)
|
||||
return;
|
||||
|
||||
if (tagIdx != _predefinedTags.Count)
|
||||
_predefinedTags.RemoveAt(tagIdx);
|
||||
|
||||
if (!string.IsNullOrEmpty(tag))
|
||||
_predefinedTags.TryAdd(tag, default);
|
||||
|
||||
Save();
|
||||
}
|
||||
|
||||
public void DrawAddFromSharedTagsAndUpdateTags(IReadOnlyCollection<string> localTags, IReadOnlyCollection<string> modTags, bool editLocal,
|
||||
Mods.Mod mod)
|
||||
{
|
||||
DrawToggleButton();
|
||||
if (!DrawList(localTags, modTags, editLocal, out var changedTag, out var index))
|
||||
return;
|
||||
|
||||
if (editLocal)
|
||||
_modManager.DataEditor.ChangeLocalTag(mod, index, changedTag);
|
||||
else
|
||||
_modManager.DataEditor.ChangeModTag(mod, index, changedTag);
|
||||
}
|
||||
|
||||
private void DrawToggleButton()
|
||||
{
|
||||
ImGui.SameLine(ImGui.GetContentRegionMax().X
|
||||
- ImGui.GetFrameHeight()
|
||||
- (ImGui.GetScrollMaxY() > 0 ? ImGui.GetStyle().ItemInnerSpacing.X : 0));
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Button, ImGui.GetColorU32(ImGuiCol.ButtonActive), _isListOpen);
|
||||
if (ImGuiUtil.DrawDisabledButton(FontAwesomeIcon.Tags.ToIconString(), new Vector2(ImGui.GetFrameHeight()),
|
||||
"Add Predefined Tags...", false, true))
|
||||
_isListOpen = !_isListOpen;
|
||||
}
|
||||
|
||||
private bool DrawList(IReadOnlyCollection<string> localTags, IReadOnlyCollection<string> modTags, bool editLocal, out string changedTag,
|
||||
out int changedIndex)
|
||||
{
|
||||
changedTag = string.Empty;
|
||||
changedIndex = -1;
|
||||
|
||||
if (!_isListOpen)
|
||||
return false;
|
||||
|
||||
ImGui.TextUnformatted("Predefined Tags");
|
||||
ImGui.Separator();
|
||||
|
||||
var ret = false;
|
||||
_enabledColor = ColorId.PredefinedTagAdd.Value();
|
||||
_disabledColor = ColorId.PredefinedTagRemove.Value();
|
||||
var (edited, others) = editLocal ? (localTags, modTags) : (modTags, localTags);
|
||||
foreach (var (tag, idx) in _predefinedTags.Keys.WithIndex())
|
||||
{
|
||||
var tagIdx = edited.IndexOf(tag);
|
||||
var inOther = tagIdx < 0 && others.IndexOf(tag) >= 0;
|
||||
if (DrawColoredButton(tag, idx, tagIdx, inOther))
|
||||
{
|
||||
(changedTag, changedIndex) = tagIdx >= 0 ? (string.Empty, tagIdx) : (tag, edited.Count);
|
||||
ret = true;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
}
|
||||
|
||||
ImGui.NewLine();
|
||||
ImGui.Separator();
|
||||
return ret;
|
||||
}
|
||||
|
||||
private bool DrawColoredButton(string buttonLabel, int index, int tagIdx, bool inOther)
|
||||
{
|
||||
using var id = ImRaii.PushId(index);
|
||||
var buttonWidth = CalcTextButtonWidth(buttonLabel);
|
||||
// Prevent adding a new tag past the right edge of the popup
|
||||
if (buttonWidth + ImGui.GetStyle().ItemSpacing.X >= ImGui.GetContentRegionAvail().X)
|
||||
ImGui.NewLine();
|
||||
|
||||
bool ret;
|
||||
using (ImRaii.Disabled(inOther))
|
||||
{
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Button, tagIdx >= 0 || inOther ? _disabledColor : _enabledColor);
|
||||
ret = ImGui.Button(buttonLabel);
|
||||
}
|
||||
|
||||
if (inOther && ImGui.IsItemHovered(ImGuiHoveredFlags.AllowWhenDisabled))
|
||||
ImGui.SetTooltip("This tag is already present in the other set of tags.");
|
||||
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static float CalcTextButtonWidth(string text)
|
||||
=> ImGui.CalcTextSize(text).X + 2 * ImGui.GetStyle().FramePadding.X;
|
||||
|
||||
public IEnumerator<string> GetEnumerator()
|
||||
=> _predefinedTags.Keys.GetEnumerator();
|
||||
|
||||
IEnumerator IEnumerable.GetEnumerator()
|
||||
=> GetEnumerator();
|
||||
|
||||
public int Count
|
||||
=> _predefinedTags.Count;
|
||||
|
||||
public string this[int index]
|
||||
=> _predefinedTags.Keys[index];
|
||||
}
|
||||
|
|
@ -110,7 +110,7 @@ public class ModsTab(
|
|||
var frameColor = ImGui.GetColorU32(ImGuiCol.FrameBg);
|
||||
using (var _ = ImRaii.Group())
|
||||
{
|
||||
using (var font = ImRaii.PushFont(UiBuilder.IconFont))
|
||||
using (ImRaii.PushFont(UiBuilder.IconFont))
|
||||
{
|
||||
ImGuiUtil.DrawTextButton(FontAwesomeIcon.InfoCircle.ToIconString(), frameHeight, frameColor);
|
||||
ImGui.SameLine();
|
||||
|
|
|
|||
|
|
@ -42,15 +42,18 @@ public class SettingsTab : ITab
|
|||
private readonly DalamudConfigService _dalamudConfig;
|
||||
private readonly DalamudPluginInterface _pluginInterface;
|
||||
private readonly IDataManager _gameData;
|
||||
private readonly PredefinedTagManager _predefinedTagManager;
|
||||
|
||||
private int _minimumX = int.MaxValue;
|
||||
private int _minimumY = int.MaxValue;
|
||||
|
||||
private readonly TagButtons _sharedTags = new();
|
||||
|
||||
public SettingsTab(DalamudPluginInterface pluginInterface, Configuration config, FontReloader fontReloader, TutorialService tutorial,
|
||||
Penumbra penumbra, FileDialogService fileDialog, ModManager modManager, ModFileSystemSelector selector,
|
||||
CharacterUtility characterUtility, ResidentResourceManager residentResources, ModExportManager modExportManager, HttpApi httpApi,
|
||||
DalamudSubstitutionProvider dalamudSubstitutionProvider, FileCompactor compactor, DalamudConfigService dalamudConfig,
|
||||
IDataManager gameData)
|
||||
IDataManager gameData, PredefinedTagManager predefinedTagConfig)
|
||||
{
|
||||
_pluginInterface = pluginInterface;
|
||||
_config = config;
|
||||
|
|
@ -70,6 +73,7 @@ public class SettingsTab : ITab
|
|||
_gameData = gameData;
|
||||
if (_compactor.CanCompact)
|
||||
_compactor.Enabled = _config.UseFileSystemCompression;
|
||||
_predefinedTagManager = predefinedTagConfig;
|
||||
}
|
||||
|
||||
public void DrawHeader()
|
||||
|
|
@ -96,6 +100,7 @@ public class SettingsTab : ITab
|
|||
|
||||
DrawGeneralSettings();
|
||||
DrawColorSettings();
|
||||
DrawPredefinedTagsSection();
|
||||
DrawAdvancedSettings();
|
||||
DrawSupportButtons();
|
||||
}
|
||||
|
|
@ -222,37 +227,38 @@ public class SettingsTab : ITab
|
|||
if (_newModDirectory.IsNullOrEmpty())
|
||||
_newModDirectory = _config.ModDirectory;
|
||||
|
||||
using var group = ImRaii.Group();
|
||||
ImGui.SetNextItemWidth(UiHelpers.InputTextMinusButton3);
|
||||
bool save;
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, !_modManager.Valid))
|
||||
{
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder)
|
||||
.Push(ImGuiCol.TextDisabled, Colors.RegexWarningBorder, !_modManager.Valid);
|
||||
save = ImGui.InputTextWithHint("##rootDirectory", "Enter Root Directory here (MANDATORY)...", ref _newModDirectory,
|
||||
RootDirectoryMaxLength, ImGuiInputTextFlags.EnterReturnsTrue);
|
||||
bool save, selected;
|
||||
using (ImRaii.Group())
|
||||
{
|
||||
ImGui.SetNextItemWidth(UiHelpers.InputTextMinusButton3);
|
||||
using (ImRaii.PushStyle(ImGuiStyleVar.FrameBorderSize, ImGuiHelpers.GlobalScale, !_modManager.Valid))
|
||||
{
|
||||
using var color = ImRaii.PushColor(ImGuiCol.Border, Colors.RegexWarningBorder)
|
||||
.Push(ImGuiCol.TextDisabled, Colors.RegexWarningBorder, !_modManager.Valid);
|
||||
save = ImGui.InputTextWithHint("##rootDirectory", "Enter Root Directory here (MANDATORY)...", ref _newModDirectory,
|
||||
RootDirectoryMaxLength, ImGuiInputTextFlags.EnterReturnsTrue);
|
||||
}
|
||||
|
||||
selected = ImGui.IsItemActive();
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(UiHelpers.ScaleX3, 0));
|
||||
ImGui.SameLine();
|
||||
DrawDirectoryPickerButton();
|
||||
style.Pop();
|
||||
ImGui.SameLine();
|
||||
|
||||
const string tt = "This is where Penumbra will store your extracted mod files.\n"
|
||||
+ "TTMP files are not copied, just extracted.\n"
|
||||
+ "This directory needs to be accessible and you need write access here.\n"
|
||||
+ "It is recommended that this directory is placed on a fast hard drive, preferably an SSD.\n"
|
||||
+ "It should also be placed near the root of a logical drive - the shorter the total path to this folder, the better.\n"
|
||||
+ "Definitely do not place it in your Dalamud directory or any sub-directory thereof.";
|
||||
ImGuiComponents.HelpMarker(tt);
|
||||
_tutorial.OpenTutorial(BasicTutorialSteps.GeneralTooltips);
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("Root Directory");
|
||||
ImGuiUtil.HoverTooltip(tt);
|
||||
}
|
||||
|
||||
var selected = ImGui.IsItemActive();
|
||||
using var style = ImRaii.PushStyle(ImGuiStyleVar.ItemSpacing, new Vector2(UiHelpers.ScaleX3, 0));
|
||||
ImGui.SameLine();
|
||||
DrawDirectoryPickerButton();
|
||||
style.Pop();
|
||||
ImGui.SameLine();
|
||||
|
||||
const string tt = "This is where Penumbra will store your extracted mod files.\n"
|
||||
+ "TTMP files are not copied, just extracted.\n"
|
||||
+ "This directory needs to be accessible and you need write access here.\n"
|
||||
+ "It is recommended that this directory is placed on a fast hard drive, preferably an SSD.\n"
|
||||
+ "It should also be placed near the root of a logical drive - the shorter the total path to this folder, the better.\n"
|
||||
+ "Definitely do not place it in your Dalamud directory or any sub-directory thereof.";
|
||||
ImGuiComponents.HelpMarker(tt);
|
||||
_tutorial.OpenTutorial(BasicTutorialSteps.GeneralTooltips);
|
||||
ImGui.SameLine();
|
||||
ImGui.TextUnformatted("Root Directory");
|
||||
ImGuiUtil.HoverTooltip(tt);
|
||||
|
||||
group.Dispose();
|
||||
_tutorial.OpenTutorial(BasicTutorialSteps.ModDirectory);
|
||||
ImGui.SameLine();
|
||||
var pos = ImGui.GetCursorPosX();
|
||||
|
|
@ -383,7 +389,7 @@ public class SettingsTab : ITab
|
|||
"Hide the Penumbra main window when you manually hide the in-game user interface.", _config.HideUiWhenUiHidden,
|
||||
v =>
|
||||
{
|
||||
_config.HideUiWhenUiHidden = v;
|
||||
_config.HideUiWhenUiHidden = v;
|
||||
_pluginInterface.UiBuilder.DisableUserUiHide = !v;
|
||||
});
|
||||
Checkbox("Hide Config Window when in Cutscenes",
|
||||
|
|
@ -680,7 +686,7 @@ public class SettingsTab : ITab
|
|||
foreach (var color in Enum.GetValues<ColorId>())
|
||||
{
|
||||
var (defaultColor, name, description) = color.Data();
|
||||
var currentColor = _config.Colors.TryGetValue(color, out var current) ? current : defaultColor;
|
||||
var currentColor = _config.Colors.GetValueOrDefault(color, defaultColor);
|
||||
if (Widget.ColorPicker(name, description, currentColor, c => _config.Colors[color] = c, defaultColor))
|
||||
_config.Save();
|
||||
}
|
||||
|
|
@ -866,7 +872,7 @@ public class SettingsTab : ITab
|
|||
if (!_dalamudConfig.GetDalamudConfig(DalamudConfigService.WaitingForPluginsOption, out bool value))
|
||||
{
|
||||
using var disabled = ImRaii.Disabled();
|
||||
Checkbox("Wait for Plugins on Startup (Disabled, can not access Dalamud Configuration)", string.Empty, false, v => { });
|
||||
Checkbox("Wait for Plugins on Startup (Disabled, can not access Dalamud Configuration)", string.Empty, false, _ => { });
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -911,4 +917,17 @@ public class SettingsTab : ITab
|
|||
if (ImGui.Button("Show Changelogs", new Vector2(width, 0)))
|
||||
_penumbra.ForceChangelogOpen();
|
||||
}
|
||||
|
||||
private void DrawPredefinedTagsSection()
|
||||
{
|
||||
if (!ImGui.CollapsingHeader("Tags"))
|
||||
return;
|
||||
|
||||
var tagIdx = _sharedTags.Draw("Predefined Tags: ",
|
||||
"Predefined tags that can be added or removed from mods with a single click.", _predefinedTagManager,
|
||||
out var editedTag);
|
||||
|
||||
if (tagIdx >= 0)
|
||||
_predefinedTagManager.ChangeSharedTag(tagIdx, editedTag);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue