1579 lines
62 KiB
C#
1579 lines
62 KiB
C#
using System;
|
||
using System.Drawing;
|
||
using System.Windows.Forms;
|
||
using System.Collections.Generic;
|
||
using System.IO;
|
||
using System.Text.Json;
|
||
using System.Linq;
|
||
using System.Runtime.InteropServices; // 添加P/Invoke支持
|
||
using System.Drawing.Drawing2D; // 添加GDI+支持
|
||
using Microsoft.Win32; // 添加Registry访问支持
|
||
|
||
namespace QuickLauncher
|
||
{
|
||
public partial class MainForm : Form
|
||
{
|
||
// 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;
|
||
|
||
public int CornerRadius
|
||
{
|
||
get { return _cornerRadius; }
|
||
set { _cornerRadius = value; Invalidate(); }
|
||
}
|
||
|
||
protected override void OnPaint(PaintEventArgs e)
|
||
{
|
||
base.OnPaint(e);
|
||
|
||
// 创建圆角路径
|
||
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();
|
||
|
||
this.Region = new Region(path);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 添加圆角按钮支持的类
|
||
private class RoundedButton : Button
|
||
{
|
||
private int _cornerRadius = 8;
|
||
|
||
public int CornerRadius
|
||
{
|
||
get { return _cornerRadius; }
|
||
set { _cornerRadius = value; Invalidate(); }
|
||
}
|
||
|
||
protected override void OnPaint(PaintEventArgs e)
|
||
{
|
||
base.OnPaint(e);
|
||
|
||
// 创建圆角路径
|
||
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();
|
||
|
||
this.Region = new Region(path);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 原有的字段
|
||
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; // 增加每次缩放的步长
|
||
|
||
// 左侧面板调整相关
|
||
private bool isResizing = false;
|
||
private int resizingStartX = 0;
|
||
private int initialPanelWidth = 0;
|
||
private const int MIN_PANEL_WIDTH = 200;
|
||
private const int MAX_PANEL_WIDTH = 500;
|
||
private Panel resizeHandle;
|
||
|
||
// 用于保存设置的类
|
||
private class AppSettings
|
||
{
|
||
public string LastSelectedCategory { get; set; } = "";
|
||
public string SortMode { get; set; } = "Name"; // Name, DateAdded
|
||
public int IconSize { get; set; } = 48; // 保存图标大小
|
||
public int LeftPanelWidth { get; set; } = 300; // 左侧面板宽度
|
||
}
|
||
|
||
private AppSettings settings = new AppSettings();
|
||
|
||
public MainForm()
|
||
{
|
||
InitializeComponent();
|
||
|
||
// 配置工具提示 - 调整为更合适的值
|
||
toolTip1 = new ToolTip();
|
||
toolTip1.AutoPopDelay = 5000;
|
||
toolTip1.InitialDelay = 200; // 稍微增加初始延迟
|
||
toolTip1.ReshowDelay = 200; // 稍微增加重新显示延迟
|
||
toolTip1.ShowAlways = true;
|
||
toolTip1.UseFading = true;
|
||
toolTip1.IsBalloon = false; // 使用标准样式
|
||
|
||
// 初始化数据和UI
|
||
InitializeUI();
|
||
|
||
// 应用Windows 11风格
|
||
ApplyWin11Style();
|
||
|
||
SetupContextMenus();
|
||
SetupEventHandlers();
|
||
LoadSettings();
|
||
LoadData();
|
||
SelectDefaultCategory();
|
||
|
||
// 监听系统主题变化
|
||
SystemEvents.UserPreferenceChanged += SystemEvents_UserPreferenceChanged;
|
||
}
|
||
|
||
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();
|
||
|
||
// 重新应用Windows 11风格
|
||
ApplyWin11Style();
|
||
}
|
||
|
||
// 应用Windows 11风格
|
||
private void ApplyWin11Style()
|
||
{
|
||
// 检测系统主题
|
||
isDarkMode = IsSystemUsingSysemDarkTheme();
|
||
|
||
// 应用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));
|
||
|
||
// 应用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;
|
||
}
|
||
|
||
// 应用主题颜色
|
||
ApplyThemeColors();
|
||
}
|
||
|
||
// 检测系统是否使用深色主题
|
||
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 { }
|
||
|
||
return false;
|
||
}
|
||
|
||
// 应用主题颜色
|
||
private void ApplyThemeColors()
|
||
{
|
||
// 设置主窗体颜色
|
||
this.ForeColor = isDarkMode ? darkTextColor : lightTextColor;
|
||
|
||
// 设置左侧面板颜色
|
||
leftPanel.BackColor = isDarkMode ? Color.FromArgb(40, 40, 40) : Color.FromArgb(243, 243, 243);
|
||
|
||
// 设置右侧面板颜色
|
||
rightPanel.BackColor = isDarkMode ? Color.FromArgb(32, 32, 32) : Color.FromArgb(250, 250, 250);
|
||
|
||
// 设置工具面板颜色
|
||
toolPanel.BackColor = isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(230, 230, 230);
|
||
|
||
// 设置快捷方式面板颜色
|
||
shortcutsPanel.BackColor = isDarkMode ? Color.FromArgb(32, 32, 32) : Color.FromArgb(250, 250, 250);
|
||
|
||
// 设置添加按钮颜色
|
||
addButton.BackColor = accentColor;
|
||
addButton.ForeColor = Color.White;
|
||
addButton.FlatAppearance.BorderSize = 0;
|
||
|
||
// 设置菜单颜色
|
||
menuStrip.BackColor = isDarkMode ? Color.FromArgb(45, 45, 45) : Color.FromArgb(230, 230, 230);
|
||
menuStrip.ForeColor = isDarkMode ? darkTextColor : lightTextColor;
|
||
|
||
// 设置菜单项颜色
|
||
foreach (ToolStripMenuItem item in menuStrip.Items)
|
||
{
|
||
item.ForeColor = isDarkMode ? Color.White : Color.Black;
|
||
|
||
// 设置下拉菜单项颜色
|
||
foreach (ToolStripItem dropItem in item.DropDownItems)
|
||
{
|
||
if (dropItem is ToolStripMenuItem menuItem)
|
||
{
|
||
menuItem.ForeColor = isDarkMode ? Color.White : Color.Black;
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设置菜单渲染器
|
||
menuStrip.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
|
||
// 刷新分类列表和当前分类的快捷方式(仅当categories已初始化时)
|
||
if (categories != null)
|
||
{
|
||
RefreshCategoryList();
|
||
if (!string.IsNullOrEmpty(currentCategory))
|
||
{
|
||
ShowCategoryItems(currentCategory);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 设置上下文菜单
|
||
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));
|
||
|
||
// 应用主题颜色
|
||
categoryContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
|
||
// 右侧面板右键菜单
|
||
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("-"); // 分隔线
|
||
|
||
// 添加图标大小调整菜单,增加更多选项
|
||
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);
|
||
|
||
// 添加主题切换选项
|
||
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);
|
||
|
||
// 应用主题颜色
|
||
shortcutsPanelContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
|
||
// 快捷方式项目右键菜单
|
||
shortcutItemContextMenu = new ContextMenuStrip();
|
||
shortcutItemContextMenu.Items.Add("启动", null, (s, e) =>
|
||
{
|
||
if (s is ToolStripMenuItem menuItem && menuItem.Tag is ShortcutItem item)
|
||
{
|
||
LaunchApplication(item.Path);
|
||
}
|
||
});
|
||
shortcutItemContextMenu.Items.Add("删除", null, (s, e) =>
|
||
{
|
||
if (s is ToolStripMenuItem menuItem && menuItem.Tag is ShortcutItem item)
|
||
{
|
||
DeleteShortcut(item);
|
||
}
|
||
});
|
||
shortcutItemContextMenu.Items.Add("重命名", null, (s, e) =>
|
||
{
|
||
if (s is ToolStripMenuItem menuItem && menuItem.Tag is ShortcutItem item)
|
||
{
|
||
RenameShortcut(item);
|
||
}
|
||
});
|
||
shortcutItemContextMenu.Items.Add("属性", null, (s, e) =>
|
||
{
|
||
if (s is ToolStripMenuItem menuItem && menuItem.Tag is ShortcutItem item)
|
||
{
|
||
ShowShortcutProperties(item);
|
||
}
|
||
});
|
||
|
||
// 应用主题颜色
|
||
shortcutItemContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
}
|
||
|
||
// 切换主题
|
||
private void ChangeTheme(bool darkMode)
|
||
{
|
||
isDarkMode = darkMode;
|
||
ApplyThemeColors();
|
||
|
||
// 更新上下文菜单渲染器
|
||
categoryContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
shortcutsPanelContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
shortcutItemContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
}
|
||
|
||
// 跟随系统主题
|
||
private void FollowSystemTheme()
|
||
{
|
||
isDarkMode = IsSystemUsingSysemDarkTheme();
|
||
ApplyThemeColors();
|
||
|
||
// 更新上下文菜单渲染器
|
||
categoryContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
shortcutsPanelContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
shortcutItemContextMenu.Renderer = new ModernMenuRenderer(isDarkMode);
|
||
}
|
||
|
||
// 现代菜单渲染器
|
||
private class ModernMenuRenderer : ToolStripProfessionalRenderer
|
||
{
|
||
private bool _isDarkMode;
|
||
|
||
public ModernMenuRenderer(bool isDarkMode) : base(new ModernColorTable(isDarkMode))
|
||
{
|
||
_isDarkMode = isDarkMode;
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
|
||
protected override void OnRenderItemText(ToolStripItemTextRenderEventArgs e)
|
||
{
|
||
// 菜单文本颜色
|
||
e.TextColor = _isDarkMode ? Color.FromArgb(240, 240, 240) : Color.FromArgb(20, 20, 20);
|
||
base.OnRenderItemText(e);
|
||
}
|
||
|
||
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);
|
||
}
|
||
}
|
||
}
|
||
|
||
// 现代菜单颜色表
|
||
private class ModernColorTable : ProfessionalColorTable
|
||
{
|
||
private bool _isDarkMode;
|
||
|
||
public ModernColorTable(bool isDarkMode)
|
||
{
|
||
_isDarkMode = isDarkMode;
|
||
}
|
||
|
||
// 菜单项
|
||
public override Color MenuItemSelected => _isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(210, 230, 250);
|
||
public override Color MenuItemBorder => Color.Transparent;
|
||
|
||
// 菜单栏
|
||
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);
|
||
|
||
// 工具栏
|
||
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);
|
||
}
|
||
|
||
// 调整图标大小
|
||
private void ResizeIcons(int newSize)
|
||
{
|
||
if (newSize >= MIN_ICON_SIZE && newSize <= MAX_ICON_SIZE)
|
||
{
|
||
iconSize = newSize;
|
||
settings.IconSize = iconSize;
|
||
SaveSettings();
|
||
|
||
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 };
|
||
var button = new Button() { Text = "确定", DialogResult = DialogResult.OK, Location = new Point(110, 60) };
|
||
|
||
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;
|
||
|
||
string oldCategory = currentCategory;
|
||
currentCategory = newName;
|
||
|
||
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 };
|
||
var button = new Button() { Text = "确定", DialogResult = DialogResult.OK, Location = new Point(110, 60) };
|
||
|
||
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 };
|
||
|
||
var button = new Button() { Text = "确定", DialogResult = DialogResult.OK, Location = new Point(150, 220) };
|
||
|
||
dialog.Controls.AddRange(new Control[] { icon, nameLabel, nameValue, pathLabel, pathValue,
|
||
dateLabel, dateValue, usageLabel, usageValue, button });
|
||
dialog.AcceptButton = button;
|
||
|
||
dialog.ShowDialog();
|
||
}
|
||
}
|
||
|
||
// 选择默认分类
|
||
private void SelectDefaultCategory()
|
||
{
|
||
// 如果没有分类,不做任何操作
|
||
if (categories.Count == 0)
|
||
return;
|
||
|
||
// 尝试选择上次选择的分类
|
||
if (!string.IsNullOrEmpty(settings.LastSelectedCategory) &&
|
||
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;
|
||
settings.LeftPanelWidth = leftPanel.Width;
|
||
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; // 加载保存的图标大小
|
||
leftPanel.Width = settings.LeftPanelWidth;
|
||
}
|
||
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;
|
||
|
||
// 添加鼠标滚轮事件处理
|
||
shortcutsPanel.MouseWheel += ShortcutsPanel_MouseWheel;
|
||
|
||
// 为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;
|
||
}
|
||
}
|
||
|
||
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()
|
||
{
|
||
// 初始化数据
|
||
categories = new Dictionary<string, List<ShortcutItem>>();
|
||
|
||
// 设置窗体样式
|
||
this.FormBorderStyle = FormBorderStyle.Sizable;
|
||
this.MinimumSize = new Size(800, 600);
|
||
|
||
// 设置控件样式
|
||
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);
|
||
|
||
// 设置分类标签样式
|
||
categoryLabel.Font = new Font("Microsoft YaHei UI", 11);
|
||
categoryLabel.ForeColor = isDarkMode ? Color.Black : Color.White;
|
||
|
||
// 创建左侧面板调整手柄
|
||
CreateResizeHandle();
|
||
|
||
// 刷新分类列表
|
||
RefreshCategoryList();
|
||
}
|
||
|
||
// 创建左侧面板调整手柄
|
||
private void CreateResizeHandle()
|
||
{
|
||
// 创建调整手柄
|
||
resizeHandle = new Panel
|
||
{
|
||
Width = 5,
|
||
Dock = DockStyle.Right,
|
||
Cursor = Cursors.SizeWE,
|
||
BackColor = Color.Transparent
|
||
};
|
||
|
||
// 添加鼠标事件
|
||
resizeHandle.MouseDown += ResizeHandle_MouseDown;
|
||
resizeHandle.MouseMove += ResizeHandle_MouseMove;
|
||
resizeHandle.MouseUp += ResizeHandle_MouseUp;
|
||
|
||
// 添加到左侧面板
|
||
leftPanel.Controls.Add(resizeHandle);
|
||
resizeHandle.BringToFront();
|
||
}
|
||
|
||
// 调整手柄鼠标按下事件
|
||
private void ResizeHandle_MouseDown(object sender, MouseEventArgs e)
|
||
{
|
||
if (e.Button == MouseButtons.Left)
|
||
{
|
||
isResizing = true;
|
||
resizingStartX = e.X;
|
||
initialPanelWidth = leftPanel.Width;
|
||
|
||
// 捕获鼠标
|
||
resizeHandle.Capture = true;
|
||
}
|
||
}
|
||
|
||
// 调整手柄鼠标移动事件
|
||
private void ResizeHandle_MouseMove(object sender, MouseEventArgs e)
|
||
{
|
||
if (isResizing)
|
||
{
|
||
// 计算新宽度
|
||
int newWidth = initialPanelWidth + (e.X - resizingStartX);
|
||
|
||
// 限制宽度范围
|
||
if (newWidth < MIN_PANEL_WIDTH)
|
||
newWidth = MIN_PANEL_WIDTH;
|
||
else if (newWidth > MAX_PANEL_WIDTH)
|
||
newWidth = MAX_PANEL_WIDTH;
|
||
|
||
// 设置新宽度
|
||
leftPanel.Width = newWidth;
|
||
|
||
// 刷新布局
|
||
this.PerformLayout();
|
||
|
||
// 刷新分类列表,以适应新宽度
|
||
RefreshCategoryList();
|
||
}
|
||
}
|
||
|
||
// 调整手柄鼠标释放事件
|
||
private void ResizeHandle_MouseUp(object sender, MouseEventArgs e)
|
||
{
|
||
if (isResizing)
|
||
{
|
||
isResizing = false;
|
||
|
||
// 释放鼠标捕获
|
||
resizeHandle.Capture = false;
|
||
|
||
// 保存设置
|
||
settings.LeftPanelWidth = leftPanel.Width;
|
||
SaveSettings();
|
||
}
|
||
}
|
||
|
||
private void AddCategory_Click(object sender, EventArgs e)
|
||
{
|
||
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;
|
||
dialog.BackColor = isDarkMode ? Color.FromArgb(32, 32, 32) : Color.FromArgb(243, 243, 243);
|
||
dialog.ForeColor = isDarkMode ? Color.White : Color.Black;
|
||
|
||
var label = new Label() {
|
||
Text = "分类名称:",
|
||
Location = new Point(10, 20),
|
||
ForeColor = isDarkMode ? Color.White : Color.Black
|
||
};
|
||
|
||
var textBox = new TextBox() {
|
||
Location = new Point(120, 17),
|
||
Width = 180,
|
||
BackColor = isDarkMode ? Color.FromArgb(45, 45, 45) : Color.White,
|
||
ForeColor = isDarkMode ? Color.White : Color.Black
|
||
};
|
||
|
||
var button = new RoundedButton() {
|
||
Text = "确定",
|
||
DialogResult = DialogResult.OK,
|
||
Location = new Point(110, 60),
|
||
Width = 100,
|
||
Height = 30,
|
||
BackColor = Color.FromArgb(210, 210, 210, 200), // 自定义RGB颜色
|
||
ForeColor = Color.FromArgb(40, 40, 40),
|
||
CornerRadius = cornerRadius
|
||
};
|
||
|
||
dialog.Controls.AddRange(new Control[] { label, textBox, button });
|
||
dialog.AcceptButton = button;
|
||
|
||
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();
|
||
|
||
// 自动选择新创建的分类
|
||
currentCategory = newCategory;
|
||
ShowCategoryItems(currentCategory);
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|
||
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 = "";
|
||
|
||
// 删除分类后,选择新的默认分类
|
||
if (categories.Count > 0)
|
||
{
|
||
currentCategory = categories.Keys.First();
|
||
ShowCategoryItems(currentCategory);
|
||
}
|
||
}
|
||
}
|
||
|
||
private void RefreshCategoryList()
|
||
{
|
||
// 如果categories为空,直接返回
|
||
if (categories == null)
|
||
return;
|
||
|
||
leftPanel.Controls.Clear();
|
||
int buttonY = 10;
|
||
|
||
foreach (var category in categories.Keys)
|
||
{
|
||
var categoryPanel = new RoundedPanel
|
||
{
|
||
Width = leftPanel.Width - 5,
|
||
Height = CATEGORY_BUTTON_HEIGHT,
|
||
Location = new Point(0, buttonY),
|
||
CornerRadius = cornerRadius
|
||
};
|
||
|
||
var btn = new RoundedButton
|
||
{
|
||
Text = category,
|
||
Width = leftPanel.Width - 20,
|
||
Height = CATEGORY_BUTTON_HEIGHT,
|
||
Location = new Point(10, 0),
|
||
FlatStyle = FlatStyle.Flat,
|
||
BackColor = category == currentCategory ?
|
||
accentColor :
|
||
(isDarkMode ? Color.FromArgb(60, 60, 60) : Color.FromArgb(230, 230, 230)),
|
||
ForeColor = category == currentCategory ?
|
||
Color.White :
|
||
(isDarkMode ? Color.FromArgb(240, 240, 240) : Color.FromArgb(20, 20, 20)),
|
||
Tag = category,
|
||
CornerRadius = cornerRadius,
|
||
FlatAppearance = { BorderSize = 0 }
|
||
};
|
||
|
||
// 移除旧的事件处理器
|
||
btn.Click -= null;
|
||
btn.Click += (s, e) =>
|
||
{
|
||
currentCategory = category;
|
||
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;
|
||
|
||
var panel = new RoundedPanel
|
||
{
|
||
Width = panelWidth,
|
||
Height = panelHeight,
|
||
Margin = new Padding(5),
|
||
Tag = item,
|
||
BackColor = isDarkMode ? Color.FromArgb(50, 50, 50) : Color.FromArgb(245, 245, 245),
|
||
CornerRadius = cornerRadius
|
||
};
|
||
|
||
var icon = new PictureBox
|
||
{
|
||
Size = new Size(iconSize, iconSize),
|
||
Location = new Point((panel.Width - iconSize) / 2, 5),
|
||
Image = item.Icon ?? SystemIcons.Application.ToBitmap(),
|
||
SizeMode = PictureBoxSizeMode.StretchImage,
|
||
Tag = item,
|
||
Cursor = Cursors.Hand // 鼠标悬停时显示手型光标
|
||
};
|
||
|
||
var label = new Label
|
||
{
|
||
Text = item.Name,
|
||
AutoSize = false,
|
||
TextAlign = ContentAlignment.MiddleCenter,
|
||
Width = panel.Width,
|
||
Height = 30,
|
||
Location = new Point(0, iconSize + 10),
|
||
Tag = item,
|
||
Cursor = Cursors.Hand, // 鼠标悬停时显示手型光标
|
||
ForeColor = isDarkMode ? Color.FromArgb(240, 240, 240) : Color.FromArgb(20, 20, 20)
|
||
};
|
||
|
||
panel.Controls.Add(icon);
|
||
panel.Controls.Add(label);
|
||
|
||
// 设置右键菜单
|
||
panel.ContextMenuStrip = shortcutItemContextMenu;
|
||
icon.ContextMenuStrip = shortcutItemContextMenu;
|
||
label.ContextMenuStrip = shortcutItemContextMenu;
|
||
|
||
// 为右键菜单项设置Tag
|
||
foreach (ToolStripItem menuItem in shortcutItemContextMenu.Items)
|
||
{
|
||
if (menuItem is ToolStripMenuItem)
|
||
{
|
||
menuItem.Tag = item;
|
||
}
|
||
}
|
||
|
||
// 移除旧的事件处理器并重新绑定
|
||
panel.DoubleClick -= null;
|
||
icon.DoubleClick -= null;
|
||
label.DoubleClick -= null;
|
||
|
||
// 双击事件 - 启动应用程序
|
||
panel.DoubleClick += (s, e) => LaunchApplication(item.Path);
|
||
icon.DoubleClick += (s, e) => LaunchApplication(item.Path);
|
||
label.DoubleClick += (s, e) => LaunchApplication(item.Path);
|
||
|
||
// 添加鼠标悬停效果
|
||
panel.MouseEnter += Panel_MouseEnter;
|
||
panel.MouseLeave += Panel_MouseLeave;
|
||
icon.MouseEnter += Panel_MouseEnter;
|
||
icon.MouseLeave += Panel_MouseLeave;
|
||
label.MouseEnter += Panel_MouseEnter;
|
||
label.MouseLeave += Panel_MouseLeave;
|
||
|
||
// 添加鼠标点击效果
|
||
panel.MouseDown += Panel_MouseDown;
|
||
panel.MouseUp += Panel_MouseUp;
|
||
icon.MouseDown += Panel_MouseDown;
|
||
icon.MouseUp += Panel_MouseUp;
|
||
label.MouseDown += Panel_MouseDown;
|
||
label.MouseUp += Panel_MouseUp;
|
||
|
||
// 直接设置工具提示
|
||
string tipText = $"名称: {item.Name}\n路径: {item.Path}\n双击启动";
|
||
toolTip1.SetToolTip(panel, tipText);
|
||
toolTip1.SetToolTip(icon, tipText);
|
||
toolTip1.SetToolTip(label, tipText);
|
||
|
||
shortcutsPanel.Controls.Add(panel);
|
||
}
|
||
|
||
// 鼠标进入面板时的效果
|
||
private void Panel_MouseEnter(object sender, EventArgs e)
|
||
{
|
||
if (sender is Control control && control.Parent is RoundedPanel panel)
|
||
{
|
||
// 应用悬停效果
|
||
panel.BackColor = isDarkMode ? Color.FromArgb(70, 70, 70) : Color.FromArgb(230, 230, 230);
|
||
|
||
// 显示工具提示
|
||
if (panel.Tag is ShortcutItem item)
|
||
{
|
||
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}");
|
||
}
|
||
}
|
||
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}");
|
||
}
|
||
}
|
||
|
||
// 鼠标离开面板时的效果
|
||
private void Panel_MouseLeave(object sender, EventArgs e)
|
||
{
|
||
if (sender is Control control && control.Parent is RoundedPanel panel)
|
||
{
|
||
// 恢复正常颜色
|
||
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);
|
||
}
|
||
}
|
||
|
||
// 鼠标按下时的效果
|
||
private void Panel_MouseDown(object sender, MouseEventArgs e)
|
||
{
|
||
if (sender is Control control && control.Parent is RoundedPanel panel)
|
||
{
|
||
// 应用按下效果
|
||
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);
|
||
}
|
||
}
|
||
|
||
// 鼠标释放时的效果
|
||
private void Panel_MouseUp(object sender, MouseEventArgs e)
|
||
{
|
||
if (sender is Control control && control.Parent is RoundedPanel panel)
|
||
{
|
||
// 恢复悬停颜色
|
||
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);
|
||
}
|
||
}
|
||
|
||
// 添加面板鼠标移动事件处理
|
||
private void ShortcutsPanel_MouseMove(object sender, MouseEventArgs e)
|
||
{
|
||
// 获取鼠标位置下的控件
|
||
Control control = shortcutsPanel.GetChildAtPoint(e.Location);
|
||
|
||
// 如果鼠标不在任何子控件上,则隐藏工具提示
|
||
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);
|
||
}
|
||
}
|
||
|
||
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);
|
||
|
||
// 加载所有图标
|
||
foreach (var category in categories.Values)
|
||
{
|
||
foreach (var item in category)
|
||
{
|
||
item.LoadIcon();
|
||
}
|
||
}
|
||
|
||
RefreshCategoryList();
|
||
}
|
||
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();
|
||
}
|
||
}
|
||
}
|
||
|
||
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;
|
||
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; // 排序顺序
|
||
|
||
// 用于序列化的构造函数
|
||
public ShortcutItem()
|
||
{
|
||
}
|
||
|
||
// 加载图标的方法
|
||
public void LoadIcon()
|
||
{
|
||
try
|
||
{
|
||
// 如果有自定义图标,优先使用自定义图标
|
||
if (!string.IsNullOrEmpty(CustomIconPath) && File.Exists(CustomIconPath))
|
||
{
|
||
try
|
||
{
|
||
// 尝试加载自定义图标
|
||
using (System.Drawing.Icon customIcon = new System.Drawing.Icon(CustomIconPath))
|
||
{
|
||
Icon = customIcon.ToBitmap();
|
||
return;
|
||
}
|
||
}
|
||
catch
|
||
{
|
||
// 如果自定义图标加载失败,继续使用默认图标
|
||
}
|
||
}
|
||
|
||
// 使用关联图标
|
||
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();
|
||
}
|
||
}
|
||
|
||
// 获取格式化的最后使用时间
|
||
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");
|
||
|
||
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");
|
||
|
||
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;
|
||
}
|
||
}
|
||
} |