Merge branch 'refs/heads/AeAstralis/tagging'

This commit is contained in:
Ottermandias 2024-03-19 21:02:04 +01:00
commit 5b9309a311
8 changed files with 317 additions and 102 deletions

View file

@ -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;

View file

@ -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") : [];
}
}

View file

@ -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
};

View file

@ -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);
}
}

View file

@ -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."

View 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];
}

View file

@ -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();

View file

@ -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);
}
}