Penumbra/Penumbra/UI/MenuTabs/TabInstalled/TabInstalledSelector.cs
2021-04-19 00:52:28 +02:00

339 lines
No EOL
12 KiB
C#

using System.IO;
using System.Linq;
using System.Numerics;
using Dalamud.Interface;
using ImGuiNET;
using Newtonsoft.Json;
using Penumbra.Models;
using Penumbra.Mods;
namespace Penumbra.UI
{
public partial class SettingsInterface
{
private class Selector
{
private const string LabelSelectorList = "##availableModList";
private const string LabelModFilter = "##ModFilter";
private const string TooltipModFilter = "Filter mods for those containing the given substring.";
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 => Service< ModManager >.Get().Mods;
private ModInfo? _mod;
private int _index;
private int? _deleteIndex;
private string _modFilter = "";
private string[]? _modNamesLower;
public Selector( SettingsInterface ui )
{
_base = ui;
ResetModNamesLower();
}
public void ResetModNamesLower()
{
_modNamesLower = Mods?.ModSettings?.Where(I => I.Mod != null)
.Select( I => I.Mod!.Meta.Name.ToLowerInvariant() ).ToArray() ?? new string[]{};
}
private void DrawPriorityChangeButton( string iconString, bool up, int unavailableWhen )
{
ImGui.PushFont( UiBuilder.IconFont );
if( _index != unavailableWhen )
{
if( ImGui.Button( iconString, SelectorButtonSizes ) )
{
SetSelection( _index );
Service< ModManager >.Get().ChangeModPriority( _mod!, up );
_modNamesLower!.Swap( _index, _index + ( up ? 1 : -1 ) );
_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 static 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 DrawModsSelectorFilter()
{
ImGui.SetNextItemWidth( SelectorButtonSizes.X * 4 );
var tmp = _modFilter;
if( ImGui.InputTextWithHint( LabelModFilter, "Filter Mods...", ref tmp, 256 ) )
{
_modFilter = tmp.ToLowerInvariant();
}
if( ImGui.IsItemHovered() )
{
ImGui.SetTooltip( TooltipModFilter );
}
}
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 );
}
private void DrawDeleteModal()
{
if( _deleteIndex == null )
{
return;
}
ImGui.OpenPopup( DialogDeleteMod );
var ret = ImGui.BeginPopupModal( DialogDeleteMod );
if( !ret )
{
return;
}
if( _mod?.Mod == null )
{
ImGui.CloseCurrentPopup();
ImGui.EndPopup();
return;
}
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();
Service< ModManager >.Get().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 );
DrawModsSelectorFilter();
// Inlay selector list
ImGui.BeginChild( LabelSelectorList, new Vector2( SelectorPanelWidth, -ImGui.GetFrameHeightWithSpacing() ), true );
if( Mods.ModSettings != null )
{
for( var modIndex = 0; modIndex < Mods.ModSettings.Count; modIndex++ )
{
var settings = Mods.ModSettings[ modIndex ];
var modName = settings.Mod.Meta.Name;
if( _modFilter.Length > 0 && !_modNamesLower![ modIndex ].Contains( _modFilter ) )
{
continue;
}
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} {modName}",
modIndex == _index
);
#else
var selected = ImGui.Selectable( modName, 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;
}
private 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 )
{
var idx = Mods?.ModSettings?.FindIndex( mod => mod.Mod.Meta.Name == name ) ?? -1;
SetSelection( idx );
}
private string GetCurrentModMetaFile()
=> _mod == null ? "" : 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();
}
_mod!.Mod.RefreshModFiles();
Service< ModManager >.Get().CalculateEffectiveFileList();
_base._menu.EffectiveTab.RebuildFileList( _base._plugin!.Configuration!.ShowAdvanced );
ResetModNamesLower();
}
public string SaveCurrentMod()
{
if( _mod == null )
return "";
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;
}
}
}
}