Add support for plugin profiles
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (NuGet) (push) Successful in 3m59s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m5s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m2s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m20s
Build / Build Launcher (push) Successful in 5m11s
All checks were successful
Build / Compute Version (push) Successful in 6s
Build / Build Nuget package (NuGet) (push) Successful in 3m59s
Build / Build Nuget package (CringeBootstrap.Abstractions) (push) Successful in 4m5s
Build / Build Nuget package (SharedCringe) (push) Successful in 4m2s
Build / Build Nuget package (CringePlugins) (push) Successful in 4m20s
Build / Build Launcher (push) Successful in 5m11s
Some minor cleanup
This commit is contained in:
@@ -1,96 +0,0 @@
|
|||||||
#if false
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Reflection;
|
|
||||||
using System.Reflection.Emit;
|
|
||||||
using System.Runtime.Loader;
|
|
||||||
using CringeBootstrap.Abstractions;
|
|
||||||
using CringeLauncher.Loader;
|
|
||||||
using HarmonyLib;
|
|
||||||
using Sandbox.Game.World;
|
|
||||||
using VRage.Collections;
|
|
||||||
using VRage.Scripting;
|
|
||||||
|
|
||||||
namespace CringeLauncher.Patches;
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
public static class ModAssemblyLoadContextPatches //todo: use ModScriptCompilerPatch
|
|
||||||
{
|
|
||||||
private static ModAssemblyLoadContext? _currentSessionContext;
|
|
||||||
private static readonly MyConcurrentHashSet<string> AssemblyNames = [];
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(MyScriptCompiler), nameof(MyScriptCompiler.Compile), MethodType.Async)]
|
|
||||||
[HarmonyTranspiler]
|
|
||||||
private static IEnumerable<CodeInstruction> CompilerTranspiler(IEnumerable<CodeInstruction> instructions, MethodBase original)
|
|
||||||
{
|
|
||||||
var matcher = new CodeMatcher(instructions);
|
|
||||||
|
|
||||||
var load1Method = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.Load), [typeof(byte[]), typeof(byte[])]);
|
|
||||||
var load2Method = AccessTools.DeclaredMethod(typeof(Assembly), nameof(Assembly.Load), [typeof(byte[])]);
|
|
||||||
|
|
||||||
return matcher.SearchForward(i => i.Calls(load1Method))
|
|
||||||
.InsertAndAdvance(new(OpCodes.Ldarg_0), CodeInstruction.LoadField(original.DeclaringType, "target"))
|
|
||||||
.SetInstruction(CodeInstruction.CallClosure((byte[] assembly, byte[] symbols, MyApiTarget target) =>
|
|
||||||
{
|
|
||||||
//if (target is not MyApiTarget.Mod) return Assembly.Load(assembly, symbols);
|
|
||||||
ArgumentNullException.ThrowIfNull(_currentSessionContext, "No session context");
|
|
||||||
return _currentSessionContext.LoadFromStream(new MemoryStream(assembly), new MemoryStream(symbols));
|
|
||||||
}))
|
|
||||||
.Start()
|
|
||||||
.SearchForward(i => i.Calls(load2Method))
|
|
||||||
.InsertAndAdvance(new(OpCodes.Ldarg_0), CodeInstruction.LoadField(original.DeclaringType, "target"))
|
|
||||||
.SetInstruction(CodeInstruction.CallClosure((byte[] assembly, MyApiTarget target) =>
|
|
||||||
{
|
|
||||||
//if (target is not MyApiTarget.Mod) return Assembly.Load(assembly);
|
|
||||||
ArgumentNullException.ThrowIfNull(_currentSessionContext, "No session context");
|
|
||||||
return _currentSessionContext.LoadFromStream(new MemoryStream(assembly));
|
|
||||||
}))
|
|
||||||
.Instructions();
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(MyScriptManager), "Compile")]
|
|
||||||
[HarmonyPrefix]
|
|
||||||
private static bool CompilePrefix(string assemblyName)
|
|
||||||
{
|
|
||||||
if (!AssemblyNames.Add(assemblyName))
|
|
||||||
{
|
|
||||||
Debug.WriteLine($"Duplicate assembly: {assemblyName}");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch(typeof(MySession), nameof(MySession.Unload))]
|
|
||||||
[HarmonyPostfix]
|
|
||||||
private static void UnloadPostfix()
|
|
||||||
{
|
|
||||||
AssemblyNames.Clear();
|
|
||||||
if (_currentSessionContext is null) return;
|
|
||||||
|
|
||||||
_currentSessionContext.Unload();
|
|
||||||
_currentSessionContext = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPatch]
|
|
||||||
private static class LoadPrefixes
|
|
||||||
{
|
|
||||||
[HarmonyTargetMethods]
|
|
||||||
private static IEnumerable<MethodInfo> TargetMethods()
|
|
||||||
{
|
|
||||||
yield return AccessTools.Method(typeof(MySession), nameof(MySession.Load));
|
|
||||||
yield return AccessTools.Method(typeof(MySession), "LoadMultiplayer");
|
|
||||||
}
|
|
||||||
|
|
||||||
[HarmonyPrefix]
|
|
||||||
private static void Prefix()
|
|
||||||
{
|
|
||||||
if (_currentSessionContext is not null)
|
|
||||||
throw new InvalidOperationException("Previous session context was not disposed");
|
|
||||||
|
|
||||||
if (AssemblyLoadContext.GetLoadContext(typeof(MySession).Assembly) is not ICoreLoadContext coreContext)
|
|
||||||
throw new NotSupportedException("Mod loading is not supported in this context");
|
|
||||||
|
|
||||||
_currentSessionContext = new ModAssemblyLoadContext(coreContext);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endif
|
|
@@ -10,7 +10,7 @@ internal sealed class MissingUsingRewriter : ProtoTagRewriter //use existing rew
|
|||||||
private readonly SemanticModel _semanticModel;
|
private readonly SemanticModel _semanticModel;
|
||||||
private MissingUsingRewriter(CSharpCompilation compilation, SyntaxTree tree) : base(compilation, tree) => _semanticModel = compilation.GetSemanticModel(tree);
|
private MissingUsingRewriter(CSharpCompilation compilation, SyntaxTree tree) : base(compilation, tree) => _semanticModel = compilation.GetSemanticModel(tree);
|
||||||
|
|
||||||
public static SyntaxTree Rewrite(CSharpCompilation compilation, SyntaxTree tree)
|
public static new SyntaxTree Rewrite(CSharpCompilation compilation, SyntaxTree tree)
|
||||||
{
|
{
|
||||||
SyntaxNode syntaxNode = new MissingUsingRewriter(compilation, tree).Visit(tree.GetRoot());
|
SyntaxNode syntaxNode = new MissingUsingRewriter(compilation, tree).Visit(tree.GetRoot());
|
||||||
return tree.WithRootAndOptions(syntaxNode, tree.Options);
|
return tree.WithRootAndOptions(syntaxNode, tree.Options);
|
||||||
|
@@ -43,7 +43,7 @@ public class PluginLoaderConfig
|
|||||||
pluginsBuilder.Add(package);
|
pluginsBuilder.Add(package);
|
||||||
}
|
}
|
||||||
|
|
||||||
var profiles = new Dictionary<string, ImmutableArray<PackageReference>>();
|
var profiles = ImmutableArray.CreateBuilder<Profile>();
|
||||||
foreach (var profile in Profiles)
|
foreach (var profile in Profiles)
|
||||||
{
|
{
|
||||||
var builder = ImmutableArray.CreateBuilder<PackageReference>();
|
var builder = ImmutableArray.CreateBuilder<PackageReference>();
|
||||||
@@ -62,13 +62,13 @@ public class PluginLoaderConfig
|
|||||||
builder.Add(package);
|
builder.Add(package);
|
||||||
}
|
}
|
||||||
|
|
||||||
profiles[profile.Name] = builder.ToImmutable();
|
profiles.Add(new(profile.Name, builder.ToImmutable()));
|
||||||
}
|
}
|
||||||
|
|
||||||
return old with
|
return old with
|
||||||
{
|
{
|
||||||
Packages = pluginsBuilder.ToImmutable(),
|
Packages = pluginsBuilder.ToImmutable(),
|
||||||
Profiles = profiles,
|
Profiles = profiles.ToImmutable(),
|
||||||
Sources = sources.ToImmutable()
|
Sources = sources.ToImmutable()
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
@@ -64,7 +64,17 @@ public sealed class ConfigHandler
|
|||||||
return reference;
|
return reference;
|
||||||
}
|
}
|
||||||
|
|
||||||
var instance = jsonNode.Deserialize<T>(_serializerOptions)!;
|
T instance;
|
||||||
|
try
|
||||||
|
{
|
||||||
|
instance = jsonNode.Deserialize<T>(_serializerOptions)!;
|
||||||
|
}
|
||||||
|
catch (JsonException e)
|
||||||
|
{
|
||||||
|
Log.Warn(e, "Failed to load config {Name}", name);
|
||||||
|
|
||||||
|
instance = defaultInstance ?? Activator.CreateInstance<T>();
|
||||||
|
}
|
||||||
ConfigReloaded?.Invoke(this, new ConfigValue<T>(name, instance));
|
ConfigReloaded?.Invoke(this, new ConfigValue<T>(name, instance));
|
||||||
|
|
||||||
return reference;
|
return reference;
|
||||||
|
@@ -4,7 +4,7 @@ using NuGet;
|
|||||||
|
|
||||||
namespace CringePlugins.Config;
|
namespace CringePlugins.Config;
|
||||||
|
|
||||||
public record PackagesConfig(ImmutableArray<PackageSource> Sources, ImmutableArray<PackageReference> Packages, Dictionary<string, ImmutableArray<PackageReference>> Profiles)
|
public record PackagesConfig(ImmutableArray<PackageSource> Sources, ImmutableArray<PackageReference> Packages, ImmutableArray<Profile> Profiles)
|
||||||
{
|
{
|
||||||
public static PackagesConfig Default { get; } = new([
|
public static PackagesConfig Default { get; } = new([
|
||||||
new("zznty", @"^SpaceEngineersDedicated\.ReferenceAssemblies$|^ImGui\.NET\.DirectX$|^NuGet$|^Cringe.+$|^SharedCringe$|^Plugin.+$", "https://ng.zznty.ru/v3/index.json"),
|
new("zznty", @"^SpaceEngineersDedicated\.ReferenceAssemblies$|^ImGui\.NET\.DirectX$|^NuGet$|^Cringe.+$|^SharedCringe$|^Plugin.+$", "https://ng.zznty.ru/v3/index.json"),
|
||||||
@@ -13,5 +13,6 @@ public record PackagesConfig(ImmutableArray<PackageSource> Sources, ImmutableArr
|
|||||||
[
|
[
|
||||||
new PackageReference("Plugin.ClientModLoader", new(new(0,0,0)))
|
new PackageReference("Plugin.ClientModLoader", new(new(0,0,0)))
|
||||||
],
|
],
|
||||||
[]); //todo: default profile with recommended plugins?
|
[]);
|
||||||
}
|
}
|
||||||
|
public record Profile(string Id, ImmutableArray<PackageReference> Plugins);
|
@@ -1,8 +1,4 @@
|
|||||||
using System.Collections.Immutable;
|
using CringePlugins.Abstractions;
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Text.Json;
|
|
||||||
using System.Xml.Serialization;
|
|
||||||
using CringePlugins.Abstractions;
|
|
||||||
using CringePlugins.Compatability;
|
using CringePlugins.Compatability;
|
||||||
using CringePlugins.Config;
|
using CringePlugins.Config;
|
||||||
using CringePlugins.Loader;
|
using CringePlugins.Loader;
|
||||||
@@ -18,6 +14,11 @@ using NuGet.Versioning;
|
|||||||
using Sandbox.Game.Gui;
|
using Sandbox.Game.Gui;
|
||||||
using Sandbox.Graphics.GUI;
|
using Sandbox.Graphics.GUI;
|
||||||
using SpaceEngineers.Game.GUI;
|
using SpaceEngineers.Game.GUI;
|
||||||
|
using System.Collections.Immutable;
|
||||||
|
using System.Diagnostics;
|
||||||
|
using System.Numerics;
|
||||||
|
using System.Text.Json;
|
||||||
|
using System.Xml.Serialization;
|
||||||
using static ImGuiNET.ImGui;
|
using static ImGuiNET.ImGui;
|
||||||
|
|
||||||
namespace CringePlugins.Ui;
|
namespace CringePlugins.Ui;
|
||||||
@@ -32,6 +33,12 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
private string _searchQuery = "";
|
private string _searchQuery = "";
|
||||||
private Task? _searchTask;
|
private Task? _searchTask;
|
||||||
|
|
||||||
|
private string _profileSearch = "";
|
||||||
|
private string _newProfileName = "";
|
||||||
|
private int _selectedProfile = -1;
|
||||||
|
private ImmutableArray<Profile> _profiles;
|
||||||
|
|
||||||
|
|
||||||
private bool _changed;
|
private bool _changed;
|
||||||
private bool _open = true;
|
private bool _open = true;
|
||||||
private readonly ConfigReference<PackagesConfig> _packagesConfig;
|
private readonly ConfigReference<PackagesConfig> _packagesConfig;
|
||||||
@@ -53,6 +60,7 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
_plugins = plugins;
|
_plugins = plugins;
|
||||||
_packages = packagesConfig.Value.Packages.ToImmutableDictionary(b => b.Id, b => b.Range,
|
_packages = packagesConfig.Value.Packages.ToImmutableDictionary(b => b.Id, b => b.Range,
|
||||||
StringComparer.OrdinalIgnoreCase);
|
StringComparer.OrdinalIgnoreCase);
|
||||||
|
_profiles = packagesConfig.Value.Profiles;
|
||||||
|
|
||||||
MyScreenManager.ScreenAdded += ScreenChanged;
|
MyScreenManager.ScreenAdded += ScreenChanged;
|
||||||
MyScreenManager.ScreenRemoved += ScreenChanged;
|
MyScreenManager.ScreenRemoved += ScreenChanged;
|
||||||
@@ -92,9 +100,9 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
{
|
{
|
||||||
if (BeginTable("InstalledTable", 3, ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.Sortable))
|
if (BeginTable("InstalledTable", 3, ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.Sortable))
|
||||||
{
|
{
|
||||||
TableSetupColumn("Id", ImGuiTableColumnFlags.None, .5f, (uint)Columns.Id);
|
TableSetupColumn("Id", ImGuiTableColumnFlags.WidthStretch, .5f, (uint)Columns.Id);
|
||||||
TableSetupColumn("Version", ImGuiTableColumnFlags.None, .25f, (uint)Columns.Version);
|
TableSetupColumn("Version", ImGuiTableColumnFlags.WidthStretch, .25f, (uint)Columns.Version);
|
||||||
TableSetupColumn("Source", ImGuiTableColumnFlags.None, .25f, (uint)Columns.Source);
|
TableSetupColumn("Source", ImGuiTableColumnFlags.WidthStretch, .25f, (uint)Columns.Source);
|
||||||
TableHeadersRow();
|
TableHeadersRow();
|
||||||
|
|
||||||
var sortSpecs = TableGetSortSpecs();
|
var sortSpecs = TableGetSortSpecs();
|
||||||
@@ -143,6 +151,12 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
EndTabItem();
|
EndTabItem();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (BeginTabItem("Profiles"))
|
||||||
|
{
|
||||||
|
ProfilesTab();
|
||||||
|
EndTabItem();
|
||||||
|
}
|
||||||
|
|
||||||
if (BeginTabItem("Sources Configuration"))
|
if (BeginTabItem("Sources Configuration"))
|
||||||
{
|
{
|
||||||
BeginChild("Sources List", new(400, 0), ImGuiChildFlags.Border | ImGuiChildFlags.ResizeX);
|
BeginChild("Sources List", new(400, 0), ImGuiChildFlags.Border | ImGuiChildFlags.ResizeX);
|
||||||
@@ -150,8 +164,8 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
if (BeginTable("Sources Table", 2,
|
if (BeginTable("Sources Table", 2,
|
||||||
ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.SizingStretchProp))
|
ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.SizingStretchProp))
|
||||||
{
|
{
|
||||||
TableSetupColumn("Name", ImGuiTableColumnFlags.None, .2f);
|
TableSetupColumn("Name", ImGuiTableColumnFlags.WidthStretch, .2f);
|
||||||
TableSetupColumn("Url", ImGuiTableColumnFlags.None, .8f);
|
TableSetupColumn("Url", ImGuiTableColumnFlags.WidthStretch, .8f);
|
||||||
TableHeadersRow();
|
TableHeadersRow();
|
||||||
|
|
||||||
for (var index = 0; index < _packagesConfig.Value.Sources.Length; index++)
|
for (var index = 0; index < _packagesConfig.Value.Sources.Length; index++)
|
||||||
@@ -321,6 +335,173 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
End();
|
End();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private unsafe void ProfilesTab()
|
||||||
|
{
|
||||||
|
InputText("##searchbox", ref _profileSearch, 256);
|
||||||
|
|
||||||
|
SameLine();
|
||||||
|
|
||||||
|
if (Button("Create New Profile"))
|
||||||
|
OpenPopup("New Profile");
|
||||||
|
|
||||||
|
|
||||||
|
if (IsItemHovered(ImGuiHoveredFlags.ForTooltip))
|
||||||
|
{
|
||||||
|
SetTooltip("Create a new profile from enabled plugins");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (BeginPopupModal("New Profile", ImGuiWindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
InputText("Name", ref _newProfileName, 50);
|
||||||
|
Separator();
|
||||||
|
|
||||||
|
if (Button("Ok##newProfileOk", new Vector2(120, 0)))
|
||||||
|
{
|
||||||
|
var len = _profiles.Length;
|
||||||
|
_profiles = _profiles.Add(new(_newProfileName, [.. _packages.Select(x => new PackageReference(x.Key, x.Value))]));
|
||||||
|
_selectedProfile = len;
|
||||||
|
|
||||||
|
_packagesConfig.Value = _packagesConfig.Value with
|
||||||
|
{
|
||||||
|
Profiles = _profiles
|
||||||
|
};
|
||||||
|
|
||||||
|
CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
SetItemDefaultFocus();
|
||||||
|
SameLine();
|
||||||
|
if (Button("Cancel##newProfileCancel", new Vector2(120, 0)))
|
||||||
|
{
|
||||||
|
CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
EndPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
Spacing();
|
||||||
|
|
||||||
|
if (_profiles.IsEmpty)
|
||||||
|
{
|
||||||
|
TextDisabled("No Profiles");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
BeginChild("Profile List", new(400, 0), ImGuiChildFlags.Border | ImGuiChildFlags.ResizeX);
|
||||||
|
|
||||||
|
if (BeginTable("ProfilesTable", 2,
|
||||||
|
ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.SizingStretchProp))
|
||||||
|
{
|
||||||
|
TableSetupColumn("Id##ProfilesTable", ImGuiTableColumnFlags.WidthStretch, .5f, (uint)Columns.Id);
|
||||||
|
TableSetupColumn("Plugins", ImGuiTableColumnFlags.WidthStretch, .25f, (uint)Columns.Count);
|
||||||
|
TableHeadersRow();
|
||||||
|
|
||||||
|
for (var i = 0; i < _profiles.Length; i++)
|
||||||
|
{
|
||||||
|
var(id, plugins) = _profiles[i];
|
||||||
|
|
||||||
|
if (!id.Contains(_profileSearch, StringComparison.OrdinalIgnoreCase))
|
||||||
|
continue;
|
||||||
|
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
TableNextColumn();
|
||||||
|
|
||||||
|
var selected = _selectedProfile == i;
|
||||||
|
|
||||||
|
if (Selectable($"{id}##profiles{i}", ref selected, ImGuiSelectableFlags.SpanAllColumns))
|
||||||
|
{
|
||||||
|
_selectedProfile = selected ? i : -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
TableNextColumn();
|
||||||
|
Text(plugins.Length.ToString());
|
||||||
|
}
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
|
||||||
|
EndChild();
|
||||||
|
|
||||||
|
SameLine();
|
||||||
|
|
||||||
|
BeginGroup();
|
||||||
|
|
||||||
|
BeginChild("Profile View", new(0, -GetFrameHeightWithSpacing())); // Leave room for 1 line below us
|
||||||
|
|
||||||
|
if (_selectedProfile >= 0)
|
||||||
|
{
|
||||||
|
var (id, plugins) = _profiles[_selectedProfile];
|
||||||
|
|
||||||
|
Text(id);
|
||||||
|
Separator();
|
||||||
|
|
||||||
|
if (BeginTable("ProfilePluginsTable", 2, ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.SizingStretchProp))
|
||||||
|
{
|
||||||
|
TableSetupColumn("Id##pluginProfilesId", ImGuiTableColumnFlags.WidthStretch, .5f, (uint)Columns.Id);
|
||||||
|
TableSetupColumn("Version##pluginProfilesVersion", ImGuiTableColumnFlags.WidthStretch, .25f, (uint)Columns.Version);
|
||||||
|
|
||||||
|
foreach (var plugin in plugins)
|
||||||
|
{
|
||||||
|
TableNextRow();
|
||||||
|
|
||||||
|
TableNextColumn();
|
||||||
|
|
||||||
|
Text(plugin.Id);
|
||||||
|
|
||||||
|
TableNextColumn();
|
||||||
|
Text(plugin.Range.ToShortString());
|
||||||
|
}
|
||||||
|
|
||||||
|
EndTable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
EndChild();
|
||||||
|
|
||||||
|
if (_selectedProfile >= 0)
|
||||||
|
{
|
||||||
|
if (Button("Activate"))
|
||||||
|
{
|
||||||
|
_packages = _profiles[_selectedProfile].Plugins.ToImmutableDictionary(b => b.Id, b => b.Range);
|
||||||
|
|
||||||
|
Save();
|
||||||
|
}
|
||||||
|
|
||||||
|
SameLine();
|
||||||
|
if (Button("Delete"))
|
||||||
|
OpenPopup("Delete?##ProfileDeletePopup");
|
||||||
|
|
||||||
|
if (BeginPopupModal("Delete?##ProfileDeletePopup", ImGuiWindowFlags.AlwaysAutoResize))
|
||||||
|
{
|
||||||
|
Text("Are you sure you want to delete this profile?");
|
||||||
|
Separator();
|
||||||
|
|
||||||
|
if (Button("Yes", new Vector2(120, 0)))
|
||||||
|
{
|
||||||
|
_profiles = _profiles.RemoveAt(_selectedProfile);
|
||||||
|
|
||||||
|
_packagesConfig.Value = _packagesConfig.Value with
|
||||||
|
{
|
||||||
|
Profiles = _profiles
|
||||||
|
};
|
||||||
|
|
||||||
|
_selectedProfile = -1;
|
||||||
|
|
||||||
|
CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
SetItemDefaultFocus();
|
||||||
|
SameLine();
|
||||||
|
if (Button("No", new Vector2(120, 0)))
|
||||||
|
{
|
||||||
|
CloseCurrentPopup();
|
||||||
|
}
|
||||||
|
|
||||||
|
EndPopup();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
EndGroup();
|
||||||
|
}
|
||||||
|
|
||||||
// TODO sources editor
|
// TODO sources editor
|
||||||
// TODO combobox with active sources (to limit search results to specific list of sources)
|
// TODO combobox with active sources (to limit search results to specific list of sources)
|
||||||
private unsafe void AvailablePluginsTab()
|
private unsafe void AvailablePluginsTab()
|
||||||
@@ -357,6 +538,7 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
: (_selectedSources ?? _packagesConfig.Value.Sources.ToImmutableHashSet()).Remove(source);
|
: (_selectedSources ?? _packagesConfig.Value.Sources.ToImmutableHashSet()).Remove(source);
|
||||||
|
|
||||||
_searchTask = RefreshAsync();
|
_searchTask = RefreshAsync();
|
||||||
|
EndCombo();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -398,9 +580,9 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
if (BeginTable("AvailableTable", 3,
|
if (BeginTable("AvailableTable", 3,
|
||||||
ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Sortable))
|
ImGuiTableFlags.ScrollY | ImGuiTableFlags.Resizable | ImGuiTableFlags.SizingStretchProp | ImGuiTableFlags.Sortable))
|
||||||
{
|
{
|
||||||
TableSetupColumn("Id", ImGuiTableColumnFlags.None, .5f, (uint)Columns.Id);
|
TableSetupColumn("Id", ImGuiTableColumnFlags.WidthStretch, .5f, (uint)Columns.Id);
|
||||||
TableSetupColumn("Version", ImGuiTableColumnFlags.None, .25f, (uint)Columns.Version);
|
TableSetupColumn("Version", ImGuiTableColumnFlags.WidthStretch, .25f, (uint)Columns.Version);
|
||||||
TableSetupColumn("Installed", ImGuiTableColumnFlags.None, .25f, (uint)Columns.Installed);
|
TableSetupColumn("Installed", ImGuiTableColumnFlags.WidthStretch, .25f, (uint)Columns.Installed);
|
||||||
TableHeadersRow();
|
TableHeadersRow();
|
||||||
|
|
||||||
var sortSpecs = TableGetSortSpecs();
|
var sortSpecs = TableGetSortSpecs();
|
||||||
@@ -569,9 +751,9 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
_searchResults = builder.ToImmutable();
|
_searchResults = builder.ToImmutable();
|
||||||
}
|
}
|
||||||
|
|
||||||
private void Save(bool keepPackages = true)
|
private void Save(bool keepChanges = true)
|
||||||
{
|
{
|
||||||
_packagesConfig.Value = keepPackages ? _packagesConfig.Value with
|
_packagesConfig.Value = keepChanges ? _packagesConfig.Value with
|
||||||
{
|
{
|
||||||
Packages = [.. _packages.Select(b => new PackageReference(b.Key, b.Value))]
|
Packages = [.. _packages.Select(b => new PackageReference(b.Key, b.Value))]
|
||||||
} : _packagesConfig;
|
} : _packagesConfig;
|
||||||
@@ -649,6 +831,7 @@ internal class PluginListComponent : IRenderComponent
|
|||||||
Id,
|
Id,
|
||||||
Version,
|
Version,
|
||||||
Source,
|
Source,
|
||||||
Installed
|
Installed,
|
||||||
|
Count
|
||||||
}
|
}
|
||||||
}
|
}
|
Reference in New Issue
Block a user