mirror of
https://github.com/xivdev/Penumbra.git
synced 2025-12-12 10:17:22 +01:00
Complete refactoring of interface code. Addition of 'Enable Mods' checkmark, that just (de)activates all mods at once without changing settings. Allow editing of mod json inside the interface in advanced mode.
This commit is contained in:
parent
5462bb6f05
commit
7e51e663ec
20 changed files with 2274 additions and 872 deletions
|
|
@ -1,5 +1,8 @@
|
|||
using System.Collections.Generic;
|
||||
using Newtonsoft.Json;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace Penumbra.Models
|
||||
{
|
||||
|
|
@ -22,5 +25,21 @@ namespace Penumbra.Models
|
|||
|
||||
[JsonIgnore]
|
||||
public bool HasGroupWithConfig { get; set; } = false;
|
||||
|
||||
public static ModMeta LoadFromFile(string filePath)
|
||||
{
|
||||
try
|
||||
{
|
||||
var meta = JsonConvert.DeserializeObject< ModMeta >( File.ReadAllText( filePath ) );
|
||||
meta.HasGroupWithConfig = meta.Groups != null && meta.Groups.Count > 0
|
||||
&& meta.Groups.Values.Any( G => G.SelectionType == SelectType.Multi || G.Options.Count > 1);
|
||||
return meta;
|
||||
}
|
||||
catch( Exception)
|
||||
{
|
||||
return null;
|
||||
// todo: handle broken mods properly
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -64,21 +64,7 @@ namespace Penumbra.Mods
|
|||
continue;
|
||||
}
|
||||
|
||||
ModMeta meta;
|
||||
|
||||
try
|
||||
{
|
||||
meta = JsonConvert.DeserializeObject< ModMeta >( File.ReadAllText( metaFile.FullName ) );
|
||||
meta.HasGroupWithConfig = meta.Groups != null && meta.Groups.Count > 0
|
||||
&& meta.Groups.Values.Any( G => G.SelectionType == SelectType.Multi || G.Options.Count > 1);
|
||||
}
|
||||
catch( Exception e )
|
||||
{
|
||||
PluginLog.Error( e, "failed to parse mod info, attempting basic load for: {FilePath}", metaFile.FullName );
|
||||
continue;
|
||||
|
||||
// todo: handle broken mods properly
|
||||
}
|
||||
var meta = ModMeta.LoadFromFile(metaFile.FullName);
|
||||
|
||||
var mod = new ResourceMod
|
||||
{
|
||||
|
|
|
|||
|
|
@ -109,6 +109,9 @@ namespace Penumbra.Mods
|
|||
ResolvedFiles.Clear();
|
||||
SwappedFiles.Clear();
|
||||
|
||||
if (!_plugin.Configuration.IsEnabled)
|
||||
return;
|
||||
|
||||
var registeredFiles = new Dictionary< string, string >();
|
||||
|
||||
foreach( var (mod, settings) in Mods.GetOrderedAndEnabledModListWithSettings( _plugin.Configuration.InvertModListOrder ) )
|
||||
|
|
|
|||
|
|
@ -124,7 +124,7 @@ namespace Penumbra
|
|||
return;
|
||||
}
|
||||
|
||||
SettingsInterface.Visible = !SettingsInterface.Visible;
|
||||
SettingsInterface.FlipVisibility();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
130
Penumbra/UI/ImGuiFramedGroup.cs
Normal file
130
Penumbra/UI/ImGuiFramedGroup.cs
Normal file
|
|
@ -0,0 +1,130 @@
|
|||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Numerics;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public static partial class ImGuiCustom
|
||||
{
|
||||
public static void BeginFramedGroup(string label) => BeginFramedGroupInternal(ref label, ZeroVector, false);
|
||||
public static void BeginFramedGroup(string label, Vector2 minSize) => BeginFramedGroupInternal(ref label, minSize, false);
|
||||
|
||||
public static bool BeginFramedGroupEdit(ref string label) => BeginFramedGroupInternal(ref label, ZeroVector, true);
|
||||
public static bool BeginFramedGroupEdit(ref string label, Vector2 minSize) => BeginFramedGroupInternal(ref label, minSize, true);
|
||||
|
||||
private static bool BeginFramedGroupInternal(ref string label, Vector2 minSize, bool edit)
|
||||
{
|
||||
var itemSpacing = ImGui.GetStyle().ItemSpacing;
|
||||
var frameHeight = ImGui.GetFrameHeight();
|
||||
var halfFrameHeight = new Vector2(ImGui.GetFrameHeight() / 2, 0);
|
||||
|
||||
ImGui.BeginGroup(); // First group
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ZeroVector);
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ZeroVector);
|
||||
|
||||
ImGui.BeginGroup(); // Second group
|
||||
|
||||
var effectiveSize = minSize;
|
||||
if (effectiveSize.X < 0)
|
||||
effectiveSize.X = ImGui.GetContentRegionAvail().X;
|
||||
|
||||
// Ensure width.
|
||||
ImGui.Dummy(new(effectiveSize.X, 0));
|
||||
// Ensure left half boundary width/distance.
|
||||
ImGui.Dummy(halfFrameHeight);
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.BeginGroup(); // Third group.
|
||||
// Ensure right half of boundary width/distance
|
||||
ImGui.Dummy(halfFrameHeight);
|
||||
|
||||
// Label block
|
||||
ImGui.SameLine();
|
||||
var ret = false;
|
||||
if (edit)
|
||||
ret = ImGuiCustom.ResizingTextInput(ref label, 1024);
|
||||
else
|
||||
ImGui.TextUnformatted(label);
|
||||
|
||||
var labelMin = ImGui.GetItemRectMin();
|
||||
var labelMax = ImGui.GetItemRectMax();
|
||||
ImGui.SameLine();
|
||||
// Ensure height and distance to label.
|
||||
ImGui.Dummy(new Vector2(0, frameHeight + itemSpacing.Y));
|
||||
|
||||
ImGui.BeginGroup(); // Fourth Group.
|
||||
|
||||
ImGui.PopStyleVar(2);
|
||||
|
||||
ImGui.SetWindowSize(new Vector2(ImGui.GetWindowSize().X - frameHeight, ImGui.GetWindowSize().Y));
|
||||
|
||||
var itemWidth = ImGui.CalcItemWidth();
|
||||
ImGui.PushItemWidth(Math.Max(0f, itemWidth - frameHeight));
|
||||
|
||||
labelStack.Add((labelMin, labelMax));
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static void DrawClippedRect(Vector2 clipMin, Vector2 clipMax, Vector2 drawMin, Vector2 drawMax, uint color, float thickness)
|
||||
{
|
||||
ImGui.PushClipRect(clipMin, clipMax, true);
|
||||
ImGui.GetWindowDrawList().AddRect(drawMin, drawMax, color, thickness);
|
||||
ImGui.PopClipRect();
|
||||
}
|
||||
|
||||
public static void EndFramedGroup()
|
||||
{
|
||||
uint borderColor = ImGui.ColorConvertFloat4ToU32(ImGui.GetStyle().Colors[(int)ImGuiCol.Border]);
|
||||
Vector2 itemSpacing = ImGui.GetStyle().ItemSpacing;
|
||||
float frameHeight = ImGui.GetFrameHeight();
|
||||
Vector2 halfFrameHeight = new(ImGui.GetFrameHeight() / 2, 0);
|
||||
|
||||
ImGui.PopItemWidth();
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.FramePadding, ZeroVector);
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ZeroVector);
|
||||
|
||||
ImGui.EndGroup(); // Close fourth group
|
||||
ImGui.EndGroup(); // Close third group
|
||||
|
||||
ImGui.SameLine();
|
||||
// Ensure right distance.
|
||||
ImGui.Dummy(halfFrameHeight);
|
||||
// Ensure bottom distance
|
||||
ImGui.Dummy(new Vector2(0, frameHeight/2 - itemSpacing.Y));
|
||||
ImGui.EndGroup(); // Close second group
|
||||
|
||||
var itemMin = ImGui.GetItemRectMin();
|
||||
var itemMax = ImGui.GetItemRectMax();
|
||||
var (currentLabelMin, currentLabelMax) = labelStack[labelStack.Count - 1];
|
||||
labelStack.RemoveAt(labelStack.Count - 1);
|
||||
|
||||
var halfFrame = new Vector2(frameHeight / 8, frameHeight / 2);
|
||||
currentLabelMin.X -= itemSpacing.X;
|
||||
currentLabelMax.X += itemSpacing.X;
|
||||
var frameMin = itemMin + halfFrame;
|
||||
var frameMax = itemMax - new Vector2(halfFrame.X, 0);
|
||||
|
||||
// Left
|
||||
DrawClippedRect(new(-float.MaxValue , -float.MaxValue ), new(currentLabelMin.X, float.MaxValue ), frameMin, frameMax, borderColor, halfFrame.X);
|
||||
// Right
|
||||
DrawClippedRect(new(currentLabelMax.X, -float.MaxValue ), new(float.MaxValue , float.MaxValue ), frameMin, frameMax, borderColor, halfFrame.X);
|
||||
// Top
|
||||
DrawClippedRect(new(currentLabelMin.X, -float.MaxValue ), new(currentLabelMax.X, currentLabelMin.Y), frameMin, frameMax, borderColor, halfFrame.X);
|
||||
// Bottom
|
||||
DrawClippedRect(new(currentLabelMin.X, currentLabelMax.Y), new(currentLabelMax.X, float.MaxValue ), frameMin, frameMax, borderColor, halfFrame.X);
|
||||
|
||||
ImGui.PopStyleVar(2);
|
||||
ImGui.SetWindowSize(new Vector2(ImGui.GetWindowSize().X + frameHeight, ImGui.GetWindowSize().Y));
|
||||
ImGui.Dummy(ZeroVector);
|
||||
|
||||
ImGui.EndGroup(); // Close first group
|
||||
}
|
||||
|
||||
private static readonly Vector2 ZeroVector = new(0, 0);
|
||||
|
||||
private static List<(Vector2, Vector2)> labelStack = new();
|
||||
}
|
||||
}
|
||||
43
Penumbra/UI/ImGuiRenameableCombo.cs
Normal file
43
Penumbra/UI/ImGuiRenameableCombo.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public static partial class ImGuiCustom
|
||||
{
|
||||
public static bool RenameableCombo(string label, ref int currentItem, ref string newName, string[] items, int numItems)
|
||||
{
|
||||
var ret = false;
|
||||
newName = "";
|
||||
var newOption = "";
|
||||
if (ImGui.BeginCombo(label, (numItems > 0) ? items[currentItem] : newOption))
|
||||
{
|
||||
for (var i = 0; i < numItems; ++i)
|
||||
{
|
||||
var isSelected = i == currentItem;
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
if (ImGui.InputText($"##{label}_{i}", ref items[i], 64, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
currentItem = i;
|
||||
newName = items[i];
|
||||
ret = true;
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
if (isSelected)
|
||||
ImGui.SetItemDefaultFocus();
|
||||
}
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
if (ImGui.InputText($"##{label}_new", ref newOption, 64, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
currentItem = numItems;
|
||||
newName = newOption;
|
||||
ret = true;
|
||||
ImGui.CloseCurrentPopup();
|
||||
}
|
||||
if (numItems == 0)
|
||||
ImGui.SetItemDefaultFocus();
|
||||
ImGui.EndCombo();
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
40
Penumbra/UI/ImGuiResizingTextInput.cs
Normal file
40
Penumbra/UI/ImGuiResizingTextInput.cs
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
using System.Collections.Generic;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public static partial class ImGuiCustom
|
||||
{
|
||||
public static bool InputOrText(bool editable, string label, ref string text, uint maxLength)
|
||||
{
|
||||
if (editable)
|
||||
return ResizingTextInput(label, ref text, maxLength);
|
||||
|
||||
ImGui.Text(text);
|
||||
return false;
|
||||
}
|
||||
|
||||
public static bool ResizingTextInput(string label, ref string input, uint maxLength) => ResizingTextInputIntern(label, ref input, maxLength).Item1;
|
||||
public static bool ResizingTextInput(ref string input, uint maxLength)
|
||||
{
|
||||
var (ret, id) = ResizingTextInputIntern($"##{input}", ref input, maxLength);
|
||||
if (ret)
|
||||
_textInputWidths.Remove(id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
private static (bool, uint) ResizingTextInputIntern(string label, ref string input, uint maxLength)
|
||||
{
|
||||
var id = ImGui.GetID(label);
|
||||
if (!_textInputWidths.TryGetValue(id, out var width))
|
||||
width = ImGui.CalcTextSize(input).X + 10;
|
||||
|
||||
ImGui.SetNextItemWidth(width);
|
||||
var ret = ImGui.InputText(label, ref input, maxLength, ImGuiInputTextFlags.EnterReturnsTrue);
|
||||
_textInputWidths[id] = ImGui.CalcTextSize(input).X + 10;
|
||||
return (ret, id);
|
||||
}
|
||||
|
||||
private static readonly Dictionary<uint, float> _textInputWidths = new();
|
||||
}
|
||||
}
|
||||
26
Penumbra/UI/ImGuiUtil.cs
Normal file
26
Penumbra/UI/ImGuiUtil.cs
Normal file
|
|
@ -0,0 +1,26 @@
|
|||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public static partial class ImGuiCustom
|
||||
{
|
||||
public static void VerticalDistance(float distance)
|
||||
{
|
||||
ImGui.SetCursorPosY(ImGui.GetCursorPosY() + distance);
|
||||
}
|
||||
|
||||
public static void RightJustifiedText(float pos, string text)
|
||||
{
|
||||
ImGui.SetCursorPosX(pos - ImGui.CalcTextSize(text).X - 2 * ImGui.GetStyle().ItemSpacing.X);
|
||||
ImGui.Text(text);
|
||||
}
|
||||
|
||||
public static void RightJustifiedLabel(float pos, string text)
|
||||
{
|
||||
ImGui.SetCursorPosX(pos - ImGui.CalcTextSize(text).X - ImGui.GetStyle().ItemSpacing.X / 2);
|
||||
ImGui.Text(text);
|
||||
ImGui.SameLine(pos);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
56
Penumbra/UI/LaunchButton.cs
Normal file
56
Penumbra/UI/LaunchButton.cs
Normal file
|
|
@ -0,0 +1,56 @@
|
|||
using System.Numerics;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class LaunchButton
|
||||
{
|
||||
// magic numbers
|
||||
private const int Padding = 50;
|
||||
private const int Width = 200;
|
||||
private const int Height = 45;
|
||||
private const string MenuButtonsName = "Penumbra Menu Buttons";
|
||||
private const string MenuButtonLabel = "Manage Mods";
|
||||
|
||||
private static readonly Vector2 WindowSize = new(Width, Height);
|
||||
private static readonly Vector2 WindowPosOffset = new(Padding + Width, Padding + Height);
|
||||
|
||||
private readonly ImGuiWindowFlags ButtonFlags = ImGuiWindowFlags.AlwaysAutoResize
|
||||
| ImGuiWindowFlags.NoBackground
|
||||
| ImGuiWindowFlags.NoDecoration
|
||||
| ImGuiWindowFlags.NoMove
|
||||
| ImGuiWindowFlags.NoScrollbar
|
||||
| ImGuiWindowFlags.NoResize
|
||||
| ImGuiWindowFlags.NoSavedSettings;
|
||||
|
||||
private readonly SettingsInterface _base;
|
||||
private readonly Dalamud.Game.ClientState.Condition _condition;
|
||||
|
||||
public LaunchButton(SettingsInterface ui)
|
||||
{
|
||||
_base = ui;
|
||||
_condition = ui._plugin.PluginInterface.ClientState.Condition;
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if( !_condition.Any() && !_base._menu.Visible )
|
||||
{
|
||||
var ss = ImGui.GetIO().DisplaySize;
|
||||
|
||||
ImGui.SetNextWindowPos( ss - WindowPosOffset, ImGuiCond.Always );
|
||||
|
||||
if( ImGui.Begin(MenuButtonsName, ButtonFlags) )
|
||||
{
|
||||
if( ImGui.Button( MenuButtonLabel, WindowSize ) )
|
||||
_base.FlipVisibility();
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
43
Penumbra/UI/MenuBar.cs
Normal file
43
Penumbra/UI/MenuBar.cs
Normal file
|
|
@ -0,0 +1,43 @@
|
|||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class MenuBar
|
||||
{
|
||||
private const string MenuLabel = "Penumbra";
|
||||
private const string MenuItemToggle = "Toggle UI";
|
||||
private const string SlashCommand = "/penumbra";
|
||||
private const string MenuItemRediscover = "Rediscover Mods";
|
||||
|
||||
#if DEBUG
|
||||
private const bool _showDebugBar = true;
|
||||
#else
|
||||
private const bool _showDebugBar = false;
|
||||
#endif
|
||||
|
||||
private readonly SettingsInterface _base;
|
||||
public MenuBar(SettingsInterface ui) => _base = ui;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if( _showDebugBar && ImGui.BeginMainMenuBar() )
|
||||
{
|
||||
if( ImGui.BeginMenu( MenuLabel ) )
|
||||
{
|
||||
if( ImGui.MenuItem( MenuItemToggle, SlashCommand, _base._menu.Visible ) )
|
||||
_base.FlipVisibility();
|
||||
|
||||
if( ImGui.MenuItem( MenuItemRediscover ) )
|
||||
_base.ReloadMods();
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
||||
ImGui.EndMainMenuBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,871 +1,46 @@
|
|||
using System;
|
||||
using System.ComponentModel.Design;
|
||||
using System.Diagnostics;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using Dalamud.Interface;
|
||||
using Dalamud.Plugin;
|
||||
using ImGuiNET;
|
||||
using Newtonsoft.Json;
|
||||
using Penumbra.Importer;
|
||||
using Penumbra.Models;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public class SettingsInterface
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private const float DefaultVerticalSpace = 20f;
|
||||
|
||||
private static readonly Vector2 AutoFillSize = new(-1, -1);
|
||||
private static readonly Vector2 ZeroVector = new( 0, 0);
|
||||
|
||||
private readonly Plugin _plugin;
|
||||
|
||||
public bool Visible;
|
||||
public bool ShowDebugBar;
|
||||
|
||||
private static readonly Vector2 AutoFillSize = new Vector2( -1, -1 );
|
||||
private static readonly Vector2 ModListSize = new Vector2( 200, -1 );
|
||||
|
||||
private static readonly Vector2 MinSettingsSize = new Vector2( 800, 450 );
|
||||
private static readonly Vector2 MaxSettingsSize = new Vector2( 69420, 42069 );
|
||||
|
||||
private const string DialogDeleteMod = "PenumbraDeleteMod";
|
||||
|
||||
private int _selectedModIndex;
|
||||
private int? _selectedModDeleteIndex;
|
||||
private ModInfo _selectedMod;
|
||||
|
||||
private bool _isImportRunning;
|
||||
private TexToolsImport _texToolsImport = null!;
|
||||
private readonly LaunchButton _launchButton;
|
||||
private readonly MenuBar _menuBar;
|
||||
private readonly SettingsMenu _menu;
|
||||
|
||||
public SettingsInterface( Plugin plugin )
|
||||
{
|
||||
_plugin = plugin;
|
||||
#if DEBUG
|
||||
Visible = true;
|
||||
ShowDebugBar = true;
|
||||
#endif
|
||||
_launchButton = new(this);
|
||||
_menuBar = new(this);
|
||||
_menu = new(this);
|
||||
}
|
||||
|
||||
public void FlipVisibility() => _menu.Visible = !_menu.Visible;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if( ShowDebugBar && ImGui.BeginMainMenuBar() )
|
||||
{
|
||||
if( ImGui.BeginMenu( "Penumbra" ) )
|
||||
{
|
||||
if( ImGui.MenuItem( "Toggle UI", "/penumbra", Visible ) )
|
||||
{
|
||||
Visible = !Visible;
|
||||
}
|
||||
|
||||
if( ImGui.MenuItem( "Rediscover Mods" ) )
|
||||
{
|
||||
ReloadMods();
|
||||
}
|
||||
|
||||
// ImGui.Separator();
|
||||
// #if DEBUG
|
||||
// ImGui.Text( _plugin.PluginDebugTitleStr );
|
||||
// #else
|
||||
// ImGui.Text( _plugin.Name );
|
||||
// #endif
|
||||
|
||||
ImGui.EndMenu();
|
||||
}
|
||||
|
||||
ImGui.EndMainMenuBar();
|
||||
}
|
||||
|
||||
if( !_plugin.PluginInterface.ClientState.Condition.Any() && !Visible )
|
||||
{
|
||||
// draw mods button on da menu :DDD
|
||||
var ss = ImGui.GetIO().DisplaySize;
|
||||
var padding = 50;
|
||||
var width = 200;
|
||||
var height = 45;
|
||||
|
||||
// magic numbers
|
||||
ImGui.SetNextWindowPos( new Vector2( ss.X - padding - width, ss.Y - padding - height ), ImGuiCond.Always );
|
||||
|
||||
if(
|
||||
ImGui.Begin(
|
||||
"Penumbra Menu Buttons",
|
||||
ImGuiWindowFlags.AlwaysAutoResize |
|
||||
ImGuiWindowFlags.NoBackground |
|
||||
ImGuiWindowFlags.NoDecoration |
|
||||
ImGuiWindowFlags.NoMove |
|
||||
ImGuiWindowFlags.NoScrollbar |
|
||||
ImGuiWindowFlags.NoResize |
|
||||
ImGuiWindowFlags.NoSavedSettings
|
||||
)
|
||||
)
|
||||
{
|
||||
if( ImGui.Button( "Manage Mods", new Vector2( width, height ) ) )
|
||||
{
|
||||
Visible = !Visible;
|
||||
}
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
}
|
||||
|
||||
if( !Visible )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.SetNextWindowSizeConstraints( MinSettingsSize, MaxSettingsSize );
|
||||
#if DEBUG
|
||||
var ret = ImGui.Begin( _plugin.PluginDebugTitleStr, ref Visible );
|
||||
#else
|
||||
var ret = ImGui.Begin( _plugin.Name, ref Visible );
|
||||
#endif
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.BeginTabBar( "PenumbraSettings" );
|
||||
|
||||
DrawSettingsTab();
|
||||
DrawImportTab();
|
||||
|
||||
|
||||
if( !_isImportRunning )
|
||||
{
|
||||
DrawModBrowser();
|
||||
|
||||
DrawInstalledMods();
|
||||
|
||||
if( _plugin.Configuration.ShowAdvanced )
|
||||
{
|
||||
DrawEffectiveFileList();
|
||||
}
|
||||
|
||||
DrawDeleteModal();
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
|
||||
ImGui.End();
|
||||
}
|
||||
|
||||
void DrawImportTab()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Import Mods" );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( !_isImportRunning )
|
||||
{
|
||||
if( ImGui.Button( "Import TexTools Modpacks" ) )
|
||||
{
|
||||
_isImportRunning = true;
|
||||
|
||||
Task.Run( async () =>
|
||||
{
|
||||
var picker = new OpenFileDialog
|
||||
{
|
||||
Multiselect = true,
|
||||
Filter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*",
|
||||
CheckFileExists = true,
|
||||
Title = "Pick one or more modpacks."
|
||||
};
|
||||
|
||||
var result = await picker.ShowDialogAsync();
|
||||
|
||||
if( result == DialogResult.OK )
|
||||
{
|
||||
foreach( var fileName in picker.FileNames )
|
||||
{
|
||||
PluginLog.Log( "-> {0} START", fileName );
|
||||
|
||||
try
|
||||
{
|
||||
_texToolsImport = new TexToolsImport( new DirectoryInfo( _plugin.Configuration.CurrentCollection ) );
|
||||
_texToolsImport.ImportModPack( new FileInfo( fileName ) );
|
||||
}
|
||||
catch( Exception ex )
|
||||
{
|
||||
PluginLog.LogError( ex, "Could not import one or more modpacks." );
|
||||
}
|
||||
|
||||
PluginLog.Log( "-> {0} OK!", fileName );
|
||||
}
|
||||
|
||||
_texToolsImport = null;
|
||||
ReloadMods();
|
||||
}
|
||||
|
||||
_isImportRunning = false;
|
||||
} );
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.Button( "Import in progress..." );
|
||||
|
||||
if( _texToolsImport != null )
|
||||
{
|
||||
switch( _texToolsImport.State )
|
||||
{
|
||||
case ImporterState.None:
|
||||
break;
|
||||
case ImporterState.WritingPackToDisk:
|
||||
ImGui.Text( "Writing modpack to disk before extracting..." );
|
||||
break;
|
||||
case ImporterState.ExtractingModFiles:
|
||||
{
|
||||
var str =
|
||||
$"{_texToolsImport.CurrentModPack} - {_texToolsImport.CurrentProgress} of {_texToolsImport.TotalProgress} files";
|
||||
|
||||
ImGui.ProgressBar( _texToolsImport.Progress, new Vector2( -1, 0 ), str );
|
||||
break;
|
||||
}
|
||||
case ImporterState.Done:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
[Conditional( "DEBUG" )]
|
||||
void DrawModBrowser()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Available Mods" );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
ImGui.Text( "woah" );
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
void DrawSettingsTab()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Settings" );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
bool dirty = false;
|
||||
|
||||
// FUCKKKKK
|
||||
var basePath = _plugin.Configuration.CurrentCollection;
|
||||
if( ImGui.InputText( "Root Folder", ref basePath, 255 ) )
|
||||
{
|
||||
_plugin.Configuration.CurrentCollection = basePath;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if( ImGui.Button( "Rediscover Mods" ) )
|
||||
{
|
||||
ReloadMods();
|
||||
_selectedModIndex = 0;
|
||||
_selectedMod = null;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( "Open Mods Folder" ) )
|
||||
{
|
||||
Process.Start( _plugin.Configuration.CurrentCollection );
|
||||
}
|
||||
|
||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 20 );
|
||||
|
||||
var invertOrder = _plugin.Configuration.InvertModListOrder;
|
||||
if( ImGui.Checkbox( "Invert mod load order (mods are loaded bottom up)", ref invertOrder ) )
|
||||
{
|
||||
_plugin.Configuration.InvertModListOrder = invertOrder;
|
||||
dirty = true;
|
||||
|
||||
ReloadMods();
|
||||
}
|
||||
|
||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 20 );
|
||||
|
||||
var showAdvanced = _plugin.Configuration.ShowAdvanced;
|
||||
if( ImGui.Checkbox( "Show Advanced Settings", ref showAdvanced ) )
|
||||
{
|
||||
_plugin.Configuration.ShowAdvanced = showAdvanced;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if( _plugin.Configuration.ShowAdvanced )
|
||||
{
|
||||
if( _plugin.ResourceLoader != null )
|
||||
{
|
||||
ImGui.Checkbox( "Log all loaded files", ref _plugin.ResourceLoader.LogAllFiles );
|
||||
}
|
||||
|
||||
var fswatch = _plugin.Configuration.DisableFileSystemNotifications;
|
||||
if( ImGui.Checkbox( "Disable filesystem change notifications", ref fswatch ) )
|
||||
{
|
||||
_plugin.Configuration.DisableFileSystemNotifications = fswatch;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
var http = _plugin.Configuration.EnableHttpApi;
|
||||
if( ImGui.Checkbox( "Enable HTTP API", ref http ) )
|
||||
{
|
||||
if( http )
|
||||
{
|
||||
_plugin.CreateWebServer();
|
||||
}
|
||||
else
|
||||
{
|
||||
_plugin.ShutdownWebServer();
|
||||
}
|
||||
|
||||
_plugin.Configuration.EnableHttpApi = http;
|
||||
dirty = true;
|
||||
}
|
||||
|
||||
if( ImGui.Button( "Reload Player Resource" ) )
|
||||
{
|
||||
_plugin.GameUtils.ReloadPlayerResources();
|
||||
}
|
||||
}
|
||||
|
||||
if( dirty )
|
||||
{
|
||||
_plugin.Configuration.Save();
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
void DrawModsSelector()
|
||||
{
|
||||
// Selector pane
|
||||
ImGui.BeginGroup();
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, new Vector2( 0, 0 ) );
|
||||
|
||||
// Inlay selector list
|
||||
ImGui.BeginChild( "availableModList", new Vector2( 240, -ImGui.GetFrameHeightWithSpacing() ), true );
|
||||
|
||||
if( _plugin.ModManager.Mods != null )
|
||||
{
|
||||
for( var modIndex = 0; modIndex < _plugin.ModManager.Mods.ModSettings.Count; modIndex++ )
|
||||
{
|
||||
var settings = _plugin.ModManager.Mods.ModSettings[ modIndex ];
|
||||
|
||||
var changedColour = false;
|
||||
if( !settings.Enabled )
|
||||
{
|
||||
ImGui.PushStyleColor( ImGuiCol.Text, 0xFF666666 );
|
||||
changedColour = true;
|
||||
}
|
||||
else if( settings.Mod.FileConflicts.Any() )
|
||||
{
|
||||
ImGui.PushStyleColor( ImGuiCol.Text, 0xFFAAAAFF );
|
||||
changedColour = true;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
var selected = ImGui.Selectable(
|
||||
$"id={modIndex} {settings.Mod.Meta.Name}",
|
||||
modIndex == _selectedModIndex
|
||||
);
|
||||
#else
|
||||
var selected = ImGui.Selectable( settings.Mod.Meta.Name, modIndex == _selectedModIndex );
|
||||
#endif
|
||||
|
||||
if( changedColour )
|
||||
{
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
if( selected )
|
||||
{
|
||||
_selectedModIndex = modIndex;
|
||||
_selectedMod = settings;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
// Selector controls
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.WindowPadding, new Vector2( 0, 0 ) );
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.FrameRounding, 0 );
|
||||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
if( _selectedModIndex != 0 )
|
||||
{
|
||||
if( ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
_plugin.ModManager.ChangeModPriority( _selectedMod );
|
||||
_selectedModIndex -= 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f );
|
||||
ImGui.Button( FontAwesomeIcon.ArrowUp.ToIconString(), new Vector2( 60, 0 ) );
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
{
|
||||
ImGui.SetTooltip(
|
||||
_plugin.Configuration.InvertModListOrder
|
||||
? "Move the selected mod down in priority"
|
||||
: "Move the selected mod up in priority"
|
||||
);
|
||||
}
|
||||
|
||||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( _selectedModIndex != _plugin.ModManager.Mods?.ModSettings.Count - 1 )
|
||||
{
|
||||
if( ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
_plugin.ModManager.ChangeModPriority( _selectedMod, true );
|
||||
_selectedModIndex += 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f );
|
||||
ImGui.Button( FontAwesomeIcon.ArrowDown.ToIconString(), new Vector2( 60, 0 ) );
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
{
|
||||
ImGui.SetTooltip(
|
||||
_plugin.Configuration.InvertModListOrder
|
||||
? "Move the selected mod up in priority"
|
||||
: "Move the selected mod down in priority"
|
||||
);
|
||||
}
|
||||
|
||||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
_selectedModDeleteIndex = _selectedModIndex;
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( "Delete the selected mod" );
|
||||
|
||||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), new Vector2( 60, 0 ) ) )
|
||||
{
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( "Add an empty mod" );
|
||||
|
||||
ImGui.PopStyleVar( 3 );
|
||||
|
||||
ImGui.EndGroup();
|
||||
}
|
||||
|
||||
void DrawDeleteModal()
|
||||
{
|
||||
if( _selectedModDeleteIndex != null )
|
||||
ImGui.OpenPopup( DialogDeleteMod );
|
||||
|
||||
var ret = ImGui.BeginPopupModal( DialogDeleteMod );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( _selectedMod?.Mod == null )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.Text( "Are you sure you want to delete the following mod:" );
|
||||
// todo: why the fuck does this become null??????
|
||||
ImGui.Text( _selectedMod?.Mod?.Meta?.Name );
|
||||
|
||||
if( ImGui.Button( "Yes, delete it" ) )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_plugin.ModManager.DeleteMod( _selectedMod.Mod );
|
||||
_selectedMod = null;
|
||||
_selectedModIndex = 0;
|
||||
_selectedModDeleteIndex = null;
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( "No, keep it" ) )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_selectedModDeleteIndex = null;
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
// Website button with On-Hover address if valid http(s), otherwise text.
|
||||
private void DrawWebsiteText()
|
||||
{
|
||||
if( ( _selectedMod.Mod.Meta.Website?.Length ?? 0 ) <= 0 )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
var validUrl = Uri.TryCreate( _selectedMod.Mod.Meta.Website, UriKind.Absolute, out Uri uriResult )
|
||||
&& ( uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp );
|
||||
ImGui.SameLine();
|
||||
if( validUrl )
|
||||
{
|
||||
if( ImGui.SmallButton( "Open Website" ) )
|
||||
{
|
||||
Process.Start( _selectedMod.Mod.Meta.Website );
|
||||
}
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( _selectedMod.Mod.Meta.Website );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextColored( new Vector4( 1f, 1f, 1f, 0.66f ), "from" );
|
||||
ImGui.SameLine();
|
||||
ImGui.Text( _selectedMod.Mod.Meta.Website );
|
||||
}
|
||||
}
|
||||
|
||||
// Create Mod-Handling buttons.
|
||||
private void DrawEditButtons()
|
||||
{
|
||||
ImGui.SameLine();
|
||||
if( ImGui.Button( "Open Mod Folder" ) )
|
||||
{
|
||||
Process.Start( _selectedMod.Mod.ModBasePath.FullName );
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( "Open the directory containing this mod in your default file explorer." );
|
||||
|
||||
ImGui.SameLine();
|
||||
if( ImGui.Button( "Edit JSON" ) )
|
||||
{
|
||||
var metaPath = Path.Combine( _selectedMod.Mod.ModBasePath.FullName, "meta.json" );
|
||||
File.WriteAllText( metaPath, JsonConvert.SerializeObject( _selectedMod.Mod.Meta, Formatting.Indented ) );
|
||||
Process.Start( metaPath );
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( "Open the JSON configuration file in your default application for .json." );
|
||||
|
||||
ImGui.SameLine();
|
||||
if( ImGui.Button( "Reload JSON" ) )
|
||||
{
|
||||
ReloadMods();
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( "Reload the configuration of all mods." );
|
||||
|
||||
ImGui.SameLine();
|
||||
if( ImGui.Button( "Deduplicate" ) )
|
||||
{
|
||||
new Deduplicator(_selectedMod.Mod.ModBasePath, _selectedMod.Mod.Meta).Run();
|
||||
var metaPath = Path.Combine( _selectedMod.Mod.ModBasePath.FullName, "meta.json" );
|
||||
File.WriteAllText( metaPath, JsonConvert.SerializeObject( _selectedMod.Mod.Meta, Formatting.Indented ) );
|
||||
ReloadMods();
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( "Try to find identical files and remove duplicate occurences to reduce the mods disk size." );
|
||||
}
|
||||
|
||||
private void DrawGroupSelectors()
|
||||
{
|
||||
//Spahetti code time
|
||||
var mod = _plugin.SettingsInterface._selectedMod;
|
||||
var conf = mod.Conf;
|
||||
var settings = mod.Mod.Meta.Groups;
|
||||
foreach( var g in settings )
|
||||
{
|
||||
switch( g.Value.SelectionType )
|
||||
{
|
||||
case SelectType.Multi:
|
||||
{
|
||||
var i = 0;
|
||||
var flag = conf[g.Key];
|
||||
foreach( var opt in g.Value.Options )
|
||||
{
|
||||
var enab = ( flag & 1 << i ) != 0;
|
||||
if( ImGui.Checkbox( g.Value.GroupName + " - " + opt.OptionName, ref enab ) )
|
||||
{
|
||||
flag = flag ^= 1 << i;
|
||||
conf[g.Key] = flag;
|
||||
_plugin.ModManager.Mods.Save();
|
||||
_plugin.ModManager.CalculateEffectiveFileList();
|
||||
}
|
||||
i++;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case SelectType.Single:
|
||||
{
|
||||
var code = conf[g.Key];
|
||||
if( g.Value.Options.Count > 1 )
|
||||
{
|
||||
if( ImGui.Combo( g.Value.GroupName, ref code, g.Value.Options.Select( x => x.OptionName ).ToArray(), g.Value.Options.ToArray().Length ) )
|
||||
{
|
||||
conf[g.Key] = code;
|
||||
_plugin.ModManager.Mods.Save();
|
||||
_plugin.ModManager.CalculateEffectiveFileList();
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void DrawInstalledMods()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Installed Mods" );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( _plugin.ModManager.Mods == null )
|
||||
{
|
||||
ImGui.Text( "You don't have any mods :(" );
|
||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 20 );
|
||||
ImGui.Text( "You'll need to install them first by creating a folder close to the root of your drive (preferably an SSD)." );
|
||||
ImGui.Text( "For example: D:/ffxiv/mods/" );
|
||||
ImGui.Text( "And pasting that path into the settings tab and clicking the 'Rediscover Mods' button." );
|
||||
ImGui.Text( "You can return to this tab once you've done that." );
|
||||
ImGui.EndTabItem();
|
||||
return;
|
||||
}
|
||||
|
||||
DrawModsSelector();
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( _selectedMod != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
ImGui.BeginChild( "selectedModInfo", AutoFillSize, true );
|
||||
|
||||
ImGui.Text( _selectedMod.Mod.Meta.Name );
|
||||
|
||||
// (Version ...) or nothing.
|
||||
if( ( _selectedMod.Mod.Meta.Version?.Length ?? 0 ) > 0 )
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.Text( $"(Version {_selectedMod.Mod.Meta.Version})" );
|
||||
}
|
||||
|
||||
// by Author or Unknown.
|
||||
ImGui.SameLine();
|
||||
ImGui.TextColored( new Vector4( 1f, 1f, 1f, 0.66f ), "by" );
|
||||
ImGui.SameLine();
|
||||
if( ( _selectedMod.Mod.Meta.Author?.Length ?? 0 ) > 0 )
|
||||
ImGui.Text( _selectedMod.Mod.Meta.Author );
|
||||
else
|
||||
ImGui.Text( "Unknown" );
|
||||
|
||||
DrawWebsiteText();
|
||||
|
||||
ImGui.SetCursorPosY( ImGui.GetCursorPosY() + 10 );
|
||||
|
||||
var enabled = _selectedMod.Enabled;
|
||||
if( ImGui.Checkbox( "Enabled", ref enabled ) )
|
||||
{
|
||||
_selectedMod.Enabled = enabled;
|
||||
_plugin.ModManager.Mods.Save();
|
||||
_plugin.ModManager.CalculateEffectiveFileList();
|
||||
}
|
||||
|
||||
DrawEditButtons();
|
||||
|
||||
ImGui.BeginTabBar( "PenumbraPluginDetails" );
|
||||
|
||||
if( _selectedMod.Mod.Meta.Description?.Length > 0 && ImGui.BeginTabItem( "About" ) )
|
||||
{
|
||||
ImGui.TextWrapped( _selectedMod.Mod.Meta.Description );
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if( ( _selectedMod.Mod.Meta.ChangedItems?.Count ?? 0 ) > 0 )
|
||||
{
|
||||
if( ImGui.BeginTabItem( "Changed Items" ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( "###", AutoFillSize ) )
|
||||
foreach( var item in _selectedMod.Mod.Meta.ChangedItems )
|
||||
ImGui.Selectable( item );
|
||||
ImGui.ListBoxFooter();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
if(_selectedMod.Mod.Meta.HasGroupWithConfig) {
|
||||
if(ImGui.BeginTabItem( "Configuration" ))
|
||||
{
|
||||
DrawGroupSelectors();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
if( ImGui.BeginTabItem( "Files" ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) )
|
||||
foreach( var file in _selectedMod.Mod.ModFiles )
|
||||
ImGui.Selectable( file.FullName );
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
if( _selectedMod.Mod.Meta.FileSwaps.Any() )
|
||||
{
|
||||
if( ImGui.BeginTabItem( "File Swaps" ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) )
|
||||
{
|
||||
foreach( var file in _selectedMod.Mod.Meta.FileSwaps )
|
||||
{
|
||||
// todo: fucking gross alloc every frame * items
|
||||
ImGui.Selectable( $"{file.Key} -> {file.Value}" );
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
if( _selectedMod.Mod.FileConflicts.Any() )
|
||||
{
|
||||
if( ImGui.BeginTabItem( "File Conflicts" ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) )
|
||||
{
|
||||
foreach( var kv in _selectedMod.Mod.FileConflicts )
|
||||
{
|
||||
var mod = kv.Key;
|
||||
var files = kv.Value;
|
||||
|
||||
if( ImGui.Selectable( mod ) )
|
||||
{
|
||||
SelectModByName( mod );
|
||||
}
|
||||
|
||||
ImGui.Indent( 15 );
|
||||
foreach( var file in files )
|
||||
{
|
||||
ImGui.Selectable( file );
|
||||
}
|
||||
|
||||
ImGui.Unindent( 15 );
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
ImGui.EndChild();
|
||||
}
|
||||
catch( Exception ex )
|
||||
{
|
||||
PluginLog.LogError( ex, "fuck" );
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
|
||||
void SelectModByName( string name )
|
||||
{
|
||||
for( var modIndex = 0; modIndex < _plugin.ModManager.Mods.ModSettings.Count; modIndex++ )
|
||||
{
|
||||
var mod = _plugin.ModManager.Mods.ModSettings[ modIndex ];
|
||||
|
||||
if( mod.Mod.Meta.Name != name )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
_selectedMod = mod;
|
||||
_selectedModIndex = modIndex;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
void DrawEffectiveFileList()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Effective File List" );
|
||||
if( !ret )
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if( ImGui.ListBoxHeader( "##", AutoFillSize ) )
|
||||
{
|
||||
// todo: virtualise this
|
||||
foreach( var file in _plugin.ModManager.ResolvedFiles )
|
||||
{
|
||||
ImGui.Selectable( file.Value.FullName + " -> " + file.Key );
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
_menuBar.Draw();
|
||||
_launchButton.Draw();
|
||||
_menu.Draw();
|
||||
}
|
||||
|
||||
private void ReloadMods()
|
||||
{
|
||||
_selectedMod = null;
|
||||
|
||||
_menu._installedTab._selector.ClearSelection();
|
||||
// create the directory if it doesn't exist
|
||||
Directory.CreateDirectory( _plugin.Configuration.CurrentCollection );
|
||||
|
||||
_plugin.ModManager.DiscoverMods( _plugin.Configuration.CurrentCollection );
|
||||
|
||||
// May select a different mod than before if mods were added or deleted, but will not crash.
|
||||
if( _selectedModIndex < _plugin.ModManager.Mods.ModSettings.Count )
|
||||
{
|
||||
_selectedMod = _plugin.ModManager.Mods.ModSettings[ _selectedModIndex ];
|
||||
}
|
||||
else
|
||||
{
|
||||
_selectedModIndex = 0;
|
||||
_selectedMod = null;
|
||||
}
|
||||
_menu._effectiveTab.RebuildFileList(_plugin.Configuration.ShowAdvanced);
|
||||
}
|
||||
}
|
||||
}
|
||||
72
Penumbra/UI/SettingsMenu.cs
Normal file
72
Penumbra/UI/SettingsMenu.cs
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
using System.Numerics;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private partial class SettingsMenu
|
||||
{
|
||||
private const string PenumbraSettingsLabel = "PenumbraSettings";
|
||||
|
||||
private static readonly Vector2 MinSettingsSize = new( 800, 450 );
|
||||
private static readonly Vector2 MaxSettingsSize = new( 69420, 42069 );
|
||||
|
||||
private readonly SettingsInterface _base;
|
||||
public readonly TabSettings _settingsTab;
|
||||
public readonly TabImport _importTab;
|
||||
public readonly TabBrowser _browserTab;
|
||||
public readonly TabInstalled _installedTab;
|
||||
public readonly TabEffective _effectiveTab;
|
||||
|
||||
public SettingsMenu(SettingsInterface ui)
|
||||
{
|
||||
_base = ui;
|
||||
_settingsTab = new(_base);
|
||||
_importTab = new(_base);
|
||||
_browserTab = new();
|
||||
_installedTab = new(_base);
|
||||
_effectiveTab = new(_base);
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
private const bool DefaultVisibility = true;
|
||||
#else
|
||||
private const bool DefaultVisibility = false;
|
||||
#endif
|
||||
public bool Visible = DefaultVisibility;
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if( !Visible )
|
||||
return;
|
||||
|
||||
ImGui.SetNextWindowSizeConstraints( MinSettingsSize, MaxSettingsSize );
|
||||
#if DEBUG
|
||||
var ret = ImGui.Begin( _base._plugin.PluginDebugTitleStr, ref Visible );
|
||||
#else
|
||||
var ret = ImGui.Begin( _base._plugin.Name, ref Visible );
|
||||
#endif
|
||||
if( !ret )
|
||||
return;
|
||||
|
||||
ImGui.BeginTabBar( PenumbraSettingsLabel );
|
||||
|
||||
_settingsTab.Draw();
|
||||
_importTab.Draw();
|
||||
|
||||
if( !_importTab.IsImporting() )
|
||||
{
|
||||
_browserTab.Draw();
|
||||
_installedTab.Draw();
|
||||
|
||||
if( _base._plugin.Configuration.ShowAdvanced )
|
||||
_effectiveTab.Draw();
|
||||
}
|
||||
|
||||
ImGui.EndTabBar();
|
||||
ImGui.End();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
22
Penumbra/UI/TabBrowser.cs
Normal file
22
Penumbra/UI/TabBrowser.cs
Normal file
|
|
@ -0,0 +1,22 @@
|
|||
using System.Diagnostics;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class TabBrowser
|
||||
{
|
||||
[Conditional( "DEBUG" )]
|
||||
public void Draw()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( "Available Mods" );
|
||||
if( !ret )
|
||||
return;
|
||||
|
||||
ImGui.Text( "woah" );
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
66
Penumbra/UI/TabEffective.cs
Normal file
66
Penumbra/UI/TabEffective.cs
Normal file
|
|
@ -0,0 +1,66 @@
|
|||
using System.Linq;
|
||||
using ImGuiNET;
|
||||
using Penumbra.Mods;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class TabEffective
|
||||
{
|
||||
private const string LabelTab = "Effective File List";
|
||||
private const float TextSizePadding = 5f;
|
||||
|
||||
private ModManager _mods;
|
||||
private (string, string)[] _fileList = null;
|
||||
private float _maxGamePath = 0f;
|
||||
|
||||
public TabEffective(SettingsInterface ui)
|
||||
{
|
||||
_mods = ui._plugin.ModManager;
|
||||
RebuildFileList(ui._plugin.Configuration.ShowAdvanced);
|
||||
}
|
||||
|
||||
public void RebuildFileList(bool advanced)
|
||||
{
|
||||
if (advanced)
|
||||
{
|
||||
_fileList = _mods.ResolvedFiles.Select( P => (P.Value.FullName, P.Key) ).ToArray();
|
||||
_maxGamePath = ((_fileList.Length > 0) ? _fileList.Max( P => ImGui.CalcTextSize(P.Item2).X ) : 0f) + TextSizePadding;
|
||||
}
|
||||
else
|
||||
{
|
||||
_fileList = null;
|
||||
_maxGamePath = 0f;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawFileLine((string, string) file)
|
||||
{
|
||||
ImGui.Selectable(file.Item2);
|
||||
ImGui.SameLine();
|
||||
ImGui.SetCursorPosX(_maxGamePath);
|
||||
ImGui.TextUnformatted(" <-- ");
|
||||
ImGui.SameLine();
|
||||
ImGui.Selectable(file.Item1);
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( LabelTab );
|
||||
if( !ret )
|
||||
return;
|
||||
|
||||
if( ImGui.ListBoxHeader( "##effective_files", AutoFillSize ) )
|
||||
{
|
||||
foreach( var file in _fileList )
|
||||
DrawFileLine(file);
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
126
Penumbra/UI/TabImport.cs
Normal file
126
Penumbra/UI/TabImport.cs
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
using ImGuiNET;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
using System.IO;
|
||||
using System;
|
||||
using Penumbra.Importer;
|
||||
using Dalamud.Plugin;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class TabImport
|
||||
{
|
||||
private const string LabelTab = "Import Mods";
|
||||
private const string LabelImportButton = "Import TexTools Modpacks";
|
||||
private const string FileTypeFilter = "TexTools TTMP Modpack (*.ttmp2)|*.ttmp*|All files (*.*)|*.*";
|
||||
private const string LabelFileDialog = "Pick one or more modpacks.";
|
||||
private const string LabelFileImportRunning = "Import in progress...";
|
||||
private const string TooltipModpack1 = "Writing modpack to disk before extracting...";
|
||||
|
||||
private static readonly Vector2 ImportBarSize = new( -1, 0 );
|
||||
|
||||
private bool _isImportRunning = false;
|
||||
private TexToolsImport _texToolsImport = null!;
|
||||
private readonly SettingsInterface _base;
|
||||
|
||||
public TabImport(SettingsInterface ui) => _base = ui;
|
||||
|
||||
public bool IsImporting() => _isImportRunning;
|
||||
|
||||
private void RunImportTask()
|
||||
{
|
||||
_isImportRunning = true;
|
||||
Task.Run( async () =>
|
||||
{
|
||||
var picker = new OpenFileDialog
|
||||
{
|
||||
Multiselect = true,
|
||||
Filter = FileTypeFilter,
|
||||
CheckFileExists = true,
|
||||
Title = LabelFileDialog
|
||||
};
|
||||
|
||||
var result = await picker.ShowDialogAsync();
|
||||
|
||||
if( result == DialogResult.OK )
|
||||
{
|
||||
foreach( var fileName in picker.FileNames )
|
||||
{
|
||||
PluginLog.Log( $"-> {fileName} START");
|
||||
|
||||
try
|
||||
{
|
||||
_texToolsImport = new TexToolsImport( new DirectoryInfo( _base._plugin.Configuration.CurrentCollection ) );
|
||||
_texToolsImport.ImportModPack( new FileInfo( fileName ) );
|
||||
}
|
||||
catch( Exception ex )
|
||||
{
|
||||
PluginLog.LogError( ex, "Could not import one or more modpacks." );
|
||||
}
|
||||
|
||||
PluginLog.Log( $"-> {fileName} OK!");
|
||||
}
|
||||
|
||||
_texToolsImport = null;
|
||||
_base.ReloadMods();
|
||||
}
|
||||
_isImportRunning = false;
|
||||
} );
|
||||
}
|
||||
|
||||
private void DrawImportButton()
|
||||
{
|
||||
if( ImGui.Button( LabelImportButton ) )
|
||||
{
|
||||
RunImportTask();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawImportProgress()
|
||||
{
|
||||
ImGui.Button( LabelFileImportRunning );
|
||||
|
||||
if( _texToolsImport != null )
|
||||
{
|
||||
switch( _texToolsImport.State )
|
||||
{
|
||||
case ImporterState.None:
|
||||
break;
|
||||
case ImporterState.WritingPackToDisk:
|
||||
ImGui.Text( TooltipModpack1 );
|
||||
break;
|
||||
case ImporterState.ExtractingModFiles:
|
||||
{
|
||||
var str =
|
||||
$"{_texToolsImport.CurrentModPack} - {_texToolsImport.CurrentProgress} of {_texToolsImport.TotalProgress} files";
|
||||
|
||||
ImGui.ProgressBar( _texToolsImport.Progress, ImportBarSize, str );
|
||||
break;
|
||||
}
|
||||
case ImporterState.Done:
|
||||
break;
|
||||
default:
|
||||
throw new ArgumentOutOfRangeException();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( LabelTab );
|
||||
if( !ret )
|
||||
return;
|
||||
|
||||
if( !_isImportRunning )
|
||||
DrawImportButton();
|
||||
else
|
||||
DrawImportProgress();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
53
Penumbra/UI/TabInstalled.cs
Normal file
53
Penumbra/UI/TabInstalled.cs
Normal file
|
|
@ -0,0 +1,53 @@
|
|||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private partial class TabInstalled
|
||||
{
|
||||
private const string LabelTab = "Installed Mods";
|
||||
|
||||
private readonly SettingsInterface _base;
|
||||
public readonly Selector _selector;
|
||||
public readonly ModPanel _modPanel;
|
||||
|
||||
public TabInstalled(SettingsInterface ui)
|
||||
{
|
||||
_base = ui;
|
||||
_selector = new(_base);
|
||||
_modPanel = new(_base, _selector);
|
||||
}
|
||||
|
||||
private void DrawNoModsAvailable()
|
||||
{
|
||||
ImGui.Text( "You don't have any mods :(" );
|
||||
ImGuiCustom.VerticalDistance(20f);
|
||||
ImGui.Text( "You'll need to install them first by creating a folder close to the root of your drive (preferably an SSD)." );
|
||||
ImGui.Text( "For example: D:/ffxiv/mods/" );
|
||||
ImGui.Text( "And pasting that path into the settings tab and clicking the 'Rediscover Mods' button." );
|
||||
ImGui.Text( "You can return to this tab once you've done that." );
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( LabelTab );
|
||||
if( !ret )
|
||||
return;
|
||||
|
||||
if (_base._plugin.ModManager.Mods != null)
|
||||
{
|
||||
_selector.Draw();
|
||||
ImGui.SameLine();
|
||||
_modPanel.Draw();
|
||||
}
|
||||
else
|
||||
DrawNoModsAvailable();
|
||||
|
||||
ImGui.EndTabItem();
|
||||
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
806
Penumbra/UI/TabInstalledDetails.cs
Normal file
806
Penumbra/UI/TabInstalledDetails.cs
Normal file
|
|
@ -0,0 +1,806 @@
|
|||
using Penumbra.Models;
|
||||
using ImGuiNET;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
internal static class Extension
|
||||
{
|
||||
// Remove the entry at idx from the list if the new string is empty, otherwise replace it.
|
||||
public static void RemoveOrChange(this List<string> list, string newString, int idx)
|
||||
{
|
||||
if (newString?.Length == 0)
|
||||
list.RemoveAt(idx);
|
||||
else
|
||||
list[idx] = newString;
|
||||
}
|
||||
}
|
||||
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class PluginDetails
|
||||
{
|
||||
#region ========== Literals ===============
|
||||
private const string LabelPluginDetails = "PenumbraPluginDetails";
|
||||
private const string LabelAboutTab = "About";
|
||||
private const string TooltipAboutEdit = "Use Ctrl+Enter for newlines.";
|
||||
private const string LabelDescEdit = "##descedit";
|
||||
private const string LabelChangedItemsTab = "Changed Items";
|
||||
private const string LabelChangedItemsHeader = "##changedItems";
|
||||
private const string LabelChangedItemIdx = "##citem_";
|
||||
private const string LabelChangedItemNew = "##citem_new";
|
||||
private const string LabelConflictsTab = "File Conflicts";
|
||||
private const string LabelConflictsHeader = "##conflicts";
|
||||
private const string LabelFileSwapTab = "File Swaps";
|
||||
private const string LabelFileSwapHeader = "##fileSwaps";
|
||||
private const string LabelFileListTab = "Files";
|
||||
private const string LabelFileListHeader = "##fileList";
|
||||
private const string TooltipFilesTab = "Green files replace their standard game path counterpart (not in any option) or are in all options of a Single-Select option.\nYellow files are restricted to some options.";
|
||||
private const string ButtonAddToGroup = "Add to Group";
|
||||
private const string ButtonRemoveFromGroup = "Remove from Group";
|
||||
private const string LabelGroupSelect = "##groupSelect";
|
||||
private const string LabelOptionSelect = "##optionSelect";
|
||||
private const string TextNoOptionAvailable = "[No Option Available]";
|
||||
private const string LabelConfigurationTab = "Configuration";
|
||||
private const string LabelNewSingleGroup = "New Single Group";
|
||||
private const string LabelNewSingleGroupEdit = "##newSingleGroup";
|
||||
private const string LabelNewMultiGroup = "New Multi Group";
|
||||
private const string TextDefaultGamePath = "default";
|
||||
private const string LabelGamePathsEdit = "Game Paths";
|
||||
private const string LabelGamePathsEditBox = "##gamePathsEdit";
|
||||
private const string TooltipGamePathText = "Click to copy to clipboard.";
|
||||
private static readonly string TooltipGamePathsEdit = $"Enter all game paths to add or remove, separated by '{GamePathsSeparator}'.\nUse '{TextDefaultGamePath}' to add the original file path.";
|
||||
private static readonly string TooltipFilesTabEdit = $"{TooltipFilesTab}\nRed Files are replaced in another group or a different option in this group, but not contained in the current option.";
|
||||
|
||||
private const char GamePathsSeparator = ';';
|
||||
private const float TextSizePadding = 5f;
|
||||
private const float OptionSelectionWidth = 140f;
|
||||
private const float CheckMarkSize = 50f;
|
||||
private const float MultiEditBoxWidth = 300f;
|
||||
private const uint ColorGreen = 0xFF00C800;
|
||||
private const uint ColorYellow = 0xFF00C8C8;
|
||||
private const uint ColorRed = 0xFF0000C8;
|
||||
#endregion
|
||||
|
||||
#region ========== State ==================
|
||||
private bool _editMode = false;
|
||||
private int _selectedGroupIndex = 0;
|
||||
private InstallerInfo? _selectedGroup = null;
|
||||
private int _selectedOptionIndex = 0;
|
||||
private Option? _selectedOption = null;
|
||||
private (string label, string name)[] _changedItemsList = null;
|
||||
private float? _fileSwapOffset = null;
|
||||
private string _currentGamePaths = "";
|
||||
|
||||
private (string name, bool selected, uint color, string relName)[] _fullFilenameList = null;
|
||||
|
||||
public void SelectGroup(int idx)
|
||||
{
|
||||
_selectedGroupIndex = idx;
|
||||
if (_selectedGroupIndex >= Meta?.Groups?.Count)
|
||||
_selectedGroupIndex = 0;
|
||||
if (Meta?.Groups?.Count > 0)
|
||||
_selectedGroup = Meta.Groups.ElementAt(_selectedGroupIndex).Value;
|
||||
else
|
||||
_selectedGroup = null;
|
||||
}
|
||||
public void SelectGroup() => SelectGroup(_selectedGroupIndex);
|
||||
|
||||
public void SelectOption(int idx)
|
||||
{
|
||||
_selectedOptionIndex = idx;
|
||||
if (_selectedOptionIndex >= _selectedGroup?.Options.Count)
|
||||
_selectedOptionIndex = 0;
|
||||
if (_selectedGroup?.Options.Count > 0)
|
||||
_selectedOption = ((InstallerInfo) _selectedGroup).Options[_selectedOptionIndex];
|
||||
else
|
||||
_selectedOption = null;
|
||||
}
|
||||
public void SelectOption() => SelectOption(_selectedOptionIndex);
|
||||
|
||||
public void ResetState()
|
||||
{
|
||||
_changedItemsList = null;
|
||||
_fileSwapOffset = null;
|
||||
_fullFilenameList = null;
|
||||
SelectGroup();
|
||||
SelectOption();
|
||||
}
|
||||
|
||||
|
||||
private readonly Selector _selector;
|
||||
private readonly SettingsInterface _base;
|
||||
public PluginDetails(SettingsInterface ui, Selector s)
|
||||
{
|
||||
_base = ui;
|
||||
_selector = s;
|
||||
ResetState();
|
||||
}
|
||||
|
||||
private ModInfo Mod { get{ return _selector.Mod(); } }
|
||||
private ModMeta Meta { get{ return Mod?.Mod?.Meta; } }
|
||||
|
||||
private void Save()
|
||||
{
|
||||
_base._plugin.ModManager.Mods.Save();
|
||||
_base._plugin.ModManager.CalculateEffectiveFileList();
|
||||
_base._menu._effectiveTab.RebuildFileList(_base._plugin.Configuration.ShowAdvanced);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region ========== Tabs ===================
|
||||
private void DrawAboutTab()
|
||||
{
|
||||
if (!_editMode && Meta.Description?.Length == 0)
|
||||
return;
|
||||
|
||||
if(ImGui.BeginTabItem( LabelAboutTab ) )
|
||||
{
|
||||
var desc = Meta.Description;
|
||||
var flags = _editMode
|
||||
? ImGuiInputTextFlags.EnterReturnsTrue | ImGuiInputTextFlags.CtrlEnterForNewLine
|
||||
: ImGuiInputTextFlags.ReadOnly;
|
||||
|
||||
if (ImGui.InputTextMultiline(LabelDescEdit, ref desc, 1 << 16, AutoFillSize, flags))
|
||||
{
|
||||
Meta.Description = desc;
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
if (_editMode && ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip( TooltipAboutEdit );
|
||||
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawChangedItemsTab()
|
||||
{
|
||||
if (!_editMode && Meta.ChangedItems?.Count == 0)
|
||||
return;
|
||||
|
||||
var flags = _editMode
|
||||
? ImGuiInputTextFlags.EnterReturnsTrue
|
||||
: ImGuiInputTextFlags.ReadOnly;
|
||||
|
||||
if( ImGui.BeginTabItem( LabelChangedItemsTab ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( LabelChangedItemsHeader, AutoFillSize ) )
|
||||
{
|
||||
if (_changedItemsList == null)
|
||||
_changedItemsList = Meta.ChangedItems.Select( (I, index) => ($"{LabelChangedItemIdx}{index}", I) ).ToArray();
|
||||
for (var i = 0; i < Meta.ChangedItems.Count; ++i)
|
||||
{
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
if ( ImGui.InputText(_changedItemsList[i].label, ref _changedItemsList[i].name, 128, flags) )
|
||||
{
|
||||
Meta.ChangedItems.RemoveOrChange(_changedItemsList[i].name, i);
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
}
|
||||
var newItem = "";
|
||||
if ( _editMode )
|
||||
{
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
if ( ImGui.InputText( LabelChangedItemNew, ref newItem, 128, flags) )
|
||||
{
|
||||
if (newItem.Length > 0)
|
||||
{
|
||||
if (Meta.ChangedItems == null)
|
||||
Meta.ChangedItems = new(){ newItem };
|
||||
else
|
||||
Meta.ChangedItems.Add(newItem);
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
}
|
||||
}
|
||||
ImGui.ListBoxFooter();
|
||||
}
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
else
|
||||
_changedItemsList = null;
|
||||
}
|
||||
|
||||
private void DrawConflictTab()
|
||||
{
|
||||
if( Mod.Mod.FileConflicts.Any() )
|
||||
{
|
||||
if( ImGui.BeginTabItem( LabelConflictsTab ) )
|
||||
{
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( LabelConflictsHeader, AutoFillSize ) )
|
||||
{
|
||||
foreach( var kv in Mod.Mod.FileConflicts )
|
||||
{
|
||||
var mod = kv.Key;
|
||||
if( ImGui.Selectable( mod ) )
|
||||
_selector.SelectModByName( mod );
|
||||
|
||||
ImGui.Indent( 15 );
|
||||
foreach( var file in kv.Value )
|
||||
ImGui.Selectable( file );
|
||||
ImGui.Unindent( 15 );
|
||||
}
|
||||
ImGui.ListBoxFooter();
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawFileSwapTab()
|
||||
{
|
||||
if( Meta.FileSwaps.Any() )
|
||||
{
|
||||
if( ImGui.BeginTabItem( LabelFileSwapTab ) )
|
||||
{
|
||||
if (_fileSwapOffset == null)
|
||||
_fileSwapOffset = Meta.FileSwaps.Max( P => ImGui.CalcTextSize(P.Key).X) + TextSizePadding;
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( LabelFileSwapHeader, AutoFillSize ) )
|
||||
{
|
||||
foreach( var file in Meta.FileSwaps )
|
||||
{
|
||||
ImGui.Selectable(file.Key);
|
||||
ImGui.SameLine(_fileSwapOffset ?? 0);
|
||||
ImGui.TextUnformatted(" -> ");
|
||||
ImGui.Selectable(file.Value);
|
||||
}
|
||||
ImGui.ListBoxFooter();
|
||||
}
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
else
|
||||
_fileSwapOffset = null;
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ========== FileList ===============
|
||||
private void UpdateFilenameList()
|
||||
{
|
||||
if (_fullFilenameList == null)
|
||||
{
|
||||
var len = Mod.Mod.ModBasePath.FullName.Length;
|
||||
_fullFilenameList = Mod.Mod.ModFiles.Select( F => (F.FullName, false, ColorGreen, "") ).ToArray();
|
||||
|
||||
if(Meta.Groups?.Count == 0)
|
||||
return;
|
||||
|
||||
for (var i = 0; i < Mod.Mod.ModFiles.Count; ++i)
|
||||
{
|
||||
_fullFilenameList[i].relName = _fullFilenameList[i].name.Substring(len).TrimStart('\\');
|
||||
foreach (var Group in Meta.Groups.Values)
|
||||
{
|
||||
var inAll = true;
|
||||
foreach (var Option in Group.Options)
|
||||
{
|
||||
if (Option.OptionFiles.ContainsKey(_fullFilenameList[i].relName))
|
||||
_fullFilenameList[i].color = ColorYellow;
|
||||
else
|
||||
inAll = false;
|
||||
}
|
||||
if (inAll && Group.SelectionType == SelectType.Single)
|
||||
_fullFilenameList[i].color = ColorGreen;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawFileListTab()
|
||||
{
|
||||
if( ImGui.BeginTabItem( LabelFileListTab ) )
|
||||
{
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip( TooltipFilesTab );
|
||||
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( LabelFileListHeader, AutoFillSize ) )
|
||||
{
|
||||
UpdateFilenameList();
|
||||
foreach(var file in _fullFilenameList)
|
||||
{
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, file.color);
|
||||
ImGui.Selectable(file.name);
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
ImGui.ListBoxFooter();
|
||||
}
|
||||
else
|
||||
_fullFilenameList = null;
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
private void HandleSelectedFilesButton(bool remove)
|
||||
{
|
||||
if (_selectedOption == null)
|
||||
return;
|
||||
var option = (Option) _selectedOption;
|
||||
|
||||
var gamePaths = _currentGamePaths.Split(';');
|
||||
if (gamePaths.Length == 0 || gamePaths[0].Length == 0)
|
||||
return;
|
||||
|
||||
int? defaultIndex = null;
|
||||
for (var i = 0; i < gamePaths.Length; ++i)
|
||||
{
|
||||
if (gamePaths[i] == TextDefaultGamePath )
|
||||
{
|
||||
defaultIndex = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
var baseLength = Mod.Mod.ModBasePath.FullName.Length;
|
||||
var changed = false;
|
||||
for (var i = 0; i < Mod.Mod.ModFiles.Count; ++i)
|
||||
{
|
||||
if (!_fullFilenameList[i].selected)
|
||||
continue;
|
||||
|
||||
var fileName = _fullFilenameList[i].relName;
|
||||
if (defaultIndex != null)
|
||||
gamePaths[(int)defaultIndex] = fileName.Replace('\\', '/');
|
||||
|
||||
if (remove && option.OptionFiles.TryGetValue(fileName, out var setPaths))
|
||||
{
|
||||
if (setPaths.RemoveWhere( P => gamePaths.Contains(P)) > 0)
|
||||
changed = true;
|
||||
if (setPaths.Count == 0 && option.OptionFiles.Remove(fileName))
|
||||
changed = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach(var gamePath in gamePaths)
|
||||
changed |= option.AddFile(fileName, gamePath);
|
||||
}
|
||||
}
|
||||
if (changed)
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
|
||||
private void DrawAddToGroupButton()
|
||||
{
|
||||
if (ImGui.Button( ButtonAddToGroup ) )
|
||||
HandleSelectedFilesButton(false);
|
||||
}
|
||||
|
||||
private void DrawRemoveFromGroupButton()
|
||||
{
|
||||
if (ImGui.Button( ButtonRemoveFromGroup ) )
|
||||
HandleSelectedFilesButton(true);
|
||||
}
|
||||
|
||||
private void DrawEditGroupSelector()
|
||||
{
|
||||
ImGui.SetNextItemWidth( OptionSelectionWidth );
|
||||
if (Meta.Groups.Count == 0)
|
||||
{
|
||||
ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, TextNoOptionAvailable, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (ImGui.Combo( LabelGroupSelect, ref _selectedGroupIndex, Meta.Groups.Values.Select( G => G.GroupName ).ToArray(), Meta.Groups.Count))
|
||||
{
|
||||
SelectGroup();
|
||||
SelectOption(0);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEditOptionSelector()
|
||||
{
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth( OptionSelectionWidth );
|
||||
if (_selectedGroup?.Options.Count == 0)
|
||||
{
|
||||
ImGui.Combo( LabelOptionSelect, ref _selectedOptionIndex, TextNoOptionAvailable, 1);
|
||||
return;
|
||||
}
|
||||
|
||||
var group = (InstallerInfo) _selectedGroup;
|
||||
if (ImGui.Combo( LabelOptionSelect, ref _selectedOptionIndex, group.Options.Select(O => O.OptionName).ToArray(), group.Options.Count))
|
||||
SelectOption();
|
||||
}
|
||||
|
||||
private void DrawGamePathInput()
|
||||
{
|
||||
ImGui.TextUnformatted( LabelGamePathsEdit );
|
||||
ImGui.SameLine();
|
||||
ImGui.SetNextItemWidth(-1);
|
||||
ImGui.InputText(LabelGamePathsEditBox, ref _currentGamePaths, 128);
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip(TooltipGamePathsEdit);
|
||||
}
|
||||
|
||||
private void DrawGroupRow()
|
||||
{
|
||||
if (_selectedGroup == null)
|
||||
SelectGroup();
|
||||
if (_selectedOption == null)
|
||||
SelectOption();
|
||||
|
||||
DrawEditGroupSelector();
|
||||
ImGui.SameLine();
|
||||
DrawEditOptionSelector();
|
||||
ImGui.SameLine();
|
||||
DrawAddToGroupButton();
|
||||
ImGui.SameLine();
|
||||
DrawRemoveFromGroupButton();
|
||||
ImGui.SameLine();
|
||||
DrawGamePathInput();
|
||||
}
|
||||
|
||||
private void DrawFileAndGamePaths(int idx)
|
||||
{
|
||||
void Selectable(uint colorNormal, uint colorReplace)
|
||||
{
|
||||
var loc = _fullFilenameList[idx].color;
|
||||
if (loc == colorNormal)
|
||||
loc = colorReplace;
|
||||
ImGui.PushStyleColor(ImGuiCol.Text, loc);
|
||||
ImGui.Selectable( _fullFilenameList[idx].name, ref _fullFilenameList[idx].selected );
|
||||
ImGui.PopStyleColor();
|
||||
}
|
||||
|
||||
const float indent = 30f;
|
||||
if (_selectedOption == null)
|
||||
{
|
||||
Selectable(0, ColorGreen);
|
||||
return;
|
||||
}
|
||||
|
||||
var fileName = _fullFilenameList[idx].relName;
|
||||
if (((Option) _selectedOption).OptionFiles.TryGetValue(fileName, out var gamePaths))
|
||||
{
|
||||
Selectable(0, ColorGreen);
|
||||
|
||||
ImGui.Indent(indent);
|
||||
foreach (var gamePath in gamePaths)
|
||||
{
|
||||
ImGui.Text(gamePath);
|
||||
if (ImGui.IsItemClicked())
|
||||
ImGui.SetClipboardText(gamePath);
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip( TooltipGamePathText );
|
||||
}
|
||||
ImGui.Unindent(indent);
|
||||
}
|
||||
else
|
||||
Selectable(ColorYellow, ColorRed);
|
||||
}
|
||||
|
||||
private void DrawFileListTabEdit()
|
||||
{
|
||||
if( ImGui.BeginTabItem( LabelFileListTab ) )
|
||||
{
|
||||
UpdateFilenameList();
|
||||
if (ImGui.IsItemHovered())
|
||||
ImGui.SetTooltip( _editMode ? TooltipFilesTabEdit : TooltipFilesTab );
|
||||
|
||||
ImGui.SetNextItemWidth( -1 );
|
||||
if( ImGui.ListBoxHeader( LabelFileListHeader, AutoFillSize - new Vector2(0, 1.5f * ImGui.GetTextLineHeight()) ) )
|
||||
for(var i = 0; i < Mod.Mod.ModFiles.Count; ++i)
|
||||
DrawFileAndGamePaths(i);
|
||||
|
||||
ImGui.ListBoxFooter();
|
||||
|
||||
DrawGroupRow();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
else
|
||||
_fullFilenameList = null;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ========== Configuration ==========
|
||||
#region ========== MultiSelectorEdit ==========
|
||||
private bool DrawMultiSelectorEditBegin(InstallerInfo group)
|
||||
{
|
||||
var groupName = group.GroupName;
|
||||
if (ImGuiCustom.BeginFramedGroupEdit(ref groupName)
|
||||
&& groupName != group.GroupName && !Meta.Groups.ContainsKey(groupName))
|
||||
{
|
||||
var oldConf = Mod.Conf[group.GroupName];
|
||||
Meta.Groups.Remove(group.GroupName);
|
||||
Mod.Conf.Remove(group.GroupName);
|
||||
if (groupName.Length > 0)
|
||||
{
|
||||
Meta.Groups[groupName] = new(){ GroupName = groupName, SelectionType = SelectType.Multi, Options = group.Options };
|
||||
Mod.Conf[groupName] = oldConf;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
private void DrawMultiSelectorEditAdd(InstallerInfo group, float nameBoxStart)
|
||||
{
|
||||
var newOption = "";
|
||||
ImGui.SetCursorPosX(nameBoxStart);
|
||||
ImGui.SetNextItemWidth(MultiEditBoxWidth);
|
||||
if (ImGui.InputText($"##new_{group.GroupName}_l", ref newOption, 64, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
if (newOption.Length != 0)
|
||||
{
|
||||
group.Options.Add(new(){ OptionName = newOption, OptionDesc = "", OptionFiles = new() });
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMultiSelectorEdit(InstallerInfo group)
|
||||
{
|
||||
var nameBoxStart = CheckMarkSize;
|
||||
var flag = Mod.Conf[group.GroupName];
|
||||
|
||||
var modChanged = DrawMultiSelectorEditBegin(group);
|
||||
|
||||
for (var i = 0; i < group.Options.Count; ++i)
|
||||
{
|
||||
var opt = group.Options[i];
|
||||
var label = $"##{opt.OptionName}_{group.GroupName}";
|
||||
DrawMultiSelectorCheckBox(group, i, flag, label);
|
||||
|
||||
ImGui.SameLine();
|
||||
var newName = opt.OptionName;
|
||||
|
||||
if (nameBoxStart == CheckMarkSize)
|
||||
nameBoxStart = ImGui.GetCursorPosX();
|
||||
|
||||
ImGui.SetNextItemWidth(MultiEditBoxWidth);
|
||||
if (ImGui.InputText($"{label}_l", ref newName, 64, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
{
|
||||
if (newName.Length == 0)
|
||||
{
|
||||
group.Options.RemoveAt(i);
|
||||
var bitmaskFront = (1 << i) - 1;
|
||||
Mod.Conf[group.GroupName] = (flag & bitmaskFront) | ((flag & ~bitmaskFront) >> 1);
|
||||
modChanged = true;
|
||||
}
|
||||
else if (newName != opt.OptionName)
|
||||
{
|
||||
group.Options[i] = new(){ OptionName = newName, OptionDesc = opt.OptionDesc, OptionFiles = opt.OptionFiles };
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
DrawMultiSelectorEditAdd(group, nameBoxStart);
|
||||
|
||||
if (modChanged)
|
||||
{
|
||||
_selector.SaveCurrentMod();
|
||||
Save();
|
||||
}
|
||||
|
||||
ImGuiCustom.EndFramedGroup();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region ========== SingleSelectorEdit ==========
|
||||
private bool DrawSingleSelectorEditGroup(InstallerInfo group)
|
||||
{
|
||||
var groupName = group.GroupName;
|
||||
if (ImGui.InputText($"##{groupName}_add", ref groupName, 64, ImGuiInputTextFlags.EnterReturnsTrue)
|
||||
&& !Meta.Groups.ContainsKey(groupName))
|
||||
{
|
||||
var oldConf = Mod.Conf[group.GroupName];
|
||||
if (groupName != group.GroupName)
|
||||
{
|
||||
Meta.Groups.Remove(group.GroupName);
|
||||
Mod.Conf.Remove(group.GroupName);
|
||||
}
|
||||
if (groupName.Length > 0)
|
||||
{
|
||||
Meta.Groups.Add(groupName, new InstallerInfo(){ GroupName = groupName, Options = group.Options, SelectionType = SelectType.Single } );
|
||||
Mod.Conf[groupName] = oldConf;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private float DrawSingleSelectorEdit(InstallerInfo group)
|
||||
{
|
||||
var code = Mod.Conf[group.GroupName];
|
||||
var selectionChanged = false;
|
||||
var modChanged = false;
|
||||
var newName = "";
|
||||
if (ImGuiCustom.RenameableCombo($"##{group.GroupName}", ref code, ref newName, group.Options.Select( x => x.OptionName ).ToArray(), group.Options.Count))
|
||||
{
|
||||
if (code == group.Options.Count)
|
||||
{
|
||||
if (newName.Length > 0)
|
||||
{
|
||||
selectionChanged = true;
|
||||
modChanged = true;
|
||||
Mod.Conf[group.GroupName] = code;
|
||||
group.Options.Add(new(){ OptionName = newName, OptionDesc = "", OptionFiles = new()});
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (newName.Length == 0)
|
||||
{
|
||||
modChanged = true;
|
||||
group.Options.RemoveAt(code);
|
||||
if (code >= group.Options.Count)
|
||||
code = 0;
|
||||
}
|
||||
else if (newName != group.Options[code].OptionName)
|
||||
{
|
||||
modChanged = true;
|
||||
group.Options[code] = new Option(){ OptionName = newName, OptionDesc = group.Options[code].OptionDesc, OptionFiles = group.Options[code].OptionFiles};
|
||||
}
|
||||
if (Mod.Conf[group.GroupName] != code)
|
||||
{
|
||||
selectionChanged = true;
|
||||
Mod.Conf[group.GroupName] = code;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
var labelEditPos = ImGui.GetCursorPosX();
|
||||
modChanged |= DrawSingleSelectorEditGroup(group);
|
||||
|
||||
if (modChanged)
|
||||
_selector.SaveCurrentMod();
|
||||
|
||||
if (selectionChanged)
|
||||
Save();
|
||||
|
||||
return labelEditPos;
|
||||
}
|
||||
#endregion
|
||||
private void AddNewGroup(string newGroup, SelectType selectType)
|
||||
{
|
||||
if (!Meta.Groups.ContainsKey(newGroup) && newGroup.Length > 0)
|
||||
{
|
||||
Meta.Groups[newGroup] = new ()
|
||||
{
|
||||
GroupName = newGroup,
|
||||
SelectionType = selectType,
|
||||
Options = new()
|
||||
} ;
|
||||
|
||||
Mod.Conf[newGroup] = 0;
|
||||
_selector.SaveCurrentMod();
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAddSingleGroupField(float labelEditPos)
|
||||
{
|
||||
var newGroup = "";
|
||||
if(labelEditPos == CheckMarkSize)
|
||||
{
|
||||
ImGui.SetCursorPosX(CheckMarkSize);
|
||||
ImGui.SetNextItemWidth(MultiEditBoxWidth);
|
||||
if (ImGui.InputText(LabelNewSingleGroup, ref newGroup, 64, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
AddNewGroup(newGroup, SelectType.Single);
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiCustom.RightJustifiedLabel(labelEditPos, LabelNewSingleGroup );
|
||||
if (ImGui.InputText(LabelNewSingleGroupEdit, ref newGroup, 64, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
AddNewGroup(newGroup, SelectType.Single);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAddMultiGroupField()
|
||||
{
|
||||
var newGroup = "";
|
||||
ImGui.SetCursorPosX(CheckMarkSize);
|
||||
ImGui.SetNextItemWidth(MultiEditBoxWidth);
|
||||
if (ImGui.InputText(LabelNewMultiGroup, ref newGroup, 64, ImGuiInputTextFlags.EnterReturnsTrue))
|
||||
AddNewGroup(newGroup, SelectType.Multi);
|
||||
}
|
||||
|
||||
private void DrawGroupSelectorsEdit()
|
||||
{
|
||||
var labelEditPos = CheckMarkSize;
|
||||
foreach( var g in Meta.Groups.Values.Where( g => g.SelectionType == SelectType.Single ) )
|
||||
labelEditPos = DrawSingleSelectorEdit(g);
|
||||
DrawAddSingleGroupField(labelEditPos);
|
||||
|
||||
foreach(var g in Meta.Groups.Values.Where( g => g.SelectionType == SelectType.Multi ))
|
||||
DrawMultiSelectorEdit(g);
|
||||
DrawAddMultiGroupField();
|
||||
}
|
||||
|
||||
#region Non-Edit
|
||||
|
||||
private void DrawMultiSelectorCheckBox(InstallerInfo group, int idx, int flag, string label)
|
||||
{
|
||||
var opt = group.Options[idx];
|
||||
var enabled = ( flag & (1 << idx)) != 0;
|
||||
var oldEnabled = enabled;
|
||||
if (ImGui.Checkbox(label, ref enabled))
|
||||
{
|
||||
if (oldEnabled != enabled)
|
||||
{
|
||||
Mod.Conf[group.GroupName] ^= (1 << idx);
|
||||
Save();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawMultiSelector(InstallerInfo group)
|
||||
{
|
||||
if (group.Options.Count == 0)
|
||||
return;
|
||||
|
||||
ImGuiCustom.BeginFramedGroup(group.GroupName);
|
||||
for(var i = 0; i < group.Options.Count; ++i)
|
||||
DrawMultiSelectorCheckBox(group, i, Mod.Conf[group.GroupName], $"{group.Options[i].OptionName}##{group.GroupName}");
|
||||
|
||||
ImGuiCustom.EndFramedGroup();
|
||||
}
|
||||
|
||||
private void DrawSingleSelector(InstallerInfo group)
|
||||
{
|
||||
if (group.Options.Count < 2)
|
||||
return;
|
||||
var code = Mod.Conf[group.GroupName];
|
||||
if( ImGui.Combo( group.GroupName, ref code, group.Options.Select( x => x.OptionName ).ToArray(), group.Options.Count ) )
|
||||
{
|
||||
Mod.Conf[group.GroupName] = code;
|
||||
Save();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawGroupSelectors()
|
||||
{
|
||||
foreach(var g in Meta.Groups.Values.Where( g => g.SelectionType == SelectType.Single ) )
|
||||
DrawSingleSelector(g);
|
||||
foreach(var g in Meta.Groups.Values.Where( g => g.SelectionType == SelectType.Multi ))
|
||||
DrawMultiSelector(g);
|
||||
return;
|
||||
}
|
||||
#endregion
|
||||
|
||||
|
||||
private void DrawConfigurationTab()
|
||||
{
|
||||
if (!_editMode && !Meta.HasGroupWithConfig)
|
||||
return;
|
||||
|
||||
if(ImGui.BeginTabItem( LabelConfigurationTab ) )
|
||||
{
|
||||
if (_editMode)
|
||||
DrawGroupSelectorsEdit();
|
||||
else
|
||||
DrawGroupSelectors();
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Draw(bool editMode)
|
||||
{
|
||||
_editMode = editMode;
|
||||
ImGui.BeginTabBar( LabelPluginDetails );
|
||||
|
||||
DrawAboutTab();
|
||||
DrawChangedItemsTab();
|
||||
DrawConfigurationTab();
|
||||
if (_editMode)
|
||||
DrawFileListTabEdit();
|
||||
else
|
||||
DrawFileListTab();
|
||||
DrawFileSwapTab();
|
||||
DrawConflictTab();
|
||||
|
||||
ImGui.EndTabBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
287
Penumbra/UI/TabInstalledModPanel.cs
Normal file
287
Penumbra/UI/TabInstalledModPanel.cs
Normal file
|
|
@ -0,0 +1,287 @@
|
|||
using ImGuiNET;
|
||||
using Dalamud.Plugin;
|
||||
using System;
|
||||
using System.Numerics;
|
||||
using System.Diagnostics;
|
||||
using Penumbra.Models;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class ModPanel
|
||||
{
|
||||
private const string LabelModPanel = "selectedModInfo";
|
||||
private const string LabelEditName = "##editName";
|
||||
private const string LabelEditVersion = "##editVersion";
|
||||
private const string LabelEditAuthor = "##editAuthor";
|
||||
private const string LabelEditWebsite = "##editWebsite";
|
||||
private const string ButtonOpenWebsite = "Open Website";
|
||||
private const string LabelModEnabled = "Enabled";
|
||||
private const string LabelEditingEnabled = "Enable Editing";
|
||||
private const string ButtonOpenModFolder = "Open Mod Folder";
|
||||
private const string TooltipOpenModFolder = "Open the directory containing this mod in your default file explorer.";
|
||||
private const string ButtonEditJson = "Edit JSON";
|
||||
private const string TooltipEditJson = "Open the JSON configuration file in your default application for .json.";
|
||||
private const string ButtonReloadJson = "Reload JSON";
|
||||
private const string TooltipReloadJson = "Reload the configuration of all mods.";
|
||||
private const string ButtonDeduplicate = "Deduplicate";
|
||||
private const string TooltipDeduplicate = "Try to find identical files and remove duplicate occurences to reduce the mods disk size. Introduces an invisible single-option Group \"Duplicates\".";
|
||||
|
||||
private const float HeaderLineDistance = 10f;
|
||||
private static readonly Vector4 GreyColor = new( 1f, 1f, 1f, 0.66f );
|
||||
|
||||
private readonly SettingsInterface _base;
|
||||
private readonly Selector _selector;
|
||||
public readonly PluginDetails _details;
|
||||
|
||||
private bool _editMode = false;
|
||||
private string _currentWebsite;
|
||||
private bool _validWebsite;
|
||||
|
||||
public ModPanel(SettingsInterface ui, Selector s)
|
||||
{
|
||||
_base = ui;
|
||||
_selector = s;
|
||||
_details = new(_base, _selector);
|
||||
_currentWebsite = Meta?.Website;
|
||||
}
|
||||
|
||||
private ModInfo Mod { get{ return _selector.Mod(); } }
|
||||
private ModMeta Meta { get{ return Mod?.Mod.Meta; } }
|
||||
|
||||
#region Header Line Functions
|
||||
private void DrawName()
|
||||
{
|
||||
var name = Meta.Name;
|
||||
if (ImGuiCustom.InputOrText(_editMode, LabelEditName, ref name, 64)
|
||||
&& name.Length > 0 && name != Meta.Name)
|
||||
{
|
||||
Meta.Name = name;
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawVersion()
|
||||
{
|
||||
if (_editMode)
|
||||
{
|
||||
ImGui.BeginGroup();
|
||||
ImGui.Text("(Version ");
|
||||
|
||||
ImGui.PushStyleVar(ImGuiStyleVar.ItemSpacing, ZeroVector);
|
||||
ImGui.SameLine();
|
||||
var version = Meta.Version ?? "";
|
||||
if (ImGuiCustom.ResizingTextInput( LabelEditVersion, ref version, 16)
|
||||
&& version != Meta.Version)
|
||||
{
|
||||
Meta.Version = version.Length > 0 ? version : null;
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
ImGui.Text(")");
|
||||
ImGui.PopStyleVar();
|
||||
ImGui.EndGroup();
|
||||
}
|
||||
else if ((Meta.Version?.Length ?? 0) > 0)
|
||||
{
|
||||
ImGui.Text( $"(Version {Meta.Version})" );
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAuthor()
|
||||
{
|
||||
ImGui.BeginGroup();
|
||||
ImGui.TextColored( GreyColor, "by" );
|
||||
|
||||
ImGui.SameLine();
|
||||
var author = Meta.Author ?? "";
|
||||
if (ImGuiCustom.InputOrText(_editMode, LabelEditAuthor, ref author, 64)
|
||||
&& author != Meta.Author)
|
||||
{
|
||||
Meta.Author = author.Length > 0 ? author : null;
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
ImGui.EndGroup();
|
||||
}
|
||||
|
||||
private void DrawWebsite()
|
||||
{
|
||||
ImGui.BeginGroup();
|
||||
if (_editMode)
|
||||
{
|
||||
ImGui.TextColored( GreyColor, "from" );
|
||||
ImGui.SameLine();
|
||||
var website = Meta.Website ?? "";
|
||||
if (ImGuiCustom.ResizingTextInput(LabelEditWebsite, ref website, 512)
|
||||
&& website != Meta.Website)
|
||||
{
|
||||
Meta.Website = website.Length > 0 ? website : null;
|
||||
_selector.SaveCurrentMod();
|
||||
}
|
||||
}
|
||||
else if (( Meta.Website?.Length ?? 0 ) > 0)
|
||||
{
|
||||
if (_currentWebsite != Meta.Website)
|
||||
{
|
||||
_currentWebsite = Meta.Website;
|
||||
_validWebsite = Uri.TryCreate( Meta.Website, UriKind.Absolute, out var uriResult )
|
||||
&& ( uriResult.Scheme == Uri.UriSchemeHttps || uriResult.Scheme == Uri.UriSchemeHttp );
|
||||
}
|
||||
if( _validWebsite )
|
||||
{
|
||||
if( ImGui.SmallButton( ButtonOpenWebsite ) )
|
||||
{
|
||||
try
|
||||
{
|
||||
var process = new ProcessStartInfo(Meta.Website)
|
||||
{
|
||||
UseShellExecute = true
|
||||
};
|
||||
Process.Start(process);
|
||||
}
|
||||
catch(System.ComponentModel.Win32Exception)
|
||||
{
|
||||
// Do nothing.
|
||||
}
|
||||
}
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( Meta.Website );
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.TextColored( GreyColor, "from" );
|
||||
ImGui.SameLine();
|
||||
ImGui.Text( Meta.Website );
|
||||
}
|
||||
}
|
||||
ImGui.EndGroup();
|
||||
}
|
||||
|
||||
private void DrawHeaderLine()
|
||||
{
|
||||
DrawName();
|
||||
ImGui.SameLine();
|
||||
DrawVersion();
|
||||
ImGui.SameLine();
|
||||
DrawAuthor();
|
||||
ImGui.SameLine();
|
||||
DrawWebsite();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Enabled Checkmarks
|
||||
private void DrawEnabledMark()
|
||||
{
|
||||
var enabled = Mod.Enabled;
|
||||
if( ImGui.Checkbox( LabelModEnabled, ref enabled ) )
|
||||
{
|
||||
Mod.Enabled = enabled;
|
||||
_base._plugin.ModManager.Mods.Save();
|
||||
_base._plugin.ModManager.CalculateEffectiveFileList();
|
||||
_base._menu._effectiveTab.RebuildFileList(_base._plugin.Configuration.ShowAdvanced);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEditableMark()
|
||||
{
|
||||
ImGui.Checkbox( LabelEditingEnabled, ref _editMode);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Edit Line Functions
|
||||
private void DrawOpenModFolderButton()
|
||||
{
|
||||
if( ImGui.Button( ButtonOpenModFolder ) )
|
||||
{
|
||||
Process.Start( Mod.Mod.ModBasePath.FullName );
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( TooltipOpenModFolder );
|
||||
}
|
||||
|
||||
private void DrawEditJsonButton()
|
||||
{
|
||||
if( ImGui.Button( ButtonEditJson ) )
|
||||
{
|
||||
Process.Start( _selector.SaveCurrentMod() );
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( TooltipEditJson );
|
||||
}
|
||||
|
||||
private void DrawReloadJsonButton()
|
||||
{
|
||||
if( ImGui.Button( ButtonReloadJson ) )
|
||||
{
|
||||
_selector.ReloadCurrentMod();
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( TooltipReloadJson );
|
||||
}
|
||||
|
||||
private void DrawDeduplicateButton()
|
||||
{
|
||||
if( ImGui.Button( ButtonDeduplicate ) )
|
||||
{
|
||||
new Deduplicator(Mod.Mod.ModBasePath, Meta).Run();
|
||||
_selector.SaveCurrentMod();
|
||||
_base._menu._effectiveTab.RebuildFileList(_base._plugin.Configuration.ShowAdvanced);
|
||||
}
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( TooltipDeduplicate );
|
||||
}
|
||||
|
||||
private void DrawEditLine()
|
||||
{
|
||||
DrawOpenModFolderButton();
|
||||
ImGui.SameLine();
|
||||
DrawEditJsonButton();
|
||||
ImGui.SameLine();
|
||||
DrawReloadJsonButton();
|
||||
ImGui.SameLine();
|
||||
DrawDeduplicateButton();
|
||||
}
|
||||
#endregion
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if( Mod != null )
|
||||
{
|
||||
try
|
||||
{
|
||||
var ret = ImGui.BeginChild( LabelModPanel, AutoFillSize, true );
|
||||
if (!ret)
|
||||
return;
|
||||
|
||||
DrawHeaderLine();
|
||||
|
||||
// Next line with fixed distance.
|
||||
ImGuiCustom.VerticalDistance(HeaderLineDistance);
|
||||
|
||||
DrawEnabledMark();
|
||||
if (_base._plugin.Configuration.ShowAdvanced)
|
||||
{
|
||||
ImGui.SameLine();
|
||||
DrawEditableMark();
|
||||
}
|
||||
|
||||
// Next line, if editable.
|
||||
if (_editMode)
|
||||
DrawEditLine();
|
||||
|
||||
_details.Draw(_editMode);
|
||||
|
||||
ImGui.EndChild();
|
||||
}
|
||||
catch( Exception ex )
|
||||
{
|
||||
PluginLog.LogError( ex, "fuck" );
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
275
Penumbra/UI/TabInstalledSelector.cs
Normal file
275
Penumbra/UI/TabInstalledSelector.cs
Normal file
|
|
@ -0,0 +1,275 @@
|
|||
using System.Numerics;
|
||||
using System.Linq;
|
||||
using System.IO;
|
||||
using Newtonsoft.Json;
|
||||
using ImGuiNET;
|
||||
using Penumbra.Mods;
|
||||
using Penumbra.Models;
|
||||
using Dalamud.Interface;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class Selector
|
||||
{
|
||||
private const string LabelSelectorList = "##availableModList";
|
||||
private const string TooltipMoveDown = "Move the selected mod down in priority";
|
||||
private const string TooltipMoveUp = "Move the selected mod up in priority";
|
||||
private const string TooltipDelete = "Delete the selected mod";
|
||||
private const string TooltipAdd = "Add an empty mod";
|
||||
private const string DialogDeleteMod = "PenumbraDeleteMod";
|
||||
private const string ButtonYesDelete = "Yes, delete it";
|
||||
private const string ButtonNoDelete = "No, keep it";
|
||||
private const float SelectorPanelWidth = 240f;
|
||||
private const uint DisabledModColor = 0xFF666666;
|
||||
private const uint ConflictingModColor = 0xFFAAAAFF;
|
||||
|
||||
private static readonly Vector2 SelectorButtonSizes = new(60, 0);
|
||||
private static readonly string ArrowUpString = FontAwesomeIcon.ArrowUp.ToIconString();
|
||||
private static readonly string ArrowDownString = FontAwesomeIcon.ArrowDown.ToIconString();
|
||||
|
||||
private readonly SettingsInterface _base;
|
||||
private ModCollection Mods{ get{ return _base._plugin.ModManager.Mods; } }
|
||||
|
||||
private ModInfo _mod = null;
|
||||
private int _index = 0;
|
||||
private int? _deleteIndex = null;
|
||||
|
||||
public Selector(SettingsInterface ui)
|
||||
{
|
||||
_base = ui;
|
||||
}
|
||||
|
||||
private void DrawPriorityChangeButton(string iconString, bool up, int unavailableWhen)
|
||||
{
|
||||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
if( _index != unavailableWhen )
|
||||
{
|
||||
if( ImGui.Button( iconString, SelectorButtonSizes ) )
|
||||
{
|
||||
SetSelection(_index);
|
||||
_base._plugin.ModManager.ChangeModPriority( _mod, up );
|
||||
_index += up ? 1 : -1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.Alpha, 0.5f );
|
||||
ImGui.Button( iconString, SelectorButtonSizes );
|
||||
ImGui.PopStyleVar();
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
{
|
||||
ImGui.SetTooltip(
|
||||
_base._plugin.Configuration.InvertModListOrder ^ up ? TooltipMoveDown : TooltipMoveUp
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawModTrashButton()
|
||||
{
|
||||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
|
||||
if( ImGui.Button( FontAwesomeIcon.Trash.ToIconString(), SelectorButtonSizes ) )
|
||||
{
|
||||
_deleteIndex = _index;
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( TooltipDelete );
|
||||
}
|
||||
|
||||
private void DrawModAddButton()
|
||||
{
|
||||
ImGui.PushFont( UiBuilder.IconFont );
|
||||
|
||||
if( ImGui.Button( FontAwesomeIcon.Plus.ToIconString(), SelectorButtonSizes ) )
|
||||
{
|
||||
// Do nothing. YEAH. #TODO.
|
||||
}
|
||||
|
||||
ImGui.PopFont();
|
||||
|
||||
if( ImGui.IsItemHovered() )
|
||||
ImGui.SetTooltip( TooltipAdd );
|
||||
}
|
||||
|
||||
private void DrawModsSelectorButtons()
|
||||
{
|
||||
// Selector controls
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.WindowPadding, ZeroVector );
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.FrameRounding, 0 );
|
||||
|
||||
DrawPriorityChangeButton(ArrowUpString, false, 0);
|
||||
ImGui.SameLine();
|
||||
DrawPriorityChangeButton(ArrowDownString, true, Mods?.ModSettings.Count - 1 ?? 0);
|
||||
ImGui.SameLine();
|
||||
DrawModTrashButton();
|
||||
ImGui.SameLine();
|
||||
DrawModAddButton();
|
||||
|
||||
ImGui.PopStyleVar( 3 );
|
||||
}
|
||||
|
||||
void DrawDeleteModal()
|
||||
{
|
||||
if( _deleteIndex != null )
|
||||
ImGui.OpenPopup( DialogDeleteMod );
|
||||
|
||||
var ret = ImGui.BeginPopupModal( DialogDeleteMod );
|
||||
if( !ret )
|
||||
return;
|
||||
|
||||
if( _mod?.Mod == null )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
ImGui.Text( "Are you sure you want to delete the following mod:" );
|
||||
// todo: why the fuck does this become null??????
|
||||
ImGui.Text( _mod?.Mod?.Meta?.Name );
|
||||
|
||||
if( ImGui.Button( ButtonYesDelete ) )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_base._plugin.ModManager.DeleteMod( _mod.Mod );
|
||||
ClearSelection();
|
||||
_base.ReloadMods();
|
||||
}
|
||||
|
||||
ImGui.SameLine();
|
||||
|
||||
if( ImGui.Button( ButtonNoDelete ) )
|
||||
{
|
||||
ImGui.CloseCurrentPopup();
|
||||
_deleteIndex = null;
|
||||
}
|
||||
|
||||
ImGui.EndPopup();
|
||||
}
|
||||
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
if (Mods == null)
|
||||
return;
|
||||
|
||||
// Selector pane
|
||||
ImGui.BeginGroup();
|
||||
ImGui.PushStyleVar( ImGuiStyleVar.ItemSpacing, ZeroVector );
|
||||
|
||||
// Inlay selector list
|
||||
ImGui.BeginChild( LabelSelectorList, new Vector2(SelectorPanelWidth, -ImGui.GetFrameHeightWithSpacing() ), true );
|
||||
|
||||
for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ )
|
||||
{
|
||||
var settings = Mods.ModSettings[ modIndex ];
|
||||
|
||||
var changedColour = false;
|
||||
if( !settings.Enabled )
|
||||
{
|
||||
ImGui.PushStyleColor( ImGuiCol.Text, DisabledModColor );
|
||||
changedColour = true;
|
||||
}
|
||||
else if( settings.Mod.FileConflicts.Any() )
|
||||
{
|
||||
ImGui.PushStyleColor( ImGuiCol.Text, ConflictingModColor );
|
||||
changedColour = true;
|
||||
}
|
||||
|
||||
#if DEBUG
|
||||
var selected = ImGui.Selectable(
|
||||
$"id={modIndex} {settings.Mod.Meta.Name}",
|
||||
modIndex == _index
|
||||
);
|
||||
#else
|
||||
var selected = ImGui.Selectable( settings.Mod.Meta.Name, modIndex == _index );
|
||||
#endif
|
||||
|
||||
if( changedColour )
|
||||
ImGui.PopStyleColor();
|
||||
|
||||
if( selected )
|
||||
SetSelection(modIndex, settings);
|
||||
}
|
||||
|
||||
ImGui.EndChild();
|
||||
|
||||
DrawModsSelectorButtons();
|
||||
ImGui.EndGroup();
|
||||
|
||||
DrawDeleteModal();
|
||||
}
|
||||
|
||||
public ModInfo Mod() => _mod;
|
||||
|
||||
private void SetSelection(int idx, ModInfo info)
|
||||
{
|
||||
_mod = info;
|
||||
if (idx != _index)
|
||||
_base._menu._installedTab._modPanel._details.ResetState();
|
||||
_index = idx;
|
||||
_deleteIndex = null;
|
||||
}
|
||||
|
||||
public void SetSelection(int idx)
|
||||
{
|
||||
if (idx >= (Mods?.ModSettings?.Count ?? 0))
|
||||
idx = -1;
|
||||
if (idx < 0)
|
||||
SetSelection(0, null);
|
||||
else
|
||||
SetSelection(idx, Mods.ModSettings[idx]);
|
||||
}
|
||||
|
||||
public void ClearSelection() => SetSelection(-1);
|
||||
|
||||
public void SelectModByName( string name )
|
||||
{
|
||||
for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ )
|
||||
{
|
||||
var mod = Mods.ModSettings[ modIndex ];
|
||||
|
||||
if( mod.Mod.Meta.Name != name )
|
||||
continue;
|
||||
|
||||
SetSelection(modIndex, mod);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
private string GetCurrentModMetaFile()
|
||||
{
|
||||
if( _mod == null )
|
||||
return "";
|
||||
return Path.Combine( _mod.Mod.ModBasePath.FullName, "meta.json" );
|
||||
}
|
||||
|
||||
public void ReloadCurrentMod()
|
||||
{
|
||||
var metaPath = GetCurrentModMetaFile();
|
||||
if (metaPath.Length > 0 && File.Exists(metaPath))
|
||||
{
|
||||
_mod.Mod.Meta = ModMeta.LoadFromFile(metaPath) ?? _mod.Mod.Meta;
|
||||
_base._menu._installedTab._modPanel._details.ResetState();
|
||||
}
|
||||
}
|
||||
|
||||
public string SaveCurrentMod()
|
||||
{
|
||||
var metaPath = GetCurrentModMetaFile();
|
||||
if (metaPath.Length > 0)
|
||||
File.WriteAllText( metaPath, JsonConvert.SerializeObject( _mod.Mod.Meta, Formatting.Indented ) );
|
||||
_base._menu._installedTab._modPanel._details.ResetState();
|
||||
return metaPath;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
174
Penumbra/UI/TabSettings.cs
Normal file
174
Penumbra/UI/TabSettings.cs
Normal file
|
|
@ -0,0 +1,174 @@
|
|||
using System.Diagnostics;
|
||||
using ImGuiNET;
|
||||
|
||||
namespace Penumbra.UI
|
||||
{
|
||||
public partial class SettingsInterface
|
||||
{
|
||||
private class TabSettings
|
||||
{
|
||||
private const string LabelTab = "Settings";
|
||||
private const string LabelRootFolder = "Root Folder";
|
||||
private const string LabelRediscoverButton = "Rediscover Mods";
|
||||
private const string LabelOpenFolder = "Open Mods Folder";
|
||||
private const string LabelEnabled = "Enable Mods";
|
||||
private const string LabelInvertModOrder = "Invert mod load order (mods are loaded bottom up)";
|
||||
private const string LabelShowAdvanced = "Show Advanced Settings";
|
||||
private const string LabelLogLoadedFiles = "Log all loaded files";
|
||||
private const string LabelDisableNotifications = "Disable filesystem change notifications";
|
||||
private const string LabelEnableHttpApi = "Enable HTTP API";
|
||||
private const string LabelReloadResource = "Reload Player Resource";
|
||||
|
||||
private readonly SettingsInterface _base;
|
||||
private readonly Configuration _config;
|
||||
private bool _configChanged;
|
||||
|
||||
public TabSettings(SettingsInterface ui)
|
||||
{
|
||||
_base = ui;
|
||||
_config = _base._plugin.Configuration;
|
||||
_configChanged = false;
|
||||
}
|
||||
|
||||
private void DrawRootFolder()
|
||||
{
|
||||
var basePath = _config.CurrentCollection;
|
||||
if( ImGui.InputText( LabelRootFolder, ref basePath, 255 ) && _config.CurrentCollection != basePath )
|
||||
{
|
||||
_config.CurrentCollection = basePath;
|
||||
_configChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawRediscoverButton()
|
||||
{
|
||||
if( ImGui.Button( LabelRediscoverButton ) )
|
||||
{
|
||||
_base.ReloadMods();
|
||||
_base._menu._installedTab._selector.ClearSelection();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawOpenModsButton()
|
||||
{
|
||||
if( ImGui.Button( LabelOpenFolder ) )
|
||||
{
|
||||
Process.Start( _config.CurrentCollection );
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEnabledBox()
|
||||
{
|
||||
var enabled = _config.IsEnabled;
|
||||
if( ImGui.Checkbox( LabelEnabled, ref enabled ) )
|
||||
{
|
||||
_config.IsEnabled = enabled;
|
||||
_base.ReloadMods();
|
||||
_configChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawInvertModOrderBox()
|
||||
{
|
||||
var invertOrder = _config.InvertModListOrder;
|
||||
if( ImGui.Checkbox( LabelInvertModOrder, ref invertOrder ) )
|
||||
{
|
||||
_config.InvertModListOrder = invertOrder;
|
||||
_base.ReloadMods();
|
||||
_configChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawShowAdvancedBox()
|
||||
{
|
||||
var showAdvanced = _config.ShowAdvanced;
|
||||
if( ImGui.Checkbox( LabelShowAdvanced, ref showAdvanced ) )
|
||||
{
|
||||
_config.ShowAdvanced = showAdvanced;
|
||||
_configChanged = true;
|
||||
_base._menu._effectiveTab.RebuildFileList(showAdvanced);
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawLogLoadedFilesBox()
|
||||
{
|
||||
if( _base._plugin.ResourceLoader != null )
|
||||
ImGui.Checkbox( LabelLogLoadedFiles, ref _base._plugin.ResourceLoader.LogAllFiles );
|
||||
}
|
||||
|
||||
private void DrawDisableNotificationsBox()
|
||||
{
|
||||
var fswatch = _config.DisableFileSystemNotifications;
|
||||
if( ImGui.Checkbox( LabelDisableNotifications, ref fswatch ) )
|
||||
{
|
||||
_config.DisableFileSystemNotifications = fswatch;
|
||||
_configChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawEnableHttpApiBox()
|
||||
{
|
||||
var http = _config.EnableHttpApi;
|
||||
if( ImGui.Checkbox( LabelEnableHttpApi, ref http ) )
|
||||
{
|
||||
if( http )
|
||||
_base._plugin.CreateWebServer();
|
||||
else
|
||||
_base._plugin.ShutdownWebServer();
|
||||
|
||||
_config.EnableHttpApi = http;
|
||||
_configChanged = true;
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawReloadResourceButton()
|
||||
{
|
||||
if( ImGui.Button( LabelReloadResource ) )
|
||||
{
|
||||
_base._plugin.GameUtils.ReloadPlayerResources();
|
||||
}
|
||||
}
|
||||
|
||||
private void DrawAdvancedSettings()
|
||||
{
|
||||
DrawLogLoadedFilesBox();
|
||||
DrawDisableNotificationsBox();
|
||||
DrawEnableHttpApiBox();
|
||||
DrawReloadResourceButton();
|
||||
}
|
||||
|
||||
public void Draw()
|
||||
{
|
||||
var ret = ImGui.BeginTabItem( LabelTab );
|
||||
if( !ret )
|
||||
return;
|
||||
|
||||
DrawRootFolder();
|
||||
|
||||
DrawRediscoverButton();
|
||||
ImGui.SameLine();
|
||||
DrawOpenModsButton();
|
||||
|
||||
ImGuiCustom.VerticalDistance(DefaultVerticalSpace);
|
||||
DrawEnabledBox();
|
||||
|
||||
ImGuiCustom.VerticalDistance(DefaultVerticalSpace);
|
||||
DrawInvertModOrderBox();
|
||||
|
||||
ImGuiCustom.VerticalDistance(DefaultVerticalSpace);
|
||||
DrawShowAdvancedBox();
|
||||
|
||||
if( _config.ShowAdvanced )
|
||||
DrawAdvancedSettings();
|
||||
|
||||
if( _configChanged )
|
||||
{
|
||||
_config.Save();
|
||||
_configChanged = false;
|
||||
}
|
||||
|
||||
ImGui.EndTabItem();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue