mirror of
https://github.com/Stone-Red-Code/DesktopMagic.git
synced 2026-09-04 08:56:15 +02:00
Add create new plugin button to plugin manager
This commit is contained in:
@@ -0,0 +1,93 @@
|
|||||||
|
using System;
|
||||||
|
using System.IO;
|
||||||
|
using System.Runtime.InteropServices;
|
||||||
|
using System.Text;
|
||||||
|
|
||||||
|
namespace DesktopMagic.Helpers;
|
||||||
|
|
||||||
|
internal static class FileUtilities
|
||||||
|
{
|
||||||
|
public static bool ExistsOnPath(string fileName)
|
||||||
|
{
|
||||||
|
return GetFullPath(fileName) is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? GetFullPath(string fileName)
|
||||||
|
{
|
||||||
|
if (File.Exists(fileName))
|
||||||
|
{
|
||||||
|
return Path.GetFullPath(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
string? values = Environment.GetEnvironmentVariable("PATH");
|
||||||
|
|
||||||
|
if (string.IsNullOrEmpty(values))
|
||||||
|
{
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
foreach (string path in values.Split(Path.PathSeparator))
|
||||||
|
{
|
||||||
|
string fullPath = Path.Combine(path, fileName);
|
||||||
|
if (File.Exists(fullPath))
|
||||||
|
{
|
||||||
|
return fullPath;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static bool HasAssociatedProgram(string extension)
|
||||||
|
{
|
||||||
|
return GetAssociatedProgram(extension) is not null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public static string? GetAssociatedProgram(string extension)
|
||||||
|
{
|
||||||
|
uint pcchOut = 0;
|
||||||
|
_ = AssocQueryString(AssocF.Verify, AssocStr.Executable, extension, null, null, ref pcchOut);
|
||||||
|
|
||||||
|
StringBuilder pszOut = new StringBuilder((int)pcchOut);
|
||||||
|
_ = AssocQueryString(AssocF.Verify, AssocStr.Executable, extension, null, pszOut, ref pcchOut);
|
||||||
|
|
||||||
|
if (File.Exists(pszOut.ToString()))
|
||||||
|
{
|
||||||
|
return pszOut.ToString();
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
|
[DllImport("Shlwapi.dll", SetLastError = true, CharSet = CharSet.Unicode)]
|
||||||
|
private static extern uint AssocQueryString(AssocF flags, AssocStr str, string pszAssoc, string? pszExtra, [Out] StringBuilder? pszOut, [In][Out] ref uint pcchOut);
|
||||||
|
|
||||||
|
[Flags]
|
||||||
|
public enum AssocF
|
||||||
|
{
|
||||||
|
Init_NoRemapCLSID = 0x1,
|
||||||
|
Init_ByExeName = 0x2,
|
||||||
|
Open_ByExeName = 0x2,
|
||||||
|
Init_DefaultToStar = 0x4,
|
||||||
|
Init_DefaultToFolder = 0x8,
|
||||||
|
NoUserSettings = 0x10,
|
||||||
|
NoTruncate = 0x20,
|
||||||
|
Verify = 0x40,
|
||||||
|
RemapRunDll = 0x80,
|
||||||
|
NoFixUps = 0x100,
|
||||||
|
IgnoreBaseClass = 0x200
|
||||||
|
}
|
||||||
|
|
||||||
|
public enum AssocStr
|
||||||
|
{
|
||||||
|
Command = 1,
|
||||||
|
Executable,
|
||||||
|
FriendlyDocName,
|
||||||
|
FriendlyAppName,
|
||||||
|
NoOpen,
|
||||||
|
ShellNewValue,
|
||||||
|
DDECommand,
|
||||||
|
DDEIfExec,
|
||||||
|
DDEApplication,
|
||||||
|
DDETopic
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -96,7 +96,15 @@
|
|||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<Border Grid.Row="3" Grid.ColumnSpan="2" Padding="0 5 0 0" BorderThickness="0 2 0 0" BorderBrush="DarkGray">
|
<Border Grid.Row="3" Grid.ColumnSpan="2" Padding="0 5 0 0" BorderThickness="0 2 0 0" BorderBrush="DarkGray">
|
||||||
|
<DockPanel>
|
||||||
<Image Source="{StaticResource ModioLogoBlueDark}" Cursor="Hand" Height="30" MouseUp="Image_MouseUp" HorizontalAlignment="Left" />
|
<Image Source="{StaticResource ModioLogoBlueDark}" Cursor="Hand" Height="30" MouseUp="Image_MouseUp" HorizontalAlignment="Left" />
|
||||||
|
<Button HorizontalAlignment="Right" Click="CreatePluginButton_Click">
|
||||||
|
<StackPanel Orientation="Horizontal">
|
||||||
|
<materialDesign:PackIcon Kind="Add" Margin="0 0 10 0" />
|
||||||
|
<TextBlock Text="{DynamicResource createNewPlugin}" />
|
||||||
|
</StackPanel>
|
||||||
|
</Button>
|
||||||
|
</DockPanel>
|
||||||
</Border>
|
</Border>
|
||||||
</Grid>
|
</Grid>
|
||||||
</busyIndicator:BusyMask>
|
</busyIndicator:BusyMask>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
using DesktopMagic.DataContexts;
|
using DesktopMagic.DataContexts;
|
||||||
|
using DesktopMagic.Dialogs;
|
||||||
using DesktopMagic.Helpers;
|
using DesktopMagic.Helpers;
|
||||||
|
|
||||||
using Modio;
|
using Modio;
|
||||||
@@ -9,11 +10,13 @@ using System;
|
|||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.ComponentModel;
|
using System.ComponentModel;
|
||||||
using System.Diagnostics;
|
using System.Diagnostics;
|
||||||
|
using System.Globalization;
|
||||||
using System.IO;
|
using System.IO;
|
||||||
using System.IO.Compression;
|
using System.IO.Compression;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Text.Json;
|
using System.Text.Json;
|
||||||
|
using System.Text.RegularExpressions;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using System.Windows;
|
using System.Windows;
|
||||||
using System.Windows.Threading;
|
using System.Windows.Threading;
|
||||||
@@ -34,6 +37,7 @@ public partial class PluginManager : Window
|
|||||||
|
|
||||||
private readonly PluginManagerDataContext pluginManagerDataContext = new();
|
private readonly PluginManagerDataContext pluginManagerDataContext = new();
|
||||||
private readonly string pluginsPath = Path.Combine(App.ApplicationDataPath, "Plugins");
|
private readonly string pluginsPath = Path.Combine(App.ApplicationDataPath, "Plugins");
|
||||||
|
private readonly string pluginDevelopmentPath = Path.Combine(App.ApplicationDataPath, "PluginDevelopment");
|
||||||
|
|
||||||
private readonly DispatcherTimer searchTimer = new()
|
private readonly DispatcherTimer searchTimer = new()
|
||||||
{
|
{
|
||||||
@@ -125,6 +129,9 @@ public partial class PluginManager : Window
|
|||||||
e.Cancel = pluginManagerDataContext.IsLoading;
|
e.Cancel = pluginManagerDataContext.IsLoading;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[GeneratedRegex(@"[^a-zA-Z0-9]")]
|
||||||
|
private static partial Regex IdentifierNameRegex();
|
||||||
|
|
||||||
private async Task Install(Mod mod)
|
private async Task Install(Mod mod)
|
||||||
{
|
{
|
||||||
pluginManagerDataContext.IsLoading = true;
|
pluginManagerDataContext.IsLoading = true;
|
||||||
@@ -235,4 +242,123 @@ public partial class PluginManager : Window
|
|||||||
|
|
||||||
pluginManagerDataContext.IsSearching = false;
|
pluginManagerDataContext.IsSearching = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void CreatePluginButton_Click(object sender, RoutedEventArgs e)
|
||||||
|
{
|
||||||
|
try
|
||||||
|
{
|
||||||
|
CreateNewPlugin();
|
||||||
|
}
|
||||||
|
catch (Exception ex)
|
||||||
|
{
|
||||||
|
App.Logger.LogError(ex.Message, source: "PluginManager");
|
||||||
|
_ = MessageBox.Show(ex.Message, "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private void CreateNewPlugin()
|
||||||
|
{
|
||||||
|
if (!FileUtilities.ExistsOnPath("dotnet.exe"))
|
||||||
|
{
|
||||||
|
_ = MessageBox.Show("The .NET SDK is required to create a plugin. Please install it and try again.", "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string pluginGuid = Guid.NewGuid().ToString();
|
||||||
|
string pluginPath = Path.Combine(pluginsPath, pluginGuid);
|
||||||
|
uint pluginId = (uint)Random.Shared.Next(1000, 9999);
|
||||||
|
|
||||||
|
InputDialog inputDialog = new((string)FindResource("enterPluginName"), "Plugin Manager")
|
||||||
|
{
|
||||||
|
Owner = this,
|
||||||
|
};
|
||||||
|
|
||||||
|
if (inputDialog.ShowDialog() is not true)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
string pluginName = inputDialog.ResponseText;
|
||||||
|
string pluginSafeName = pluginName.ToLower().Replace("_", " ");
|
||||||
|
|
||||||
|
TextInfo info = CultureInfo.CurrentCulture.TextInfo;
|
||||||
|
pluginSafeName = info.ToTitleCase(pluginSafeName);
|
||||||
|
pluginSafeName = IdentifierNameRegex().Replace(pluginSafeName, "");
|
||||||
|
|
||||||
|
if (!Directory.Exists(pluginDevelopmentPath))
|
||||||
|
{
|
||||||
|
_ = Directory.CreateDirectory(pluginDevelopmentPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
string pluginProjectPath = Path.Combine(pluginDevelopmentPath, pluginSafeName);
|
||||||
|
|
||||||
|
if (Directory.Exists(pluginProjectPath))
|
||||||
|
{
|
||||||
|
_ = MessageBox.Show("A plugin with the same name already exists. Please choose a different name.", "Plugin Manager", MessageBoxButton.OK, MessageBoxImage.Error);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
PluginMetadata pluginMetadata = new(pluginName, pluginId);
|
||||||
|
|
||||||
|
_ = Directory.CreateDirectory(pluginPath);
|
||||||
|
_ = Directory.CreateDirectory(pluginProjectPath);
|
||||||
|
|
||||||
|
string pluginMetadataPath = Path.Combine(pluginPath, "metadata.json");
|
||||||
|
File.WriteAllText(pluginMetadataPath, JsonSerializer.Serialize(pluginMetadata));
|
||||||
|
|
||||||
|
string cmd = $"new classlib -n {pluginSafeName} -o {pluginProjectPath} -f net8.0 --target-framework-override net8.0-windows7";
|
||||||
|
Process process = Process.Start("dotnet", cmd);
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
// Install the required NuGet packages
|
||||||
|
process = Process.Start("dotnet", $"add {pluginProjectPath} package DesktopMagic.Api");
|
||||||
|
process.WaitForExit();
|
||||||
|
|
||||||
|
File.Move(Path.Combine(pluginProjectPath, "Class1.cs"), Path.Combine(pluginProjectPath, $"{pluginSafeName}.cs"));
|
||||||
|
|
||||||
|
string code = $@"using DesktopMagic.Api;
|
||||||
|
using System.Drawing;
|
||||||
|
|
||||||
|
namespace {pluginSafeName};
|
||||||
|
|
||||||
|
public class {pluginSafeName}Plugin : Plugin
|
||||||
|
{{
|
||||||
|
public override Bitmap Main()
|
||||||
|
{{
|
||||||
|
Bitmap bmp = new Bitmap(1000, 1000);
|
||||||
|
|
||||||
|
using (Graphics g = Graphics.FromImage(bmp))
|
||||||
|
{{
|
||||||
|
g.Clear(Application.Theme.PrimaryColor); // Set the background color to the color specified in the DesktopMagic application.
|
||||||
|
|
||||||
|
g.DrawString(""Hello World"", new Font(Application.Theme.Font, 100), Brushes.Black, new PointF(0, 0)); // Draw ""Hello World"" to the image.
|
||||||
|
}}
|
||||||
|
|
||||||
|
bmp.SetResolution(300, 300); // Set DPI to avoid scaling issues.
|
||||||
|
|
||||||
|
return bmp; // Return the image.
|
||||||
|
}}
|
||||||
|
}}
|
||||||
|
";
|
||||||
|
|
||||||
|
File.WriteAllText(Path.Combine(pluginProjectPath, $"{pluginSafeName}.cs"), code);
|
||||||
|
|
||||||
|
// Open the project in the default IDE
|
||||||
|
|
||||||
|
string? associatedProgram = FileUtilities.GetAssociatedProgram(".csproj");
|
||||||
|
|
||||||
|
if (associatedProgram is null)
|
||||||
|
{
|
||||||
|
_ = Process.Start("explorer.exe", pluginProjectPath);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
ProcessStartInfo psi = new ProcessStartInfo
|
||||||
|
{
|
||||||
|
FileName = associatedProgram,
|
||||||
|
Arguments = Path.Combine(pluginProjectPath, $"{pluginSafeName}.csproj"),
|
||||||
|
};
|
||||||
|
|
||||||
|
_ = Process.Start(psi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -15,6 +15,8 @@
|
|||||||
<system:String x:Key="updatePlugins">Neu Laden</system:String>
|
<system:String x:Key="updatePlugins">Neu Laden</system:String>
|
||||||
<system:String x:Key="pluginsFolder">Plugins Ordner</system:String>
|
<system:String x:Key="pluginsFolder">Plugins Ordner</system:String>
|
||||||
<system:String x:Key="pluginManager">Plugins Manager</system:String>
|
<system:String x:Key="pluginManager">Plugins Manager</system:String>
|
||||||
|
<system:String x:Key="createNewPlugin">Neues Plugin erstellen</system:String>
|
||||||
|
<system:String x:Key="enterPluginName">Pluginnamen eingeben</system:String>
|
||||||
<system:String x:Key="color">Farbe:</system:String>
|
<system:String x:Key="color">Farbe:</system:String>
|
||||||
<system:String x:Key="default">Standard</system:String>
|
<system:String x:Key="default">Standard</system:String>
|
||||||
<system:String x:Key="wantToCloseProgram">Wollen sie das Programm wirklich schließen?</system:String>
|
<system:String x:Key="wantToCloseProgram">Wollen sie das Programm wirklich schließen?</system:String>
|
||||||
|
|||||||
@@ -15,6 +15,8 @@
|
|||||||
<system:String x:Key="updatePlugins">Reload</system:String>
|
<system:String x:Key="updatePlugins">Reload</system:String>
|
||||||
<system:String x:Key="pluginsFolder">Plugins Folder</system:String>
|
<system:String x:Key="pluginsFolder">Plugins Folder</system:String>
|
||||||
<system:String x:Key="pluginManager">Plugins Manager</system:String>
|
<system:String x:Key="pluginManager">Plugins Manager</system:String>
|
||||||
|
<system:String x:Key="createNewPlugin">Create New Plugin</system:String>
|
||||||
|
<system:String x:Key="enterPluginName">Enter plugin name</system:String>
|
||||||
<system:String x:Key="color">Color:</system:String>
|
<system:String x:Key="color">Color:</system:String>
|
||||||
<system:String x:Key="default">Default</system:String>
|
<system:String x:Key="default">Default</system:String>
|
||||||
<system:String x:Key="wantToCloseProgram">Do you really want to close the program?</system:String>
|
<system:String x:Key="wantToCloseProgram">Do you really want to close the program?</system:String>
|
||||||
|
|||||||
Reference in New Issue
Block a user