delete:插件系统
This commit is contained in:
+1
-67
@@ -1,16 +1,10 @@
|
|||||||
|
|
||||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||||
# Visual Studio Version 17
|
# Visual Studio Version 17
|
||||||
VisualStudioVersion = 17.5.33530.505
|
VisualStudioVersion = 17.5.33530.505
|
||||||
MinimumVisualStudioVersion = 10.0.40219.1
|
MinimumVisualStudioVersion = 10.0.40219.1
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvasForClass", "Ink Canvas\InkCanvasForClass.csproj", "{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}"
|
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvasForClass", "Ink Canvas\InkCanvasForClass.csproj", "{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}"
|
||||||
EndProject
|
EndProject
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvas.PluginSdk", "Plugins\SDK\InkCanvas.PluginSdk.csproj", "{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}"
|
|
||||||
EndProject
|
|
||||||
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "InkCanvas.PluginHost", "Plugins\Host\InkCanvas.PluginHost.csproj", "{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}"
|
|
||||||
EndProject
|
|
||||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleClockPlugin", "Plugins\Samples\SampleClockPlugin\SampleClockPlugin.csproj", "{60891C83-8F04-438E-8064-D827E7AC1817}"
|
|
||||||
EndProject
|
|
||||||
Global
|
Global
|
||||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||||
Debug|Any CPU = Debug|Any CPU
|
Debug|Any CPU = Debug|Any CPU
|
||||||
@@ -45,66 +39,6 @@ Global
|
|||||||
{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x64.Build.0 = Release|Any CPU
|
{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x64.Build.0 = Release|Any CPU
|
||||||
{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x86.ActiveCfg = Release|Any CPU
|
{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x86.ActiveCfg = Release|Any CPU
|
||||||
{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x86.Build.0 = Release|Any CPU
|
{8D0EDFC7-F974-4571-BC49-6F3A6653FE81}.Release|x86.Build.0 = Release|Any CPU
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|ARM64.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM64.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|ARM64.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7081}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|ARM64.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM64.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|ARM64.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{E4B8F2A1-6C3D-4E9F-A1B2-3C4D5E6F7082}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM.ActiveCfg = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM.Build.0 = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM64.ActiveCfg = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|ARM64.Build.0 = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x64.ActiveCfg = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x64.Build.0 = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x86.ActiveCfg = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Debug|x86.Build.0 = Debug|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|Any CPU.Build.0 = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM.ActiveCfg = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM.Build.0 = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM64.ActiveCfg = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|ARM64.Build.0 = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|x64.ActiveCfg = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|x64.Build.0 = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|x86.ActiveCfg = Release|Any CPU
|
|
||||||
{60891C83-8F04-438E-8064-D827E7AC1817}.Release|x86.Build.0 = Release|Any CPU
|
|
||||||
EndGlobalSection
|
EndGlobalSection
|
||||||
GlobalSection(SolutionProperties) = preSolution
|
GlobalSection(SolutionProperties) = preSolution
|
||||||
HideSolutionNode = FALSE
|
HideSolutionNode = FALSE
|
||||||
|
|||||||
@@ -1,274 +0,0 @@
|
|||||||
using iNKORE.UI.WPF.Controls;
|
|
||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台按钮控件
|
|
||||||
/// </summary>
|
|
||||||
public class LauncherButton
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 父插件
|
|
||||||
/// </summary>
|
|
||||||
private readonly SuperLauncherPlugin _plugin;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 实际按钮控件
|
|
||||||
/// </summary>
|
|
||||||
private readonly SimpleStackPanel _panel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取按钮UI元素
|
|
||||||
/// </summary>
|
|
||||||
public UIElement Element => _panel;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugin">父插件</param>
|
|
||||||
public LauncherButton(SuperLauncherPlugin plugin)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
_plugin = plugin;
|
|
||||||
LogHelper.WriteLogToFile("开始创建启动台按钮");
|
|
||||||
|
|
||||||
// 创建SimpleStackPanel
|
|
||||||
_panel = new SimpleStackPanel
|
|
||||||
{
|
|
||||||
Name = "Launcher_Icon",
|
|
||||||
Orientation = Orientation.Vertical,
|
|
||||||
HorizontalAlignment = HorizontalAlignment.Center,
|
|
||||||
Width = 28,
|
|
||||||
Margin = new Thickness(0, -2, 0, 0),
|
|
||||||
Background = Brushes.Transparent
|
|
||||||
};
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile("创建SimpleStackPanel完成");
|
|
||||||
|
|
||||||
// 添加图标
|
|
||||||
var image = CreateIconImage();
|
|
||||||
_panel.Children.Add(image);
|
|
||||||
|
|
||||||
// 添加文本
|
|
||||||
TextBlock textBlock = new TextBlock
|
|
||||||
{
|
|
||||||
Text = "启动台",
|
|
||||||
Foreground = Brushes.Black,
|
|
||||||
FontSize = 8,
|
|
||||||
Margin = new Thickness(0, 1, 0, 0),
|
|
||||||
TextAlignment = TextAlignment.Center
|
|
||||||
};
|
|
||||||
_panel.Children.Add(textBlock);
|
|
||||||
|
|
||||||
// 设置鼠标事件
|
|
||||||
_panel.MouseDown += Panel_MouseDown;
|
|
||||||
_panel.MouseUp += Panel_MouseUp;
|
|
||||||
_panel.MouseLeave += Panel_MouseLeave;
|
|
||||||
|
|
||||||
// 右键菜单支持
|
|
||||||
_panel.ContextMenu = CreateContextMenu();
|
|
||||||
|
|
||||||
// 设置工具提示
|
|
||||||
_panel.ToolTip = "启动台";
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile("启动台按钮创建完成");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"创建启动台按钮时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建右键菜单
|
|
||||||
/// </summary>
|
|
||||||
private ContextMenu CreateContextMenu()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 创建菜单
|
|
||||||
ContextMenu menu = new ContextMenu();
|
|
||||||
|
|
||||||
// 创建位置切换菜单项
|
|
||||||
MenuItem positionMenuItem = new MenuItem();
|
|
||||||
positionMenuItem.Header = _plugin.Config.ButtonPosition == LauncherButtonPosition.Left ?
|
|
||||||
"移至右侧" : "移至左侧";
|
|
||||||
positionMenuItem.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
// 切换位置
|
|
||||||
_plugin.Config.ButtonPosition = _plugin.Config.ButtonPosition == LauncherButtonPosition.Left ?
|
|
||||||
LauncherButtonPosition.Right : LauncherButtonPosition.Left;
|
|
||||||
|
|
||||||
// 更新按钮位置
|
|
||||||
_plugin.UpdateButtonPosition();
|
|
||||||
|
|
||||||
// 保存配置
|
|
||||||
_plugin.SaveConfig();
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"通过右键菜单切换启动台按钮位置为: {_plugin.Config.ButtonPosition}");
|
|
||||||
};
|
|
||||||
menu.Items.Add(positionMenuItem);
|
|
||||||
|
|
||||||
// 添加设置菜单项
|
|
||||||
MenuItem settingsMenuItem = new MenuItem();
|
|
||||||
settingsMenuItem.Header = "打开设置";
|
|
||||||
settingsMenuItem.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
// 打开插件设置窗口
|
|
||||||
var mainWindow = Application.Current.MainWindow;
|
|
||||||
if (mainWindow != null)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 使用反射调用主窗口的ShowPluginSettings方法
|
|
||||||
var method = mainWindow.GetType().GetMethod("ShowPluginSettings");
|
|
||||||
if (method != null)
|
|
||||||
{
|
|
||||||
method.Invoke(mainWindow, null);
|
|
||||||
LogHelper.WriteLogToFile("已打开插件设置窗口");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"打开插件设置窗口失败: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
menu.Items.Add(settingsMenuItem);
|
|
||||||
|
|
||||||
return menu;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"创建右键菜单时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取实际的UI元素
|
|
||||||
/// </summary>
|
|
||||||
[Obsolete("使用Element属性代替")]
|
|
||||||
public UIElement GetUIElement()
|
|
||||||
{
|
|
||||||
return _panel;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建图标图像
|
|
||||||
/// </summary>
|
|
||||||
private Image CreateIconImage()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 创建图像
|
|
||||||
Image image = new Image
|
|
||||||
{
|
|
||||||
Height = 17,
|
|
||||||
Margin = new Thickness(0, 3, 0, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
// 设置位图缩放模式
|
|
||||||
RenderOptions.SetBitmapScalingMode(image, BitmapScalingMode.HighQuality);
|
|
||||||
|
|
||||||
// 创建绘图图像
|
|
||||||
DrawingImage drawingImage = new DrawingImage();
|
|
||||||
DrawingGroup drawingGroup = new DrawingGroup();
|
|
||||||
drawingGroup.ClipGeometry = Geometry.Parse("M0,0 V24 H24 V0 H0 Z");
|
|
||||||
|
|
||||||
// 使用提供的应用网格图标
|
|
||||||
GeometryDrawing geometryDrawing = new GeometryDrawing
|
|
||||||
{
|
|
||||||
Brush = new SolidColorBrush(Color.FromRgb(0x1B, 0x1B, 0x1B)),
|
|
||||||
Geometry = Geometry.Parse("F0 M24,24z M0,0z M4.41721,4.29873C4.35178,4.29873,4.29873,4.35178,4.29873,4.41721L4.29873,9.15646C4.29873,9.22189,4.35178,9.27494,4.41721,9.27494L9.15646,9.27494C9.22189,9.27494,9.27494,9.22189,9.27494,9.15646L9.27494,4.41721C9.27494,4.35178,9.22189,4.29873,9.15646,4.29873L4.41721,4.29873z M2.64,4.41721C2.64,3.43569,3.43569,2.64,4.41721,2.64L9.15646,2.64C10.138,2.64,10.9337,3.43569,10.9337,4.41721L10.9337,9.15646C10.9337,10.138,10.138,10.9337,9.15646,10.9337L4.41721,10.9337C3.43569,10.9337,2.64,10.138,2.64,9.15646L2.64,4.41721z M14.8435,4.29873C14.7781,4.29873,14.7251,4.35178,14.7251,4.41721L14.7251,9.15646C14.7251,9.22189,14.7781,9.27494,14.8435,9.27494L19.5828,9.27494C19.6482,9.27494,19.7013,9.22189,19.7013,9.15646L19.7013,4.41721C19.7013,4.35178,19.6482,4.29873,19.5828,4.29873L14.8435,4.29873z M13.0663,4.41721C13.0663,3.43569,13.862,2.64,14.8435,2.64L19.5828,2.64C20.5643,2.64,21.36,3.43569,21.36,4.41721L21.36,9.15646C21.36,10.138,20.5643,10.9337,19.5828,10.9337L14.8435,10.9337C13.862,10.9337,13.0663,10.138,13.0663,9.15646L13.0663,4.41721z M14.8435,14.7251C14.7781,14.7251,14.7251,14.7781,14.7251,14.8435L14.7251,19.5828C14.7251,19.6482,14.7781,19.7013,14.8435,19.7013L19.5828,19.7013C19.6482,19.7013,19.7013,19.6482,19.7013,19.5828L19.7013,14.8435C19.7013,14.7781,19.6482,14.7251,19.5828,14.7251L14.8435,14.7251z M13.0663,14.8435C13.0663,13.862,13.862,13.0663,14.8435,13.0663L19.5828,13.0663C20.5643,13.0663,21.36,13.862,21.36,14.8435L21.36,19.5828C21.36,20.5643,20.5643,21.36,19.5828,21.36L14.8435,21.36C13.862,21.36,13.0663,20.5643,13.0663,19.5828L13.0663,14.8435z M4.41721,14.7251C4.35178,14.7251,4.29873,14.7781,4.29873,14.8435L4.29873,19.5828C4.29873,19.6482,4.35178,19.7013,4.41721,19.7013L9.15646,19.7013C9.22189,19.7013,9.27494,19.6482,9.27494,19.5828L9.27494,14.8435C9.27494,14.7781,9.22189,14.7251,9.15646,14.7251L4.41721,14.7251z M2.64,14.8435C2.64,13.862,3.43569,13.0663,4.41721,13.0663L9.15646,13.0663C10.138,13.0663,10.9337,13.862,10.9337,14.8435L10.9337,19.5828C10.9337,20.5643,10.138,21.36,9.15646,21.36L4.41721,21.36C3.43569,21.36,2.64,20.5643,2.64,19.5828L2.64,14.8435z")
|
|
||||||
};
|
|
||||||
|
|
||||||
drawingGroup.Children.Add(geometryDrawing);
|
|
||||||
|
|
||||||
// 设置图像源
|
|
||||||
drawingImage.Drawing = drawingGroup;
|
|
||||||
image.Source = drawingImage;
|
|
||||||
|
|
||||||
return image;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"创建图标图像时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
|
|
||||||
// 返回一个空图像
|
|
||||||
return new Image();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 鼠标按下事件
|
|
||||||
/// </summary>
|
|
||||||
private void Panel_MouseDown(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 提供反馈
|
|
||||||
_panel.Background = new SolidColorBrush(Color.FromArgb(40, 0, 0, 0));
|
|
||||||
LogHelper.WriteLogToFile("启动台按钮鼠标按下");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"启动台按钮鼠标按下事件出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 鼠标抬起事件
|
|
||||||
/// </summary>
|
|
||||||
private void Panel_MouseUp(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 只有左键点击才显示启动台窗口
|
|
||||||
if (e.ChangedButton != MouseButton.Left)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 恢复背景
|
|
||||||
_panel.Background = Brushes.Transparent;
|
|
||||||
LogHelper.WriteLogToFile("启动台按钮鼠标抬起,准备显示启动台窗口");
|
|
||||||
|
|
||||||
// 获取按钮在屏幕上的位置
|
|
||||||
Point buttonPosition = _panel.PointToScreen(new Point(_panel.ActualWidth / 2, 0));
|
|
||||||
|
|
||||||
// 显示启动台窗口
|
|
||||||
_plugin.ShowLauncherWindow(buttonPosition);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"启动台按钮鼠标抬起事件出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 鼠标离开事件
|
|
||||||
/// </summary>
|
|
||||||
private void Panel_MouseLeave(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 恢复背景
|
|
||||||
_panel.Background = Brushes.Transparent;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"启动台按钮鼠标离开事件出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,332 +0,0 @@
|
|||||||
using Microsoft.Win32;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.Drawing;
|
|
||||||
using System.IO;
|
|
||||||
using System.Runtime.InteropServices;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Interop;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Media.Imaging;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台按钮位置
|
|
||||||
/// </summary>
|
|
||||||
public enum LauncherButtonPosition
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 左侧
|
|
||||||
/// </summary>
|
|
||||||
Left,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 右侧
|
|
||||||
/// </summary>
|
|
||||||
Right
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台配置
|
|
||||||
/// </summary>
|
|
||||||
public class LauncherConfig
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台按钮位置
|
|
||||||
/// </summary>
|
|
||||||
public LauncherButtonPosition ButtonPosition { get; set; } = LauncherButtonPosition.Right;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台应用程序列表
|
|
||||||
/// </summary>
|
|
||||||
public List<LauncherItem> Items { get; set; } = new List<LauncherItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台应用项
|
|
||||||
/// </summary>
|
|
||||||
public class LauncherItem
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 应用程序名称
|
|
||||||
/// </summary>
|
|
||||||
public string Name { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用程序路径
|
|
||||||
/// </summary>
|
|
||||||
public string Path { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否可见
|
|
||||||
/// </summary>
|
|
||||||
public bool IsVisible { get; set; } = true;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 在启动台中的位置(0-39)
|
|
||||||
/// </summary>
|
|
||||||
public int Position { get; set; } = -1;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否已固定位置
|
|
||||||
/// </summary>
|
|
||||||
public bool IsPositionFixed { get; set; } = false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 图标缓存
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
private ImageSource _iconCache;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取应用程序图标
|
|
||||||
/// </summary>
|
|
||||||
[JsonIgnore]
|
|
||||||
public ImageSource Icon
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
if (_iconCache != null)
|
|
||||||
{
|
|
||||||
return _iconCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(Path))
|
|
||||||
{
|
|
||||||
// 从文件中获取图标
|
|
||||||
Icon icon = System.Drawing.Icon.ExtractAssociatedIcon(Path);
|
|
||||||
if (icon != null)
|
|
||||||
{
|
|
||||||
_iconCache = Imaging.CreateBitmapSourceFromHIcon(
|
|
||||||
icon.Handle,
|
|
||||||
Int32Rect.Empty,
|
|
||||||
BitmapSizeOptions.FromEmptyOptions());
|
|
||||||
|
|
||||||
icon.Dispose();
|
|
||||||
return _iconCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 从注册表中获取文件类型关联图标
|
|
||||||
string extension = System.IO.Path.GetExtension(Path);
|
|
||||||
if (!string.IsNullOrEmpty(extension))
|
|
||||||
{
|
|
||||||
string fileType = Registry.ClassesRoot.OpenSubKey(extension)?.GetValue(string.Empty) as string;
|
|
||||||
if (!string.IsNullOrEmpty(fileType))
|
|
||||||
{
|
|
||||||
string iconPath = Registry.ClassesRoot.OpenSubKey(fileType + "\\DefaultIcon")?.GetValue(string.Empty) as string;
|
|
||||||
if (!string.IsNullOrEmpty(iconPath))
|
|
||||||
{
|
|
||||||
string[] parts = iconPath.Split(',');
|
|
||||||
string iconFile = parts[0].Trim('"');
|
|
||||||
int iconIndex = parts.Length > 1 ? Convert.ToInt32(parts[1]) : 0;
|
|
||||||
|
|
||||||
if (File.Exists(iconFile))
|
|
||||||
{
|
|
||||||
Icon icon = IconExtractor.Extract(iconFile, iconIndex, true);
|
|
||||||
if (icon != null)
|
|
||||||
{
|
|
||||||
_iconCache = Imaging.CreateBitmapSourceFromHIcon(
|
|
||||||
icon.Handle,
|
|
||||||
Int32Rect.Empty,
|
|
||||||
BitmapSizeOptions.FromEmptyOptions());
|
|
||||||
|
|
||||||
icon.Dispose();
|
|
||||||
return _iconCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"获取应用图标时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回默认图标
|
|
||||||
return GetDefaultIcon();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取默认图标
|
|
||||||
/// </summary>
|
|
||||||
private ImageSource GetDefaultIcon()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 对于资源管理器,使用特定图标
|
|
||||||
if (Path.EndsWith("explorer.exe", StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 直接从C:\Windows\explorer.exe获取图标
|
|
||||||
string explorerPath = @"C:\Windows\explorer.exe";
|
|
||||||
if (File.Exists(explorerPath))
|
|
||||||
{
|
|
||||||
Icon icon = System.Drawing.Icon.ExtractAssociatedIcon(explorerPath);
|
|
||||||
if (icon != null)
|
|
||||||
{
|
|
||||||
_iconCache = Imaging.CreateBitmapSourceFromHIcon(
|
|
||||||
icon.Handle,
|
|
||||||
Int32Rect.Empty,
|
|
||||||
BitmapSizeOptions.FromEmptyOptions());
|
|
||||||
|
|
||||||
icon.Dispose();
|
|
||||||
return _iconCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"获取资源管理器图标时出错: {ex.Message}", LogHelper.LogType.Warning);
|
|
||||||
// 如果获取Windows图标失败,回退到默认图标
|
|
||||||
}
|
|
||||||
|
|
||||||
// 回退到备用图标
|
|
||||||
string explorerIconPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Icons-Fluent", "ic_fluent_folder_24_regular.png");
|
|
||||||
if (File.Exists(explorerIconPath))
|
|
||||||
{
|
|
||||||
Uri uri = new Uri(explorerIconPath);
|
|
||||||
BitmapImage image = new BitmapImage(uri);
|
|
||||||
_iconCache = image;
|
|
||||||
return _iconCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 返回一个简单的默认图标
|
|
||||||
string iconPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Icons-png", "icc.png");
|
|
||||||
if (File.Exists(iconPath))
|
|
||||||
{
|
|
||||||
Uri uri = new Uri(iconPath);
|
|
||||||
BitmapImage image = new BitmapImage(uri);
|
|
||||||
_iconCache = image;
|
|
||||||
return _iconCache;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果还是没有找到,尝试使用应用程序图标
|
|
||||||
string appIconPath = System.IO.Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Resources", "Icons-Fluent", "ic_fluent_apps_24_regular.png");
|
|
||||||
if (File.Exists(appIconPath))
|
|
||||||
{
|
|
||||||
Uri uri = new Uri(appIconPath);
|
|
||||||
BitmapImage image = new BitmapImage(uri);
|
|
||||||
_iconCache = image;
|
|
||||||
return _iconCache;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"获取默认图标时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动应用程序
|
|
||||||
/// </summary>
|
|
||||||
public void Launch()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (string.IsNullOrEmpty(Path))
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile("无法启动应用程序:路径为空", LogHelper.LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查文件是否存在
|
|
||||||
if (!File.Exists(Path) && !Path.Contains(":\\"))
|
|
||||||
{
|
|
||||||
// 可能是系统命令,如explorer.exe
|
|
||||||
ProcessStartInfo psi = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = Path,
|
|
||||||
UseShellExecute = true
|
|
||||||
};
|
|
||||||
Process.Start(psi);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 使用Process.Start启动应用程序
|
|
||||||
ProcessStartInfo psi = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = Path,
|
|
||||||
UseShellExecute = true
|
|
||||||
};
|
|
||||||
Process.Start(psi);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"已启动应用程序: {Path}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"启动应用程序时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"启动应用程序时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 图标提取工具类
|
|
||||||
/// </summary>
|
|
||||||
public static class IconExtractor
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 从文件中提取图标
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="file">文件路径</param>
|
|
||||||
/// <param name="index">图标索引</param>
|
|
||||||
/// <param name="largeIcon">是否提取大图标</param>
|
|
||||||
/// <returns>提取的图标</returns>
|
|
||||||
public static Icon Extract(string file, int index, bool largeIcon)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
IntPtr large;
|
|
||||||
IntPtr small;
|
|
||||||
ExtractIconEx(file, index, out large, out small, 1);
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Icon.FromHandle(largeIcon ? large : small);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
if (large != IntPtr.Zero)
|
|
||||||
DestroyIcon(large);
|
|
||||||
|
|
||||||
if (small != IntPtr.Zero)
|
|
||||||
DestroyIcon(small);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
[DllImport("Shell32.dll", EntryPoint = "ExtractIconEx")]
|
|
||||||
private static extern int ExtractIconEx(
|
|
||||||
[MarshalAs(UnmanagedType.LPStr)] string lpszFile,
|
|
||||||
int nIconIndex,
|
|
||||||
out IntPtr phiconLarge,
|
|
||||||
out IntPtr phiconSmall,
|
|
||||||
int nIcons);
|
|
||||||
|
|
||||||
[DllImport("User32.dll")]
|
|
||||||
private static extern int DestroyIcon(IntPtr hIcon);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,143 +0,0 @@
|
|||||||
<UserControl x:Class="Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher.LauncherSettingsControl"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:local="clr-namespace:Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
d:DesignHeight="500" d:DesignWidth="600">
|
|
||||||
|
|
||||||
<UserControl.Resources>
|
|
||||||
<!-- 自定义按钮样式 -->
|
|
||||||
<Style x:Key="DefaultButtonStyle" TargetType="Button">
|
|
||||||
<Setter Property="FontWeight" Value="SemiBold"/>
|
|
||||||
<Setter Property="FontSize" Value="12"/>
|
|
||||||
<Setter Property="Cursor" Value="Hand"/>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border x:Name="border"
|
|
||||||
Background="{TemplateBinding Background}"
|
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
|
||||||
BorderThickness="{TemplateBinding BorderThickness}"
|
|
||||||
CornerRadius="4"
|
|
||||||
Padding="{TemplateBinding Padding}">
|
|
||||||
<ContentPresenter HorizontalAlignment="Center"
|
|
||||||
VerticalAlignment="Center"
|
|
||||||
TextElement.Foreground="{TemplateBinding Foreground}"/>
|
|
||||||
</Border>
|
|
||||||
<ControlTemplate.Triggers>
|
|
||||||
<Trigger Property="IsMouseOver" Value="True">
|
|
||||||
<Setter TargetName="border" Property="Opacity" Value="0.8"/>
|
|
||||||
<Setter Property="Effect">
|
|
||||||
<Setter.Value>
|
|
||||||
<DropShadowEffect Color="Black" Direction="270" ShadowDepth="2" Opacity="0.3" BlurRadius="4"/>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Trigger>
|
|
||||||
<Trigger Property="IsPressed" Value="True">
|
|
||||||
<Setter TargetName="border" Property="Opacity" Value="0.6"/>
|
|
||||||
<Setter Property="RenderTransform">
|
|
||||||
<Setter.Value>
|
|
||||||
<ScaleTransform ScaleX="0.95" ScaleY="0.95"/>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
<Setter Property="RenderTransformOrigin" Value="0.5,0.5"/>
|
|
||||||
</Trigger>
|
|
||||||
<Trigger Property="IsEnabled" Value="False">
|
|
||||||
<Setter TargetName="border" Property="Opacity" Value="0.4"/>
|
|
||||||
<Setter Property="Cursor" Value="Arrow"/>
|
|
||||||
</Trigger>
|
|
||||||
</ControlTemplate.Triggers>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</UserControl.Resources>
|
|
||||||
|
|
||||||
<Grid Margin="10">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- 标题 -->
|
|
||||||
<TextBlock Grid.Row="0" Text="超级启动台设置" FontSize="16" FontWeight="Bold" Margin="0,0,0,15" Foreground="Black"/>
|
|
||||||
|
|
||||||
<!-- 基本设置 -->
|
|
||||||
<StackPanel Grid.Row="1" Margin="0,0,0,15">
|
|
||||||
<TextBlock Text="基本设置" FontSize="14" FontWeight="SemiBold" Margin="0,0,0,10" Foreground="Black"/>
|
|
||||||
|
|
||||||
<Grid Margin="10,0,0,0">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="120"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- 按钮位置 -->
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="按钮位置:" VerticalAlignment="Center" Foreground="Black"/>
|
|
||||||
<StackPanel Grid.Row="0" Grid.Column="1" Orientation="Horizontal" Margin="0,5">
|
|
||||||
<RadioButton x:Name="RbtnLeft" Content="浮动栏左侧" Margin="0,0,20,0" Checked="RbtnPosition_Checked" Foreground="Black"/>
|
|
||||||
<RadioButton x:Name="RbtnRight" Content="浮动栏右侧" IsChecked="True" Checked="RbtnPosition_Checked" Foreground="Black"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</StackPanel>
|
|
||||||
|
|
||||||
<!-- 应用管理 -->
|
|
||||||
<Grid Grid.Row="2">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Text="应用管理" FontSize="14" FontWeight="SemiBold" Margin="0,0,0,10" Foreground="Black"/>
|
|
||||||
|
|
||||||
<Border Grid.Row="1" BorderThickness="1" BorderBrush="#CCCCCC" CornerRadius="5">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- 应用列表 -->
|
|
||||||
<DataGrid Grid.Row="0" x:Name="DgApps" AutoGenerateColumns="False" Margin="5"
|
|
||||||
CanUserAddRows="False" CanUserDeleteRows="False"
|
|
||||||
HeadersVisibility="Column" SelectionMode="Single"
|
|
||||||
SelectionChanged="DgApps_SelectionChanged">
|
|
||||||
<DataGrid.Columns>
|
|
||||||
<DataGridCheckBoxColumn Header="显示" Binding="{Binding IsVisible}" Width="50"/>
|
|
||||||
<DataGridTextColumn Header="名称" Binding="{Binding Name}" Width="150"/>
|
|
||||||
<DataGridTextColumn Header="路径" Binding="{Binding Path}" Width="*"/>
|
|
||||||
<DataGridTextColumn Header="位置" Binding="{Binding Position}" Width="50"/>
|
|
||||||
</DataGrid.Columns>
|
|
||||||
</DataGrid>
|
|
||||||
|
|
||||||
<!-- 操作按钮 -->
|
|
||||||
<StackPanel Grid.Row="1" Orientation="Horizontal" Margin="5">
|
|
||||||
<Button x:Name="BtnAdd" Content="添加" Padding="10,5" Margin="0,5,5,5" Click="BtnAdd_Click"
|
|
||||||
Background="#FF007ACC" Foreground="White" BorderBrush="#FF005A9B" BorderThickness="1"
|
|
||||||
Style="{StaticResource DefaultButtonStyle}"/>
|
|
||||||
<Button x:Name="BtnEdit" Content="编辑" Padding="10,5" Margin="5" Click="BtnEdit_Click"
|
|
||||||
Background="#FF6C757D" Foreground="White" BorderBrush="#FF5A6268" BorderThickness="1"
|
|
||||||
Style="{StaticResource DefaultButtonStyle}"/>
|
|
||||||
<Button x:Name="BtnDelete" Content="删除" Padding="10,5" Margin="5" Click="BtnDelete_Click"
|
|
||||||
Background="#FFDC3545" Foreground="White" BorderBrush="#FFBD2130" BorderThickness="1"
|
|
||||||
Style="{StaticResource DefaultButtonStyle}"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- 底部按钮 -->
|
|
||||||
<StackPanel Grid.Row="3" Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,15,0,0">
|
|
||||||
<Button x:Name="BtnSave" Content="保存设置" Padding="15,5" Click="BtnSave_Click"
|
|
||||||
Background="#FF28A745" Foreground="White" BorderBrush="#FF1E7E34" BorderThickness="1"
|
|
||||||
Style="{StaticResource DefaultButtonStyle}"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</UserControl>
|
|
||||||
@@ -1,396 +0,0 @@
|
|||||||
using Ink_Canvas.Windows;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
using System;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// LauncherSettingsControl.xaml 的交互逻辑
|
|
||||||
/// </summary>
|
|
||||||
public partial class LauncherSettingsControl : UserControl
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 父插件
|
|
||||||
/// </summary>
|
|
||||||
private readonly SuperLauncherPlugin _plugin;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="plugin">父插件</param>
|
|
||||||
public LauncherSettingsControl(SuperLauncherPlugin plugin)
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
_plugin = plugin;
|
|
||||||
|
|
||||||
// 设置按钮位置
|
|
||||||
RbtnLeft.IsChecked = _plugin.Config.ButtonPosition == LauncherButtonPosition.Left;
|
|
||||||
RbtnRight.IsChecked = _plugin.Config.ButtonPosition == LauncherButtonPosition.Right;
|
|
||||||
|
|
||||||
// 绑定应用列表
|
|
||||||
DgApps.ItemsSource = _plugin.LauncherItems;
|
|
||||||
|
|
||||||
// 初始化按钮状态
|
|
||||||
UpdateButtonStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新按钮状态
|
|
||||||
/// </summary>
|
|
||||||
private void UpdateButtonStates()
|
|
||||||
{
|
|
||||||
bool hasSelection = DgApps.SelectedItem != null;
|
|
||||||
BtnEdit.IsEnabled = hasSelection;
|
|
||||||
BtnDelete.IsEnabled = hasSelection;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 位置单选按钮选择事件
|
|
||||||
/// </summary>
|
|
||||||
private void RbtnPosition_Checked(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (!IsLoaded) return;
|
|
||||||
|
|
||||||
LauncherButtonPosition oldPosition = _plugin.Config.ButtonPosition;
|
|
||||||
|
|
||||||
if (sender == RbtnLeft)
|
|
||||||
{
|
|
||||||
_plugin.Config.ButtonPosition = LauncherButtonPosition.Left;
|
|
||||||
}
|
|
||||||
else if (sender == RbtnRight)
|
|
||||||
{
|
|
||||||
_plugin.Config.ButtonPosition = LauncherButtonPosition.Right;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果位置发生变化,更新按钮位置
|
|
||||||
if (oldPosition != _plugin.Config.ButtonPosition)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 更新按钮位置
|
|
||||||
_plugin.UpdateButtonPosition();
|
|
||||||
|
|
||||||
// 保存配置
|
|
||||||
_plugin.SaveConfig();
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"启动台按钮位置已更改为: {_plugin.Config.ButtonPosition}");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"更新启动台按钮位置时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"更新启动台按钮位置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnAdd_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 创建新的启动项
|
|
||||||
LauncherItem item = new LauncherItem
|
|
||||||
{
|
|
||||||
Name = "",
|
|
||||||
Path = "",
|
|
||||||
IsVisible = true,
|
|
||||||
Position = -1 // 让插件管理器分配位置
|
|
||||||
};
|
|
||||||
|
|
||||||
// 直接显示编辑对话框
|
|
||||||
EditLauncherItem(item, true);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"添加启动项时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"添加启动项时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 编辑应用按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnEdit_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (DgApps.SelectedItem is LauncherItem item)
|
|
||||||
{
|
|
||||||
EditLauncherItem(item, false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除应用按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnDelete_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (DgApps.SelectedItem is LauncherItem item)
|
|
||||||
{
|
|
||||||
// 确认删除
|
|
||||||
MessageBoxResult result = MessageBox.Show(
|
|
||||||
$"确定要删除 {item.Name} 吗?",
|
|
||||||
"删除确认",
|
|
||||||
MessageBoxButton.YesNo,
|
|
||||||
MessageBoxImage.Question);
|
|
||||||
|
|
||||||
if (result == MessageBoxResult.Yes)
|
|
||||||
{
|
|
||||||
// 从集合中移除
|
|
||||||
_plugin.LauncherItems.Remove(item);
|
|
||||||
|
|
||||||
// 保存配置
|
|
||||||
_plugin.SaveConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存设置按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnSave_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 保存配置
|
|
||||||
_plugin.SaveConfig();
|
|
||||||
|
|
||||||
// 如果插件已启用,重新加载启动台按钮
|
|
||||||
if (_plugin.IsEnabled)
|
|
||||||
{
|
|
||||||
_plugin.Disable();
|
|
||||||
_plugin.Enable();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 如果插件未启用,则启用它
|
|
||||||
_plugin.Enable();
|
|
||||||
|
|
||||||
// 通知PluginSettingsWindow刷新插件列表
|
|
||||||
var window = Window.GetWindow(this);
|
|
||||||
if (window is PluginSettingsWindow pluginSettingsWindow)
|
|
||||||
{
|
|
||||||
// 触发刷新
|
|
||||||
pluginSettingsWindow.RefreshPluginList();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageBox.Show("设置已保存并应用!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"保存设置时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"保存设置时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用项选择变更事件
|
|
||||||
/// </summary>
|
|
||||||
private void DgApps_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
UpdateButtonStates();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 编辑启动项
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">启动项</param>
|
|
||||||
/// <param name="isNew">是否为新建</param>
|
|
||||||
private void EditLauncherItem(LauncherItem item, bool isNew)
|
|
||||||
{
|
|
||||||
// 创建简单的编辑窗口
|
|
||||||
Window editWindow = new Window
|
|
||||||
{
|
|
||||||
Title = isNew ? "添加" : "编辑应用",
|
|
||||||
Width = 400,
|
|
||||||
Height = 200,
|
|
||||||
WindowStartupLocation = WindowStartupLocation.CenterScreen,
|
|
||||||
ResizeMode = ResizeMode.NoResize
|
|
||||||
};
|
|
||||||
|
|
||||||
// 创建编辑表单
|
|
||||||
Grid grid = new Grid
|
|
||||||
{
|
|
||||||
Margin = new Thickness(20)
|
|
||||||
};
|
|
||||||
|
|
||||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
|
||||||
grid.RowDefinitions.Add(new RowDefinition { Height = GridLength.Auto });
|
|
||||||
grid.RowDefinitions.Add(new RowDefinition { Height = new GridLength(1, GridUnitType.Star) });
|
|
||||||
|
|
||||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(80) });
|
|
||||||
grid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
|
||||||
|
|
||||||
// 名称输入框
|
|
||||||
TextBlock nameLabel = new TextBlock
|
|
||||||
{
|
|
||||||
Text = "名称:",
|
|
||||||
VerticalAlignment = VerticalAlignment.Center
|
|
||||||
};
|
|
||||||
TextBox nameTextBox = new TextBox
|
|
||||||
{
|
|
||||||
Text = item.Name,
|
|
||||||
Margin = new Thickness(0, 5, 0, 5)
|
|
||||||
};
|
|
||||||
|
|
||||||
Grid.SetRow(nameLabel, 0);
|
|
||||||
Grid.SetColumn(nameLabel, 0);
|
|
||||||
Grid.SetRow(nameTextBox, 0);
|
|
||||||
Grid.SetColumn(nameTextBox, 1);
|
|
||||||
|
|
||||||
grid.Children.Add(nameLabel);
|
|
||||||
grid.Children.Add(nameTextBox);
|
|
||||||
|
|
||||||
// 路径输入框
|
|
||||||
TextBlock pathLabel = new TextBlock
|
|
||||||
{
|
|
||||||
Text = "路径:",
|
|
||||||
VerticalAlignment = VerticalAlignment.Center
|
|
||||||
};
|
|
||||||
Grid pathGrid = new Grid();
|
|
||||||
pathGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength(1, GridUnitType.Star) });
|
|
||||||
pathGrid.ColumnDefinitions.Add(new ColumnDefinition { Width = new GridLength() });
|
|
||||||
|
|
||||||
TextBox pathTextBox = new TextBox
|
|
||||||
{
|
|
||||||
Text = item.Path,
|
|
||||||
Margin = new Thickness(0, 5, 5, 5)
|
|
||||||
};
|
|
||||||
Button browseButton = new Button
|
|
||||||
{
|
|
||||||
Content = "浏览",
|
|
||||||
Padding = new Thickness(5, 0, 5, 0),
|
|
||||||
Margin = new Thickness(0, 5, 0, 5)
|
|
||||||
};
|
|
||||||
|
|
||||||
browseButton.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
OpenFileDialog dialog = new OpenFileDialog
|
|
||||||
{
|
|
||||||
Title = "选择应用程序",
|
|
||||||
Filter = "应用程序 (*.exe)|*.exe|所有文件 (*.*)|*.*",
|
|
||||||
Multiselect = false,
|
|
||||||
FileName = pathTextBox.Text
|
|
||||||
};
|
|
||||||
|
|
||||||
if (dialog.ShowDialog() == true)
|
|
||||||
{
|
|
||||||
pathTextBox.Text = dialog.FileName;
|
|
||||||
|
|
||||||
// 如果选择的是.exe文件,自动获取文件名填入名称字段
|
|
||||||
if (Path.GetExtension(dialog.FileName).ToLower() == ".exe")
|
|
||||||
{
|
|
||||||
string fileName = Path.GetFileNameWithoutExtension(dialog.FileName);
|
|
||||||
// 只有在名称字段为空或者是新建项目时才自动填入
|
|
||||||
if (string.IsNullOrWhiteSpace(nameTextBox.Text) || isNew)
|
|
||||||
{
|
|
||||||
nameTextBox.Text = fileName;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
Grid.SetColumn(pathTextBox, 0);
|
|
||||||
Grid.SetColumn(browseButton, 1);
|
|
||||||
pathGrid.Children.Add(pathTextBox);
|
|
||||||
pathGrid.Children.Add(browseButton);
|
|
||||||
|
|
||||||
Grid.SetRow(pathLabel, 1);
|
|
||||||
Grid.SetColumn(pathLabel, 0);
|
|
||||||
Grid.SetRow(pathGrid, 1);
|
|
||||||
Grid.SetColumn(pathGrid, 1);
|
|
||||||
|
|
||||||
grid.Children.Add(pathLabel);
|
|
||||||
grid.Children.Add(pathGrid);
|
|
||||||
|
|
||||||
// 确认和取消按钮
|
|
||||||
StackPanel buttonPanel = new StackPanel
|
|
||||||
{
|
|
||||||
Orientation = Orientation.Horizontal,
|
|
||||||
HorizontalAlignment = HorizontalAlignment.Right,
|
|
||||||
Margin = new Thickness(0, 10, 0, 0)
|
|
||||||
};
|
|
||||||
|
|
||||||
Button okButton = new Button
|
|
||||||
{
|
|
||||||
Content = "确定",
|
|
||||||
Padding = new Thickness(15, 5, 15, 5),
|
|
||||||
Margin = new Thickness(0, 0, 10, 0),
|
|
||||||
IsDefault = true
|
|
||||||
};
|
|
||||||
|
|
||||||
Button cancelButton = new Button
|
|
||||||
{
|
|
||||||
Content = "取消",
|
|
||||||
Padding = new Thickness(15, 5, 15, 5),
|
|
||||||
IsCancel = true
|
|
||||||
};
|
|
||||||
|
|
||||||
okButton.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
// 验证输入
|
|
||||||
if (string.IsNullOrWhiteSpace(nameTextBox.Text))
|
|
||||||
{
|
|
||||||
MessageBox.Show("请输入应用名称!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrWhiteSpace(pathTextBox.Text))
|
|
||||||
{
|
|
||||||
MessageBox.Show("请输入应用路径!", "提示", MessageBoxButton.OK, MessageBoxImage.Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新项目
|
|
||||||
item.Name = nameTextBox.Text;
|
|
||||||
item.Path = pathTextBox.Text;
|
|
||||||
|
|
||||||
// 如果是新建,添加到集合
|
|
||||||
if (isNew)
|
|
||||||
{
|
|
||||||
_plugin.AddLauncherItem(item);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 触发属性变更通知,刷新DataGrid
|
|
||||||
if (DgApps.ItemsSource is ICollectionView view)
|
|
||||||
{
|
|
||||||
view.Refresh();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存配置
|
|
||||||
_plugin.SaveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
editWindow.DialogResult = true;
|
|
||||||
editWindow.Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
cancelButton.Click += (s, e) =>
|
|
||||||
{
|
|
||||||
editWindow.DialogResult = false;
|
|
||||||
editWindow.Close();
|
|
||||||
};
|
|
||||||
|
|
||||||
buttonPanel.Children.Add(okButton);
|
|
||||||
buttonPanel.Children.Add(cancelButton);
|
|
||||||
|
|
||||||
Grid.SetRow(buttonPanel, 2);
|
|
||||||
Grid.SetColumnSpan(buttonPanel, 2);
|
|
||||||
|
|
||||||
grid.Children.Add(buttonPanel);
|
|
||||||
|
|
||||||
// 设置窗口内容
|
|
||||||
editWindow.Content = grid;
|
|
||||||
|
|
||||||
// 显示窗口
|
|
||||||
editWindow.ShowDialog();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,91 +0,0 @@
|
|||||||
<Window x:Class="Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher.LauncherWindow"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:local="clr-namespace:Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="启动台"
|
|
||||||
Width="400"
|
|
||||||
Height="300"
|
|
||||||
WindowStyle="None"
|
|
||||||
AllowsTransparency="True"
|
|
||||||
Background="#80000000"
|
|
||||||
ResizeMode="NoResize"
|
|
||||||
Topmost="True"
|
|
||||||
Deactivated="Window_Deactivated"
|
|
||||||
ShowInTaskbar="False">
|
|
||||||
|
|
||||||
<Window.Resources>
|
|
||||||
<!-- 应用项样式 -->
|
|
||||||
<Style x:Key="LauncherItemStyle" TargetType="Button">
|
|
||||||
<Setter Property="Width" Value="80"/>
|
|
||||||
<Setter Property="Height" Value="80"/>
|
|
||||||
<Setter Property="Margin" Value="5"/>
|
|
||||||
<Setter Property="Background" Value="#40FFFFFF"/>
|
|
||||||
<Setter Property="Foreground" Value="White"/>
|
|
||||||
<Setter Property="BorderThickness" Value="0"/>
|
|
||||||
<Setter Property="Template">
|
|
||||||
<Setter.Value>
|
|
||||||
<ControlTemplate TargetType="Button">
|
|
||||||
<Border x:Name="border" Background="{TemplateBinding Background}"
|
|
||||||
BorderBrush="{TemplateBinding BorderBrush}"
|
|
||||||
BorderThickness="{TemplateBinding BorderThickness}"
|
|
||||||
CornerRadius="8">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Image Grid.Row="0" Source="{Binding Icon}" Width="32" Height="32" Margin="0,10,0,5"/>
|
|
||||||
<TextBlock Grid.Row="1" Text="{Binding Name}" TextWrapping="Wrap" TextAlignment="Center"
|
|
||||||
Margin="2,0,2,8" FontSize="11" Foreground="White"/>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
<ControlTemplate.Triggers>
|
|
||||||
<Trigger Property="IsMouseOver" Value="True">
|
|
||||||
<Setter Property="Background" Value="#80FFFFFF"/>
|
|
||||||
</Trigger>
|
|
||||||
<Trigger Property="IsPressed" Value="True">
|
|
||||||
<Setter Property="Background" Value="#C0FFFFFF"/>
|
|
||||||
</Trigger>
|
|
||||||
</ControlTemplate.Triggers>
|
|
||||||
</ControlTemplate>
|
|
||||||
</Setter.Value>
|
|
||||||
</Setter>
|
|
||||||
</Style>
|
|
||||||
</Window.Resources>
|
|
||||||
|
|
||||||
<Border CornerRadius="15" Background="#80000000" BorderThickness="1" BorderBrush="#40FFFFFF">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- 标题栏 -->
|
|
||||||
<Grid Grid.Row="0" Height="40">
|
|
||||||
<TextBlock Text="启动台" Foreground="White" FontSize="18" FontWeight="Bold"
|
|
||||||
VerticalAlignment="Center" Margin="15,0,0,0"/>
|
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Right" Margin="0,0,10,0">
|
|
||||||
<Button x:Name="BtnFixMode" Click="BtnFixMode_Click" Width="30" Height="30"
|
|
||||||
Margin="5,0" Background="Transparent" BorderThickness="0"
|
|
||||||
ToolTip="切换固定模式">
|
|
||||||
<Path x:Name="FixModeIcon" Data="M7,2V13H10V22L17,10H13L17,2H7Z" Fill="White" Stretch="Uniform" Width="16" Height="16"/>
|
|
||||||
</Button>
|
|
||||||
<Button x:Name="BtnClose" Click="BtnClose_Click" Width="30" Height="30"
|
|
||||||
Background="Transparent" BorderThickness="0"
|
|
||||||
ToolTip="关闭">
|
|
||||||
<Path Data="M19,6.41L17.59,5L12,10.59L6.41,5L5,6.41L10.59,12L5,17.59L6.41,19L12,13.41L17.59,19L19,17.59L13.41,12L19,6.41Z"
|
|
||||||
Fill="White" Stretch="Uniform" Width="16" Height="16"/>
|
|
||||||
</Button>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- 应用网格 -->
|
|
||||||
<ScrollViewer Grid.Row="1" Margin="10" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
|
||||||
<WrapPanel x:Name="AppPanel" Orientation="Horizontal" HorizontalAlignment="Center"/>
|
|
||||||
</ScrollViewer>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</Window>
|
|
||||||
@@ -1,466 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.Diagnostics;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Threading;
|
|
||||||
using System.Threading.Tasks;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Input;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Threading;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// LauncherWindow.xaml 的交互逻辑
|
|
||||||
/// </summary>
|
|
||||||
public partial class LauncherWindow : Window
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 父插件
|
|
||||||
/// </summary>
|
|
||||||
private readonly SuperLauncherPlugin _plugin;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否处于固定模式
|
|
||||||
/// </summary>
|
|
||||||
private bool _isFixMode;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用项按钮列表
|
|
||||||
/// </summary>
|
|
||||||
private readonly Dictionary<Button, LauncherItem> _appButtons = new Dictionary<Button, LauncherItem>();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 拖拽中的按钮
|
|
||||||
/// </summary>
|
|
||||||
private Button _draggingButton;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 拖拽开始位置
|
|
||||||
/// </summary>
|
|
||||||
private Point _dragStartPoint;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 构造函数
|
|
||||||
/// </summary>
|
|
||||||
public LauncherWindow(SuperLauncherPlugin plugin)
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
_plugin = plugin;
|
|
||||||
|
|
||||||
// 加载应用项
|
|
||||||
LoadLauncherItems();
|
|
||||||
|
|
||||||
// 添加鼠标按下事件(用于拖动窗口)
|
|
||||||
MouseDown += (s, e) =>
|
|
||||||
{
|
|
||||||
if (e.ChangedButton == MouseButton.Left && e.ButtonState == MouseButtonState.Pressed)
|
|
||||||
{
|
|
||||||
DragMove();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// 根据应用数量调整窗口大小
|
|
||||||
AdjustWindowSize();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载启动台应用项
|
|
||||||
/// </summary>
|
|
||||||
private void LoadLauncherItems()
|
|
||||||
{
|
|
||||||
// 清空现有应用项
|
|
||||||
AppPanel.Children.Clear();
|
|
||||||
_appButtons.Clear();
|
|
||||||
|
|
||||||
// 获取显示的应用项
|
|
||||||
var visibleItems = _plugin.LauncherItems
|
|
||||||
.Where(item => item.IsVisible)
|
|
||||||
.OrderBy(item => item.Position)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
foreach (var item in visibleItems)
|
|
||||||
{
|
|
||||||
// 创建应用按钮
|
|
||||||
Button appButton = new Button
|
|
||||||
{
|
|
||||||
Style = (Style)FindResource("LauncherItemStyle"),
|
|
||||||
DataContext = item,
|
|
||||||
Tag = item.Position
|
|
||||||
};
|
|
||||||
|
|
||||||
// 添加点击事件
|
|
||||||
appButton.Click += AppButton_Click;
|
|
||||||
|
|
||||||
// 在固定模式下,添加拖拽事件
|
|
||||||
appButton.PreviewMouseDown += AppButton_PreviewMouseDown;
|
|
||||||
appButton.PreviewMouseMove += AppButton_PreviewMouseMove;
|
|
||||||
appButton.PreviewMouseUp += AppButton_PreviewMouseUp;
|
|
||||||
|
|
||||||
// 记录按钮和项目的对应关系
|
|
||||||
_appButtons.Add(appButton, item);
|
|
||||||
|
|
||||||
// 添加到面板
|
|
||||||
AppPanel.Children.Add(appButton);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据应用数量调整窗口大小
|
|
||||||
/// </summary>
|
|
||||||
private void AdjustWindowSize()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 每行最多显示4个应用
|
|
||||||
const int appsPerRow = 4;
|
|
||||||
|
|
||||||
// 计算行数
|
|
||||||
int visibleCount = _appButtons.Count;
|
|
||||||
int rowCount = (int)Math.Ceiling(visibleCount / (double)appsPerRow);
|
|
||||||
|
|
||||||
// 设置窗口宽度(每个应用90像素宽 = 80 + 5*2)
|
|
||||||
Width = Math.Min(appsPerRow * 90 + 40, 400); // 最大宽度400
|
|
||||||
|
|
||||||
// 设置窗口高度(每个应用90像素高 = 80 + 5*2)
|
|
||||||
Height = Math.Min(rowCount * 90 + 60, 600); // 最大高度600,标题栏40 + 边距20
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"调整启动台窗口大小时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void AppButton_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_isFixMode) return; // 在固定模式下,不响应点击事件
|
|
||||||
|
|
||||||
if (sender is Button button && _appButtons.TryGetValue(button, out LauncherItem item))
|
|
||||||
{
|
|
||||||
// 获取应用路径和名称,用于后续启动
|
|
||||||
string appPath = item.Path;
|
|
||||||
string appName = item.Name;
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"点击启动应用: {appName}, 路径: {appPath}");
|
|
||||||
|
|
||||||
// 首先标记窗口正在关闭
|
|
||||||
IsClosing = true;
|
|
||||||
|
|
||||||
// 创建一个应用启动任务
|
|
||||||
var launchTask = new Task(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 等待一段时间,确保窗口关闭流程已经开始
|
|
||||||
Thread.Sleep(200);
|
|
||||||
|
|
||||||
// 使用UI线程启动应用
|
|
||||||
Application.Current.Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 检查应用路径是否存在
|
|
||||||
if (File.Exists(appPath) || !appPath.Contains(":\\"))
|
|
||||||
{
|
|
||||||
// 创建进程启动信息
|
|
||||||
var psi = new ProcessStartInfo
|
|
||||||
{
|
|
||||||
FileName = appPath,
|
|
||||||
UseShellExecute = true,
|
|
||||||
};
|
|
||||||
|
|
||||||
// 启动应用程序
|
|
||||||
var process = Process.Start(psi);
|
|
||||||
LogHelper.WriteLogToFile($"应用程序 {appName} 已启动");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"应用路径不存在: {appPath}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"找不到应用程序: {appPath}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"启动应用程序失败: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"启动应用程序失败: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"应用启动任务出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// 关闭窗口
|
|
||||||
try
|
|
||||||
{
|
|
||||||
Dispatcher.BeginInvoke(new Action(() =>
|
|
||||||
{
|
|
||||||
try { Close(); } catch (Exception ex) { System.Diagnostics.Debug.WriteLine(ex); }
|
|
||||||
|
|
||||||
// 启动应用程序任务
|
|
||||||
launchTask.Start();
|
|
||||||
}), DispatcherPriority.Background);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"关闭窗口或启动任务时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
// 如果无法通过UI关闭窗口,直接启动任务
|
|
||||||
launchTask.Start();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"应用按钮点击事件出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
try { IsClosing = true; Close(); } catch (Exception innerEx) { System.Diagnostics.Debug.WriteLine(innerEx); }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region 固定模式拖拽事件
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用按钮鼠标按下事件
|
|
||||||
/// </summary>
|
|
||||||
private void AppButton_PreviewMouseDown(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
if (!_isFixMode) return;
|
|
||||||
|
|
||||||
if (e.ChangedButton == MouseButton.Left && sender is Button button)
|
|
||||||
{
|
|
||||||
_draggingButton = button;
|
|
||||||
_dragStartPoint = e.GetPosition(AppPanel);
|
|
||||||
button.CaptureMouse();
|
|
||||||
button.Opacity = 0.7;
|
|
||||||
|
|
||||||
// 阻止事件冒泡,以避免触发按钮点击
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用按钮鼠标移动事件
|
|
||||||
/// </summary>
|
|
||||||
private void AppButton_PreviewMouseMove(object sender, MouseEventArgs e)
|
|
||||||
{
|
|
||||||
if (!_isFixMode || _draggingButton == null) return;
|
|
||||||
|
|
||||||
if (e.LeftButton == MouseButtonState.Pressed)
|
|
||||||
{
|
|
||||||
Point currentPosition = e.GetPosition(AppPanel);
|
|
||||||
|
|
||||||
// 移动按钮
|
|
||||||
System.Windows.Controls.Canvas.SetLeft(_draggingButton, currentPosition.X - _draggingButton.ActualWidth / 2);
|
|
||||||
System.Windows.Controls.Canvas.SetTop(_draggingButton, currentPosition.Y - _draggingButton.ActualHeight / 2);
|
|
||||||
|
|
||||||
// 将按钮移到最上层
|
|
||||||
Panel.SetZIndex(_draggingButton, 100);
|
|
||||||
|
|
||||||
// 阻止事件冒泡
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 应用按钮鼠标释放事件
|
|
||||||
/// </summary>
|
|
||||||
private void AppButton_PreviewMouseUp(object sender, MouseButtonEventArgs e)
|
|
||||||
{
|
|
||||||
if (!_isFixMode || _draggingButton == null) return;
|
|
||||||
|
|
||||||
// 释放鼠标捕获
|
|
||||||
_draggingButton.ReleaseMouseCapture();
|
|
||||||
|
|
||||||
// 计算新位置
|
|
||||||
Point releasePoint = e.GetPosition(AppPanel);
|
|
||||||
int newPosition = CalculateGridPosition(releasePoint);
|
|
||||||
|
|
||||||
// 获取当前项目
|
|
||||||
LauncherItem currentItem = _appButtons[_draggingButton];
|
|
||||||
|
|
||||||
// 重新排序
|
|
||||||
ReorderItems(currentItem, newPosition);
|
|
||||||
|
|
||||||
// 重新加载应用项
|
|
||||||
LoadLauncherItems();
|
|
||||||
|
|
||||||
// 保存配置
|
|
||||||
_plugin.SaveConfig();
|
|
||||||
|
|
||||||
// 清除拖拽状态
|
|
||||||
_draggingButton.Opacity = 1;
|
|
||||||
Panel.SetZIndex(_draggingButton, 0);
|
|
||||||
_draggingButton = null;
|
|
||||||
|
|
||||||
// 阻止事件冒泡
|
|
||||||
e.Handled = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 计算网格位置
|
|
||||||
/// </summary>
|
|
||||||
private int CalculateGridPosition(Point point)
|
|
||||||
{
|
|
||||||
// 计算行和列
|
|
||||||
int columnCount = 4; // 每行最多4个应用
|
|
||||||
int columnWidth = 90; // 应用宽度(包括边距)
|
|
||||||
int rowHeight = 90; // 应用高度(包括边距)
|
|
||||||
|
|
||||||
int column = (int)(point.X / columnWidth);
|
|
||||||
int row = (int)(point.Y / rowHeight);
|
|
||||||
|
|
||||||
// 确保在有效范围内
|
|
||||||
column = Math.Max(0, Math.Min(column, columnCount - 1));
|
|
||||||
row = Math.Max(0, row);
|
|
||||||
|
|
||||||
// 计算位置索引
|
|
||||||
return row * columnCount + column;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重新排序应用项
|
|
||||||
/// </summary>
|
|
||||||
private void ReorderItems(LauncherItem item, int newPosition)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 设置项目为固定位置
|
|
||||||
item.IsPositionFixed = true;
|
|
||||||
|
|
||||||
// 如果位置相同,无需调整
|
|
||||||
if (item.Position == newPosition)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取所有可见项目
|
|
||||||
var visibleItems = _plugin.LauncherItems
|
|
||||||
.Where(i => i.IsVisible)
|
|
||||||
.OrderBy(i => i.Position)
|
|
||||||
.ToList();
|
|
||||||
|
|
||||||
// 移除当前项目
|
|
||||||
visibleItems.Remove(item);
|
|
||||||
|
|
||||||
// 查找插入位置
|
|
||||||
int insertIndex = 0;
|
|
||||||
for (int i = 0; i < visibleItems.Count; i++)
|
|
||||||
{
|
|
||||||
if (visibleItems[i].Position >= newPosition)
|
|
||||||
{
|
|
||||||
insertIndex = i;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
insertIndex = i + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 插入项目
|
|
||||||
visibleItems.Insert(insertIndex, item);
|
|
||||||
|
|
||||||
// 重新分配位置
|
|
||||||
for (int i = 0; i < visibleItems.Count; i++)
|
|
||||||
{
|
|
||||||
visibleItems[i].Position = i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"重新排序应用项时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 窗口事件处理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 窗口失去焦点事件
|
|
||||||
/// </summary>
|
|
||||||
private void Window_Deactivated(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 只有在非固定模式、窗口已加载、未处于关闭状态且IsLoaded=true时关闭窗口
|
|
||||||
if (!_isFixMode && IsLoaded && !IsClosing)
|
|
||||||
{
|
|
||||||
// 标记为正在关闭
|
|
||||||
IsClosing = true;
|
|
||||||
|
|
||||||
// 使用Dispatcher.BeginInvoke而不是直接调用Close,避免冲突
|
|
||||||
Dispatcher.BeginInvoke(new Action(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 再次检查窗口状态
|
|
||||||
if (IsLoaded && !IsClosing)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"延迟关闭窗口时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}), DispatcherPriority.Background);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"窗口失去焦点关闭时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 窗口是否正在关闭
|
|
||||||
/// </summary>
|
|
||||||
private bool IsClosing { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重写OnClosing方法,标记窗口正在关闭
|
|
||||||
/// </summary>
|
|
||||||
protected override void OnClosing(CancelEventArgs e)
|
|
||||||
{
|
|
||||||
IsClosing = true;
|
|
||||||
base.OnClosing(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 关闭按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnClose_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
Close();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 固定模式按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnFixMode_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
// 切换固定模式
|
|
||||||
_isFixMode = !_isFixMode;
|
|
||||||
|
|
||||||
// 更新固定模式按钮图标颜色
|
|
||||||
FixModeIcon.Fill = _isFixMode ? Brushes.Yellow : Brushes.White;
|
|
||||||
|
|
||||||
// 显示提示
|
|
||||||
if (_isFixMode)
|
|
||||||
{
|
|
||||||
MessageBox.Show("已进入固定模式,您可以拖动应用图标调整位置。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,589 +0,0 @@
|
|||||||
using Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher;
|
|
||||||
using Newtonsoft.Json;
|
|
||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins.BuiltIn
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 超级启动台插件
|
|
||||||
/// </summary>
|
|
||||||
public class SuperLauncherPlugin : PluginBase
|
|
||||||
{
|
|
||||||
#region 插件基本信息
|
|
||||||
|
|
||||||
public override string Name => "超级启动台";
|
|
||||||
|
|
||||||
public override string Description => "在浮动栏添加一个启动台按钮,可快速启动常用应用程序。";
|
|
||||||
|
|
||||||
public override Version Version => new Version(1, 0, 1);
|
|
||||||
|
|
||||||
public override string Author => "ICC CE 团队";
|
|
||||||
|
|
||||||
public override bool IsBuiltIn => true;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 插件属性和字段
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台配置
|
|
||||||
/// </summary>
|
|
||||||
public LauncherConfig Config { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台应用程序列表
|
|
||||||
/// </summary>
|
|
||||||
public ObservableCollection<LauncherItem> LauncherItems { get; private set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台按钮
|
|
||||||
/// </summary>
|
|
||||||
private LauncherButton _launcherButton;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启动台窗口
|
|
||||||
/// </summary>
|
|
||||||
private LauncherWindow _launcherWindow;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 配置文件路径
|
|
||||||
/// </summary>
|
|
||||||
private readonly string _configPath = Path.Combine(App.RootPath, "PluginConfigs", "SuperLauncher.json");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 标记是否已添加到浮动栏
|
|
||||||
/// </summary>
|
|
||||||
private bool _isAddedToFloatingBar;
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 插件生命周期
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
// 创建配置目录
|
|
||||||
string configDir = Path.Combine(App.RootPath, "PluginConfigs");
|
|
||||||
if (!Directory.Exists(configDir))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(configDir);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载配置
|
|
||||||
LoadConfig();
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile("超级启动台插件已初始化");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"初始化超级启动台插件时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Enable()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (IsEnabled) return; // 防止重复启用
|
|
||||||
|
|
||||||
// 创建启动台按钮
|
|
||||||
if (_launcherButton == null)
|
|
||||||
{
|
|
||||||
_launcherButton = new LauncherButton(this);
|
|
||||||
LogHelper.WriteLogToFile("超级启动台按钮已创建");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加启动台按钮到浮动栏
|
|
||||||
AddLauncherButtonToFloatingBar();
|
|
||||||
|
|
||||||
// 设置启用状态
|
|
||||||
base.Enable();
|
|
||||||
|
|
||||||
// 保存插件配置
|
|
||||||
SavePluginSettings();
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile("超级启动台插件已启用");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"启用超级启动台插件时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Disable()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!IsEnabled) return; // 防止重复禁用
|
|
||||||
|
|
||||||
// 从浮动栏移除启动台按钮
|
|
||||||
RemoveLauncherButtonFromFloatingBar();
|
|
||||||
|
|
||||||
// 如果启动台窗口打开,则关闭
|
|
||||||
if (_launcherWindow != null && _launcherWindow.IsVisible)
|
|
||||||
{
|
|
||||||
_launcherWindow.Close();
|
|
||||||
_launcherWindow = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 设置禁用状态
|
|
||||||
base.Disable();
|
|
||||||
|
|
||||||
// 保存插件配置
|
|
||||||
SavePluginSettings();
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile("超级启动台插件已禁用");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"禁用超级启动台插件时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override UserControl GetSettingsView()
|
|
||||||
{
|
|
||||||
return new LauncherSettingsControl(this);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Cleanup()
|
|
||||||
{
|
|
||||||
// 保存配置
|
|
||||||
SaveConfig();
|
|
||||||
|
|
||||||
// 从浮动栏移除启动台按钮
|
|
||||||
RemoveLauncherButtonFromFloatingBar();
|
|
||||||
|
|
||||||
// 如果启动台窗口打开,则关闭
|
|
||||||
if (_launcherWindow != null && _launcherWindow.IsVisible)
|
|
||||||
{
|
|
||||||
_launcherWindow.Close();
|
|
||||||
_launcherWindow = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Cleanup();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存插件设置
|
|
||||||
/// </summary>
|
|
||||||
public override void SavePluginSettings()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 确保配置已加载
|
|
||||||
if (Config == null)
|
|
||||||
{
|
|
||||||
LoadConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 更新其他设置,但不更改插件启用状态
|
|
||||||
|
|
||||||
// 保存配置
|
|
||||||
SaveConfig();
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile("超级启动台插件设置已保存");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"保存超级启动台插件设置时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 配置管理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载配置
|
|
||||||
/// </summary>
|
|
||||||
private void LoadConfig()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (File.Exists(_configPath))
|
|
||||||
{
|
|
||||||
string json = File.ReadAllText(_configPath);
|
|
||||||
Config = JsonConvert.DeserializeObject<LauncherConfig>(json) ?? CreateDefaultConfig();
|
|
||||||
LauncherItems = new ObservableCollection<LauncherItem>(Config.Items ?? new List<LauncherItem>());
|
|
||||||
|
|
||||||
// 注意:不再根据配置更改插件启用状态
|
|
||||||
// 插件状态由PluginManager统一管理
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Config = CreateDefaultConfig();
|
|
||||||
LauncherItems = new ObservableCollection<LauncherItem>(Config.Items);
|
|
||||||
SaveConfig();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"加载超级启动台配置时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
Config = CreateDefaultConfig();
|
|
||||||
LauncherItems = new ObservableCollection<LauncherItem>(Config.Items);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存配置
|
|
||||||
/// </summary>
|
|
||||||
public void SaveConfig()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 同步LauncherItems到Config
|
|
||||||
Config.Items = new List<LauncherItem>(LauncherItems);
|
|
||||||
|
|
||||||
// 序列化并保存配置
|
|
||||||
string json = JsonConvert.SerializeObject(Config, Formatting.Indented);
|
|
||||||
File.WriteAllText(_configPath, json);
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile("超级启动台配置已保存");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"保存超级启动台配置时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建默认配置
|
|
||||||
/// </summary>
|
|
||||||
private LauncherConfig CreateDefaultConfig()
|
|
||||||
{
|
|
||||||
var config = new LauncherConfig
|
|
||||||
{
|
|
||||||
ButtonPosition = LauncherButtonPosition.Right,
|
|
||||||
// 不再使用IsEnabled,插件状态由PluginManager管理
|
|
||||||
Items = new List<LauncherItem>
|
|
||||||
{
|
|
||||||
new LauncherItem
|
|
||||||
{
|
|
||||||
Name = "资源管理器",
|
|
||||||
Path = @"C:\Windows\explorer.exe",
|
|
||||||
IsVisible = true,
|
|
||||||
Position = 0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return config;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 启动台按钮管理
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 将启动台按钮添加到浮动栏
|
|
||||||
/// </summary>
|
|
||||||
private void AddLauncherButtonToFloatingBar()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 如果已经添加,先移除
|
|
||||||
if (_isAddedToFloatingBar)
|
|
||||||
{
|
|
||||||
RemoveLauncherButtonFromFloatingBar();
|
|
||||||
_isAddedToFloatingBar = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取主窗口实例
|
|
||||||
var mainWindow = Application.Current.MainWindow;
|
|
||||||
if (mainWindow == null)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile("未找到主窗口实例,无法添加启动台按钮", LogHelper.LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建启动台按钮
|
|
||||||
_launcherButton = new LauncherButton(this);
|
|
||||||
var buttonElement = _launcherButton.Element;
|
|
||||||
|
|
||||||
// 查找浮动栏
|
|
||||||
var floatingBar = mainWindow.FindName("StackPanelFloatingBar") as Panel;
|
|
||||||
if (floatingBar == null)
|
|
||||||
{
|
|
||||||
// 如果直接查找失败,则尝试遍历可视树查找
|
|
||||||
Panel floatingBarPanelFromTree = null;
|
|
||||||
FindStackPanelFloatingBar(mainWindow, ref floatingBarPanelFromTree);
|
|
||||||
floatingBar = floatingBarPanelFromTree;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (floatingBar == null)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile("未找到浮动栏,无法添加启动台按钮", LogHelper.LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加启动台按钮到浮动栏
|
|
||||||
if (Config.ButtonPosition == LauncherButtonPosition.Left)
|
|
||||||
{
|
|
||||||
floatingBar.Children.Insert(0, buttonElement);
|
|
||||||
LogHelper.WriteLogToFile("启动台按钮已添加到浮动栏左侧");
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
floatingBar.Children.Add(buttonElement);
|
|
||||||
LogHelper.WriteLogToFile("启动台按钮已添加到浮动栏右侧");
|
|
||||||
}
|
|
||||||
|
|
||||||
_isAddedToFloatingBar = true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"添加启动台按钮到浮动栏时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 递归查找StackPanelFloatingBar
|
|
||||||
/// </summary>
|
|
||||||
private void FindStackPanelFloatingBar(DependencyObject parent, ref Panel result)
|
|
||||||
{
|
|
||||||
if (parent == null || result != null) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 检查当前对象是否为我们要找的面板
|
|
||||||
if (parent is Panel panel && panel.Name == "StackPanelFloatingBar")
|
|
||||||
{
|
|
||||||
result = panel;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取子元素数量
|
|
||||||
int childCount = VisualTreeHelper.GetChildrenCount(parent);
|
|
||||||
|
|
||||||
// 遍历所有子元素
|
|
||||||
for (int i = 0; i < childCount; i++)
|
|
||||||
{
|
|
||||||
DependencyObject child = VisualTreeHelper.GetChild(parent, i);
|
|
||||||
FindStackPanelFloatingBar(child, ref result);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"查找StackPanelFloatingBar时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从浮动栏移除启动台按钮
|
|
||||||
/// </summary>
|
|
||||||
private void RemoveLauncherButtonFromFloatingBar()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (!_isAddedToFloatingBar || _launcherButton == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取主窗口实例
|
|
||||||
var mainWindow = Application.Current.MainWindow;
|
|
||||||
if (mainWindow == null)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile("未找到主窗口实例,无法移除启动台按钮", LogHelper.LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取按钮元素
|
|
||||||
var buttonElement = _launcherButton.Element;
|
|
||||||
|
|
||||||
// 查找浮动栏
|
|
||||||
var floatingBar = mainWindow.FindName("StackPanelFloatingBar") as Panel;
|
|
||||||
if (floatingBar == null)
|
|
||||||
{
|
|
||||||
// 如果直接查找失败,则尝试遍历可视树查找
|
|
||||||
Panel floatingBarPanelFromTree = null;
|
|
||||||
FindStackPanelFloatingBar(mainWindow, ref floatingBarPanelFromTree);
|
|
||||||
floatingBar = floatingBarPanelFromTree;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (floatingBar == null)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile("未找到浮动栏,无法移除启动台按钮", LogHelper.LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 从浮动栏移除启动台按钮
|
|
||||||
if (floatingBar.Children.Contains(buttonElement))
|
|
||||||
{
|
|
||||||
floatingBar.Children.Remove(buttonElement);
|
|
||||||
LogHelper.WriteLogToFile("启动台按钮已从浮动栏移除");
|
|
||||||
}
|
|
||||||
|
|
||||||
_isAddedToFloatingBar = false;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"移除启动台按钮时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新启动台按钮位置
|
|
||||||
/// </summary>
|
|
||||||
public void UpdateButtonPosition()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 如果按钮已添加到浮动栏,重新添加以更新位置
|
|
||||||
if (_isAddedToFloatingBar)
|
|
||||||
{
|
|
||||||
RemoveLauncherButtonFromFloatingBar();
|
|
||||||
AddLauncherButtonToFloatingBar();
|
|
||||||
LogHelper.WriteLogToFile($"启动台按钮位置已更新为: {Config.ButtonPosition}");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"更新启动台按钮位置时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
LogHelper.NewLog(ex);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 启动台功能
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示启动台窗口
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="buttonPosition">按钮在屏幕上的位置</param>
|
|
||||||
public void ShowLauncherWindow(Point buttonPosition)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 如果窗口已存在,关闭它
|
|
||||||
if (_launcherWindow != null && _launcherWindow.IsVisible)
|
|
||||||
{
|
|
||||||
_launcherWindow.Close();
|
|
||||||
_launcherWindow = null;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建新的启动台窗口
|
|
||||||
_launcherWindow = new LauncherWindow(this);
|
|
||||||
|
|
||||||
// 计算窗口位置,使其位于按钮上方
|
|
||||||
PositionLauncherWindow(_launcherWindow, buttonPosition);
|
|
||||||
|
|
||||||
// 显示窗口
|
|
||||||
_launcherWindow.Show();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"显示启动台窗口时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置启动台窗口位置
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="window">启动台窗口</param>
|
|
||||||
/// <param name="buttonPosition">按钮在屏幕上的位置</param>
|
|
||||||
private void PositionLauncherWindow(LauncherWindow window, Point buttonPosition)
|
|
||||||
{
|
|
||||||
// 确保窗口已加载
|
|
||||||
if (window.ActualWidth == 0 || window.ActualHeight == 0)
|
|
||||||
{
|
|
||||||
window.WindowStartupLocation = WindowStartupLocation.CenterScreen;
|
|
||||||
|
|
||||||
// 设置窗口加载完成后的位置
|
|
||||||
window.Loaded += (s, e) =>
|
|
||||||
{
|
|
||||||
// 窗口位于按钮上方居中
|
|
||||||
double left = buttonPosition.X - (window.ActualWidth / 2);
|
|
||||||
double top = buttonPosition.Y - window.ActualHeight - 10; // 在按钮上方留出一些间距
|
|
||||||
|
|
||||||
// 确保窗口在屏幕内
|
|
||||||
left = Math.Max(0, Math.Min(left, SystemParameters.WorkArea.Width - window.ActualWidth));
|
|
||||||
top = Math.Max(0, Math.Min(top, SystemParameters.WorkArea.Height - window.ActualHeight));
|
|
||||||
|
|
||||||
window.Left = left;
|
|
||||||
window.Top = top;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// 窗口位于按钮上方居中
|
|
||||||
double left = buttonPosition.X - (window.ActualWidth / 2);
|
|
||||||
double top = buttonPosition.Y - window.ActualHeight - 10; // 在按钮上方留出一些间距
|
|
||||||
|
|
||||||
// 确保窗口在屏幕内
|
|
||||||
left = Math.Max(0, Math.Min(left, SystemParameters.WorkArea.Width - window.ActualWidth));
|
|
||||||
top = Math.Max(0, Math.Min(top, SystemParameters.WorkArea.Height - window.ActualHeight));
|
|
||||||
|
|
||||||
window.Left = left;
|
|
||||||
window.Top = top;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加应用到启动台
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="item">启动台项</param>
|
|
||||||
public void AddLauncherItem(LauncherItem item)
|
|
||||||
{
|
|
||||||
// 如果项目数量已达上限,则不添加
|
|
||||||
if (LauncherItems.Count >= 40)
|
|
||||||
{
|
|
||||||
MessageBox.Show("启动台项目数量已达上限(40个)!", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 寻找合适的位置
|
|
||||||
if (item.Position < 0)
|
|
||||||
{
|
|
||||||
item.Position = FindNextAvailablePosition();
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加项目并保存配置
|
|
||||||
LauncherItems.Add(item);
|
|
||||||
SaveConfig();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 查找下一个可用位置
|
|
||||||
/// </summary>
|
|
||||||
private int FindNextAvailablePosition()
|
|
||||||
{
|
|
||||||
// 获取已使用的位置列表
|
|
||||||
var usedPositions = new HashSet<int>();
|
|
||||||
foreach (var item in LauncherItems)
|
|
||||||
{
|
|
||||||
usedPositions.Add(item.Position);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 查找第一个可用位置
|
|
||||||
for (int i = 0; i < 40; i++)
|
|
||||||
{
|
|
||||||
if (!usedPositions.Contains(i))
|
|
||||||
{
|
|
||||||
return i;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果所有位置都已使用,则返回0
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,296 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 操作服务接口,统一所有执行操作相关的方法
|
|
||||||
/// </summary>
|
|
||||||
public interface IActionService
|
|
||||||
{
|
|
||||||
#region 画布操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清除当前画布
|
|
||||||
/// </summary>
|
|
||||||
void ClearCanvas();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清除所有画布
|
|
||||||
/// </summary>
|
|
||||||
void ClearAllCanvases();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加新页面
|
|
||||||
/// </summary>
|
|
||||||
void AddNewPage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除当前页面
|
|
||||||
/// </summary>
|
|
||||||
void DeleteCurrentPage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 切换到指定页面
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pageIndex">页面索引</param>
|
|
||||||
void SwitchToPage(int pageIndex);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 切换到下一页
|
|
||||||
/// </summary>
|
|
||||||
void NextPage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 切换到上一页
|
|
||||||
/// </summary>
|
|
||||||
void PreviousPage();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 绘制操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置绘制模式
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mode">绘制模式</param>
|
|
||||||
void SetDrawingMode(int mode);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置笔触宽度
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">宽度</param>
|
|
||||||
void SetInkWidth(double width);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置笔触颜色
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">颜色</param>
|
|
||||||
void SetInkColor(Color color);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置高亮笔宽度
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">宽度</param>
|
|
||||||
void SetHighlighterWidth(double width);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置橡皮擦大小
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="size">大小</param>
|
|
||||||
void SetEraserSize(int size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置橡皮擦类型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">类型</param>
|
|
||||||
void SetEraserType(int type);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置橡皮擦形状
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="shape">形状</param>
|
|
||||||
void SetEraserShape(int shape);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置笔触透明度
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">透明度</param>
|
|
||||||
void SetInkAlpha(double alpha);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置笔触样式
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="style">样式</param>
|
|
||||||
void SetInkStyle(int style);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置背景颜色
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">颜色</param>
|
|
||||||
void SetBackgroundColor(string color);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 文件操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存画布内容
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
void SaveCanvas(string filePath);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载画布内容
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
void LoadCanvas(string filePath);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导出为图片
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
/// <param name="format">图片格式</param>
|
|
||||||
void ExportAsImage(string filePath, string format);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导出为PDF
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
void ExportAsPDF(string filePath);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 撤销重做操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 撤销操作
|
|
||||||
/// </summary>
|
|
||||||
void Undo();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重做操作
|
|
||||||
/// </summary>
|
|
||||||
void Redo();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 选择操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 全选
|
|
||||||
/// </summary>
|
|
||||||
void SelectAll();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 取消选择
|
|
||||||
/// </summary>
|
|
||||||
void DeselectAll();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除选中内容
|
|
||||||
/// </summary>
|
|
||||||
void DeleteSelected();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 复制选中内容
|
|
||||||
/// </summary>
|
|
||||||
void CopySelected();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 剪切选中内容
|
|
||||||
/// </summary>
|
|
||||||
void CutSelected();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 粘贴内容
|
|
||||||
/// </summary>
|
|
||||||
void Paste();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 系统设置操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置系统设置
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">设置类型</typeparam>
|
|
||||||
/// <param name="key">设置键</param>
|
|
||||||
/// <param name="value">设置值</param>
|
|
||||||
void SetSetting<T>(string key, T value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存设置到文件
|
|
||||||
/// </summary>
|
|
||||||
void SaveSettings();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 从文件加载设置
|
|
||||||
/// </summary>
|
|
||||||
void LoadSettings();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重置设置为默认值
|
|
||||||
/// </summary>
|
|
||||||
void ResetSettings();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 插件管理操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
void EnablePlugin(string pluginName);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 禁用插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
void DisablePlugin(string pluginName);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 卸载插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
void UnloadPlugin(string pluginName);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 事件系统操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册事件处理器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="handler">事件处理器</param>
|
|
||||||
void RegisterEventHandler(string eventName, EventHandler handler);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注销事件处理器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="handler">事件处理器</param>
|
|
||||||
void UnregisterEventHandler(string eventName, EventHandler handler);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 触发事件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="sender">事件发送者</param>
|
|
||||||
/// <param name="args">事件参数</param>
|
|
||||||
void TriggerEvent(string eventName, object sender, EventArgs args);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 应用程序操作
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重启应用程序
|
|
||||||
/// </summary>
|
|
||||||
void RestartApplication();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 退出应用程序
|
|
||||||
/// </summary>
|
|
||||||
void ExitApplication();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检查更新
|
|
||||||
/// </summary>
|
|
||||||
void CheckForUpdates();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 打开帮助文档
|
|
||||||
/// </summary>
|
|
||||||
void OpenHelpDocument();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 打开关于页面
|
|
||||||
/// </summary>
|
|
||||||
void OpenAboutPage();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,180 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.IO;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// ICCPP 插件适配器,用于加载和管理 .iccpp 格式的插件
|
|
||||||
/// </summary>
|
|
||||||
public class ICCPPPluginAdapter : PluginBase
|
|
||||||
{
|
|
||||||
private readonly byte[] _pluginData;
|
|
||||||
private readonly string _pluginPath;
|
|
||||||
private readonly string _pluginName;
|
|
||||||
private readonly Version _pluginVersion;
|
|
||||||
private bool _isInitialized;
|
|
||||||
|
|
||||||
public override string PluginStateKey => "ICCPP:" + (_pluginPath ?? string.Empty);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 创建 ICCPP 插件适配器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginPath">插件文件路径</param>
|
|
||||||
/// <param name="pluginData">插件文件数据</param>
|
|
||||||
public ICCPPPluginAdapter(string pluginPath, byte[] pluginData)
|
|
||||||
{
|
|
||||||
_pluginPath = pluginPath;
|
|
||||||
_pluginData = pluginData;
|
|
||||||
PluginPath = pluginPath;
|
|
||||||
|
|
||||||
// 从文件名获取插件名称
|
|
||||||
_pluginName = Path.GetFileNameWithoutExtension(pluginPath);
|
|
||||||
_pluginVersion = new Version(1, 0, 0); // 默认版本
|
|
||||||
|
|
||||||
// 尝试从插件数据中读取更多信息
|
|
||||||
TryReadPluginMetadata();
|
|
||||||
}
|
|
||||||
|
|
||||||
public ICCPPPluginAdapter()
|
|
||||||
{
|
|
||||||
_pluginPath = string.Empty;
|
|
||||||
_pluginData = new byte[0];
|
|
||||||
PluginPath = string.Empty;
|
|
||||||
_pluginName = "ICCPPPlugin";
|
|
||||||
_pluginVersion = new Version(1, 0, 0);
|
|
||||||
// 可选:初始化其他字段
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 尝试从插件数据中读取元数据
|
|
||||||
/// </summary>
|
|
||||||
private void TryReadPluginMetadata()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 这里可以根据 .iccpp 文件的实际格式解析元数据
|
|
||||||
// 例如,如果文件有特定的头部结构,可以在这里解析
|
|
||||||
|
|
||||||
// 示例:如果前100字节包含元数据
|
|
||||||
if (_pluginData.Length > 100)
|
|
||||||
{
|
|
||||||
// 解析元数据的代码...
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"解析插件 {_pluginName} 元数据时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#region IPlugin 接口实现
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件名称
|
|
||||||
/// </summary>
|
|
||||||
public override string Name => _pluginName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件描述
|
|
||||||
/// </summary>
|
|
||||||
public override string Description => $"{_pluginName} (ICCPP 格式插件)";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件版本
|
|
||||||
/// </summary>
|
|
||||||
public override Version Version => _pluginVersion;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件作者
|
|
||||||
/// </summary>
|
|
||||||
public override string Author => "未知";
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为内置插件
|
|
||||||
/// </summary>
|
|
||||||
public override bool IsBuiltIn => false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 初始化插件
|
|
||||||
/// </summary>
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
if (_isInitialized) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 这里可以添加 .iccpp 插件的初始化逻辑
|
|
||||||
// 例如,根据文件格式加载特定资源
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已初始化");
|
|
||||||
_isInitialized = true;
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"初始化 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用插件
|
|
||||||
/// </summary>
|
|
||||||
public override void Enable()
|
|
||||||
{
|
|
||||||
if (IsEnabled) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 这里可以添加 .iccpp 插件的启用逻辑
|
|
||||||
// 例如,加载动态库、注册事件等
|
|
||||||
|
|
||||||
base.Enable(); // 设置启用状态并触发事件
|
|
||||||
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已启用");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"启用 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 禁用插件
|
|
||||||
/// </summary>
|
|
||||||
public override void Disable()
|
|
||||||
{
|
|
||||||
if (!IsEnabled) return;
|
|
||||||
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 这里可以添加 .iccpp 插件的禁用逻辑
|
|
||||||
// 例如,卸载动态库、注销事件等
|
|
||||||
|
|
||||||
base.Disable(); // 设置禁用状态并触发事件
|
|
||||||
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已禁用");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"禁用 ICCPP 插件 {Name} 时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清理插件资源
|
|
||||||
/// </summary>
|
|
||||||
public override void Cleanup()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 这里可以添加 .iccpp 插件的清理逻辑
|
|
||||||
// 例如,释放资源等
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"ICCPP 插件 {Name} 已清理资源");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"清理 ICCPP 插件 {Name} 资源时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,214 +0,0 @@
|
|||||||
using System.Collections.Generic;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 获取服务接口,统一所有获取类的方法
|
|
||||||
/// </summary>
|
|
||||||
public interface IGetService
|
|
||||||
{
|
|
||||||
#region 窗口和UI获取
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取主窗口引用
|
|
||||||
/// </summary>
|
|
||||||
Window MainWindow { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前画布
|
|
||||||
/// </summary>
|
|
||||||
global::System.Windows.Controls.InkCanvas CurrentCanvas { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取所有画布页面
|
|
||||||
/// </summary>
|
|
||||||
List<global::System.Windows.Controls.Canvas> AllCanvasPages { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前页面索引
|
|
||||||
/// </summary>
|
|
||||||
int CurrentPageIndex { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前页面数量
|
|
||||||
/// </summary>
|
|
||||||
int TotalPageCount { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取浮动工具栏
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement FloatingToolBar { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取左侧面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement LeftPanel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取右侧面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement RightPanel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取顶部面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement TopPanel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取底部面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement BottomPanel { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 绘制工具状态获取
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前绘制模式
|
|
||||||
/// </summary>
|
|
||||||
int CurrentDrawingMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前笔触宽度
|
|
||||||
/// </summary>
|
|
||||||
double CurrentInkWidth { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前笔触颜色
|
|
||||||
/// </summary>
|
|
||||||
Color CurrentInkColor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前高亮笔宽度
|
|
||||||
/// </summary>
|
|
||||||
double CurrentHighlighterWidth { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前橡皮擦大小
|
|
||||||
/// </summary>
|
|
||||||
int CurrentEraserSize { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前橡皮擦类型
|
|
||||||
/// </summary>
|
|
||||||
int CurrentEraserType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前橡皮擦形状
|
|
||||||
/// </summary>
|
|
||||||
int CurrentEraserShape { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前笔触透明度
|
|
||||||
/// </summary>
|
|
||||||
double CurrentInkAlpha { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前笔触样式
|
|
||||||
/// </summary>
|
|
||||||
int CurrentInkStyle { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前背景颜色
|
|
||||||
/// </summary>
|
|
||||||
string CurrentBackgroundColor { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 应用状态获取
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前主题模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsDarkTheme { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为白板模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsWhiteboardMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为PPT模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsPPTMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为全屏模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsFullScreenMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为画板模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsCanvasMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为选择模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsSelectionMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为擦除模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsEraserMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为形状绘制模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsShapeDrawingMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取当前是否为高亮模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsHighlighterMode { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 撤销重做状态获取
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取是否可以撤销
|
|
||||||
/// </summary>
|
|
||||||
bool CanUndo { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取是否可以重做
|
|
||||||
/// </summary>
|
|
||||||
bool CanRedo { get; }
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 系统设置获取
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取系统设置
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">设置类型</typeparam>
|
|
||||||
/// <param name="key">设置键</param>
|
|
||||||
/// <param name="defaultValue">默认值</param>
|
|
||||||
/// <returns>设置值</returns>
|
|
||||||
T GetSetting<T>(string key, T defaultValue = default(T));
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 插件信息获取
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取所有已加载的插件
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>插件列表</returns>
|
|
||||||
List<IPlugin> GetAllPlugins();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取指定插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
/// <returns>插件实例</returns>
|
|
||||||
IPlugin GetPlugin(string pluginName);
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,67 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 定义插件的基本接口
|
|
||||||
/// </summary>
|
|
||||||
public interface IPlugin
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 插件名称
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件描述
|
|
||||||
/// </summary>
|
|
||||||
string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件版本
|
|
||||||
/// </summary>
|
|
||||||
Version Version { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件作者
|
|
||||||
/// </summary>
|
|
||||||
string Author { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为内置插件
|
|
||||||
/// </summary>
|
|
||||||
bool IsBuiltIn { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 初始化插件
|
|
||||||
/// 此方法在插件加载时被调用,用于执行一些初始化工作
|
|
||||||
/// </summary>
|
|
||||||
void Initialize();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用插件
|
|
||||||
/// 此方法在插件被用户或系统启用时调用,激活插件功能
|
|
||||||
/// </summary>
|
|
||||||
void Enable();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 禁用插件
|
|
||||||
/// 此方法在插件被用户或系统禁用时调用,停用插件功能
|
|
||||||
/// </summary>
|
|
||||||
void Disable();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件设置界面
|
|
||||||
/// 此方法返回插件的设置界面控件,用于展示在设置窗口
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>插件设置界面</returns>
|
|
||||||
UserControl GetSettingsView();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件卸载时的清理工作
|
|
||||||
/// 此方法在插件被卸载前调用,用于释放资源和执行清理
|
|
||||||
/// </summary>
|
|
||||||
void Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,38 +0,0 @@
|
|||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 插件服务接口,提供对软件内部功能的访问
|
|
||||||
/// 继承自三个专门的服务接口:获取服务、窗口服务、操作服务
|
|
||||||
/// </summary>
|
|
||||||
public interface IPluginService : IGetService, IWindowService, IActionService
|
|
||||||
{
|
|
||||||
// 这个接口现在继承自三个专门的服务接口
|
|
||||||
// 所有方法都在子接口中定义,这里不需要重复定义
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 通知类型枚举
|
|
||||||
/// </summary>
|
|
||||||
public enum NotificationType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 信息
|
|
||||||
/// </summary>
|
|
||||||
Info,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 成功
|
|
||||||
/// </summary>
|
|
||||||
Success,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 警告
|
|
||||||
/// </summary>
|
|
||||||
Warning,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 错误
|
|
||||||
/// </summary>
|
|
||||||
Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,152 +0,0 @@
|
|||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 窗口服务接口,统一所有窗口操作相关的方法
|
|
||||||
/// </summary>
|
|
||||||
public interface IWindowService
|
|
||||||
{
|
|
||||||
#region 窗口显示和隐藏
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void HideSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示插件设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowPluginSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏插件设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void HidePluginSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示帮助窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowHelpWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏帮助窗口
|
|
||||||
/// </summary>
|
|
||||||
void HideHelpWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示关于窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowAboutWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏关于窗口
|
|
||||||
/// </summary>
|
|
||||||
void HideAboutWindow();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 对话框和通知
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示通知消息
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">消息内容</param>
|
|
||||||
/// <param name="type">消息类型</param>
|
|
||||||
void ShowNotification(string message, NotificationType type = NotificationType.Info);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示确认对话框
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">消息内容</param>
|
|
||||||
/// <param name="title">标题</param>
|
|
||||||
/// <returns>用户选择结果</returns>
|
|
||||||
bool ShowConfirmDialog(string message, string title = "确认");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示输入对话框
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">提示消息</param>
|
|
||||||
/// <param name="title">标题</param>
|
|
||||||
/// <param name="defaultValue">默认值</param>
|
|
||||||
/// <returns>用户输入内容</returns>
|
|
||||||
string ShowInputDialog(string message, string title = "输入", string defaultValue = "");
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 窗口状态控制
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口全屏状态
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isFullScreen">是否全屏</param>
|
|
||||||
void SetFullScreen(bool isFullScreen);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口置顶状态
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isTopMost">是否置顶</param>
|
|
||||||
void SetTopMost(bool isTopMost);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口可见性
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isVisible">是否可见</param>
|
|
||||||
void SetWindowVisibility(bool isVisible);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 最小化窗口
|
|
||||||
/// </summary>
|
|
||||||
void MinimizeWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 最大化窗口
|
|
||||||
/// </summary>
|
|
||||||
void MaximizeWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 恢复窗口
|
|
||||||
/// </summary>
|
|
||||||
void RestoreWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 关闭窗口
|
|
||||||
/// </summary>
|
|
||||||
void CloseWindow();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
|
|
||||||
#region 窗口位置和大小
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口位置
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">X坐标</param>
|
|
||||||
/// <param name="y">Y坐标</param>
|
|
||||||
void SetWindowPosition(double x, double y);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口大小
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">宽度</param>
|
|
||||||
/// <param name="height">高度</param>
|
|
||||||
void SetWindowSize(double width, double height);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取窗口位置
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>窗口位置</returns>
|
|
||||||
(double x, double y) GetWindowPosition();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取窗口大小
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>窗口大小</returns>
|
|
||||||
(double width, double height) GetWindowSize();
|
|
||||||
|
|
||||||
#endregion
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,166 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 插件基类,提供基本实现
|
|
||||||
/// </summary>
|
|
||||||
public abstract class PluginBase : IPlugin
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 插件状态(私有字段)
|
|
||||||
/// </summary>
|
|
||||||
private bool _isEnabled;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件状态(公共属性)
|
|
||||||
/// </summary>
|
|
||||||
public bool IsEnabled
|
|
||||||
{
|
|
||||||
get => _isEnabled;
|
|
||||||
protected set
|
|
||||||
{
|
|
||||||
if (_isEnabled != value)
|
|
||||||
{
|
|
||||||
_isEnabled = value;
|
|
||||||
OnEnabledStateChanged(value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件ID
|
|
||||||
/// </summary>
|
|
||||||
public string Id { get; protected set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 写入 <see cref="PluginManager"/> 配置时使用的稳定键(默认同类型全名;多实例类型如 SDK 目录插件应重写)。
|
|
||||||
/// </summary>
|
|
||||||
public virtual string PluginStateKey => GetType().FullName;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件路径
|
|
||||||
/// </summary>
|
|
||||||
public string PluginPath { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件名称
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件描述
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件版本
|
|
||||||
/// </summary>
|
|
||||||
public abstract Version Version { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件作者
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Author { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为内置插件
|
|
||||||
/// </summary>
|
|
||||||
public virtual bool IsBuiltIn => false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 状态变更事件
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<bool> EnabledStateChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 初始化插件
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Initialize()
|
|
||||||
{
|
|
||||||
Id = GetType().FullName;
|
|
||||||
|
|
||||||
// 添加日志,记录插件名称
|
|
||||||
try
|
|
||||||
{
|
|
||||||
string name = Name;
|
|
||||||
LogHelper.WriteLogToFile($"初始化插件: ID={Id}, 名称={name ?? "未命名"}");
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(name))
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"警告: 插件 {Id} 的名称为空", LogHelper.LogType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"获取插件名称时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"插件 {Name} 已初始化");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用插件
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Enable()
|
|
||||||
{
|
|
||||||
if (!IsEnabled)
|
|
||||||
{
|
|
||||||
IsEnabled = true;
|
|
||||||
LogHelper.WriteLogToFile($"插件 {Name} 已启用");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 禁用插件
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Disable()
|
|
||||||
{
|
|
||||||
if (IsEnabled)
|
|
||||||
{
|
|
||||||
IsEnabled = false;
|
|
||||||
LogHelper.WriteLogToFile($"插件 {Name} 已禁用");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件设置界面
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>插件设置界面</returns>
|
|
||||||
public virtual UserControl GetSettingsView()
|
|
||||||
{
|
|
||||||
// 默认返回空设置页面
|
|
||||||
return new UserControl();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件卸载时的清理工作
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Cleanup()
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"插件 {Name} 已卸载");
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存插件自身的设置
|
|
||||||
/// 注意:此方法仅用于保存插件的特定设置,不应影响插件启用/禁用状态
|
|
||||||
/// 插件启用状态由PluginManager统一管理
|
|
||||||
/// </summary>
|
|
||||||
public virtual void SavePluginSettings()
|
|
||||||
{
|
|
||||||
// 默认实现不做任何事情
|
|
||||||
// 子类可以重写此方法,将自身设置保存到配置文件中
|
|
||||||
LogHelper.WriteLogToFile($"插件 {Name} 设置已保存", LogHelper.LogType.Event);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 触发状态变更事件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isEnabled">是否启用</param>
|
|
||||||
protected virtual void OnEnabledStateChanged(bool isEnabled)
|
|
||||||
{
|
|
||||||
EnabledStateChanged?.Invoke(this, isEnabled);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,25 +0,0 @@
|
|||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 在加载任何 SDK 插件之前初始化宿主上下文(实现 <see cref="IPluginContext"/> 与 <see cref="IPluginService"/>)。
|
|
||||||
/// </summary>
|
|
||||||
public static class PluginRuntime
|
|
||||||
{
|
|
||||||
private static PluginSdkHostContext _context;
|
|
||||||
|
|
||||||
public static PluginSdkHostContext SdkContext => _context;
|
|
||||||
|
|
||||||
/// <summary>与 <see cref="SdkContext"/> 相同实例,便于旧代码通过 <see cref="PluginServiceManager"/> 访问。</summary>
|
|
||||||
public static IPluginService Services => SdkContext != null ? (IPluginService)SdkContext : null;
|
|
||||||
|
|
||||||
public static void Initialize(MainWindow mainWindow)
|
|
||||||
{
|
|
||||||
if (_context == null)
|
|
||||||
{
|
|
||||||
_context = new PluginSdkHostContext();
|
|
||||||
}
|
|
||||||
|
|
||||||
_context.SetMainWindow(mainWindow);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
File diff suppressed because it is too large
Load Diff
@@ -1,24 +0,0 @@
|
|||||||
using System;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 兼容旧代码的薄门面:与 <see cref="PluginSdkHostContext"/> 为同一实例,实现 <see cref="IPluginService"/>。
|
|
||||||
/// </summary>
|
|
||||||
public static class PluginServiceManager
|
|
||||||
{
|
|
||||||
public static IPluginService Instance
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
var ctx = PluginRuntime.SdkContext;
|
|
||||||
if (ctx == null)
|
|
||||||
{
|
|
||||||
throw new InvalidOperationException("插件宿主尚未初始化:请先调用 PluginRuntime.Initialize(MainWindow)。");
|
|
||||||
}
|
|
||||||
|
|
||||||
return (IPluginService)ctx;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,133 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using InkCanvasForClass.PluginHost;
|
|
||||||
using InkCanvasForClass.PluginSdk;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Helpers.Plugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 将基于 <see cref="IInkCanvasPlugin"/> 的外部插件适配为宿主统一的 <see cref="IPlugin"/>。
|
|
||||||
/// </summary>
|
|
||||||
public sealed class SdkPluginAdapter : PluginBase
|
|
||||||
{
|
|
||||||
private readonly IInkCanvasPlugin _core;
|
|
||||||
private readonly string _folderId;
|
|
||||||
|
|
||||||
public SdkPluginAdapter(string folderId, IInkCanvasPlugin core, string mainAssemblyPath)
|
|
||||||
{
|
|
||||||
_folderId = folderId ?? throw new ArgumentNullException(nameof(folderId));
|
|
||||||
_core = core ?? throw new ArgumentNullException(nameof(core));
|
|
||||||
PluginPath = mainAssemblyPath ?? string.Empty;
|
|
||||||
}
|
|
||||||
|
|
||||||
public string FolderId => _folderId;
|
|
||||||
|
|
||||||
public IInkCanvasPlugin Core => _core;
|
|
||||||
|
|
||||||
public override string PluginStateKey => "SdkFolder:" + _folderId;
|
|
||||||
|
|
||||||
public override string Name => _core.Name;
|
|
||||||
|
|
||||||
public override string Description => _core.Description;
|
|
||||||
|
|
||||||
public override Version Version => _core.Version;
|
|
||||||
|
|
||||||
public override string Author => _core.Author;
|
|
||||||
|
|
||||||
public override bool IsBuiltIn => false;
|
|
||||||
|
|
||||||
public override void Initialize()
|
|
||||||
{
|
|
||||||
base.Initialize();
|
|
||||||
|
|
||||||
var ctx = PluginRuntime.SdkContext;
|
|
||||||
if (ctx == null)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"SDK 插件 {_core.Name} 初始化失败:宿主上下文未就绪", LogHelper.LogType.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_core.Initialize(ctx);
|
|
||||||
|
|
||||||
var registry = PluginManager.Instance.ExtensionRegistry;
|
|
||||||
registry.SetCurrentPluginId(_folderId);
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_core is InkCanvasPluginBase pluginBase)
|
|
||||||
{
|
|
||||||
pluginBase.RegisterExtensions(registry);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
registry.SetCurrentPluginId(string.Empty);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Enable()
|
|
||||||
{
|
|
||||||
if (IsEnabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_core is InkCanvasPluginBase b)
|
|
||||||
{
|
|
||||||
b.IsEnabled = true;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_core.Start();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Enable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Disable()
|
|
||||||
{
|
|
||||||
if (!IsEnabled)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_core is InkCanvasPluginBase b)
|
|
||||||
{
|
|
||||||
b.IsEnabled = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_core.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Disable();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override UserControl GetSettingsView()
|
|
||||||
{
|
|
||||||
return _core.GetSettingsView();
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Cleanup()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_core is InkCanvasPluginBase b)
|
|
||||||
{
|
|
||||||
b.IsEnabled = false;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
_core.Stop();
|
|
||||||
}
|
|
||||||
|
|
||||||
_core.Cleanup();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"SDK 插件 {_core.Name} Cleanup 出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Cleanup();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -157,10 +157,6 @@
|
|||||||
<PackageReference Include="AForge.Math" Version="2.2.5" />
|
<PackageReference Include="AForge.Math" Version="2.2.5" />
|
||||||
<PackageReference Include="WebDav.Client" Version="2.9.0" />
|
<PackageReference Include="WebDav.Client" Version="2.9.0" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\Plugins\SDK\InkCanvas.PluginSdk.csproj" />
|
|
||||||
<ProjectReference Include="..\Plugins\Host\InkCanvas.PluginHost.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
<ItemGroup Condition="'$(MSBuildRuntimeType)' == 'Full'">
|
<ItemGroup Condition="'$(MSBuildRuntimeType)' == 'Full'">
|
||||||
<COMReference Include="IWshRuntimeLibrary">
|
<COMReference Include="IWshRuntimeLibrary">
|
||||||
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
|
<Guid>{F935DC20-1CF0-11D0-ADB9-00C04FD58A0B}</Guid>
|
||||||
|
|||||||
@@ -247,21 +247,6 @@
|
|||||||
<!-- 主要导航按钮 -->
|
<!-- 主要导航按钮 -->
|
||||||
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
<ScrollViewer Grid.Row="1" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled">
|
||||||
<StackPanel>
|
<StackPanel>
|
||||||
<!-- Plugins -->
|
|
||||||
<Button Width="40" Height="40" Margin="0,5,0,0" Style="{StaticResource NavButton}"
|
|
||||||
Click="NavPlugins_Click" Tag="plugins" ToolTip="{x:Static props:Strings.Nav_Plugins}">
|
|
||||||
<Image Width="20" Height="20">
|
|
||||||
<Image.Source>
|
|
||||||
<DrawingImage>
|
|
||||||
<DrawingImage.Drawing>
|
|
||||||
<GeometryDrawing Brush="White"
|
|
||||||
Geometry="M342.826667 213.333333a149.333333 149.333333 0 0 1 295.68 0H682.666667a128 128 0 0 1 128 128v44.16a149.333333 149.333333 0 0 1 0 295.68V725.333333a128 128 0 0 1-128 128h-128v-21.333333a64 64 0 0 0-128 0v21.333333H298.666667a128 128 0 0 1-128-128v-128h21.333333a64 64 0 0 0 0-128H170.666667V341.333333a128 128 0 0 1 128-128h44.16zM426.666667 234.666667V298.666667H298.666667q-17.664 0-30.165334 12.501333T256 341.333333v56.576q22.528 10.752 41.6 29.866667Q341.333333 471.466667 341.333333 533.333333q0 61.866667-43.733333 105.6-19.072 19.072-41.6 29.824V725.333333q0 17.664 12.501333 30.165334T298.666667 768h56.576q10.752-22.528 29.866666-41.6Q428.8 682.666667 490.666667 682.666667q61.866667 0 105.6 43.733333 19.072 19.072 29.824 41.6H682.666667q17.664 0 30.165333-12.501333T725.333333 725.333333v-128h64a64 64 0 0 0 0-128H725.333333V341.333333q0-17.664-12.501333-30.165333T682.666667 298.666667h-128V234.666667a64 64 0 1 0-128 0z"/>
|
|
||||||
</DrawingImage.Drawing>
|
|
||||||
</DrawingImage>
|
|
||||||
</Image.Source>
|
|
||||||
</Image>
|
|
||||||
</Button>
|
|
||||||
|
|
||||||
<!-- Startup -->
|
<!-- Startup -->
|
||||||
<Button Width="40" Height="40" Margin="0,10,0,0" Style="{StaticResource NavButton}"
|
<Button Width="40" Height="40" Margin="0,10,0,0" Style="{StaticResource NavButton}"
|
||||||
Click="NavStartup_Click" Tag="startup" ToolTip="{x:Static props:Strings.Nav_Startup}">
|
Click="NavStartup_Click" Tag="startup" ToolTip="{x:Static props:Strings.Nav_Startup}">
|
||||||
@@ -671,19 +656,6 @@
|
|||||||
</ikw:SimpleStackPanel>
|
</ikw:SimpleStackPanel>
|
||||||
</GroupBox>
|
</GroupBox>
|
||||||
|
|
||||||
<GroupBox Name="GroupBoxPlugins">
|
|
||||||
<GroupBox.Header>
|
|
||||||
<TextBlock Margin="0,12,0,0" Text="{i18n:I18n Key=Settings_Plugins}" FontWeight="Bold" Foreground="#fafafa"
|
|
||||||
FontSize="26" />
|
|
||||||
</GroupBox.Header>
|
|
||||||
<ikw:SimpleStackPanel Spacing="6" Margin="0,10,0,0">
|
|
||||||
<TextBlock TextWrapping="Wrap" Margin="0,0,0,10" Foreground="#fafafa" Text="{i18n:I18n Key=Settings_PluginsDesc}"/>
|
|
||||||
<Button x:Name="BtnOpenPluginManager" Content="{i18n:I18n Key=Btn_OpenPluginManager}"
|
|
||||||
HorizontalAlignment="Left" Click="BtnOpenPluginManager_Click"
|
|
||||||
Padding="15,5" Margin="0,10,0,0"/>
|
|
||||||
</ikw:SimpleStackPanel>
|
|
||||||
</GroupBox>
|
|
||||||
|
|
||||||
<GroupBox Name="GroupBoxStartup">
|
<GroupBox Name="GroupBoxStartup">
|
||||||
<GroupBox.Header>
|
<GroupBox.Header>
|
||||||
<TextBlock Margin="0,12,0,0" Text="{i18n:I18n Key=Startup_Start}" FontWeight="Bold" Foreground="#fafafa"
|
<TextBlock Margin="0,12,0,0" Text="{i18n:I18n Key=Startup_Start}" FontWeight="Bold" Foreground="#fafafa"
|
||||||
|
|||||||
@@ -1,5 +1,4 @@
|
|||||||
using Ink_Canvas.Helpers;
|
using Ink_Canvas.Helpers;
|
||||||
using Ink_Canvas.Helpers.Plugins;
|
|
||||||
using Ink_Canvas.Windows;
|
using Ink_Canvas.Windows;
|
||||||
using iNKORE.UI.WPF.Modern;
|
using iNKORE.UI.WPF.Modern;
|
||||||
using iNKORE.UI.WPF.Modern.Controls;
|
using iNKORE.UI.WPF.Modern.Controls;
|
||||||
@@ -80,12 +79,6 @@ namespace Ink_Canvas
|
|||||||
public int BoothResolutionWidth => _boothResolutionWidth;
|
public int BoothResolutionWidth => _boothResolutionWidth;
|
||||||
public int BoothResolutionHeight => _boothResolutionHeight;
|
public int BoothResolutionHeight => _boothResolutionHeight;
|
||||||
|
|
||||||
/// <summary>供插件系统访问的白板页面列表(只读)。</summary>
|
|
||||||
public IList<System.Windows.Controls.Canvas> WhiteboardPages => whiteboardPages;
|
|
||||||
|
|
||||||
/// <summary>供插件系统访问的当前页索引。</summary>
|
|
||||||
public int CurrentPageIndex => currentPageIndex;
|
|
||||||
|
|
||||||
private static Cursor _cachedPenCursor = null;
|
private static Cursor _cachedPenCursor = null;
|
||||||
private static readonly object _cursorLock = new object();
|
private static readonly object _cursorLock = new object();
|
||||||
|
|
||||||
@@ -1372,8 +1365,6 @@ namespace Ink_Canvas
|
|||||||
}), DispatcherPriority.Loaded);
|
}), DispatcherPriority.Loaded);
|
||||||
}
|
}
|
||||||
|
|
||||||
// 初始化插件系统
|
|
||||||
InitializePluginSystem();
|
|
||||||
// 确保开关和设置同步
|
// 确保开关和设置同步
|
||||||
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
|
ToggleSwitchNoFocusMode.IsOn = Settings.Advanced.IsNoFocusMode;
|
||||||
ApplyNoFocusMode();
|
ApplyNoFocusMode();
|
||||||
@@ -2584,9 +2575,6 @@ namespace Ink_Canvas
|
|||||||
case "about":
|
case "about":
|
||||||
targetGroupBox = GroupBoxAbout;
|
targetGroupBox = GroupBoxAbout;
|
||||||
break;
|
break;
|
||||||
case "plugins":
|
|
||||||
targetGroupBox = GroupBoxPlugins;
|
|
||||||
break;
|
|
||||||
default:
|
default:
|
||||||
// 默认滚动到顶部
|
// 默认滚动到顶部
|
||||||
SettingsPanelScrollViewer.ScrollToTop();
|
SettingsPanelScrollViewer.ScrollToTop();
|
||||||
@@ -2734,9 +2722,6 @@ namespace Ink_Canvas
|
|||||||
case "about":
|
case "about":
|
||||||
SetNavButtonTag("about");
|
SetNavButtonTag("about");
|
||||||
break;
|
break;
|
||||||
case "plugins":
|
|
||||||
SetNavButtonTag("plugins");
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -2823,64 +2808,6 @@ namespace Ink_Canvas
|
|||||||
|
|
||||||
#endregion Navigation Sidebar Methods
|
#endregion Navigation Sidebar Methods
|
||||||
|
|
||||||
#region 插件???
|
|
||||||
|
|
||||||
// 添加插件系统初始化方法
|
|
||||||
private void InitializePluginSystem()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
PluginRuntime.Initialize(this);
|
|
||||||
PluginManager.Instance.Initialize();
|
|
||||||
LogHelper.WriteLogToFile("插件系统已初始化");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"初始化插件系统时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加插件管理导航点击事件处理
|
|
||||||
private void NavPlugins_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
ShowSettingsSection("plugins");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 添加打开插件管理器按钮点击事件
|
|
||||||
private void BtnOpenPluginManager_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 暂时隐藏设置面板
|
|
||||||
BorderSettings.Visibility = Visibility.Hidden;
|
|
||||||
BorderSettingsMask.Visibility = Visibility.Hidden;
|
|
||||||
|
|
||||||
// 创建并显示插件设置窗口
|
|
||||||
PluginSettingsWindow pluginSettingsWindow = new PluginSettingsWindow();
|
|
||||||
|
|
||||||
// 设置窗口关闭事件,用于在插件管理窗口关闭后恢复设置面板
|
|
||||||
pluginSettingsWindow.Closed += (s, args) =>
|
|
||||||
{
|
|
||||||
// 恢复设置面板显示
|
|
||||||
BorderSettings.Visibility = Visibility.Visible;
|
|
||||||
BorderSettingsMask.Visibility = Visibility.Visible;
|
|
||||||
};
|
|
||||||
|
|
||||||
// 显示插件设置窗口
|
|
||||||
pluginSettingsWindow.ShowDialog();
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// 确保在发生错误时也恢复设置面板显示
|
|
||||||
BorderSettings.Visibility = Visibility.Visible;
|
|
||||||
BorderSettingsMask.Visibility = Visibility.Visible;
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"打开插件管理器时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"打开插件管理器时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#endregion 插件???
|
|
||||||
|
|
||||||
#region 新设置窗口
|
#region 新设置窗口
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -1,152 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Ink;
|
|
||||||
using MessageBox = iNKORE.UI.WPF.Modern.Controls.MessageBox;
|
|
||||||
|
|
||||||
namespace Ink_Canvas
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 供 <see cref="Helpers.Plugins.PluginSdkHostContext"/> 调用的宿主 API,封装 UI 线程与内部墨迹逻辑。
|
|
||||||
/// </summary>
|
|
||||||
public partial class MainWindow : Window
|
|
||||||
{
|
|
||||||
internal void PluginHost_RunOnUiThread(Action action)
|
|
||||||
{
|
|
||||||
if (action == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Dispatcher.CheckAccess())
|
|
||||||
{
|
|
||||||
action();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Dispatcher.Invoke(action);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void PluginHost_Undo()
|
|
||||||
{
|
|
||||||
PluginHost_RunOnUiThread(() =>
|
|
||||||
{
|
|
||||||
if (inkCanvas.GetSelectedStrokes().Count != 0)
|
|
||||||
{
|
|
||||||
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
|
||||||
inkCanvas.Select(new StrokeCollection());
|
|
||||||
}
|
|
||||||
|
|
||||||
var item = timeMachine.Undo();
|
|
||||||
ApplyHistoryToCanvas(item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void PluginHost_Redo()
|
|
||||||
{
|
|
||||||
PluginHost_RunOnUiThread(() =>
|
|
||||||
{
|
|
||||||
if (inkCanvas.GetSelectedStrokes().Count != 0)
|
|
||||||
{
|
|
||||||
GridInkCanvasSelectionCover.Visibility = Visibility.Collapsed;
|
|
||||||
inkCanvas.Select(new StrokeCollection());
|
|
||||||
}
|
|
||||||
|
|
||||||
var item = timeMachine.Redo();
|
|
||||||
ApplyHistoryToCanvas(item);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void PluginHost_ClearInk(bool erasedByCode)
|
|
||||||
{
|
|
||||||
PluginHost_RunOnUiThread(() => ClearStrokes(erasedByCode));
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool PluginHost_CanUndo()
|
|
||||||
{
|
|
||||||
if (Dispatcher.CheckAccess())
|
|
||||||
{
|
|
||||||
return timeMachine != null && timeMachine.CanUndo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Dispatcher.Invoke(() => timeMachine != null && timeMachine.CanUndo);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool PluginHost_CanRedo()
|
|
||||||
{
|
|
||||||
if (Dispatcher.CheckAccess())
|
|
||||||
{
|
|
||||||
return timeMachine != null && timeMachine.CanRedo;
|
|
||||||
}
|
|
||||||
|
|
||||||
return Dispatcher.Invoke(() => timeMachine != null && timeMachine.CanRedo);
|
|
||||||
}
|
|
||||||
|
|
||||||
internal void PluginHost_ShowInfo(string title, string message)
|
|
||||||
{
|
|
||||||
PluginHost_RunOnUiThread(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
MessageBox.Show(message ?? string.Empty, title ?? string.Empty);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// 忽略对话框失败,避免插件拖垮宿主
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
internal bool PluginHost_ShowConfirm(string title, string message)
|
|
||||||
{
|
|
||||||
if (Dispatcher.CheckAccess())
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return MessageBox.Show(message ?? string.Empty, title ?? string.Empty, MessageBoxButton.YesNo) ==
|
|
||||||
MessageBoxResult.Yes;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return MessageBox.Show(message ?? string.Empty, title ?? string.Empty, MessageBoxButton.YesNo) ==
|
|
||||||
MessageBoxResult.Yes;
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
internal string PluginHost_ShowInput(string title, string message, string defaultValue)
|
|
||||||
{
|
|
||||||
string Show()
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
return Microsoft.VisualBasic.Interaction.InputBox(message ?? string.Empty, title ?? string.Empty,
|
|
||||||
defaultValue ?? string.Empty);
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
return defaultValue ?? string.Empty;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Dispatcher.CheckAccess())
|
|
||||||
{
|
|
||||||
return Show();
|
|
||||||
}
|
|
||||||
|
|
||||||
return Dispatcher.Invoke(Show);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,179 +0,0 @@
|
|||||||
<Window x:Class="Ink_Canvas.Windows.PluginSettingsWindow"
|
|
||||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
|
||||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
|
||||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
|
||||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
|
||||||
xmlns:ui="http://schemas.inkore.net/lib/ui/wpf/modern"
|
|
||||||
xmlns:ikw="http://schemas.inkore.net/lib/ui/wpf"
|
|
||||||
xmlns:local="clr-namespace:Ink_Canvas.Windows"
|
|
||||||
mc:Ignorable="d"
|
|
||||||
Title="插件管理" Height="550" Width="800"
|
|
||||||
WindowStartupLocation="CenterScreen"
|
|
||||||
ResizeMode="CanResize"
|
|
||||||
Topmost="True"
|
|
||||||
ui:ThemeManager.IsThemeAware="True"
|
|
||||||
ui:TitleBar.ExtendViewIntoTitleBar="True"
|
|
||||||
ui:WindowHelper.SystemBackdropType="Mica"
|
|
||||||
ui:WindowHelper.UseModernWindowStyle="True"
|
|
||||||
ui:TitleBar.Height="48">
|
|
||||||
|
|
||||||
<Window.Resources>
|
|
||||||
<!-- 定义必要的资源 -->
|
|
||||||
<SolidColorBrush x:Key="BorderBrush" Color="#DDDDDD"/>
|
|
||||||
<SolidColorBrush x:Key="SystemAccentColorLight1" Color="#3B82F6"/>
|
|
||||||
<SolidColorBrush x:Key="SystemAccentColor" Color="#2563EB"/>
|
|
||||||
<SolidColorBrush x:Key="SystemControlBackgroundChromeMediumBrush" Color="#F0F0F0"/>
|
|
||||||
</Window.Resources>
|
|
||||||
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- 自定义标题栏 -->
|
|
||||||
<Border x:Name="Border_TitleBarRoot"
|
|
||||||
Height="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=(ui:TitleBar.Height)}">
|
|
||||||
<Grid>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<TextBlock Text="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=Title}"
|
|
||||||
VerticalAlignment="Center" Margin="12,0,0,0" FontSize="12" FontWeight="SemiBold"/>
|
|
||||||
|
|
||||||
<!--Right Inset-->
|
|
||||||
<Rectangle Width="{Binding RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=Window}, Path=(ui:TitleBar.SystemOverlayRightInset)}"
|
|
||||||
Grid.Column="2"/>
|
|
||||||
|
|
||||||
<!--Right Buttons-->
|
|
||||||
<ikw:SimpleStackPanel x:Name="StackPanel_RightButtons"
|
|
||||||
Orientation="Horizontal" Grid.Column="1" Spacing="5">
|
|
||||||
|
|
||||||
|
|
||||||
</ikw:SimpleStackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- 内容区域背景 -->
|
|
||||||
<Border Grid.Row="1" Grid.RowSpan="2"
|
|
||||||
Background="{DynamicResource SystemControlBackgroundAltHighBrush}"
|
|
||||||
BorderThickness="0,1,0,0"
|
|
||||||
BorderBrush="{DynamicResource SystemControlForegroundBaseLowBrush}"/>
|
|
||||||
|
|
||||||
<!-- 主内容区 -->
|
|
||||||
<Grid Grid.Row="1" Margin="20,20,20,20">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="250"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<!-- 左侧插件列表 -->
|
|
||||||
<Border Grid.Column="0" BorderThickness="1" BorderBrush="{DynamicResource BorderBrush}" Margin="0,0,10,0" CornerRadius="5">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Text="插件列表" Margin="10,10,0,5" FontSize="16" FontWeight="SemiBold" Foreground="Black"/>
|
|
||||||
|
|
||||||
<ListView Grid.Row="1" x:Name="PluginListView" BorderThickness="0" Margin="0,5,0,0"
|
|
||||||
SelectionChanged="PluginListView_SelectionChanged">
|
|
||||||
<ListView.ItemTemplate>
|
|
||||||
<DataTemplate>
|
|
||||||
<Grid Margin="0,5">
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
<TextBlock Text="{Binding Name}" Grid.Column="0" VerticalAlignment="Center"
|
|
||||||
Foreground="Black" FontWeight="Normal" FontSize="14"/>
|
|
||||||
<ui:ToggleSwitch Grid.Column="1" IsOn="{Binding IsEnabled}"
|
|
||||||
Toggled="PluginToggleSwitch_Toggled"
|
|
||||||
Tag="{Binding}" MinWidth="40"/>
|
|
||||||
</Grid>
|
|
||||||
</DataTemplate>
|
|
||||||
</ListView.ItemTemplate>
|
|
||||||
</ListView>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- 右侧插件详情和设置 -->
|
|
||||||
<ScrollViewer Grid.Column="1" Margin="10,0,0,0" VerticalScrollBarVisibility="Auto">
|
|
||||||
<Grid>
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="*"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
|
|
||||||
<!-- 插件详情 -->
|
|
||||||
<Border Grid.Row="0" BorderThickness="1" BorderBrush="{DynamicResource BorderBrush}" Padding="15" CornerRadius="5">
|
|
||||||
<Grid x:Name="PluginDetailGrid">
|
|
||||||
<Grid.RowDefinitions>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
<RowDefinition Height="Auto"/>
|
|
||||||
</Grid.RowDefinitions>
|
|
||||||
<Grid.ColumnDefinitions>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
<ColumnDefinition Width="*"/>
|
|
||||||
<ColumnDefinition Width="Auto"/>
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="0" Text="名称:" FontWeight="SemiBold" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
<TextBlock Grid.Row="0" Grid.Column="1" Text="{Binding Name}" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="1" Grid.Column="0" Text="版本:" FontWeight="SemiBold" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
<TextBlock Grid.Row="1" Grid.Column="1" Text="{Binding Version}" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="2" Grid.Column="0" Text="作者:" FontWeight="SemiBold" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
<TextBlock Grid.Row="2" Grid.Column="1" Text="{Binding Author}" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
|
|
||||||
<TextBlock Grid.Row="3" Grid.Column="0" Text="描述:" FontWeight="SemiBold" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
<TextBlock Grid.Row="3" Grid.Column="1" Text="{Binding Description}" TextWrapping="Wrap" Margin="0,0,0,5" Foreground="Black"/>
|
|
||||||
|
|
||||||
<Button Grid.Row="3" Grid.Column="2" x:Name="BtnDeletePlugin" Content="删除插件"
|
|
||||||
Visibility="Collapsed" Click="BtnDeletePlugin_Click"
|
|
||||||
Margin="10,0,0,0" Padding="8,3" HorizontalAlignment="Right"
|
|
||||||
Background="#FFEE5555" Foreground="White"/>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- 插件设置区域 -->
|
|
||||||
<Border Grid.Row="1" BorderThickness="1" BorderBrush="{DynamicResource BorderBrush}" Margin="0,10,0,0" Padding="15" CornerRadius="5">
|
|
||||||
<StackPanel>
|
|
||||||
<TextBlock Text="插件设置" FontSize="16" FontWeight="SemiBold" Margin="0,0,0,10" Foreground="Black"/>
|
|
||||||
<ContentControl x:Name="PluginSettingsContainer" MinHeight="50"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
|
|
||||||
<!-- 插件配置内容区 -->
|
|
||||||
<Border Grid.Row="2" BorderThickness="1" BorderBrush="{DynamicResource BorderBrush}" Margin="0,10,0,0" Padding="0" CornerRadius="5">
|
|
||||||
<ContentControl x:Name="PluginContentContainer" Margin="0"/>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</ScrollViewer>
|
|
||||||
</Grid>
|
|
||||||
|
|
||||||
<!-- 底部操作栏 -->
|
|
||||||
<Border Grid.Row="2" Background="{DynamicResource SystemControlBackgroundAltHighBrush}" Height="60">
|
|
||||||
<Grid>
|
|
||||||
<StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center" Margin="20,0,0,0">
|
|
||||||
<Button x:Name="BtnLoadPlugin" Content="加载本地插件" Click="BtnLoadPlugin_Click"
|
|
||||||
Padding="15,5" Background="{DynamicResource SystemAccentColor}" Foreground="White"/>
|
|
||||||
<Button x:Name="BtnSaveConfig" Content="保存状态" Click="BtnSaveConfig_Click"
|
|
||||||
Padding="15,5" Margin="10,0,0,0" Background="{DynamicResource SystemAccentColor}" Foreground="White"
|
|
||||||
ToolTip="手动保存当前所有插件的启用/禁用状态到配置文件"/>
|
|
||||||
<Button x:Name="BtnExportPlugin" Content="导出插件" Click="BtnExportPlugin_Click"
|
|
||||||
Padding="15,5" Margin="10,0,0,0" Background="{DynamicResource SystemAccentColor}" Foreground="White"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Grid>
|
|
||||||
</Border>
|
|
||||||
</Grid>
|
|
||||||
</Window>
|
|
||||||
@@ -1,727 +0,0 @@
|
|||||||
using Ink_Canvas.Helpers;
|
|
||||||
using Ink_Canvas.Helpers.Plugins;
|
|
||||||
using Ink_Canvas.Helpers.Plugins.BuiltIn;
|
|
||||||
using Ink_Canvas.Helpers.Plugins.BuiltIn.SuperLauncher;
|
|
||||||
using iNKORE.UI.WPF.Modern.Controls;
|
|
||||||
using Microsoft.Win32;
|
|
||||||
using System;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.ComponentModel;
|
|
||||||
using System.IO;
|
|
||||||
using System.Linq;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Threading;
|
|
||||||
using MessageBox = iNKORE.UI.WPF.Modern.Controls.MessageBox;
|
|
||||||
|
|
||||||
namespace Ink_Canvas.Windows
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// PluginSettingsWindow.xaml 的交互逻辑
|
|
||||||
/// </summary>
|
|
||||||
public partial class PluginSettingsWindow : Window, INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 刷新插件列表
|
|
||||||
/// </summary>
|
|
||||||
public void RefreshPluginList()
|
|
||||||
{
|
|
||||||
LoadPlugins();
|
|
||||||
|
|
||||||
// 如果当前选中的插件仍然存在,保持其选中状态
|
|
||||||
if (SelectedPlugin != null)
|
|
||||||
{
|
|
||||||
var matchingPlugin = Plugins.FirstOrDefault(p => p.Plugin.GetType().FullName == SelectedPlugin.GetType().FullName);
|
|
||||||
if (matchingPlugin != null)
|
|
||||||
{
|
|
||||||
PluginListView.SelectedItem = matchingPlugin;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
OnPropertyChanged(nameof(SelectedPlugin));
|
|
||||||
LogHelper.WriteLogToFile("插件列表已刷新");
|
|
||||||
}
|
|
||||||
|
|
||||||
private IPlugin _selectedPlugin;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前选中的插件
|
|
||||||
/// </summary>
|
|
||||||
public IPlugin SelectedPlugin
|
|
||||||
{
|
|
||||||
get => _selectedPlugin;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_selectedPlugin != value)
|
|
||||||
{
|
|
||||||
_selectedPlugin = value;
|
|
||||||
OnPropertyChanged(nameof(SelectedPlugin));
|
|
||||||
OnPropertyChanged(nameof(Name));
|
|
||||||
OnPropertyChanged(nameof(Version));
|
|
||||||
OnPropertyChanged(nameof(Author));
|
|
||||||
OnPropertyChanged(nameof(Description));
|
|
||||||
OnPropertyChanged(nameof(IsEnabled));
|
|
||||||
OnPropertyChanged(nameof(IsBuiltIn));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public new string Name => SelectedPlugin?.Name ?? string.Empty;
|
|
||||||
public string Version => SelectedPlugin?.Version?.ToString() ?? string.Empty;
|
|
||||||
public string Author => SelectedPlugin?.Author ?? string.Empty;
|
|
||||||
public string Description => SelectedPlugin?.Description ?? string.Empty;
|
|
||||||
public new bool IsEnabled => SelectedPlugin is PluginBase plugin && plugin.IsEnabled;
|
|
||||||
public bool IsBuiltIn => SelectedPlugin?.IsBuiltIn ?? false;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件列表
|
|
||||||
/// </summary>
|
|
||||||
public ObservableCollection<PluginViewModel> Plugins { get; } = new ObservableCollection<PluginViewModel>();
|
|
||||||
|
|
||||||
public PluginSettingsWindow()
|
|
||||||
{
|
|
||||||
InitializeComponent();
|
|
||||||
|
|
||||||
// 设置数据上下文
|
|
||||||
PluginDetailGrid.DataContext = this;
|
|
||||||
|
|
||||||
// 设置导出按钮初始状态
|
|
||||||
BtnExportPlugin.IsEnabled = false;
|
|
||||||
BtnExportPlugin.ToolTip = "请先选择要导出的插件";
|
|
||||||
|
|
||||||
// 加载插件列表
|
|
||||||
LoadPlugins();
|
|
||||||
|
|
||||||
// 注册窗口关闭事件
|
|
||||||
Closing += PluginSettingsWindow_Closing;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 窗口关闭事件处理
|
|
||||||
/// </summary>
|
|
||||||
private void PluginSettingsWindow_Closing(object sender, CancelEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 保存插件配置
|
|
||||||
LogHelper.WriteLogToFile("插件管理窗口关闭,保存插件配置...");
|
|
||||||
PluginManager.Instance.SaveConfig();
|
|
||||||
LogHelper.WriteLogToFile("插件配置已保存");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"关闭窗口时保存插件配置出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载插件列表
|
|
||||||
/// </summary>
|
|
||||||
private void LoadPlugins()
|
|
||||||
{
|
|
||||||
Plugins.Clear();
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"开始加载插件列表到UI,插件总数: {PluginManager.Instance.Plugins.Count}");
|
|
||||||
|
|
||||||
// 添加所有已加载的插件
|
|
||||||
foreach (var plugin in PluginManager.Instance.Plugins)
|
|
||||||
{
|
|
||||||
bool isEnabled = false;
|
|
||||||
|
|
||||||
// 从插件实例获取启用状态
|
|
||||||
if (plugin is PluginBase pluginBase)
|
|
||||||
{
|
|
||||||
isEnabled = pluginBase.IsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 记录插件详细信息
|
|
||||||
LogHelper.WriteLogToFile($"正在加载插件到UI: 类型={plugin.GetType().FullName}, 名称={plugin.Name ?? "未命名"}, 状态={isEnabled}");
|
|
||||||
|
|
||||||
// 创建视图模型并添加到集合
|
|
||||||
var viewModel = new PluginViewModel(plugin)
|
|
||||||
{
|
|
||||||
IsEnabled = isEnabled
|
|
||||||
};
|
|
||||||
Plugins.Add(viewModel);
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"已加载插件到UI列表: {plugin.Name},状态: {(isEnabled ? "启用" : "禁用")}");
|
|
||||||
}
|
|
||||||
|
|
||||||
// 绑定到ListView
|
|
||||||
LogHelper.WriteLogToFile($"绑定 {Plugins.Count} 个插件到ListView");
|
|
||||||
PluginListView.ItemsSource = Plugins;
|
|
||||||
|
|
||||||
// 如果有插件,选择第一个
|
|
||||||
if (Plugins.Count > 0)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"选择第一个插件: {Plugins[0].Name}");
|
|
||||||
PluginListView.SelectedIndex = 0;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile("没有找到任何插件", LogHelper.LogType.Warning);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 更新属性变更通知
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="propertyName">属性名称</param>
|
|
||||||
protected void OnPropertyChanged(string propertyName)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件列表选择变更事件
|
|
||||||
/// </summary>
|
|
||||||
private void PluginListView_SelectionChanged(object sender, SelectionChangedEventArgs e)
|
|
||||||
{
|
|
||||||
if (PluginListView.SelectedItem is PluginViewModel viewModel)
|
|
||||||
{
|
|
||||||
// 设置当前选中的插件
|
|
||||||
SelectedPlugin = viewModel.Plugin;
|
|
||||||
|
|
||||||
// 加载插件设置界面
|
|
||||||
PluginSettingsContainer.Content = SelectedPlugin.GetSettingsView();
|
|
||||||
|
|
||||||
// 设置删除按钮的可见性
|
|
||||||
BtnDeletePlugin.Visibility = !SelectedPlugin.IsBuiltIn ? Visibility.Visible : Visibility.Collapsed;
|
|
||||||
|
|
||||||
// 设置导出按钮的可用状态
|
|
||||||
BtnExportPlugin.IsEnabled = !SelectedPlugin.IsBuiltIn;
|
|
||||||
if (SelectedPlugin.IsBuiltIn)
|
|
||||||
{
|
|
||||||
BtnExportPlugin.ToolTip = "内置插件无法导出";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
BtnExportPlugin.ToolTip = "将插件导出为.iccpp文件";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
SelectedPlugin = null;
|
|
||||||
PluginSettingsContainer.Content = null;
|
|
||||||
BtnDeletePlugin.Visibility = Visibility.Collapsed;
|
|
||||||
BtnExportPlugin.IsEnabled = false;
|
|
||||||
BtnExportPlugin.ToolTip = "请先选择要导出的插件";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载本地插件按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnLoadPlugin_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 创建文件对话框
|
|
||||||
OpenFileDialog dialog = new OpenFileDialog
|
|
||||||
{
|
|
||||||
Filter = "ICC插件文件(*.iccpp)|*.iccpp",
|
|
||||||
Title = "选择要加载的插件文件"
|
|
||||||
};
|
|
||||||
|
|
||||||
// 显示对话框
|
|
||||||
if (dialog.ShowDialog() == true)
|
|
||||||
{
|
|
||||||
// 获取插件文件路径
|
|
||||||
string pluginPath = dialog.FileName;
|
|
||||||
|
|
||||||
// 检查是否在Plugins目录下
|
|
||||||
string pluginsDirectory = Path.Combine(App.RootPath, "Plugins");
|
|
||||||
string targetPath = Path.Combine(pluginsDirectory, Path.GetFileName(pluginPath));
|
|
||||||
|
|
||||||
// 确保Plugins目录存在
|
|
||||||
if (!Directory.Exists(pluginsDirectory))
|
|
||||||
{
|
|
||||||
Directory.CreateDirectory(pluginsDirectory);
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果插件不在Plugins目录下,复制过去
|
|
||||||
if (!string.Equals(pluginPath, targetPath, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
File.Copy(pluginPath, targetPath, true);
|
|
||||||
pluginPath = targetPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 加载插件
|
|
||||||
IPlugin plugin = PluginManager.Instance.LoadExternalPlugin(pluginPath);
|
|
||||||
|
|
||||||
if (plugin != null)
|
|
||||||
{
|
|
||||||
// 刷新插件列表
|
|
||||||
LoadPlugins();
|
|
||||||
|
|
||||||
// 选择新加载的插件
|
|
||||||
foreach (var item in Plugins)
|
|
||||||
{
|
|
||||||
if (item.Plugin == plugin)
|
|
||||||
{
|
|
||||||
PluginListView.SelectedItem = item;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageBox.Show($"插件 {plugin.Name} v{plugin.Version} 已成功加载!", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MessageBox.Show("插件加载失败,请检查文件是否有效。", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
MessageBox.Show($"加载插件时发生错误:{ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除插件按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnDeletePlugin_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
if (SelectedPlugin == null) return;
|
|
||||||
|
|
||||||
// 不能删除内置插件
|
|
||||||
if (SelectedPlugin.IsBuiltIn)
|
|
||||||
{
|
|
||||||
MessageBox.Show("内置插件无法删除。", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存插件名称,以便在删除后使用
|
|
||||||
string pluginName = SelectedPlugin.Name;
|
|
||||||
|
|
||||||
// 确认删除
|
|
||||||
MessageBoxResult result = MessageBox.Show(
|
|
||||||
$"确定要删除插件 {pluginName} 吗?\n此操作将永久删除插件文件,无法恢复。",
|
|
||||||
"删除确认",
|
|
||||||
MessageBoxButton.YesNo,
|
|
||||||
MessageBoxImage.Warning);
|
|
||||||
|
|
||||||
if (result == MessageBoxResult.Yes)
|
|
||||||
{
|
|
||||||
// 删除插件
|
|
||||||
bool success = PluginManager.Instance.DeletePlugin(SelectedPlugin);
|
|
||||||
|
|
||||||
if (success)
|
|
||||||
{
|
|
||||||
// 刷新插件列表
|
|
||||||
LoadPlugins();
|
|
||||||
|
|
||||||
// 如果还有插件,选择第一个
|
|
||||||
if (Plugins.Count > 0)
|
|
||||||
{
|
|
||||||
PluginListView.SelectedIndex = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
MessageBox.Show($"插件 {pluginName} 已成功删除。", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
MessageBox.Show($"删除插件 {pluginName} 失败,请稍后重试。", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导出插件按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnExportPlugin_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 检查是否有选中的插件
|
|
||||||
if (SelectedPlugin == null)
|
|
||||||
{
|
|
||||||
MessageBox.Show("请先选择要导出的插件", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查是否为内置插件
|
|
||||||
if (SelectedPlugin.IsBuiltIn)
|
|
||||||
{
|
|
||||||
MessageBox.Show("内置插件无法导出", "提示", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查插件文件是否存在
|
|
||||||
string pluginPath = null;
|
|
||||||
if (SelectedPlugin is PluginBase pluginBase)
|
|
||||||
{
|
|
||||||
pluginPath = pluginBase.PluginPath;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (string.IsNullOrEmpty(pluginPath) || !File.Exists(pluginPath))
|
|
||||||
{
|
|
||||||
MessageBox.Show("插件文件不存在或无法访问", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 创建保存文件对话框
|
|
||||||
SaveFileDialog dialog = new SaveFileDialog
|
|
||||||
{
|
|
||||||
Filter = "ICC插件文件(*.iccpp)|*.iccpp",
|
|
||||||
Title = "导出插件",
|
|
||||||
FileName = Path.GetFileName(pluginPath)
|
|
||||||
};
|
|
||||||
|
|
||||||
// 显示对话框
|
|
||||||
if (dialog.ShowDialog() == true)
|
|
||||||
{
|
|
||||||
// 获取目标路径
|
|
||||||
string targetPath = dialog.FileName;
|
|
||||||
|
|
||||||
// 如果目标文件已存在,询问是否覆盖
|
|
||||||
if (File.Exists(targetPath) && !string.Equals(pluginPath, targetPath, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
MessageBoxResult result = MessageBox.Show("目标文件已存在,是否覆盖?", "确认", MessageBoxButton.YesNo, MessageBoxImage.Question);
|
|
||||||
if (result != MessageBoxResult.Yes)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 复制插件文件到目标路径
|
|
||||||
if (!string.Equals(pluginPath, targetPath, StringComparison.OrdinalIgnoreCase))
|
|
||||||
{
|
|
||||||
File.Copy(pluginPath, targetPath, true);
|
|
||||||
}
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"插件 {SelectedPlugin.Name} 已成功导出到: {targetPath}");
|
|
||||||
MessageBox.Show($"插件 {SelectedPlugin.Name} 已成功导出!", "成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"导出插件时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"导出插件时发生错误: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件开关切换事件
|
|
||||||
/// </summary>
|
|
||||||
private void PluginToggleSwitch_Toggled(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (sender is ToggleSwitch toggleSwitch &&
|
|
||||||
toggleSwitch.Tag is IPlugin plugin)
|
|
||||||
{
|
|
||||||
// 记录当前开关状态
|
|
||||||
bool targetState = toggleSwitch.IsOn;
|
|
||||||
|
|
||||||
// 记录插件类型名称和名称,用于稍后查找重载后的插件
|
|
||||||
string pluginTypeName = plugin.GetType().FullName;
|
|
||||||
string pluginName = plugin.Name;
|
|
||||||
bool wasBuiltIn = plugin.IsBuiltIn;
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"UI开关切换: {pluginName}, 目标状态: {(targetState ? "启用" : "禁用")}");
|
|
||||||
|
|
||||||
// 切换插件状态
|
|
||||||
PluginManager.Instance.TogglePlugin(plugin, targetState);
|
|
||||||
|
|
||||||
// 立即同步保存配置到文件(确保状态被立即持久化)
|
|
||||||
PluginManager.Instance.SaveConfig();
|
|
||||||
LogHelper.WriteLogToFile("插件状态已立即保存到配置文件");
|
|
||||||
|
|
||||||
// 延迟一下再检查状态,确保变更已应用
|
|
||||||
Dispatcher.BeginInvoke(new Action(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 查找最新的插件实例
|
|
||||||
IPlugin currentPlugin = null;
|
|
||||||
foreach (var p in PluginManager.Instance.Plugins)
|
|
||||||
{
|
|
||||||
if (p.GetType().FullName == pluginTypeName || p.Name == pluginName)
|
|
||||||
{
|
|
||||||
currentPlugin = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (currentPlugin == null)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"无法找到插件: {pluginName},UI状态可能不准确", LogHelper.LogType.Warning);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 检查实际状态
|
|
||||||
bool actualState = currentPlugin is PluginBase pb && pb.IsEnabled;
|
|
||||||
LogHelper.WriteLogToFile($"插件 {pluginName} 实际状态: {(actualState ? "启用" : "禁用")}");
|
|
||||||
|
|
||||||
// 更新视图模型
|
|
||||||
PluginViewModel viewModel = null;
|
|
||||||
if (toggleSwitch.DataContext is PluginViewModel vm)
|
|
||||||
{
|
|
||||||
viewModel = vm;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
viewModel = Plugins.FirstOrDefault(p => p.Plugin == currentPlugin);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (viewModel != null)
|
|
||||||
{
|
|
||||||
// 确保视图模型状态与实际状态一致
|
|
||||||
if (viewModel.IsEnabled != actualState)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"同步视图模型状态: {(actualState ? "启用" : "禁用")}");
|
|
||||||
viewModel.IsEnabled = actualState;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保UI开关状态与实际状态一致
|
|
||||||
if (toggleSwitch.IsOn != actualState)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"同步UI开关状态: {(actualState ? "启用" : "禁用")}");
|
|
||||||
toggleSwitch.IsOn = actualState;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果是当前选中的插件,更新属性
|
|
||||||
if (currentPlugin == SelectedPlugin)
|
|
||||||
{
|
|
||||||
OnPropertyChanged(nameof(IsEnabled));
|
|
||||||
}
|
|
||||||
|
|
||||||
// 对于内置插件,特别处理
|
|
||||||
if (wasBuiltIn)
|
|
||||||
{
|
|
||||||
// 特殊插件刷新逻辑,如果是超级启动台插件,立即刷新UI
|
|
||||||
if (currentPlugin is SuperLauncherPlugin &&
|
|
||||||
PluginSettingsContainer.Content is LauncherSettingsControl)
|
|
||||||
{
|
|
||||||
// 重新获取设置界面
|
|
||||||
PluginSettingsContainer.Content = currentPlugin.GetSettingsView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
LogHelper.WriteLogToFile($"插件 {pluginName} UI状态同步完成");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"同步UI状态时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}), DispatcherPriority.Background);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"切换插件状态时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"切换插件状态时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 刷新插件列表按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void Button_Refresh_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
// 刷新插件列表
|
|
||||||
RefreshPluginList();
|
|
||||||
LogHelper.WriteLogToFile("用户点击刷新按钮,刷新插件列表");
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"刷新插件列表时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
MessageBox.Show($"刷新插件列表时出错: {ex.Message}", "错误", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存插件状态按钮点击事件
|
|
||||||
/// </summary>
|
|
||||||
private void BtnSaveConfig_Click(object sender, RoutedEventArgs e)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
int syncCount = 0;
|
|
||||||
|
|
||||||
// 遍历界面上所有插件视图模型,获取开关状态
|
|
||||||
foreach (var viewModel in Plugins)
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (viewModel.Plugin != null)
|
|
||||||
{
|
|
||||||
// 获取UI中开关的当前状态(从界面控件读取)
|
|
||||||
bool uiState = viewModel.IsEnabled;
|
|
||||||
|
|
||||||
// 获取插件类型名,用于查找配置
|
|
||||||
string pluginTypeName = viewModel.Plugin.GetType().FullName;
|
|
||||||
|
|
||||||
// 查找实际的插件实例(可能与viewModel.Plugin不同,因为可能已经重新加载)
|
|
||||||
IPlugin actualPlugin = null;
|
|
||||||
foreach (var p in PluginManager.Instance.Plugins)
|
|
||||||
{
|
|
||||||
if (p.GetType().FullName == pluginTypeName)
|
|
||||||
{
|
|
||||||
actualPlugin = p;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果找不到对应的实际插件实例,跳过
|
|
||||||
if (actualPlugin == null)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"手动保存:无法找到与UI对应的插件实例:{viewModel.Name}", LogHelper.LogType.Warning);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 获取插件实际状态
|
|
||||||
bool pluginState = false;
|
|
||||||
if (actualPlugin is PluginBase pluginBase)
|
|
||||||
{
|
|
||||||
pluginState = pluginBase.IsEnabled;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 如果界面状态与插件实际状态不一致,应用界面状态
|
|
||||||
if (uiState != pluginState)
|
|
||||||
{
|
|
||||||
// 应用界面的状态到插件
|
|
||||||
PluginManager.Instance.TogglePlugin(actualPlugin, uiState);
|
|
||||||
LogHelper.WriteLogToFile($"手动保存:同步插件 {actualPlugin.Name} 状态 {pluginState} -> {uiState}");
|
|
||||||
syncCount++;
|
|
||||||
}
|
|
||||||
|
|
||||||
// 确保配置中的状态也与界面一致
|
|
||||||
if (PluginManager.Instance.PluginStates.TryGetValue(pluginTypeName, out bool configState) && configState != uiState)
|
|
||||||
{
|
|
||||||
PluginManager.Instance.PluginStates[pluginTypeName] = uiState;
|
|
||||||
LogHelper.WriteLogToFile($"手动保存:更新配置中插件 {actualPlugin.Name} 状态 {configState} -> {uiState}");
|
|
||||||
syncCount++;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch (Exception pluginEx)
|
|
||||||
{
|
|
||||||
// 单个插件处理失败不应该影响其他插件
|
|
||||||
LogHelper.WriteLogToFile($"手动保存:处理插件 {viewModel.Name} 时出错: {pluginEx.Message}", LogHelper.LogType.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// 保存插件状态配置
|
|
||||||
PluginManager.Instance.SaveConfig();
|
|
||||||
|
|
||||||
// 记录日志
|
|
||||||
LogHelper.WriteLogToFile($"用户手动保存插件状态配置,同步了 {syncCount} 个状态变更");
|
|
||||||
|
|
||||||
// 刷新插件列表,确保UI与最新状态同步
|
|
||||||
RefreshPluginList();
|
|
||||||
|
|
||||||
// 显示保存成功提示
|
|
||||||
string message = syncCount > 0
|
|
||||||
? $"插件状态已成功保存,同步了 {syncCount} 个状态变更"
|
|
||||||
: "插件状态已成功保存,所有插件状态已是最新";
|
|
||||||
MessageBox.Show(message, "保存成功", MessageBoxButton.OK, MessageBoxImage.Information);
|
|
||||||
}
|
|
||||||
catch (Exception ex)
|
|
||||||
{
|
|
||||||
// 记录错误日志
|
|
||||||
LogHelper.WriteLogToFile($"手动保存插件状态时出错: {ex.Message}", LogHelper.LogType.Error);
|
|
||||||
|
|
||||||
// 显示错误信息
|
|
||||||
MessageBox.Show($"保存插件状态时发生错误: {ex.Message}", "保存失败", MessageBoxButton.OK, MessageBoxImage.Error);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件视图模型
|
|
||||||
/// </summary>
|
|
||||||
public class PluginViewModel : INotifyPropertyChanged
|
|
||||||
{
|
|
||||||
public event PropertyChangedEventHandler PropertyChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件实例
|
|
||||||
/// </summary>
|
|
||||||
public IPlugin Plugin { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件名称
|
|
||||||
/// </summary>
|
|
||||||
public string Name
|
|
||||||
{
|
|
||||||
get
|
|
||||||
{
|
|
||||||
string name = Plugin?.Name ?? "未命名插件";
|
|
||||||
LogHelper.WriteLogToFile($"获取插件名称: {name},类型: {Plugin?.GetType().FullName ?? "未知"}");
|
|
||||||
return name;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件是否启用
|
|
||||||
/// </summary>
|
|
||||||
private bool _isEnabled;
|
|
||||||
public bool IsEnabled
|
|
||||||
{
|
|
||||||
get => _isEnabled;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_isEnabled != value)
|
|
||||||
{
|
|
||||||
_isEnabled = value;
|
|
||||||
OnPropertyChanged(nameof(IsEnabled));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public PluginViewModel(IPlugin plugin)
|
|
||||||
{
|
|
||||||
Plugin = plugin;
|
|
||||||
|
|
||||||
// 获取实际状态
|
|
||||||
_isEnabled = plugin is PluginBase pluginBase && pluginBase.IsEnabled;
|
|
||||||
|
|
||||||
// 记录日志
|
|
||||||
LogHelper.WriteLogToFile($"创建插件视图模型: {plugin?.GetType().FullName ?? "未知"}, 名称: {plugin?.Name ?? "未命名"}");
|
|
||||||
|
|
||||||
// 注册插件状态变更事件
|
|
||||||
if (plugin is PluginBase pb)
|
|
||||||
{
|
|
||||||
pb.EnabledStateChanged += Plugin_EnabledStateChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 处理插件状态变更事件
|
|
||||||
/// </summary>
|
|
||||||
private void Plugin_EnabledStateChanged(object sender, bool isEnabled)
|
|
||||||
{
|
|
||||||
// 在UI线程上更新状态
|
|
||||||
Application.Current.Dispatcher.BeginInvoke(new Action(() =>
|
|
||||||
{
|
|
||||||
IsEnabled = isEnabled;
|
|
||||||
|
|
||||||
// 确保配置立即保存
|
|
||||||
if (sender is IPlugin plugin)
|
|
||||||
{
|
|
||||||
LogHelper.WriteLogToFile($"视图模型捕获到插件 {plugin.Name} 状态变更: {(isEnabled ? "启用" : "禁用")}");
|
|
||||||
PluginManager.Instance.SaveConfig();
|
|
||||||
LogHelper.WriteLogToFile("视图模型已触发配置保存");
|
|
||||||
}
|
|
||||||
}));
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 属性变更通知
|
|
||||||
/// </summary>
|
|
||||||
protected void OnPropertyChanged(string propertyName)
|
|
||||||
{
|
|
||||||
PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(propertyName));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -142,15 +142,6 @@
|
|||||||
</StackPanel>
|
</StackPanel>
|
||||||
</Border>
|
</Border>
|
||||||
|
|
||||||
<!-- 插件管理 -->
|
|
||||||
<Border Margin="0,25,0,0" BorderBrush="#e6e6e6" BorderThickness="1.25,1.25,1.25,4" CornerRadius="8">
|
|
||||||
<StackPanel Orientation="Vertical" Margin="18,18,18,18">
|
|
||||||
<TextBlock Text="通过插件扩展InkCanvas的功能。您可以启用或禁用插件,或加载自定义插件。"
|
|
||||||
TextWrapping="Wrap" Foreground="#9a9996" FontSize="11" Margin="0,0,0,12"/>
|
|
||||||
<Button x:Name="BtnOpenPluginManager" Content="打开插件管理器"
|
|
||||||
HorizontalAlignment="Left" Padding="15,5"/>
|
|
||||||
</StackPanel>
|
|
||||||
</Border>
|
|
||||||
</StackPanel>
|
</StackPanel>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</UserControl>
|
</UserControl>
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Collections.ObjectModel;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using InkCanvasForClass.PluginSdk;
|
|
||||||
|
|
||||||
namespace InkCanvasForClass.PluginHost
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 收集插件登记的菜单 / 工具栏 / 设置页,供宿主窗口在启动后统一挂载。
|
|
||||||
/// </summary>
|
|
||||||
public sealed class CollectingPluginRegistry : IPluginRegistry
|
|
||||||
{
|
|
||||||
private string _currentPluginId = "";
|
|
||||||
|
|
||||||
public string CurrentPluginId => _currentPluginId;
|
|
||||||
|
|
||||||
public ObservableCollection<MenuItemRegistration> MenuItems { get; } =
|
|
||||||
new ObservableCollection<MenuItemRegistration>();
|
|
||||||
|
|
||||||
public ObservableCollection<ToolbarButtonRegistration> ToolbarButtons { get; } =
|
|
||||||
new ObservableCollection<ToolbarButtonRegistration>();
|
|
||||||
|
|
||||||
public ObservableCollection<SettingsPageRegistration> SettingsPages { get; } =
|
|
||||||
new ObservableCollection<SettingsPageRegistration>();
|
|
||||||
|
|
||||||
public void SetCurrentPluginId(string pluginId)
|
|
||||||
{
|
|
||||||
_currentPluginId = pluginId ?? "";
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterMenuItem(string groupKey, MenuItem item)
|
|
||||||
{
|
|
||||||
if (item == null) return;
|
|
||||||
MenuItems.Add(new MenuItemRegistration(_currentPluginId, groupKey ?? "", item));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterToolbarButton(Button button)
|
|
||||||
{
|
|
||||||
if (button == null) return;
|
|
||||||
ToolbarButtons.Add(new ToolbarButtonRegistration(_currentPluginId, button));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void RegisterSettingsPage(string pageId, string displayName, Func<UserControl> createView)
|
|
||||||
{
|
|
||||||
if (string.IsNullOrWhiteSpace(pageId) || createView == null) return;
|
|
||||||
SettingsPages.Add(new SettingsPageRegistration(
|
|
||||||
_currentPluginId,
|
|
||||||
pageId,
|
|
||||||
displayName ?? pageId,
|
|
||||||
createView));
|
|
||||||
}
|
|
||||||
|
|
||||||
public void Clear()
|
|
||||||
{
|
|
||||||
MenuItems.Clear();
|
|
||||||
ToolbarButtons.Clear();
|
|
||||||
SettingsPages.Clear();
|
|
||||||
_currentPluginId = "";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class MenuItemRegistration
|
|
||||||
{
|
|
||||||
public MenuItemRegistration(string pluginId, string groupKey, MenuItem item)
|
|
||||||
{
|
|
||||||
PluginId = pluginId ?? "";
|
|
||||||
GroupKey = groupKey ?? "";
|
|
||||||
Item = item ?? throw new ArgumentNullException(nameof(item));
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PluginId { get; }
|
|
||||||
public string GroupKey { get; }
|
|
||||||
public MenuItem Item { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class ToolbarButtonRegistration
|
|
||||||
{
|
|
||||||
public ToolbarButtonRegistration(string pluginId, Button button)
|
|
||||||
{
|
|
||||||
PluginId = pluginId ?? "";
|
|
||||||
Button = button ?? throw new ArgumentNullException(nameof(button));
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PluginId { get; }
|
|
||||||
public Button Button { get; }
|
|
||||||
}
|
|
||||||
|
|
||||||
public sealed class SettingsPageRegistration
|
|
||||||
{
|
|
||||||
public SettingsPageRegistration(string pluginId, string pageId, string displayName, Func<UserControl> createView)
|
|
||||||
{
|
|
||||||
PluginId = pluginId ?? "";
|
|
||||||
PageId = pageId ?? "";
|
|
||||||
DisplayName = displayName ?? "";
|
|
||||||
CreateView = createView ?? throw new ArgumentNullException(nameof(createView));
|
|
||||||
}
|
|
||||||
|
|
||||||
public string PluginId { get; }
|
|
||||||
public string PageId { get; }
|
|
||||||
public string DisplayName { get; }
|
|
||||||
public Func<UserControl> CreateView { get; }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<RootNamespace>InkCanvasForClass.PluginHost</RootNamespace>
|
|
||||||
<AssemblyName>InkCanvas.PluginHost</AssemblyName>
|
|
||||||
<LangVersion>7.3</LangVersion>
|
|
||||||
<Nullable>disable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\SDK\InkCanvas.PluginSdk.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,103 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace InkCanvasForClass.PluginSdk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Ink Canvas 插件接口
|
|
||||||
/// </summary>
|
|
||||||
public interface IInkCanvasPlugin
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 插件唯一标识符
|
|
||||||
/// </summary>
|
|
||||||
string Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件名称
|
|
||||||
/// </summary>
|
|
||||||
string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件描述
|
|
||||||
/// </summary>
|
|
||||||
string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件版本
|
|
||||||
/// </summary>
|
|
||||||
Version Version { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件作者
|
|
||||||
/// </summary>
|
|
||||||
string Author { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件主页URL
|
|
||||||
/// </summary>
|
|
||||||
string Homepage { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件图标
|
|
||||||
/// </summary>
|
|
||||||
ImageSource Icon { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件初始化
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">插件上下文</param>
|
|
||||||
void Initialize(IPluginContext context);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件启动
|
|
||||||
/// </summary>
|
|
||||||
void Start();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件停止
|
|
||||||
/// </summary>
|
|
||||||
void Stop();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件清理
|
|
||||||
/// </summary>
|
|
||||||
void Cleanup();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件设置界面
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>设置界面控件</returns>
|
|
||||||
UserControl GetSettingsView();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件菜单项
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>菜单项列表</returns>
|
|
||||||
IEnumerable<MenuItem> GetMenuItems();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件工具栏按钮
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>工具栏按钮列表</returns>
|
|
||||||
IEnumerable<Button> GetToolbarButtons();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件状态栏信息
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>状态栏信息</returns>
|
|
||||||
string GetStatusBarInfo();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件是否已启用
|
|
||||||
/// </summary>
|
|
||||||
bool IsEnabled { get; set; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件启用状态变更事件
|
|
||||||
/// </summary>
|
|
||||||
event EventHandler<bool> EnabledChanged;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,569 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Ink;
|
|
||||||
|
|
||||||
namespace InkCanvasForClass.PluginSdk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 插件上下文接口,提供对主应用程序功能的访问
|
|
||||||
/// </summary>
|
|
||||||
public interface IPluginContext
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 主窗口实例
|
|
||||||
/// </summary>
|
|
||||||
Window MainWindow { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前画布
|
|
||||||
/// </summary>
|
|
||||||
System.Windows.Controls.InkCanvas CurrentCanvas { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 所有画布页面
|
|
||||||
/// </summary>
|
|
||||||
IList<System.Windows.Controls.Canvas> AllCanvasPages { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前页面索引
|
|
||||||
/// </summary>
|
|
||||||
int CurrentPageIndex { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 总页面数
|
|
||||||
/// </summary>
|
|
||||||
int TotalPageCount { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 浮动工具栏
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement FloatingToolBar { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 左侧面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement LeftPanel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 右侧面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement RightPanel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 顶部面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement TopPanel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 底部面板
|
|
||||||
/// </summary>
|
|
||||||
FrameworkElement BottomPanel { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前绘制模式
|
|
||||||
/// </summary>
|
|
||||||
int CurrentDrawingMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前墨迹宽度
|
|
||||||
/// </summary>
|
|
||||||
double CurrentInkWidth { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前墨迹颜色
|
|
||||||
/// </summary>
|
|
||||||
Color CurrentInkColor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前高亮笔宽度
|
|
||||||
/// </summary>
|
|
||||||
double CurrentHighlighterWidth { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前橡皮擦大小
|
|
||||||
/// </summary>
|
|
||||||
int CurrentEraserSize { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前橡皮擦类型
|
|
||||||
/// </summary>
|
|
||||||
int CurrentEraserType { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前橡皮擦形状
|
|
||||||
/// </summary>
|
|
||||||
int CurrentEraserShape { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前墨迹透明度
|
|
||||||
/// </summary>
|
|
||||||
double CurrentInkAlpha { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前墨迹样式
|
|
||||||
/// </summary>
|
|
||||||
int CurrentInkStyle { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 当前背景颜色
|
|
||||||
/// </summary>
|
|
||||||
string CurrentBackgroundColor { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为深色主题
|
|
||||||
/// </summary>
|
|
||||||
bool IsDarkTheme { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为白板模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsWhiteboardMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为PPT模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsPPTMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为全屏模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsFullScreenMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为画布模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsCanvasMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为选择模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsSelectionMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为橡皮擦模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsEraserMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为形状绘制模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsShapeDrawingMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否为高亮笔模式
|
|
||||||
/// </summary>
|
|
||||||
bool IsHighlighterMode { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否可以撤销
|
|
||||||
/// </summary>
|
|
||||||
bool CanUndo { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 是否可以重做
|
|
||||||
/// </summary>
|
|
||||||
bool CanRedo { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取设置值
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">设置类型</typeparam>
|
|
||||||
/// <param name="key">设置键</param>
|
|
||||||
/// <param name="defaultValue">默认值</param>
|
|
||||||
/// <returns>设置值</returns>
|
|
||||||
T GetSetting<T>(string key, T defaultValue = default(T));
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置设置值
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">设置类型</typeparam>
|
|
||||||
/// <param name="key">设置键</param>
|
|
||||||
/// <param name="value">设置值</param>
|
|
||||||
void SetSetting<T>(string key, T value);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存设置
|
|
||||||
/// </summary>
|
|
||||||
void SaveSettings();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载设置
|
|
||||||
/// </summary>
|
|
||||||
void LoadSettings();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重置设置
|
|
||||||
/// </summary>
|
|
||||||
void ResetSettings();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取所有插件
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>插件列表</returns>
|
|
||||||
IList<IInkCanvasPlugin> GetAllPlugins();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 根据名称获取插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
/// <returns>插件实例</returns>
|
|
||||||
IInkCanvasPlugin GetPlugin(string pluginName);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
void EnablePlugin(string pluginName);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 禁用插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
void DisablePlugin(string pluginName);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 卸载插件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pluginName">插件名称</param>
|
|
||||||
void UnloadPlugin(string pluginName);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void HideSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示插件设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowPluginSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏插件设置窗口
|
|
||||||
/// </summary>
|
|
||||||
void HidePluginSettingsWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示帮助窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowHelpWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏帮助窗口
|
|
||||||
/// </summary>
|
|
||||||
void HideHelpWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示关于窗口
|
|
||||||
/// </summary>
|
|
||||||
void ShowAboutWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 隐藏关于窗口
|
|
||||||
/// </summary>
|
|
||||||
void HideAboutWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示通知
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">消息内容</param>
|
|
||||||
/// <param name="type">通知类型</param>
|
|
||||||
void ShowNotification(string message, NotificationType type = NotificationType.Info);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示确认对话框
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">消息内容</param>
|
|
||||||
/// <param name="title">标题</param>
|
|
||||||
/// <returns>用户选择结果</returns>
|
|
||||||
bool ShowConfirmDialog(string message, string title = "确认");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示输入对话框
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">提示消息</param>
|
|
||||||
/// <param name="title">标题</param>
|
|
||||||
/// <param name="defaultValue">默认值</param>
|
|
||||||
/// <returns>用户输入内容</returns>
|
|
||||||
string ShowInputDialog(string message, string title = "输入", string defaultValue = "");
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置全屏模式
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isFullScreen">是否全屏</param>
|
|
||||||
void SetFullScreen(bool isFullScreen);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置置顶模式
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isTopMost">是否置顶</param>
|
|
||||||
void SetTopMost(bool isTopMost);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口可见性
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isVisible">是否可见</param>
|
|
||||||
void SetWindowVisibility(bool isVisible);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 最小化窗口
|
|
||||||
/// </summary>
|
|
||||||
void MinimizeWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 最大化窗口
|
|
||||||
/// </summary>
|
|
||||||
void MaximizeWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 还原窗口
|
|
||||||
/// </summary>
|
|
||||||
void RestoreWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 关闭窗口
|
|
||||||
/// </summary>
|
|
||||||
void CloseWindow();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口位置
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="x">X坐标</param>
|
|
||||||
/// <param name="y">Y坐标</param>
|
|
||||||
void SetWindowPosition(double x, double y);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置窗口大小
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">宽度</param>
|
|
||||||
/// <param name="height">高度</param>
|
|
||||||
void SetWindowSize(double width, double height);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取窗口位置
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>窗口位置</returns>
|
|
||||||
(double x, double y) GetWindowPosition();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取窗口大小
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>窗口大小</returns>
|
|
||||||
(double width, double height) GetWindowSize();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清除当前画布
|
|
||||||
/// </summary>
|
|
||||||
void ClearCanvas();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 清除所有画布
|
|
||||||
/// </summary>
|
|
||||||
void ClearAllCanvases();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 添加新页面
|
|
||||||
/// </summary>
|
|
||||||
void AddNewPage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除当前页面
|
|
||||||
/// </summary>
|
|
||||||
void DeleteCurrentPage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 切换到指定页面
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="pageIndex">页面索引</param>
|
|
||||||
void SwitchToPage(int pageIndex);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 下一页
|
|
||||||
/// </summary>
|
|
||||||
void NextPage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 上一页
|
|
||||||
/// </summary>
|
|
||||||
void PreviousPage();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置绘制模式
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="mode">绘制模式</param>
|
|
||||||
void SetDrawingMode(int mode);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置墨迹宽度
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">宽度</param>
|
|
||||||
void SetInkWidth(double width);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置墨迹颜色
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">颜色</param>
|
|
||||||
void SetInkColor(Color color);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置高亮笔宽度
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="width">宽度</param>
|
|
||||||
void SetHighlighterWidth(double width);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置橡皮擦大小
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="size">大小</param>
|
|
||||||
void SetEraserSize(int size);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置橡皮擦类型
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="type">类型</param>
|
|
||||||
void SetEraserType(int type);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置橡皮擦形状
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="shape">形状</param>
|
|
||||||
void SetEraserShape(int shape);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置墨迹透明度
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="alpha">透明度</param>
|
|
||||||
void SetInkAlpha(double alpha);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置墨迹样式
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="style">样式</param>
|
|
||||||
void SetInkStyle(int style);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置背景颜色
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="color">颜色</param>
|
|
||||||
void SetBackgroundColor(string color);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存画布
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
void SaveCanvas(string filePath);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 加载画布
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
void LoadCanvas(string filePath);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导出为图片
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
/// <param name="format">格式</param>
|
|
||||||
void ExportAsImage(string filePath, string format);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 导出为PDF
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="filePath">文件路径</param>
|
|
||||||
void ExportAsPDF(string filePath);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 撤销操作
|
|
||||||
/// </summary>
|
|
||||||
void Undo();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重做操作
|
|
||||||
/// </summary>
|
|
||||||
void Redo();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 全选
|
|
||||||
/// </summary>
|
|
||||||
void SelectAll();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 取消选择
|
|
||||||
/// </summary>
|
|
||||||
void DeselectAll();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 删除选中项
|
|
||||||
/// </summary>
|
|
||||||
void DeleteSelected();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 复制选中项
|
|
||||||
/// </summary>
|
|
||||||
void CopySelected();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 剪切选中项
|
|
||||||
/// </summary>
|
|
||||||
void CutSelected();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 粘贴
|
|
||||||
/// </summary>
|
|
||||||
void Paste();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册事件处理器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="handler">事件处理器</param>
|
|
||||||
void RegisterEventHandler(string eventName, EventHandler handler);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注销事件处理器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="handler">事件处理器</param>
|
|
||||||
void UnregisterEventHandler(string eventName, EventHandler handler);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 触发事件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="sender">事件发送者</param>
|
|
||||||
/// <param name="args">事件参数</param>
|
|
||||||
void TriggerEvent(string eventName, object sender, EventArgs args);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 重启应用程序
|
|
||||||
/// </summary>
|
|
||||||
void RestartApplication();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 退出应用程序
|
|
||||||
/// </summary>
|
|
||||||
void ExitApplication();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 检查更新
|
|
||||||
/// </summary>
|
|
||||||
void CheckForUpdates();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 打开帮助文档
|
|
||||||
/// </summary>
|
|
||||||
void OpenHelpDocument();
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 打开关于页面
|
|
||||||
/// </summary>
|
|
||||||
void OpenAboutPage();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace InkCanvasForClass.PluginSdk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 方案 B:不依赖 Microsoft.Extensions.DependencyInjection 的轻量扩展注册表。
|
|
||||||
/// 宿主在适当时机将登记项挂到菜单 / 工具栏 / 设置 UI。
|
|
||||||
/// </summary>
|
|
||||||
public interface IPluginRegistry
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 当前正在执行注册的插件目录 Id(由宿主在加载每个插件前设置)。
|
|
||||||
/// </summary>
|
|
||||||
string CurrentPluginId { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册主菜单或上下文菜单中的项;<paramref name="groupKey"/> 由宿主解释(如 "Main.Plugins")。
|
|
||||||
/// </summary>
|
|
||||||
void RegisterMenuItem(string groupKey, MenuItem item);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册工具栏按钮。
|
|
||||||
/// </summary>
|
|
||||||
void RegisterToolbarButton(Button button);
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册设置页;<paramref name="createView"/> 在打开设置时惰性创建。
|
|
||||||
/// </summary>
|
|
||||||
void RegisterSettingsPage(string pageId, string displayName, Func<UserControl> createView);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<RootNamespace>InkCanvasForClass.PluginSdk</RootNamespace>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
|
|
||||||
<PackageId>InkCanvas.PluginSdk</PackageId>
|
|
||||||
<PackageVersion>1.0.0</PackageVersion>
|
|
||||||
<Authors>Ink Canvas Team</Authors>
|
|
||||||
<Company>Ink Canvas</Company>
|
|
||||||
<Product>Ink Canvas Plugin SDK</Product>
|
|
||||||
<Description>SDK for developing Ink Canvas plugins - 墨迹画布插件开发SDK</Description>
|
|
||||||
<PackageProjectUrl>https://github.com/your-org/ink-canvas</PackageProjectUrl>
|
|
||||||
<RepositoryUrl>https://github.com/your-org/ink-canvas</RepositoryUrl>
|
|
||||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
|
||||||
<PackageTags>ink;canvas;plugin;sdk;wpf;drawing</PackageTags>
|
|
||||||
<Copyright>Copyright © 2025</Copyright>
|
|
||||||
<AssemblyVersion>1.0.0.0</AssemblyVersion>
|
|
||||||
<FileVersion>1.0.0.0</FileVersion>
|
|
||||||
<LangVersion>7.3</LangVersion>
|
|
||||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<None Include="README.md" Pack="true" PackagePath="README.md" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<PackageReference Include="Newtonsoft.Json" Version="13.0.3" />
|
|
||||||
<PackageReference Include="System.ComponentModel.Annotations" Version="5.0.0" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
@@ -1,268 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
|
|
||||||
namespace InkCanvasForClass.PluginSdk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// Ink Canvas 插件基类
|
|
||||||
/// 提供插件的基本实现
|
|
||||||
/// </summary>
|
|
||||||
public abstract class InkCanvasPluginBase : IInkCanvasPlugin
|
|
||||||
{
|
|
||||||
private bool _isEnabled;
|
|
||||||
private IPluginContext _context;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件唯一标识符
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Id { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件名称
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Name { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件描述
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Description { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件版本
|
|
||||||
/// </summary>
|
|
||||||
public abstract Version Version { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件作者
|
|
||||||
/// </summary>
|
|
||||||
public abstract string Author { get; }
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件主页URL
|
|
||||||
/// </summary>
|
|
||||||
public virtual string Homepage => string.Empty;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件图标
|
|
||||||
/// </summary>
|
|
||||||
public virtual ImageSource Icon => null;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件是否已启用
|
|
||||||
/// </summary>
|
|
||||||
public virtual bool IsEnabled
|
|
||||||
{
|
|
||||||
get => _isEnabled;
|
|
||||||
set
|
|
||||||
{
|
|
||||||
if (_isEnabled != value)
|
|
||||||
{
|
|
||||||
_isEnabled = value;
|
|
||||||
OnEnabledChanged(value);
|
|
||||||
EnabledChanged?.Invoke(this, value);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件启用状态变更事件
|
|
||||||
/// </summary>
|
|
||||||
public event EventHandler<bool> EnabledChanged;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件上下文
|
|
||||||
/// </summary>
|
|
||||||
protected IPluginContext Context => _context;
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件初始化
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="context">插件上下文</param>
|
|
||||||
public virtual void Initialize(IPluginContext context)
|
|
||||||
{
|
|
||||||
_context = context;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 方案 B:在 <see cref="Initialize"/> 之后由宿主调用,用于向 <see cref="IPluginRegistry"/> 登记菜单、工具栏、设置页等。
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="registry">宿主提供的注册表</param>
|
|
||||||
public virtual void RegisterExtensions(IPluginRegistry registry)
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件启动
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Start()
|
|
||||||
{
|
|
||||||
// 默认实现为空
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件停止
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Stop()
|
|
||||||
{
|
|
||||||
// 默认实现为空
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 插件清理
|
|
||||||
/// </summary>
|
|
||||||
public virtual void Cleanup()
|
|
||||||
{
|
|
||||||
// 默认实现为空
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件设置界面
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>设置界面控件</returns>
|
|
||||||
public virtual UserControl GetSettingsView()
|
|
||||||
{
|
|
||||||
return new UserControl();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件菜单项
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>菜单项列表</returns>
|
|
||||||
public virtual IEnumerable<MenuItem> GetMenuItems()
|
|
||||||
{
|
|
||||||
return new List<MenuItem>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件工具栏按钮
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>工具栏按钮列表</returns>
|
|
||||||
public virtual IEnumerable<Button> GetToolbarButtons()
|
|
||||||
{
|
|
||||||
return new List<Button>();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取插件状态栏信息
|
|
||||||
/// </summary>
|
|
||||||
/// <returns>状态栏信息</returns>
|
|
||||||
public virtual string GetStatusBarInfo()
|
|
||||||
{
|
|
||||||
return $"{Name} v{Version} - {(IsEnabled ? "已启用" : "已禁用")}";
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 启用状态变更时的处理
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="isEnabled">是否启用</param>
|
|
||||||
protected virtual void OnEnabledChanged(bool isEnabled)
|
|
||||||
{
|
|
||||||
if (isEnabled)
|
|
||||||
{
|
|
||||||
Start();
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示通知
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">消息内容</param>
|
|
||||||
/// <param name="type">通知类型</param>
|
|
||||||
protected void ShowNotification(string message, NotificationType type = NotificationType.Info)
|
|
||||||
{
|
|
||||||
_context?.ShowNotification(message, type);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示确认对话框
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">消息内容</param>
|
|
||||||
/// <param name="title">标题</param>
|
|
||||||
/// <returns>用户选择结果</returns>
|
|
||||||
protected bool ShowConfirmDialog(string message, string title = "确认")
|
|
||||||
{
|
|
||||||
return _context?.ShowConfirmDialog(message, title) ?? false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 显示输入对话框
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="message">提示消息</param>
|
|
||||||
/// <param name="title">标题</param>
|
|
||||||
/// <param name="defaultValue">默认值</param>
|
|
||||||
/// <returns>用户输入内容</returns>
|
|
||||||
protected string ShowInputDialog(string message, string title = "输入", string defaultValue = "")
|
|
||||||
{
|
|
||||||
return _context?.ShowInputDialog(message, title, defaultValue) ?? defaultValue;
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 获取设置值
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">设置类型</typeparam>
|
|
||||||
/// <param name="key">设置键</param>
|
|
||||||
/// <param name="defaultValue">默认值</param>
|
|
||||||
/// <returns>设置值</returns>
|
|
||||||
protected T GetSetting<T>(string key, T defaultValue = default)
|
|
||||||
{
|
|
||||||
if (_context == null) return defaultValue;
|
|
||||||
return _context.GetSetting(key, defaultValue);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 设置设置值
|
|
||||||
/// </summary>
|
|
||||||
/// <typeparam name="T">设置类型</typeparam>
|
|
||||||
/// <param name="key">设置键</param>
|
|
||||||
/// <param name="value">设置值</param>
|
|
||||||
protected void SetSetting<T>(string key, T value)
|
|
||||||
{
|
|
||||||
_context?.SetSetting(key, value);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 保存设置
|
|
||||||
/// </summary>
|
|
||||||
protected void SaveSettings()
|
|
||||||
{
|
|
||||||
_context?.SaveSettings();
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注册事件处理器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="handler">事件处理器</param>
|
|
||||||
protected void RegisterEventHandler(string eventName, EventHandler handler)
|
|
||||||
{
|
|
||||||
_context?.RegisterEventHandler(eventName, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 注销事件处理器
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="handler">事件处理器</param>
|
|
||||||
protected void UnregisterEventHandler(string eventName, EventHandler handler)
|
|
||||||
{
|
|
||||||
_context?.UnregisterEventHandler(eventName, handler);
|
|
||||||
}
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 触发事件
|
|
||||||
/// </summary>
|
|
||||||
/// <param name="eventName">事件名称</param>
|
|
||||||
/// <param name="sender">事件发送者</param>
|
|
||||||
/// <param name="args">事件参数</param>
|
|
||||||
protected void TriggerEvent(string eventName, object sender, EventArgs args)
|
|
||||||
{
|
|
||||||
_context?.TriggerEvent(eventName, sender, args);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,28 +0,0 @@
|
|||||||
namespace InkCanvasForClass.PluginSdk
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 通知类型枚举
|
|
||||||
/// </summary>
|
|
||||||
public enum NotificationType
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 信息
|
|
||||||
/// </summary>
|
|
||||||
Info,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 成功
|
|
||||||
/// </summary>
|
|
||||||
Success,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 警告
|
|
||||||
/// </summary>
|
|
||||||
Warning,
|
|
||||||
|
|
||||||
/// <summary>
|
|
||||||
/// 错误
|
|
||||||
/// </summary>
|
|
||||||
Error
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,160 +0,0 @@
|
|||||||
# Ink Canvas Plugin SDK
|
|
||||||
|
|
||||||
Ink Canvas 插件开发SDK,用于开发墨迹画布应用的插件。
|
|
||||||
|
|
||||||
**命名空间**:`InkCanvasForClass.PluginSdk`(避免与 WPF 控件 `System.Windows.Controls.InkCanvas` 在引用 `InkCanvas.*` 时产生歧义)。
|
|
||||||
|
|
||||||
## 方案 B:轻量注册表(无 Microsoft.Extensions.DependencyInjection)
|
|
||||||
|
|
||||||
宿主在加载每个插件、调用 `Initialize` 之后,会调用 `InkCanvasPluginBase.RegisterExtensions(IPluginRegistry registry)`。插件可在此登记菜单项、工具栏按钮、设置页工厂;宿主窗口稍后统一挂载。注册表实现类型为 `InkCanvasForClass.PluginHost.CollectingPluginRegistry`,由主程序内 `PluginManager.Instance.ExtensionRegistry` 暴露。
|
|
||||||
|
|
||||||
## 安装
|
|
||||||
|
|
||||||
```bash
|
|
||||||
dotnet add package InkCanvas.PluginSdk
|
|
||||||
```
|
|
||||||
|
|
||||||
## 快速开始
|
|
||||||
|
|
||||||
### 1. 创建插件项目
|
|
||||||
|
|
||||||
创建一个新的类库项目,并添加对 `InkCanvas.PluginSdk` 的引用。
|
|
||||||
|
|
||||||
### 2. 实现插件接口
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
using InkCanvas.PluginSdk;
|
|
||||||
using System;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
|
|
||||||
namespace MyPlugin
|
|
||||||
{
|
|
||||||
public class MyPlugin : InkCanvasPluginBase
|
|
||||||
{
|
|
||||||
public override string Id => "com.example.myplugin";
|
|
||||||
public override string Name => "我的插件";
|
|
||||||
public override string Description => "这是一个示例插件";
|
|
||||||
public override Version Version => new Version(1, 0, 0);
|
|
||||||
public override string Author => "插件作者";
|
|
||||||
|
|
||||||
public override void Start()
|
|
||||||
{
|
|
||||||
// 插件启动时的逻辑
|
|
||||||
ShowNotification("插件已启动!", NotificationType.Success);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Stop()
|
|
||||||
{
|
|
||||||
// 插件停止时的逻辑
|
|
||||||
ShowNotification("插件已停止!", NotificationType.Info);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override UserControl GetSettingsView()
|
|
||||||
{
|
|
||||||
// 返回插件设置界面
|
|
||||||
return new MyPluginSettingsView();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
### 3. 插件功能
|
|
||||||
|
|
||||||
#### 访问主应用程序功能
|
|
||||||
|
|
||||||
通过 `Context` 属性可以访问主应用程序的各种功能:
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
// 获取当前画布
|
|
||||||
var canvas = Context.CurrentCanvas;
|
|
||||||
|
|
||||||
// 设置墨迹颜色
|
|
||||||
Context.SetInkColor(Colors.Red);
|
|
||||||
|
|
||||||
// 清除画布
|
|
||||||
Context.ClearCanvas();
|
|
||||||
|
|
||||||
// 显示通知
|
|
||||||
Context.ShowNotification("操作完成!", NotificationType.Success);
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 创建菜单项
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public override IEnumerable<MenuItem> GetMenuItems()
|
|
||||||
{
|
|
||||||
var menuItem = new MenuItem
|
|
||||||
{
|
|
||||||
Header = "我的功能",
|
|
||||||
Icon = new Image { Source = MyIcon }
|
|
||||||
};
|
|
||||||
menuItem.Click += (s, e) => {
|
|
||||||
// 处理菜单点击
|
|
||||||
ShowNotification("菜单被点击了!");
|
|
||||||
};
|
|
||||||
|
|
||||||
return new[] { menuItem };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 创建工具栏按钮
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public override IEnumerable<Button> GetToolbarButtons()
|
|
||||||
{
|
|
||||||
var button = new Button
|
|
||||||
{
|
|
||||||
Content = "我的工具",
|
|
||||||
ToolTip = "这是一个工具按钮"
|
|
||||||
};
|
|
||||||
button.Click += (s, e) => {
|
|
||||||
// 处理按钮点击
|
|
||||||
Context.SetInkColor(Colors.Blue);
|
|
||||||
};
|
|
||||||
|
|
||||||
return new[] { button };
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
#### 事件处理
|
|
||||||
|
|
||||||
```csharp
|
|
||||||
public override void Start()
|
|
||||||
{
|
|
||||||
// 注册事件处理器
|
|
||||||
RegisterEventHandler("CanvasChanged", OnCanvasChanged);
|
|
||||||
RegisterEventHandler("DrawingModeChanged", OnDrawingModeChanged);
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnCanvasChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
ShowNotification("画布已更改");
|
|
||||||
}
|
|
||||||
|
|
||||||
private void OnDrawingModeChanged(object sender, EventArgs e)
|
|
||||||
{
|
|
||||||
ShowNotification($"绘制模式已更改为: {Context.CurrentDrawingMode}");
|
|
||||||
}
|
|
||||||
```
|
|
||||||
|
|
||||||
## API 参考
|
|
||||||
|
|
||||||
### IInkCanvasPlugin 接口
|
|
||||||
|
|
||||||
插件必须实现的主要接口。
|
|
||||||
|
|
||||||
### IPluginContext 接口
|
|
||||||
|
|
||||||
提供对主应用程序功能的访问。
|
|
||||||
|
|
||||||
### InkCanvasPluginBase 基类
|
|
||||||
|
|
||||||
提供插件的基本实现,建议继承此类。
|
|
||||||
|
|
||||||
## 示例插件
|
|
||||||
|
|
||||||
查看 `Examples` 文件夹中的示例插件,了解如何实现各种功能。
|
|
||||||
|
|
||||||
## 许可证
|
|
||||||
|
|
||||||
MIT License
|
|
||||||
@@ -1,137 +0,0 @@
|
|||||||
using System;
|
|
||||||
using System.Windows;
|
|
||||||
using System.Windows.Controls;
|
|
||||||
using System.Windows.Media;
|
|
||||||
using System.Windows.Threading;
|
|
||||||
using InkCanvasForClass.PluginSdk;
|
|
||||||
|
|
||||||
namespace InkCanvasForClass.SamplePlugins
|
|
||||||
{
|
|
||||||
/// <summary>
|
|
||||||
/// 示例插件:在当前 <see cref="InkCanvas"/> 右上角叠加显示实时时钟(不拦截笔触命中)。
|
|
||||||
/// </summary>
|
|
||||||
public sealed class ClockOverlayPlugin : InkCanvasPluginBase
|
|
||||||
{
|
|
||||||
public override string Id => "inkcanvas.sample.clock-overlay";
|
|
||||||
|
|
||||||
public override string Name => "画布时钟示例";
|
|
||||||
|
|
||||||
public override string Description => "在画布右上角显示当前时间(HH:mm:ss)";
|
|
||||||
|
|
||||||
public override Version Version => new Version(1, 0, 0);
|
|
||||||
|
|
||||||
public override string Author => "ICC CE Sample";
|
|
||||||
|
|
||||||
private Border _host;
|
|
||||||
private TextBlock _timeText;
|
|
||||||
private DispatcherTimer _timer;
|
|
||||||
private System.Windows.Controls.InkCanvas _canvas;
|
|
||||||
private SizeChangedEventHandler _sizeHandler;
|
|
||||||
|
|
||||||
public override void Start()
|
|
||||||
{
|
|
||||||
base.Start();
|
|
||||||
|
|
||||||
var mw = Context?.MainWindow;
|
|
||||||
var canvas = Context?.CurrentCanvas as System.Windows.Controls.InkCanvas;
|
|
||||||
if (mw == null || canvas == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
mw.Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
_canvas = canvas;
|
|
||||||
_host = new Border
|
|
||||||
{
|
|
||||||
Background = new SolidColorBrush(Color.FromArgb(170, 32, 32, 36)),
|
|
||||||
CornerRadius = new CornerRadius(8),
|
|
||||||
Padding = new Thickness(12, 8, 12, 8),
|
|
||||||
IsHitTestVisible = false
|
|
||||||
};
|
|
||||||
_timeText = new TextBlock
|
|
||||||
{
|
|
||||||
FontSize = 24,
|
|
||||||
FontWeight = FontWeights.SemiBold,
|
|
||||||
Foreground = Brushes.White,
|
|
||||||
FontFamily = new FontFamily("Segoe UI, Microsoft YaHei UI")
|
|
||||||
};
|
|
||||||
_host.Child = _timeText;
|
|
||||||
Panel.SetZIndex(_host, 10050);
|
|
||||||
|
|
||||||
_canvas.Children.Add(_host);
|
|
||||||
_sizeHandler = (s, e) => Reposition();
|
|
||||||
_canvas.SizeChanged += _sizeHandler;
|
|
||||||
Reposition();
|
|
||||||
|
|
||||||
_timer = new DispatcherTimer { Interval = TimeSpan.FromSeconds(1) };
|
|
||||||
_timer.Tick += (_, __) => Tick();
|
|
||||||
_timer.Start();
|
|
||||||
Tick();
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Tick()
|
|
||||||
{
|
|
||||||
if (_timeText != null)
|
|
||||||
{
|
|
||||||
_timeText.Text = DateTime.Now.ToString("HH:mm:ss");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
private void Reposition()
|
|
||||||
{
|
|
||||||
if (_canvas == null || _host == null)
|
|
||||||
{
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
_host.UpdateLayout();
|
|
||||||
var left = Math.Max(8, _canvas.ActualWidth - _host.ActualWidth - 20);
|
|
||||||
InkCanvas.SetLeft(_host, left);
|
|
||||||
InkCanvas.SetTop(_host, 20);
|
|
||||||
}
|
|
||||||
|
|
||||||
public override void Stop()
|
|
||||||
{
|
|
||||||
var mw = Context?.MainWindow;
|
|
||||||
if (mw != null && (_canvas != null || _host != null))
|
|
||||||
{
|
|
||||||
mw.Dispatcher.Invoke(() =>
|
|
||||||
{
|
|
||||||
try
|
|
||||||
{
|
|
||||||
if (_timer != null)
|
|
||||||
{
|
|
||||||
_timer.Stop();
|
|
||||||
_timer = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_canvas != null && _sizeHandler != null)
|
|
||||||
{
|
|
||||||
_canvas.SizeChanged -= _sizeHandler;
|
|
||||||
_sizeHandler = null;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (_canvas != null && _host != null && _canvas.Children.Contains(_host))
|
|
||||||
{
|
|
||||||
_canvas.Children.Remove(_host);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch
|
|
||||||
{
|
|
||||||
// 避免卸载时异常影响宿主
|
|
||||||
}
|
|
||||||
finally
|
|
||||||
{
|
|
||||||
_host = null;
|
|
||||||
_timeText = null;
|
|
||||||
_canvas = null;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
base.Stop();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,16 +0,0 @@
|
|||||||
<Project Sdk="Microsoft.NET.Sdk">
|
|
||||||
|
|
||||||
<PropertyGroup>
|
|
||||||
<TargetFramework>net472</TargetFramework>
|
|
||||||
<RootNamespace>InkCanvasForClass.SamplePlugins</RootNamespace>
|
|
||||||
<AssemblyName>SampleClockPlugin</AssemblyName>
|
|
||||||
<UseWPF>true</UseWPF>
|
|
||||||
<LangVersion>7.3</LangVersion>
|
|
||||||
<Nullable>disable</Nullable>
|
|
||||||
</PropertyGroup>
|
|
||||||
|
|
||||||
<ItemGroup>
|
|
||||||
<ProjectReference Include="..\..\SDK\InkCanvas.PluginSdk.csproj" />
|
|
||||||
</ItemGroup>
|
|
||||||
|
|
||||||
</Project>
|
|
||||||
Reference in New Issue
Block a user