2025-03-12 14:06:44 +08:00
|
|
|
|
using System;
|
|
|
|
|
|
using System.Drawing;
|
|
|
|
|
|
using System.Windows.Forms;
|
|
|
|
|
|
using System.Collections.Generic;
|
|
|
|
|
|
using System.IO;
|
|
|
|
|
|
using System.Text.Json;
|
|
|
|
|
|
using System.Linq;
|
2025-03-12 15:18:23 +08:00
|
|
|
|
using System.Runtime.InteropServices; // 添加P/Invoke支持
|
|
|
|
|
|
using System.Drawing.Drawing2D; // 添加GDI+支持
|
2025-03-13 14:08:06 +08:00
|
|
|
|
using System.Drawing.Imaging; // 添加图像处理支持
|
2025-03-15 23:50:17 +08:00
|
|
|
|
using Microsoft.Win32;
|
|
|
|
|
|
using System.Diagnostics; // 添加Registry访问支持
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
namespace QuickLauncher
|
|
|
|
|
|
{
|
|
|
|
|
|
public partial class MainForm : Form
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// Windows 11 UI相关
|
|
|
|
|
|
private bool isDarkMode = false;
|
|
|
|
|
|
private Color accentColor = Color.FromArgb(0, 120, 212); // Windows默认蓝色
|
|
|
|
|
|
private readonly Color lightBackColor = Color.FromArgb(243, 243, 243);
|
|
|
|
|
|
private readonly Color darkBackColor = Color.FromArgb(32, 32, 32);
|
|
|
|
|
|
private readonly Color lightTextColor = Color.FromArgb(0, 0, 0);
|
|
|
|
|
|
private readonly Color darkTextColor = Color.FromArgb(255, 255, 255);
|
|
|
|
|
|
private readonly int cornerRadius = 8; // Windows 11圆角半径
|
|
|
|
|
|
|
|
|
|
|
|
// P/Invoke用于实现Windows 11 Mica效果
|
|
|
|
|
|
[DllImport("dwmapi.dll")]
|
|
|
|
|
|
private static extern int DwmSetWindowAttribute(IntPtr hwnd, int attr, ref int attrValue, int attrSize);
|
|
|
|
|
|
|
|
|
|
|
|
// DWM属性常量
|
|
|
|
|
|
private const int DWMWA_USE_IMMERSIVE_DARK_MODE = 20;
|
|
|
|
|
|
private const int DWMWA_MICA_EFFECT = 1029;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加圆角支持的类
|
|
|
|
|
|
private class RoundedPanel : Panel
|
|
|
|
|
|
{
|
|
|
|
|
|
private int _cornerRadius = 8;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
public int CornerRadius
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _cornerRadius; }
|
|
|
|
|
|
set { _cornerRadius = value; Invalidate(); }
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnPaint(e);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-13 14:08:06 +08:00
|
|
|
|
// 设置高质量绘图模式
|
|
|
|
|
|
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
|
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
|
|
|
|
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
|
|
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 创建圆角路径
|
|
|
|
|
|
using (GraphicsPath path = new GraphicsPath())
|
|
|
|
|
|
{
|
|
|
|
|
|
path.AddArc(0, 0, CornerRadius, CornerRadius, 180, 90);
|
|
|
|
|
|
path.AddArc(Width - CornerRadius, 0, CornerRadius, CornerRadius, 270, 90);
|
|
|
|
|
|
path.AddArc(Width - CornerRadius, Height - CornerRadius, CornerRadius, CornerRadius, 0, 90);
|
|
|
|
|
|
path.AddArc(0, Height - CornerRadius, CornerRadius, CornerRadius, 90, 90);
|
|
|
|
|
|
path.CloseAllFigures();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
this.Region = new Region(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 添加圆角按钮支持的类
|
|
|
|
|
|
private class RoundedButton : Button
|
|
|
|
|
|
{
|
|
|
|
|
|
private int _cornerRadius = 8;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
public int CornerRadius
|
|
|
|
|
|
{
|
|
|
|
|
|
get { return _cornerRadius; }
|
|
|
|
|
|
set { _cornerRadius = value; Invalidate(); }
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
protected override void OnPaint(PaintEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnPaint(e);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-13 14:08:06 +08:00
|
|
|
|
// 设置高质量绘图模式
|
|
|
|
|
|
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
|
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
|
|
|
|
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
|
|
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 创建圆角路径
|
|
|
|
|
|
using (GraphicsPath path = new GraphicsPath())
|
|
|
|
|
|
{
|
|
|
|
|
|
path.AddArc(0, 0, CornerRadius, CornerRadius, 180, 90);
|
|
|
|
|
|
path.AddArc(Width - CornerRadius, 0, CornerRadius, CornerRadius, 270, 90);
|
|
|
|
|
|
path.AddArc(Width - CornerRadius, Height - CornerRadius, CornerRadius, CornerRadius, 0, 90);
|
|
|
|
|
|
path.AddArc(0, Height - CornerRadius, CornerRadius, CornerRadius, 90, 90);
|
|
|
|
|
|
path.CloseAllFigures();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
this.Region = new Region(path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 原有的字段
|
2025-03-12 14:06:44 +08:00
|
|
|
|
private Dictionary<string, List<ShortcutItem>> categories;
|
|
|
|
|
|
private string dataFilePath = "shortcuts.json";
|
|
|
|
|
|
private string settingsFilePath = "settings.json";
|
|
|
|
|
|
private const int CATEGORY_BUTTON_HEIGHT = 40;
|
|
|
|
|
|
private string currentCategory = "";
|
|
|
|
|
|
private ContextMenuStrip categoryContextMenu;
|
|
|
|
|
|
private ContextMenuStrip shortcutsPanelContextMenu;
|
|
|
|
|
|
private ContextMenuStrip shortcutItemContextMenu;
|
|
|
|
|
|
private int iconSize = 48; // 默认图标大小
|
|
|
|
|
|
private const int MIN_ICON_SIZE = 24; // 最小图标大小
|
|
|
|
|
|
private const int MAX_ICON_SIZE = 256; // 增加最大图标大小到256
|
|
|
|
|
|
private const int ICON_SIZE_STEP = 16; // 增加每次缩放的步长
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 左侧面板调整相关
|
|
|
|
|
|
private bool isResizing = false;
|
2025-03-17 23:34:35 +08:00
|
|
|
|
private int resizingStartX = 5;
|
|
|
|
|
|
private int initialPanelWidth = 5;
|
2025-03-12 15:18:23 +08:00
|
|
|
|
private const int MIN_PANEL_WIDTH = 200;
|
|
|
|
|
|
private const int MAX_PANEL_WIDTH = 500;
|
|
|
|
|
|
private Panel resizeHandle;
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
// 用于保存设置的类
|
|
|
|
|
|
private class AppSettings
|
|
|
|
|
|
{
|
|
|
|
|
|
public string LastSelectedCategory { get; set; } = "";
|
|
|
|
|
|
public string SortMode { get; set; } = "Name"; // Name, DateAdded
|
|
|
|
|
|
public int IconSize { get; set; } = 48; // 保存图标大小
|
2025-03-12 15:18:23 +08:00
|
|
|
|
public int LeftPanelWidth { get; set; } = 300; // 左侧面板宽度
|
2025-03-13 14:08:06 +08:00
|
|
|
|
public bool EnableAutoDocking { get; set; } = false; // 启用自动停靠
|
|
|
|
|
|
public Point FloatingIconPosition { get; set; } = new Point(0, 0); // 浮动图标位置
|
|
|
|
|
|
public bool ShowFloatingIconOnStartup { get; set; } = false; // 启动时不显示浮动图标
|
|
|
|
|
|
public string FloatingIconPath { get; set; } = ""; // 浮动按钮图标路径
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private AppSettings settings = new AppSettings();
|
|
|
|
|
|
|
2025-03-13 14:08:06 +08:00
|
|
|
|
// 添加浮动图标相关代码
|
|
|
|
|
|
private NotifyIcon notifyIcon;
|
|
|
|
|
|
private Form floatingIcon;
|
|
|
|
|
|
private bool isFloatingIconVisible = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 修改ResizeHandle相关代码,添加鼠标光标
|
|
|
|
|
|
private void InitializeResizeHandle()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建调整大小的控件
|
|
|
|
|
|
resizeHandle = new Panel
|
|
|
|
|
|
{
|
|
|
|
|
|
Width = 5,
|
|
|
|
|
|
Dock = DockStyle.Right,
|
|
|
|
|
|
BackColor = Color.Transparent,
|
|
|
|
|
|
Cursor = Cursors.SizeWE // 设置为水平调整大小的光标
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 添加事件处理
|
|
|
|
|
|
resizeHandle.MouseDown += ResizeHandle_MouseDown;
|
|
|
|
|
|
resizeHandle.MouseMove += ResizeHandle_MouseMove;
|
|
|
|
|
|
resizeHandle.MouseUp += ResizeHandle_MouseUp;
|
2025-03-17 23:34:35 +08:00
|
|
|
|
resizeHandle.MouseEnter += (s, e) => resizeHandle.Cursor = Cursors.SizeWE;
|
|
|
|
|
|
resizeHandle.MouseLeave += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!isResizing)
|
|
|
|
|
|
{
|
|
|
|
|
|
resizeHandle.Cursor = Cursors.SizeWE;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
2025-03-13 14:08:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加到左侧面板
|
|
|
|
|
|
leftPanel.Controls.Add(resizeHandle);
|
|
|
|
|
|
resizeHandle.BringToFront();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 修改停靠方法,改进停靠行为
|
|
|
|
|
|
private bool isDocked = false;
|
|
|
|
|
|
private FormBorderStyle originalBorderStyle;
|
|
|
|
|
|
private Size originalSize;
|
|
|
|
|
|
private Point originalLocation;
|
|
|
|
|
|
private FormWindowState originalWindowState;
|
|
|
|
|
|
private const int DOCK_THRESHOLD = 10; // 停靠阈值
|
|
|
|
|
|
|
|
|
|
|
|
private void DockToScreenEdge()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查是否启用自动停靠
|
|
|
|
|
|
if (!settings.EnableAutoDocking)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
Screen currentScreen = Screen.FromControl(this);
|
|
|
|
|
|
Rectangle screenBounds = currentScreen.WorkingArea;
|
|
|
|
|
|
bool shouldDock = false;
|
|
|
|
|
|
DockStyle dockPosition = DockStyle.None;
|
|
|
|
|
|
|
|
|
|
|
|
// 检查左边缘
|
|
|
|
|
|
if (Math.Abs(this.Left - screenBounds.Left) <= DOCK_THRESHOLD)
|
|
|
|
|
|
{
|
|
|
|
|
|
shouldDock = true;
|
|
|
|
|
|
dockPosition = DockStyle.Left;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 检查右边缘
|
|
|
|
|
|
else if (Math.Abs(screenBounds.Right - (this.Left + this.Width)) <= DOCK_THRESHOLD)
|
|
|
|
|
|
{
|
|
|
|
|
|
shouldDock = true;
|
|
|
|
|
|
dockPosition = DockStyle.Right;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果应该停靠但尚未停靠
|
|
|
|
|
|
if (shouldDock && !isDocked)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 保存原始状态
|
|
|
|
|
|
originalBorderStyle = this.FormBorderStyle;
|
|
|
|
|
|
originalSize = this.Size;
|
|
|
|
|
|
originalLocation = this.Location;
|
|
|
|
|
|
originalWindowState = this.WindowState;
|
|
|
|
|
|
|
|
|
|
|
|
// 应用停靠样式
|
|
|
|
|
|
ApplyDockStyle(dockPosition, screenBounds);
|
|
|
|
|
|
isDocked = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
// 如果不应该停靠但当前已停靠
|
|
|
|
|
|
else if (!shouldDock && isDocked)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 恢复原始状态
|
|
|
|
|
|
this.FormBorderStyle = originalBorderStyle;
|
|
|
|
|
|
this.Size = originalSize;
|
|
|
|
|
|
this.Location = originalLocation;
|
|
|
|
|
|
this.WindowState = originalWindowState;
|
|
|
|
|
|
isDocked = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ApplyDockStyle(DockStyle dockPosition, Rectangle screenBounds)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置为无边框样式
|
|
|
|
|
|
this.FormBorderStyle = FormBorderStyle.SizableToolWindow;
|
|
|
|
|
|
|
|
|
|
|
|
// 根据停靠位置调整窗体
|
|
|
|
|
|
if (dockPosition == DockStyle.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Location = new Point(screenBounds.Left, screenBounds.Top);
|
|
|
|
|
|
this.Size = new Size(Math.Min(this.Width, screenBounds.Width / 4), screenBounds.Height);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (dockPosition == DockStyle.Right)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Location = new Point(screenBounds.Right - Math.Min(this.Width, screenBounds.Width / 4), screenBounds.Top);
|
|
|
|
|
|
this.Size = new Size(Math.Min(this.Width, screenBounds.Width / 4), screenBounds.Height);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置窗体始终置顶
|
|
|
|
|
|
this.TopMost = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
public MainForm()
|
|
|
|
|
|
{
|
|
|
|
|
|
InitializeComponent();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 配置工具提示 - 调整为更合适的值
|
|
|
|
|
|
toolTip1 = new ToolTip();
|
|
|
|
|
|
toolTip1.AutoPopDelay = 5000;
|
|
|
|
|
|
toolTip1.InitialDelay = 200; // 稍微增加初始延迟
|
|
|
|
|
|
toolTip1.ReshowDelay = 200; // 稍微增加重新显示延迟
|
|
|
|
|
|
toolTip1.ShowAlways = true;
|
|
|
|
|
|
toolTip1.UseFading = true;
|
|
|
|
|
|
toolTip1.IsBalloon = false; // 使用标准样式
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-13 14:08:06 +08:00
|
|
|
|
// 移除最小化按钮,保留最大化按钮
|
|
|
|
|
|
this.MinimizeBox = false;
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 初始化数据和UI
|
|
|
|
|
|
InitializeUI();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用Windows 11风格
|
|
|
|
|
|
ApplyWin11Style();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
SetupContextMenus();
|
|
|
|
|
|
SetupEventHandlers();
|
2025-03-13 14:08:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化浮动图标(必须在LoadSettings之前)
|
|
|
|
|
|
InitializeNotifyIcon();
|
|
|
|
|
|
|
|
|
|
|
|
// 加载设置
|
2025-03-12 14:06:44 +08:00
|
|
|
|
LoadSettings();
|
2025-03-13 14:08:06 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
LoadData();
|
|
|
|
|
|
SelectDefaultCategory();
|
2025-03-12 15:18:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 监听系统主题变化
|
|
|
|
|
|
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
|
2025-03-13 14:08:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化调整大小的控件
|
|
|
|
|
|
InitializeResizeHandle();
|
|
|
|
|
|
|
|
|
|
|
|
// 确保主窗口显示,浮动图标隐藏
|
|
|
|
|
|
this.Show();
|
|
|
|
|
|
this.Activate();
|
|
|
|
|
|
if (floatingIcon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
HideFloatingIcon();
|
|
|
|
|
|
}
|
2025-03-12 15:18:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SystemEvents_UserPreferenceChanged(object sender, UserPreferenceChangedEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Category == UserPreferenceCategory.General)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 在UI线程中更新主题
|
|
|
|
|
|
if (this.InvokeRequired)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Invoke(new Action(() => UpdateTheme()));
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
UpdateTheme();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void UpdateTheme()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 更新深色模式状态
|
|
|
|
|
|
isDarkMode = IsSystemUsingSysemDarkTheme();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 重新应用Windows 11风格
|
|
|
|
|
|
ApplyWin11Style();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 应用Windows 11风格
|
|
|
|
|
|
private void ApplyWin11Style()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检测系统主题
|
|
|
|
|
|
isDarkMode = IsSystemUsingSysemDarkTheme();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用Mica效果
|
|
|
|
|
|
if (Environment.OSVersion.Version.Build >= 22000) // Windows 11
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 应用深色/浅色模式
|
|
|
|
|
|
int darkMode = isDarkMode ? 1 : 0;
|
|
|
|
|
|
DwmSetWindowAttribute(this.Handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref darkMode, sizeof(int));
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用Mica效果
|
|
|
|
|
|
int micaEffect = 1;
|
|
|
|
|
|
DwmSetWindowAttribute(this.Handle, DWMWA_MICA_EFFECT, ref micaEffect, sizeof(int));
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果不支持,则使用备用方案
|
|
|
|
|
|
this.BackColor = isDarkMode ? darkBackColor : lightBackColor;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 在Windows 10上使用备用方案
|
|
|
|
|
|
this.BackColor = isDarkMode ? darkBackColor : lightBackColor;
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用主题颜色
|
|
|
|
|
|
ApplyThemeColors();
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 检测系统是否使用深色主题
|
|
|
|
|
|
private bool IsSystemUsingSysemDarkTheme()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var key = Registry.CurrentUser.OpenSubKey(@"Software\Microsoft\Windows\CurrentVersion\Themes\Personalize"))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (key != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
var value = key.GetValue("AppsUseLightTheme");
|
|
|
|
|
|
if (value != null && value is int)
|
|
|
|
|
|
{
|
|
|
|
|
|
return (int)value == 0;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
return false;
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用主题颜色
|
|
|
|
|
|
private void ApplyThemeColors()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置主窗体颜色
|
|
|
|
|
|
this.ForeColor = isDarkMode ? darkTextColor : lightTextColor;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置左侧面板颜色
|
|
|
|
|
|
leftPanel.BackColor = isDarkMode ? Color.FromArgb(40, 40, 40) : Color.FromArgb(243, 243, 243);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置右侧面板颜色
|
|
|
|
|
|
rightPanel.BackColor = isDarkMode ? Color.FromArgb(32, 32, 32) : Color.FromArgb(250, 250, 250);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置工具面板颜色
|
|
|
|
|
|
toolPanel.BackColor = isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(230, 230, 230);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置快捷方式面板颜色
|
|
|
|
|
|
shortcutsPanel.BackColor = isDarkMode ? Color.FromArgb(32, 32, 32) : Color.FromArgb(250, 250, 250);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置分类文字颜色
|
|
|
|
|
|
categoryLabel.ForeColor = isDarkMode ? Color.FromArgb(255, 255, 255) : Color.FromArgb(0, 0, 0);
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置添加按钮颜色
|
|
|
|
|
|
addButton.BackColor = accentColor;
|
|
|
|
|
|
addButton.ForeColor = Color.White;
|
|
|
|
|
|
addButton.FlatAppearance.BorderSize = 0;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置菜单颜色
|
|
|
|
|
|
menuStrip.BackColor = isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(230, 230, 230);
|
|
|
|
|
|
menuStrip.ForeColor = isDarkMode ? darkTextColor : lightTextColor;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置菜单项颜色
|
|
|
|
|
|
foreach (ToolStripMenuItem item in menuStrip.Items)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.ForeColor = isDarkMode ? Color.White : Color.Black;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置下拉菜单项颜色
|
|
|
|
|
|
foreach (ToolStripItem dropItem in item.DropDownItems)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (dropItem is ToolStripMenuItem menuItem)
|
|
|
|
|
|
{
|
|
|
|
|
|
menuItem.ForeColor = isDarkMode ? Color.White : Color.Black;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置菜单渲染器
|
|
|
|
|
|
menuStrip.Renderer = new ModernMenuRenderer(isDarkMode);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 刷新分类列表和当前分类的快捷方式(仅当categories已初始化时)
|
|
|
|
|
|
if (categories != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
RefreshCategoryList();
|
|
|
|
|
|
if (!string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 设置上下文菜单
|
|
|
|
|
|
private void SetupContextMenus()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 分类右键菜单
|
|
|
|
|
|
categoryContextMenu = new ContextMenuStrip();
|
|
|
|
|
|
categoryContextMenu.Items.Add("添加新分类", null, (s, e) => AddCategory_Click(s, e));
|
|
|
|
|
|
categoryContextMenu.Items.Add("删除当前分类", null, (s, e) => DeleteCategory_Click(s, e));
|
|
|
|
|
|
categoryContextMenu.Items.Add("重命名分类", null, (s, e) => RenameCategory_Click(s, e));
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用主题颜色
|
|
|
|
|
|
categoryContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
// 右侧面板右键菜单
|
|
|
|
|
|
shortcutsPanelContextMenu = new ContextMenuStrip();
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add("添加程序", null, (s, e) => AddButton_Click(s, e));
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add("-"); // 分隔线
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add("按名称排序", null, (s, e) => SortShortcuts("Name"));
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add("按添加时间排序", null, (s, e) => SortShortcuts("DateAdded"));
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add("按使用频率排序", null, (s, e) => SortShortcuts("UsageCount"));
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add("-"); // 分隔线
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 添加图标大小调整菜单,增加更多选项
|
|
|
|
|
|
var sizeMenu = new ToolStripMenuItem("图标大小");
|
|
|
|
|
|
sizeMenu.DropDownItems.Add("超小图标 (24px)", null, (s, e) => { ResizeIcons(24); });
|
|
|
|
|
|
sizeMenu.DropDownItems.Add("小图标 (48px)", null, (s, e) => { ResizeIcons(48); });
|
|
|
|
|
|
sizeMenu.DropDownItems.Add("中图标 (64px)", null, (s, e) => { ResizeIcons(64); });
|
|
|
|
|
|
sizeMenu.DropDownItems.Add("大图标 (96px)", null, (s, e) => { ResizeIcons(96); });
|
|
|
|
|
|
sizeMenu.DropDownItems.Add("较大图标 (128px)", null, (s, e) => { ResizeIcons(128); });
|
|
|
|
|
|
sizeMenu.DropDownItems.Add("超大图标 (192px)", null, (s, e) => { ResizeIcons(192); });
|
|
|
|
|
|
sizeMenu.DropDownItems.Add("巨大图标 (256px)", null, (s, e) => { ResizeIcons(256); });
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add(sizeMenu);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 添加主题切换选项
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add("-"); // 分隔线
|
|
|
|
|
|
var themeMenu = new ToolStripMenuItem("主题设置");
|
|
|
|
|
|
themeMenu.DropDownItems.Add("浅色主题", null, (s, e) => { ChangeTheme(false); });
|
|
|
|
|
|
themeMenu.DropDownItems.Add("深色主题", null, (s, e) => { ChangeTheme(true); });
|
|
|
|
|
|
themeMenu.DropDownItems.Add("跟随系统", null, (s, e) => { FollowSystemTheme(); });
|
|
|
|
|
|
shortcutsPanelContextMenu.Items.Add(themeMenu);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用主题颜色
|
|
|
|
|
|
shortcutsPanelContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
// 快捷方式项目右键菜单
|
|
|
|
|
|
shortcutItemContextMenu = new ContextMenuStrip();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
shortcutItemContextMenu.Items.Add("启动", null, (s, e) =>
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-15 23:50:17 +08:00
|
|
|
|
if (shortcutItemContextMenu.Tag is ShortcutItem item)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
LaunchApplication(item.Path);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-03-12 18:03:58 +08:00
|
|
|
|
shortcutItemContextMenu.Items.Add("删除", null, (s, e) =>
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-15 23:50:17 +08:00
|
|
|
|
if (shortcutItemContextMenu.Tag is ShortcutItem item)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
DeleteShortcut(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-03-12 18:03:58 +08:00
|
|
|
|
shortcutItemContextMenu.Items.Add("重命名", null, (s, e) =>
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-15 23:50:17 +08:00
|
|
|
|
if (shortcutItemContextMenu.Tag is ShortcutItem item)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
RenameShortcut(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-03-12 18:03:58 +08:00
|
|
|
|
shortcutItemContextMenu.Items.Add("属性", null, (s, e) =>
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-15 23:50:17 +08:00
|
|
|
|
if (shortcutItemContextMenu.Tag is ShortcutItem item)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
ShowShortcutProperties(item);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-03-15 23:50:17 +08:00
|
|
|
|
shortcutItemContextMenu.Items.Add("打开程序目录", null, (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (shortcutItemContextMenu.Tag is ShortcutItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
OpenProgramDirectory(item.Path);
|
|
|
|
|
|
}
|
|
|
|
|
|
});
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用主题颜色
|
|
|
|
|
|
shortcutItemContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 切换主题
|
|
|
|
|
|
private void ChangeTheme(bool darkMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
isDarkMode = darkMode;
|
|
|
|
|
|
ApplyThemeColors();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 更新上下文菜单渲染器
|
|
|
|
|
|
categoryContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
shortcutsPanelContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
shortcutItemContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 跟随系统主题
|
|
|
|
|
|
private void FollowSystemTheme()
|
|
|
|
|
|
{
|
|
|
|
|
|
isDarkMode = IsSystemUsingSysemDarkTheme();
|
|
|
|
|
|
ApplyThemeColors();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 更新上下文菜单渲染器
|
|
|
|
|
|
categoryContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
shortcutsPanelContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
shortcutItemContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 现代菜单渲染器
|
|
|
|
|
|
private class ModernMenuRenderer : ToolStripProfessionalRenderer
|
|
|
|
|
|
{
|
|
|
|
|
|
private bool _isDarkMode;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
public ModernMenuRenderer(bool isDarkMode) : base(new ModernColorTable(isDarkMode))
|
|
|
|
|
|
{
|
|
|
|
|
|
_isDarkMode = isDarkMode;
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
protected override void OnRenderMenuItemBackground(ToolStripItemRenderEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Item.Selected)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 选中项背景
|
|
|
|
|
|
Rectangle rect = new Rectangle(2, 0, e.Item.Width - 4, e.Item.Height);
|
|
|
|
|
|
Color highlightColor = _isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(210, 230, 250);
|
|
|
|
|
|
using (SolidBrush brush = new SolidBrush(highlightColor))
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Graphics.FillRoundedRectangle(brush, rect, 4);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 普通项背景
|
|
|
|
|
|
Color backColor = _isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(250, 250, 250);
|
|
|
|
|
|
using (SolidBrush brush = new SolidBrush(backColor))
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Graphics.FillRectangle(brush, e.Item.ContentRectangle);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
protected override void OnRenderToolStripBackground(ToolStripRenderEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 菜单背景
|
|
|
|
|
|
Color backColor = _isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(250, 250, 250);
|
|
|
|
|
|
using (SolidBrush brush = new SolidBrush(backColor))
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Graphics.FillRectangle(brush, e.AffectedBounds);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 菜单文本颜色
|
|
|
|
|
|
e.TextColor = _isDarkMode ? Color.FromArgb(240, 240, 240) : Color.FromArgb(20, 20, 20);
|
|
|
|
|
|
base.OnRenderItemText(e);
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
protected override void OnRenderSeparator(ToolStripSeparatorRenderEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 分隔线颜色
|
|
|
|
|
|
Color lineColor = _isDarkMode ? Color.FromArgb(80, 80, 80) : Color.FromArgb(200, 200, 200);
|
|
|
|
|
|
int y = e.Item.Height / 2;
|
|
|
|
|
|
using (Pen pen = new Pen(lineColor))
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Graphics.DrawLine(pen, 4, y, e.Item.Width - 4, y);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 现代菜单颜色表
|
|
|
|
|
|
private class ModernColorTable : ProfessionalColorTable
|
|
|
|
|
|
{
|
|
|
|
|
|
private bool _isDarkMode;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
public ModernColorTable(bool isDarkMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
_isDarkMode = isDarkMode;
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 菜单项
|
|
|
|
|
|
public override Color MenuItemSelected => _isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(210, 230, 250);
|
|
|
|
|
|
public override Color MenuItemBorder => Color.Transparent;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 菜单栏
|
|
|
|
|
|
public override Color MenuBorder => Color.Transparent;
|
|
|
|
|
|
public override Color MenuItemSelectedGradientBegin => _isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(210, 230, 250);
|
|
|
|
|
|
public override Color MenuItemSelectedGradientEnd => _isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(210, 230, 250);
|
|
|
|
|
|
public override Color MenuItemPressedGradientBegin => _isDarkMode ? Color.FromArgb(80, 80, 80) : Color.FromArgb(190, 210, 240);
|
|
|
|
|
|
public override Color MenuItemPressedGradientEnd => _isDarkMode ? Color.FromArgb(80, 80, 80) : Color.FromArgb(190, 210, 240);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 工具栏
|
|
|
|
|
|
public override Color ToolStripDropDownBackground => _isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(250, 250, 250);
|
|
|
|
|
|
public override Color ImageMarginGradientBegin => _isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(250, 250, 250);
|
|
|
|
|
|
public override Color ImageMarginGradientMiddle => _isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(250, 250, 250);
|
|
|
|
|
|
public override Color ImageMarginGradientEnd => _isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(250, 250, 250);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 调整图标大小
|
|
|
|
|
|
private void ResizeIcons(int newSize)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (newSize >= MIN_ICON_SIZE && newSize <= MAX_ICON_SIZE)
|
|
|
|
|
|
{
|
|
|
|
|
|
iconSize = newSize;
|
|
|
|
|
|
settings.IconSize = iconSize;
|
|
|
|
|
|
SaveSettings();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 处理鼠标滚轮事件
|
|
|
|
|
|
private void ShortcutsPanel_MouseWheel(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 检查Ctrl键是否按下
|
|
|
|
|
|
if (ModifierKeys == Keys.Control)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 向上滚动,放大图标
|
|
|
|
|
|
if (e.Delta > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
ResizeIcons(iconSize + ICON_SIZE_STEP);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 向下滚动,缩小图标
|
|
|
|
|
|
else if (e.Delta < 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
ResizeIcons(iconSize - ICON_SIZE_STEP);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重命名分类
|
|
|
|
|
|
private void RenameCategory_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请先选择要重命名的分类", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
using (var dialog = new Form())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Text = "重命名分类";
|
|
|
|
|
|
dialog.Size = new Size(350, 150);
|
|
|
|
|
|
dialog.StartPosition = FormStartPosition.CenterParent;
|
|
|
|
|
|
dialog.FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
|
|
|
|
dialog.MaximizeBox = false;
|
|
|
|
|
|
dialog.MinimizeBox = false;
|
|
|
|
|
|
|
|
|
|
|
|
var label = new Label() { Text = "新名称:", Location = new Point(10, 20) };
|
|
|
|
|
|
var textBox = new TextBox() { Text = currentCategory, Location = new Point(120, 17), Width = 180 };
|
2025-03-12 15:44:35 +08:00
|
|
|
|
var button = new RoundedButton() { Text = "确定", DialogResult = DialogResult.OK, Location = new Point(110, 60), CornerRadius = cornerRadius, BackColor = accentColor, ForeColor = Color.White };
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
dialog.Controls.AddRange(new Control[] { label, textBox, button });
|
|
|
|
|
|
dialog.AcceptButton = button;
|
|
|
|
|
|
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK && !string.IsNullOrWhiteSpace(textBox.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
string newName = textBox.Text.Trim();
|
|
|
|
|
|
if (newName != currentCategory && !categories.ContainsKey(newName))
|
|
|
|
|
|
{
|
|
|
|
|
|
var items = categories[currentCategory];
|
|
|
|
|
|
categories.Remove(currentCategory);
|
|
|
|
|
|
categories[newName] = items;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
string oldCategory = currentCategory;
|
|
|
|
|
|
currentCategory = newName;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
SaveData();
|
|
|
|
|
|
RefreshCategoryList();
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (categories.ContainsKey(newName) && newName != currentCategory)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("该分类名称已存在", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 排序快捷方式
|
|
|
|
|
|
private void SortShortcuts(string sortMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(currentCategory) || !categories.ContainsKey(currentCategory))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
settings.SortMode = sortMode;
|
|
|
|
|
|
SaveSettings();
|
|
|
|
|
|
|
|
|
|
|
|
switch (sortMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "Name":
|
|
|
|
|
|
categories[currentCategory] = categories[currentCategory].OrderBy(s => s.Name).ToList();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "DateAdded":
|
|
|
|
|
|
categories[currentCategory] = categories[currentCategory].OrderByDescending(s => s.DateAdded).ToList();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "UsageCount":
|
|
|
|
|
|
categories[currentCategory] = categories[currentCategory].OrderByDescending(s => s.UsageCount).ToList();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 删除快捷方式
|
|
|
|
|
|
private void DeleteShortcut(ShortcutItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(currentCategory) || !categories.ContainsKey(currentCategory))
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
if (MessageBox.Show($"确定要删除 '{item.Name}' 吗?", "确认删除",
|
|
|
|
|
|
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
|
|
|
|
|
|
{
|
|
|
|
|
|
categories[currentCategory].Remove(item);
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重命名快捷方式
|
|
|
|
|
|
private void RenameShortcut(ShortcutItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var dialog = new Form())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Text = "重命名快捷方式";
|
|
|
|
|
|
dialog.Size = new Size(350, 150);
|
|
|
|
|
|
dialog.StartPosition = FormStartPosition.CenterParent;
|
|
|
|
|
|
dialog.FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
|
|
|
|
dialog.MaximizeBox = false;
|
|
|
|
|
|
dialog.MinimizeBox = false;
|
|
|
|
|
|
|
|
|
|
|
|
var label = new Label() { Text = "新名称:", Location = new Point(10, 20) };
|
|
|
|
|
|
var textBox = new TextBox() { Text = item.Name, Location = new Point(120, 17), Width = 180 };
|
2025-03-12 15:44:35 +08:00
|
|
|
|
var button = new RoundedButton() { Text = "确定", DialogResult = DialogResult.OK, Location = new Point(110, 60), CornerRadius = cornerRadius, BackColor = accentColor, ForeColor = Color.White };
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
dialog.Controls.AddRange(new Control[] { label, textBox, button });
|
|
|
|
|
|
dialog.AcceptButton = button;
|
|
|
|
|
|
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK && !string.IsNullOrWhiteSpace(textBox.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
item.Name = textBox.Text.Trim();
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示快捷方式属性
|
|
|
|
|
|
private void ShowShortcutProperties(ShortcutItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var dialog = new Form())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Text = "快捷方式属性";
|
|
|
|
|
|
dialog.Size = new Size(400, 300);
|
|
|
|
|
|
dialog.StartPosition = FormStartPosition.CenterParent;
|
|
|
|
|
|
dialog.FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
|
|
|
|
dialog.MaximizeBox = false;
|
|
|
|
|
|
dialog.MinimizeBox = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 使用当前图标大小显示图标
|
|
|
|
|
|
var icon = new PictureBox
|
|
|
|
|
|
{
|
|
|
|
|
|
Size = new Size(Math.Min(64, iconSize), Math.Min(64, iconSize)), // 限制属性对话框中的图标大小
|
|
|
|
|
|
Location = new Point(20, 20),
|
|
|
|
|
|
Image = item.Icon ?? SystemIcons.Application.ToBitmap(),
|
|
|
|
|
|
SizeMode = PictureBoxSizeMode.StretchImage
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var nameLabel = new Label() { Text = "名称:", Location = new Point(20, 80), AutoSize = true };
|
|
|
|
|
|
var nameValue = new Label() { Text = item.Name, Location = new Point(120, 80), AutoSize = true };
|
|
|
|
|
|
|
|
|
|
|
|
var pathLabel = new Label() { Text = "路径:", Location = new Point(20, 110), AutoSize = true };
|
|
|
|
|
|
var pathValue = new Label() { Text = item.Path, Location = new Point(120, 110), Width = 250, AutoEllipsis = true };
|
|
|
|
|
|
|
|
|
|
|
|
var dateLabel = new Label() { Text = "添加日期:", Location = new Point(20, 140), AutoSize = true };
|
|
|
|
|
|
var dateValue = new Label() { Text = item.DateAdded.ToString(), Location = new Point(120, 140), AutoSize = true };
|
|
|
|
|
|
|
|
|
|
|
|
var usageLabel = new Label() { Text = "使用次数:", Location = new Point(20, 170), AutoSize = true };
|
|
|
|
|
|
var usageValue = new Label() { Text = item.UsageCount.ToString(), Location = new Point(120, 170), AutoSize = true };
|
|
|
|
|
|
|
2025-03-12 15:44:35 +08:00
|
|
|
|
var button = new RoundedButton() { Text = "确定", DialogResult = DialogResult.OK, Location = new Point(150, 220), CornerRadius = cornerRadius, BackColor = accentColor, ForeColor = Color.White };
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
2025-03-12 18:03:58 +08:00
|
|
|
|
dialog.Controls.AddRange(new Control[] { icon, nameLabel, nameValue, pathLabel, pathValue,
|
2025-03-12 14:06:44 +08:00
|
|
|
|
dateLabel, dateValue, usageLabel, usageValue, button });
|
|
|
|
|
|
dialog.AcceptButton = button;
|
|
|
|
|
|
|
|
|
|
|
|
dialog.ShowDialog();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-15 23:50:17 +08:00
|
|
|
|
// 打开程序目录
|
|
|
|
|
|
private void OpenProgramDirectory(string programPath)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (File.Exists(programPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 使用explorer.exe /select, 来打开文件所在目录并高亮显示该文件
|
|
|
|
|
|
Process.Start("explorer.exe", $"/select,\"{programPath}\"");
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("文件不存在,无法打开所在目录", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"打开程序目录时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 选择默认分类
|
|
|
|
|
|
private void SelectDefaultCategory()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果没有分类,不做任何操作
|
|
|
|
|
|
if (categories.Count == 0)
|
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试选择上次选择的分类
|
2025-03-12 18:03:58 +08:00
|
|
|
|
if (!string.IsNullOrEmpty(settings.LastSelectedCategory) &&
|
2025-03-12 14:06:44 +08:00
|
|
|
|
categories.ContainsKey(settings.LastSelectedCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
currentCategory = settings.LastSelectedCategory;
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 如果没有上次选择的分类或该分类不存在,选择第一个分类
|
|
|
|
|
|
currentCategory = categories.Keys.First();
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 保存设置
|
|
|
|
|
|
private void SaveSettings()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
settings.LastSelectedCategory = currentCategory;
|
|
|
|
|
|
settings.IconSize = iconSize;
|
2025-03-12 15:18:23 +08:00
|
|
|
|
settings.LeftPanelWidth = leftPanel.Width;
|
2025-03-13 14:08:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 添加null检查
|
|
|
|
|
|
if (floatingIcon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
settings.FloatingIconPosition = floatingIcon.Location;
|
|
|
|
|
|
// 不要在这里设置FloatingIconPath,它应该只在ChangeFloatingIconImage方法中设置
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
var options = new JsonSerializerOptions
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteIndented = true
|
|
|
|
|
|
};
|
|
|
|
|
|
var data = JsonSerializer.Serialize(settings, options);
|
|
|
|
|
|
File.WriteAllText(settingsFilePath, data);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"保存设置失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加载设置
|
|
|
|
|
|
private void LoadSettings()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (File.Exists(settingsFilePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var json = File.ReadAllText(settingsFilePath);
|
|
|
|
|
|
settings = JsonSerializer.Deserialize<AppSettings>(json) ?? new AppSettings();
|
|
|
|
|
|
iconSize = settings.IconSize; // 加载保存的图标大小
|
2025-03-12 15:18:23 +08:00
|
|
|
|
leftPanel.Width = settings.LeftPanelWidth;
|
2025-03-13 14:08:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 确保floatingIcon已初始化
|
|
|
|
|
|
if (floatingIcon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
floatingIcon.Location = settings.FloatingIconPosition;
|
|
|
|
|
|
// 不要在这里设置Visible属性,让ShowFloatingIcon方法来控制
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
settings = new AppSettings();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SetupEventHandlers()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 清除所有事件处理器 - 移除不存在的引用
|
|
|
|
|
|
addButton.Click -= AddButton_Click;
|
|
|
|
|
|
this.FormClosing -= MainForm_FormClosing;
|
|
|
|
|
|
shortcutsPanel.MouseWheel -= ShortcutsPanel_MouseWheel;
|
|
|
|
|
|
|
|
|
|
|
|
// 只为shortcutsPanel添加拖放支持
|
|
|
|
|
|
shortcutsPanel.AllowDrop = true;
|
|
|
|
|
|
shortcutsPanel.DragEnter += ShortcutsPanel_DragEnter;
|
|
|
|
|
|
shortcutsPanel.DragDrop += ShortcutsPanel_DragDrop;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 添加鼠标滚轮事件处理
|
|
|
|
|
|
shortcutsPanel.MouseWheel += ShortcutsPanel_MouseWheel;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 为shortcutsPanel添加鼠标移动事件,用于处理空白区域的工具提示
|
|
|
|
|
|
shortcutsPanel.MouseMove += ShortcutsPanel_MouseMove;
|
|
|
|
|
|
|
|
|
|
|
|
// 为shortcutsPanel添加右键菜单
|
|
|
|
|
|
shortcutsPanel.ContextMenuStrip = shortcutsPanelContextMenu;
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定添加程序按钮事件
|
|
|
|
|
|
addButton.Click += AddButton_Click;
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定窗体关闭事件,保存当前选择的分类
|
|
|
|
|
|
this.FormClosing += MainForm_FormClosing;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加缺失的事件处理方法
|
|
|
|
|
|
private void ShortcutsPanel_DragEnter(object sender, DragEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("DragEnter triggered");
|
|
|
|
|
|
if (e.Data.GetDataPresent(DataFormats.FileDrop) && !string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Effect = DragDropEffects.Copy;
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Effect = DragDropEffects.None;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
private void ShortcutsPanel_DragDrop(object sender, DragEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Console.WriteLine("DragDrop triggered");
|
|
|
|
|
|
if (string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请先选择一个分类", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
|
|
|
|
bool addedAny = false;
|
|
|
|
|
|
foreach (string file in files)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (File.Exists(file))
|
|
|
|
|
|
{
|
|
|
|
|
|
AddNewShortcut(file, currentCategory);
|
|
|
|
|
|
addedAny = true;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!addedAny)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("没有找到有效的文件", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
SaveSettings();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void InitializeUI()
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 初始化数据
|
2025-03-12 14:06:44 +08:00
|
|
|
|
categories = new Dictionary<string, List<ShortcutItem>>();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置窗体样式
|
|
|
|
|
|
this.FormBorderStyle = FormBorderStyle.Sizable;
|
|
|
|
|
|
this.MinimumSize = new Size(800, 600);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置控件样式
|
|
|
|
|
|
addButton.FlatStyle = FlatStyle.Flat;
|
|
|
|
|
|
addButton.FlatAppearance.BorderSize = 0;
|
|
|
|
|
|
addButton.BackColor = accentColor;
|
|
|
|
|
|
addButton.ForeColor = Color.White;
|
|
|
|
|
|
addButton.Font = new Font("Microsoft YaHei UI", 10, FontStyle.Regular);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置分类标签样式
|
|
|
|
|
|
categoryLabel.Font = new Font("Microsoft YaHei UI", 11);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
categoryLabel.ForeColor = isDarkMode ? Color.FromArgb(0, 0, 0) : Color.FromArgb(255, 255, 255);
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 刷新分类列表
|
2025-03-12 14:06:44 +08:00
|
|
|
|
RefreshCategoryList();
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 调整手柄鼠标按下事件
|
|
|
|
|
|
private void ResizeHandle_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
isResizing = true;
|
|
|
|
|
|
resizingStartX = e.X;
|
|
|
|
|
|
initialPanelWidth = leftPanel.Width;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 捕获鼠标
|
|
|
|
|
|
resizeHandle.Capture = true;
|
2025-03-17 23:34:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 设置鼠标光标
|
|
|
|
|
|
this.Cursor = Cursors.SizeWE;
|
|
|
|
|
|
resizeHandle.Cursor = Cursors.SizeWE;
|
2025-03-12 15:18:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 调整手柄鼠标移动事件
|
|
|
|
|
|
private void ResizeHandle_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isResizing)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 计算新宽度
|
|
|
|
|
|
int newWidth = initialPanelWidth + (e.X - resizingStartX);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 限制宽度范围
|
|
|
|
|
|
if (newWidth < MIN_PANEL_WIDTH)
|
|
|
|
|
|
newWidth = MIN_PANEL_WIDTH;
|
|
|
|
|
|
else if (newWidth > MAX_PANEL_WIDTH)
|
|
|
|
|
|
newWidth = MAX_PANEL_WIDTH;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 设置新宽度
|
|
|
|
|
|
leftPanel.Width = newWidth;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 刷新布局
|
|
|
|
|
|
this.PerformLayout();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 调整手柄鼠标释放事件
|
|
|
|
|
|
private void ResizeHandle_MouseUp(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isResizing)
|
|
|
|
|
|
{
|
2025-03-17 23:34:35 +08:00
|
|
|
|
// 先保存设置
|
|
|
|
|
|
settings.LeftPanelWidth = leftPanel.Width;
|
|
|
|
|
|
SaveSettings();
|
|
|
|
|
|
|
|
|
|
|
|
// 在鼠标释放后刷新一次分类列表
|
|
|
|
|
|
RefreshCategoryList();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-17 23:34:35 +08:00
|
|
|
|
// 重置调整状态
|
|
|
|
|
|
isResizing = false;
|
|
|
|
|
|
|
|
|
|
|
|
// 恢复默认鼠标光标
|
|
|
|
|
|
this.Cursor = Cursors.Default;
|
|
|
|
|
|
|
|
|
|
|
|
// 最后释放鼠标捕获
|
2025-03-12 15:18:23 +08:00
|
|
|
|
resizeHandle.Capture = false;
|
2025-03-17 23:34:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 确保调整手柄保持正确的光标
|
|
|
|
|
|
resizeHandle.Cursor = Cursors.SizeWE;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-17 23:34:35 +08:00
|
|
|
|
// 添加窗体鼠标移动事件处理
|
|
|
|
|
|
protected override void OnMouseMove(MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnMouseMove(e);
|
|
|
|
|
|
|
|
|
|
|
|
// 如果正在调整大小,确保鼠标光标保持为调整大小状态
|
|
|
|
|
|
if (isResizing)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Cursor = Cursors.SizeWE;
|
|
|
|
|
|
resizeHandle.Cursor = Cursors.SizeWE;
|
2025-03-12 15:18:23 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
private void AddCategory_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var dialog = new Form())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Text = "添加新分类";
|
2025-03-12 18:03:58 +08:00
|
|
|
|
dialog.Size = new Size(350, 200);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
dialog.StartPosition = FormStartPosition.CenterParent;
|
|
|
|
|
|
dialog.FormBorderStyle = FormBorderStyle.FixedDialog;
|
|
|
|
|
|
dialog.MaximizeBox = false;
|
|
|
|
|
|
dialog.MinimizeBox = false;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
dialog.BackColor = isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(240, 240, 240);
|
2025-03-12 15:18:23 +08:00
|
|
|
|
dialog.ForeColor = isDarkMode ? Color.White : Color.Black;
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
2025-03-12 18:03:58 +08:00
|
|
|
|
// 应用Windows 11深色/浅色模式到标题栏
|
|
|
|
|
|
if (Environment.OSVersion.Version.Build >= 22000)
|
|
|
|
|
|
{
|
|
|
|
|
|
int darkMode = isDarkMode ? 1 : 0;
|
|
|
|
|
|
DwmSetWindowAttribute(dialog.Handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref darkMode, sizeof(int));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var label = new Label()
|
|
|
|
|
|
{
|
|
|
|
|
|
Text = "分类名称:",
|
2025-03-12 15:18:23 +08:00
|
|
|
|
Location = new Point(10, 20),
|
2025-03-12 18:03:58 +08:00
|
|
|
|
ForeColor = isDarkMode ? Color.White : Color.Black,
|
|
|
|
|
|
AutoSize = true
|
2025-03-12 15:18:23 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-12 18:03:58 +08:00
|
|
|
|
var textBox = new TextBox()
|
|
|
|
|
|
{
|
|
|
|
|
|
Location = new Point(120, 17),
|
2025-03-12 15:18:23 +08:00
|
|
|
|
Width = 180,
|
2025-03-12 18:03:58 +08:00
|
|
|
|
BackColor = isDarkMode ? Color.FromArgb(60, 60, 60) : Color.White,
|
|
|
|
|
|
ForeColor = isDarkMode ? Color.White : Color.Black,
|
|
|
|
|
|
BorderStyle = BorderStyle.FixedSingle
|
2025-03-12 15:18:23 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-12 18:03:58 +08:00
|
|
|
|
var button = new RoundedButton()
|
|
|
|
|
|
{
|
|
|
|
|
|
Text = "确定",
|
|
|
|
|
|
DialogResult = DialogResult.OK,
|
2025-03-12 15:18:23 +08:00
|
|
|
|
Location = new Point(110, 60),
|
|
|
|
|
|
Width = 100,
|
|
|
|
|
|
Height = 30,
|
2025-03-12 15:44:35 +08:00
|
|
|
|
BackColor = accentColor,
|
|
|
|
|
|
ForeColor = Color.White,
|
2025-03-12 15:18:23 +08:00
|
|
|
|
CornerRadius = cornerRadius
|
|
|
|
|
|
};
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
dialog.Controls.AddRange(new Control[] { label, textBox, button });
|
|
|
|
|
|
dialog.AcceptButton = button;
|
|
|
|
|
|
|
2025-03-12 18:03:58 +08:00
|
|
|
|
// 确保在显示对话框之前应用主题
|
|
|
|
|
|
dialog.HandleCreated += (s, ev) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (Environment.OSVersion.Version.Build >= 22000)
|
|
|
|
|
|
{
|
|
|
|
|
|
int darkMode = isDarkMode ? 1 : 0;
|
|
|
|
|
|
DwmSetWindowAttribute(dialog.Handle, DWMWA_USE_IMMERSIVE_DARK_MODE, ref darkMode, sizeof(int));
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK && !string.IsNullOrWhiteSpace(textBox.Text))
|
|
|
|
|
|
{
|
|
|
|
|
|
string newCategory = textBox.Text.Trim();
|
|
|
|
|
|
if (!categories.ContainsKey(newCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
categories[newCategory] = new List<ShortcutItem>();
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
RefreshCategoryList();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 自动选择新创建的分类
|
2025-03-12 18:03:58 +08:00
|
|
|
|
SwitchCategory(newCategory);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void DeleteCategory_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请先选择要删除的分类", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (MessageBox.Show($"确定要删除分类 '{currentCategory}' 吗?", "确认删除",
|
|
|
|
|
|
MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
|
|
|
|
|
|
{
|
|
|
|
|
|
categories.Remove(currentCategory);
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
RefreshCategoryList();
|
|
|
|
|
|
shortcutsPanel.Controls.Clear();
|
|
|
|
|
|
currentCategory = "";
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 删除分类后,选择新的默认分类
|
|
|
|
|
|
if (categories.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentCategory = categories.Keys.First();
|
|
|
|
|
|
ShowCategoryItems(currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void RefreshCategoryList()
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 如果categories为空,直接返回
|
|
|
|
|
|
if (categories == null)
|
|
|
|
|
|
return;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-17 23:34:35 +08:00
|
|
|
|
// 保存resizeHandle的引用
|
|
|
|
|
|
Panel savedResizeHandle = resizeHandle;
|
|
|
|
|
|
|
|
|
|
|
|
// 清除所有控件,但保留resizeHandle
|
2025-03-12 14:06:44 +08:00
|
|
|
|
leftPanel.Controls.Clear();
|
2025-03-17 23:34:35 +08:00
|
|
|
|
|
|
|
|
|
|
// 重新添加resizeHandle
|
|
|
|
|
|
if (savedResizeHandle != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
leftPanel.Controls.Add(savedResizeHandle);
|
|
|
|
|
|
savedResizeHandle.BringToFront();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
int buttonY = 10;
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var category in categories.Keys)
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
var categoryPanel = new RoundedPanel
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
Width = leftPanel.Width - 5,
|
|
|
|
|
|
Height = CATEGORY_BUTTON_HEIGHT,
|
2025-03-12 15:18:23 +08:00
|
|
|
|
Location = new Point(0, buttonY),
|
|
|
|
|
|
CornerRadius = cornerRadius
|
2025-03-12 14:06:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
var btn = new RoundedButton
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
Text = category,
|
|
|
|
|
|
Width = leftPanel.Width - 20,
|
|
|
|
|
|
Height = CATEGORY_BUTTON_HEIGHT,
|
|
|
|
|
|
Location = new Point(10, 0),
|
|
|
|
|
|
FlatStyle = FlatStyle.Flat,
|
2025-03-12 18:03:58 +08:00
|
|
|
|
BackColor = category == currentCategory ?
|
|
|
|
|
|
accentColor :
|
2025-03-12 15:18:23 +08:00
|
|
|
|
(isDarkMode ? Color.FromArgb(60, 60, 60) : Color.FromArgb(230, 230, 230)),
|
2025-03-12 18:03:58 +08:00
|
|
|
|
ForeColor = category == currentCategory ?
|
|
|
|
|
|
Color.White :
|
2025-03-12 15:18:23 +08:00
|
|
|
|
(isDarkMode ? Color.FromArgb(240, 240, 240) : Color.FromArgb(20, 20, 20)),
|
|
|
|
|
|
Tag = category,
|
|
|
|
|
|
CornerRadius = cornerRadius,
|
|
|
|
|
|
FlatAppearance = { BorderSize = 0 }
|
2025-03-12 14:06:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 移除旧的事件处理器
|
|
|
|
|
|
btn.Click -= null;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
btn.Click += (s, e) =>
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
currentCategory = category;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
foreach (Control panel in leftPanel.Controls)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (panel is RoundedPanel && panel.Controls.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
var button = panel.Controls[0] as RoundedButton;
|
|
|
|
|
|
if (button != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
string btnCategory = button.Tag as string;
|
|
|
|
|
|
button.BackColor = btnCategory == category ?
|
|
|
|
|
|
accentColor :
|
|
|
|
|
|
(isDarkMode ? Color.FromArgb(60, 60, 60) : Color.FromArgb(230, 230, 230));
|
|
|
|
|
|
button.ForeColor = btnCategory == category ?
|
|
|
|
|
|
Color.White :
|
|
|
|
|
|
(isDarkMode ? Color.FromArgb(240, 240, 240) : Color.FromArgb(20, 20, 20));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
ShowCategoryItems(category);
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 添加右键菜单
|
|
|
|
|
|
btn.ContextMenuStrip = categoryContextMenu;
|
|
|
|
|
|
|
|
|
|
|
|
categoryPanel.Controls.Add(btn);
|
|
|
|
|
|
categoryPanel.AllowDrop = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 移除旧的事件处理器
|
|
|
|
|
|
categoryPanel.DragEnter -= null;
|
|
|
|
|
|
categoryPanel.DragDrop -= null;
|
|
|
|
|
|
|
|
|
|
|
|
categoryPanel.DragEnter += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Data.GetDataPresent(DataFormats.FileDrop))
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Effect = DragDropEffects.Copy;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
categoryPanel.DragDrop += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
string[] files = (string[])e.Data.GetData(DataFormats.FileDrop);
|
|
|
|
|
|
foreach (string file in files)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (File.Exists(file))
|
|
|
|
|
|
{
|
|
|
|
|
|
AddNewShortcut(file, category);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
leftPanel.Controls.Add(categoryPanel);
|
|
|
|
|
|
buttonY += CATEGORY_BUTTON_HEIGHT + 5;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ShowCategoryItems(string category)
|
|
|
|
|
|
{
|
|
|
|
|
|
shortcutsPanel.Controls.Clear();
|
|
|
|
|
|
if (categories.ContainsKey(category))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 更新顶部分类标签
|
|
|
|
|
|
categoryLabel.Text = $"当前分类: {category}";
|
|
|
|
|
|
|
|
|
|
|
|
// 根据设置的排序模式排序
|
|
|
|
|
|
List<ShortcutItem> sortedItems = categories[category];
|
|
|
|
|
|
switch (settings.SortMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
case "Name":
|
|
|
|
|
|
sortedItems = sortedItems.OrderBy(s => s.Name).ToList();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "DateAdded":
|
|
|
|
|
|
sortedItems = sortedItems.OrderByDescending(s => s.DateAdded).ToList();
|
|
|
|
|
|
break;
|
|
|
|
|
|
case "UsageCount":
|
|
|
|
|
|
sortedItems = sortedItems.OrderByDescending(s => s.UsageCount).ToList();
|
|
|
|
|
|
break;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
foreach (var item in sortedItems)
|
|
|
|
|
|
{
|
|
|
|
|
|
AddShortcutControl(item, category);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void AddShortcutControl(ShortcutItem item, string category)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 根据当前图标大小调整面板大小
|
|
|
|
|
|
int panelWidth = Math.Max(80, iconSize + 10);
|
|
|
|
|
|
int panelHeight = iconSize + 60;
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
var panel = new RoundedPanel
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
|
|
|
|
|
Width = panelWidth,
|
|
|
|
|
|
Height = panelHeight,
|
|
|
|
|
|
Margin = new Padding(5),
|
|
|
|
|
|
Tag = item,
|
2025-03-12 15:18:23 +08:00
|
|
|
|
BackColor = isDarkMode ? Color.FromArgb(50, 50, 50) : Color.FromArgb(245, 245, 245),
|
|
|
|
|
|
CornerRadius = cornerRadius
|
2025-03-12 14:06:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
var icon = new PictureBox
|
|
|
|
|
|
{
|
|
|
|
|
|
Size = new Size(iconSize, iconSize),
|
|
|
|
|
|
Location = new Point((panel.Width - iconSize) / 2, 5),
|
2025-03-12 15:44:35 +08:00
|
|
|
|
Image = GetItemIcon(item),
|
|
|
|
|
|
SizeMode = PictureBoxSizeMode.Zoom,
|
2025-03-12 14:06:44 +08:00
|
|
|
|
Tag = item,
|
2025-03-12 15:44:35 +08:00
|
|
|
|
Cursor = Cursors.Hand
|
2025-03-12 14:06:44 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-12 21:27:55 +08:00
|
|
|
|
// 创建一个新的文本框控件实例
|
|
|
|
|
|
var label = new TextBox();
|
|
|
|
|
|
|
|
|
|
|
|
// 计算文本所需的高度
|
|
|
|
|
|
// TextRenderer.MeasureText: 测量指定文本在给定条件下需要的尺寸
|
|
|
|
|
|
// item.Name: 要显示的文本内容
|
|
|
|
|
|
// new Font(): 创建微软雅黑8号字体
|
|
|
|
|
|
// new Size(panel.Width, 0): 指定宽度限制,高度不限
|
|
|
|
|
|
// TextFormatFlags.WordBreak: 允许在单词间换行
|
|
|
|
|
|
// TextFormatFlags.TextBoxControl: 使用文本框的文本渲染规则
|
|
|
|
|
|
// .Height + 10: 获取计算出的高度并额外添加10像素的边距
|
2025-03-12 22:27:37 +08:00
|
|
|
|
var textHeight = TextRenderer.MeasureText(item.Name, new Font("Microsoft YaHei", 8), new Size(panel.Width, 0), TextFormatFlags.WordBreak | TextFormatFlags.TextBoxControl).Height + 10;
|
2025-03-12 21:27:55 +08:00
|
|
|
|
|
2025-03-12 22:27:37 +08:00
|
|
|
|
label.Text = item.Name; // 设置显示的文本内容
|
|
|
|
|
|
label.AutoSize = false; // 禁用自动尺寸调整
|
|
|
|
|
|
label.TextAlign = HorizontalAlignment.Center; // 文本水平居中对齐
|
2025-03-12 21:27:55 +08:00
|
|
|
|
label.MinimumSize = new Size(panel.Width, 30); // 设置最小尺寸
|
|
|
|
|
|
label.MaximumSize = new Size(panelWidth, 0); // 设置最大宽度,高度不限
|
2025-03-12 22:27:37 +08:00
|
|
|
|
label.Location = new Point(0, iconSize + 20); // 设置位置(在图标下方10像素)
|
|
|
|
|
|
label.Tag = item; // 存储关联的数据项
|
|
|
|
|
|
label.Cursor = Cursors.Hand; // 鼠标悬停时显示手型光标
|
|
|
|
|
|
label.ForeColor = isDarkMode ? Color.FromArgb(240, 240, 240) : Color.FromArgb(20, 20, 20); // 根据暗/亮模式设置文字颜色
|
|
|
|
|
|
label.Padding = new Padding(0); // 设置内边距为2像素
|
|
|
|
|
|
label.Font = new Font("Microsoft YaHei", 8); // 设置字体为微软雅黑8号
|
|
|
|
|
|
label.Multiline = true; // 启用多行显示
|
|
|
|
|
|
label.ReadOnly = true; // 设置为只读,防止编辑
|
2025-03-12 21:27:55 +08:00
|
|
|
|
label.BorderStyle = BorderStyle.None; // 移除边框
|
2025-03-12 22:27:37 +08:00
|
|
|
|
label.BackColor = panel.BackColor; // 背景色与面板一致
|
|
|
|
|
|
label.Height = textHeight; // 应用计算出的高度
|
2025-03-12 21:27:55 +08:00
|
|
|
|
|
|
|
|
|
|
// 将图标和文本框添加到面板中
|
|
|
|
|
|
panel.Controls.Add(icon); // 添加图标控件
|
|
|
|
|
|
panel.Controls.Add(label); // 添加文本框控件
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 设置右键菜单
|
|
|
|
|
|
panel.ContextMenuStrip = shortcutItemContextMenu;
|
|
|
|
|
|
icon.ContextMenuStrip = shortcutItemContextMenu;
|
|
|
|
|
|
label.ContextMenuStrip = shortcutItemContextMenu;
|
|
|
|
|
|
|
|
|
|
|
|
// 为右键菜单项设置Tag
|
2025-03-15 23:50:17 +08:00
|
|
|
|
//foreach (ToolStripItem menuItem in shortcutItemContextMenu.Items)
|
|
|
|
|
|
//{
|
|
|
|
|
|
// if (menuItem is ToolStripMenuItem)
|
|
|
|
|
|
// {
|
|
|
|
|
|
// menuItem.Tag = item;
|
|
|
|
|
|
// }
|
|
|
|
|
|
//}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加鼠标右键点击事件,在显示菜单前绑定当前选中的 ShortcutItem
|
|
|
|
|
|
EventHandler rightClickHandler = (s, e) =>
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-15 23:50:17 +08:00
|
|
|
|
if (s is Control control && control.Parent is RoundedPanel panel && panel.Tag is ShortcutItem item)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-15 23:50:17 +08:00
|
|
|
|
shortcutItemContextMenu.Tag = item; // 绑定当前选中的快捷方式
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
2025-03-15 23:50:17 +08:00
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 绑定到所有相关控件
|
|
|
|
|
|
panel.MouseDown += (s, e) => { if (e.Button == MouseButtons.Right) rightClickHandler(s, e); };
|
|
|
|
|
|
icon.MouseDown += (s, e) => { if (e.Button == MouseButtons.Right) rightClickHandler(s, e); };
|
|
|
|
|
|
label.MouseDown += (s, e) => { if (e.Button == MouseButtons.Right) rightClickHandler(s, e); };
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:44:35 +08:00
|
|
|
|
// 双击事件 - 启动应用程序或预览图片
|
2025-03-12 18:03:58 +08:00
|
|
|
|
EventHandler doubleClickHandler = (s, e) =>
|
2025-03-12 15:44:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (IsImageFile(item.Path))
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowImagePreview(item.Path);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
2025-03-12 18:03:58 +08:00
|
|
|
|
LaunchApplication(item.Path); // 启动应用程序
|
2025-03-12 15:44:35 +08:00
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
panel.DoubleClick += doubleClickHandler;
|
|
|
|
|
|
icon.DoubleClick += doubleClickHandler;
|
|
|
|
|
|
label.DoubleClick += doubleClickHandler;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 添加鼠标悬停效果
|
|
|
|
|
|
panel.MouseEnter += Panel_MouseEnter;
|
|
|
|
|
|
panel.MouseLeave += Panel_MouseLeave;
|
|
|
|
|
|
icon.MouseEnter += Panel_MouseEnter;
|
|
|
|
|
|
icon.MouseLeave += Panel_MouseLeave;
|
|
|
|
|
|
label.MouseEnter += Panel_MouseEnter;
|
|
|
|
|
|
label.MouseLeave += Panel_MouseLeave;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 添加鼠标点击效果
|
|
|
|
|
|
panel.MouseDown += Panel_MouseDown;
|
|
|
|
|
|
panel.MouseUp += Panel_MouseUp;
|
|
|
|
|
|
icon.MouseDown += Panel_MouseDown;
|
|
|
|
|
|
icon.MouseUp += Panel_MouseUp;
|
|
|
|
|
|
label.MouseDown += Panel_MouseDown;
|
|
|
|
|
|
label.MouseUp += Panel_MouseUp;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:44:35 +08:00
|
|
|
|
// 设置工具提示
|
|
|
|
|
|
string tipText = GetTooltipText(item);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
toolTip1.SetToolTip(panel, tipText);
|
|
|
|
|
|
toolTip1.SetToolTip(icon, tipText);
|
|
|
|
|
|
toolTip1.SetToolTip(label, tipText);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
shortcutsPanel.Controls.Add(panel);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 15:44:35 +08:00
|
|
|
|
private Image GetItemIcon(ShortcutItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (IsImageFile(item.Path))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 为图片文件创建缩略图
|
|
|
|
|
|
using (var img = Image.FromFile(item.Path))
|
|
|
|
|
|
{
|
|
|
|
|
|
return new Bitmap(img, new Size(iconSize, iconSize));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
return item.Icon ?? SystemIcons.Application.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
return item.Icon ?? SystemIcons.Application.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private bool IsImageFile(string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
string ext = Path.GetExtension(path).ToLower();
|
|
|
|
|
|
return new[] { ".jpg", ".jpeg", ".png", ".gif", ".bmp", ".tiff", ".ico" }.Contains(ext);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private string GetTooltipText(ShortcutItem item)
|
|
|
|
|
|
{
|
|
|
|
|
|
string type = IsImageFile(item.Path) ? "图片文件" : "应用程序";
|
|
|
|
|
|
return $"名称: {item.Name}\n类型: {type}\n路径: {item.Path}\n" +
|
|
|
|
|
|
$"添加时间: {item.DateAdded:yyyy-MM-dd}\n使用次数: {item.UsageCount}";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ShowImagePreview(string imagePath)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
using (var previewForm = new Form())
|
|
|
|
|
|
{
|
|
|
|
|
|
previewForm.Text = Path.GetFileName(imagePath);
|
|
|
|
|
|
previewForm.StartPosition = FormStartPosition.CenterScreen;
|
|
|
|
|
|
previewForm.BackColor = isDarkMode ? Color.FromArgb(32, 32, 32) : Color.FromArgb(243, 243, 243);
|
|
|
|
|
|
previewForm.WindowState = FormWindowState.Normal;
|
|
|
|
|
|
|
|
|
|
|
|
var pictureBox = new PictureBox
|
|
|
|
|
|
{
|
|
|
|
|
|
Dock = DockStyle.Fill,
|
|
|
|
|
|
SizeMode = PictureBoxSizeMode.Zoom,
|
|
|
|
|
|
Image = Image.FromFile(imagePath)
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 设置窗体大小为屏幕大小的80%
|
|
|
|
|
|
var screen = Screen.FromControl(this);
|
|
|
|
|
|
previewForm.Size = new Size(
|
|
|
|
|
|
(int)(screen.WorkingArea.Width * 0.8),
|
|
|
|
|
|
(int)(screen.WorkingArea.Height * 0.8)
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加ESC键关闭功能
|
|
|
|
|
|
previewForm.KeyPreview = true;
|
2025-03-12 18:03:58 +08:00
|
|
|
|
previewForm.KeyDown += (s, e) =>
|
2025-03-12 15:44:35 +08:00
|
|
|
|
{
|
|
|
|
|
|
if (e.KeyCode == Keys.Escape)
|
|
|
|
|
|
previewForm.Close();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 添加鼠标滚轮缩放
|
|
|
|
|
|
pictureBox.MouseWheel += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (ModifierKeys == Keys.Control)
|
|
|
|
|
|
{
|
|
|
|
|
|
float zoom = e.Delta > 0 ? 1.1f : 0.9f;
|
|
|
|
|
|
pictureBox.Size = new Size(
|
|
|
|
|
|
(int)(pictureBox.Size.Width * zoom),
|
|
|
|
|
|
(int)(pictureBox.Size.Height * zoom)
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2025-03-12 18:03:58 +08:00
|
|
|
|
var item = categories[currentCategory].FirstOrDefault(i => i.Path == imagePath);
|
|
|
|
|
|
if (item != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.UsageCount++;
|
|
|
|
|
|
item.LastUsed = DateTime.Now;
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 15:44:35 +08:00
|
|
|
|
previewForm.Controls.Add(pictureBox);
|
|
|
|
|
|
previewForm.ShowDialog();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"无法预览图片: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 鼠标进入面板时的效果
|
|
|
|
|
|
private void Panel_MouseEnter(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
if (sender is Control control && control.Parent is RoundedPanel panel)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用悬停效果
|
|
|
|
|
|
panel.BackColor = isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(230, 230, 230);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 显示工具提示
|
|
|
|
|
|
if (panel.Tag is ShortcutItem item)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
toolTip1.SetToolTip(panel, $"名称: {item.Name}\n路径: {item.Path}\n添加时间: {item.DateAdded.ToString("yyyy-MM-dd")}\n使用次数: {item.UsageCount}");
|
|
|
|
|
|
toolTip1.SetToolTip(control, $"名称: {item.Name}\n路径: {item.Path}\n添加时间: {item.DateAdded.ToString("yyyy-MM-dd")}\n使用次数: {item.UsageCount}");
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 15:18:23 +08:00
|
|
|
|
else if (sender is RoundedPanel directPanel && directPanel.Tag is ShortcutItem directItem)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 直接是面板的情况
|
|
|
|
|
|
directPanel.BackColor = isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(230, 230, 230);
|
|
|
|
|
|
toolTip1.SetToolTip(directPanel, $"名称: {directItem.Name}\n路径: {directItem.Path}\n添加时间: {directItem.DateAdded.ToString("yyyy-MM-dd")}\n使用次数: {directItem.UsageCount}");
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标离开面板时的效果
|
|
|
|
|
|
private void Panel_MouseLeave(object sender, EventArgs e)
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
if (sender is Control control && control.Parent is RoundedPanel panel)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 恢复正常颜色
|
|
|
|
|
|
panel.BackColor = isDarkMode ? Color.FromArgb(50, 50, 50) : Color.FromArgb(245, 245, 245);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is RoundedPanel directPanel)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 直接是面板的情况
|
|
|
|
|
|
directPanel.BackColor = isDarkMode ? Color.FromArgb(50, 50, 50) : Color.FromArgb(245, 245, 245);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标按下时的效果
|
|
|
|
|
|
private void Panel_MouseDown(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
if (sender is Control control && control.Parent is RoundedPanel panel)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 应用按下效果
|
|
|
|
|
|
panel.BackColor = isDarkMode ? Color.FromArgb(90, 90, 90) : Color.FromArgb(210, 210, 210);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is RoundedPanel directPanel)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 直接是面板的情况
|
|
|
|
|
|
directPanel.BackColor = isDarkMode ? Color.FromArgb(90, 90, 90) : Color.FromArgb(210, 210, 210);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标释放时的效果
|
|
|
|
|
|
private void Panel_MouseUp(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
if (sender is Control control && control.Parent is RoundedPanel panel)
|
2025-03-12 14:06:44 +08:00
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 恢复悬停颜色
|
|
|
|
|
|
panel.BackColor = isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(230, 230, 230);
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (sender is RoundedPanel directPanel)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 直接是面板的情况
|
|
|
|
|
|
directPanel.BackColor = isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(230, 230, 230);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加面板鼠标移动事件处理
|
|
|
|
|
|
private void ShortcutsPanel_MouseMove(object sender, MouseEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 获取鼠标位置下的控件
|
|
|
|
|
|
Control control = shortcutsPanel.GetChildAtPoint(e.Location);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 如果鼠标不在任何子控件上,则隐藏工具提示
|
|
|
|
|
|
if (control == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
toolTip1.RemoveAll();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加工具提示组件
|
|
|
|
|
|
private ToolTip toolTip1 = new ToolTip();
|
|
|
|
|
|
|
|
|
|
|
|
private void AddButton_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请先选择一个分类", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
using (OpenFileDialog dialog = new OpenFileDialog())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Filter = "应用程序|*.exe|所有文件|*.*";
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
AddNewShortcut(dialog.FileName, currentCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void AddNewShortcut(string filePath, string category)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 放宽文件类型限制,允许任何文件类型
|
|
|
|
|
|
var item = new ShortcutItem
|
|
|
|
|
|
{
|
|
|
|
|
|
Name = Path.GetFileNameWithoutExtension(filePath),
|
|
|
|
|
|
Path = filePath,
|
|
|
|
|
|
DateAdded = DateTime.Now,
|
|
|
|
|
|
UsageCount = 0
|
|
|
|
|
|
};
|
|
|
|
|
|
item.LoadIcon();
|
|
|
|
|
|
|
|
|
|
|
|
categories[category].Add(item);
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
if (category == currentCategory)
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowCategoryItems(category);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
2025-03-12 18:03:58 +08:00
|
|
|
|
// 启动应用程序
|
2025-03-12 14:06:44 +08:00
|
|
|
|
private void LaunchApplication(string path)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 查找并更新使用次数
|
|
|
|
|
|
if (!string.IsNullOrEmpty(currentCategory) && categories.ContainsKey(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
var item = categories[currentCategory].FirstOrDefault(i => i.Path == path);
|
|
|
|
|
|
if (item != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.UsageCount++;
|
|
|
|
|
|
item.LastUsed = DateTime.Now;
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var startInfo = new System.Diagnostics.ProcessStartInfo
|
|
|
|
|
|
{
|
|
|
|
|
|
FileName = path,
|
|
|
|
|
|
UseShellExecute = true
|
|
|
|
|
|
};
|
|
|
|
|
|
System.Diagnostics.Process.Start(startInfo);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"启动程序失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SaveData()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var options = new JsonSerializerOptions
|
|
|
|
|
|
{
|
|
|
|
|
|
WriteIndented = true
|
|
|
|
|
|
};
|
|
|
|
|
|
var data = JsonSerializer.Serialize(categories, options);
|
|
|
|
|
|
File.WriteAllText(dataFilePath, data);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"保存配置失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void LoadData()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (File.Exists(dataFilePath))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
var json = File.ReadAllText(dataFilePath);
|
|
|
|
|
|
categories = JsonSerializer.Deserialize<Dictionary<string, List<ShortcutItem>>>(json);
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
// 加载所有图标
|
|
|
|
|
|
foreach (var category in categories.Values)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in category)
|
|
|
|
|
|
{
|
|
|
|
|
|
item.LoadIcon();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
2025-03-12 14:06:44 +08:00
|
|
|
|
RefreshCategoryList();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
|
|
|
|
|
|
// 如果有上次选择的分类,则选择它
|
|
|
|
|
|
if (!string.IsNullOrEmpty(settings.LastSelectedCategory) && categories.ContainsKey(settings.LastSelectedCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
SwitchCategory(settings.LastSelectedCategory);
|
|
|
|
|
|
}
|
|
|
|
|
|
// 否则选择第一个分类
|
|
|
|
|
|
else if (categories.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
SwitchCategory(categories.Keys.First());
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"加载配置失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
categories = new Dictionary<string, List<ShortcutItem>>();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果没有数据文件,创建一个默认分类
|
|
|
|
|
|
categories = new Dictionary<string, List<ShortcutItem>>();
|
|
|
|
|
|
categories["默认分类"] = new List<ShortcutItem>();
|
|
|
|
|
|
SaveData();
|
|
|
|
|
|
RefreshCategoryList();
|
2025-03-12 18:03:58 +08:00
|
|
|
|
SwitchCategory("默认分类");
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void SwitchCategory(string category)
|
|
|
|
|
|
{
|
|
|
|
|
|
currentCategory = category;
|
|
|
|
|
|
RefreshCategoryList();
|
|
|
|
|
|
ShowCategoryItems(category);
|
|
|
|
|
|
SaveSettings(); // 保存当前选择的分类
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void button1_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
isDarkMode = !isDarkMode; // 切换主题状态
|
|
|
|
|
|
ApplyTheme(isDarkMode);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private void ApplyTheme(bool darkMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (darkMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
ChangeTheme(true);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
2025-03-12 18:03:58 +08:00
|
|
|
|
else
|
|
|
|
|
|
ChangeTheme(false);
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
2025-03-12 22:27:37 +08:00
|
|
|
|
|
|
|
|
|
|
private void 关于ToolStripMenuItem_Click(object sender, EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
Form1 form1 = new Form1();
|
|
|
|
|
|
form1.StartPosition = FormStartPosition.CenterParent;
|
|
|
|
|
|
form1.ShowDialog(this);
|
|
|
|
|
|
}
|
2025-03-13 14:08:06 +08:00
|
|
|
|
|
|
|
|
|
|
// 初始化通知图标和浮动图标
|
|
|
|
|
|
private void InitializeNotifyIcon()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建通知区域图标
|
|
|
|
|
|
notifyIcon = new NotifyIcon
|
|
|
|
|
|
{
|
|
|
|
|
|
Icon = this.Icon,
|
|
|
|
|
|
Text = "工具箱",
|
|
|
|
|
|
Visible = true
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 创建右键菜单
|
|
|
|
|
|
ContextMenuStrip contextMenu = new ContextMenuStrip();
|
|
|
|
|
|
contextMenu.Items.Add("显示主窗口", null, (s, e) => { ShowMainWindowAndHideIcon(); });
|
|
|
|
|
|
contextMenu.Items.Add("-");
|
|
|
|
|
|
contextMenu.Items.Add("添加新快捷方式", null, (s, e) => { ShowMainWindowAndAddShortcut(); });
|
|
|
|
|
|
contextMenu.Items.Add("打开最近使用的项目", null, (s, e) => { ShowRecentItemsMenu(); });
|
|
|
|
|
|
contextMenu.Items.Add("-");
|
|
|
|
|
|
|
|
|
|
|
|
// 添加浮动图标控制选项
|
|
|
|
|
|
var floatingIconMenu = new ToolStripMenuItem("浮动图标");
|
|
|
|
|
|
floatingIconMenu.DropDownItems.Add("显示浮动图标", null, (s, e) => { ShowFloatingIcon(); });
|
|
|
|
|
|
floatingIconMenu.DropDownItems.Add("隐藏浮动图标", null, (s, e) => { HideFloatingIcon(); });
|
|
|
|
|
|
contextMenu.Items.Add(floatingIconMenu);
|
|
|
|
|
|
|
|
|
|
|
|
contextMenu.Items.Add("设置", null, (s, e) => { ShowSettingsDialog(); });
|
|
|
|
|
|
contextMenu.Items.Add("-");
|
|
|
|
|
|
contextMenu.Items.Add("退出", null, (s, e) => { ExitApplication(); });
|
|
|
|
|
|
|
|
|
|
|
|
// 应用主题颜色
|
|
|
|
|
|
contextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
|
|
|
|
|
|
notifyIcon.ContextMenuStrip = contextMenu;
|
|
|
|
|
|
notifyIcon.MouseClick += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowMainWindowAndHideIcon();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 创建浮动图标窗体
|
|
|
|
|
|
CreateFloatingIcon();
|
|
|
|
|
|
|
|
|
|
|
|
// 不再根据设置自动显示浮动图标
|
|
|
|
|
|
// 浮动图标只会在主窗口最小化或关闭时显示
|
|
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 记录错误但不中断程序运行
|
|
|
|
|
|
MessageBox.Show($"初始化通知图标时出错: {ex.Message}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示主窗口并隐藏浮动图标
|
|
|
|
|
|
private void ShowMainWindowAndHideIcon()
|
|
|
|
|
|
{
|
|
|
|
|
|
HideFloatingIcon();
|
|
|
|
|
|
ShowMainWindow();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示主窗口
|
|
|
|
|
|
private void ShowMainWindow()
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Show();
|
|
|
|
|
|
this.WindowState = FormWindowState.Normal;
|
|
|
|
|
|
this.Activate();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重写窗体状态改变事件
|
|
|
|
|
|
protected override void OnResize(EventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
base.OnResize(e);
|
|
|
|
|
|
|
|
|
|
|
|
// 当窗口最小化时,显示浮动图标
|
|
|
|
|
|
if (this.WindowState == FormWindowState.Minimized)
|
|
|
|
|
|
{
|
|
|
|
|
|
this.Hide();
|
|
|
|
|
|
ShowFloatingIcon();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 重写窗体关闭事件
|
|
|
|
|
|
protected override void OnFormClosing(FormClosingEventArgs e)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.CloseReason == CloseReason.UserClosing)
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Cancel = true; // 取消关闭操作
|
|
|
|
|
|
this.Hide(); // 隐藏窗体
|
|
|
|
|
|
ShowFloatingIcon(); // 显示浮动图标
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 清理资源
|
|
|
|
|
|
if (notifyIcon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
notifyIcon.Visible = false;
|
|
|
|
|
|
notifyIcon.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (floatingIcon != null && !floatingIcon.IsDisposed)
|
|
|
|
|
|
{
|
|
|
|
|
|
floatingIcon.Close();
|
|
|
|
|
|
floatingIcon.Dispose();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
base.OnFormClosing(e);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建浮动图标窗体
|
|
|
|
|
|
private void CreateFloatingIcon()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
floatingIcon = new Form
|
|
|
|
|
|
{
|
|
|
|
|
|
Size = new Size(64, 64), // 增大尺寸,更容易点击
|
|
|
|
|
|
FormBorderStyle = FormBorderStyle.None,
|
|
|
|
|
|
ShowInTaskbar = false,
|
|
|
|
|
|
TopMost = true,
|
|
|
|
|
|
StartPosition = FormStartPosition.Manual,
|
|
|
|
|
|
TransparencyKey = Color.Magenta, // 设置透明色
|
|
|
|
|
|
BackColor = Color.Magenta, // 设置背景色为透明色
|
|
|
|
|
|
Visible = false // 确保创建时默认隐藏
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 创建一个圆形面板作为图标容器
|
|
|
|
|
|
RoundedPanel iconPanel = new RoundedPanel
|
|
|
|
|
|
{
|
|
|
|
|
|
Size = new Size(64, 64), // 增大尺寸
|
|
|
|
|
|
Location = new Point(0, 0),
|
|
|
|
|
|
CornerRadius = 60, // 完全圆形
|
|
|
|
|
|
BackColor = Color.FromArgb(50, 50, 50) // 使用强调色,更加醒目
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 添加阴影效果
|
|
|
|
|
|
iconPanel.Paint += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置高质量绘图模式
|
|
|
|
|
|
e.Graphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
|
e.Graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
|
|
|
|
e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
|
|
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制阴影
|
|
|
|
|
|
using (GraphicsPath path = new GraphicsPath())
|
|
|
|
|
|
{
|
|
|
|
|
|
path.AddEllipse(0, 0, iconPanel.Width, iconPanel.Height);
|
|
|
|
|
|
|
|
|
|
|
|
// 创建渐变背景
|
|
|
|
|
|
Color baseColor = isDarkMode ? Color.FromArgb(50, 50, 50) : Color.FromArgb(240, 240, 240);
|
|
|
|
|
|
Color gradientColor = isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(220, 220, 220);
|
|
|
|
|
|
|
|
|
|
|
|
using (LinearGradientBrush bgBrush = new LinearGradientBrush(
|
|
|
|
|
|
new Point(0, 0),
|
|
|
|
|
|
new Point(0, iconPanel.Height),
|
|
|
|
|
|
baseColor,
|
|
|
|
|
|
gradientColor))
|
|
|
|
|
|
{
|
|
|
|
|
|
e.Graphics.FillPath(bgBrush, path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 创建阴影效果
|
|
|
|
|
|
using (PathGradientBrush brush = new PathGradientBrush(path))
|
|
|
|
|
|
{
|
|
|
|
|
|
brush.CenterColor = Color.FromArgb(0, 0, 0, 0);
|
|
|
|
|
|
brush.SurroundColors = new Color[] { Color.FromArgb(80, 0, 0, 0) }; // 增强阴影效果
|
|
|
|
|
|
brush.WrapMode = WrapMode.Clamp;
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制阴影
|
|
|
|
|
|
e.Graphics.FillPath(brush, path);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 绘制边框 - 使用白色或深色边框增加对比度
|
|
|
|
|
|
using (Pen pen = new Pen(isDarkMode ? Color.FromArgb(180, 180, 180) : Color.FromArgb(50, 50, 50), 1.5f))
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置平滑连接和端点
|
|
|
|
|
|
pen.LineJoin = LineJoin.Round;
|
|
|
|
|
|
pen.StartCap = LineCap.Round;
|
|
|
|
|
|
pen.EndCap = LineCap.Round;
|
|
|
|
|
|
pen.Alignment = PenAlignment.Center; // 确保边框居中对齐
|
|
|
|
|
|
|
|
|
|
|
|
// 使用更平滑的方式绘制圆形
|
|
|
|
|
|
e.Graphics.DrawEllipse(pen, 0, 0, iconPanel.Width - 1, iconPanel.Height - 1);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加内部边框,创造更精致的外观
|
|
|
|
|
|
using (Pen innerPen = new Pen(isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(220, 220, 220), 1f))
|
|
|
|
|
|
{
|
|
|
|
|
|
innerPen.LineJoin = LineJoin.Round;
|
|
|
|
|
|
innerPen.StartCap = LineCap.Round;
|
|
|
|
|
|
innerPen.EndCap = LineCap.Round;
|
|
|
|
|
|
innerPen.Alignment = PenAlignment.Center; // 确保边框居中对齐
|
|
|
|
|
|
|
|
|
|
|
|
// 使用更平滑的方式绘制内部圆形
|
|
|
|
|
|
e.Graphics.DrawEllipse(innerPen, 2, 2, iconPanel.Width - 5, iconPanel.Height - 5);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 添加图标
|
|
|
|
|
|
PictureBox iconBox = new PictureBox
|
|
|
|
|
|
{
|
|
|
|
|
|
Size = new Size(48, 48), // 稍微调整图标尺寸
|
|
|
|
|
|
Location = new Point(8, 8), // 居中放置
|
|
|
|
|
|
SizeMode = PictureBoxSizeMode.StretchImage,
|
|
|
|
|
|
BackColor = Color.Transparent // 使用透明背景,让图标更清晰
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试加载自定义图标
|
|
|
|
|
|
Image iconImage = null;
|
|
|
|
|
|
if (!string.IsNullOrEmpty(settings.FloatingIconPath) && File.Exists(settings.FloatingIconPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
iconImage = Image.FromFile(settings.FloatingIconPath);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果加载失败,使用默认图标
|
|
|
|
|
|
iconImage = this.Icon.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 使用默认图标
|
|
|
|
|
|
iconImage = this.Icon.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 优化图标显示
|
|
|
|
|
|
try {
|
|
|
|
|
|
// 尝试创建高质量图标
|
|
|
|
|
|
Bitmap highQualityIcon = new Bitmap(48, 48);
|
|
|
|
|
|
using (Graphics g = Graphics.FromImage(highQualityIcon))
|
|
|
|
|
|
{
|
|
|
|
|
|
g.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
|
g.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
|
|
|
|
g.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
|
|
g.CompositingQuality = CompositingQuality.HighQuality;
|
|
|
|
|
|
g.DrawImage(iconImage, 0, 0, 48, 48);
|
|
|
|
|
|
}
|
|
|
|
|
|
iconBox.Image = highQualityIcon;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch {
|
|
|
|
|
|
// 如果失败,使用原始图标
|
|
|
|
|
|
iconBox.Image = iconImage;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
iconPanel.Controls.Add(iconBox);
|
|
|
|
|
|
floatingIcon.Controls.Add(iconPanel);
|
|
|
|
|
|
|
|
|
|
|
|
// 添加鼠标事件
|
|
|
|
|
|
bool isDragging = false;
|
|
|
|
|
|
Point dragStartPoint = Point.Empty;
|
|
|
|
|
|
|
|
|
|
|
|
// 添加双击事件
|
|
|
|
|
|
iconPanel.DoubleClick += (s, e) => {
|
|
|
|
|
|
ShowMainWindowAndHideIcon();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconBox.DoubleClick += (s, e) => {
|
|
|
|
|
|
ShowMainWindowAndHideIcon();
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标进入时的效果 - 使用更明显的高亮效果
|
|
|
|
|
|
iconPanel.MouseEnter += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 高亮效果 - 使用更亮的颜色
|
|
|
|
|
|
Color brighterColor = Color.FromArgb(
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).R + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).G + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).B + 30, 255)
|
|
|
|
|
|
);
|
|
|
|
|
|
iconPanel.BackColor = brighterColor;
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 鼠标离开时的效果
|
|
|
|
|
|
iconPanel.MouseLeave += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
iconPanel.BackColor = Color.FromArgb(50, 50, 50);
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconPanel.MouseDown += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
isDragging = true;
|
|
|
|
|
|
dragStartPoint = e.Location;
|
|
|
|
|
|
// 按下效果 - 使用更深的颜色
|
|
|
|
|
|
Color darkerColor = Color.FromArgb(
|
|
|
|
|
|
Math.Max(Color.FromArgb(50, 50, 50).R - 30, 0),
|
|
|
|
|
|
Math.Max(Color.FromArgb(50, 50, 50).G - 30, 0),
|
|
|
|
|
|
Math.Max(Color.FromArgb(50, 50, 50).B - 30, 0)
|
|
|
|
|
|
);
|
|
|
|
|
|
iconPanel.BackColor = darkerColor;
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconPanel.MouseMove += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isDragging)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 计算新位置
|
|
|
|
|
|
Point newLocation = new Point(
|
|
|
|
|
|
floatingIcon.Location.X + e.X - dragStartPoint.X,
|
|
|
|
|
|
floatingIcon.Location.Y + e.Y - dragStartPoint.Y
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 确保不超出屏幕边界
|
|
|
|
|
|
newLocation = EnsureIconOnScreen(newLocation);
|
|
|
|
|
|
|
|
|
|
|
|
// 应用新位置
|
|
|
|
|
|
floatingIcon.Location = newLocation;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconPanel.MouseUp += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isDragging)
|
|
|
|
|
|
{
|
|
|
|
|
|
isDragging = false;
|
|
|
|
|
|
// 恢复悬停效果
|
|
|
|
|
|
Color brighterColor = Color.FromArgb(
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).R + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).G + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).B + 30, 255)
|
|
|
|
|
|
);
|
|
|
|
|
|
iconPanel.BackColor = brighterColor;
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (e.Button == MouseButtons.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 单击左键时显示主窗口并隐藏浮动图标
|
|
|
|
|
|
ShowMainWindowAndHideIcon();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 为图标也添加相同的事件处理
|
|
|
|
|
|
iconBox.MouseEnter += (s, e) => {
|
|
|
|
|
|
// 使用与面板相同的高亮效果
|
|
|
|
|
|
Color brighterColor = Color.FromArgb(
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).R + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).G + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).B + 30, 255)
|
|
|
|
|
|
);
|
|
|
|
|
|
iconPanel.BackColor = brighterColor;
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconBox.MouseLeave += (s, e) => {
|
|
|
|
|
|
// 恢复正常颜色
|
|
|
|
|
|
iconPanel.BackColor = Color.FromArgb(50, 50, 50);
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconBox.MouseDown += (s, e) => {
|
|
|
|
|
|
if (e.Button == MouseButtons.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
isDragging = true;
|
|
|
|
|
|
dragStartPoint = e.Location;
|
|
|
|
|
|
// 按下效果 - 使用更深的颜色
|
|
|
|
|
|
Color darkerColor = Color.FromArgb(
|
|
|
|
|
|
Math.Max(Color.FromArgb(50, 50, 50).R - 30, 0),
|
|
|
|
|
|
Math.Max(Color.FromArgb(50, 50, 50).G - 30, 0),
|
|
|
|
|
|
Math.Max(Color.FromArgb(50, 50, 50).B - 30, 0)
|
|
|
|
|
|
);
|
|
|
|
|
|
iconPanel.BackColor = darkerColor;
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconBox.MouseMove += (s, e) => {
|
|
|
|
|
|
if (isDragging)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 计算新位置
|
|
|
|
|
|
Point newLocation = new Point(
|
|
|
|
|
|
floatingIcon.Location.X + e.X - dragStartPoint.X,
|
|
|
|
|
|
floatingIcon.Location.Y + e.Y - dragStartPoint.Y
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
|
|
|
|
// 确保不超出屏幕边界
|
|
|
|
|
|
newLocation = EnsureIconOnScreen(newLocation);
|
|
|
|
|
|
|
|
|
|
|
|
// 应用新位置
|
|
|
|
|
|
floatingIcon.Location = newLocation;
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
iconBox.MouseUp += (s, e) => {
|
|
|
|
|
|
if (isDragging)
|
|
|
|
|
|
{
|
|
|
|
|
|
isDragging = false;
|
|
|
|
|
|
// 恢复悬停效果
|
|
|
|
|
|
Color brighterColor = Color.FromArgb(
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).R + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).G + 30, 255),
|
|
|
|
|
|
Math.Min(Color.FromArgb(50, 50, 50).B + 30, 255)
|
|
|
|
|
|
);
|
|
|
|
|
|
iconPanel.BackColor = brighterColor;
|
|
|
|
|
|
// 不再设置窗体背景色
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (e.Button == MouseButtons.Left)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 单击左键时显示主窗口并隐藏浮动图标
|
|
|
|
|
|
ShowMainWindowAndHideIcon();
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
// 右键菜单
|
|
|
|
|
|
ContextMenuStrip iconMenu = new ContextMenuStrip();
|
|
|
|
|
|
iconMenu.Items.Add("显示主窗口", null, (s, e) => { ShowMainWindowAndHideIcon(); });
|
|
|
|
|
|
iconMenu.Items.Add("-");
|
|
|
|
|
|
iconMenu.Items.Add("添加新快捷方式", null, (s, e) => { ShowMainWindowAndAddShortcut(); });
|
|
|
|
|
|
iconMenu.Items.Add("打开最近使用的项目", null, (s, e) => { ShowRecentItemsMenu(); });
|
|
|
|
|
|
iconMenu.Items.Add("-");
|
|
|
|
|
|
iconMenu.Items.Add("修改浮动按钮图标", null, (s, e) => { ChangeFloatingIconImage(); });
|
|
|
|
|
|
iconMenu.Items.Add("-");
|
|
|
|
|
|
iconMenu.Items.Add("设置", null, (s, e) => { ShowSettingsDialog(); });
|
|
|
|
|
|
iconMenu.Items.Add("-");
|
|
|
|
|
|
iconMenu.Items.Add("退出", null, (s, e) => { ExitApplication(); });
|
|
|
|
|
|
|
|
|
|
|
|
// 应用主题颜色
|
|
|
|
|
|
iconMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
|
|
|
|
|
|
iconPanel.ContextMenuStrip = iconMenu;
|
|
|
|
|
|
iconBox.ContextMenuStrip = iconMenu;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"创建浮动图标时出错: {ex.Message}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示主窗口并立即打开添加快捷方式对话框
|
|
|
|
|
|
private void ShowMainWindowAndAddShortcut()
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowMainWindowAndHideIcon();
|
|
|
|
|
|
|
|
|
|
|
|
// 等待主窗口完全显示
|
|
|
|
|
|
this.BeginInvoke(new Action(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (!string.IsNullOrEmpty(currentCategory))
|
|
|
|
|
|
{
|
|
|
|
|
|
AddButton_Click(null, EventArgs.Empty);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("请先选择一个分类", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
}
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示最近使用的项目菜单
|
|
|
|
|
|
private void ShowRecentItemsMenu()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 创建一个临时菜单
|
|
|
|
|
|
ContextMenuStrip recentMenu = new ContextMenuStrip();
|
|
|
|
|
|
recentMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
|
|
|
|
|
|
|
|
|
|
|
// 获取最近使用的项目(所有分类中按最后使用时间排序的前10个项目)
|
|
|
|
|
|
var recentItems = categories
|
|
|
|
|
|
.SelectMany(c => c.Value)
|
|
|
|
|
|
.Where(item => item.LastUsed > DateTime.MinValue)
|
|
|
|
|
|
.OrderByDescending(item => item.LastUsed)
|
|
|
|
|
|
.Take(10)
|
|
|
|
|
|
.ToList();
|
|
|
|
|
|
|
|
|
|
|
|
if (recentItems.Count > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (var item in recentItems)
|
|
|
|
|
|
{
|
|
|
|
|
|
var menuItem = new ToolStripMenuItem(item.Name);
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试设置图标
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
if (item.Icon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
menuItem.Image = new Bitmap(item.Icon, new Size(16, 16));
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
|
|
|
|
|
|
menuItem.Tag = item;
|
|
|
|
|
|
menuItem.Click += (s, e) =>
|
|
|
|
|
|
{
|
|
|
|
|
|
if (s is ToolStripMenuItem mi && mi.Tag is ShortcutItem shortcut)
|
|
|
|
|
|
{
|
|
|
|
|
|
LaunchApplication(shortcut.Path);
|
|
|
|
|
|
}
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
recentMenu.Items.Add(menuItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
var noItemsMenuItem = new ToolStripMenuItem("没有最近使用的项目");
|
|
|
|
|
|
noItemsMenuItem.Enabled = false;
|
|
|
|
|
|
recentMenu.Items.Add(noItemsMenuItem);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示菜单
|
|
|
|
|
|
recentMenu.Show(Cursor.Position);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"显示最近使用项目时出错: {ex.Message}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示设置对话框
|
|
|
|
|
|
private void ShowSettingsDialog()
|
|
|
|
|
|
{
|
|
|
|
|
|
ShowMainWindowAndHideIcon();
|
|
|
|
|
|
|
|
|
|
|
|
// 等待主窗口完全显示
|
|
|
|
|
|
this.BeginInvoke(new Action(() =>
|
|
|
|
|
|
{
|
|
|
|
|
|
// 这里可以打开设置对话框
|
|
|
|
|
|
MessageBox.Show("设置功能尚未实现", "提示", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
}));
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 退出应用程序
|
|
|
|
|
|
private void ExitApplication()
|
|
|
|
|
|
{
|
|
|
|
|
|
// 确认是否退出
|
|
|
|
|
|
if (MessageBox.Show("确定要退出程序吗?", "确认", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.Yes)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 保存设置
|
|
|
|
|
|
SaveSettings();
|
|
|
|
|
|
|
|
|
|
|
|
// 清理资源
|
|
|
|
|
|
if (notifyIcon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
notifyIcon.Visible = false;
|
|
|
|
|
|
notifyIcon.Dispose();
|
|
|
|
|
|
notifyIcon = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (floatingIcon != null && !floatingIcon.IsDisposed)
|
|
|
|
|
|
{
|
|
|
|
|
|
floatingIcon.Close();
|
|
|
|
|
|
floatingIcon.Dispose();
|
|
|
|
|
|
floatingIcon = null;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用 ExitThread 而不是 Exit
|
|
|
|
|
|
Application.ExitThread();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"退出程序时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
// 如果出错,强制退出
|
|
|
|
|
|
Environment.Exit(0);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 显示浮动图标
|
|
|
|
|
|
private void ShowFloatingIcon()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (floatingIcon == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
CreateFloatingIcon();
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"创建浮动图标时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
if (!isFloatingIconVisible && floatingIcon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 设置初始位置(屏幕右侧中间)
|
|
|
|
|
|
Screen screen = Screen.PrimaryScreen;
|
|
|
|
|
|
|
|
|
|
|
|
// 如果有保存的位置,使用保存的位置
|
|
|
|
|
|
Point iconPosition;
|
|
|
|
|
|
if (settings.FloatingIconPosition.X != 0 && settings.FloatingIconPosition.Y != 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
iconPosition = settings.FloatingIconPosition;
|
|
|
|
|
|
|
|
|
|
|
|
// 确保图标在屏幕内
|
|
|
|
|
|
iconPosition = EnsureIconOnScreen(iconPosition);
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
// 默认位置:屏幕右侧中间
|
|
|
|
|
|
iconPosition = new Point(
|
|
|
|
|
|
screen.WorkingArea.Right - floatingIcon.Width - 20,
|
|
|
|
|
|
screen.WorkingArea.Bottom / 2 - floatingIcon.Height / 2
|
|
|
|
|
|
);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
floatingIcon.Location = iconPosition;
|
|
|
|
|
|
floatingIcon.Show();
|
|
|
|
|
|
isFloatingIconVisible = true;
|
|
|
|
|
|
|
|
|
|
|
|
// 移除淡入效果代码,直接显示
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"显示浮动图标时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 隐藏浮动图标
|
|
|
|
|
|
private void HideFloatingIcon()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isFloatingIconVisible && floatingIcon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 保存当前位置
|
|
|
|
|
|
settings.FloatingIconPosition = floatingIcon.Location;
|
|
|
|
|
|
SaveSettings();
|
|
|
|
|
|
|
|
|
|
|
|
// 移除淡出效果代码,直接隐藏
|
|
|
|
|
|
floatingIcon.Hide();
|
|
|
|
|
|
isFloatingIconVisible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果出现错误,尝试直接隐藏
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
floatingIcon.Hide();
|
|
|
|
|
|
isFloatingIconVisible = false;
|
|
|
|
|
|
}
|
|
|
|
|
|
catch { }
|
|
|
|
|
|
|
|
|
|
|
|
MessageBox.Show($"隐藏浮动图标时出错: {ex.Message}", "警告", MessageBoxButtons.OK, MessageBoxIcon.Warning);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 完全重写确保图标在屏幕内的方法
|
|
|
|
|
|
private Point EnsureIconOnScreen(Point position)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (floatingIcon == null)
|
|
|
|
|
|
return position;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取包含该点的屏幕
|
|
|
|
|
|
Screen screen = Screen.FromPoint(position);
|
|
|
|
|
|
if (screen == null)
|
|
|
|
|
|
{
|
|
|
|
|
|
screen = Screen.PrimaryScreen;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
Rectangle workArea = screen.WorkingArea;
|
|
|
|
|
|
|
|
|
|
|
|
// 获取浮动图标的实际大小
|
|
|
|
|
|
int iconWidth = floatingIcon.Width;
|
|
|
|
|
|
int iconHeight = floatingIcon.Height;
|
|
|
|
|
|
|
|
|
|
|
|
// 计算实际可见图标的大小(圆形部分)
|
|
|
|
|
|
int visibleIconSize = 64; // 圆形图标的直径
|
|
|
|
|
|
|
|
|
|
|
|
// 计算边缘偏移量
|
|
|
|
|
|
int leftOffset = 0; // 左侧不需要偏移
|
|
|
|
|
|
int topOffset = 0; // 顶部不需要偏移
|
|
|
|
|
|
int rightOffset = iconWidth - visibleIconSize; // 右侧偏移量等于窗体宽度减去可见图标宽度
|
|
|
|
|
|
int bottomOffset = iconHeight - visibleIconSize; // 底部偏移量等于窗体高度减去可见图标高度
|
|
|
|
|
|
|
|
|
|
|
|
// 为了确保图标能够完全贴近右侧边缘,额外增加偏移量
|
|
|
|
|
|
//rightOffset += 10; // 额外增加20像素的偏移量
|
|
|
|
|
|
|
|
|
|
|
|
// 确保X坐标在屏幕内
|
|
|
|
|
|
if (position.X < workArea.Left - leftOffset)
|
|
|
|
|
|
{
|
|
|
|
|
|
position.X = workArea.Left - leftOffset;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (position.X + iconWidth > workArea.Right + rightOffset)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 确保图标可以完全贴近屏幕右侧边缘
|
|
|
|
|
|
position.X = workArea.Right + rightOffset - iconWidth;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 确保Y坐标在屏幕内
|
|
|
|
|
|
if (position.Y < workArea.Top - topOffset)
|
|
|
|
|
|
{
|
|
|
|
|
|
position.Y = workArea.Top - topOffset;
|
|
|
|
|
|
}
|
|
|
|
|
|
else if (position.Y + iconHeight > workArea.Bottom + bottomOffset)
|
|
|
|
|
|
{
|
|
|
|
|
|
position.Y = workArea.Bottom + bottomOffset - iconHeight;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return position;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 切换浮动图标显示状态
|
|
|
|
|
|
private void ToggleFloatingIcon()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (isFloatingIconVisible)
|
|
|
|
|
|
HideFloatingIcon();
|
|
|
|
|
|
else
|
|
|
|
|
|
ShowFloatingIcon();
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 修改浮动按钮图标
|
|
|
|
|
|
private void ChangeFloatingIconImage()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 显示文件选择对话框
|
|
|
|
|
|
using (OpenFileDialog dialog = new OpenFileDialog())
|
|
|
|
|
|
{
|
|
|
|
|
|
dialog.Title = "选择新的浮动按钮图标";
|
|
|
|
|
|
dialog.Filter = "图标文件|*.ico;*.png;*.jpg;*.jpeg;*.bmp;*.gif|所有文件|*.*";
|
|
|
|
|
|
dialog.Multiselect = false;
|
|
|
|
|
|
|
|
|
|
|
|
if (dialog.ShowDialog() == DialogResult.OK)
|
|
|
|
|
|
{
|
|
|
|
|
|
string iconPath = dialog.FileName;
|
|
|
|
|
|
|
|
|
|
|
|
// 检查文件是否存在
|
|
|
|
|
|
if (!File.Exists(iconPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show("选择的文件不存在", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 尝试加载图标
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
Image newIcon = Image.FromFile(iconPath);
|
|
|
|
|
|
|
|
|
|
|
|
// 查找浮动图标中的PictureBox控件
|
|
|
|
|
|
if (floatingIcon != null && !floatingIcon.IsDisposed)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (Control control in floatingIcon.Controls)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (control is RoundedPanel panel)
|
|
|
|
|
|
{
|
|
|
|
|
|
foreach (Control panelControl in panel.Controls)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (panelControl is PictureBox iconBox)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 更新图标
|
|
|
|
|
|
iconBox.Image = newIcon;
|
|
|
|
|
|
|
|
|
|
|
|
// 保存图标路径到设置
|
|
|
|
|
|
settings.FloatingIconPath = iconPath;
|
|
|
|
|
|
SaveSettings();
|
|
|
|
|
|
|
|
|
|
|
|
MessageBox.Show("浮动按钮图标已更新", "成功", MessageBoxButtons.OK, MessageBoxIcon.Information);
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
MessageBox.Show("无法找到浮动按钮图标控件", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"加载图标文件失败: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch (Exception ex)
|
|
|
|
|
|
{
|
|
|
|
|
|
MessageBox.Show($"修改浮动按钮图标时出错: {ex.Message}", "错误", MessageBoxButtons.OK, MessageBoxIcon.Error);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public class ShortcutItem
|
|
|
|
|
|
{
|
|
|
|
|
|
public string Name { get; set; }
|
|
|
|
|
|
public string Path { get; set; }
|
|
|
|
|
|
[System.Text.Json.Serialization.JsonIgnore]
|
|
|
|
|
|
public Bitmap Icon { get; set; }
|
|
|
|
|
|
public DateTime DateAdded { get; set; } = DateTime.Now;
|
|
|
|
|
|
public DateTime LastUsed { get; set; } = DateTime.MinValue;
|
|
|
|
|
|
public int UsageCount { get; set; } = 0;
|
2025-03-12 15:18:23 +08:00
|
|
|
|
public string Description { get; set; } = ""; // 添加描述属性
|
|
|
|
|
|
public string Arguments { get; set; } = ""; // 添加启动参数
|
|
|
|
|
|
public bool RunAsAdmin { get; set; } = false; // 是否以管理员身份运行
|
|
|
|
|
|
public string Category { get; set; } = ""; // 所属分类
|
|
|
|
|
|
public string CustomIconPath { get; set; } = ""; // 自定义图标路径
|
|
|
|
|
|
public string BackgroundColor { get; set; } = ""; // 自定义背景色
|
|
|
|
|
|
public int SortOrder { get; set; } = 0; // 排序顺序
|
2025-03-12 14:06:44 +08:00
|
|
|
|
|
|
|
|
|
|
// 用于序列化的构造函数
|
|
|
|
|
|
public ShortcutItem()
|
|
|
|
|
|
{
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 加载图标的方法
|
|
|
|
|
|
public void LoadIcon()
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
2025-03-12 15:18:23 +08:00
|
|
|
|
// 如果有自定义图标,优先使用自定义图标
|
|
|
|
|
|
if (!string.IsNullOrEmpty(CustomIconPath) && File.Exists(CustomIconPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 尝试加载自定义图标
|
|
|
|
|
|
using (System.Drawing.Icon customIcon = new System.Drawing.Icon(CustomIconPath))
|
|
|
|
|
|
{
|
|
|
|
|
|
Icon = customIcon.ToBitmap();
|
|
|
|
|
|
return;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果自定义图标加载失败,继续使用默认图标
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 使用关联图标
|
2025-03-12 14:06:44 +08:00
|
|
|
|
if (File.Exists(Path))
|
|
|
|
|
|
{
|
|
|
|
|
|
using (System.Drawing.Icon icon = System.Drawing.Icon.ExtractAssociatedIcon(Path))
|
|
|
|
|
|
{
|
|
|
|
|
|
if (icon != null)
|
|
|
|
|
|
{
|
|
|
|
|
|
Icon = icon.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Icon = SystemIcons.Application.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
Icon = SystemIcons.Application.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
Icon = SystemIcons.Application.ToBitmap();
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
2025-03-12 15:18:23 +08:00
|
|
|
|
|
|
|
|
|
|
// 获取格式化的最后使用时间
|
|
|
|
|
|
public string GetFormattedLastUsed()
|
|
|
|
|
|
{
|
|
|
|
|
|
if (LastUsed == DateTime.MinValue)
|
|
|
|
|
|
return "从未使用";
|
|
|
|
|
|
|
|
|
|
|
|
TimeSpan span = DateTime.Now - LastUsed;
|
|
|
|
|
|
|
|
|
|
|
|
if (span.TotalDays > 365)
|
|
|
|
|
|
return $"{Math.Floor(span.TotalDays / 365)}年前";
|
|
|
|
|
|
if (span.TotalDays > 30)
|
|
|
|
|
|
return $"{Math.Floor(span.TotalDays / 30)}个月前";
|
|
|
|
|
|
if (span.TotalDays > 1)
|
|
|
|
|
|
return $"{Math.Floor(span.TotalDays)}天前";
|
|
|
|
|
|
if (span.TotalHours > 1)
|
|
|
|
|
|
return $"{Math.Floor(span.TotalHours)}小时前";
|
|
|
|
|
|
if (span.TotalMinutes > 1)
|
|
|
|
|
|
return $"{Math.Floor(span.TotalMinutes)}分钟前";
|
|
|
|
|
|
|
|
|
|
|
|
return "刚刚";
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 获取背景颜色
|
|
|
|
|
|
public Color GetBackgroundColor(bool isDarkMode)
|
|
|
|
|
|
{
|
|
|
|
|
|
// 如果有自定义背景色,尝试解析
|
|
|
|
|
|
if (!string.IsNullOrEmpty(BackgroundColor))
|
|
|
|
|
|
{
|
|
|
|
|
|
try
|
|
|
|
|
|
{
|
|
|
|
|
|
// 尝试解析颜色字符串,格式为 R,G,B
|
|
|
|
|
|
string[] parts = BackgroundColor.Split(',');
|
|
|
|
|
|
if (parts.Length == 3 &&
|
|
|
|
|
|
int.TryParse(parts[0], out int r) &&
|
|
|
|
|
|
int.TryParse(parts[1], out int g) &&
|
|
|
|
|
|
int.TryParse(parts[2], out int b))
|
|
|
|
|
|
{
|
|
|
|
|
|
return Color.FromArgb(r, g, b);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
catch
|
|
|
|
|
|
{
|
|
|
|
|
|
// 解析失败,使用默认颜色
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 返回默认颜色
|
|
|
|
|
|
return isDarkMode ? Color.FromArgb(50, 50, 50) : Color.FromArgb(245, 245, 245);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// 添加GDI+扩展方法
|
|
|
|
|
|
public static class GraphicsExtensions
|
|
|
|
|
|
{
|
|
|
|
|
|
public static void FillRoundedRectangle(this Graphics graphics, Brush brush, Rectangle bounds, int cornerRadius)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (graphics == null)
|
|
|
|
|
|
throw new ArgumentNullException("graphics");
|
|
|
|
|
|
if (brush == null)
|
|
|
|
|
|
throw new ArgumentNullException("brush");
|
|
|
|
|
|
|
2025-03-13 14:08:06 +08:00
|
|
|
|
// 设置高质量绘图模式
|
|
|
|
|
|
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
|
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
|
|
|
|
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
|
|
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
using (GraphicsPath path = CreateRoundedRectangle(bounds, cornerRadius))
|
|
|
|
|
|
{
|
|
|
|
|
|
graphics.FillPath(brush, path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
public static void DrawRoundedRectangle(this Graphics graphics, Pen pen, Rectangle bounds, int cornerRadius)
|
|
|
|
|
|
{
|
|
|
|
|
|
if (graphics == null)
|
|
|
|
|
|
throw new ArgumentNullException("graphics");
|
|
|
|
|
|
if (pen == null)
|
|
|
|
|
|
throw new ArgumentNullException("pen");
|
|
|
|
|
|
|
2025-03-13 14:08:06 +08:00
|
|
|
|
// 设置高质量绘图模式
|
|
|
|
|
|
graphics.SmoothingMode = SmoothingMode.HighQuality;
|
|
|
|
|
|
graphics.InterpolationMode = InterpolationMode.HighQualityBicubic;
|
|
|
|
|
|
graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;
|
|
|
|
|
|
graphics.CompositingQuality = CompositingQuality.HighQuality;
|
|
|
|
|
|
|
|
|
|
|
|
// 设置平滑连接和端点
|
|
|
|
|
|
pen.LineJoin = LineJoin.Round;
|
|
|
|
|
|
pen.StartCap = LineCap.Round;
|
|
|
|
|
|
pen.EndCap = LineCap.Round;
|
|
|
|
|
|
|
2025-03-12 15:18:23 +08:00
|
|
|
|
using (GraphicsPath path = CreateRoundedRectangle(bounds, cornerRadius))
|
|
|
|
|
|
{
|
|
|
|
|
|
graphics.DrawPath(pen, path);
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
private static GraphicsPath CreateRoundedRectangle(Rectangle bounds, int cornerRadius)
|
|
|
|
|
|
{
|
|
|
|
|
|
GraphicsPath path = new GraphicsPath();
|
|
|
|
|
|
|
|
|
|
|
|
if (cornerRadius > 0)
|
|
|
|
|
|
{
|
|
|
|
|
|
path.AddArc(bounds.X, bounds.Y, cornerRadius * 2, cornerRadius * 2, 180, 90);
|
|
|
|
|
|
path.AddArc(bounds.Right - cornerRadius * 2, bounds.Y, cornerRadius * 2, cornerRadius * 2, 270, 90);
|
|
|
|
|
|
path.AddArc(bounds.Right - cornerRadius * 2, bounds.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 0, 90);
|
|
|
|
|
|
path.AddArc(bounds.X, bounds.Bottom - cornerRadius * 2, cornerRadius * 2, cornerRadius * 2, 90, 90);
|
|
|
|
|
|
path.CloseFigure();
|
|
|
|
|
|
}
|
|
|
|
|
|
else
|
|
|
|
|
|
{
|
|
|
|
|
|
path.AddRectangle(bounds);
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
return path;
|
|
|
|
|
|
}
|
2025-03-12 14:06:44 +08:00
|
|
|
|
}
|
|
|
|
|
|
}
|