Compare commits

...
1020 Commits
Author SHA1 Message Date
龙腾猫跃 28ef67ee0f 2.10.5 2025-07-22 23:49:12 +08:00
龙腾猫跃 add4153067 2.10.4 2025-07-22 21:09:24 +08:00
龙腾猫跃 3e474b89ef Merge pull request #6845 from LuoYun-Team/actions
ci(build): 让工作流支持新版本代码的自动替换
2025-07-22 19:23:58 +08:00
薄奚梦灵 b5cfebe8aa ci(build): 让工作流支持新版本代码的自动替换 2025-07-22 12:54:02 +08:00
龙腾猫跃 4486e7ea2c Merge pull request #6445 from PCL-Community/fix#6443
fix(PageVersionOverall): 重命名版本时会修改后缀名且会修改不应重命名的文件或文件夹
2025-07-22 00:41:09 +08:00
龙腾猫跃 4d91d0b27e Merge pull request #6706 from shatyuka/fix/search-forge-mods
fix: 搜索旧版本 Forge mod 崩溃
2025-07-20 19:20:26 +08:00
龙腾猫跃 14e14b9810 Merge pull request #6772 from LuoYun-Team/Drop
fix(Drop): 文件拖拽修复
2025-07-20 18:57:17 +08:00
龙腾猫跃 d6575df6ab Merge pull request #6685 from MoYuan-CN/issue/6673
imp(download): 改进可选组件互斥逻辑
2025-07-20 03:19:48 +08:00
龙腾猫跃 eed6c92f5a Merge pull request #6594 from PCL-Community/fix#6588
fix(ModSecret): 开源版本龙猫蓝配色错误
2025-07-19 04:30:54 +08:00
龙腾猫跃 ae8de397ae Merge pull request #6717 from xrlzu-Community/main
feat:去掉“刷新头像”和“修改披风”之间的线
2025-07-18 19:39:53 +08:00
龙腾猫跃 2de22b780c Merge pull request #6795 from lingting/main
chore: 自动搜索java路径添加 ~/.jdks
2025-07-18 19:36:34 +08:00
龙腾猫跃 4d954ae45d Merge pull request #6701 from LuoYun-Team/skin-url
fix(skin): 可能尝试使用 HTTPS 协议从没有 SSL 证书的服务器下载皮肤文件
2025-07-18 19:27:53 +08:00
龙腾猫跃 3d63ceba57 Merge pull request #6644 from PCL-Community/optimize-1
feat(PageDownloadCompDetail): 为每种资源区分 CachedFolder
2025-07-18 19:16:46 +08:00
龙腾猫跃 8b234d8e4f Merge pull request #6635 from zkitefly/patch-4
fix: 修复微软登录提示语句问题
2025-07-18 19:11:02 +08:00
龙腾猫跃 d6a5a8b83e Merge pull request #6626 from Light-Beacon/main
chore: 更新仓库指向仓库的链接
2025-07-18 19:10:15 +08:00
龙腾猫跃 885b3eada6 Merge pull request #6587 from LuoYun-Team/java-version
fix(java): JVM 崩溃导致错误将版本号识别为 JDK/JRE 64
2025-07-18 05:09:34 +08:00
龙腾猫跃 deb902904b Merge pull request #6585 from hongggggv/fix
chore: 修改资源筛选版本
2025-07-18 04:58:44 +08:00
龙腾猫跃 1458ce95ce Merge pull request #6527 from Baiyuexiao-Studio/security-interrupt
feat: 支持识别因为微软账号被标记为可疑活动导致登陆失败
2025-07-18 04:39:20 +08:00
龙腾猫跃 d8efb76bf0 Merge pull request #6505 from LuoYun-Team/CustomKey
feat(Secret):允许使用环境变量覆盖部分内容
2025-07-18 04:37:46 +08:00
hongggggv a843b22f38 Merge branch 'Meloong-Git:main' into fix 2025-07-17 23:14:58 +08:00
Luo 08e4414f34 将版本号改为 1.21.8 2025-07-17 23:13:23 +08:00
lingtingand龙腾猫跃 ff225e9f37 chore: 文件夹以\结尾
Co-authored-by: 龙腾猫跃 <[email protected]>
2025-07-14 10:21:42 +08:00
龙腾猫跃 96b6ef294b Merge pull request #6473 from PCL-Community/fix#6439
fix(PageDownloadCompDetail): 部分原版可用的光影无法显示可下载的游戏版本
2025-07-14 04:38:53 +08:00
龙腾猫跃 f271d7212c Merge pull request #6797 from PCL-Community/#6774
fix: 选择图片不能选择 jpeg 格式
2025-07-14 01:44:43 +08:00
wyc-26 ad583c29c2 fix: 选择图片不能选择 jpeg 格式 2025-07-13 22:08:27 +08:00
龙腾猫跃 f98dcd8fef Merge pull request #6407 from LuoYun-Team/HttpClient
Refactor(Network):用 HttpClient 代替已经过时的 WebRequest、WebClient、ServicePointManager
2025-07-13 20:53:35 +08:00
龙腾猫跃 9b49235cda Merge pull request #6287 from PCL-Community/fix#5252
fix(ModLaunch): 证书不信任导致无法登录皮肤站
2025-07-13 20:42:46 +08:00
龙腾猫跃 f090a63c54 Merge pull request #6216 from LuoYun-Team/dialog
fix:文件删除没有无法放入回收站的提示
2025-07-13 20:39:50 +08:00
龙腾猫跃 c332a4dc94 Merge pull request #6027 from PCL-Community/feat#6026
feat: 点击“下载新 Mod”按钮跳转到下载页面时自动填充搜索框的内容
2025-07-13 20:23:32 +08:00
龙腾猫跃 6770e55214 Merge pull request #5798 from CiiLu/music
解决 #5762 :仅合法音乐纳入背景音乐数量统计
2025-07-13 20:03:51 +08:00
lingting dd028bb6d8 chore: 自动搜索java路径添加 ~/.jdks 2025-07-13 17:40:18 +08:00
薄奚梦灵 5126b257f8 chore: 将旧代码还原获取 2025-07-11 18:04:03 +08:00
薄奚梦灵 35398052bb fix(Drop): 文件拖拽修复 2025-07-11 17:57:46 +08:00
xrlzu 17031e1a65 feat:去掉“刷新头像”和“修改披风”之间的线 2025-07-04 20:14:42 +08:00
shatyuka e40a41a761 fix: 搜索旧版本 Forge mod 崩溃 2025-07-02 21:56:46 +08:00
薄奚梦灵 5ae813825c fix(skin): 可能尝试使用 HTTPS 协议从没有 SSL 证书的服务器下载皮肤文件 2025-07-01 21:42:01 +08:00
hongggggv 48684f8f85 将版本号改为 1.21.7 2025-07-01 21:05:18 +08:00
墨渊 3f5392d76d fix(version): 应当是 1.20.5+ 2025-06-30 05:21:18 +00:00
MoYuan-CN 9af03d499a imp(download): 改进可选组件互斥逻辑
在 1.21.5 及以后的版本中不允许同时选择 OptiFine 和 Fabric
选择了 Fabric 时会给出 Blue 等级的提示以帮助用户理解和寻找光影加载代替方案
2025-06-30 12:25:40 +08:00
wyc-26 d6043c7d32 feat(PageDownloadCompDetail): 为每种资源区分 CachedFolder 2025-06-25 21:52:27 +08:00
Luo a38e20870b 回退上次更改 2025-06-25 16:22:19 +08:00
Luo 72a2b5da8c 修改 Mod 支持所有常用版本的描述 2025-06-25 16:18:22 +08:00
Zkitefly f3017b6b62 Update MyMsgLogin.xaml.vb 2025-06-25 16:02:26 +08:00
Nattiden 5274ae8499 chore: 链接更新 2025-06-23 21:10:38 +08:00
薄奚梦灵andtangge233 83e34b84fa Update Plain Craft Launcher 2/Modules/Base/ModNet.vb
Co-authored-by: tangge233 <[email protected]>
2025-06-23 20:45:34 +08:00
薄奚梦灵 65812b8754 chore: 删除无用代码 2025-06-20 18:38:28 +08:00
wyc-26 6616afde6d chore: 一不小心动了注释位置 2025-06-20 15:15:54 +08:00
wyc-26 7cd5747f4f fix(ModSecret): 开源版本龙猫蓝配色错误 2025-06-20 15:14:34 +08:00
薄奚梦灵 70ec0b66f9 fix(java): JVM 崩溃导致错误将版本号识别为 JDK/JRE 64 2025-06-19 12:36:47 +08:00
Luo 74e5eb82f5 修改筛选版本 2025-06-19 11:14:30 +08:00
龙腾猫跃 fdf5407ea3 2.10.3 2025-06-17 16:51:31 +08:00
龙腾猫跃 ebc9f5e31f 2.10.2 2025-06-17 05:25:51 +08:00
龙腾猫跃 4585f31082 2.10.2 正式版 2025-06-17 05:19:00 +08:00
龙腾猫跃 a63c5b46a6 Merge pull request #5872 from Open-KFC/feat4311
Feat:模组管理页面无需点击右侧控件即可触发全选快捷键
2025-06-17 03:20:14 +08:00
龙腾猫跃 01b26cdf3c Merge pull request #6472 from PCL-Community/fix#6451
fix(ModWatcher): Quilt 加载器错误窗口关闭后提示启动成功
2025-06-17 03:13:12 +08:00
龙腾猫跃 27b4df0e85 Merge pull request #6117 from LuoYun-Team/ModComp
pref(ModComp):提高代码可维护性
2025-06-17 03:11:21 +08:00
龙腾猫跃 a219eca488 Merge pull request #6440 from MoYuan-CN/issue/6438
typo: unexpected "s" appear in shader filter options
2025-06-17 03:06:29 +08:00
龙腾猫跃 666243e072 Merge pull request #6249 from PCL-Community/feat#6244
feat(ModDownloadLib): 自动创建资源包文件夹
2025-06-17 02:56:33 +08:00
龙腾猫跃 66bf71a7f3 Merge pull request #6456 from CreeperIsASpy/main
fix(PageSetupSystem.xaml.vb): 修复弹窗中页面名称错误的问题
2025-06-17 02:48:46 +08:00
龙腾猫跃 f1c046986c Merge pull request #6482 from tangge233/fix/HRKill
chore: 修复火绒的特征查杀
2025-06-17 02:40:37 +08:00
龙腾猫跃 d1fa7109ed Merge pull request #6570 from LuoYun-Team/curseforge-link
chore(CurseForge): 增加新的 Fallback
2025-06-17 02:36:27 +08:00
龙腾猫跃 6c426b09cc Merge pull request #6437 from LuoYun-Team/Skin
fix:可能在获取正版皮肤时失败
2025-06-17 02:29:27 +08:00
薄奚梦灵 cbf038d51f chore(CurseForge): 增加新的 Fallback 2025-06-16 22:39:37 +08:00
白月晓 5e31a1d937 Update MyMsgLogin.xaml.vb 2025-06-09 21:44:24 +08:00
白月晓 81619cbfc7 feat: 支持识别因为微软账号被标记为可疑活动导致登陆失败
From https://github.com/PCL-Community/PCL2-CE/issues/769
2025-06-09 18:51:58 +08:00
薄奚梦灵 300d1ecf66 feat(Secret):允许使用环境变量覆盖部分内容 2025-06-07 17:01:16 +08:00
薄奚梦灵andbaiyuexiao496 6dbb5c98cc fix: 少了特定标头和异常抛出
CO-Authored-By: baiyuexiao496 <[email protected]>
2025-06-07 14:18:00 +08:00
wyc-26 2991e43b45 chore: 小改 2025-06-05 19:52:27 +08:00
wyc-26 0c1b9e389a fix(ModWatcher): 忘写对应的 WatcherLog 2025-06-05 19:40:09 +08:00
tangge233 809a281a7e style: 修改变量名称 2025-06-04 22:54:56 +08:00
wyc-26 da8a50abd3 fix(PageDownloadCompDetail): 给资源包也加上 2025-06-04 21:06:48 +08:00
tangge233 cddcd9e8b2 chore: 修复火绒的特征查杀 (感谢火绒论坛的 UnknownOoo 老哥) 2025-06-04 18:43:38 +08:00
薄奚梦灵 7ecf306445 chore: 弄错了 2025-06-02 13:44:17 +08:00
薄奚梦灵andjiangyanyue 3adf47aa2c fix: 编译错误
CO-Authored-by: jiangyanyue <[email protected]>
2025-06-02 13:40:43 +08:00
薄奚梦灵 70a2f28073 revert: 错误的文件更改 2025-06-02 13:27:23 +08:00
薄奚梦灵 9c9216c02c revert: 错误的文件更改 2025-06-02 13:20:21 +08:00
wyc-26 f2ae0fbaa9 fix(PageDownloadCompDetail): 部分原版可用的光影无法显示可下载的游戏版本 2025-06-02 12:20:50 +08:00
wyc-26 c2a476feff fix(ModWatcher): Quilt 加载器错误窗口关闭后提示启动成功 2025-06-02 11:55:18 +08:00
wyc-26 36c03d1654 fix(PageComp): 重复的代码 2025-06-02 11:03:36 +08:00
wyc-26 ebd20195be Merge branch 'main' into feat#6026 2025-06-02 10:59:14 +08:00
薄奚梦灵andqiuyue712 5a94854809 Refactor(ModNet): 使用 HttpClient 代替过失函数 Feat(ModNet): 支持 GZip 等压缩格式响应的读取
CO-authored-by: qiuyue712 <[email protected]>
2025-06-02 00:08:22 +08:00
仿生猫梦见苦力怕 dcac683bfd Update PageSetupLeft.xaml.vb 2025-06-01 21:25:40 +08:00
薄奚梦灵 d2e210320b Merge pull request #51 from Hex-Dragon/main
sync
2025-06-01 15:45:07 +08:00
wyc-26 73d705aa5b fix(PageVersionOverall): 重命名版本时会修改后缀名且会修改不应重命名的文件或文件夹 2025-05-31 23:08:11 +08:00
墨渊 878ff980dc Update PageDownloadShader.xaml 2025-05-31 20:49:49 +08:00
薄奚梦灵 e19f910251 fix:可能在获取正版皮肤时失败 2025-05-31 18:41:48 +08:00
龙腾猫跃 6b0c923777 2.10.1 2025-05-31 16:53:00 +08:00
龙腾猫跃 03a64108d9 Merge pull request #5771 from Open-KFC/fix5665
fix(PageVersionMod): 在模组列表中划动鼠标选择时如果鼠标在列表之外松开会导致无法与悬浮卡片交互
2025-05-30 23:10:26 +08:00
龙腾猫跃 bf121009ae Merge pull request #4401 from tmdakm/main
读取MCBBS整合包文件中的Jvm和Launch参数
2025-05-29 23:08:49 +08:00
龙腾猫跃 971db70ae9 Merge pull request #6347 from Open-KFC/default-mcwindow-size
fix(LaunchArg): 默认窗口大小错误
2025-05-29 02:28:03 +08:00
龙腾猫跃 2359776803 Merge pull request #6257 from LuoYun-Team/enforce-https
fix:使用 HTTP 协议获取皮肤导致被劫持
2025-05-28 17:15:56 +08:00
龙腾猫跃 8f8819d0f0 Merge pull request #6321 from Open-KFC/title-bar-pic
fix(ImageTitleLogo): 保证在重新设置标题栏图片时得到刷新
2025-05-28 17:02:42 +08:00
龙腾猫跃 8e383ed436 Merge pull request #6318 from PCL-Community/fix#6317
fix(PageSetupUI): 修正功能隐藏中的选项卡名称
2025-05-28 17:00:53 +08:00
龙腾猫跃 34123d5944 Merge pull request #6300 from written143/cape
添加普通披风、薄煎饼披风和创始人披风的翻译
2025-05-28 17:00:03 +08:00
龙腾猫跃 0c8ccafd46 Merge pull request #6227 from CreeperIsASpy/main
fix: 极小概率在主页卡片卡出“内容见 ModSetup” 的 Hint
2025-05-28 16:57:00 +08:00
龙腾猫跃 deefff4504 Merge pull request #6234 from LuoYun-Team/resourcepack
chore:修改命名
2025-05-28 16:52:55 +08:00
龙腾猫跃 83856e5192 Merge pull request #6247 from PCL-Community/feat#6246
feat(PageDownloadCompDetail): 支持为资源包和光影包选择默认下载位置
2025-05-28 16:23:55 +08:00
龙腾猫跃 81d6e501cd Merge pull request #6340 from Open-KFC/drag-over-flowdocument
fix(FileDrag): 鼠标位于可编辑文字控件上无法完成向窗口的文件拖放
2025-05-28 15:34:40 +08:00
龙腾猫跃 65f17ba6f5 Merge pull request #6369 from PCL-Community/fix#2294
fix(PageVersionOverall): 缓存问题导致切换语言失败
2025-05-28 15:26:23 +08:00
龙腾猫跃 cc81df2e26 Merge pull request #6397 from Pigeon0v0/export
imp(export): 排除 HMCL 版本配置与自定义 Log4j2 文件
2025-05-28 15:18:17 +08:00
薄奚梦灵 9a0ad08498 Merge pull request #49 from LuoYun-Team/modnet
pref(ModNet):使用 HttpClient 替代过时的 WebRequest 和 WebClient
2025-05-26 13:44:49 +08:00
Pigeon0v0 3ce005b06b imp(export): 排除 HMCL 版本配置与自定义 Log4j2 文件 2025-05-25 11:10:46 +08:00
Open-KFC 30556c2347 fix #5665 在模组列表中划过鼠标时如果鼠标在模组条目列表之外松开会导致无法与悬浮卡片的按钮交互 2025-05-24 20:12:09 +08:00
wyc-26 fa2d66cc45 fix(PageVersionOverall): 缓存问题导致切换语言失败 2025-05-18 10:15:30 +08:00
Open-KFC ae8b807ad8 fix(LaunchArg): 默认窗口大小错误 2025-05-14 10:43:09 +08:00
Open-KFC b15c3e1da2 fix(FileDrag): 用户无法将文件拖放到可编辑文字控件上 2025-05-13 06:52:26 +08:00
Open-KFC 1c0bd6d02a fix(ImageTitleLogo): 保证在重新设置标题栏图片时得到刷新 2025-05-09 23:29:15 +08:00
wyc-26 ca3eb311b6 fix(PageSetupUI): 修正功能隐藏中的选项卡名称 2025-05-09 18:13:21 +08:00
written143 0f8632a10b Fix 2025-05-09 17:53:49 +08:00
written143 5594dbdb8e 添加薄煎饼披风和创始人披风的翻译 2025-05-08 20:04:13 +08:00
written143 c72cf1e3d5 添加普通披风的翻译 2025-05-07 00:30:18 +08:00
wyc-26 443d306d31 fix(ModLaunch): 证书不信任导致无法登录皮肤站*2 2025-05-05 14:30:09 +08:00
wyc-26 acaff10bf0 fix(ModLaunch): 证书不信任导致无法登录皮肤站 2025-05-05 14:15:36 +08:00
龙腾猫跃 bf6fa718c8 2.10.0 正式版 2025-05-04 20:49:18 +08:00
薄奚梦灵 85bd89fbc0 fix(PageSetupUI):错误显示了内容见 ModSetup 的提示 2025-05-03 14:13:13 +08:00
薄奚梦灵 825334cb9d Revert(88be968866): fix Hex-Dragon#6222 2025-05-03 14:10:30 +08:00
wyc-26 e6d7c06f29 refactor(PageDownloadCompDetail): 优化选择默认保存位置部分代码 2025-05-01 20:32:59 +08:00
薄奚梦灵 cfa7ce16bd fix:强制使用 HTTPS 避免获取皮肤错误 2025-05-01 18:43:03 +08:00
wyc-26 fa12897ea9 feat(ModDownloadLib): 自动创建资源包文件夹 2025-05-01 10:41:25 +08:00
wyc-26 1a71b72ab9 feat(PageDownloadCompDetail): 支持为资源包和光影包选择默认下载位置 2025-05-01 09:33:39 +08:00
薄奚梦灵 124f5c2f8b Merge pull request #43 from Hex-Dragon/main
u
2025-04-30 14:49:34 +08:00
薄奚梦灵 c492d74568 chore:修改命名 2025-04-30 07:00:24 +08:00
CreeperIsASpy 88be968866 fix #6222 2025-04-29 21:36:19 +08:00
龙腾猫跃 44aea3e962 2.10.0 2025-04-29 18:18:46 +08:00
龙腾猫跃 9c8be3a22e Merge pull request #5976 from PCL-Community/fix#5848
fix(PageDownloadInstall): 打断安装预览页面进入动画后再次切换至下载页面时显示错误
2025-04-29 01:18:29 +08:00
龙腾猫跃 da71d25a8c Merge pull request #5776 from Open-KFC/fix4677
Fix:通过网络获取到更多可更新模组时未同步至‘可更新’模组列表视图
2025-04-29 01:11:45 +08:00
龙腾猫跃 1cd42280de Merge pull request #5775 from Open-KFC/fix4596
Fix: 在点击刷新按钮后对应的MyListItem显示不正确
2025-04-29 01:08:39 +08:00
龙腾猫跃 967ff2a9c8 Merge pull request #6197 from LuoYun-Team/abuse
feat(MyMsgLogin):增加账号被封禁时的错误提示
2025-04-29 01:03:01 +08:00
龙腾猫跃 7d0b4b72c1 Merge pull request #6137 from Open-KFC/task-bar-progress
fix(ModLoader): 不应当显示的加载器的进度也被计入到显示的总进度中
2025-04-29 00:59:44 +08:00
龙腾猫跃 b29977ee2f Merge pull request #6019 from PCL-Community/fix#6000
fix(ModLaunch): 启动脚本乱码
2025-04-29 00:57:35 +08:00
薄奚梦灵 f3680f0b78 fix:大文件删除没有无法放入回收站的提示 2025-04-28 11:52:19 +08:00
薄奚梦灵 67197bfa94 Merge pull request #33 from Hex-Dragon/main
u
2025-04-28 11:41:35 +08:00
薄奚梦灵 effdf5a3a9 Merge pull request #32 from Hex-Dragon/main
u
2025-04-28 11:41:04 +08:00
龙腾猫跃 e51a5cb6c2 fix: 编译错误 2025-04-28 02:53:53 +08:00
龙腾猫跃 5177d3ca0b fix: 哪儿来的 FormLoginOAuth 2025-04-28 02:49:05 +08:00
龙腾猫跃 e7bb3d2261 Merge pull request #4360 from Pigeon0v0/datapacks
支持下载数据包
2025-04-28 02:42:51 +08:00
龙腾猫跃 cc850c8850 Merge branch 'main' into datapacks 2025-04-28 02:42:43 +08:00
龙腾猫跃 aee0ea9147 Merge pull request #4359 from Pigeon0v0/shaders
支持下载光影包
2025-04-28 02:39:30 +08:00
龙腾猫跃 0b214f20e4 Merge branch 'main' into shaders 2025-04-28 02:39:20 +08:00
龙腾猫跃 3abb4493a2 Merge pull request #4020 from Pigeon0v0/resourcepacks
支持下载资源包
2025-04-28 02:36:25 +08:00
龙腾猫跃 580a76ab8e Merge branch 'main' into resourcepacks 2025-04-28 02:36:17 +08:00
薄奚梦灵 4823a834c6 Merge pull request #24 from Hex-Dragon/main
uuu
2025-04-27 16:23:35 +08:00
薄奚梦灵 1e98e91d4a Merge pull request #19 from Hex-Dragon/main
v10�u�B�Jh24.���ʛ�qށ����(�je��N�'�?j��������o^��*
2025-04-27 07:34:08 +08:00
龙腾猫跃 9b9d138e40 Merge pull request #5773 from LuoYun-Team/check-rename
fix(BtnDisplayRename_Click):在重命名前检查路径
2025-04-25 21:50:01 +08:00
薄奚梦灵 d33cbdc3e0 chore:先丢回去 2025-04-25 21:21:24 +08:00
薄奚梦灵 c8f9066ef2 style(PageVersionOverall):移除无用代码 2025-04-25 21:10:52 +08:00
薄奚梦灵 c44d1f066c Merge branch 'main' into check-rename 2025-04-25 21:09:38 +08:00
龙腾猫跃 38b22c5242 Merge pull request #5781 from LuoYun-Team/skip-download-folder
fix(ModJava):错误将下载目录的 Java 当作特定路径 Java
2025-04-25 19:48:55 +08:00
wyc-26 7cc3595e75 fix(ModLaunch): 同步 #5909 中修改的选择编码的方式 2025-04-25 19:43:51 +08:00
龙腾猫跃 41334e69b3 Merge pull request #5896 from LuoYun-Team/tips
fix(PageSetupUI):修改显示文本
2025-04-25 19:29:10 +08:00
龙腾猫跃 31434a9b47 Merge pull request #5912 from LuoYun-Team/uac
fix:为可能出错的部分加个 Try Catch
2025-04-25 19:15:46 +08:00
龙腾猫跃 5353c109b7 Merge pull request #6101 from PCL-Community/fix#6070
fix(ModModPack): 解压压缩包进度可能超过 100%
2025-04-25 19:04:11 +08:00
龙腾猫跃 59bdc75342 Merge pull request #5792 from Open-KFC/fix5655
Fix:鼠标保持移动时抬起仍可继续改变窗口大小
2025-04-25 19:01:57 +08:00
龙腾猫跃 fd5b64bffc Merge pull request #6150 from LuoYun-Team/ignore-system32
chore:忽略 system32 的 Java
2025-04-25 18:37:04 +08:00
龙腾猫跃 5d3b1786d7 Merge pull request #6116 from LuoYun-Team/2025
fix:识别问题
2025-04-25 18:36:15 +08:00
龙腾猫跃 03b5f79d44 Merge pull request #6138 from Open-KFC/dl-spd-lim
fix(Setup): 下载速度限制的配置项不会在打开程序时被读取
2025-04-25 18:31:49 +08:00
龙腾猫跃 8b16e1fe90 Merge pull request #6076 from PCL-Community/fix#6073
fix(PageVersionExport): 无法导出某些版本的 Xearo 文件
2025-04-25 18:31:14 +08:00
龙腾猫跃 c2b4c5bb6b Merge pull request #6053 from PCL-Community/fix#6049
chore:  筛选器增加版本 1.21.5
2025-04-25 18:28:37 +08:00
龙腾猫跃 3d1833fd38 Merge pull request #5967 from PCL-Community/fix#5966
chore(MySkin): 增加渴望披风的翻译
2025-04-25 18:28:13 +08:00
龙腾猫跃 0c553219b2 Merge pull request #6042 from PCL-Community/fix#6041
fix(FormMain): 2.9.3 没有更新日志
2025-04-25 18:09:58 +08:00
薄奚梦灵 a197845749 fix: 少了 $ 2025-04-23 20:30:03 +08:00
薄奚梦灵andMichaelshenmo de7dffefe8 style(MyMsgLogin):统一格式
Co-authored-by: Michaelshenmo <[email protected]>
2025-04-23 20:28:24 +08:00
薄奚梦灵 a13a8dd83f feat(MyMsgLogin):增加账号被封禁时的错误提示 2025-04-22 07:14:45 +08:00
龙腾猫跃 acde605ce5 Update LICENCE 2025-04-22 05:43:25 +08:00
龙腾猫跃 ec06c310db 修正 3.5 的歧义 2025-04-22 05:38:23 +08:00
龙腾猫跃 dc611a982f Update LICENCE 2025-04-21 19:28:20 +08:00
薄奚梦灵 7cdada22a9 chore:忽略 system32 的 Java 2025-04-14 16:32:18 +08:00
薄奚梦灵 74657d54c7 pref(ModNet):使用 HttpClient 替代过时的 WebRequest 和 WebClient 2025-04-13 15:21:57 +08:00
Open-KFC 68f07aa6c2 fix(Setup): 下载速度限制的配置项不会在打开程序时被读取 2025-04-13 07:31:41 +08:00
Open-KFC 2775ccc4fe fix(ModLoader): 不应当显示的加载器的进度也被计入到显示的总进度中 2025-04-13 06:24:31 +08:00
薄奚梦灵andallMagic 683410743a style:空格
Co-authored-by: allMagic <[email protected]>
2025-04-12 21:45:24 +08:00
薄奚梦灵andallMagic 5302b405b7 style:空格
Co-authored-by: allMagic <[email protected]>
2025-04-12 21:45:14 +08:00
薄奚梦灵 35c5b69747 fix:shao'o'e 2025-04-11 20:28:43 +08:00
薄奚梦灵 8dc1148ebc pref(ModComp):提高代码可读性 2025-04-11 20:25:30 +08:00
薄奚梦灵 4ef328e595 fix:版本名称写错了 2025-04-11 17:27:44 +08:00
薄奚梦灵 a849c3cfd1 fix:识别问题 2025-04-11 08:49:13 +08:00
wyc-26 bd24d4c304 fix(ModModpack): 初始值不为 0 2025-04-10 16:36:01 +08:00
wyc-26 0604427492 Merge branch 'main' into fix#5966 2025-04-09 19:33:14 +08:00
wyc-26 d915fc2362 fix(ModModPack): 解压压缩包进度可能超过 100% 2025-04-09 18:21:16 +08:00
wyc-26 2f0958afb7 fix(PageVersionExport): 无法导出某些版本的 Xearo 文件 2025-04-06 20:10:56 +08:00
wyc-26 e038911973 chore: 筛选器增加版本 1.21.5 2025-04-06 00:38:32 +00:00
wyc-26 9021e96684 fix(FormMain): 2.9.3 没有更新日志 2025-04-05 19:01:32 +08:00
龙腾猫跃 16e09c792c 2.9.3 2025-04-05 18:22:00 +08:00
wyc-26 52ddb97938 chore(PageDownloadMod): 还是这样好了…… 2025-04-05 07:46:04 +08:00
wyc-26 31f0b81652 fix(PageDownloadMod): 小问题 2025-04-04 18:05:14 +08:00
wyc-26 ca729067c1 feat: 点击“下载新 Mod”按钮跳转到下载页面时自动填充搜索框的内容 2025-04-04 08:25:22 +08:00
龙腾猫跃 36cc718efb Merge pull request #6025 from PCL-Community/fix#6024
fix(ModDownloadLib): #5920 造成的无法下载 OptiFine
2025-04-03 23:57:48 +08:00
wyc-26 13340edaf0 fix(ModDownloadLib): #5920 造成的无法下载 OptiFine 2025-04-03 22:16:09 +08:00
龙腾猫跃 ca19c3cb35 Merge pull request #5899 from Open-KFC/fix5886
Fix:重选Fabric后FabricAPI不再自动选择
2025-04-03 03:58:35 +08:00
龙腾猫跃 8d85bb47c9 Merge pull request #6017 from LuoYun-Team/2025
支持识别 2025 年愚人节版本
2025-04-02 20:18:12 +08:00
wyc-26 56cf544bb8 fix(ModLaunch): 启动脚本乱码 2025-04-02 18:34:41 +08:00
薄奚梦灵 dcab78dcc4 黑历史+1 2025-04-02 13:46:58 +08:00
薄奚梦灵 c2a7882a4d pref(ModMinecraft):增加 2025 年愚人节版本的识别支持 2025-04-02 12:10:32 +08:00
wyc-26 c00d4e2bd6 Merge branch 'main' into fix#5966 2025-04-01 20:18:43 +08:00
薄奚梦灵 4cd8840385 style(modbase):无用换行 2025-04-01 13:41:30 +08:00
龙腾猫跃 e00e78c88c Merge pull request #5888 from shanlisi567/main
添加家园披风和入侵披风的翻译
2025-03-31 23:46:14 +08:00
龙腾猫跃 d1a6a88a7f Merge pull request #5938 from PCL-Community/fix#2294
fix(ModLaunch): 缓存问题导致切换语言失败
2025-03-31 23:43:46 +08:00
龙腾猫跃 1746b16da3 Merge pull request #5920 from PCL-Community/fix#5917
fix(ModDownloadLib): 1.14 及以上版本无法下载 OptiFine
2025-03-31 23:09:29 +08:00
龙腾猫跃 f518d12c0a Merge pull request #5996 from tangge233/fix/ValidServerCheck
chore: 防止小白无脑复制上面的 LittleSkin 地址到自动进入服务器
2025-03-31 23:00:19 +08:00
tangge233 0b888f7b01 chore: 防止小白无脑复制上面的 LittleSkin 地址 2025-03-31 22:35:09 +08:00
wyc-26 d91515c27d fix(PageDownloadInstall): 打断安装预览页面进入动画后再次切换至下载页面时显示错误*2 2025-03-28 22:35:47 +08:00
wyc-26 38c5f5e9a1 fix(PageDownloadInstall): 打断安装预览页面进入动画后再次切换至下载页面时显示错误 2025-03-28 20:35:35 +08:00
wyc-26 7d9923908b chore(MySkin): 增加渴望披风的翻译 2025-03-26 20:19:35 +08:00
wyc-26 59e93114a9 fix(ModLaunch): 缓存问题导致切换语言失败 2025-03-23 21:33:39 +08:00
wyc-26 d546528904 chore(ModDownloadLib): 按意见进行修改 2025-03-22 15:21:33 +00:00
wyc-26 f2b6ef27ed chore(ModMain): 优化代码 2025-03-22 15:11:33 +00:00
wyc-26 207ebb4e27 chore(ModMain): 修改描述 2025-03-22 22:30:51 +08:00
wyc-26 6b9bfbf4f6 fix(ModDownloadLib): 1.14 及以上版本无法下载 OptiFine 2025-03-22 22:28:12 +08:00
薄奚梦灵 4e14427349 fix(ModModPack):还不让用 Finally 了是吧 2025-03-22 15:53:01 +08:00
薄奚梦灵 0aabb69e16 fix(ShellOnly):只为可能出错的部分弹出提示 2025-03-22 15:43:56 +08:00
薄奚梦灵 d1d19a4bb3 fix(ModBase):加个 Try Catch 2025-03-22 09:14:23 +08:00
shanlisi567 5f7c5b2770 更改“威胁披风”为“入侵披风” 2025-03-21 12:35:08 +08:00
Open-KFC 502af24cec fix: 重选Fabric后FabricAPI不再自动选择 2025-03-21 09:07:00 +08:00
薄奚梦灵 44be631d4a fix(PageSetupUI):修改显示文本 2025-03-21 07:36:59 +08:00
Open-KFC 1f48948ca6 fix: 通过网络获取到更多可更新模组时未同步至‘可更新’模组列表视图 2025-03-20 22:52:51 +08:00
OpenKFC 443cffa285 Merge branch 'Hex-Dragon:main' into fix5655 2025-03-20 16:28:44 +08:00
OpenKFC 7eb3591353 Merge branch 'Hex-Dragon:main' into fix4596 2025-03-20 16:18:31 +08:00
OpenKFC ba3ed00e4b Merge branch 'Hex-Dragon:main' into feat4311 2025-03-20 16:09:44 +08:00
shanlisi567 c41b6b361e cape 2025-03-19 22:54:31 +08:00
单莉斯 34697c0d27 Ctrl+C Ctrl+V MySkin.xaml.vb 2025-03-19 20:32:52 +08:00
单莉斯 a4284dbc50 从全角更改到半角MySkin.xaml.vb 2025-03-19 20:21:59 +08:00
单莉斯 fce8781b22 Update MySkin.xaml.vb 2025-03-19 19:25:48 +08:00
龙腾猫跃 05d51a1336 fix: 重命名 Result 枚举为 ProcessReturnValues 2025-03-18 22:16:47 +08:00
龙腾猫跃 6ed967281b 2.9.2 2025-03-18 21:58:55 +08:00
薄奚梦灵 d42f67066a Merge pull request #10 from Hex-Dragon/main
111
2025-03-18 09:31:32 +08:00
薄奚梦灵 b8ce4ec899 Merge pull request #8 from Hex-Dragon/main
awa
2025-03-18 09:30:53 +08:00
龙腾猫跃 4c8174d6db Merge pull request #5847 from Hill23333/modname-new-style
feat: Mod命名默认值增加“【】xxx”
2025-03-17 23:11:34 +08:00
龙腾猫跃 de303f4c8b Merge pull request #5845 from nanhuajiaren/main
新功能:自动修改显卡设置
2025-03-17 22:37:59 +08:00
龙腾猫跃 ad8eb32ad9 Merge branch 'main' into main 2025-03-17 22:37:51 +08:00
薄奚梦灵 92eeba5fff fix(MyMsgInput):validate 输入
不要相信用户输入
2025-03-17 12:01:47 +08:00
Open-KFC aa3f0cd432 feat #4311: 模组管理页面无需点击右侧控件即可触发全选快捷键 2025-03-17 10:03:52 +08:00
龙腾猫跃 0b181baf6f Merge pull request #5795 from hadesanc1/hadesanc1/issue5721
Fix:在特定情况下,即使可用内存大于预计分配的内存,仍出现“(可用 xx GB)“字样
2025-03-17 01:59:43 +08:00
龙腾猫跃 47969e62dd Merge pull request #5863 from LuoYun-Team/Not-Refresh-Export-Config
Fix(PageVersionExport):没有刷新配置
2025-03-17 01:50:41 +08:00
龙腾猫跃 3b80d5915e Merge pull request #5861 from LuoYun-Team/fix-tip
fix(PageSetupLaunch):提示错误
2025-03-16 17:04:50 +08:00
薄奚梦灵 2fd1235a99 Fix(PageVersionExport):没有刷新配置 2025-03-16 11:55:33 +08:00
薄奚梦灵 5e24f91029 style(PageSetupLaunch):语法错误 2025-03-16 11:01:06 +08:00
薄奚梦灵 e6ba658e16 fix(PageSetupLaunch):提示错误 2025-03-16 10:58:02 +08:00
龙腾猫跃 e7034db134 Merge pull request #5415 from tangge233/NAudio
优化:自动切换到默认音频设备
2025-03-15 17:43:19 +08:00
tangge233 482d6f71fc fix(ModMusic): 千年播放老问题 2025-03-15 01:24:57 +08:00
tangge233 bf86b0732a fix: 默认音频设备的代号应该是 -1 2025-03-15 01:07:23 +08:00
tangge233 39b84e8701 style: 切换逻辑移位 2025-03-15 00:36:06 +08:00
龙腾猫跃 415188c962 Merge pull request #5785 from LuoYun-Team/allow-disable-jlw
feat(ModLaunch):允许不使用 JLW
2025-03-14 23:42:33 +08:00
龙腾猫跃 7bac28edd9 Merge pull request #5818 from allMagicNB/encoding-fix
修复编码
2025-03-14 22:47:53 +08:00
龙腾猫跃 4d25a3d61f Merge pull request #5777 from LuoYun-Team/ins-opt-as-mod
refactor(McInstallLoader):始终将 OptiFine 作为 Mod 安装
2025-03-14 20:58:41 +08:00
Hill23333 bccb2901ed feat: Mod命名默认值增加“【】xxx” 2025-03-13 21:48:32 +08:00
nanhuajiaren 715c4666f3 新增显示设置功能,通过写入注册表将MC设置为“高性能” 2025-03-13 15:41:37 +08:00
nanhuajiaren 482812ce85 Revert "新增显示设置功能,通过写入注册表将MC设置为“高性能”"
This reverts commit 2e9ca1345c.
2025-03-13 15:39:27 +08:00
nanhuajiaren 2e9ca1345c 新增显示设置功能,通过写入注册表将MC设置为“高性能” 2025-03-13 15:33:01 +08:00
allMagic 49a1016da5 fix space 2025-03-09 15:04:13 +08:00
allMagic 5c70a594b0 Encoding Fixed 2025-03-09 14:32:03 +08:00
Ciilu 855ff55495 扩展名排除 2025-03-08 07:18:05 +08:00
Ciilu a174c4856a update 2025-03-07 22:12:58 +08:00
hadesanc1 d0b6e54b29 在特定情况下,即使可用内存大于预计分配的内存,仍出现“(可用 xx GB)“字样
Fixes #5721
2025-03-07 18:41:00 +08:00
Open-KFC 16755cd4a9 fix #5655: 鼠标保持移动时抬起仍可继续改变窗口大小 2025-03-07 03:43:21 +08:00
薄奚梦灵 d88509018d Revert(ModSetup):删除调试痕迹 2025-03-05 18:38:27 +08:00
薄奚梦灵 2f6b283e0d Revert(Setup&Launch):撤销更改 2025-03-05 18:37:13 +08:00
薄奚梦灵 013c64ba4f fix(PageVersionSetup):没有增加对应内容
chore(Setup): 修改描述
2025-03-05 18:29:12 +08:00
薄奚梦灵 c24fb4ee6a fix(ModLaunch):逻辑错误导致版本设置的使用 JLW 选项无效 2025-03-05 18:23:35 +08:00
薄奚梦灵 60d14e8594 feat(setup):允许禁用 jlw 2025-03-05 13:57:09 +08:00
薄奚梦灵 7c3d820f12 chore(ModJava):删掉多余的让龙猫写 2025-03-04 21:59:30 +08:00
薄奚梦灵 045c378526 chore(ModJava):注释 2025-03-04 21:57:38 +08:00
薄奚梦灵 287d3aeb45 fix(ModJava):排除下载目录的 Java 2025-03-04 21:47:43 +08:00
薄奚梦灵 e973b1174b fix(McInstallLoader):始终将 OptiFine 作为 Mod 安装 2025-03-04 12:32:23 +08:00
薄奚梦灵 da6b64c9bc fix(btnDisplayDesc_Click):少了个标记 2025-03-04 12:30:43 +08:00
薄奚梦灵 80a004ceef fix(BtnDisplayRename_Click):在重命名前检查路径 2025-03-04 12:04:17 +08:00
Open-KFC 0ee9215b8e fix #4596: 在点击刷新按钮后对应的MyListItem显示不正确 2025-03-03 23:32:05 +08:00
薄奚梦灵 40e0afefdd fix(ModValidate):未检查路径是否存在 2025-03-03 16:30:02 +08:00
龙腾猫跃 503244a0de 2.9.1 2025-02-22 01:20:08 +08:00
龙腾猫跃 1a0c7b0520 Merge pull request #4758 from youzi-3222/feat-98
导出整合包 复活
2025-02-22 00:15:16 +08:00
龙腾猫跃 a6ebf3b43d Merge pull request #5650 from tangge233/FixModrinthApi
修复:没读取 loaders 字段
2025-02-12 23:14:20 +08:00
tangge233 bbb8e97712 fix: not read loader info on modrinth 2025-02-12 21:27:11 +08:00
龙腾猫跃 bcc63bebe9 Merge pull request #5634 from 3gf8jv4dv/fix-dirtpath-term
Revise GrassPath translation
2025-02-12 18:41:19 +08:00
龙腾猫跃 dbe09a3283 Merge pull request #5526 from Txt-Text/main
读取MMC整合包instance.cfg中的JvmArgs参数
2025-02-12 18:32:46 +08:00
龙腾猫跃 b7e7126572 Merge pull request #5523 from Silverteal/patch-1
修改 Referer 的字段顺序以符合正常语义
2025-02-12 18:18:08 +08:00
龙腾猫跃 51490a637a Merge pull request #5508 from LuoYo-Team/Remove-ClientToken
Chore:移除 ClientToken & 对 ModLaunch 刷新请求部分进行解耦合
2025-02-12 18:12:33 +08:00
龙腾猫跃 406d19b678 Merge pull request #5647 from Muqingxue-Studio/main
Fix:硬编码路径导致编译问题
2025-02-12 17:37:04 +08:00
慕轻雪 1db1323273 Merge pull request #1 from Muqingxue-Studio/mqingxue-patch-1
ci:use context
2025-02-12 15:31:53 +08:00
慕轻雪andallMagicNB f31a5b14bc ci:use context
Co-authored-by: allMagicNB <[email protected]>
2025-02-12 15:31:35 +08:00
慕轻雪 b5407ad644 Fix:Self-hosted runner 不会自动清理文件导致编译失败 2025-02-12 14:44:59 +08:00
慕轻雪 5740b16325 Fix:使用了错误的变量名 2025-02-12 14:18:59 +08:00
慕轻雪 9ff7f89f86 Update build.yml 2025-02-12 14:09:47 +08:00
慕轻雪 c27dfff84c Fix:使用字符串模板插入&修改命名以避免与自带变量冲突 2025-02-12 14:06:15 +08:00
慕轻雪 25f9363170 Fix:路径拼接 2025-02-12 14:02:10 +08:00
慕轻雪 74730f6102 Chore:自动获取工作目录 2025-02-12 13:55:42 +08:00
3gf8jv4dv 2441c52526 Revise GrassPath translation
Ref: History section on https://minecraft.wiki/w/Dirt_Path

Resolves Hex-Dragon#5633
2025-02-10 19:01:22 +08:00
龙腾猫跃 aa7ee23039 Merge pull request #5611 from Muqingxue-Studio/main
Feat:优化 Actions 文件
2025-02-07 17:55:29 +08:00
慕轻雪 e48f39ef5b Test 2025-02-07 13:19:34 +08:00
慕轻雪 df2cc61c27 Add Description 2025-02-06 22:39:44 +08:00
慕轻雪 4f2e20ff4e Format Code 2025-02-06 22:35:00 +08:00
慕轻雪 cde644c1e1 done 2025-02-06 22:22:43 +08:00
慕轻雪 aa3e08a7fb test 2025-02-06 22:10:39 +08:00
慕轻雪 4c1e9ccf72 Fix bug 2025-02-06 22:04:44 +08:00
慕轻雪 f8cbbf8092 test 2025-02-06 22:01:35 +08:00
无聊的小洛 b0e4ca9cbc Chore:格式化源代码 2025-02-06 21:29:30 +08:00
无聊的小洛and慕轻雪 9118b1d20e Update Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb
Co-authored-by: 慕轻雪 <[email protected]>
2025-02-06 21:05:03 +08:00
youzi-3222 fc1519e9b1 👌 🐛 ✨ 修改 @MoYuan-CN 的 Review,修复已知问题 2025-02-03 21:53:49 +08:00
龙腾猫跃 c5197e2f2d 2.8.13 正式版 2025-01-27 23:39:43 +08:00
huangyu 63d36f6595 Merge branch 'Hex-Dragon:main' into main 2025-01-27 15:47:35 +08:00
Txt-Text 72a33fe2cc Update ModModpack.vb
读取JvmArgs参数,删除一些废话注释
2025-01-27 11:18:37 +08:00
Txt-Text 847c433310 Update ModModpack.vb
让PCL能够正确读取MMC整合包instance.cfg中的JvmArgs
2025-01-27 09:52:00 +08:00
Silverteal 30579e6f41 修改Referer的字段顺序以符合正常语义 2025-01-26 22:41:05 +08:00
无聊的小洛 feade470a4 移除 LittleSkin OAuth 代码 2025-01-25 22:34:51 +08:00
无聊的小洛 3eed7c5b7f 移除 ClientToken 2025-01-25 22:24:56 +08:00
龙腾猫跃 70636a9a77 2.8.13 2025-01-25 03:00:46 +08:00
youzi-3222 86b0e6d459 🔥 删除 Logo 相关代码 2025-01-23 08:56:44 +08:00
youzi-3222 1b8d164061 🐛 修复已知问题 2025-01-23 08:00:59 +08:00
龙腾猫跃 107a5ae016 再次明确第六条 2025-01-22 18:38:13 +08:00
龙腾猫跃 391d50ce34 明确“相似功能”的限制 2025-01-21 22:11:07 +08:00
youzi-3222 74a9d18fc5 ♿ 👌 导出整合包改用 Loader 2025-01-17 14:02:08 +08:00
youzi-3222 08ad8e6682 ✨ 👌 允许多个链接 2025-01-16 18:24:25 +08:00
youzi-3222 1e5d5f0377 🐛 👌 Mod 文件保留原始文件名 2025-01-16 17:33:40 +08:00
youzi-3222 e6e9ebd5dc 💄 👌 合并预览与信息卡片 2025-01-16 16:27:56 +08:00
龙腾猫跃 604bcd0997 Merge pull request #5404 from hadesanc1/hadesanc1/issue5402
当在版本设置中连续按下mod右侧的“删除”按钮时,g概率导致PCL2崩溃。
2025-01-16 00:25:57 +08:00
龙腾猫跃 96a4bd05bd Merge pull request #5400 from hadesanc1/hadesanc1/issue5366
“设置/个性化/功能隐藏”字样在PCL2小窗口时不能完整显示文本
2025-01-16 00:18:26 +08:00
龙腾猫跃 36df43ad8a Merge pull request #5414 from hadesanc1/hadesanc1/issue5241
加载图标过于靠下
2025-01-16 00:07:16 +08:00
龙腾猫跃 46713b3870 Merge pull request #5398 from hadesanc1/hadesanc1/issue5259
搜索部分mod时未在mod下载详情页出现MC版本筛选
2025-01-16 00:04:53 +08:00
龙腾猫跃 58dfc9a25d Merge pull request #5413 from hadesanc1/hadesanc1/issue5248
[mod前置数量显示错误]在有前置的mod详情界面,离开再回来,mod前置显示增加
2025-01-16 00:02:03 +08:00
龙腾猫跃 51751f2464 Merge pull request #5354 from wuliaodexiaoluo/main
Fix:语言标头问题
2025-01-15 23:59:52 +08:00
龙腾猫跃 eaf7a93b52 Merge pull request #5337 from Silverteal/dpi-patch-1
通过修改 DPI 配置增强多屏幕 DPI 体验
2025-01-15 23:58:06 +08:00
龙腾猫跃 718d61af29 Merge pull request #5293 from PlayMcBKuwu/main
修复: 判断语言是否为中文 -> 判断语言是否为中文(中国大陆)
2025-01-15 23:51:58 +08:00
龙腾猫跃 49c2318ece Merge pull request #5260 from Pigeon0v0/office-cape
添加办公室披风翻译
2025-01-15 23:50:13 +08:00
龙腾猫跃 3a90962001 Merge pull request #5412 from hadesanc1/hadesanc1/issue5255
[可视化mod列表出错...]搜索Sand Filter时必报错
2025-01-15 22:44:58 +08:00
youzi-3222 838cb79420 🎨 取消测试时的注释 2025-01-14 16:50:51 +08:00
youzi-3222 f6cbb0f986 ♻️ 🐛 修复关闭版本隔离时的问题 2025-01-14 16:47:28 +08:00
youzi-3222 1dd235d313 Merge branch 'feat-98' of https://github.com/youzi-3222/PCL2 into feat-98 2025-01-14 15:12:53 +08:00
youzi-3222 fa778eedb7 🔀 合并上游分支 2025-01-14 14:21:40 +08:00
tangge233 7dff62aebf feat: output device change 2025-01-13 21:46:12 +08:00
tangge233 5034866c8f Merge branch 'main' into NAudio 2025-01-13 21:22:52 +08:00
hadesanc1 836260478c 加载图标过于靠下
Fixes #5241
2025-01-13 20:33:13 +08:00
hadesanc1 96c35a3bed [mod前置数量显示错误]在有前置的mod详情界面,离开再回来,mod前置显示增加
Fixes #5248
2025-01-13 20:06:41 +08:00
hadesanc1 81cf8c1901 [可视化mod列表出错...]搜索Sand Filter时必报错
Fixes #5255
2025-01-13 19:36:28 +08:00
hadesanc1 3b1ab78fb9 当在版本设置中连续按下mod右侧的“删除”按钮时,g概率导致PCL2崩溃。
Fixes #5402
2025-01-12 12:21:00 +08:00
hadesanc1 df83b248f8 “设置/个性化/功能隐藏”字样在PCL2小窗口时不能完整显示文本
Fixes #5366
2025-01-12 03:05:19 +08:00
hadesanc1 8b0694fdd0 搜索部分mod时未在mod下载详情页出现MC版本筛选
Fixes #5259
2025-01-12 00:31:09 +08:00
无聊的小洛 28c32765ce Fix:语言标头问题 2025-01-01 13:48:29 +08:00
Silverteal 5e55e48259 Update App.config 2024-12-26 15:18:00 +08:00
Silverteal ed72973cef Update app.manifest 2024-12-26 15:13:46 +08:00
鹿目 まどか Advancedand3gf8jv4dv a1da68a8c2 修复: 判断语言是否为中文 -> 判断语言是否为中文(中国大陆)
Co-authored-by: 3gf8jv4dv <[email protected]>
2024-12-15 22:11:18 +08:00
鹿目 まどか Advanced 53f7aa0b40 修复: 判断语言是否为中文 -> 判断语言是否为中文(中国) 2024-12-15 22:06:33 +08:00
Pigeon0v0 68bb80fc81 add: 办公室披风翻译 2024-12-14 08:59:38 +08:00
龙腾猫跃 a8bb82b033 2.8.12 正式版 2024-12-13 18:16:06 +08:00
龙腾猫跃 7083b0f4f4 2.8.12 2024-12-11 20:16:31 +08:00
龙腾猫跃 6ed0c6e4fe 2.8.11(重新上传) 2024-12-08 22:09:43 +08:00
龙腾猫跃 f678dfe853 fix: #5238 2024-12-08 21:11:57 +08:00
龙腾猫跃 b37c264e32 Update PageOtherTest.xaml.vb 2024-12-08 20:58:40 +08:00
龙腾猫跃 68f8b3eeac 2.8.11 2024-12-08 20:21:23 +08:00
龙腾猫跃 37354d15f7 Merge pull request #5229 from allMagicNB/main
自动编译时添加 Help.zip
2024-12-08 19:40:47 +08:00
allMagicNB 38b3cefa89 fix 2024-12-08 19:29:23 +08:00
allMagicNB bce8e71571 fix 2024-12-08 06:59:23 +08:00
allMagicNB f300858ced fix 2024-12-07 23:39:29 +08:00
allMagicNB bdcbab700e + PCL2Help.zip 2024-12-07 23:07:41 +08:00
龙腾猫跃 b8eb669351 Merge pull request #5225 from Ad-closeNN/main
[优化] 为 option.txt 加上 s
2024-12-07 19:28:02 +08:00
Ad-closeNN b9d69a3258 为 option.txt 加上 s 2024-12-07 19:17:46 +08:00
龙腾猫跃 e454f0c640 Merge pull request #5212 from 3gf8jv4dv/download-page-version-filter
Change the download page version filter item
2024-12-05 23:55:05 +08:00
龙腾猫跃 454c9ea377 Merge pull request #5129 from Hill23333/main
修复32位Java提示错误
2024-12-05 21:29:21 +08:00
龙腾猫跃 4f258c8078 Merge pull request #5098 from lactobionicAcid/branch
Fix #5096
2024-12-05 20:41:24 +08:00
龙腾猫跃 4b2e2d8eef Merge pull request #5073 from tangge233/homepage
优化:请求头逻辑
2024-12-05 18:58:53 +08:00
龙腾猫跃 1242d97a1c Update LICENCE 2024-12-05 02:07:04 +08:00
龙腾猫跃 6225391afa Update LICENCE 2024-12-05 02:04:46 +08:00
龙腾猫跃 b1a0e9a79d 允许分发衍生内容 2024-12-05 01:28:49 +08:00
龙腾猫跃 347bc8fb82 Update README.md 2024-12-05 01:20:17 +08:00
3gf8jv4dv 6bdf7e235a Change the download page version filter item
- Remove 1.21.3
- Add 1.21.4
2024-12-03 21:45:43 +08:00
Hill23333 d7424d4d2b Merge branch 'Hex-Dragon:main' into main 2024-11-24 18:23:18 +08:00
龙腾猫跃 37561a842b Delete .github/workflows/issue_similarity.yml 2024-11-18 19:00:37 +08:00
Hill23333 e04e462737 少了个“Not” 2024-11-16 22:58:19 +08:00
Hill23333 ba262a1741 修复32位Java提示错误 2024-11-16 22:38:55 +08:00
乳糖酸酱 df11fa5a9d Merge branch 'Hex-Dragon:main' into branch 2024-11-16 02:39:57 +08:00
龙腾猫跃 b6a52f90f6 Update README.md 2024-11-12 14:53:32 +08:00
lactobionicAcid 531706e73b Update ModMusic.vb 2024-11-10 16:12:29 +08:00
lactobionicAcid 66a2406e0a Update ModMusic.vb 2024-11-10 16:10:03 +08:00
lactobionicAcid 6ec48abe77 Fix #5096 2024-11-10 15:51:07 +08:00
tangge233 9aecc1920a fix: 目录问题…… 2024-11-09 09:43:04 +08:00
tangge233 75cc86d2a2 feat: 自己下 2024-11-08 22:09:52 +08:00
tangge233 8abf4707a1 chore: 漏了一个,问题不大 2024-11-08 17:05:21 +08:00
tangge233 b6cc6c10c3 fix: 不是每个请求都需要的 Header 2024-11-08 16:54:29 +08:00
tangge233 5d16cf24bb chore: 换一个方式 2024-11-08 16:51:38 +08:00
tangge233 05acfc6b51 fix: B站图床 2024-11-08 16:19:14 +08:00
龙腾猫跃 2a46c9f5ce 2.8.10 2024-11-08 00:43:29 +08:00
龙腾猫跃 47585e5c9d Merge pull request #5030 from 3gf8jv4dv/minecraft.experience-cape-translation
Add translation for Minecraft Experience cape
2024-11-08 00:00:39 +08:00
龙腾猫跃 114d9dd079 Merge pull request #5043 from ZeroWolf233/main
按F5刷新自定义主页
2024-11-04 17:38:51 +08:00
龙腾猫跃 9aff4288b8 Merge pull request #4998 from 3gf8jv4dv/download-page-version-filter
Change the download page version filter item
2024-11-04 16:52:11 +08:00
ZeroWolf cb322b6fa0 chore: 删除没用的东西 2024-11-02 11:25:46 +08:00
ZeroWolf233 6f1db2d079 chore: 减少屎山 2024-11-01 21:41:21 +08:00
ZeroWolf233 07ac34dafe chore: 删掉莫名其妙的第7行 2024-11-01 21:37:24 +08:00
ZeroWolf233 4638ed72f2 Merge branch 'main' of github.com:ZeroWolf233/PCL2 2024-11-01 21:25:13 +08:00
ZeroWolf233 b04ee5f28f feat: 按F5刷新自定义主页 2024-11-01 21:24:35 +08:00
龙腾猫跃 7756187dee Merge pull request #5040 from tangge233/patch-1
chore: 微调 action 脚本参数...
2024-11-01 15:02:31 +08:00
tangge233 6a10bd5406 chore: 微调参数... 2024-11-01 10:09:22 +08:00
3gf8jv4dv 134857b62f Revise 2024-10-29 21:54:22 +08:00
3gf8jv4dv ade7bcff64 Add translation for Minecraft Experience cape 2024-10-28 21:27:29 +08:00
龙腾猫跃 d599245369 Merge pull request #5025 from MiyamizuSu/main
修正了一处bug
2024-10-28 02:08:33 +08:00
MiyamizuSu 70936254de 修正了一处bug:
版本隔离弹窗取消无效bug
issue#4995
2024-10-27 20:29:13 +08:00
tangge233 9786a447ca chore: 接口 2024-10-26 11:50:08 +08:00
龙腾猫跃 564ee333aa Merge pull request #5001 from tangge233/action
利用 action bot 进行 issue 查重
2024-10-24 15:09:48 +08:00
tangge233 4a2666a998 Create issue_similarity.yml 2024-10-23 21:32:00 +08:00
3gf8jv4dv cadb9bb4a0 Change the download page version filter item 2024-10-23 21:11:17 +08:00
龙腾猫跃 c2d20e422b 2.8.9 正式版 2024-10-21 00:46:14 +08:00
龙腾猫跃 3f8e64450a 编译修复 2024-10-16 03:34:19 +08:00
龙腾猫跃 c5ae532fd5 2.8.9 2024-10-16 03:24:00 +08:00
龙腾猫跃 fb1caf0c8f Merge pull request #4810 from tangge233/Server
新功能:原版服务端下载功能
2024-10-15 17:16:08 +08:00
龙腾猫跃 2ad1a6bae2 Merge pull request #4868 from tangge233/WebP
MyImage 控件
2024-10-14 03:51:47 +08:00
龙腾猫跃 6de59a7f5b Update MyImage.vb 2024-10-14 03:51:13 +08:00
tangge233and龙腾猫跃 8d266c8a0b chore: apply suggestions
Co-Authored-By: 龙腾猫跃 <[email protected]>
2024-10-13 22:43:31 +08:00
tangge233 e1d58151cf chore: add summary tip 2024-10-13 21:39:33 +08:00
tangge233 7ba082c3f2 chore: apply suggestions 2024-10-13 21:33:10 +08:00
游子柚子andPigeon0v0 f27822b005 💬 高级选项提示文案
Co-authored-by: Pigeon0v0 <[email protected]>
2024-10-13 20:51:52 +08:00
tangge233 494e4f6516 Merge branch 'Hex-Dragon:main' into WebP 2024-10-13 10:35:08 +08:00
tangge233 0a9d115fd5 Merge branch 'Hex-Dragon:main' into Server 2024-10-13 10:34:58 +08:00
Hex Dragon Bot 106be2fbaf Merge pull request #4506 from SALTWOOD/main
通过检测 NTFS 8.3 文件名修复 #4505
2024-10-13 04:41:47 +08:00
龙腾猫跃 ac9011a323 修改标签 2024-10-13 04:28:38 +08:00
tangge233 50112b70bd chore: Try Catch 2024-10-09 00:24:47 +08:00
tangge233 71d915f3ef feat: UseCache 选项和异步加载图片 2024-10-09 00:14:05 +08:00
tangge233 e6c1b192ce Revert MyBitmap.vb 2024-10-08 23:30:45 +08:00
tangge233 788f7c9a96 fix: 不使用磁盘缓存 2024-10-03 13:49:54 +08:00
tangge233 e782d0ed2d fix: apply suggestions 2024-10-02 17:22:20 +08:00
tangge233 a6aa7847c0 feat: 修改实现方式 2024-10-02 12:07:42 +08:00
tangge233 805a0e1544 fix: 测试忘记删了 2024-10-01 23:17:12 +08:00
tangge233 94476384bd feat: MyImage 控件 2024-10-01 23:12:40 +08:00
tangge233 b1c01873b7 Merge branch 'Hex-Dragon:main' into Server 2024-10-01 21:25:52 +08:00
Pigeon0v0 4a6a17e380 ui: 从#4770 偷来了一个 Icon 2024-10-01 14:39:08 +08:00
Pigeon0v0 4de4577103 ui: 从#4770 偷来了一个 Icon 2024-10-01 14:38:18 +08:00
龙腾猫跃 76bf3c40d0 2.8.8 2024-10-01 03:39:04 +08:00
龙腾猫跃 d48ab143be 添加主页预设反馈入口 2024-10-01 02:19:52 +08:00
龙腾猫跃 fad37c9b46 正式版 2.8.7 2024-09-28 17:58:43 +08:00
tangge233 ddb6ef9426 Merge branch 'Hex-Dragon:main' into Server 2024-09-24 19:09:44 +08:00
龙腾猫跃 b5c9736918 2.8.7 2024-09-24 17:04:14 +08:00
龙腾猫跃 30bc43bdb5 Merge pull request #4228 from allMagicNB/main
让工作流编译支持替换 client_id 和 x-api-key
2024-09-24 13:11:29 +08:00
龙腾猫跃 2dfa810431 Merge branch 'main' into main 2024-09-24 13:11:20 +08:00
allMagic 8e0368180c 更新 build.yml 2024-09-24 05:40:12 +08:00
tangge233 c9fb9b9eea feat: 下载器 2024-09-23 22:23:22 +08:00
tangge233 d2620297ca feat: 原版服务端下载功能 2024-09-23 21:23:36 +08:00
龙腾猫跃 778e5636ce Merge pull request #4779 from Pigeon0v0/fix-3868
Fix #3868
2024-09-22 15:37:34 +08:00
Pigeon0v0 0d8b8fc267 fix: 多打了一个 s 导致有些光影下不了 2024-09-22 13:14:10 +08:00
Pigeon0v0 cc46b29ba6 Fix #3868 2024-09-22 11:02:30 +08:00
Pigeon0v0 893f791bb2 chores: 同步 #4360 有关下载任务名称的修改 2024-09-22 10:30:14 +08:00
Pigeon0v0 f0b32ab6f2 chores: 同步 #4360 有关下载任务名称的修改 2024-09-22 10:24:01 +08:00
Pigeon0v0 ff6239bb89 Merge branch 'main' into shaders 2024-09-22 10:20:14 +08:00
Pigeon0v0 d1eac50d15 Merge branch 'main' into datapacks 2024-09-22 10:16:53 +08:00
Pigeon0v0 9d3be21090 fix: 修复了查看数据包工程时崩溃的问题,但可能会炸掉点别的东西,需要测试 2024-09-22 10:15:49 +08:00
龙腾猫跃 49fe40662f Merge pull request #3940 from Pigeon0v0/auth
微软登录设备代码流
2024-09-22 01:53:04 +08:00
龙腾猫跃 1aaf37f815 Merge pull request #4743 from tangge233/webp
新功能:支持加载 WebP 格式图片的资源图标
2024-09-19 20:24:56 +08:00
龙腾猫跃 3606a834c0 Merge pull request #4709 from OLDRedstone/main
修复因未使用模组列表搜索并尝试移除搜索结果导致的异常#4691
2024-09-19 18:14:27 +08:00
tangge233 08faaf1f46 feat: 支持转换 webp 图片 2024-09-16 16:48:43 +08:00
OLDREDSTONE 7afd002b85 Fix #4691 2024-09-10 14:14:32 +08:00
龙腾猫跃 4f69e9e2d2 2.8.6 正式版 2024-09-05 18:07:00 +08:00
龙腾猫跃 140b7effca 2.8.6 2024-09-05 05:55:55 +08:00
allMagic e51f6f0a66 Update .github/workflows/build.yml 2024-09-03 20:02:17 +08:00
allMagic b30ad60d99 Update Plain Craft Launcher 2/Modules/Base/ModBase.vb 2024-09-03 19:56:54 +08:00
allMagic 5bf3ce0105 Update Plain Craft Launcher 2/Application.xaml.vb 2024-08-31 18:26:47 +08:00
allMagic ae503a6945 更新 build.yml 2024-08-31 18:16:08 +08:00
allMagic dff5b4730e Merge branch 'main' into main 2024-08-31 18:05:50 +08:00
allMagic 4d28be2610 更新 ModBase.vb 2024-08-31 17:55:06 +08:00
allMagic 58ad193581 更新 Application.xaml.vb 2024-08-31 17:54:43 +08:00
allMagic 9fb45610bf 更新 Application.xaml.vb 2024-08-31 17:48:53 +08:00
allMagic 0d47b82c71 + CommitHash 2024-08-31 17:02:16 +08:00
龙腾猫跃 007b51b314 2.8.5 2024-08-31 02:39:45 +08:00
龙腾猫跃 a74b2d55c7 添加对复刻赞助功能的限制 2024-08-31 02:25:50 +08:00
龙腾猫跃 1d946cb675 Merge pull request #4498 from JingHai-Lingyun/issue3519
LittleSkin 登陆失败时使用 Json 返回的错误数据中的建议
2024-08-31 01:59:57 +08:00
龙腾猫跃 6dea3ffb9c Merge pull request #4621 from Pigeon0v0/neo-desc
修改 NeoForge 介绍
2024-08-31 01:42:12 +08:00
allMagic e32bc28510 漏个单引号 2024-08-31 00:46:15 +08:00
allMagic 9ed5f04f17 Update Plain Craft Launcher 2/Modules/ModSecret.vb 2024-08-31 00:44:40 +08:00
allMagic d390ce05d4 Update Plain Craft Launcher 2/Modules/ModSecret.vb 2024-08-31 00:44:33 +08:00
allMagic 6b041cd540 Update .github/workflows/build.yml 2024-08-31 00:42:45 +08:00
allMagic c917066e0b + Const 2024-08-31 00:40:21 +08:00
Pigeon0v0 bec86c0022 Merge branch 'main' into resourcepacks 2024-08-28 19:44:46 +08:00
Pigeon0v0 7b7ad7899a Merge branch 'main' into auth 2024-08-28 19:43:39 +08:00
Pigeon0v0 545ebd680f text: 修改 NeoForge 介绍,更严谨一点 2024-08-28 19:38:47 +08:00
allMagic 5ea5dc3164 Fix Replace client_id 2024-08-27 11:06:43 +08:00
allMagic 68c1deb2aa Merge branch 'main' into main 2024-08-27 10:15:09 +08:00
凌云 3d7cffbcde Merge branch 'Hex-Dragon:main' into issue3519 2024-08-26 18:02:00 +08:00
youzi-2333 10e4bc0bbb 🐛 Tag: resources -> resourcepacks
我是傻逼。
2024-08-20 15:33:14 +08:00
tangge233 37eacb00c5 comment: 同步下注释 2024-08-20 14:28:25 +08:00
tangge233 ef5b0ba1f7 fix: 搁这最强大脑呢? 2024-08-20 14:24:40 +08:00
youzi-2333 ddfc6897d7 🐛 修复一些问题 2024-08-20 12:27:12 +08:00
allMagic 2bdda5795a 更新 build.yml 2024-08-20 11:23:25 +08:00
allMagic 26c492b370 更新 build.yml 2024-08-20 11:15:08 +08:00
allMagic b6a06f8d8d 更新 build.yml 2024-08-20 11:13:04 +08:00
龙腾猫跃 f40a299010 Merge pull request #4404 from tangge233/ModFilter
新功能:简单的本地 Mod 筛选
2024-08-20 00:16:45 +08:00
龙腾猫跃 a509ac6337 Merge pull request #4541 from tangge233/ModPageUIImprove
优化:当有 Mod 选中时在下方空开一定空间方便操作
2024-08-19 19:57:00 +08:00
龙腾猫跃 cfdda03b35 Merge pull request #4533 from wuliaodexiaoluo/4532
Fix #4532
2024-08-19 19:53:14 +08:00
tangge233 894b36e746 style: 当有 Mod 选中时在下方空开一定空间方便操作 2024-08-18 21:41:14 +08:00
无聊的小洛 e42098171e 更新地址 2024-08-18 11:02:24 +08:00
凌云 76549b4039 Merge branch 'Hex-Dragon:main' into issue3519 2024-08-18 07:18:59 +08:00
tangge233 93574f60f4 Merge branch 'Hex-Dragon:main' into ModFilter 2024-08-17 15:48:30 +08:00
龙腾猫跃 62394e0052 2.8.4 2024-08-17 01:46:19 +08:00
凌云andallMagic 0acd917e6b Use suggestion
Update Plain Craft Launcher 2/Modules/Minecraft/ModLaunch.vb

Co-authored-by: allMagic <[email protected]>
2024-08-16 19:09:22 +08:00
SALTWOOD 2427fb7619 refactor: 使用正则表达式检测 NTFS 8.3 文件名 2024-08-16 11:38:09 +08:00
SALTWOOD 3af99aca0a fix: 少了一个字 2024-08-15 17:24:42 +08:00
SALTWOOD 8b0d9e5a5c fix: 暂时使用波浪号检测修复 #4505 2024-08-15 17:12:27 +08:00
tangge233 05dc7a2650 fix: 窗口重获焦点后筛选项被重置 2024-08-15 17:03:41 +08:00
huangyu c0f8b5c701 End if 2024-08-15 15:07:37 +08:00
JingHai-Lingyun 881e79dfdf Fix 2024-08-14 22:38:24 +08:00
tangge233 20fcb59e36 Merge branch 'Hex-Dragon:main' into ModFilter 2024-08-14 18:07:05 +08:00
allMagic f919ae49af Merge branch 'Hex-Dragon:main' into main 2024-08-14 18:06:44 +08:00
龙腾猫跃 c62ab46b99 Merge pull request #4485 from allMagicNB/Fix-#4482
Fix 导出崩溃报告中的 “游戏崩溃前的输出.txt” 可能乱码 #4482
2024-08-14 05:29:20 +08:00
龙腾猫跃 bdb19e1ae4 Merge pull request #4491 from LxHTT/main
fix: 下载 NeoForge 时,从未使用镜像源
2024-08-13 22:55:21 +08:00
Pigeon0v0 5598ff3239 fix: 新增的 otc 参数可能导致网页无法打开,解决方案是去掉了这个参数 2024-08-13 21:57:24 +08:00
LxHTT b11c8c5d96 fix: 下载 NeoForge 时,从未使用镜像源 2024-08-13 21:30:47 +08:00
allMagicNB 348472b3ca Revert 2024-08-13 19:33:15 +08:00
tangge233 918178d0bd Merge branch 'Hex-Dragon:main' into ModFilter 2024-08-13 14:28:42 +08:00
allMagicNB 19fe4c03dc Fix #4482:+ "chcp 65001 > nul" & Encoding:=Encoding.UTF8 2024-08-13 14:00:26 +08:00
allMagicNB 06d92556b6 Fix 导出崩溃报告中的 “游戏崩溃前的输出.txt” 可能乱码 #4482 2024-08-13 11:57:46 +08:00
allMagic 1519c9038a Merge branch 'Hex-Dragon:main' into main 2024-08-13 10:46:07 +08:00
龙腾猫跃 4c1bfe9140 Merge pull request #4438 from 3gf8jv4dv/kitchen-sink
Revise the translation of Kitchen Sink
2024-08-13 03:46:08 +08:00
tangge233 9577e9946b Merge branch 'Hex-Dragon:main' into ModFilter 2024-08-12 09:54:33 +08:00
龙腾猫跃 a6d6c97fd7 Merge pull request #4415 from allMagicNB/Close-#4366
Close 添加对 MCC 15周年披风的翻译 #4366
2024-08-12 03:11:51 +08:00
龙腾猫跃 1c6af2caca Merge pull request #4291 from youzi-2333/feat-setup-modsrc
添加国内 Mod 镜像下载源
2024-08-12 03:08:47 +08:00
龙腾猫跃 12a3712524 Merge pull request #4449 from tangge233/VersionSortFix
fix: 检测愚人节版本所用时区不正确
2024-08-12 03:07:56 +08:00
龙腾猫跃 9d56a95dcb Merge pull request #4441 from 3gf8jv4dv/mod_modpack-download-filter-gameversion-1.21.1
Add 1.21.1 to Mod and Modpack downloadpage version filter
2024-08-12 03:02:35 +08:00
tangge233 e5a0eddcea fix: 检测愚人节版本所用时区不正确 2024-08-09 14:05:29 +08:00
3gf8jv4dv f7d2cd1cb6 Add 1.21.1 to Mod and Modpack downloadpage version filter 2024-08-08 08:27:58 +08:00
3gf8jv4dv ec3ebe3215 Update 2024-08-07 23:51:17 +08:00
3gf8jv4dv 084fb1248e Revise the translation of Kitchen Sink 2024-08-07 22:41:03 +08:00
tangge233 53743495ec fix: 全选逻辑不正确 2024-08-06 20:34:04 +08:00
tangge233 76adffffad fix: 鬼知道为什么没有初始化 2024-08-06 11:58:37 +08:00
tangge233 7721db131b fix: 刷新列表后全部选项不在 Checked 状态 2024-08-06 11:03:57 +08:00
allMagicNB f639435813 + "MCC 15th Year" Cape 2024-08-06 06:36:56 +08:00
tangge233 9fe1471f8e fix: 用枚举替代字符串 2024-08-05 23:43:31 +08:00
tangge233 eca89febf6 feat: 使用 MyRadioButton 2024-08-05 23:34:49 +08:00
tangge233 f9c4e5a752 fix: Ctrl+A 实现不合逻辑 2024-08-05 19:53:45 +08:00
tangge233 8972aec56a feat: Mod 管理卡片标题 2024-08-05 19:20:28 +08:00
tangge233 0007a0ac72 fix: 全选逻辑问题、UI问题 2024-08-05 18:57:52 +08:00
tangge233 d2ef7d7989 feat: 加个分割线 2024-08-05 18:15:16 +08:00
tangge233 3e06ea4502 fix: 错误的全部统计 2024-08-05 14:37:30 +08:00
tangge233and3gf8jv4dv 7cbdca12f3 Apply suggestions from 3gf8jv4dv
Co-authored-by: 3gf8jv4dv <[email protected]>
2024-08-05 13:51:12 +08:00
tangge233 cfe925c667 feat: 改成龙猫想要的样子 2024-08-05 13:32:36 +08:00
tangge233 c0a966f212 fix: 禁用或启用模组没有改变其所在卡片 2024-08-05 00:52:08 +08:00
tangge233 d915cd48f6 feat: 无可更新 Mod 时隐藏对应卡片 2024-08-05 00:41:00 +08:00
tangge233 591421393f fix: 意料之外的内容加入 2024-08-05 00:31:52 +08:00
tangge233 ebfed4243b feat: 适当修改本地 Mod 管理界面与操作逻辑 2024-08-05 00:22:15 +08:00
tangge233 462f985cc3 初步实现分类展示 2024-08-04 23:24:20 +08:00
huangyuandallMagic 53578a8de9 Update Plain Craft Launcher 2/Modules/Minecraft/ModModpack.vb
Co-authored-by: allMagic <[email protected]>
2024-08-03 21:46:42 +08:00
huangyu 40e421ee34 launchArgument to VersionAdvanceGame 2024-08-03 21:15:18 +08:00
huangyu 7534f9da1f Read JvmArgs and LaunchArgs in ModPack 2024-08-03 21:04:57 +08:00
allMagic 3f332fee8e X_API_KEY -> CURSEFORGE_API_KEY 2024-08-03 20:00:48 +08:00
allMagic 7be16a8906 Merge branch 'Hex-Dragon:main' into main 2024-08-03 19:49:06 +08:00
youzi-2333 86bace4d13 👌 修改 LTCatt 的审核 2024-07-31 08:57:26 +08:00
Pigeon0v0and3gf8jv4dv 22746c3ca9 fix: typo
Co-authored-by: 3gf8jv4dv <[email protected]>
2024-07-31 06:59:07 +08:00
Pigeon0v0 0bbb048c59 feat(auth): 打开的微软验证网页现在会自动填入设备代码 2024-07-30 21:42:42 +08:00
龙腾猫跃 8f49799c6d Merge pull request #3945 from Silverteal/patch-1
所有4月1日发布的版本自动视为愚人节版
2024-07-29 05:45:40 +08:00
youzi-2333 6c8a7a33b7 👌 💥 更新 LTCatt 的审核 2024-07-28 22:30:59 +08:00
龙腾猫跃 020ce330b5 https://github.com/Hex-Dragon/PCL2/discussions/4361#discussioncomment-10169901 2024-07-28 16:13:06 +08:00
龙腾猫跃 c8c981fd8c 放宽分发限制 2024-07-28 04:28:58 +08:00
Pigeon0v0 c1ba65783d feat: 支持加载数据包列表(但是下不了一点) 2024-07-27 18:33:04 +08:00
Pigeon0v0 51e3f47bac chores: 修改标签,消除歧义 2024-07-27 17:01:20 +08:00
Pigeon0v0 94ccc00f95 fix: 光影包列表加载动画文本错误
fix: 无法获取 Modrinth 上 Vanilla Shader 分类的光影(原 URL 写错了)
2024-07-27 16:45:04 +08:00
Pigeon0v0 f45322905f feat: 数据包下载 (WIP) 2024-07-27 12:54:27 +08:00
Pigeon0v0 c556dbb39c feat: 光影包下载 2024-07-27 11:03:59 +08:00
youzi-2333 89f537a00e 👌 更新一部分 LTCatt 的审核 2024-07-26 22:52:28 +08:00
龙腾猫跃 9c0ae93d7d Create FUNDING.yml 2024-07-26 17:02:43 +08:00
龙腾猫跃 016ff2c912 Merge pull request #4349 from Forks-Space/main
Readme 徽标更改爱发电 net->com
2024-07-26 16:35:09 +08:00
Ad_closeNN a4982c5ca7 进一步更改徽标 2024-07-26 16:22:23 +08:00
Ad_closeNN 6208a21b85 徽标更改爱发电 net->com 2024-07-26 16:21:32 +08:00
youzi-2333 690e73eab1 🚸 优化弹出 explorer 2024-07-25 17:29:21 +08:00
youzi-2333 6808620083 🐛 空文件夹造成选中判断错误 2024-07-23 09:05:48 +08:00
youzi-2333 1095a33a44 💥 🚸 显示部分选中的文件夹 2024-07-23 08:49:19 +08:00
youzi-2333 43511b0a49 🐛 空文件夹总是判定为被选中 2024-07-22 08:57:49 +08:00
youzi-2333 3d18a5acc5 🚧 UI 设计(未完成) 2024-07-21 22:18:48 +08:00
allMagicNB 2b57e1ec48 Merge branch 'main' of https://github.com/allMagicNB/PCL2 2024-07-20 18:10:18 +08:00
allMagicNB 7cf91d923e del Release 2024-07-20 17:55:36 +08:00
youzi-2333 de9afd3ece 🚧 UI 设计(未完成) 2024-07-19 22:46:09 +08:00
youzi-2333 e69b189c8b ✏️ MCLM -> MCIM
我是【该词语违禁】
2024-07-18 14:40:01 +08:00
youzi-2333andluolinlin768 898f53428f 🚸 修复一些问题
Co-authored-by: luolinlin768
2024-07-18 13:33:12 +08:00
youzi-2333 3bd39de728 🐛 修复整合包描述 Reload 时被覆盖的问题 2024-07-18 13:09:17 +08:00
youzi-2333 8ed02fe4d9 ✨ 为 Mod 列表、下载添加 MCLM 下载源 2024-07-18 12:38:45 +08:00
Pigeon0v0 4ae3e4aa20 feat: 支持复制设备代码和验证网址 2024-07-18 10:46:50 +08:00
allMagic 1bd7b717d0 - dir 2024-07-17 19:58:01 +08:00
allMagic fa9e1be4e2 更新 build.yml 2024-07-17 19:43:38 +08:00
allMagic 15f82f100c 更新 build.yml 2024-07-17 17:28:10 +08:00
allMagic cc18004c41 更新 build.yml 2024-07-17 17:25:04 +08:00
allMagic 227ceccb8f - .zip 2024-07-17 17:22:31 +08:00
allMagic 83a5370bad 更新 build.yml 2024-07-17 16:45:26 +08:00
allMagicNB 2348d3c8f3 + env 2024-07-17 15:13:15 +08:00
allMagicNB d7e649c44e Fix Replace 2024-07-17 15:00:23 +08:00
allMagicNB b10fc8c720 Fix something 2024-07-17 14:56:33 +08:00
youzi-2333 4547b81d68 🚧 添加整合包描述的设置 2024-07-16 13:18:41 +08:00
youzi-2333 aacaf792ef 🐛 修复图标设置的问题 2024-07-15 22:29:29 +08:00
allMagic ecf1fae8ff Merge branch 'Hex-Dragon:main' into main 2024-07-15 13:16:55 +08:00
youzi-2333 13d0cb725e 🐛 修复问题 2024-07-15 08:21:15 +08:00
龙腾猫跃 5bd8ac3870 2.8.3 2024-07-13 14:56:27 +08:00
youzi-2333 33581b5be9 Merge branch 'luolinlin768-feat-98' into feat-98 2024-07-12 21:46:15 +08:00
youzi-2333 00fdf1f3d3 🔀 Merge from luolinlin768/feat-98 to youzi-2333/feat-98 2024-07-12 21:45:18 +08:00
youzi-2333 ca07edc707 🚧 修改一些龙猫的审查 2024-07-12 21:42:07 +08:00
allMagic d52a4ec081 Update build.yml 2024-07-12 13:41:59 +08:00
allMagic a7a4838b96 [no ci]Update build.yml 2024-07-12 13:22:28 +08:00
淋淋 落 6850cd6764 修改了“包含启动器”和“启动器全局配置”的位置 2024-07-12 13:17:33 +08:00
allMagic c860ad26e2 [no ci]Update build.yml 2024-07-12 13:11:49 +08:00
allMagic 8423ef6371 Merge branch 'Hex-Dragon:main' into main 2024-07-12 11:38:36 +08:00
淋淋 落 a1b98308d4 Revert "修改了“导出整合包”的和边界的距离,21改为20"
This reverts commit 1284f464c1.
2024-07-12 11:11:19 +08:00
淋淋 落 1284f464c1 修改了“导出整合包”的和边界的距离,21改为20 2024-07-12 10:56:23 +08:00
淋淋 落 bc5b37cce5 修改了文案 2024-07-12 10:43:58 +08:00
淋淋 落 82c398dee0 更改了一些错误,修改了标题,添加了提示,修改了间距 2024-07-12 10:30:57 +08:00
淋淋 落 c4974bbf5a 删除了多余的换行 2024-07-12 09:31:03 +08:00
淋淋 落 465a38163b 在基础选项里添加了服务器文件的选择,优化了基础选项里的排版 2024-07-12 09:30:12 +08:00
淋淋 落 b28c707cb5 修改了导出整合包UI 2024-07-12 09:02:15 +08:00
龙腾猫跃 a3c419e76d 2.8.2 正式版 2024-07-12 01:39:26 +08:00
allMagic eaebd04bbb Merge branch 'Hex-Dragon:main' into main 2024-07-11 21:10:19 +08:00
Pigeon0v0 da56c5b44b Merge branch 'main' into resourcepacks 2024-07-11 20:38:14 +08:00
龙腾猫跃 5436c5ec8a 2.8.2 2024-07-11 20:13:26 +08:00
allMagic 2b55ed078b Update .gitignore 2024-07-11 20:13:08 +08:00
龙腾猫跃 73a8d60d6d Merge pull request #4175 from youzi-2333/feat-3066
完成 #3066 自动安装 modpack.zip
2024-07-11 20:05:58 +08:00
allMagicNB 4358058696 更换语气,让 “应该做” 变成 “可以做”。 2024-07-11 19:45:03 +08:00
allMagicNB d49a8f8717 Fix & + .gitignore & + Headers("x-api-key") 2024-07-11 19:40:46 +08:00
allMagic 59a05a8c71 Merge branch 'Hex-Dragon:main' into main 2024-07-11 16:41:50 +08:00
龙腾猫跃 5fb3e3a786 Merge pull request #4219 from killcerr/main
修复使用绝对路径导致的编译问题
2024-07-11 16:16:38 +08:00
龙腾猫跃 74001fecea Merge pull request #4204 from lactobionicAcid/patch-1
Fix #4183
2024-07-11 16:11:49 +08:00
龙腾猫跃 068b2a4773 Merge pull request #4193 from lactobionicAcid/main
Fix #4179
2024-07-11 16:09:22 +08:00
Silverteal a465807d0c Merge pull request #11 from PCL-Community/patch-1
Fix Bugs
2024-07-11 16:01:31 +08:00
allMagic e0bd274e0d 更新 build.yml 2024-07-11 15:58:19 +08:00
allMagic 4747c3dc68 更新 build.yml 2024-07-11 15:27:27 +08:00
allMagic 3c71a2cbf8 更新 build.yml 2024-07-11 15:21:43 +08:00
allMagic 678fc3b40c Update build.yml 2024-07-11 15:13:15 +08:00
youzi-2333 ae4f1b8672 👌 排除 log4j2.xml 2024-07-11 14:11:44 +08:00
youzi-2333 32803b1b67 👌 排除 HMCL 版本配置 2024-07-11 13:35:47 +08:00
youzi-2333 4c69defb42 ✨ 对齐 mr 整合包的输入框
强迫症快乐.jpg
2024-07-11 13:28:19 +08:00
youzi-2333 b7118be391 💬 修改包含存档的 Tooltip 2024-07-11 13:17:37 +08:00
youzi-2333 05b175b5ef ⏪ 回滚 vbproj 文件 2024-07-11 13:06:30 +08:00
youzi-2333 dce9892f61 🔀 Merge from remote 2024-07-11 13:02:28 +08:00
youzi-2333andPigeon0v0 a74e59baf4 💬 更新文案
Co-authored-by: Pigeon0v0 <[email protected]>
2024-07-11 13:00:28 +08:00
柚子柚子andPigeon0v0 bc58fdaf39 Update Plain Craft Launcher 2/Pages/PageVersion/PageVersionExport.xaml.vb
Co-authored-by: Pigeon0v0 <[email protected]>
2024-07-11 12:59:22 +08:00
youzi-2333 92f30181d5 ✨ 完成 UI 2024-07-11 12:58:48 +08:00
乳糖酸菌 b8c512c04c Update ModModpack.vb
将原先使用的.Remove方法替换为.Replace方法。
2024-07-11 10:36:32 +08:00
youzi-2333 49db56856d ✨ 导出整合包:Modrinth 2024-07-11 10:07:59 +08:00
youzi-2333 87e1fb0b1e 🐛 修复导出压缩包的问题 2024-07-10 22:14:55 +08:00
killcerr ea2b7298e9 修复使用绝对路径导致的编译问题 2024-07-10 19:57:02 +08:00
killcerr d108b62eed 修复使用绝对路径导致的编译问题 2024-07-10 19:44:33 +08:00
killcerr 8ea99d21be 修复使用绝对路径导致的编译问题 2024-07-10 19:41:26 +08:00
乳糖酸菌 f68978f7d8 Update PageDownloadInstall.xaml.vb
removed extra space
2024-07-10 18:41:45 +08:00
youzi-2333 ad41b4e377 🎨 修复工程设置问题 2024-07-09 11:49:49 +08:00
youzi-2333 09e896dc26 🚧 导出整合包:压缩包 2024-07-09 10:50:49 +08:00
乳糖酸菌 9ab43a72f2 Update PageDownloadInstall.xaml.vb
Fix #4202
2024-07-09 00:25:22 +08:00
乳糖酸菌 7a7370582c Update ModModpack.vb 2024-07-08 04:07:18 +08:00
龙腾猫跃 fce1f90b55 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2024-07-07 02:17:38 +08:00
龙腾猫跃 7ee533ca43 2.8.1 2024-07-07 02:17:36 +08:00
youzi-2333 8e3af89bd3 ✨ 完成 #3066 自动安装 modpack.zip 2024-07-06 22:34:12 +08:00
龙腾猫跃 f264f82b4b Merge pull request #4167 from 3gf8jv4dv/comma-to-halfwidth
Comma fix in `MySkin.xaml.vb` code
2024-07-06 17:04:20 +08:00
3gf8jv4dv 514bd15679 Change a comma to half-width 2024-07-06 03:00:41 +00:00
龙腾猫跃 7b0e925748 2.8.0 2024-07-06 07:18:48 +08:00
龙腾猫跃 1f4d6e3fa1 Merge pull request #4045 from Pigeon0v0/neoforge
NeoForge 支持
2024-07-05 22:03:36 +08:00
Pigeon0v0 7b8cb73115 同步 #3319 修改 2024-07-04 22:59:18 +08:00
龙腾猫跃 f999da7cce 允许在 <100 人的 QQ 群内分发修改后的版本 2024-07-04 22:09:58 +08:00
龙腾猫跃 32f5d09001 Merge pull request #4060 from youzi-2333/event-start-selected
完成 #3997 允许启动当前版本
2024-07-04 20:14:20 +08:00
龙腾猫跃 34e8397ec1 Merge pull request #4155 from youzi-2333/opti-music
只有一首音乐时右键重播
2024-07-04 20:01:47 +08:00
龙腾猫跃 746ba344e1 Merge pull request #4143 from Mxmilu666/main
Fix #3819 #4151
2024-07-04 19:55:33 +08:00
youzi-2333 fca3a2cbb5 🎨 删除多余 Import
……
2024-07-04 15:58:53 +08:00
youzi-2333 e824263992 🚸 只有一首音乐时右键重播 2024-07-04 15:57:43 +08:00
无聊的小洛 10e17d48c5 致命错误
败笔也
2024-07-04 11:37:12 +08:00
无聊的小洛 fa7deb7500 修正错误
为什么要大写啊
2024-07-04 11:36:00 +08:00
无聊的小洛 2f39c57e58 Update FormMain.xaml.vb
之前改的没改回来
2024-07-04 11:35:11 +08:00
wuliaodexiaoluo aa576e669d Fix Bugs 2024-07-04 11:23:15 +08:00
Mxmilu 86a51dea78 Fix #4151 2024-07-03 14:06:06 +08:00
Mxmilu d37572f850 Fix #3819 2024-07-02 21:46:10 +08:00
龙腾猫跃 b766f4d151 Merge pull request #4138 from Deep-Dark-Forest/patch-1
修复追随者披风不能被汉化的 bug
2024-07-02 15:48:53 +08:00
深黑森林 99c0845a1b Update MySkin.xaml.vb 2024-07-02 11:58:17 +08:00
龙腾猫跃 c13f9b199b Merge pull request #4058 from youzi-2333/version-mem-opti
为版本设置添加启动前内存优化
2024-07-02 02:40:47 +08:00
龙腾猫跃 9369759824 Merge pull request #4093 from SALTWOOD/main
简化了 Java 搜索时的一大堆 SearchEntry.Contains
2024-07-02 01:43:03 +08:00
龙腾猫跃 203516509a Merge pull request #3885 from wuyuncheng-26/main
添加 Follower's Cape 的翻译
2024-07-01 22:20:48 +08:00
龙腾猫跃 fec341506b Merge pull request #3999 from PCL-Community/main
单独兼容打开网址 `minecraft://`
2024-07-01 22:17:33 +08:00
Pigeon0v0 7921184a58 chores: 一些判断和命名修改 2024-06-30 21:05:41 +08:00
Pigeon0v0 bec5ddd833 chores: 代码清理 2024-06-30 17:19:34 +08:00
Pigeon0v0 3c44a55b37 refactor: NeoForge BMCLAPI 版本列表(爱来自 bangbang93)
fix: 安装 NeoForge 整合包时的参数初始化不正确
chores: 在低版本(<=1.19)的自动安装界面将不会显示 NeoForge
2024-06-30 15:01:06 +08:00
SALTWOOD 6674533cfb modify: 删除多余的关键词,因为下文已针对其进行全字匹配 2024-06-28 22:20:09 +08:00
Pigeon0v0 4dba7c969c chores: 代码可读性和相关优化 2024-06-28 22:00:01 +08:00
Pigeon0v0 cf43244264 refactor: 合并 Forge 和 NeoForge 部分代码 2024-06-28 09:44:55 +08:00
龙腾猫跃 101cb133fb 明确在 GitHub 上的 Fork 不违反大量使用情形的第三条 2024-06-28 05:20:43 +08:00
Pigeon0v0 a54cfef36a 代码清理 2024-06-27 19:43:39 +08:00
Pigeon0v0 f98578f60d Merge pull request #4 from youzi-2333/pigeon-neoforge
修改一些龙猫的审查
2024-06-27 18:51:21 +08:00
youzi-2333 b61081fad9 👌 修改一些龙猫的审查 2024-06-27 18:30:47 +08:00
Pigeon0v0 1b53489cf3 fix: BMCLAPI 获取支持的 Neo 列表时会意外的包含 1.20
fix: NeoForge 1.20.1 官方源版本列表不能正常解析
2024-06-27 14:09:31 +08:00
Pigeon0v0 e3c27678b6 fix: 合并了 Curse 和 Modrinth 的部分相似标签(去重) 2024-06-27 08:27:09 +08:00
Pigeon0v0 ac6ed8d986 chores: Clean up 2024-06-27 08:05:06 +08:00
Pigeon0v0 6efaa09616 fix: 官方源总是 Fallback 到 BMCLAPI 2024-06-27 08:04:09 +08:00
Pigeon0v0 ee10caa84e fix: NeoForge 官方源不可用
chores: 代码清理
2024-06-26 23:55:58 +08:00
Pigeon0v0 2cfa9b2015 feat: NeoForge BMCLAPI 版本列表获取
fix: 之前的排序方法会导致 IDE 警告
2024-06-26 23:43:37 +08:00
Pigeon0v0 707b6eec14 fix: NeoForge 手动安装版本列表不能正常加载(修完了) 2024-06-26 22:13:11 +08:00
Pigeon0v0 3f5c29264f feat(neoforge): NeoForge 官方源版本列表
feat(neoforge): NeoForge Minecraft 版本列表(官方源 Only)
fix: NeoForge 手动安装无法正常加载(只修了一半)
ui: 在自动安装的 NeoForge 卡片中显示最新稳定版和最新测试版
chores: 代码清理
2024-06-26 21:27:08 +08:00
SALTWOOD 4a804cf966 refactor: 简化搜索 Java 时的关键词检测 2024-06-23 18:27:35 +08:00
Pigeon0v0 61ac6270cb fix: 1.20.1 NeoForge 无法安装(Json 路径拼接错误)
fix: NeoForge 版本分类错误
fix: 错误地提示 NeoForge 版本不可使用 Mod
2024-06-22 08:46:10 +08:00
Pigeon0v0 70a6b6a946 chores: 删除调试用信息 2024-06-22 00:23:53 +08:00
Pigeon0v0 7d50ed1ca6 fix: 1.20.1 NeoForge 近期版本无法安装(Json 路径错误) 2024-06-22 00:23:18 +08:00
Pigeon0v0 3bc34160a2 fix: 1.20.1 NeoForge 安装失败(Json 路径错误) 2024-06-21 23:13:52 +08:00
Pigeon0v0 e0ae69660b chores: 界面文本更改,现在安装的是 NeoForge 还是 Forge 更清晰了
fix: 部分早期 Modrinth 的 NeoForge 整合包无法正确识别
2024-06-21 17:00:02 +08:00
Pigeon0v0 f83afdbbc1 fix: 1.20.1 NeoForge 下载地址拼接可能有误(如果版本为 1.20.1 则硬编码以避免问题)
fix: 整合包安装时错误信息文本有误
chores: 代码清理(NeoForge 不需要部分 Forge 逻辑)
fix(未完成): 官方源版本列表获取
2024-06-21 16:38:42 +08:00
youzi-2333 c62e0e2bd8 🍱 修改教学文件 2024-06-20 14:42:32 +08:00
youzi-2333 82dacd7eeb 🐛 修复 {mcv} 被替换的问题 2024-06-19 13:07:32 +08:00
youzi-2333 a32bf0b79e ✨ 完成 #3997
顺便把教学文件也改了……
Discussion: #4002
2024-06-18 18:13:03 +08:00
youzi-2333 dc3804a960 🎨 将内存优化合并到 Select Case
https://github.com/Hex-Dragon/PCL2/pull/4058#discussion_r1643297785
2024-06-18 13:28:19 +08:00
youzi-2333 61c0927baf 🎨 让 ComboChange 接管选择事件
https://github.com/Hex-Dragon/PCL2/pull/4058#discussion_r1643295425
2024-06-18 13:07:29 +08:00
youzi-2333 6e7cf7b481 ✨ 为版本设置添加启动前内存优化 2024-06-18 00:18:36 +08:00
Pigeon0v0 136803f652 fix: 回滚修改,修复版本列表问题 2024-06-16 16:19:28 +08:00
Pigeon0v0 9dab0b8b6b 改一行注释 2024-06-16 15:37:54 +08:00
Pigeon0v0 9c64dc0209 尝试修复 NeoForge 手动安装包列表加载不出的问题,但是失败了 2024-06-16 15:37:00 +08:00
Pigeon0v0 f3079dd619 feat: NeoForge 整合包安装
fix: 部分情况下安装 NeoForge 会失败(DownloadInfo 为空)
2024-06-16 15:29:30 +08:00
Pigeon0v0 66182f2cd0 fix: Icon 显示及其导致的崩溃问题
fix: 1.20.1 NeoForge 下载链接拼接错误
fix: 自动安装界面选择 NeoForge 后使用了 rawVersion 作为版本号
2024-06-16 14:41:16 +08:00
Pigeon0v0 030c49829d Merge pull request #2 from JingHai-Lingyun/neoforge
Small Optimize: Version Name and Icon
2024-06-16 13:22:08 +08:00
Pigeon0v0 c31e3b53b8 Merge branch 'neoforge' into neoforge 2024-06-16 13:21:50 +08:00
Pigeon0v0 d305dd3e43 fix: 版本列表不能正常显示核心 NeoForge 版本
fix: 自动安装页 NeoForge 存在多余的描述
chores: NeoForge Icon 显示,但目前有点小问题
2024-06-16 13:19:17 +08:00
JingHai-Lingyun 27825ed107 Update PageDownloadInstall.xaml.vb
Solve a conflict
2024-06-16 10:32:57 +08:00
Pigeon0v0 f4b1e3ed1a feat: 正式支持 NeoForge 自动安装 2024-06-16 09:44:00 +08:00
Pigeon0v0 0e0335e688 ui: 添加 NeoForge 手动安装 Tab
feat: NeoForge 自动安装 Stage 1
fix: StdVersion 可能错误地包含了 "neoforge-" 前缀
fix: 自动安装选择 NeoForge 时自动生成的核心名称存在重复字符串
2024-06-16 08:52:45 +08:00
Pigeon0v0 d8fe599739 fix: 所有版本都显示为测试版 / 正式版 2024-06-16 07:00:37 +08:00
Pigeon0v0 96b0018adf chores: 开源版本提示新增 2024-06-16 06:43:13 +08:00
JingHai-Lingyun 31e391f872 optimize: version name and icon
Now, NeoForge client's info and name looks like the Forge client's behavior
2024-06-16 00:34:42 +08:00
Pigeon0v0 65d21d4f21 Installer 下载和代码清理 2024-06-15 23:57:29 +08:00
Pigeon0v0 655364b06a fix: 一处逻辑判断错误,但未解决版本判断错误的问题 2024-06-15 23:29:53 +08:00
Pigeon0v0 8d9dc4712b fix: NeoForge 版本列表排序,但是抽象实现 2024-06-15 23:12:42 +08:00
Pigeon0v0 e731ef69d4 ui: 显示 NeoForge 版本属性(测试版 / 稳定版) 2024-06-15 22:38:39 +08:00
龙腾猫跃 9b6e92b9eb Merge pull request #4040 from allMagicNB/main
让工作流不会因为没有 Tag 而跳过
2024-06-15 22:05:48 +08:00
Pigeon0v0 7ba79db82c feat(neoforge): 添加了 NeoForge 的安装选项,并支持获取版本列表 2024-06-15 21:34:02 +08:00
Pigeon0v0 8e58cb0dc6 fix: 错误的 ComboBox 大小 2024-06-15 19:18:48 +08:00
allMagic fcc1afff3d 更新 build.yml 2024-06-15 18:27:36 +08:00
allMagic b2e9a4486e 更新 build.yml 2024-06-15 18:26:47 +08:00
allMagic f223ebfed9 更新 build.yml 2024-06-15 18:24:29 +08:00
allMagic 1b186dc6ae 更新 build.yml 2024-06-15 18:15:14 +08:00
allMagic 2c0ecc8100 更新 build.yml 2024-06-15 18:06:52 +08:00
allMagic 7348a6be94 更新 build.yml 2024-06-15 17:08:04 +08:00
allMagic 786f172425 更新 build.yml 2024-06-15 16:59:26 +08:00
allMagic adbcb3399c 更新 build.yml 2024-06-15 16:45:04 +08:00
allMagic 5994b38a4b 更新 build.yml 2024-06-15 16:43:27 +08:00
allMagic a8ea33b3b2 更新 build.yml 2024-06-15 16:35:37 +08:00
allMagic 695fdc9068 更新 build.yml 2024-06-15 16:32:15 +08:00
allMagic e70e904033 更新 build.yml 2024-06-15 16:24:21 +08:00
allMagic 0a2c01d773 Add workflow_dispatch 2024-06-15 16:21:28 +08:00
allMagic d34a28a503 Add Set Hash 2024-06-15 16:11:52 +08:00
JingHai-Lingyun bb1b9d193f Update ModBase.vb 2024-06-14 20:48:54 +08:00
JingHai-Lingyun ac2f29910b 好吧,这并不会出错 2024-06-14 19:47:13 +08:00
Pigeon0v0 937f034a1b feat: 支持下载资源包 2024-06-13 22:23:36 +08:00
Pigeon0v0 536c309967 Merge branch 'Hex-Dragon:main' into auth 2024-06-13 20:22:08 +08:00
龙腾猫跃 f1fedfc785 Merge pull request #4009 from allMagicNB/main
重构编译工作流文件
2024-06-13 19:36:35 +08:00
龙腾猫跃 f8b89be64e Merge pull request #4018 from Silverteal/patch-3
修复 #4013
2024-06-13 19:04:24 +08:00
Silverteal a2b4881d08 Fix #4013 2024-06-13 10:57:44 +08:00
allMagic 5c8888d138 更新 build.yml 2024-06-12 22:11:17 +08:00
allMagic af2787cdb8 更新 build.yml 2024-06-12 22:09:36 +08:00
是小胖呀26andallMagic 1d9c6d8aab Update Plain Craft Launcher 2/Pages/PageLaunch/MySkin.xaml.vb
Co-authored-by: allMagic <[email protected]>
2024-06-12 07:33:39 +08:00
allMagic 2996df399b 更新 build.yml 2024-06-12 06:11:49 +08:00
是小胖呀26 6b719a45c5 Update MySkin.xaml.vb 2024-06-11 23:33:23 +08:00
allMagic 073f9ef549 更新 build.yml 2024-06-11 22:41:18 +08:00
allMagic ffcb399432 更新 build.yml 2024-06-11 22:36:35 +08:00
allMagic b6ca6dd7dc 更新 build.yml 2024-06-11 22:13:11 +08:00
allMagic 094737ef01 Update build.yml 2024-06-11 22:04:32 +08:00
JingHai-Lingyun eefb8b50a7 又改了改
现在如果给 URL Scheme 传参也能接受了
2024-06-10 13:46:28 +08:00
JingHai-Lingyun 657b5efc2e 写死了单独逻辑
避免有人传了点别的东西进去,现在只有 `minecraft://` 会单独处理
2024-06-10 12:14:35 +08:00
JingHai-Lingyun aa5ff163e6 fix #3985 2024-06-10 12:04:52 +08:00
凌云 a18ccf78d1 fix #3985 2024-06-10 11:48:55 +08:00
allMagic 9e43f9e75c Create build.yml 2024-06-10 10:10:53 +08:00
allMagic 67d954f7e3 Delete .github/workflows/build.yml
既然是重构,直接删了得了
2024-06-10 09:26:24 +08:00
龙腾猫跃 deca6b6302 2.7.4 正式版 2024-06-07 17:47:23 +08:00
龙腾猫跃 94528e36e7 Update LICENCE 2024-06-04 02:41:51 +08:00
龙腾猫跃 c3752d5660 Update LICENCE 2024-06-03 23:26:47 +08:00
龙腾猫跃 f4277104c1 Update LICENCE 2024-06-03 23:19:04 +08:00
龙腾猫跃 cf6ab30891 Merge pull request #3944 from Silverteal/patch-2
修正工作流文件
2024-06-02 17:08:37 +08:00
Silverteal 0703c4d938 Update build.yml 2024-06-02 07:09:31 +08:00
Silverteal 2ee78d8dd1 Merge branch 'main' into patch-2
Signed-off-by: Silverteal <[email protected]>

# Conflicts:
#	.github/workflows/dotnet-desktop.yml
2024-06-02 07:00:24 +08:00
Silverteal 32b6883575 更新 build.yml 2024-06-01 23:21:43 +08:00
Silverteal 59b7fac9d5 Merge pull request #7 from Silverteal/patch-2-patch-1
Patch 2 patch 1
2024-06-01 22:42:43 +08:00
Silverteal b18a5340f2 Update build.yml 2024-06-01 22:32:57 +08:00
Silverteal 3a07beb531 Update build.yml 2024-06-01 21:20:24 +08:00
Silverteal 84b4b3b8e5 Update build.yml 2024-06-01 21:07:56 +08:00
Silverteal 3eacf3ff67 Update build.yml 2024-06-01 21:02:54 +08:00
Silverteal 5697dcf6e1 Merge pull request #6 from Silverteal/patch-2-patch-1
Patch 2 patch 1
2024-06-01 21:01:15 +08:00
Silverteal e4ecc79bc9 Update build.yml 2024-06-01 19:54:17 +08:00
Silverteal 937f947d71 Update build.yml 2024-06-01 19:43:48 +08:00
Silverteal 36a71e035b Update build.yml 2024-06-01 19:28:24 +08:00
Silverteal af3737df1e Update build.yml 2024-06-01 19:04:45 +08:00
Silverteal 941a111749 Update build.yml 2024-06-01 19:01:12 +08:00
Silverteal 3aab7ead7a Update build.yml 2024-06-01 18:57:41 +08:00
Silverteal 3f9ba48749 Update build.yml 2024-06-01 18:54:20 +08:00
Silverteal 27264e16cb Update build.yml 2024-06-01 18:52:50 +08:00
Pigeon0v0 dea21c27c5 改了改文案避免误解 2024-06-01 11:58:04 +08:00
Pigeon0v0 8b5187bff4 加了确认弹窗并支持取消,加了轮询频率,加了一些兜底 2024-06-01 11:44:15 +08:00
Pigeon0v0 236557ab9e 改了改提示,让用户知道一下设备代码复制到剪贴板了 2024-06-01 10:32:09 +08:00
Silverteal 3a1c24a517 Update build.yml, optimize language 2024-06-01 10:12:33 +08:00
Silverteal 2647a9d5f7 Merge pull request #5 from Silverteal/frontiere
Make artifact name friendly and remove pr
2024-06-01 10:07:46 +08:00
Silverteal 331d6ca5f1 Delete .github/workflows/build-pr.yml 2024-06-01 10:05:11 +08:00
Silverteal 9a05dc1e6b Update build.yml 2024-06-01 10:04:19 +08:00
Pigeon0v0 99b2adb646 feat: 微软登录设备代码流,并移除了浏览器验证方式 2024-06-01 10:00:48 +08:00
Silverteal 862281c324 Update build.yml 2024-06-01 09:55:17 +08:00
Silverteal 9ba57ab2eb Fix a typo
Signed-off-by: Silverteal <[email protected]>
2024-06-01 07:26:17 +08:00
Silverteal 73f8bdf4e1 Delete .github/workflows/build-pr.yml 2024-06-01 06:53:20 +08:00
Silverteal a95e8e8bf7 Create build-pr.yml 2024-06-01 06:52:08 +08:00
Silverteal 2ff1ac7254 Update build.yml 2024-06-01 06:47:59 +08:00
Silverteal ddb00d0303 Create build-pr.yml 2024-06-01 06:47:40 +08:00
Silverteal f5653cbd27 Update build.yml 2024-05-31 23:44:04 +08:00
Silverteal 7f6b2938da Update build.yml 2024-05-31 23:29:43 +08:00
Silverteal 85a138092a Update build.yml 2024-05-31 23:28:21 +08:00
Silverteal 5593049913 Update build.yml 2024-05-31 23:23:19 +08:00
Silverteal ccf4e9517d Try Update build.yml again 2024-05-31 23:00:55 +08:00
Silverteal a4d2e21e1f Merge pull request #1 from Hex-Dragon/main
merge upstream
2024-05-31 18:21:05 +08:00
龙腾猫跃 879fc00d72 Merge pull request #3929 from allMagicNB/main
修改 Actions 的编译参数
2024-05-31 15:47:27 +08:00
Silverteal 8fe6c5c344 Try Update build.yml 2024-05-31 14:51:06 +08:00
Silverteal 7c0beaa7e0 Update and rename dotnet-desktop.yml to build.yml 2024-05-31 14:48:08 +08:00
Silverteal 9402523e01 Merge branch 'Hex-Dragon:main' into main 2024-05-31 14:40:01 +08:00
allMagic f32b671ea1 更新 dotnet-desktop.yml 2024-05-31 06:20:23 +08:00
allMagic 966fa0280f 删除多余参数 2024-05-31 06:14:59 +08:00
龙腾猫跃 b86588e855 Merge pull request #3921 from allMagicNB/Auto-Build
Auto build
2024-05-31 05:23:06 +08:00
allMagic 900970b1e7 Delete the Badge 2024-05-30 19:21:25 +08:00
allMagic d104961365 更新 dotnet-desktop.yml 2024-05-30 06:23:12 +08:00
allMagic 5d19fb8072 Delete the link of the badge 2024-05-29 20:35:07 +08:00
allMagic 01d7df91c8 Delete Install .NET SDK 5 2024-05-29 19:33:59 +08:00
allMagic 30263bafd6 更新 dotnet-desktop.yml 2024-05-29 19:29:33 +08:00
allMagic 3b1862b352 Delete unit test 2024-05-29 19:23:23 +08:00
allMagic 630649a66b change "on:"… 2024-05-29 19:12:02 +08:00
allMagic b8e890c7d6 更新 dotnet-desktop.yml 2024-05-29 13:43:27 +08:00
allMagic d8c967c6fa 更新 dotnet-desktop.yml 2024-05-29 13:19:42 +08:00
allMagic 0996c5d58f 更新 dotnet-desktop.yml 2024-05-29 06:16:51 +08:00
allMagic 159502090a Update README.md 2024-05-28 22:09:35 +08:00
allMagic 3404cefba8 Update dotnet-desktop.yml 2024-05-28 21:57:00 +08:00
allMagic 53fe5c93ce Create dotnet-desktop.yml 2024-05-28 21:53:33 +08:00
allMagic 8d73e7f3ad Delete .github/workflows/dotnet-desktop.yml 2024-05-28 21:48:09 +08:00
allMagic 0cc5759ad9 Update dotnet-desktop.yml 2024-05-28 21:37:57 +08:00
allMagic a75e636789 Create dotnet-desktop.yml 2024-05-28 21:21:53 +08:00
龙腾猫跃 56cb6bc7d9 可编译版本 2024-05-27 01:15:32 +08:00
龙腾猫跃 c23fecfe14 公开更多代码 2024-05-26 23:53:25 +08:00
龙腾猫跃 0811b4f382 公开 ModMain.vb 2024-05-26 17:42:44 +08:00
龙腾猫跃 e1268cefdb 2.7.4 2024-05-25 17:42:12 +08:00
是小胖呀26 fe35f79405 Update MySkin.xaml.vb 2024-05-25 13:22:28 +08:00
是小胖呀26 1895568794 Update MySkin.xaml.vb 2024-05-23 19:58:44 +08:00
龙腾猫跃 0bdef8648f Merge pull request #3883 from Deep-Dark-Forest/main
添加紫色心形披风的汉化
2024-05-23 19:20:42 +08:00
深黑森林 3cbe38d2fb Update MySkin.xaml.vb 2024-05-23 19:03:57 +08:00
龙腾猫跃 adff1a6009 Merge pull request #3850 from xiaoliyuanpp/main
fix #3840
2024-05-23 05:00:57 +08:00
龙腾猫跃 8a1c053be6 Merge pull request #3776 from allMagicNB/fix-#3702
fix #3702
2024-05-23 04:58:27 +08:00
肖力源 35114ed38d Update MySkin.xaml.vb 2024-05-20 19:03:57 +08:00
肖力源 2dc437c8bb 修复#3840 2024-05-18 21:43:32 +08:00
龙腾猫跃 df81f71f9b 2.7.3 正式版 2024-05-17 16:58:33 +08:00
龙腾猫跃 67d830ea29 2.7.3 2024-05-16 21:06:03 +08:00
龙腾猫跃 a84601d99c 2.7.2 2024-05-13 18:09:30 +08:00
allMagic 7f37c83f52 fix #3702 2024-05-06 18:54:45 +08:00
龙腾猫跃 a5a3800957 Merge pull request #3781 from Chiloven945/main
修改模组及整合包版本筛选列表冗余
2024-05-06 17:14:35 +08:00
龙腾猫跃 baba653a67 Update README.md 2024-05-06 17:10:37 +08:00
龙腾猫跃 5733cbdb0e Merge pull request #3768 from allMagicNB/Revive-#85-#91-#192
Revive #85 #91 #192
2024-05-06 16:09:33 +08:00
ClovenBugle 6e1072d042 修改整合包版本筛选列表冗余
删去1.20、1.20.3、1.20.5因均有被继后版本修复的bug
添加1.19.2因其为1.19最常用的模组版本
2024-05-04 11:40:42 +08:00
ClovenBugle efe58c9748 修改模组版本筛选列表冗余
删去1.20、1.20.3、1.20.5因均有被继后版本修复的bug
添加1.19.2因其为1.19最常用的模组版本
2024-05-04 11:37:50 +08:00
Silverteal c99575c3f1 修改PageDownloadClient.xaml.vb和PageDownloadInstall.xaml.vb
对4月1日版本直接判定为愚人节版
2024-05-04 09:22:24 +08:00
allMagicNB 1158ff9e78 fix #3702 2024-05-02 21:21:43 +08:00
allMagicNB 5b58e3868d 更换爱发电主页链接 2024-05-01 16:28:24 +08:00
allMagicNB 0a48feba18 不加了不加了……都预览不了 2024-05-01 14:58:46 +08:00
allMagicNB 7d89b90ae1 换 SVG…… 2024-05-01 14:31:02 +08:00
allMagicNB f6cae4ea23 添加 “赞助-爱发电” Badge 2024-05-01 14:14:29 +08:00
allMagicNB a09baee5f8 添加 “赞助-爱发电” Badge 2024-05-01 14:13:20 +08:00
allMagicNB fa3d5bc09b 增加 “Issues” Badge 2024-05-01 13:33:39 +08:00
allMagicNB c169532794 为 Bagde 添加链接和说明 2024-05-01 10:48:38 +08:00
allMagic 37313e4d6e Update README.md
再改下
2024-05-01 10:18:04 +08:00
allMagic dd9cdaf15f Update README.md
换了下 Star 的 Logo
2024-05-01 10:17:32 +08:00
allMagic 6a2f95e96f Update README.md
Revive #85 #91 #192
2024-04-30 23:00:24 +08:00
龙腾猫跃 d682b59803 Merge pull request #3732 from allMagicNB/main
增加资源下载界面的 1.20.5(#3731)
2024-04-25 04:14:52 +08:00
allMagic 02347239b4 Add 1.20.5 2024-04-25 02:12:48 +08:00
allMagic dc4eda533c Add 1.20.5 2024-04-25 02:10:28 +08:00
龙腾猫跃 d86ad945a6 Merge pull request #3699 from zkitefly/crash
updata CrashReason.Fabric报错并给出解决方案
2024-04-19 22:04:02 +08:00
zkitefly 12be800391 updata CrashReason.Fabric报错并给出解决方案 2024-04-19 13:52:59 +00:00
龙腾猫跃 c47b80df36 2.7.1 正式版 2024-04-08 17:15:20 +08:00
龙腾猫跃 43b0acba08 2.7.1 2024-04-08 01:54:35 +08:00
龙腾猫跃 c1cad542c2 Merge pull request #3530 from wuliaodexiaoluo/main
添加 JVM 参数
2024-04-05 22:14:26 +08:00
龙腾猫跃 09f9b8f1e5 Merge branch 'main' into main 2024-04-05 22:14:18 +08:00
龙腾猫跃 4241060010 2.7.0 正式版 2024-04-05 17:36:13 +08:00
龙腾猫跃 0dab617b64 2.7.0 2024-04-04 03:26:43 +08:00
龙腾猫跃 515b7e89c5 Merge pull request #3593 from allMagicNB/main
fix #3591
2024-04-04 01:26:23 +08:00
allMagic d83f98b34a fix #3591 2024-04-02 13:32:14 +08:00
allMagic e2030970a3 fix #3591 2024-04-02 06:23:00 +08:00
allMagic e623d3464a fix #3591 2024-04-01 22:55:39 +08:00
allMagic 81346f0821 fix #3591 2024-04-01 22:37:05 +08:00
allMagic 810c6e8618 fix #3591 2024-04-01 22:17:49 +08:00
wuliaodexiaoluo a5199d32ed Update FormMain.xaml.vb 2024-03-20 08:42:54 +08:00
wuliaodexiaoluo b058e7722d Update FormMain.xaml.vb 2024-03-19 14:52:56 +08:00
wuliaodexiaoluo 4beef0fb5d Merge pull request #4 from wuliaodexiaoluo/wuliaodexiaoluo-patch-2
Update FormMain.xaml.vb
2024-03-19 13:56:29 +08:00
wuliaodexiaoluo eb195373ea Update FormMain.xaml.vb
修复 UAC 阻止文件拖拽
2024-03-19 13:56:11 +08:00
wuliaodexiaoluo 65ca2e0cf4 Update PageSetupLaunch.xaml 2024-03-16 13:10:15 +08:00
wuliaodexiaoluo 09e420ad6b Merge pull request #3 from wuliaodexiaoluo/wuliaodexiaoluo-patch-2
Update PageSetupLaunch.xaml
2024-03-16 13:01:45 +08:00
wuliaodexiaoluo 95429cc9cc Merge branch 'main' into wuliaodexiaoluo-patch-2 2024-03-16 13:01:37 +08:00
wuliaodexiaoluo 5a78a46b28 Update PageSetupLaunch.xaml
解决描述错误
2024-03-16 12:53:00 +08:00
wuliaodexiaoluo 3ae624d4fb Update PageSetupLaunch.xaml
手滑了抱歉。。。
2024-03-16 12:51:14 +08:00
wuliaodexiaoluo 91f39f2afd Merge pull request #2 from wuliaodexiaoluo/wuliaodexiaoluo-patch-1
Fix # 3511
2024-03-16 12:31:42 +08:00
wuliaodexiaoluo 65da5b67f7 Update PageSetupLaunch.xaml 2024-03-16 12:30:46 +08:00
wuliaodexiaoluo 268cb092dd Update PageSetupLaunch.xaml 2024-03-16 12:27:47 +08:00
wuliaodexiaoluo 9728af60d0 Update PageSetupLaunch.xaml 2024-03-16 12:24:48 +08:00
wuliaodexiaoluo 7affc1e24f Merge pull request #1 from Hex-Dragon/main
Update
2024-03-16 12:23:26 +08:00
龙腾猫跃 3076f3a6b7 Merge pull request #3475 from WorldHim/patch-1
修复 #3461 换行缺失
2024-03-03 04:42:17 +08:00
WorldHim 02c8b7211b fix: #3461 2024-03-02 20:30:02 +08:00
龙腾猫跃 5843649cfa 2.6.15 正式版 2024-03-02 18:04:12 +08:00
龙腾猫跃 f78250020e 2.6.15 2024-03-02 17:53:55 +08:00
龙腾猫跃 031cd898f6 Merge pull request #3427 from zkitefly/patch-4
Update bug2.yml
2024-02-26 06:14:19 +08:00
zkitefly 1b272a6f06 更新 bug2.yml 2024-02-25 17:23:50 +08:00
zkiteflyand柚子柚子 f2e9be66c1 Update .github/ISSUE_TEMPLATE/bug2.yml
Co-authored-by: 柚子柚子 <[email protected]>
2024-02-25 15:28:04 +08:00
zkitefly c719803849 Update bug2.yml
?
2024-02-25 15:15:13 +08:00
zkiteflyand何杰豪 2b485233cb Update .github/ISSUE_TEMPLATE/bug2.yml
Co-authored-by: 何杰豪 <[email protected]>
2024-02-25 15:10:49 +08:00
zkitefly 5198298336 Update bug2.yml 2024-02-25 15:07:14 +08:00
zkitefly a1a2d53d31 Update bug2.yml 2024-02-25 11:37:16 +08:00
龙腾猫跃 ec6784d57d 2.6.14 正式版 2024-02-23 17:59:24 +08:00
龙腾猫跃 83ebc61d8a 2.6.14 2024-02-22 00:04:00 +08:00
龙腾猫跃 63d48b09e3 Merge pull request #3231 from zkitefly/fabric_error-chinese
添加"Fabric报错并给出解决方案"中文检查支持
2024-02-20 04:27:32 +08:00
zkitefly 4a25b066d2 Fix https://github.com/Hex-Dragon/PCL2/issues/3228 . 添加"Fabric报错并给出解决方案"中文检查支持 2024-01-31 11:39:32 +00:00
龙腾猫跃 8c8b1066bf 2.6.13 正式版 2024-01-06 22:46:38 +08:00
龙腾猫跃 fb4386952d 2.6.13 2024-01-06 22:35:35 +08:00
龙腾猫跃 fa054d9a9e 2.6.12 正式版 2023-12-26 16:52:03 +08:00
龙腾猫跃 6705444fb4 2.6.12 2023-12-18 04:56:23 +08:00
龙腾猫跃 c98e0367d0 2.6.10 正式版重新签名 2023-11-28 18:01:30 +08:00
龙腾猫跃 2c7b532188 2.6.11 2023-11-27 00:49:59 +08:00
龙腾猫跃 e2a3dd3281 Merge pull request #2864 from zkitefly/minecraft.wiki
`https://minecraft.fandom.com/zh/wiki/` -> `https://zh.minecraft.wiki/w/`
2023-11-21 18:14:34 +08:00
zkitefly e712280c7b Update ModDownloadLib.vb 2023-11-11 11:26:52 +08:00
龙腾猫跃 8308577549 2.6.10 正式版 2023-10-25 16:36:22 +08:00
龙腾猫跃 f0c634db78 2.6.10 修正 2023-10-23 23:37:34 +08:00
龙腾猫跃 7b623dbc2d 2.6.10 2023-10-23 23:34:18 +08:00
龙腾猫跃 037e6b19b4 2.6.9 2023-10-07 05:29:24 +08:00
龙腾猫跃 5ff7aed46e Merge pull request #2724 from JingHai-Lingyun/main
Update PageLoginMs.xaml.vb
2023-09-30 04:08:43 +08:00
凌云 3779d74e93 Update PageLoginMs.xaml.vb 2023-09-29 10:16:25 +08:00
龙腾猫跃 3b8de89309 2.6.8 2023-09-12 00:55:44 +08:00
龙腾猫跃 f18ede2c7a Merge pull request #2649 from zkitefly/patch-4
Update ModCrash.vb
2023-09-07 16:58:36 +08:00
龙腾猫跃 4158e95f87 * 2023-09-06 17:36:44 +08:00
龙腾猫跃 a77c2385cd * 2023-09-06 17:32:16 +08:00
龙腾猫跃 fe5dc2d07f 修改 issue 模板 2023-09-06 17:28:27 +08:00
zkitefly 17c2049d2c Update ModCrash.vb 2023-08-31 21:33:05 +08:00
zkitefly 0eebb8ec78 Update ModCrash.vb 2023-08-31 10:15:50 +08:00
zkitefly 58d40976a7 Update ModCrash.vb 2023-08-31 10:07:12 +08:00
龙腾猫跃 b2f2bcf4b6 Merge pull request #2617 from so1ve/main-1
在issue template中添加讨论链接
2023-08-26 00:28:12 +08:00
Ray 2a6708cc08 Update config.yml 2023-08-26 00:14:35 +08:00
Ray c9c00bc23f Update config.yml 2023-08-26 00:12:42 +08:00
Ray 7fa092eb25 Update config.yml 2023-08-26 00:12:05 +08:00
Ray d4e692b69f Update config.yml 2023-08-26 00:10:15 +08:00
龙腾猫跃 8479c47da0 Merge pull request #2574 from zkitefly/issue
https://github.com/Hex-Dragon/PCL2/discussions/2572
2023-08-23 02:40:57 +08:00
zkitefly 971aa0034d 还是换回去吧( 2023-08-22 23:11:08 +08:00
龙腾猫跃 b717bb31c8 2.6.7 正式版 2023-08-22 22:47:42 +08:00
zkitefly 3037a9e384 改一下 2023-08-22 22:41:40 +08:00
zkitefly 6794b24292 https://github.com/Hex-Dragon/PCL2/discussions/2572 2023-08-22 22:39:33 +08:00
龙腾猫跃 d774de5436 2.6.7 2023-08-22 16:19:12 +08:00
龙腾猫跃 e4ae1a057a 2.6.6 正式版 2023-08-21 14:22:57 +08:00
龙腾猫跃 41250d8387 2.6.6 2023-08-21 04:02:19 +08:00
龙腾猫跃 79778490d5 2.6.5 2023-08-15 16:38:52 +08:00
龙腾猫跃 e1e084aea3 Merge pull request #2487 from SALTWOOD/main
Fix #2486
2023-08-13 19:22:36 +08:00
SALTWOOD 836d55e445 Fix #2486 2023-08-13 17:26:35 +08:00
龙腾猫跃 3574931bfb Merge pull request #2301 from zkitefly/patch-2
Update ModCrash.vb
2023-08-06 11:25:17 +08:00
zkitefly c9aabd6a55 Update ModCrash.vb 2023-07-21 09:30:39 +08:00
龙腾猫跃 e6c6975047 2.6.4 2023-07-18 04:45:38 +08:00
龙腾猫跃 9c41a807c3 Merge pull request #2271 from zkitefly/patch-2
Update ModCrash.vb
2023-07-17 18:17:15 +08:00
zkitefly a0fe5903f0 Update ModCrash.vb 2023-07-17 16:43:44 +08:00
zkitefly 06be5b5b17 Update ModCrash.vb
https://github.com/Hex-Dragon/PCL2/discussions/2270
2023-07-17 16:08:38 +08:00
龙腾猫跃 73d43310c9 Merge pull request #2173 from zkitefly/patch-2
Update PageVersionSetup.xaml
2023-07-16 00:55:53 +08:00
龙腾猫跃 9b54ea3dee Merge pull request #2148 from zkitefly/log
添加检查:Mod依赖项未完善
2023-07-16 00:53:21 +08:00
zkitefly fa5026ccd7 Update PageVersionSetup.xaml 2023-07-04 17:48:05 +08:00
zkitefly ca3e7f40e1 Update PageVersionSetup.xaml 2023-07-04 17:47:15 +08:00
zkitefly 8004385d6f Update PageVersionSetup.xaml 2023-07-04 17:46:50 +08:00
龙腾猫跃 2c2bd2d489 2.6.3 正式版 2023-07-02 22:04:24 +08:00
[email protected] 80cf5957f2 更新 ModCrash.vb 2023-06-30 11:57:25 +08:00
[email protected] 7d139cbd73 添加检查:Mod依赖项未完善
https://mclo.gs/p25LjXV
2023-06-30 11:17:10 +08:00
龙腾猫跃 8a770f63cf 2.6.3 重新上传 2023-06-24 17:32:40 +08:00
龙腾猫跃 07e824b0a1 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-06-22 17:04:56 +08:00
龙腾猫跃 794c3003f3 2.6.3 2023-06-22 17:04:23 +08:00
龙腾猫跃 d956fb2521 Merge pull request #1954 from zkitefly/patch-4
在安装 MMC 和 MCBBS 整合包时如果加载器是 org.quiltmc.quilt-loader ,则提示不支持
2023-06-17 17:21:04 +08:00
龙腾猫跃 6005856661 Merge pull request #2055 from zkitefly/log2
部分mod需要JDK11报错时的错误分析检测优化
2023-06-17 17:17:17 +08:00
龙腾猫跃 920817cc34 Merge pull request #2057 from zkitefly/log3
`OptiFine与Forge不兼容`的新规则
2023-06-17 17:11:40 +08:00
[email protected] c1167632a6 OptiFine与Forge不兼容的新规则
1.20的qwq
2023-06-17 01:14:06 +08:00
[email protected] 352799c0ed 部分mod需要JDK11报错时的错误分析检测优化
https://mclo.gs/D5MVHDa#L30
https://mclo.gs/nWMnElV#L34
https://mclo.gs/eoO8xjH#L14
https://mclo.gs/BVagUsw#L14
https://mclo.gs/Jw1dRMZ#L27
https://mclo.gs/PYRFCj3#L21
https://mclo.gs/4dCbKcJ#L19
https://mclo.gs/NCfhHYC#L14
2023-06-17 00:47:12 +08:00
zkitefly 3e5ba70516 Update ModModpack.vb 2023-06-09 22:14:59 +08:00
zkitefly 9420c37640 在安装 MMC 整合包时如果加载器是 org.quiltmc.quilt-loader ,则提示不支持 2023-06-03 02:07:36 +08:00
龙腾猫跃 ce164dd6fd 2.6.2 2023-05-28 20:18:59 +08:00
龙腾猫跃 c1a26a119f 2.6.1(正式版重新上传) 2023-05-26 00:37:18 +08:00
龙腾猫跃 10cc561ac6 2.6.0 正式版重新上传 2023-05-26 00:30:09 +08:00
龙腾猫跃 ba883713d9 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-05-25 18:16:18 +08:00
龙腾猫跃 d01372495b 2.6.0 正式版 2023-05-25 18:16:05 +08:00
龙腾猫跃 5c2a78e5e0 Merge pull request #1865 from WForst-Breeze/wfb-1
优化 综合 Bug 反馈 模板
2023-05-17 14:48:22 +08:00
风释清然SC 74a5e1d6ab 优化 综合 Bug 反馈 2023-05-16 21:26:01 +08:00
风释清然SC 800347fa37 优化 综合 Bug 反馈 2023-05-16 21:08:07 +08:00
龙腾猫跃 cf74de5789 2.6.0 2023-05-11 02:03:06 +08:00
龙腾猫跃 1748fec3dd Merge pull request #1773 from zkitefly/log2
更新 ModCrash.vb
2023-05-10 02:28:33 +08:00
龙腾猫跃 854546444b Merge pull request #1772 from zkitefly/patch-4
修改链接
2023-05-10 01:40:02 +08:00
[email protected] 1224c1a427 更新 ModCrash.vb
https://mclo.gs/pyYhqhx
https://mclo.gs/qCDf08i
2023-05-03 10:54:42 +08:00
[email protected] c02045bfe0 更新 ModCrash.vb
https://mclo.gs/rVgURRg
2023-05-03 10:28:17 +08:00
[email protected] 820e4c0cef 更新 ModCrash.vb 2023-05-02 19:07:17 +08:00
zkitefly e99293ecd2 修改链接 2023-05-02 18:51:27 +08:00
龙腾猫跃 fd7049ceed 2.5.4 2023-04-26 04:27:52 +08:00
龙腾猫跃 11ecc11566 2.5.3 重发布 2023-04-09 22:35:54 +08:00
龙腾猫跃 78d8a778c7 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-04-09 02:49:47 +08:00
龙腾猫跃 f4448eddf4 2.5.3 2023-04-09 02:49:08 +08:00
龙腾猫跃 9fc2a502ef Merge pull request #1601 from zkitefly/patch-4
Update ModCrash.vb
2023-04-08 21:44:45 +08:00
zkitefly 2392752756 Update ModCrash.vb 2023-04-08 12:42:24 +08:00
龙腾猫跃 3fd6c9d483 Merge pull request #1564 from youzi-2333/main
添加常见错误
2023-04-07 18:01:39 +08:00
youzi-2333 ba0929983c 添加常见错误 2023-04-02 22:00:13 +08:00
龙腾猫跃 b5adc1175c 2.5.2 正式版 2023-03-28 14:52:45 +08:00
龙腾猫跃 7cf61bc7cd 2.5.2 2023-03-24 00:41:28 +08:00
龙腾猫跃 d886acdeac 2.5.1 2023-03-08 23:34:10 +08:00
龙腾猫跃 36c10ade8c Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-02-16 22:21:13 +08:00
龙腾猫跃 6dc8789ac0 2.5.0 2023-02-16 22:21:04 +08:00
龙腾猫跃 e6b3b8e778 Merge pull request #1121 from zkitefly/log
更新 ModCrash.vb
2023-02-13 22:52:48 +08:00
龙腾猫跃 a9bf0b682a 2.4.9 正式版 2023-02-07 16:51:28 +08:00
龙腾猫跃 d540b94448 2.4.9 2023-02-06 22:54:56 +08:00
龙腾猫跃 64539ad55c 2.4.8 正式版 2023-02-06 16:36:43 +08:00
龙腾猫跃 b06328645c 2.4.8 2023-02-04 18:35:32 +08:00
[email protected] 324d2457f7 更新 ModCrash.vb
https://github.com/huanghongxun/HMCL/discussions/1904#discussioncomment-4332485
https://github.com/huanghongxun/HMCL/discussions/1904#discussioncomment-4332522
2023-02-02 22:26:55 +08:00
龙腾猫跃 eb9e7864c9 2.4.7 正式版 2023-01-29 14:23:27 +08:00
龙腾猫跃 c2b282c8db 2.4.7 2023-01-27 01:11:26 +08:00
龙腾猫跃 48214557da Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2023-01-26 01:50:57 +08:00
龙腾猫跃 06b50fa74c 2.4.6 2023-01-26 01:50:52 +08:00
龙腾猫跃 7cab6b281a Merge pull request #1002 from WForst-Breeze/main
更改对于无法加载 Mod 的版本的提示
2023-01-24 20:22:09 +08:00
风释清然SC c28f05aae1 想了想还是改回来吧…… 2023-01-24 20:15:27 +08:00
风释清然SC f11aedef5d Update PageVersionModDisabled.xaml 2023-01-24 19:55:35 +08:00
风释清然SC 63e002780a PCL2 #1001 2023-01-24 19:54:04 +08:00
龙腾猫跃 8e5362e2df Merge pull request #925 from WorldHim/main
修复反馈链接问题
2023-01-24 18:47:55 +08:00
WorldHim 3129edd09f 修复反馈链接问题 2023-01-16 08:05:54 +08:00
龙腾猫跃 45a9bf1096 2.4.5 2023-01-08 20:36:30 +08:00
龙腾猫跃 bef94fa743 2.4.4 正式版 2022-12-16 16:44:47 +08:00
龙腾猫跃 fd329037e7 2.4.4 2022-12-12 02:34:19 +08:00
龙腾猫跃 5fb5a3b963 2.4.3 2022-11-26 22:39:08 +08:00
龙腾猫跃 5ef1d60e2e 由于联机已被禁用,公开联机部分代码 2022-11-10 20:22:47 +08:00
龙腾猫跃 d091e153a9 删除联机的反馈选项 2022-11-08 19:57:28 +08:00
龙腾猫跃 97c5367108 2.4.2 2022-11-08 19:17:11 +08:00
龙腾猫跃 24cb4599d6 删除联机入口 2022-11-05 21:27:44 +08:00
龙腾猫跃 ef32179598 2.4.1 2022-11-03 22:29:41 +08:00
龙腾猫跃 e9b34ad998 再次更新 licence 2022-10-31 12:03:27 +08:00
龙腾猫跃 2d9a4d9391 Merge pull request #299 from Silverteal/patch-1
Update licence.txt
2022-10-31 11:50:07 +08:00
Silverteal 89f6059ea8 Update licence.txt 2022-10-29 20:39:08 +08:00
龙腾猫跃 1368a902c8 2.4.0(补充更改) 2022-10-16 21:58:56 +08:00
龙腾猫跃 0066d1b35e 2.4.0 2022-10-15 21:10:59 +08:00
龙腾猫跃 dcf0e17890 更新联机反馈网址 2022-10-14 22:50:47 +08:00
龙腾猫跃 f7c10035e8 Merge branch 'main' of https://github.com/Hex-Dragon/PCL2 2022-10-08 17:54:34 +08:00
龙腾猫跃 9876fe3442 2.3.5 (正式版) 2022-10-08 17:54:31 +08:00
龙腾猫跃 8175425458 Merge pull request #176 from zkitefly/patch-1
修改链接
2022-10-02 11:25:09 +08:00
zkitefly cb3b748367 add 2022-10-02 09:12:01 +08:00
zkitefly f67189919f add 2022-10-02 09:04:28 +08:00
zkitefly 07061dc4a1 add 2022-10-02 08:56:23 +08:00
zkitefly d7a8c03776 修改链接 2022-10-02 08:43:43 +08:00
龙腾猫跃 c400836de8 2.3.5 2022-09-29 17:51:58 +08:00
龙腾猫跃 bbbafa5429 上传一个瞎写的协议 2022-09-25 21:50:53 +08:00
232 changed files with 48200 additions and 13698 deletions

No files matched your search

+3
View File
@@ -0,0 +1,3 @@
# These are supported funding model platforms
custom: ['https://afdian.com/a/LTCat']
+17 -11
View File
@@ -1,6 +1,6 @@
name: "Minecraft 崩溃"
description: "PCL2 提示 “Minecraft 出现错误”,或游戏崩溃"
labels: [· Bug, 新反馈]
description: "PCL 提示 “Minecraft 出现错误”,或游戏崩溃"
labels: [· Bug, 新提交]
body:
- type: checkboxes
id: "yml-1"
@@ -8,13 +8,11 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "**我所启动的游戏不是整合包,且未开启安装 Mod。** 安装 Mod 后的游戏崩溃不是 PCL2 的原因,请 **不要** 提交反馈。你可以在 QQ 群里或者论坛找人求助,但这里并不是你求助的地方。"
- label: "**我所启动的游戏不是整合包,且未安装任何 Mod。** 安装 Mod 后的游戏崩溃基本不是 PCL 的原因,请 **不要** 提交反馈。你可以在论坛或社区找人求助,但这里并不是你求助的地方。"
required: false
- label: "**我已尝试使用 HMCL 启动,HMCL 没有出现问题。** 如果 HMCL 也无法启动就不是 PCL 导致的问题,请 **不要** 提交反馈。[下载 HMCL](https://hmcl.huangyuhui.net/download)"
required: true
- label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是游戏本身存在问题,并非 PCL2 的问题,请 **不要** 提交反馈。[下载其他启动器](https://www.mcbbs.net/forum.php?mod=forumdisplay&fid=43&filter=typeid&typeid=908)"
required: true
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一 Bug 未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Meloong-Git/PCL/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Meloong-Git/PCL/discussions/1930) 中搜索,确认了这一 Bug 未被提交过。"
required: true
- type: textarea
id: "yml-2"
@@ -26,8 +24,16 @@ body:
- type: textarea
id: "yml-3"
attributes:
label: 错误报告、日志与附件
description: "上传 PCL2 提供的错误报告。如果没有,也可以上传 PCL 文件夹中的 Log1~5.txt。"
label: PCL 错误报告、日志与附件
description: "上传 PCL 提供的错误报告(在崩溃时选择导出错误报告)。如果没有,也可以上传 PCL 文件夹中的 Log1~5.txt。"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: true
required: true
- type: textarea
id: "yml-4"
attributes:
label: HMCL 启动脚本
description: "在 HMCL 中进入版本列表,点击版本右侧的三个点,选择 生成启动脚本。"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: false
+7 -9
View File
@@ -1,6 +1,6 @@
name: "下载或登录时卡住或失败"
description: "下载游戏、Mod 或整合包,登录正版账号时出现问题"
labels: [· Bug, 新反馈]
description: "下载游戏、Mod 或整合包,或登录正版账号时出现问题"
labels: [· Bug, 新提交]
body:
- type: checkboxes
id: "yml-1"
@@ -8,13 +8,11 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是网络环境不佳[(解决方法)](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-0hDr),并非 PCL2 的问题,请 **不要** 提交反馈。[下载其他启动器](https://www.mcbbs.net/forum.php?mod=forumdisplay&fid=43&filter=typeid&typeid=908)"
- label: "**我已尝试使用其他启动器,其他启动器没有出现问题。** 如果其他启动器也存在问题,证明是网络环境不佳[(解决方法)](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-0hDr),并非 PCL 的问题,请 **不要** 提交反馈。[下载 HMCL](https://hmcl.huangyuhui.net/download)"
required: false
- label: "我知晓大多数此类问题都是网络环境不佳导致的,但我确实认为我的问题可能是 PCL 导致的,和网络环境无关。"
required: true
- label: "我已知晓大多数此类问题都是网络环境不佳导致的,但我确实认为我的问题是 PCL2 导致的,和我的网络环境无关。"
required: true
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一 Bug 未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Meloong-Git/PCL/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Meloong-Git/PCL/discussions/1930) 中搜索,确认了这一 Bug 未被提交过。"
required: true
- type: textarea
id: "yml-2"
@@ -40,4 +38,4 @@ body:
description: "上传 PCL 文件夹中的 Log1~5.txt。[日志在哪?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-fvZW)"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: true
required: true
+3 -5
View File
@@ -1,6 +1,6 @@
name: "综合 Bug 反馈"
description: "遇见了没有细分选项的其他 Bug"
labels: [· Bug, 新反馈]
labels: [· Bug, 新提交]
body:
- type: checkboxes
id: "yml-1"
@@ -8,9 +8,7 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未修复这个 Bug。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一 Bug 未被提交过。"
- label: "我已在 [Issues 页面](https://github.com/Meloong-Git/PCL/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Meloong-Git/PCL/discussions/1930) 中搜索,确认了这一 Bug 未被提交过。"
required: true
- type: textarea
id: "yml-2"
@@ -36,4 +34,4 @@ body:
description: "上传 PCL 文件夹中的 Log1~5.txt。[日志在哪?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-fvZW)"
placeholder: "先点击这个文本框,然后再将文件直接拖拽到文本框中以上传。"
validations:
required: true
required: true
+3 -5
View File
@@ -1,6 +1,6 @@
name: "优化建议"
description: "对已有功能的小幅度优化或改进建议"
labels: [· 优化, 新反馈]
labels: [· 优化, 新提交]
body:
- type: checkboxes
id: "yml-1"
@@ -8,11 +8,9 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未实现这项建议。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
- label: "我已在 [Issues 页面](https://github.com/Meloong-Git/PCL/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Meloong-Git/PCL/discussions/1930) 中搜索,确认了这一建议未被提交过。"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一建议未被提交过。"
required: true
- label: "我已查看 [功能投票页面](https://github.com/Hex-Dragon/PCL2/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8/),确认了这一建议未在投票列表中。"
- label: "我已查看 [功能投票页面](https://github.com/Meloong-Git/PCL/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8/),确认了这一建议未在投票列表中。"
required: true
- type: textarea
id: "yml-2"
+9 -6
View File
@@ -1,11 +1,14 @@
blank_issues_enabled: false
contact_links:
- name: 主页预设反馈
url: https://github.com/Meloong-Git/PCL/discussions/categories/自定义主页
about: 提交与预设的主页(设置 → 个性化 → 主页预设)中的具体内容相关的反馈
- name: 帮助文档反馈
url: https://github.com/LTCatt/PCL2Help/issues
about: 提交 PCL2 帮助系统(更多 → 帮助)相关的反馈
- name: 联机模块反馈
url: https://mcer.cn/
about: 向联机模块开发者提交反馈
about: 提交与 PCL 帮助文档(更多 → 帮助)中的具体内容相关的反馈
- name: 提问
url: https://github.com/Hex-Dragon/PCL2/discussions/new?category=%E6%8F%90%E9%97%AE
about: 我不想提交反馈,只是想问一些问题
url: https://github.com/Meloong-Git/PCL/discussions/new?category=%E6%8F%90%E9%97%AE
about: 我想问一些 PCL 相关的问题……
- name: 讨论
url: https://github.com/Meloong-Git/PCL/discussions/new?category=%E8%AE%A8%E8%AE%BA
about: 我想讨论一些 PCL 相关的事情……
+4 -6
View File
@@ -1,6 +1,6 @@
name: "新功能提案"
description: "对已有功能的大幅度修改,或添加一个新内容或选项"
labels: [· 新功能, 新反馈]
labels: [· 新功能, 新提交]
body:
- type: checkboxes
id: "yml-1"
@@ -8,13 +8,11 @@ body:
label: "检查项"
description: "请逐个检查下列项目,并勾选确认。"
options:
- label: "我已点击 `设置 → 启动器 → 检查更新` 确认了启动器已为最新版,且最新版未实现这一功能。[怎样更新?](https://shimo.im/docs/qKPttVvXKqPD8YDC#anchor-oTgb)"
- label: "我已在 [Issues 页面](https://github.com/Meloong-Git/PCL/issues?q=is%3Aissue+) 和 [常见&难检反馈及问题列表](https://github.com/Meloong-Git/PCL/discussions/1930) 中搜索,确认了这一提案未被提交过。"
required: true
- label: "我已在 [Issues 页面](https://github.com/Hex-Dragon/PCL2/issues?q=is%3Aissue+) 中搜索,确认了这一提案未被提交过。"
- label: "我已查看 [功能投票页面](https://github.com/Meloong-Git/PCL/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8/),确认了这一提案未在投票列表中。"
required: true
- label: "我已查看 [功能投票页面](https://github.com/Hex-Dragon/PCL2/discussions/categories/%E5%8A%9F%E8%83%BD%E6%8A%95%E7%A5%A8/),确认了这一提案未在投票列表中。"
required: true
- label: "我已知晓还没做的新功能真的太多了,忙不过来,所以新功能提案几乎不会被处理,也不建议再提交新功能提案 qwq……"
- label: "我知晓还没做的新功能真的太多了,忙不过来,所以新功能提案几乎不会被处理,也不建议再提交新功能提案 qwq……"
required: true
- type: textarea
id: "yml-2"
+65
View File
@@ -0,0 +1,65 @@
name: Build
on:
push:
paths:
- 'Plain Craft Launcher 2/**'
- '.github/workflows/**'
pull_request:
paths:
- 'Plain Craft Launcher 2/**'
- '.github/workflows/**'
workflow_dispatch:
jobs:
build:
name: Build
runs-on: windows-latest
strategy:
matrix:
configuration: [Debug, Release]
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Set Describe
shell: bash
run: |
describe=`git describe --tags --always`
echo "describe=$describe" >> $GITHUB_ENV
- name: Setup MSBuild.exe
uses: microsoft/setup-msbuild@v2
with:
msbuild-architecture: x64
- name: Update Help
run: |
Set-Location ..
git clone https://github.com/LTCatt/PCL2Help.git -b master --single-branch --depth 1
Set-Location PCL2Help
Remove-Item -Path *.* -Recurse -Force
Compress-Archive -Path .\* -DestinationPath .\Help.zip
Copy-Item -Path .\Help.zip -Destination "${{ GITHUB.WORKSPACE }}\Plain Craft Launcher 2\Resources\Help.zip" -Force
Set-Location ..
Remove-Item PCL2Help -Recurse -Force
Set-Location ${{ GITHUB.WORKSPACE }}
- name: Replace
run: |
(gc "Plain Craft Launcher 2\Modules\ModSecret.vb") -replace 'Public OAuthClientId As String = If(Environment.GetEnvironmentVariable("PCL_MS_CLIENT_ID"), "")', 'Public OAuthClientId As String = If(Environment.GetEnvironmentVariable("PCL_MS_CLIENT_ID"), "${{ secrets.CLIENT_ID }}")' | Out-File "Plain Craft Launcher 2\Modules\ModSecret.vb"
(gc "Plain Craft Launcher 2\Modules\ModSecret.vb") -replace 'Public CurseForgeAPIKey As String = If(Environment.GetEnvironmentVariable("PCL_CURSEFORGE_API_KEY"), "")', 'Public CurseForgeAPIKey As String = If(Environment.GetEnvironmentVariable("PCL_CURSEFORGE_API_KEY"), "${{ secrets.CURSEFORGE_API_KEY }}")' | Out-File "Plain Craft Launcher 2\Modules\ModSecret.vb"
(gc "Plain Craft Launcher 2\Modules\Base\ModBase.vb") -replace 'Public Const CommitHash As String = ""', 'Public Const CommitHash As String = "${{ github.sha }}"' | Out-File "Plain Craft Launcher 2\Modules\Base\ModBase.vb"
- name: Build
run: msbuild "Plain Craft Launcher 2\Plain Craft Launcher 2.vbproj" -p:Configuration=${{ matrix.configuration }}
- name: Upload a Build Artifact
uses: actions/upload-artifact@v4
with:
name: ${{ matrix.configuration }} ${{ env.describe }}
path: Plain Craft Launcher 2\obj\${{ matrix.configuration }}\Plain Craft Launcher 2.exe
+1 -20
View File
@@ -1,7 +1,3 @@
# Ignore Root .txt File
/*.txt
# --------------------------------------------------------------------------------------------
## Ignore Visual Studio temporary files, build results, and
@@ -345,19 +341,4 @@ ASALocalRun/
# BeatPulse healthcheck temp database
healthchecksdb
# ------------------------------------------------------------
*.lnk
# 包含主题解锁、加密解密等部分的代码
ModSecret.vb
ModSetup.vb
PageOtherAbout.*
PageOtherTest.*
PageSetupUI.*
# 公开联机代码可能导致安全风险
PageLink/
# 开发者工具
ModDevelop.vb
# 不公开底层函数库,以免抄袭
ModMain.vb
MaskFiles/
+49
View File
@@ -0,0 +1,49 @@
一、声明
本文件仅作为指南,不是法律文件或协议。但开发者在此承诺,在您遵守本指南且善意、合理使用的情况下,不会追究您的责任。
法律上,开发者仍保留所有权利(All Rights Reserved),若情况恶劣,仍可能将诉讼作为最终手段。
二、轻度使用
若您仅参考了本存储库中极小部分的内容,或您在制作与 PCL 的实质功能不存在任何重叠的软件,则为轻度使用。
其常见情形例如:
· 使用或参考存储库中极小部分的内容,来开发启动器或其他软件。
· 虽参考了较大量的内容,但制作的软件与 PCL 的实质功能不存在任何重叠。
若属于轻度使用,您需要:
1、以适当的形式给出署名。
2、不得将您的内容与 PCL 混淆,或暗示您的内容与 PCL 有关。
 例如:您的内容不得使用 Planting Craft Launcher、PCL 手机版 等会造成混淆或暗示这与 PCL 有关的名称。
三、重度使用
若不符合轻度使用的情形,即为重度使用。
其常见情形例如:
· 基于本存储库进行修改。
· 参考存储库中较大量的内容,以制作或重新实现 PCL 的部分实质功能(例如启动或下载 Java 版 Minecraft,下载或管理 Mod 等)。
若属于重度使用,您需要:
1、明确表示您的内容是第三方基于 PCL 独立进行二次创作的产物。
2、您的内容的名称必须以 Plain Craft Launcher (PCL) 开头,并在其后添加足以表现其由第三方修改的后缀。
 允许的示例:PCL 某服务器魔改版、PCL PR Collection、PCL (XX Bug Fix)、PCL XXX修改版。
 禁止的示例:PCL 某服务器特供版(暗示由官方提供)、PCL 3、PCL 手机版、PCL++、PCL Pro(这像是官方的后续作品)。
3、在关于页面的首位给出龙腾猫跃的署名及对应的赞助链接,公开源代码,且继续使用本文件作为指南(可参考 CC BY-SC 协议)。
4、软件若有 Minecraft 启动功能,则应实现与 McLaunchPrecheck 函数一致的 Minecraft 正版购买弹窗与赞助弹窗。
5、软件在 Windows 系统上运行时,不应有与 PCL 的赞助解锁功能类似的功能或表现。
 例如:界面的主要色相必须为蓝色(即使没有修改功能,改为其他色相也和需要赞助解锁的主题功能类似)。
————————————
说人话的备注:
因为没有法律专业人士检查,所以这不敢作为正式的法律协议,如果有专业人士愿意帮忙改一改我也很乐意……
这些规则主要是为了阻止恶意的使用和 “山寨版” 的出现,常规、善意的使用都没啥问题的,放心吧!
如果你只是参考了一小段代码,署个名就行啦,不用担心。
如果对具体细节有疑问,欢迎在 https://github.com/Meloong-Git/PCL/discussions/new?category=%E6%8F%90%E9%97%AE 发帖询问!
多谢大家啦!
+37
View File
@@ -0,0 +1,37 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.2.32616.157
MinimumVisualStudioVersion = 10.0.40219.1
Project("{F184B08F-C81C-45F6-A57F-5ABD9991F28F}") = "Plain Craft Launcher 2", "Plain Craft Launcher 2\Plain Craft Launcher 2.vbproj", "{4499F2D2-18EF-4238-B1F0-7BD547AFF925}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Beta|Any CPU = Beta|Any CPU
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
ReleaseUpdate|Any CPU = ReleaseUpdate|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.Beta|Any CPU.ActiveCfg = BETA|Any CPU
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.Beta|Any CPU.Build.0 = BETA|Any CPU
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.Debug|Any CPU.Build.0 = Debug|Any CPU
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.Release|Any CPU.ActiveCfg = Release|Any CPU
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.Release|Any CPU.Build.0 = Release|Any CPU
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.ReleaseUpdate|Any CPU.ActiveCfg = ReleaseUpdate|Any CPU
{4499F2D2-18EF-4238-B1F0-7BD547AFF925}.ReleaseUpdate|Any CPU.Build.0 = ReleaseUpdate|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {838A572E-025C-4A2B-B682-68732EC0FE76}
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
GlobalSection(Performance) = preSolution
HasPerformanceSessions = true
EndGlobalSection
EndGlobal
+33 -27
View File
@@ -1,33 +1,39 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true"/>
</settings>
</system.net>
<system.net>
<settings>
<httpWebRequest useUnsafeHeaderParsing="true"/>
</settings>
</system.net>
<startup>
<supportedRuntime version="v4.0" sku=".NETFramework,Version=v4.6.2"/>
</startup>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false" />
<generatePublisherEvidence enabled="false"/>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
<runtime>
<AppContextSwitchOverrides value="Switch.System.Net.DontEnableSchUseStrongCrypto=false" />
<AppContextSwitchOverrides value="Switch.System.Windows.DoNotScaleForDpiChanges=false"/> <!-- #5337 -->
<AppContextSwitchOverrides value="Switch.System.IO.UseLegacyPathHandling=false;Switch.System.IO.BlockLongPaths=false" /> <!-- 长路径支持 -->
<generatePublisherEvidence enabled="false"/>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="System.Numerics.Vectors" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.1.4.0" newVersion="4.1.4.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Runtime.CompilerServices.Unsafe" publicKeyToken="b03f5f7f11d50a3a" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.6.0" newVersion="4.0.6.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.Buffers" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="System.ValueTuple" publicKeyToken="cc7b13ffcd2ddd51" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-4.0.3.0" newVersion="4.0.3.0"/>
</dependentAssembly>
<dependentAssembly>
<assemblyIdentity name="Newtonsoft.Json" publicKeyToken="30ad4fe6b2a6aeed" culture="neutral"/>
<bindingRedirect oldVersion="0.0.0.0-6.0.0.0" newVersion="13.0.0.0"/>
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>
+46 -35
View File
@@ -8,11 +8,12 @@
<Application.Resources>
<ResourceDictionary>
<!-- 本地化 -->
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="pack://application:,,,/Resources/Language/zh_CN.xaml" />
<ResourceDictionary Source="pack://application:,,,/Resources/Language/zh_CN.xaml" />
</ResourceDictionary.MergedDictionaries>
<!-- Converter -->
<local:AdditionConverter x:Key="AdditionConverter"/>
<local:MultiplicationConverter x:Key="MultiplicationConverter"/>
<local:InverseBooleanToVisibilityConverter x:Key="InverseBooleanToVisibilityConverter"/>
<local:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter"/>
<!-- 颜色表 -->
<SolidColorBrush x:Key="ColorBrush1">#343d4a</SolidColorBrush>
@@ -23,7 +24,8 @@
<SolidColorBrush x:Key="ColorBrush6">#d5e6fd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrush7">#e0eafd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrush8">#eaf2fe</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrush9">#80e0eafd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushBg0">#96c0f9</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushBg1">#bee0eafd</SolidColorBrush>
<Color x:Key="ColorObject1">#343d4a</Color>
<Color x:Key="ColorObject2">#0b5bcb</Color>
<Color x:Key="ColorObject3">#1370f3</Color>
@@ -32,7 +34,8 @@
<Color x:Key="ColorObject6">#d5e6fd</Color>
<Color x:Key="ColorObject7">#e0eafd</Color>
<Color x:Key="ColorObject8">#eaf2fe</Color>
<Color x:Key="ColorObject9">#40eaf2fe</Color>
<Color x:Key="ColorObjectBg0">#96c0f9</Color>
<Color x:Key="ColorObjectBg1">#bee0eafd</Color>
<SolidColorBrush x:Key="ColorBrushGray1">#404040</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushGray2">#737373</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushGray3">#8c8c8c</SolidColorBrush>
@@ -52,10 +55,12 @@
<SolidColorBrush x:Key="ColorBrushRedBack">#80fbdddd</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushRedLight">#ff4c4c</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushRedDark">#ce2111</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushHalfWhite" Color="#44ffffff" />
<SolidColorBrush x:Key="ColorBrushHalfWhite" Color="#55ffffff" />
<SolidColorBrush x:Key="ColorBrushSemiWhite" Color="#bbffffff" />
<SolidColorBrush x:Key="ColorBrushWhite" Color="#ffffff" />
<SolidColorBrush x:Key="ColorBrushTransparent" Color="Transparent" />
<SolidColorBrush x:Key="ColorBrushSemiTransparent">#01eaf2fe</SolidColorBrush>
<SolidColorBrush x:Key="ColorBrushBackgroundTransparentSidebar" Color="#D2FFFFFF" />
<SolidColorBrush x:Key="ColorBrushBackgroundTransparentSidebar" Color="#F1FFFFFF" />
<!-- Window -->
<Style TargetType="{x:Type Window}" x:Key="MyWindow">
@@ -63,7 +68,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type Window}">
<ContentPresenter/>
<ContentPresenter />
</ControlTemplate>
</Setter.Value>
</Setter>
@@ -129,9 +134,9 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1.5" CornerRadius="3" MaxWidth="500" Background="White" Margin="0,0,4,4" SnapsToDevicePixels="True">
<Border Loaded="TooltipLoaded" Unloaded="TooltipUnloaded" BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1.5" CornerRadius="4" MaxWidth="500" Background="#E5FFFFFF" Margin="0,0,4,4" SnapsToDevicePixels="True">
<Border.Effect>
<DropShadowEffect Opacity="0.4" BlurRadius="4" ShadowDepth="2" />
<DropShadowEffect Opacity="0.3" BlurRadius="4" ShadowDepth="2" Color="{DynamicResource ColorObject1}" />
</Border.Effect>
<TextBlock Text="{TemplateBinding ContentControl.Content}" TextWrapping="Wrap" Foreground="{DynamicResource ColorBrush1}" Margin="7,5" FontSize="12"/>
</Border>
@@ -143,7 +148,7 @@
<Setter Property="Template">
<Setter.Value>
<ControlTemplate>
<Border BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1" CornerRadius="3" Background="White" Margin="0,0,4,4" SnapsToDevicePixels="True">
<Border Loaded="TooltipLoaded" Unloaded="TooltipUnloaded" BorderBrush="{DynamicResource ColorBrush1}" BorderThickness="1" CornerRadius="3" Background="White" Margin="0,0,4,4" SnapsToDevicePixels="True">
<TextBlock Text="{TemplateBinding ContentControl.Content}" TextWrapping="Wrap" Foreground="{DynamicResource ColorBrush1}" Margin="7,5" FontSize="12"/>
</Border>
</ControlTemplate>
@@ -198,7 +203,7 @@
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:MyScrollViewer">
<Style TargetType="local:MyScrollViewer" x:Name="StyleMyScrollViewer">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="CanContentScroll" Value="False" />
<Setter Property="PanningMode" Value="VerticalOnly" />
@@ -214,6 +219,7 @@
</Setter.Value>
</Setter>
</Style>
<Style TargetType="local:PageComp" BasedOn="{StaticResource {x:Type local:MyScrollViewer}}" />
<Style TargetType="ScrollViewer" x:Key="ScrollViewerFullMargin">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="CanContentScroll" Value="False" />
@@ -273,25 +279,25 @@
<Setter Property="ScrollViewer.PanningMode" Value="VerticalFirst"/>
<Setter Property="Stylus.IsFlicksEnabled" Value="False"/>
<Setter Property="UndoLimit" Value="15" />
<Setter Property="MaxLength" Value="10000" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush1}" />
<Setter Property="MaxLength" Value="1000" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrushBg0}" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<ControlTemplate TargetType="local:MyTextBox">
<Grid SnapsToDevicePixels="True" ToolTip="{TemplateBinding ToolTip}">
<Grid.RowDefinitions>
<RowDefinition MinHeight="28" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Margin="{TemplateBinding Padding}" IsHitTestVisible="False" VerticalAlignment="Center" BorderThickness="0">
<TextBlock x:Name="labHint" Foreground="{StaticResource ColorBrushGray3}" Margin="7,0,0,0" Padding="{TemplateBinding BorderThickness}" FontSize="{TemplateBinding FontSize}" FontFamily="Resources/#PCL English, Microsoft YaHei UI" />
</Border>
<Border x:Name="border" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" CornerRadius="3">
<Border x:Name="border" BorderThickness="{TemplateBinding BorderThickness}" BorderBrush="{TemplateBinding BorderBrush}" Background="{TemplateBinding Background}" CornerRadius="{TemplateBinding CornerRadius}">
<ScrollViewer x:Name="PART_ContentHost" Style="{StaticResource ScrollViewerNoMargin}" RenderOptions.ClearTypeHint="Enabled" BorderThickness="0"
Margin="5,0,0,0" Cursor="IBeam" />
<!-- 由于未知原因,TextView 会有 2,0 的 Margin -->
</Border>
<TextBlock Grid.Row="1" x:Name="labWrong" Height="0" Foreground="{TemplateBinding BorderBrush}" Padding="0,4,0,0" />
<Border Margin="{TemplateBinding Padding}" IsHitTestVisible="False" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" VerticalAlignment="{TemplateBinding VerticalContentAlignment}" BorderThickness="0">
<TextBlock x:Name="labHint" Foreground="{StaticResource ColorBrushGray4}" Margin="7,0,0,0" Padding="{TemplateBinding BorderThickness}" FontSize="{TemplateBinding FontSize}" FontFamily="Resources/#PCL English, Microsoft YaHei UI" />
</Border>
<TextBlock Grid.Row="1" x:Name="labWrong" Height="0" Foreground="{TemplateBinding BorderBrush}" Padding="0,4,0,0" Margin="0,0,0,-3" />
</Grid>
</ControlTemplate>
</Setter.Value>
@@ -303,7 +309,7 @@
<Setter Property="SelectionBrush" Value="{DynamicResource ColorBrush3}" />
<Setter Property="Foreground" Value="{DynamicResource ColorBrush1}" />
<Setter Property="Background" Value="{StaticResource ColorBrushHalfWhite}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush1}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrushBg0}" />
<Setter Property="KeyboardNavigation.TabNavigation" Value="None"/>
<Setter Property="HorizontalContentAlignment" Value="Left"/>
<Setter Property="FocusVisualStyle" Value="{x:Null}"/>
@@ -317,19 +323,20 @@
<ControlTemplate.Triggers>
<Trigger Property="IsEnabled" Value="False">
<Trigger.Setters>
<Setter Property="Foreground" Value="{StaticResource ColorBrushGray4}" />
<Setter Property="BorderBrush" Value="{StaticResource ColorBrushGray4}" />
<Setter Property="BorderBrush" Value="{StaticResource ColorBrushGray5}" />
<Setter Property="Background" Value="{StaticResource ColorBrushGray6}" />
</Trigger.Setters>
</Trigger>
<Trigger Property="IsMouseOver" Value="True">
<Trigger.Setters>
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush3}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush4}" />
<Setter Property="Background" Value="{DynamicResource ColorBrush7}" />
</Trigger.Setters>
</Trigger>
<Trigger Property="IsFocused" Value="True">
<Trigger.Setters>
<Setter Property="Background" Value="{DynamicResource ColorBrush9}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush4}" />
<Setter Property="BorderBrush" Value="{DynamicResource ColorBrush3}" />
<Setter Property="Background" Value="{DynamicResource ColorBrush7}" />
</Trigger.Setters>
</Trigger>
</ControlTemplate.Triggers>
@@ -340,7 +347,7 @@
<!-- ComboBox -->
<DataTemplate x:Key="ComboBoxItemTemplateWithDelete">
<local:MyListItem Title="{Binding}" FontSize="13" PaddingRight="40" MaxHeight="26" IsScaleAnimationEnabled="False" Margin="-1,0,0,0">
<local:MyListItem Title="{Binding}" FontSize="13" MaxHeight="26" IsScaleAnimationEnabled="False" Margin="-3,0,0,0">
<local:MyListItem.Buttons>
<x:Array Type="local:MyIconButton">
<local:MyIconButton Grid.Column="1" Height="20" Width="20" VerticalAlignment="Center" Tag="{Binding}" Click="MyIconButton_Click" Logo="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z" />
@@ -348,16 +355,12 @@
</local:MyListItem.Buttons>
</local:MyListItem>
</DataTemplate>
<!--<DataTemplate x:Key="ComboBoxItemTemplateNormal">
<local:MyListItem Title="{Binding}" FontSize="13" PaddingRight="40" Height="26" Margin="-1,0,0,0" />
</DataTemplate>-->
<Style TargetType="local:MyComboBox">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="SnapsToDevicePixels" Value="True" />
<Setter Property="Foreground" Value="{DynamicResource ColorBrush1}" />
<Setter Property="Foreground" Value="{DynamicResource ColorBrushBg0}" />
<Setter Property="Background" Value="{StaticResource ColorBrushHalfWhite}" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<!--<Setter Property="ItemTemplate" Value="{StaticResource ComboBoxItemTemplateNormal}"/>-->
<Setter Property="FontSize" Value="13" />
<Setter Property="MaxDropDownHeight" Value="160" />
<Setter Property="Template">
@@ -366,7 +369,10 @@
<Grid>
<Border x:Name="border" Background="{TemplateBinding Background}" CornerRadius="3" BorderThickness="1" BorderBrush="{TemplateBinding Foreground}" />
<ToggleButton Margin="0,0,1.5,0" Foreground="{TemplateBinding Foreground}" IsTabStop="False" SnapsToDevicePixels="False" Focusable="False" IsChecked="{Binding IsDropDownOpen,Mode=TwoWay,RelativeSource={RelativeSource TemplatedParent}}" ClickMode="Press" />
<ContentPresenter Margin="8.5,0,21.5,0" IsHitTestVisible="False" Content="{TemplateBinding SelectionBoxItem}" ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}" ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" VerticalAlignment="Center" />
<ContentPresenter x:Name="PART_Content" Margin="8.5,0,21.5,0" IsHitTestVisible="False" VerticalAlignment="Center"
Content="{TemplateBinding SelectionBoxItem}"
ContentTemplate="{TemplateBinding SelectionBoxItemTemplate}"
ContentTemplateSelector="{TemplateBinding ItemTemplateSelector}" />
<Popup x:Name="PART_Popup" SnapsToDevicePixels="True" VerticalOffset="-1.5" AllowsTransparency="True" IsOpen="{Binding IsDropDownOpen, Mode=TwoWay, RelativeSource={RelativeSource TemplatedParent}}" Placement="Bottom" PopupAnimation="Fade">
<Grid x:Name="PanPopup">
<Border Background="White" CornerRadius="3" />
@@ -462,6 +468,11 @@
</Style>
<Style TargetType="ComboBoxItem" x:Key="MyComboBoxItem">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="ToolTipService.Placement" Value="Relative" />
<Setter Property="ToolTipService.VerticalOffset" Value="-2" />
<Setter Property="ToolTipService.HorizontalOffset" Value="200" />
<Setter Property="ToolTipService.InitialShowDelay" Value="150" />
<Setter Property="ToolTipService.BetweenShowDelay" Value="150" />
<Setter Property="FocusVisualStyle" Value="{x:Null}" />
<Setter Property="Background" Value="{StaticResource ColorBrushTransparent}" />
<Setter Property="Template">
+162 -136
View File
@@ -1,5 +1,4 @@
Imports System.Net
Imports System.Reflection
Imports System.Reflection
Imports System.Windows.Threading
Public Class Application
@@ -12,34 +11,51 @@ Public Class Application
Try
ModDevelop.Start()
Catch ex As Exception
Log(ex, "开发者模式测试出错", LogLevel.Feedback)
Log(ex, "开发者模式测试出错", LogLevel.Msgbox)
End Try
End Sub
#End If
'开始
Private Sub Application_Startup(sender As Object, e As StartupEventArgs) Handles Me.Startup
ApplicationStartTick = GetTimeTick()
SecretOnApplicationStart()
Try
SecretOnApplicationStart()
'检查参数调用
If e.Args.Length > 0 Then
If e.Args(0) = "--update" Then
'自动更新
UpdateReplace(e.Args(1), e.Args(2).Trim(""""), e.Args(3).Trim(""""), e.Args(4))
Environment.[Exit](Result.Cancel)
Exit Sub
ElseIf e.Args(0) = "--link" Then
'稍作等待后切换到联机页面
Thread.Sleep(1000)
FormMain.IsLinkRestart = True
Environment.Exit(ProcessReturnValues.TaskDone)
ElseIf e.Args(0) = "--gpu" Then
'调整显卡设置
Try
SetGPUPreference(e.Args(1).Trim(""""))
Environment.Exit(ProcessReturnValues.TaskDone)
Catch ex As Exception
Environment.Exit(ProcessReturnValues.Fail)
End Try
ElseIf e.Args(0).StartsWithF("--memory") Then
'内存优化
Dim Ram = My.Computer.Info.AvailablePhysicalMemory
Try
PageOtherTest.MemoryOptimizeInternal(False)
Catch ex As Exception
MsgBox(ex.Message, MsgBoxStyle.Critical, "内存优化失败")
Environment.Exit(-1)
End Try
If My.Computer.Info.AvailablePhysicalMemory < Ram Then '避免 ULong 相减出现负数
Environment.Exit(0)
Else
Environment.Exit((My.Computer.Info.AvailablePhysicalMemory - Ram) / 1024) '返回清理的内存量(K)
End If
#If DEBUG Then
ElseIf e.Args(0) = "--make" Then
'制作更新包
UpdateMake(e.Args(1))
Environment.[Exit](Result.Cancel)
Exit Sub
ElseIf e.Args(0) = "--edit1" Then
ExeEdit(e.Args(1), True)
Environment.Exit(ProcessReturnValues.TaskDone)
ElseIf e.Args(0) = "--edit2" Then
ExeEdit(e.Args(1), False)
Environment.Exit(ProcessReturnValues.TaskDone)
#End If
End If
End If
@@ -48,28 +64,48 @@ Public Class Application
Directory.CreateDirectory(Path & "PCL\Musics")
Try
Directory.CreateDirectory(PathTemp)
If Not CheckPermission(PathTemp) Then Throw New Exception("PCL2 没有对 " & PathTemp & " 的访问权限")
If Not CheckPermission(PathTemp) Then Throw New Exception("PCL 没有对 " & PathTemp & " 的访问权限")
Catch ex As Exception
MyMsgBox("手动设置的缓存文件夹不可用,PCL2 将使用默认缓存文件夹。" & vbCrLf & "错误原因:" & GetString(ex, False), "缓存文件夹不可用")
Setup.Set("SystemSystemCache", "")
PathTemp = IO.Path.GetTempPath() & "PCL\"
If PathTemp = IO.Path.GetTempPath() & "PCL\" Then
MyMsgBox("PCL 无法访问缓存文件夹,可能导致程序出错或无法正常使用!" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
Else
MyMsgBox("手动设置的缓存文件夹不可用,PCL 将使用默认缓存文件夹。" & vbCrLf & "错误原因:" & GetExceptionDetail(ex), "缓存文件夹不可用")
Setup.Set("SystemSystemCache", "")
PathTemp = IO.Path.GetTempPath() & "PCL\"
End If
End Try
Directory.CreateDirectory(PathTemp & "Cache")
Directory.CreateDirectory(PathTemp & "Download")
Directory.CreateDirectory(PathAppdata)
'检测单例
#If Not DEBUG Then
Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher 2 ")
Dim ShouldWaitForExit As Boolean = e.Args.Length > 0 AndAlso e.Args(0) = "--wait" '要求等待已有的 PCL 退出
Dim WaitRetryCount As Integer = 0
WaitRetry:
Dim WindowHwnd As IntPtr = FindWindow(Nothing, "Plain Craft Launcher ")
If WindowHwnd = IntPtr.Zero Then FindWindow(Nothing, "Plain Craft Launcher 2 ")
If WindowHwnd <> IntPtr.Zero Then
'将已有的 PCL2 窗口拖出来
If ShouldWaitForExit AndAlso WaitRetryCount < 20 Then '至多等待 10 秒
WaitRetryCount += 1
Thread.Sleep(500)
GoTo WaitRetry
End If
'将已有的 PCL 窗口拖出来
ShowWindowToTop(WindowHwnd)
'播放提示音并退出
Beep()
Environment.[Exit](Result.Cancel)
Exit Sub
Environment.[Exit](ProcessReturnValues.Cancel)
End If
#End If
'设置 ToolTipService 默认值
ToolTipService.InitialShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(300))
ToolTipService.BetweenShowDelayProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(400))
ToolTipService.ShowDurationProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(9999999))
ToolTipService.PlacementProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(Primitives.PlacementMode.Bottom))
ToolTipService.HorizontalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(8.0))
ToolTipService.VerticalOffsetProperty.OverrideMetadata(GetType(DependencyObject), New FrameworkPropertyMetadata(4.0))
'设置初始窗口
If Setup.Get("UiLauncherLogo") AndAlso Not FormMain.IsLinkRestart Then
If Setup.Get("UiLauncherLogo") Then
FrmStart = New SplashScreen("Images\icon.ico")
FrmStart.Show(False, True)
End If
@@ -78,24 +114,32 @@ Public Class Application
'日志初始化
LogStart()
'添加日志
Log("[Start] 程序版本:" & VersionDisplayName & "(" & VersionCode & ")")
Log("[Start] 识别码:" & UniqueAddress & If(ThemeCheckOne(9), ",已解锁反馈主题", ""))
Log("[Start] 程序路径:" & PathWithName)
'检测压缩包运行
Log($"[Start] 程序版本:{VersionDisplayName} ({VersionCode}{If(CommitHash = "", "", $",#{CommitHash}")})")
#If RELEASE Then
Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",正式版", "")}")
#Else
Log($"[Start] 识别码:{UniqueAddress}{If(ThemeCheckOne(9), ",已解锁反馈主题", "")}")
#End If
Log($"[Start] 程序路径:{PathWithName}")
Log($"[Start] 系统编码:{Encoding.Default.HeaderName} ({Encoding.Default.CodePage}, GBK={IsGBKEncoding})")
Log($"[Start] 管理员权限:{IsAdmin()}")
'检测异常环境
If Path.Contains(IO.Path.GetTempPath()) OrElse Path.Contains("AppData\Local\Temp\") Then
MyMsgBox("PCL2 正在临时文件夹运行,设置、游戏存档等很可能无法保存,且部分功能会无法使用或出错。" & vbCrLf & "请将 PCL2 从压缩文件中解压,或是更换文件夹后再继续使用!", "环境警告", "我知道了", IsWarn:=True)
MyMsgBox("请将 PCL 从压缩包中解压之后再使用!" & vbCrLf & "在当前环境下运行可能会导致丢失游戏存档或设置,部分功能也可能无法使用!", "环境警告", "我知道了", IsWarn:=True)
End If
If Is32BitSystem Then
MyMsgBox("PCL 和新版 Minecraft 均不再支持 32 位系统,部分功能将无法使用。" & vbCrLf & "非常建议重装为 64 位系统后再进行游戏!", "环境警告", "我知道了", IsWarn:=True)
End If
'设置初始化
Setup.Load("SystemDebugMode")
Setup.Load("SystemDebugAnim")
Setup.Load("ToolDownloadThread")
Setup.Load("ToolDownloadCert")
Setup.Load("ToolDownloadSpeed")
'网络配置初始化
ServicePointManager.Expect100Continue = True
ServicePointManager.SecurityProtocol = SecurityProtocolType.Ssl3 Or SecurityProtocolType.Tls Or SecurityProtocolType.Tls11 Or SecurityProtocolType.Tls12
ServicePointManager.DefaultConnectionLimit = 1024
ServicePointManager.ServerCertificateValidationCallback = New Security.RemoteCertificateValidationCallback(Function() As Boolean
Return True
End Function)
'计时
Log("[Start] 第一阶段加载用时:" & GetTimeTick() - ApplicationStartTick & " ms")
ApplicationStartTick = GetTimeTick()
@@ -105,8 +149,13 @@ Public Class Application
#End If
AniControlEnabled += 1
Catch ex As Exception
MsgBox(GetString(ex, False, True), MsgBoxStyle.Critical, "PCL2 初始化错误")
FormMain.EndProgramForce(Result.Exception)
Dim FilePath As String = Nothing
Try
FilePath = PathWithName
Catch
End Try
MsgBox(GetExceptionDetail(ex, True) & vbCrLf & "PCL 所在路径:" & If(String.IsNullOrEmpty(FilePath), "获取失败", FilePath), MsgBoxStyle.Critical, "PCL 初始化错误")
FormMain.EndProgramForce(ProcessReturnValues.Exception)
End Try
End Sub
@@ -116,123 +165,100 @@ Public Class Application
End Sub
'异常
Private IsCritErrored As Boolean = False
Private Sub Application_DispatcherUnhandledException(sender As Object, e As DispatcherUnhandledExceptionEventArgs) Handles Me.DispatcherUnhandledException
On Error Resume Next
e.Handled = True
If IsProgramEnded Then Exit Sub
If IsCritErrored Then
'在汇报错误后继续引发错误,知道这次压不住了
FormMain.EndProgramForce(Result.Exception)
Exit Sub
End If
IsCritErrored = True
Dim ExceptionString As String = GetString(e.Exception, False, True)
If ExceptionString.Contains("System.Windows.Threading.Dispatcher.Invoke") OrElse
ExceptionString.Contains("MS.Internal.AppModel.ITaskbarList.HrInit") OrElse
ExceptionString.Contains(".Net Framework") OrElse ' “自动错误判断” 的结果分析
ExceptionString.Contains("未能加载文件或程序集") Then
If IsProgramEnded Then Return
FeedbackInfo()
Dim Detail As String = GetExceptionDetail(e.Exception, True)
If Detail.Contains("System.Windows.Threading.Dispatcher.Invoke") OrElse Detail.Contains("MS.Internal.AppModel.ITaskbarList.HrInit") OrElse Detail.Contains("未能加载文件或程序集") OrElse
Detail.Contains(".NET Framework") Then ' “自动错误判断” 的结果分析
OpenWebsite("https://dotnet.microsoft.com/zh-cn/download/dotnet-framework/thank-you/net462-offline-installer")
MsgBox("你的 .Net Framework 版本过低或损坏,请在打开的网页中重新下载并安装 .NET Framework 4.6.2 后重试!", MsgBoxStyle.Information, "运行环境错误")
FormMain.EndProgramForce(Result.Cancel)
Log(e.Exception, "你的 .NET Framework 版本过低或损坏,请下载并重新安装 .NET Framework 4.6.2!" & vbCrLf & "若无法安装,可在卸载高版本的 .NET Framework 后再试。", LogLevel.Critical, "运行环境错误")
Else
FeedbackInfo()
Log(e.Exception, "程序出现未知错误", LogLevel.Assert, "锟斤拷烫烫烫")
Log(e.Exception, "程序出现未知错误", LogLevel.Critical, "锟斤拷烫烫烫")
End If
End Sub
'动态 DLL 调用
Private Shared AssemblyStun As Assembly
Private Shared AssemblyNAudio As Assembly
Private Shared AssemblyJson As Assembly
Private Shared AssemblyDialog As Assembly
Private Shared ReadOnly AssemblyStunLock As New Object
Private Shared ReadOnly AssemblyNAudioLock As New Object
Private Shared ReadOnly AssemblyJsonLock As New Object
Private Shared ReadOnly AssemblyDialogLock As New Object
Public Shared Function AssemblyResolve(sender As Object, args As ResolveEventArgs) As Assembly
If args.Name.StartsWith("NAudio") Then
SyncLock AssemblyNAudioLock
If AssemblyNAudio Is Nothing Then
Log("[Start] 加载 DLL:NAudio")
AssemblyNAudio = Assembly.Load(GetResources("NAudio"))
Private Declare Function SetDllDirectory Lib "kernel32" Alias "SetDllDirectoryA" (lpPathName As String) As Boolean
Public Shared Function AssemblyResolve(sender As Object, Args As ResolveEventArgs) As Assembly
'缓存
Static Prefixes As String() = {"NAudio", "Newtonsoft.Json", "Ookii.Dialogs.Wpf", "Imazen.WebP", "CacheCow.Common", "CacheCow.Client.FileStore", "CacheCow.Client", "System.Net.Http.Formatting"}
Static Locks As New Dictionary(Of String, Object)(StringComparer.Ordinal)
Static LoadedAssembly As New Dictionary(Of String, Assembly)(StringComparer.Ordinal)
'查找对应的 DLL
Dim Prefix As String = Prefixes.FirstOrDefault(Function(p) Args.Name.StartsWithF(p))
If Prefix Is Nothing Then Return Nothing
'加载 DLL
If Not Locks.ContainsKey(Prefix) Then Locks(Prefix) = New Object()
SyncLock Locks(Prefix)
If Not LoadedAssembly.ContainsKey(Prefix) Then
Log($"[Start] 加载 DLL:{Prefix}")
LoadedAssembly(Prefix) = Assembly.Load(GetResources(Prefix))
'WebP 特判
If Prefix = "Imazen.WebP" Then
SetDllDirectory(PathPure.TrimEnd("\"c))
WriteFile(PathPure & "libwebp.dll", GetResources("libwebp64"))
End If
Return AssemblyNAudio
End SyncLock
ElseIf args.Name.StartsWith("Newtonsoft.Json") Then
SyncLock AssemblyJsonLock
If AssemblyJson Is Nothing Then
Log("[Start] 加载 DLL:Json")
AssemblyJson = Assembly.Load(GetResources("Json"))
End If
Return AssemblyJson
End SyncLock
ElseIf args.Name.StartsWith("Ookii.Dialogs.Wpf") Then
SyncLock AssemblyDialogLock
If AssemblyDialog Is Nothing Then
Log("[Start] 加载 DLL:Dialogs")
AssemblyDialog = Assembly.Load(GetResources("Dialogs"))
End If
Return AssemblyDialog
End SyncLock
ElseIf args.Name.StartsWith("STUN") Then
SyncLock AssemblyStunLock
If AssemblyStun Is Nothing Then
Log("[Start] 加载 DLL:STUN")
AssemblyStun = Assembly.Load(GetResources("STUN"))
End If
Return AssemblyStun
End SyncLock
Else
Return Nothing
End If
End If
Return LoadedAssembly(Prefix)
End SyncLock
End Function
'切换窗口
'控件模板事件
Private Sub MyIconButton_Click(sender As Object, e As EventArgs)
If Setup.Get("LoginType") = McLoginType.Legacy Then
'离线
Dim Names As New List(Of String)
Names.AddRange(Setup.Get("LoginLegacyName").ToString.Split("¨"))
Names.Remove(sender.Tag)
Setup.Set("LoginLegacyName", Join(Names, "¨"))
FrmLoginLegacy.ComboName.ItemsSource = Names
FrmLoginLegacy.ComboName.Text = If(Names.Count > 0, Names(0), "")
Else
'非离线
Dim Token As String = GetStringFromEnum(Setup.Get("LoginType"))
Dim Dict As New Dictionary(Of String, String)
Dim Names As New List(Of String)
Dim Passs As New List(Of String)
If Not Setup.Get("Login" & Token & "Email") = "" Then Names.AddRange(Setup.Get("Login" & Token & "Email").ToString.Split("¨"))
If Not Setup.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Setup.Get("Login" & Token & "Pass").ToString.Split("¨"))
For i = 0 To Names.Count - 1
Dict.Add(Names(i), Passs(i))
Next
Dict.Remove(sender.Tag)
Setup.Set("Login" & Token & "Email", Join(Dict.Keys.ToArray, "¨"))
Setup.Set("Login" & Token & "Pass", Join(Dict.Values.ToArray, "¨"))
Select Case Token
Case "Mojang"
FrmLoginMojang.ComboName.ItemsSource = Dict.Keys
FrmLoginMojang.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
FrmLoginMojang.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
Case "Nide"
FrmLoginNide.ComboName.ItemsSource = Dict.Keys
FrmLoginNide.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
FrmLoginNide.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
Case "Auth"
FrmLoginAuth.ComboName.ItemsSource = Dict.Keys
FrmLoginAuth.ComboName.Text = If(Dict.Keys.Count > 0, Dict.Keys(0), "")
FrmLoginAuth.TextPass.Password = If(Dict.Values.Count > 0, Dict.Values(0), "")
Case Else
DebugAssert(True)
Exit Sub
End Select
End If
Select Case Setup.Get("LoginType")
Case McLoginType.Ms
'微软
Dim MsJson As JObject = GetJson(Setup.Get("LoginMsJson"))
MsJson.Remove(sender.Tag)
Setup.Set("LoginMsJson", MsJson.ToString(Newtonsoft.Json.Formatting.None))
If FrmLoginMs.ComboAccounts.SelectedItem Is sender.Parent Then FrmLoginMs.ComboAccounts.SelectedIndex = 0
FrmLoginMs.ComboAccounts.Items.Remove(sender.Parent)
Case McLoginType.Legacy
'离线
Dim Names As New List(Of String)
Names.AddRange(Setup.Get("LoginLegacyName").ToString.Split("¨"))
Names.Remove(sender.Tag)
Setup.Set("LoginLegacyName", Join(Names, "¨"))
FrmLoginLegacy.ComboName.ItemsSource = Names
FrmLoginLegacy.ComboName.Text = If(Names.Any, Names(0), "")
Case Else
'第三方
Dim Token As String = GetStringFromEnum(Setup.Get("LoginType"))
Dim Dict As New Dictionary(Of String, String)
Dim Names As New List(Of String)
Dim Passs As New List(Of String)
If Not Setup.Get("Login" & Token & "Email") = "" Then Names.AddRange(Setup.Get("Login" & Token & "Email").ToString.Split("¨"))
If Not Setup.Get("Login" & Token & "Pass") = "" Then Passs.AddRange(Setup.Get("Login" & Token & "Pass").ToString.Split("¨"))
For i = 0 To Names.Count - 1
Dict.Add(Names(i), Passs(i))
Next
Dict.Remove(sender.Tag)
Setup.Set("Login" & Token & "Email", Join(Dict.Keys, "¨"))
Setup.Set("Login" & Token & "Pass", Join(Dict.Values, "¨"))
Select Case Token
Case "Nide"
FrmLoginNide.ComboName.ItemsSource = Dict.Keys
FrmLoginNide.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
FrmLoginNide.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
Case "Auth"
FrmLoginAuth.ComboName.ItemsSource = Dict.Keys
FrmLoginAuth.ComboName.Text = If(Dict.Keys.Any, Dict.Keys(0), "")
FrmLoginAuth.TextPass.Password = If(Dict.Values.Any, Dict.Values(0), "")
End Select
End Select
End Sub
Public Shared ShowingTooltips As New List(Of Border)
Private Sub TooltipLoaded(sender As Border, e As EventArgs)
ShowingTooltips.Add(sender)
End Sub
Private Sub TooltipUnloaded(sender As Border, e As RoutedEventArgs)
ShowingTooltips.Remove(sender)
End Sub
End Class
@@ -7,7 +7,7 @@
<Border.RenderTransform>
<ScaleTransform />
</Border.RenderTransform>
<TextBlock TextOptions.TextFormattingMode="Display" SnapsToDevicePixels="True" TextTrimming="None" Text="Button" HorizontalAlignment="Center" x:Name="LabText" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Foreground="{Binding Parent.BorderBrush, RelativeSource={RelativeSource Self}}" FontSize="13" IsHitTestVisible="False">
<TextBlock TextOptions.TextFormattingMode="Display" SnapsToDevicePixels="True" TextTrimming="None" HorizontalAlignment="Center" x:Name="LabText" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5" Foreground="{Binding Parent.BorderBrush, RelativeSource={RelativeSource Self}}" FontSize="13" IsHitTestVisible="False">
<TextBlock.RenderTransform>
<ScaleTransform />
</TextBlock.RenderTransform>
@@ -1,22 +1,30 @@
Public Class MyButton
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyButton
'声明
Public Event Click(sender As Object, e As EventArgs) '自定义事件
Public Event Click(sender As Object, e As MouseButtonEventArgs) '自定义事件
'自定义属性
Public Uuid As Integer = GetUuid()
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabText.Inlines
End Get
End Property
Public Property Text As String
Get
Return LabText.Text
Return GetValue(TextProperty)
End Get
Set(value As String)
LabText.Text = value
SetValue(TextProperty, value)
End Set
End Property '显示文本
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyButton), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If Not IsNothing(sender) Then CType(sender, MyButton).LabText.Text = e.NewValue
End Sub)))
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If sender IsNot Nothing Then CType(sender, MyButton).LabText.Text = e.NewValue
End Sub)))
Public Property TextPadding As Thickness
Get
Return LabText.Padding
@@ -134,23 +142,21 @@
'实现自定义事件
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If IsMouseDown Then
Log("[Control] 按下按钮:" & Text)
RaiseEvent Click(sender, e)
If Not String.IsNullOrEmpty(Tag) Then
If Tag.ToString.StartsWith("链接-") OrElse Tag.ToString.StartsWith("启动-") Then
Hint("主页自定义按钮语法已更新,且不再兼容老版本语法,请查看新的自定义示例!")
End If
If Not IsMouseDown Then Return
Log("[Control] 按下按钮:" & Text)
RaiseEvent Click(sender, e)
If Not String.IsNullOrEmpty(Tag) Then
If Tag.ToString.StartsWithF("链接-") OrElse Tag.ToString.StartsWithF("启动-") Then
Hint("主页自定义按钮语法已更新,且不再兼容老版本语法,请查看新的自定义示例!")
End If
ModEvent.TryStartEvent(EventType, EventData)
End If
ModEvent.TryStartEvent(EventType, EventData)
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
@@ -159,8 +165,7 @@
Get
Return GetValue(EventDataProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
@@ -177,10 +182,10 @@
}, "MyButton Scale " & Uuid)
End Sub
Private Sub Button_MouseEnter() Handles Me.MouseEnter
AniStart(AaColor(PanFore, BackgroundProperty, If(_ColorType = ColorState.Red, "ColorBrushRedBack", "ColorBrush9"), AnimationColorIn), "MyButton Background " & Uuid)
AniStart(AaColor(PanFore, BackgroundProperty, If(_ColorType = ColorState.Red, "ColorBrushRedBack", "ColorBrush7"), AnimationColorIn), "MyButton Background " & Uuid)
End Sub
Private Sub Button_MouseUp() Handles Me.MouseLeftButtonUp
If Not IsMouseDown Then Exit Sub
If Not IsMouseDown Then Return
IsMouseDown = False
AniStart({
AaScaleTransform(PanFore, 1 - CType(PanFore.RenderTransform, ScaleTransform).ScaleX, 300, 10, New AniEaseOutFluent(AniEasePower.Middle))
@@ -188,7 +193,7 @@
End Sub
Private Sub Button_MouseLeave() Handles Me.MouseLeave
AniStart(AaColor(PanFore, BackgroundProperty, "ColorBrushHalfWhite", AnimationColorOut), "MyButton Background " & Uuid)
If Not IsMouseDown Then Exit Sub
If Not IsMouseDown Then Return
IsMouseDown = False
AniStart(AaScaleTransform(PanFore, 1 - CType(PanFore.RenderTransform, ScaleTransform).ScaleX, 800,, New AniEaseOutFluent(AniEasePower.Strong)), "MyButton Scale " & Uuid)
End Sub
+198 -106
View File
@@ -3,43 +3,81 @@
'控件
Inherits Grid
Private ReadOnly MainGrid As Grid
Private ReadOnly MainChrome As SystemDropShadowChrome
Public ReadOnly Property MainChrome As MyDropShadow
Private ReadOnly MainBorder As Border
Public MainTextBlock As TextBlock
Public MainSwap As Shapes.Path
Public Property BorderChild As UIElement
Get
Return MainBorder.Child
End Get
Set(value As UIElement)
MainBorder.Child = value
End Set
End Property
Private _MainTextBlock As TextBlock
Public Property MainTextBlock As TextBlock
Get
Init() '当父级触发 Loaded 时,本卡片可能尚未触发 Loaded(该事件从父级向子级调用),因此这会是 null。手动触发以确保控件已加载。
Return _MainTextBlock
End Get
Set(value As TextBlock)
_MainTextBlock = value
End Set
End Property
Private _MainSwap As Shapes.Path
Public Property MainSwap As Shapes.Path
Get
Init()
Return _MainSwap
End Get
Set(value As Shapes.Path)
_MainSwap = value
End Set
End Property
'属性
Public Uuid As Integer = GetUuid()
Public ReadOnly Property Inlines As InlineCollection
Get
Return MainTextBlock.Inlines
End Get
End Property
Public Property CornerRadius As CornerRadius
Get
Return MainChrome.CornerRadius
End Get
Set(value As CornerRadius)
MainChrome.CornerRadius = value
MainBorder.CornerRadius = value
End Set
End Property
Public Property Title As String
Get
Return GetValue(TitleProperty)
End Get
Set(value As String)
SetValue(TitleProperty, value)
If MainTextBlock IsNot Nothing Then MainTextBlock.Text = value
If _MainTextBlock IsNot Nothing Then MainTextBlock.Text = value
End Set
End Property
Public Shared ReadOnly TitleProperty As DependencyProperty = DependencyProperty.Register("Title", GetType(String), GetType(MyCard), New PropertyMetadata(""))
'UI 建立
Public Sub New()
MainChrome = New SystemDropShadowChrome With {.Margin = New Thickness(-9.5, -9, 0.5, -0.5), .Opacity = 0.1, .CornerRadius = New CornerRadius(6)}
MainChrome.SetResourceReference(SystemDropShadowChrome.ColorProperty, "ColorObject1")
Children.Add(MainChrome)
MainBorder = New Border With {.Background = New SolidColorBrush(Color.FromArgb(205, 255, 255, 255)), .CornerRadius = New CornerRadius(6), .IsHitTestVisible = False}
Children.Add(MainBorder)
MainChrome = New MyDropShadow With {
.Margin = New Thickness(-3, -3, -3, -3 - GetWPFSize(1)), .ShadowRadius = 3, .Opacity = DropShadowIdleOpacity, .CornerRadius = New CornerRadius(5)}
MainChrome.SetResourceReference(MyDropShadow.ColorProperty, "ColorObject1")
Children.Insert(0, MainChrome)
MainBorder = New Border With {.Background = New SolidColorBrush(Color.FromArgb(245, 255, 255, 255)), .CornerRadius = New CornerRadius(5), .IsHitTestVisible = False}
Children.Insert(1, MainBorder)
MainGrid = New Grid
Children.Add(MainGrid)
End Sub
Private IsLoad As Boolean = False
Private Sub MyCard_Loaded() Handles Me.Loaded
'卡片的进入时动画已被页面通用切换动画替代
'If LoadAnimation AndAlso IsLoad Then
' StartHeightAnimation(Math.Min(50, ActualHeight), ActualHeight - Math.Min(50, ActualHeight), True)
'End If
If IsLoad Then Exit Sub
Private Sub Init() Handles Me.Loaded
If IsLoad Then Return
IsLoad = True
'初次加载限定
If Not Title = "" AndAlso IsNothing(MainTextBlock) Then
If MainTextBlock Is Nothing Then
MainTextBlock = New TextBlock With {.HorizontalAlignment = HorizontalAlignment.Left, .VerticalAlignment = VerticalAlignment.Top, .Margin = New Thickness(15, 12, 0, 0), .FontWeight = FontWeights.Bold, .FontSize = 13, .IsHitTestVisible = False}
MainTextBlock.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrush1")
MainTextBlock.SetBinding(TextBlock.TextProperty, New Binding("Title") With {.Source = Me, .Mode = BindingMode.OneWay})
@@ -51,7 +89,6 @@
MainSwap.SetResourceReference(Shapes.Path.FillProperty, "ColorBrush1")
MainGrid.Children.Add(MainSwap)
End If
IsLoad = True
'改变默认的折叠
If IsSwaped AndAlso SwapControl IsNot Nothing Then
MainSwap.RenderTransform = New RotateTransform(If(SwapLogoRight, 270, 0))
@@ -72,25 +109,17 @@
'这一部分的代码是好几年前留下的究极屎坑,当时还不知道该咋正确调用这种方法,就写了这么一坨屎
'但是现在……反正勉强能用……懒得改了就这样吧.jpg
'别骂了别骂了.jpg
If IsNothing(Stack.Tag) Then Exit Sub
If IsNothing(Stack.Tag) Then Return
'排序
Select Case Type
Case 3
Stack.Tag = Sort(CType(Stack.Tag, List(Of DlOptiFineListEntry)), Function(Left As DlOptiFineListEntry, Right As DlOptiFineListEntry) As Boolean
Return VersionSortBoolean(Left.NameDisplay, Right.NameDisplay)
End Function)
Stack.Tag = CType(Stack.Tag, List(Of DlOptiFineListEntry)).Sort(Function(a, b) VersionSortBoolean(a.NameDisplay, b.NameDisplay))
Case 4, 10
Stack.Tag = Sort(CType(Stack.Tag, List(Of DlLiteLoaderListEntry)), Function(Left As DlLiteLoaderListEntry, Right As DlLiteLoaderListEntry) As Boolean
Return VersionSortBoolean(Left.Inherit, Right.Inherit)
End Function)
Stack.Tag = CType(Stack.Tag, List(Of DlLiteLoaderListEntry)).Sort(Function(a, b) VersionSortBoolean(a.Inherit, b.Inherit))
Case 6
Stack.Tag = Sort(CType(Stack.Tag, List(Of DlForgeVersionEntry)), Function(Left As DlForgeVersionEntry, Right As DlForgeVersionEntry) As Boolean
Return VersionSortBoolean(Left.Version, Right.Version)
End Function)
Stack.Tag = CType(Stack.Tag, List(Of DlForgeVersionEntry)).Sort(Function(a, b) a.Version > b.Version)
Case 8, 9
Stack.Tag = Sort(CType(Stack.Tag, List(Of DlCfFile)), Function(Left As DlCfFile, Right As DlCfFile) As Boolean
Return Left.Date > Right.Date
End Function)
Stack.Tag = CType(Stack.Tag, List(Of CompFile)).Sort(Function(a, b) a.ReleaseDate > b.ReleaseDate)
End Select
'控件转换
Select Case Type
@@ -105,7 +134,7 @@
Case 6
ForgeDownloadListItemPreload(Stack, Stack.Tag, AddressOf ForgeSave_Click, True)
Case 8
DlCfFilesPreload(Stack, Stack.Tag, AddressOf FrmDownloadMod.ProjectClick)
CompFilesCardPreload(Stack, Stack.Tag)
End Select
'实现控件虚拟化
For Each Data As Object In Stack.Tag
@@ -122,15 +151,34 @@
Case 6
Stack.Children.Add(ForgeDownloadListItem(Data, AddressOf ForgeSave_Click, True))
Case 7
Stack.Children.Add(McDownloadListItem(Data, AddressOf FrmDownloadInstall.MinecraftSelected, False))
'不能使用 AddressOf,这导致了 #535,原因完全不明,疑似是编译器 Bug
Stack.Children.Add(McDownloadListItem(Data, Sub(sender, e) FrmDownloadInstall.MinecraftSelected(sender, e), False))
Case 8
Stack.Children.Add(CType(Data, DlCfFile).ToListItem(AddressOf FrmDownloadCfDetail.Save_Click))
If CType(Stack.Tag, List(Of CompFile)).Distinct(Function(a, b) a.DisplayName = b.DisplayName).Count <>
CType(Stack.Tag, List(Of CompFile)).Count Then
'存在重复的名称(#1344)
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Save_Click, BadDisplayName:=True))
Else
'不存在重复的名称,正常加载
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Save_Click))
End If
Case 9
Stack.Children.Add(CType(Data, DlCfFile).ToListItem(AddressOf FrmDownloadCfDetail.Install_Click, AddressOf FrmDownloadCfDetail.Save_Click))
If CType(Stack.Tag, List(Of CompFile)).Distinct(Function(a, b) a.DisplayName = b.DisplayName).Count <>
CType(Stack.Tag, List(Of CompFile)).Count Then
'存在重复的名称(#1344)
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Install_Click, AddressOf FrmDownloadCompDetail.Save_Click, BadDisplayName:=True))
Else
'不存在重复的名称,正常加载
Stack.Children.Add(CType(Data, CompFile).ToListItem(AddressOf FrmDownloadCompDetail.Install_Click, AddressOf FrmDownloadCompDetail.Save_Click))
End If
Case 10
Stack.Children.Add(LiteLoaderDownloadListItem(Data, AddressOf LiteLoaderSave_Click, True))
Case 11
Stack.Children.Add(CType(Data, HelpEntry).ToListItem)
Case 12
Stack.Children.Add(FabricDownloadListItem(CType(Data, JObject), AddressOf FrmDownloadInstall.Fabric_Selected))
Case 13
Stack.Children.Add(NeoForgeDownloadListItem(Data, AddressOf NeoForgeSave_Click, True))
Case Else
Log("未知的虚拟化种类:" & Type, LogLevel.Feedback)
End Select
@@ -139,65 +187,91 @@
Stack.Tag = Nothing
End Sub
'事件
'动画
Private Const DropShadowIdleOpacity As Double = 0.07
Private Const DropShadowHoverOpacity As Double = 0.4
Public Property HasMouseAnimation As Boolean = True
Private Sub MyCard_MouseEnter(sender As Object, e As MouseEventArgs) Handles Me.MouseEnter
If Not HasMouseAnimation Then Return
Dim AniList As New List(Of AniData)
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush2", 150))
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush2", 150))
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush2", 90))
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush2", 90))
AniList.AddRange({
AaColor(MainChrome, SystemDropShadowChrome.ColorProperty, "ColorObject2", 180),
AaColor(MainBorder, Border.BackgroundProperty, New MyColor(230, 255, 255, 255) - MainBorder.Background, 180),
AaOpacity(MainChrome, 0.3 - MainChrome.Opacity, 180)
})
AaColor(MainChrome, MyDropShadow.ColorProperty, "ColorObject4", 90),
AaOpacity(MainChrome, DropShadowHoverOpacity - MainChrome.Opacity, 90)
})
AniStart(AniList, "MyCard Mouse " & Uuid)
End Sub
Private Sub MyCard_MouseLeave(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave
If Not HasMouseAnimation Then Return
Dim AniList As New List(Of AniData)
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush1", 250))
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush1", 250))
If Not IsNothing(MainTextBlock) Then AniList.Add(AaColor(MainTextBlock, TextBlock.ForegroundProperty, "ColorBrush1", 90))
If Not IsNothing(MainSwap) Then AniList.Add(AaColor(MainSwap, Shapes.Path.FillProperty, "ColorBrush1", 90))
AniList.AddRange({
AaColor(MainChrome, SystemDropShadowChrome.ColorProperty, "ColorObject1", 300),
AaColor(MainBorder, Border.BackgroundProperty, New MyColor(205, 255, 255, 255) - MainBorder.Background, 300),
AaOpacity(MainChrome, 0.1 - MainChrome.Opacity, 300)
})
AaColor(MainChrome, MyDropShadow.ColorProperty, "ColorObject1", 90),
AaOpacity(MainChrome, DropShadowIdleOpacity - MainChrome.Opacity, 90)
})
AniStart(AniList, "MyCard Mouse " & Uuid)
End Sub
'高度改变动画
#Region "高度改变动画"
''' <summary>
''' 是否启用高度改变动画。
''' </summary>
Public Property UseAnimation As Boolean = True
Private IsHeightAnimating As Boolean = False
Private ActualUsedHeight As Double '回滚实际高度(例如 NaN)
Private Sub MySizeChanged(sender As Object, e As SizeChangedEventArgs) Handles Me.SizeChanged
If Not UseAnimation Then Exit Sub
If Not UseAnimation Then Return
Dim DeltaHeight As Double = If(IsSwaped, SwapedHeight, e.NewSize.Height) - e.PreviousSize.Height
'卡片的进入时动画已被页面通用切换动画替代
If e.PreviousSize.Height = 0 OrElse IsHeightAnimating OrElse Math.Abs(DeltaHeight) < 1 OrElse ActualHeight = 0 Then Exit Sub
If e.PreviousSize.Height = 0 OrElse IsHeightAnimating OrElse Math.Abs(DeltaHeight) < 1 OrElse ActualHeight = 0 Then Return
StartHeightAnimation(DeltaHeight, e.PreviousSize.Height, False)
End Sub
Private Sub StartHeightAnimation(DeltaHeight As Double, PreviousHeight As Double, IsLoadAnimation As Boolean)
If IsHeightAnimating OrElse FrmMain Is Nothing Then Exit Sub '避免 XAML 设计器出错
Private Sub StartHeightAnimation(Delta As Double, PreviousHeight As Double, IsLoadAnimation As Boolean)
If IsHeightAnimating OrElse FrmMain Is Nothing Then Return '避免 XAML 设计器出错
Dim AnimList As New List(Of AniData)
If DeltaHeight > 10 OrElse (DeltaHeight < -10 AndAlso Not IsNothing(SwapControl)) Then '如果不是需要折叠的卡片,高度减小时的弹跳会吞掉按钮下边框
'高度增加较大,使用弹起动画
Dim Delta As Double = MathRange(Math.Abs(DeltaHeight) * 0.05, 3, 10) * Math.Sign(DeltaHeight)
AnimList.AddRange({
AaHeight(Me, DeltaHeight + Delta, 300, If(IsLoadAnimation, 30, 0), If(DeltaHeight > FrmMain.Height, New AniEaseInFluent(AniEasePower.ExtraStrong), New AniEaseOutFluent(AniEasePower.ExtraStrong))),
AaHeight(Me, -Delta, 150, 260, Ease:=New AniEaseOutFluent(AniEasePower.Strong))
})
Else
'普通的改变就行啦
AnimList.AddRange({
AaHeight(Me, DeltaHeight, MathRange(Math.Abs(DeltaHeight) * 4, 150, 250),, New AniEaseOutFluent)
})
End If
AnimList.Add(AaCode(Sub()
IsHeightAnimating = False
Height = ActualUsedHeight
If IsSwaped Then SwapControl.Visibility = Visibility.Collapsed
End Sub,, True))
AniStart(AnimList, "MyCard Height " & Uuid)
Dim AbsDelta = Math.Abs(Delta)
If AbsDelta <= 800 Then
'短距离,直接使用 150ms 的缓动动画
AnimList.Add(AaHeight(Me, Delta, 150,, New AniEaseOutFluent(AniEasePower.ExtraStrong)))
Else
Dim EaseLength As Integer, EaseTime As Integer
Dim InitSpeed As Integer '到达缓动区前的初速度
If Delta < 0 AndAlso AbsDelta - EaseLength > 5000 * 0.1 Then
'收回距离过长 (>0.1s),强制以 100ms 完成匀速段,然后让减速段更长
EaseLength = 200
EaseTime = 150
InitSpeed = (AbsDelta - EaseLength) / 0.1
ElseIf Delta > 0 AndAlso AbsDelta - EaseLength > 5000 * 0.6 Then
'展开距离过长 (>0.6s),以 5000 速度展示 300ms 匀速段,剩下的距离全部归入减速段
InitSpeed = 5000
EaseLength = AbsDelta - InitSpeed * 0.3
EaseTime = 400
Else
'中程,匀速地快速展开(或收回)
EaseLength = 150
EaseTime = 200
InitSpeed = 4000
End If
'匀速段
AnimList.Add(AaHeight(Me, (AbsDelta - EaseLength) * Math.Sign(Delta),
(AbsDelta - EaseLength) / InitSpeed * 1000))
'减速段
AnimList.Add(AaHeight(Me, EaseLength * Math.Sign(Delta),
EaseTime,, New AniEaseOutFluentWithInitial(InitSpeed, EaseTime / 1000, EaseLength), True))
End If
AnimList.Add(AaCode(
Sub()
IsHeightAnimating = False
Height = ActualUsedHeight
If IsSwaped AndAlso SwapControl IsNot Nothing Then SwapControl.Visibility = Visibility.Collapsed
End Sub,, True))
AniStart(AnimList, "MyCard Height " & Uuid)
IsHeightAnimating = True
ActualUsedHeight = If(IsSwaped, SwapedHeight, Height)
Height = PreviousHeight
@@ -211,7 +285,10 @@
IsHeightAnimating = False
End Sub
'折叠
#End Region
#Region "折叠"
'若设置了 CanSwap,或 SwapControl 不为空,则判定为会进行折叠
'这是因为不能直接在 XAML 中设置 SwapControl
Public SwapControl As Object
@@ -227,19 +304,19 @@
Get
Return _IsSwaped
End Get
Set(ByVal value As Boolean)
If _IsSwaped = value Then Exit Property
Set(value As Boolean)
If _IsSwaped = value Then Return
_IsSwaped = value
If SwapControl Is Nothing Then Exit Property
If SwapControl Is Nothing Then Return
'展开
If Not IsSwaped AndAlso TypeOf SwapControl Is StackPanel Then StackInstall(SwapControl, SwapType, Title)
'若尚未加载,会在 Loaded 事件中触发无动画的折叠,不需要在这里进行
If Not IsLoaded Then Exit Property
If Not IsLoaded Then Return
'更新高度
SwapControl.Visibility = Visibility.Visible
TriggerForceResize()
'改变箭头
AniStart(AaRotateTransform(MainSwap, If(_IsSwaped, If(SwapLogoRight, 270, 0), 180) - CType(MainSwap.RenderTransform, RotateTransform).Angle, 400,, New AniEaseOutBack(AniEasePower.Weak)), "MyCard Swap " & Uuid, True)
AniStart(AaRotateTransform(MainSwap, If(_IsSwaped, If(SwapLogoRight, 270, 0), 180) - CType(MainSwap.RenderTransform, RotateTransform).Angle, 250,, New AniEaseOutFluent(AniEasePower.ExtraStrong)), "MyCard Swap " & Uuid, True)
End Set
End Property
Private _IsSwaped As Boolean = False
@@ -251,48 +328,63 @@
Public Const SwapedHeight As Integer = 40
Private Sub MyCard_MouseLeftButtonDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
Dim Pos As Double = Mouse.GetPosition(Me).Y
If Not IsSwaped AndAlso (IsNothing(SwapControl) OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判
If Not IsSwaped AndAlso
(SwapControl Is Nothing OrElse Pos > If(IsSwaped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判
IsMouseDown = True
End Sub
Private Sub MyCard_MouseLeftButtonUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If IsMouseDown Then
If Not IsMouseDown Then Return
IsMouseDown = False
Dim Pos As Double = Mouse.GetPosition(Me).Y
If Not IsSwaped AndAlso
(SwapControl Is Nothing OrElse Pos > If(IsSwaped, SwapedHeight, SwapedHeight - 6) OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Return '检测点击位置;或已经不在可视树上的误判
Dim ee = New RouteEventArgs(True)
RaiseEvent PreviewSwap(Me, ee)
If ee.Handled Then
IsMouseDown = False
Dim Pos As Double = Mouse.GetPosition(Me).Y
If Not IsSwaped AndAlso (IsNothing(SwapControl) OrElse Pos > SwapedHeight OrElse (Pos = 0 AndAlso Not IsMouseDirectlyOver)) Then Exit Sub '检测点击位置;或已经不在可视树上的误判
Dim ee = New RouteEventArgs(True)
RaiseEvent PreviewSwap(Me, ee)
If ee.Handled Then
IsMouseDown = False
Exit Sub
End If
IsSwaped = Not IsSwaped
Log("[Control] " & If(IsSwaped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title))
RaiseEvent Swap(Me, ee)
Return
End If
IsSwaped = Not IsSwaped
Log("[Control] " & If(IsSwaped, "折叠卡片", "展开卡片") & If(Title Is Nothing, "", ":" & Title))
RaiseEvent Swap(Me, ee)
End Sub
Private Sub MyCard_MouseLeave_Swap(sender As Object, e As MouseEventArgs) Handles Me.MouseLeave
IsMouseDown = False
End Sub
#End Region
End Class
Partial Public Module ModAnimation
Public Sub AniDispose(Control As MyCard, RemoveFromChildren As Boolean, Optional CallBack As ParameterizedThreadStart = Nothing)
If Not Control.IsHitTestVisible Then Exit Sub
Control.IsHitTestVisible = False
AniStart({
AaScaleTransform(Control, -0.08, 200,, New AniEaseInFluent),
AaOpacity(Control, -1, 200,, New AniEaseOutFluent),
AaHeight(Control, -Control.ActualHeight, 150, 100, New AniEaseOutFluent),
AaCode(Sub()
If RemoveFromChildren Then
CType(Control.Parent, Object).Children.Remove(Control)
Else
Control.Visibility = Visibility.Collapsed
End If
If CallBack IsNot Nothing Then CallBack(Control)
End Sub,, True)
If Control.IsHitTestVisible Then
Control.IsHitTestVisible = False
AniStart({
AaScaleTransform(Control, -0.08, 200,, New AniEaseInFluent),
AaOpacity(Control, -1, 200,, New AniEaseOutFluent),
AaHeight(Control, -Control.ActualHeight, 150, 100, New AniEaseOutFluent),
AaCode(
Sub()
If RemoveFromChildren Then
If Control.Parent Is Nothing Then Return
CType(Control.Parent, Object).Children.Remove(Control)
Else
Control.Visibility = Visibility.Collapsed
End If
If CallBack IsNot Nothing Then CallBack(Control)
End Sub,, True)
}, "MyCard Dispose " & Control.Uuid)
Else
If RemoveFromChildren Then
If Control.Parent Is Nothing Then Return
CType(Control.Parent, Object).Children.Remove(Control)
Else
Control.Visibility = Visibility.Collapsed
End If
If CallBack IsNot Nothing Then CallBack(Control)
End If
End Sub
End Module
@@ -4,7 +4,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d" x:Class="MyCheckBox"
FocusVisualStyle="{x:Null}"
MinWidth="20" x:Name="PanBack" UseLayoutRounding="False" SnapsToDevicePixels="False" MinHeight="20" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True" d:DesignWidth="126.4" d:DesignHeight="44.8">
<TextBlock IsHitTestVisible="False" FontSize="13" x:Name="LabText" Padding="0" Margin="26,0,0,0" Text="Checkbox" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center" />
<TextBlock IsHitTestVisible="False" FontSize="13" x:FieldModifier="Public" x:Name="LabText" Padding="0" Margin="26,0,0,0" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center" />
<Border IsHitTestVisible="False" x:Name="ShapeBorder" BorderThickness="1.1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="18" Height="18" BorderBrush="{DynamicResource ColorBrush1}" CornerRadius="3" Margin="1,0,0,0" Background="{StaticResource ColorBrushHalfWhite}" />
<Path IsHitTestVisible="False" x:Name="ShapeCheck" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{Binding BorderBrush, ElementName=ShapeBorder}" Width="12" Height="12" Margin="4,0,0,0" Data="M0,6L1.5,4.5 4.5,7.5 10.5,1.5 12,3 4.5,10.5 0,6z">
<Path.RenderTransform>
@@ -1,4 +1,7 @@
Public Class MyCheckBox
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyCheckBox
'基础
@@ -14,29 +17,32 @@
End Sub '使外部程序引发本控件的 Change 事件
'自定义属性
Private _Checked As Boolean = False '是否选中
Public Property Checked As Boolean
Get
Return _Checked
Return GetValue(CheckedProperty)
End Get
Set(value As Boolean)
SetChecked(value, False, True)
SetChecked(value, False)
End Set
End Property
Public Shared ReadOnly CheckedProperty As DependencyProperty =
DependencyProperty.Register("Checked", GetType(Boolean), GetType(MyCheckBox), New PropertyMetadata(False,
Sub(d As MyCheckBox, e As DependencyPropertyChangedEventArgs)
'在使用 XAML 设置 Checked 属性时,不会触发 Checked_Set 方法,所以需要在这里手动触发 UI 改变
If Not d.IsLoaded Then d.SyncUI()
End Sub))
Private Const AnimationTimeOfCheck As Integer = 150 '勾选状态变更动画长度
''' <summary>
''' 手动设置 Checked 属性。
''' </summary>
''' <param name="value">新的 Checked 属性。</param>
''' <param name="user">是否由用户引发。</param>
''' <param name="anime">是否执行动画。</param>
Public Sub SetChecked(value As Boolean, user As Boolean, anime As Boolean)
Public Sub SetChecked(value As Boolean, user As Boolean)
Try
If value = _Checked Then Exit Sub
If value = Checked Then Return
'Preview 事件
If value AndAlso user Then
Dim e = New RouteEventArgs(user)
RaiseEvent PreviewChange(Me, e)
@@ -44,64 +50,71 @@
MouseDowned = True
Checkbox_MouseLeave()
MouseDowned = False
Exit Sub
Return
End If
End If
_Checked = value
SetValue(CheckedProperty, value)
If IsLoaded Then RaiseEvent Change(Me, user)
'更改动画
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso anime Then '防止默认属性变更触发动画
AllowMouseDown = False
If Checked Then
'由无变有
AniStart({
AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True),
AaScaleTransform(ShapeCheck, 1 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack(AniEasePower.Weak)),
AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
}, "MyCheckBox Scale " & Uuid)
AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush2"), "ColorBrushGray4"), AnimationTimeOfCheck)
}, "MyCheckBox BorderColor " & Uuid)
AniStart({
AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
}, "MyCheckBox AllowMouseDown " & Uuid)
Else
'由有变无
AniStart({
AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True),
AaScaleTransform(ShapeCheck, -CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 0.9, , New AniEaseInFluent(AniEasePower.Weak)),
AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
}, "MyCheckBox Scale " & Uuid)
AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfCheck)
}, "MyCheckBox BorderColor " & Uuid)
AniStart({
AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
}, "MyCheckBox AllowMouseDown " & Uuid)
End If
Else
'不使用动画
AniStop("MyCheckBox Scale " & Uuid)
AniStop("MyCheckBox BorderColor " & Uuid)
AniStop("MyCheckBox AllowMouseDown " & Uuid)
If Checked Then
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 1
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 1
ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4"))
Else
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 0
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 0
ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
End If
End If
SyncUI()
Catch ex As Exception
Log(ex, "设置 Checked 失败")
End Try
End Sub
Private Sub SyncUI()
If AniControlEnabled = 0 AndAlso IsLoaded Then '防止默认属性变更触发动画
AllowMouseDown = False
If Checked Then
'由无变有
AniStart({
AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True),
AaScaleTransform(ShapeCheck, 1 - CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack(AniEasePower.Weak)),
AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
}, "MyCheckBox Scale " & Uuid)
AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush2"), "ColorBrushGray4"), AnimationTimeOfCheck)
}, "MyCheckBox BorderColor " & Uuid)
AniStart({
AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
}, "MyCheckBox AllowMouseDown " & Uuid)
Else
'由有变无
AniStart({
AaScale(ShapeBorder, 12 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True),
AaScaleTransform(ShapeCheck, -CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX, AnimationTimeOfCheck * 0.9, , New AniEaseInFluent(AniEasePower.Weak)),
AaScale(ShapeBorder, 6, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.7, New AniEaseOutBack, , True)
}, "MyCheckBox Scale " & Uuid)
AniStart({
AaColor(ShapeBorder, Border.BorderBrushProperty, If(IsEnabled, If(IsMouseOver, "ColorBrush3", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfCheck)
}, "MyCheckBox BorderColor " & Uuid)
AniStart({
AaCode(Sub() AllowMouseDown = True, AnimationTimeOfCheck * 2)
}, "MyCheckBox AllowMouseDown " & Uuid)
End If
Else
'不使用动画
AniStop("MyCheckBox Scale " & Uuid)
AniStop("MyCheckBox BorderColor " & Uuid)
AniStop("MyCheckBox AllowMouseDown " & Uuid)
If Checked Then
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 1
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 1
ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4"))
Else
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleX = 0
CType(ShapeCheck.RenderTransform, ScaleTransform).ScaleY = 0
ShapeBorder.SetResourceReference(Border.BorderBrushProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
End If
End If
End Sub
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabText.Inlines
End Get
End Property
Public Property Text As String
Get
Return GetValue(TextProperty)
@@ -110,27 +123,27 @@
SetValue(TextProperty, value)
End Set
End Property '内容
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyCheckbox), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If Not IsNothing(sender) Then CType(sender, MyCheckbox).LabText.Text = e.NewValue
End Sub)))
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyCheckBox), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If Not IsNothing(sender) Then CType(sender, MyCheckBox).LabText.Text = e.NewValue
End Sub)))
'点击事件
Private MouseDowned As Boolean = False
Private AllowMouseDown As Boolean = True
Private Sub Checkbox_MouseUp() Handles Me.MouseLeftButtonUp
If Not MouseDowned Then Exit Sub
If Not MouseDowned Then Return
Log("[Control] 按下复选框(" & (Not Checked).ToString & "):" & Text)
MouseDowned = False
SetChecked(Not Checked, True, True)
SetChecked(Not Checked, True)
AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100), "MyCheckBox Background " & Uuid)
End Sub
Private Sub Checkbox_MouseDown() Handles Me.MouseLeftButtonDown
If Not AllowMouseDown Then Exit Sub
If Not AllowMouseDown Then Return
MouseDowned = True
Focus()
AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrush9", 100), "MyCheckBox Background " & Uuid)
AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushBg1", 100), "MyCheckBox Background " & Uuid)
If Checked Then
AniStart({
AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True),
@@ -141,7 +154,7 @@
End If
End Sub
Private Sub Checkbox_MouseLeave() Handles Me.MouseLeave
If Not MouseDowned Then Exit Sub
If Not MouseDowned Then Return
MouseDowned = False
AniStart(AaColor(ShapeBorder, Border.BackgroundProperty, "ColorBrushHalfWhite", 100), "MyCheckBox Background " & Uuid)
If Checked Then
@@ -190,7 +203,7 @@
}, "MyCheckBox BorderColor " & Uuid)
End Sub
Private Sub Checkbox_MouseLeaveAnimation() Handles Me.MouseLeave
If Not IsEnabled Then Exit Sub 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
If Not IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
AniStart({
AaColor(LabText, TextBlock.ForegroundProperty, If(Me.IsEnabled, "ColorBrush1", "ColorBrushGray4"), AnimationTimeOfMouseOut)
}, "MyCheckBox TextColor " & Uuid)
+25 -23
View File
@@ -8,7 +8,7 @@
Public Property HintText As String = ""
Public Overrides Sub OnApplyTemplate()
MyBase.OnApplyTemplate()
If Not IsEditable Then Exit Sub
If Not IsEditable Then Return
Try
TextBox = Template.FindName("PART_EditableTextBox", Me)
TextBox.AddHandler(LostFocusEvent, New RoutedEventHandler(AddressOf RefreshColor))
@@ -62,44 +62,40 @@
'指向动画
Public Sub RefreshColor() Handles Me.IsEnabledChanged, Me.MouseEnter, Me.MouseLeave, Me.PreviewMouseLeftButtonDown, Me.PreviewMouseLeftButtonUp, Me.GotKeyboardFocus
'判断当前颜色
Dim ColorName As String
Dim BackName As String
Dim ForeColorName As String
Dim BackColorName As String
Dim Time As Integer
If IsEnabled Then
If IsEditable AndAlso Template.FindName("PART_EditableTextBox", Me).IsFocused Then
ColorName = "ColorBrush4"
BackName = "ColorBrush9"
Time = 60
ElseIf IsMouseDown OrElse IsDropDownOpen Then
ColorName = "ColorBrush3"
BackName = "ColorBrush9"
Time = 60
If IsMouseDown OrElse IsDropDownOpen OrElse (IsEditable AndAlso Template.FindName("PART_EditableTextBox", Me).IsFocused) Then
ForeColorName = "ColorBrush3"
BackColorName = "ColorBrush7"
Time = 10
ElseIf IsMouseOver Then
ColorName = "ColorBrush3"
BackName = "ColorBrushHalfWhite"
ForeColorName = "ColorBrush4"
BackColorName = "ColorBrush7"
Time = 100
Else
ColorName = "ColorBrush1"
BackName = "ColorBrushHalfWhite"
Time = 200
ForeColorName = "ColorBrushBg0"
BackColorName = "ColorBrushHalfWhite"
Time = 100
End If
Else
ColorName = "ColorBrushGray4"
BackName = "ColorBrushHalfWhite"
ForeColorName = "ColorBrushGray5"
BackColorName = "ColorBrushGray6"
Time = 200
End If
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
AniStart({
AaColor(Me, ForegroundProperty, ColorName, Time),
AaColor(Me, BackgroundProperty, BackName, Time)
AaColor(Me, ForegroundProperty, ForeColorName, Time),
AaColor(Me, BackgroundProperty, BackColorName, Time)
}, "MyComboBox Color " & Uuid)
Else
'无动画
AniStop("MyComboBox Color " & Uuid)
SetResourceReference(ForegroundProperty, ColorName)
SetResourceReference(BackgroundProperty, BackName)
SetResourceReference(ForegroundProperty, ForeColorName)
SetResourceReference(BackgroundProperty, BackColorName)
End If
End Sub
@@ -120,7 +116,7 @@
'修复 WPF Bug:下拉框文本修改后,依然误认为还选择着此前的选项,导致再次点击该选项时内容不变
Private IsTextChanging As Boolean = False
Private Sub MyComboBox_TextChanged(sender As Object, e As TextChangedEventArgs) Handles Me.TextChanged
If IsTextChanging OrElse Not IsEditable Then Exit Sub
If IsTextChanging OrElse Not IsEditable Then Return
If SelectedItem IsNot Nothing AndAlso Text <> SelectedItem.ToString Then
Dim RawText As String = Text
Dim RawSelectionStart As Integer = TextBox.SelectionStart
@@ -132,4 +128,10 @@
End If
End Sub
Public ReadOnly Property ContentPresenter As ContentPresenter
Get
Return Template.FindName("PART_Content", Me)
End Get
End Property
End Class
@@ -35,7 +35,7 @@
NewFontOpacity = 0.4
Time = AnimationTimeOut
End If
If BackColorName = NewBackColorName AndAlso FontOpacity = NewFontOpacity Then Exit Sub
If BackColorName = NewBackColorName AndAlso FontOpacity = NewFontOpacity Then Return
BackColorName = NewBackColorName
FontOpacity = NewFontOpacity
'触发颜色动画
@@ -1,65 +1,89 @@
Public NotInheritable Class SystemDropShadowChrome
Public Class MyDropShadow
Inherits Decorator
'源码来源于:https://referencesource.microsoft.com/#PresentationFramework.Aero/parent/Shared/Microsoft/Windows/Themes/SystemDropShadowChrome.cs,6d9c27d92a8128c1
Public Shared ReadOnly ColorProperty As DependencyProperty = DependencyProperty.Register("Color", GetType(Color), GetType(SystemDropShadowChrome), New FrameworkPropertyMetadata(Color.FromArgb(&H71, &H0, &H0, &H0), FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf ClearBrushes)))
''' <summary>
''' 阴影颜色。
''' </summary>
Public Property Color As Color
Get
Return CType(GetValue(ColorProperty), Color)
Return GetValue(ColorProperty)
End Get
Set(value As Color)
SetValue(ColorProperty, value)
End Set
End Property
Public Shared ReadOnly ColorProperty As DependencyProperty = DependencyProperty.Register("Color", GetType(Color), GetType(MyDropShadow),
New FrameworkPropertyMetadata(Color.FromArgb(&H71, &H0, &H0, &H0), FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf ClearBrushes)))
Public Shared ReadOnly CornerRadiusProperty As DependencyProperty = DependencyProperty.Register("CornerRadius", GetType(CornerRadius), GetType(SystemDropShadowChrome), New FrameworkPropertyMetadata(New CornerRadius(), FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf ClearBrushes)), New ValidateValueCallback(AddressOf IsCornerRadiusValid))
''' <summary>
''' 阴影模糊半径。
''' </summary>
Public Property ShadowRadius As Double
Get
Return GetValue(ShadowRadiusProperty)
End Get
Set(value As Double)
SetValue(ShadowRadiusProperty, value)
End Set
End Property
Public Shared ReadOnly ShadowRadiusProperty As DependencyProperty = DependencyProperty.Register("ShadowRadius", GetType(Double), GetType(MyDropShadow),
New FrameworkPropertyMetadata(CDbl(5), FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf ClearBrushes)))
''' <summary>
''' 圆角大小。
''' </summary>
Public Property CornerRadius As CornerRadius
Get
Return CType(GetValue(CornerRadiusProperty), CornerRadius)
Return GetValue(CornerRadiusProperty)
End Get
Set(value As CornerRadius)
SetValue(CornerRadiusProperty, value)
End Set
End Property
Private Shared Function IsCornerRadiusValid(value As Object) As Boolean
Dim cr As CornerRadius = CType(value, CornerRadius)
Dim cr As CornerRadius = value
Return Not (cr.TopLeft < 0.0 OrElse cr.TopRight < 0.0 OrElse cr.BottomLeft < 0.0 OrElse cr.BottomRight < 0.0 OrElse Double.IsNaN(cr.TopLeft) OrElse Double.IsNaN(cr.TopRight) OrElse Double.IsNaN(cr.BottomLeft) OrElse Double.IsNaN(cr.BottomRight) OrElse Double.IsInfinity(cr.TopLeft) OrElse Double.IsInfinity(cr.TopRight) OrElse Double.IsInfinity(cr.BottomLeft) OrElse Double.IsInfinity(cr.BottomRight))
End Function
Public Shared ReadOnly CornerRadiusProperty As DependencyProperty = DependencyProperty.Register("CornerRadius", GetType(CornerRadius), GetType(MyDropShadow),
New FrameworkPropertyMetadata(New CornerRadius(), FrameworkPropertyMetadataOptions.AffectsRender, New PropertyChangedCallback(AddressOf ClearBrushes)), New ValidateValueCallback(AddressOf IsCornerRadiusValid))
' =======================================
' 渲染
' =======================================
Private Const ShadowDepth As Double = 5
Protected Overrides Sub OnRender(drawingContext As DrawingContext)
Dim cornerRadius As CornerRadius = Me.CornerRadius
Dim shadowBounds As New Rect(New Point(ShadowDepth, ShadowDepth), New Size(RenderSize.Width, RenderSize.Height))
Dim shadowBounds As New Rect(0, 0, RenderSize.Width, RenderSize.Height)
Dim color As Color = Me.Color
If shadowBounds.Width > 0 AndAlso shadowBounds.Height > 0 AndAlso color.A > 0 Then
Dim centerWidth As Double = shadowBounds.Right - shadowBounds.Left - 2 * ShadowDepth
Dim centerHeight As Double = shadowBounds.Bottom - shadowBounds.Top - 2 * ShadowDepth
Dim centerWidth As Double = shadowBounds.Right - shadowBounds.Left - 2 * ShadowRadius
Dim centerHeight As Double = shadowBounds.Bottom - shadowBounds.Top - 2 * ShadowRadius
Dim maxRadius As Double = Math.Min(centerWidth * 0.5, centerHeight * 0.5)
cornerRadius.TopLeft = Math.Min(cornerRadius.TopLeft, maxRadius)
cornerRadius.TopRight = Math.Min(cornerRadius.TopRight, maxRadius)
cornerRadius.BottomLeft = Math.Min(cornerRadius.BottomLeft, maxRadius)
cornerRadius.BottomRight = Math.Min(cornerRadius.BottomRight, maxRadius)
Dim brushes As Brush() = GetBrushes(color, cornerRadius)
Dim centerTop As Double = shadowBounds.Top + ShadowDepth
Dim centerLeft As Double = shadowBounds.Left + ShadowDepth
Dim centerRight As Double = shadowBounds.Right - ShadowDepth
Dim centerBottom As Double = shadowBounds.Bottom - ShadowDepth
Dim centerTop As Double = shadowBounds.Top + ShadowRadius
Dim centerLeft As Double = shadowBounds.Left + ShadowRadius
Dim centerRight As Double = shadowBounds.Right - ShadowRadius
Dim centerBottom As Double = shadowBounds.Bottom - ShadowRadius
Dim guidelineSetX As Double() = New Double() {centerLeft, centerLeft + cornerRadius.TopLeft, centerRight - cornerRadius.TopRight, centerLeft + cornerRadius.BottomLeft, centerRight - cornerRadius.BottomRight, centerRight}
Dim guidelineSetY As Double() = New Double() {centerTop, centerTop + cornerRadius.TopLeft, centerTop + cornerRadius.TopRight, centerBottom - cornerRadius.BottomLeft, centerBottom - cornerRadius.BottomRight, centerBottom}
drawingContext.PushGuidelineSet(New GuidelineSet(guidelineSetX, guidelineSetY))
cornerRadius.TopLeft += ShadowDepth
cornerRadius.TopRight += ShadowDepth
cornerRadius.BottomLeft += ShadowDepth
cornerRadius.BottomRight += ShadowDepth
cornerRadius.TopLeft += ShadowRadius
cornerRadius.TopRight += ShadowRadius
cornerRadius.BottomLeft += ShadowRadius
cornerRadius.BottomRight += ShadowRadius
Dim topLeft As New Rect(shadowBounds.Left, shadowBounds.Top, cornerRadius.TopLeft, cornerRadius.TopLeft)
drawingContext.DrawRectangle(brushes(Placement.TopLeft), Nothing, topLeft)
Dim topWidth As Double = guidelineSetX(2) - guidelineSetX(1)
If topWidth > 0 Then
Dim top As New Rect(guidelineSetX(1), shadowBounds.Top, topWidth, ShadowDepth)
Dim top As New Rect(guidelineSetX(1), shadowBounds.Top, topWidth, ShadowRadius)
drawingContext.DrawRectangle(brushes(Placement.Top), Nothing, top)
End If
@@ -68,14 +92,14 @@
Dim leftHeight As Double = guidelineSetY(3) - guidelineSetY(1)
If leftHeight > 0 Then
Dim left As New Rect(shadowBounds.Left, guidelineSetY(1), ShadowDepth, leftHeight)
Dim left As New Rect(shadowBounds.Left, guidelineSetY(1), ShadowRadius, leftHeight)
drawingContext.DrawRectangle(brushes(Placement.Left), Nothing, left)
End If
Dim rightHeight As Double = guidelineSetY(4) - guidelineSetY(2)
If rightHeight > 0 Then
Dim right As New Rect(guidelineSetX(5), guidelineSetY(2), ShadowDepth, rightHeight)
Dim right As New Rect(guidelineSetX(5), guidelineSetY(2), ShadowRadius, rightHeight)
drawingContext.DrawRectangle(brushes(Placement.Right), Nothing, right)
End If
@@ -84,20 +108,20 @@
Dim bottomWidth As Double = guidelineSetX(4) - guidelineSetX(3)
If bottomWidth > 0 Then
Dim bottom As New Rect(guidelineSetX(3), guidelineSetY(5), bottomWidth, ShadowDepth)
Dim bottom As New Rect(guidelineSetX(3), guidelineSetY(5), bottomWidth, ShadowRadius)
drawingContext.DrawRectangle(brushes(Placement.Bottom), Nothing, bottom)
End If
Dim bottomRight As New Rect(guidelineSetX(4), guidelineSetY(4), cornerRadius.BottomRight, cornerRadius.BottomRight)
drawingContext.DrawRectangle(brushes(Placement.BottomRight), Nothing, bottomRight)
If cornerRadius.TopLeft = ShadowDepth AndAlso cornerRadius.TopLeft = cornerRadius.TopRight AndAlso cornerRadius.TopLeft = cornerRadius.BottomLeft AndAlso cornerRadius.TopLeft = cornerRadius.BottomRight Then
If cornerRadius.TopLeft = ShadowRadius AndAlso cornerRadius.TopLeft = cornerRadius.TopRight AndAlso cornerRadius.TopLeft = cornerRadius.BottomLeft AndAlso cornerRadius.TopLeft = cornerRadius.BottomRight Then
Dim center As New Rect(guidelineSetX(0), guidelineSetY(0), centerWidth, centerHeight)
drawingContext.DrawRectangle(brushes(Placement.Center), Nothing, center)
Else
Dim figure As New PathFigure()
If cornerRadius.TopLeft > ShadowDepth Then
If cornerRadius.TopLeft > ShadowRadius Then
figure.StartPoint = New Point(guidelineSetX(1), guidelineSetY(0))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(1), guidelineSetY(1)), True))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(0), guidelineSetY(1)), True))
@@ -105,7 +129,7 @@
figure.StartPoint = New Point(guidelineSetX(0), guidelineSetY(0))
End If
If cornerRadius.BottomLeft > ShadowDepth Then
If cornerRadius.BottomLeft > ShadowRadius Then
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(0), guidelineSetY(3)), True))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(3), guidelineSetY(3)), True))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(3), guidelineSetY(5)), True))
@@ -113,7 +137,7 @@
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(0), guidelineSetY(5)), True))
End If
If cornerRadius.BottomRight > ShadowDepth Then
If cornerRadius.BottomRight > ShadowRadius Then
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(4), guidelineSetY(5)), True))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(4), guidelineSetY(4)), True))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(5), guidelineSetY(4)), True))
@@ -121,7 +145,7 @@
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(5), guidelineSetY(5)), True))
End If
If cornerRadius.TopRight > ShadowDepth Then
If cornerRadius.TopRight > ShadowRadius Then
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(5), guidelineSetY(2)), True))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(2), guidelineSetY(2)), True))
figure.Segments.Add(New LineSegment(New Point(guidelineSetX(2), guidelineSetY(0)), True))
@@ -158,28 +182,27 @@
Private _brushes As Brush()
Private Shared Sub ClearBrushes(o As DependencyObject, e As DependencyPropertyChangedEventArgs)
CType(o, SystemDropShadowChrome)._brushes = Nothing
CType(o, MyDropShadow)._brushes = Nothing
End Sub
Private Shared Function CreateStops(c As Color, cornerRadius As Double) As GradientStopCollection
Dim gradientScale As Double = 1 / (cornerRadius + ShadowDepth)
Dim gsc As New GradientStopCollection From {
New GradientStop(c, (0.5 + cornerRadius) * gradientScale)
}
Private Function CreateStops(c As Color, cornerRadius As Double) As GradientStopCollection
Dim gradientScale As Double = 1 / (ShadowRadius + cornerRadius)
Dim gsc As New GradientStopCollection
Dim stopColor As Color = c
gsc.Add(New GradientStop(stopColor, (ShadowRadius * 0.1 + cornerRadius) * gradientScale))
stopColor.A = CByte(0.74336 * c.A)
gsc.Add(New GradientStop(stopColor, (1.5 + cornerRadius) * gradientScale))
gsc.Add(New GradientStop(stopColor, (ShadowRadius * 0.3 + cornerRadius) * gradientScale))
stopColor.A = CByte(0.38053 * c.A)
gsc.Add(New GradientStop(stopColor, (2.5 + cornerRadius) * gradientScale))
gsc.Add(New GradientStop(stopColor, (ShadowRadius * 0.5 + cornerRadius) * gradientScale))
stopColor.A = CByte(0.12389 * c.A)
gsc.Add(New GradientStop(stopColor, (3.5 + cornerRadius) * gradientScale))
gsc.Add(New GradientStop(stopColor, (ShadowRadius * 0.7 + cornerRadius) * gradientScale))
stopColor.A = CByte(0.02654 * c.A)
gsc.Add(New GradientStop(stopColor, (4.5 + cornerRadius) * gradientScale))
gsc.Add(New GradientStop(stopColor, (ShadowRadius * 0.9 + cornerRadius) * gradientScale))
stopColor.A = 0
gsc.Add(New GradientStop(stopColor, (5 + cornerRadius) * gradientScale))
gsc.Add(New GradientStop(stopColor, (ShadowRadius + cornerRadius) * gradientScale))
gsc.Freeze()
Return gsc
End Function
Private Shared Function CreateBrushes(c As Color, cornerRadius As CornerRadius) As Brush()
Private Function CreateBrushes(c As Color, cornerRadius As CornerRadius) As Brush()
Dim brushes As Brush() = New Brush(8) {}
brushes(Placement.Center) = New SolidColorBrush(c)
brushes(Placement.Center).Freeze()
@@ -297,3 +320,5 @@
End Function
End Class
'参考自:https://referencesource.microsoft.com/#PresentationFramework.Aero/parent/Shared/Microsoft/Windows/Themes/SystemDropShadowChrome.cs,6d9c27d92a8128c1
@@ -2,7 +2,7 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" x:Name="PanBack" mc:Ignorable="d" x:Class="MyExtraButton"
Width="40" RenderTransformOrigin="0.5,0.5" ToolTipService.ShowDuration="2333333" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="16" ToolTipService.HorizontalOffset="-8" Height="0">
Width="40" RenderTransformOrigin="0.5,0.5" ToolTipService.Placement="Left" ToolTipService.VerticalOffset="16" ToolTipService.HorizontalOffset="-8" Height="0">
<Grid.RenderTransform>
<ScaleTransform ScaleX="0" ScaleY="0" />
</Grid.RenderTransform>
@@ -16,6 +16,11 @@
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.2" />
</Border.Effect>
</Border>
<Border x:Name="PanProgress" CornerRadius="1000" BorderThickness="0.001" Background="#2FFFFFFF" ClipToBounds="True" Visibility="Collapsed">
<Border.Clip>
<RectangleGeometry x:Name="RectProgress" Rect="0,5,40,35" />
</Border.Clip>
</Border>
<Path x:Name="Path" Stretch="Uniform" Margin="12" Fill="{DynamicResource ColorBrush8}" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<ScaleTransform />
@@ -4,6 +4,24 @@
Public Event Click(sender As Object, e As MouseButtonEventArgs) '自定义事件
Public Event RightClick(sender As Object, e As MouseButtonEventArgs)
'进度条
Private _Progress As Double = 0
Public Property Progress As Double
Get
Return _Progress
End Get
Set(value As Double)
If _Progress = value Then Return
_Progress = value
If value < 0.0001 Then
PanProgress.Visibility = Visibility.Collapsed
Else
PanProgress.Visibility = Visibility.Visible
RectProgress.Rect = New Rect(0, 40 * (1 - value), 40, 40 * value)
End If
End Set
End Property
'自定义属性
Public Uuid As Integer = GetUuid()
Private _Logo As String = ""
@@ -12,7 +30,7 @@
Return _Logo
End Get
Set(value As String)
If value = _Logo Then Exit Property
If value = _Logo Then Return
_Logo = value
Path.Data = (New GeometryConverter).ConvertFromString(value)
End Set
@@ -33,7 +51,7 @@
Return _Show
End Get
Set(value As Boolean)
If _Show = value Then Exit Property
If _Show = value Then Return
_Show = value
RunInUi(Sub()
If value Then
@@ -84,7 +102,7 @@
Get
Return _CanRightClick
End Get
Set(ByVal value As Boolean)
Set(value As Boolean)
_CanRightClick = value
End Set
End Property
@@ -95,20 +113,20 @@
Private Sub Button_LeftMouseDown(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonDown
If Not IsLeftMouseHeld AndAlso Not IsRightMouseHeld Then
AniStart({
AaScaleTransform(PanScale, 0.85 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 800,, New AniEaseOutFluent(AniEasePower.Strong)),
AaScaleTransform(PanScale, -0.05, 60,, New AniEaseOutFluent)
}, "MyExtraButton Scale " & Uuid)
AaScaleTransform(PanScale, 0.85 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 800,, New AniEaseOutFluent(AniEasePower.Strong)),
AaScaleTransform(PanScale, -0.05, 60,, New AniEaseOutFluent)
}, "MyExtraButton Scale " & Uuid)
End If
IsLeftMouseHeld = True
Focus()
End Sub
Private Sub Button_RightMouseDown(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseRightButtonDown
If Not CanRightClick Then Exit Sub
If Not CanRightClick Then Return
If Not IsLeftMouseHeld AndAlso Not IsRightMouseHeld Then
AniStart({
AaScaleTransform(PanScale, 0.85 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 800,, New AniEaseOutFluent(AniEasePower.Strong)),
AaScaleTransform(PanScale, -0.05, 60,, New AniEaseOutFluent)
}, "MyExtraButton Scale " & Uuid)
AaScaleTransform(PanScale, 0.85 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 800,, New AniEaseOutFluent(AniEasePower.Strong)),
AaScaleTransform(PanScale, -0.05, 60,, New AniEaseOutFluent)
}, "MyExtraButton Scale " & Uuid)
End If
IsRightMouseHeld = True
Focus()
@@ -116,18 +134,18 @@
Private Sub Button_LeftMouseUp() Handles PanClick.MouseLeftButtonUp
If Not IsRightMouseHeld Then
AniStart({
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack)
}, "MyExtraButton Scale " & Uuid)
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack)
}, "MyExtraButton Scale " & Uuid)
End If
IsLeftMouseHeld = False
RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave
End Sub
Private Sub Button_RightMouseUp() Handles PanClick.MouseRightButtonUp
If Not CanRightClick Then Exit Sub
If Not CanRightClick Then Return
If Not IsLeftMouseHeld Then
AniStart({
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack)
}, "MyExtraButton Scale " & Uuid)
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack)
}, "MyExtraButton Scale " & Uuid)
End If
IsRightMouseHeld = False
RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave
@@ -136,8 +154,8 @@
IsLeftMouseHeld = False
IsRightMouseHeld = False
AniStart({
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 500,, New AniEaseOutFluent)
}, "MyExtraButton Scale " & Uuid)
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 500,, New AniEaseOutFluent)
}, "MyExtraButton Scale " & Uuid)
RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave
End Sub
@@ -145,11 +163,14 @@
'务必放在 IsMouseDown 更新之后
Private Const AnimationColorIn As Integer = 120
Private Const AnimationColorOut As Integer = 150
Public Sub RefreshColor() Handles PanClick.MouseEnter, PanClick.MouseLeave, Me.Loaded
Public Sub RefreshColor() Handles PanClick.MouseEnter, PanClick.MouseLeave, Me.Loaded, Me.IsEnabledChanged
Try
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
If IsMouseOver Then
If Not IsEnabled Then
'禁用
AniStart(AaColor(PanColor, BackgroundProperty, "ColorBrushGray4", AnimationColorIn), "MyExtraButton Color " & Uuid)
ElseIf IsMouseOver Then
'指向
AniStart(AaColor(PanColor, BackgroundProperty, "ColorBrush4", AnimationColorIn), "MyExtraButton Color " & Uuid)
Else
@@ -160,8 +181,10 @@
Else
AniStop("MyExtraButton Color " & Uuid)
If IsMouseOver Then
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush2")
If Not IsEnabled Then
PanColor.SetResourceReference(BackgroundProperty, "ColorBrushGray4")
ElseIf IsMouseOver Then
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush4")
Else
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush3")
End If
@@ -0,0 +1,33 @@
<Grid
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
x:Name="PanBack" mc:Ignorable="d" x:Class="MyExtraTextButton"
RenderTransformOrigin="0.5,0.5" ToolTipService.Placement="Left" Height="52" Margin="20">
<Grid.RenderTransform>
<ScaleTransform ScaleX="0" ScaleY="0" />
</Grid.RenderTransform>
<Border x:Name="PanClick" BorderThickness="0.001" Background="{StaticResource ColorBrushSemiTransparent}"
CornerRadius="{Binding ActualHeight, ConverterParameter=0.4, Converter={StaticResource MultiplicationConverter}, ElementName=PanBack, Mode=OneWay}"/>
<Grid x:Name="PanScale" IsHitTestVisible="False" RenderTransformOrigin="0.5,0.5" Margin="0,10,0,0">
<Grid.RenderTransform>
<ScaleTransform />
</Grid.RenderTransform>
<Border x:Name="PanColor" BorderThickness="0.001" Background="{DynamicResource ColorBrush3}"
CornerRadius="{Binding ActualHeight, ConverterParameter=0.4, Converter={StaticResource MultiplicationConverter}, ElementName=PanBack, Mode=OneWay}">
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="10" Opacity="0.2" />
</Border.Effect>
</Border>
<StackPanel Orientation="Horizontal" Margin="20,0" SnapsToDevicePixels="False" UseLayoutRounding="False">
<Path x:Name="Path" Stretch="Uniform" Margin="2,12,0,12" Fill="{DynamicResource ColorBrush8}" RenderTransformOrigin="0.5,0.5">
<Path.RenderTransform>
<ScaleTransform />
</Path.RenderTransform>
</Path>
<TextBlock x:Name="LabText" VerticalAlignment="Center" Foreground="{DynamicResource ColorBrush8}" FontSize="16"
Margin="12,0,0,0.8" />
</StackPanel>
</Grid>
</Grid>
@@ -0,0 +1,163 @@
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyExtraTextButton
'声明
Public Event Click(sender As Object, e As MouseButtonEventArgs) '自定义事件
'自定义属性
Public Uuid As Integer = GetUuid()
Private _Logo As String = ""
Public Property Logo As String
Get
Return _Logo
End Get
Set(value As String)
If value = _Logo Then Return
_Logo = value
Path.Data = (New GeometryConverter).ConvertFromString(value)
End Set
End Property
Private _LogoScale As Double = 1
Public Property LogoScale() As Double
Get
Return _LogoScale
End Get
Set(value As Double)
_LogoScale = value
If Path IsNot Nothing Then Path.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}
End Set
End Property
'显示文本
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabText.Inlines
End Get
End Property
Public Property Text As String
Get
Return GetValue(TextProperty)
End Get
Set(value As String)
SetValue(TextProperty, value)
End Set
End Property
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyExtraTextButton), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If sender IsNot Nothing Then CType(sender, MyExtraTextButton).LabText.Text = e.NewValue
End Sub)))
'动画
Private _Show As Boolean = False
Public Property Show As Boolean
Get
Return _Show
End Get
Set(value As Boolean)
If _Show = value Then Return
_Show = value
RunInUi(
Sub()
If value Then
'有了
Opacity = 0
AniStart({
AaOpacity(Me, 1 - Opacity, 80, 50),
AaScaleTransform(Me, 0.15 - CType(RenderTransform, ScaleTransform).ScaleX, 400, 50, New AniEaseOutBack),
AaScaleTransform(Me, 0.85, 160, 50, New AniEaseOutFluent(AniEasePower.Middle))
}, "MyExtraTextButton MainScale " & Uuid)
Else
'没了
AniStart({
AaOpacity(Me, -Opacity, 50, 50),
AaScaleTransform(Me, -CType(RenderTransform, ScaleTransform).ScaleX, 100,, New AniEaseInFluent(AniEasePower.Weak))
}, "MyExtraTextButton MainScale " & Uuid)
End If
IsHitTestVisible = value '防止缩放动画中依然可以点进去
End Sub)
End Set
End Property
'触发点击事件
Private Sub Button_LeftMouseUp(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonUp
If IsLeftMouseHeld Then
Log("[Control] 按下附加图标按钮:" & Text)
RaiseEvent Click(sender, e)
e.Handled = True
Button_LeftMouseUp()
End If
End Sub
'鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行)
Private IsLeftMouseHeld As Boolean = False
Private Sub Button_LeftMouseDown(sender As Object, e As MouseButtonEventArgs) Handles PanClick.MouseLeftButtonDown
If Not IsLeftMouseHeld Then
AniStart({
AaScaleTransform(PanScale, 0.85 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 800,, New AniEaseOutFluent(AniEasePower.Strong)),
AaScaleTransform(PanScale, -0.05, 60,, New AniEaseOutFluent)
}, "MyExtraTextButton Scale " & Uuid)
End If
IsLeftMouseHeld = True
Focus()
End Sub
Private Sub Button_LeftMouseUp() Handles PanClick.MouseLeftButtonUp
AniStart({
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack)
}, "MyExtraTextButton Scale " & Uuid)
IsLeftMouseHeld = False
RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave
End Sub
Private Sub Button_RightMouseUp() Handles PanClick.MouseRightButtonUp
If Not IsLeftMouseHeld Then
AniStart({
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 300,, New AniEaseOutBack)
}, "MyExtraTextButton Scale " & Uuid)
End If
RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave
End Sub
Private Sub Button_MouseLeave() Handles PanClick.MouseLeave
IsLeftMouseHeld = False
AniStart({
AaScaleTransform(PanScale, 1 - CType(PanScale.RenderTransform, ScaleTransform).ScaleX, 500,, New AniEaseOutFluent)
}, "MyExtraTextButton Scale " & Uuid)
RefreshColor() '直接刷新颜色以判断是否已触发 MouseLeave
End Sub
'自定义事件
'务必放在 IsMouseDown 更新之后
Private Const AnimationColorIn As Integer = 120
Private Const AnimationColorOut As Integer = 150
Public Sub RefreshColor() Handles PanClick.MouseEnter, PanClick.MouseLeave, Me.Loaded, Me.IsEnabledChanged
Try
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
If Not IsEnabled Then
'禁用
AniStart(AaColor(PanColor, BackgroundProperty, "ColorBrushGray4", AnimationColorIn), "MyExtraTextButton Color " & Uuid)
ElseIf IsMouseOver Then
'指向
AniStart(AaColor(PanColor, BackgroundProperty, "ColorBrush4", AnimationColorIn), "MyExtraTextButton Color " & Uuid)
Else
'普通
AniStart(AaColor(PanColor, BackgroundProperty, "ColorBrush3", AnimationColorOut), "MyExtraTextButton Color " & Uuid)
End If
Else
AniStop("MyExtraTextButton Color " & Uuid)
If Not IsEnabled Then
PanColor.SetResourceReference(BackgroundProperty, "ColorBrushGray4")
ElseIf IsMouseOver Then
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush4")
Else
PanColor.SetResourceReference(BackgroundProperty, "ColorBrush3")
End If
End If
Catch ex As Exception
Log(ex, "刷新附加图标按钮颜色出错")
End Try
End Sub
End Class
+4 -12
View File
@@ -3,22 +3,14 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
FocusVisualStyle="{x:Null}"
UseLayoutRounding="True" SnapsToDevicePixels="True" HorizontalAlignment="Stretch" BorderThickness="1" BorderBrush="#99FF4444" CornerRadius="3">
<Border.Background>
<LinearGradientBrush EndPoint="1,0.5" StartPoint="0,0.5">
<GradientStop x:Name="Gradient1" Color="#88FFBBBB" Offset="0.3"/>
<GradientStop x:Name="Gradient2" Color="#88FF8888" Offset="0.9"/>
</LinearGradientBrush>
</Border.Background>
UseLayoutRounding="True" SnapsToDevicePixels="True" HorizontalAlignment="Stretch" BorderThickness="3,0,0,0" BorderBrush="#99FF4444" CornerRadius="2">
<Grid UseLayoutRounding="False" SnapsToDevicePixels="False">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Path IsHitTestVisible="False" Grid.Column="0" x:Name="Path" VerticalAlignment="Center" Fill="#BF0000" Width="14" Stretch="Uniform" Margin="10,0,2,0" Data="F1 M 58.5832,55.4172L 17.4169,55.4171C 15.5619,53.5621 15.5619,50.5546 17.4168,48.6996L 35.201,15.8402C 37.056,13.9852 40.0635,13.9852 41.9185,15.8402L 58.5832,48.6997C 60.4382,50.5546 60.4382,53.5622 58.5832,55.4172 Z M 34.0417,25.7292L 36.0208,41.9584L 39.9791,41.9583L 41.9583,25.7292L 34.0417,25.7292 Z M 38,44.3333C 36.2511,44.3333 34.8333,45.7511 34.8333,47.5C 34.8333,49.2489 36.2511,50.6667 38,50.6667C 39.7489,50.6667 41.1666,49.2489 41.1666,47.5C 41.1666,45.7511 39.7489,44.3333 38,44.3333 Z " />
<TextBlock IsHitTestVisible="False" Grid.Column="1" x:Name="LabText" Margin="0,0.5,0,0" Padding="6,6,8,6" Text="提示文本" VerticalAlignment="Center" Foreground="#BF0000" TextWrapping="Wrap" />
<local:MyIconButton x:Name="BtnClose" SnapsToDevicePixels="True" Visibility="Collapsed" Foreground="#BF0000" Theme="Custom" Margin="0,0,6,0" Grid.Column="2" Height="20" Width="20" VerticalAlignment="Center" Logo="F1 M 26.9166,22.1667L 37.9999,33.25L 49.0832,22.1668L 53.8332,26.9168L 42.7499,38L 53.8332,49.0834L 49.0833,53.8334L 37.9999,42.75L 26.9166,53.8334L 22.1666,49.0833L 33.25,38L 22.1667,26.9167L 26.9166,22.1667 Z"
ToolTip="不再显示" ToolTipService.Placement="Center" ToolTipService.VerticalOffset="29" ToolTipService.HorizontalOffset="2" />
<TextBlock IsHitTestVisible="False" x:Name="LabText" LineHeight="16" Margin="0,0,0,-1" Padding="12,9" VerticalAlignment="Center" TextWrapping="Wrap" />
<local:MyIconButton x:Name="BtnClose" Visibility="Collapsed" Theme="Custom" Margin="0,0,8,0" Grid.Column="1" Height="20" Width="20" VerticalAlignment="Center" Logo="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z"
ToolTip="不再提示" ToolTipService.Placement="Center" ToolTipService.VerticalOffset="29" ToolTipService.HorizontalOffset="2" />
</Grid>
</Border>
+126 -45
View File
@@ -1,82 +1,163 @@
Public Class MyHint
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyHint
Public Uuid As Integer = GetUuid()
Private _IsWarn As Boolean = True
Public Property IsWarn As Boolean
'边框
Public Property HasBorder As Boolean
Get
Return _IsWarn
Return BorderThickness.Top > 0
End Get
Set(value As Boolean)
If _IsWarn = value Then Exit Property
_IsWarn = value
If _IsWarn Then
BorderBrush = New MyColor("#99FF4444")
Gradient1.Color = New MyColor("#88FFBBBB")
Gradient2.Color = New MyColor("#88FF8888")
Path.Fill = New MyColor("#BF0000")
LabText.Foreground = New MyColor("#BF0000")
BtnClose.Foreground = New MyColor("#BF0000")
Path.Data = (New GeometryConverter).ConvertFromString("F1 M 58.5832,55.4172L 17.4169,55.4171C 15.5619,53.5621 15.5619,50.5546 17.4168,48.6996L 35.201,15.8402C 37.056,13.9852 40.0635,13.9852 41.9185,15.8402L 58.5832,48.6997C 60.4382,50.5546 60.4382,53.5622 58.5832,55.4172 Z M 34.0417,25.7292L 36.0208,41.9584L 39.9791,41.9583L 41.9583,25.7292L 34.0417,25.7292 Z M 38,44.3333C 36.2511,44.3333 34.8333,45.7511 34.8333,47.5C 34.8333,49.2489 36.2511,50.6667 38,50.6667C 39.7489,50.6667 41.1666,49.2489 41.1666,47.5C 41.1666,45.7511 39.7489,44.3333 38,44.3333 Z ")
If value Then
BorderThickness = New Thickness(3, GetWPFSize(1), GetWPFSize(1), GetWPFSize(1))
Else
BorderBrush = New MyColor("#994D76FF")
Gradient1.Color = New MyColor("#88B0D0FF")
Gradient2.Color = New MyColor("#889EBAFF")
Path.Fill = New MyColor("#0062BF")
LabText.Foreground = New MyColor("#0062BF")
BtnClose.Foreground = New MyColor("#0062BF")
Path.Data = (New GeometryConverter).ConvertFromString("F1M38,19C48.4934,19 57,27.5066 57,38 57,48.4934 48.4934,57 38,57 27.5066,57 19,48.4934 19,38 19,27.5066 27.5066,19 38,19z M33.25,33.25L33.25,36.4167 36.4166,36.4167 36.4166,47.5 33.25,47.5 33.25,50.6667 44.3333,50.6667 44.3333,47.5 41.1666,47.5 41.1666,36.4167 41.1666,33.25 33.25,33.25z M38.7917,25.3333C37.48,25.3333 36.4167,26.3967 36.4167,27.7083 36.4167,29.02 37.48,30.0833 38.7917,30.0833 40.1033,30.0833 41.1667,29.02 41.1667,27.7083 41.1667,26.3967 40.1033,25.3333 38.7917,25.3333z")
BorderThickness = New Thickness(3, 0, 0, 0)
End If
End Set
End Property
Public Property Text As String
'配色
Public Enum Themes
Blue = 0
Red = 1
Yellow = 2
End Enum
Public Property Theme As Themes
Get
Return LabText.Text
Return _ColorType
End Get
Set(ByVal value As String)
LabText.Text = value
Set(value As Themes)
_ColorType = value
UpdateUI()
End Set
End Property
Private _ColorType As Themes = Themes.Red
Private Sub UpdateUI() Handles Me.Loaded
Select Case Theme
Case Themes.Blue
Background = New MyColor("#d9ecff")
BorderBrush = New MyColor("#1172D4")
LabText.Foreground = New MyColor("#0F64B8")
BtnClose.Foreground = New MyColor("#0F64B8")
Case Themes.Red
Background = New MyColor("#ffdddf")
BorderBrush = New MyColor("#d82929")
LabText.Foreground = New MyColor("#bf0b0b")
BtnClose.Foreground = New MyColor("#bf0b0b")
Case Themes.Yellow
Background = New MyColor("#ffebd7")
BorderBrush = New MyColor("#f57a00")
LabText.Foreground = New MyColor("#d86c00")
BtnClose.Foreground = New MyColor("#d86c00")
End Select
End Sub
<Obsolete("IsWarn 已过时。请换用 Theme 属性。")>
Public Property IsWarn As Boolean
Get
Return Theme = Themes.Red
End Get
Set(value As Boolean)
Theme = If(value, Themes.Red, Themes.Blue)
End Set
End Property
Public Shared ReadOnly IsWarnProperty As DependencyProperty =
DependencyProperty.Register("IsWarn", GetType(Boolean), GetType(MyHint), New PropertyMetadata(True,
Sub(d As MyHint, e As DependencyPropertyChangedEventArgs)
d.Theme = If(e.NewValue, Themes.Red, Themes.Blue)
End Sub))
'文本
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabText.Inlines
End Get
End Property
Public Property Text As String
Get
Return GetValue(TextProperty)
End Get
Set(value As String)
SetValue(TextProperty, value)
End Set
End Property
Public Shared ReadOnly TextProperty As DependencyProperty =
DependencyProperty.Register("Text", GetType(String), GetType(MyHint), New PropertyMetadata("",
Sub(d As MyHint, e As DependencyPropertyChangedEventArgs)
d.LabText.Text = e.NewValue
End Sub))
'关闭按钮
Public Property CanClose As Boolean
Get
Return BtnClose.Visibility = Visibility.Visible
End Get
Set(ByVal value As Boolean)
Set(value As Boolean)
BtnClose.Visibility = If(value, Visibility.Visible, Visibility.Collapsed)
End Set
End Property
Public RelativeSetup As String = ""
Public Property RelativeSetup As String = ""
Private Sub MyHint_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
If CanClose AndAlso Setup.Get(RelativeSetup) Then
Visibility = Visibility.Collapsed
End If
If CanClose AndAlso Setup.Get(RelativeSetup) Then Visibility = Visibility.Collapsed
End Sub
Private Sub BtnClose_Click(sender As Object, e As EventArgs) Handles BtnClose.Click
Setup.Set(RelativeSetup, True)
AniDispose(Me, False)
End Sub
'触发点击事件
Private IsMouseDown As Boolean = False
Private Sub MyHint_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If Not IsMouseDown Then Return
IsMouseDown = False
Log("[Control] 按下提示条" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
e.Handled = True
ModEvent.TryStartEvent(EventType, EventData)
End Sub
Private Sub MyHint_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
IsMouseDown = True
End Sub
Private Sub MyHint_MouseLeave() Handles Me.MouseLeave
IsMouseDown = False
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyHint), New PropertyMetadata(Nothing))
Public Property EventData As String
Get
Return GetValue(EventDataProperty)
End Get
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyHint), New PropertyMetadata(Nothing))
End Class
Partial Public Module ModAnimation
Public Sub AniDispose(Control As MyHint, RemoveFromChildren As Boolean, Optional CallBack As ParameterizedThreadStart = Nothing)
If Not Control.IsHitTestVisible Then Exit Sub
If Not Control.IsHitTestVisible Then Return
Control.IsHitTestVisible = False
AniStart({
AaScaleTransform(Control, -0.08, 200,, New AniEaseInFluent),
AaOpacity(Control, -1, 200,, New AniEaseOutFluent),
AaHeight(Control, -Control.ActualHeight, 150, 100, New AniEaseOutFluent),
AaCode(Sub()
If RemoveFromChildren Then
CType(Control.Parent, Object).Children.Remove(Control)
Else
Control.Visibility = Visibility.Collapsed
End If
If CallBack IsNot Nothing Then CallBack(Control)
End Sub,, True)
}, "MyCard Dispose " & Control.Uuid)
AaScaleTransform(Control, -0.08, 200,, New AniEaseInFluent),
AaOpacity(Control, -1, 200,, New AniEaseOutFluent),
AaHeight(Control, -Control.ActualHeight, 150, 100, New AniEaseOutFluent),
AaCode(
Sub()
If RemoveFromChildren Then
CType(Control.Parent, Object).Children.Remove(Control)
Else
Control.Visibility = Visibility.Collapsed
End If
If CallBack IsNot Nothing Then CallBack(Control)
End Sub,, True)
}, "MyCard Dispose " & Control.Uuid)
End Sub
End Module
@@ -1,7 +1,7 @@
Public Class MyIconButton
'声明
Public Event Click(sender As Object, e As EventArgs) '自定义事件
'自定义事件
Public Event Click(sender As Object, e As EventArgs)
'自定义属性
@@ -30,6 +30,7 @@
Color
White
Black
Red
Custom
End Enum
Public Property Theme As Themes = Themes.Color
@@ -49,13 +50,31 @@
'触发点击事件
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonUp
If IsMouseDown Then
Log("[Control] 按下图标按钮" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
RaiseEvent Click(sender, e)
e.Handled = True
Button_MouseUp()
End If
If Not IsMouseDown Then Return
Log("[Control] 按下图标按钮" & If(String.IsNullOrEmpty(Name), "", ":" & Name))
RaiseEvent Click(sender, e)
e.Handled = True
Button_MouseUp()
ModEvent.TryStartEvent(EventType, EventData)
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyIconButton), New PropertyMetadata(Nothing))
Public Property EventData As String
Get
Return GetValue(EventDataProperty)
End Get
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyIconButton), New PropertyMetadata(Nothing))
'鼠标点击判定(务必放在点击事件之后,以使得 Button_MouseUp 先于 Button_MouseLeave 执行)
Private IsMouseDown As Boolean = False
@@ -92,7 +111,16 @@
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
If PanBack.Background Is Nothing Then PanBack.Background = New MyColor(0, 255, 255, 255)
If Path.Fill Is Nothing AndAlso Theme = Themes.Black Then Path.Fill = New MyColor(140, 0, 0, 0)
If Path.Fill Is Nothing Then
Select Case Theme
Case Themes.Red
Path.Fill = New MyColor(160, 255, 76, 76)
Case Themes.Black
Path.Fill = New MyColor(160, 0, 0, 0)
Case Themes.Custom
Path.Fill = New MyColor(160, Foreground)
End Select
End If
If IsMouseOver Then
'指向
Dim AnimList As New List(Of AniData)
@@ -101,6 +129,8 @@
AnimList.Add(AaColor(Path, Shape.FillProperty, "ColorBrush2", AnimationColorIn))
Case Themes.White
AnimList.Add(AaColor(PanBack, BackgroundProperty, New MyColor(50, 255, 255, 255) - PanBack.Background, AnimationColorIn))
Case Themes.Red
AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(255, 76, 76) - Path.Fill, AnimationColorIn))
Case Themes.Black
AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(230, 0, 0, 0) - Path.Fill, AnimationColorIn))
Case Themes.Custom
@@ -117,6 +147,9 @@
Case Themes.White
AnimList.Add(AaColor(Path, Shape.FillProperty, "ColorBrush8", AnimationColorOut))
AnimList.Add(AaColor(PanBack, BackgroundProperty, New MyColor(0, 255, 255, 255) - PanBack.Background, AnimationColorOut))
Case Themes.Red
AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(160, 255, 76, 76) - Path.Fill, AnimationColorOut))
PanBack.Background = New MyColor(0, 255, 255, 255)
Case Themes.Black
AnimList.Add(AaColor(Path, Shape.FillProperty, New MyColor(160, 0, 0, 0) - Path.Fill, AnimationColorOut))
PanBack.Background = New MyColor(0, 255, 255, 255)
@@ -135,6 +168,8 @@
Path.SetResourceReference(Shape.FillProperty, "ColorBrush5")
Case Themes.White
Path.SetResourceReference(Shape.FillProperty, "ColorBrush8")
Case Themes.Red
Path.Fill = New MyColor(160, 255, 76, 76)
Case Themes.Black
Path.Fill = New MyColor(160, 0, 0, 0)
Case Themes.Custom
@@ -151,7 +186,7 @@
End Class
Partial Public Module ModAnimation
Public Sub AniDispose(Control As MyIconButton, RemoveFromChildren As Boolean, Optional CallBack As ParameterizedThreadStart = Nothing)
If Not Control.IsHitTestVisible Then Exit Sub
If Not Control.IsHitTestVisible Then Return
Control.IsHitTestVisible = False
AniStart({
AaScaleTransform(Control, -1.5, 200,, New AniEaseInFluent),
@@ -0,0 +1,9 @@
<Border x:Name="PanBack" x:Class="MyIconTextButton"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
HorizontalAlignment="Center" VerticalAlignment="Center" Background="{StaticResource ColorBrushSemiTransparent}" CornerRadius="13.5" MinHeight="27" MaxHeight="27">
<StackPanel Orientation="Horizontal">
<Path x:Name="ShapeLogo" HorizontalAlignment="Left" RenderTransformOrigin="0.5,0.5" Margin="12,0,0,0" Stretch="Uniform" Fill="White" MaxHeight="16" MaxWidth="16" VerticalAlignment="Center" />
<TextBlock x:Name="LabText" VerticalAlignment="Center" Grid.Column="1" Foreground="White" Margin="7,0,12,1" Grid.ColumnSpan="2" SnapsToDevicePixels="False" UseLayoutRounding="False" />
</StackPanel>
</Border>
@@ -0,0 +1,194 @@
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyIconTextButton
'基础
Public Uuid As Integer = GetUuid()
Public Event Check(sender As Object, raiseByMouse As Boolean)
Public Event Change(sender As Object, raiseByMouse As Boolean)
Public Sub RaiseChange()
RaiseEvent Change(Me, False)
End Sub '使外部程序可以引发本控件的 Change 事件
'自定义属性
Public Property Logo As String
Get
Return ShapeLogo.Data.ToString
End Get
Set(value As String)
ShapeLogo.Data = (New GeometryConverter).ConvertFromString(value)
End Set
End Property
Private _LogoScale As Double = 1
Public Property LogoScale() As Double
Get
Return _LogoScale
End Get
Set(value As Double)
_LogoScale = value
If Not IsNothing(ShapeLogo) Then ShapeLogo.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale}
End Set
End Property
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabText.Inlines
End Get
End Property
Public Property Text As String
Get
Return GetValue(TextProperty)
End Get
Set(value As String)
SetValue(TextProperty, value)
End Set
End Property '内容
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If Not IsNothing(sender) Then CType(sender, MyIconTextButton).LabText.Text = e.NewValue
End Sub)))
Public Enum ColorState
Black
Highlight
End Enum
Public Property ColorType As ColorState
Get
Return GetValue(ColorTypeProperty)
End Get
Set(value As ColorState)
If ColorType = value Then Return
SetValue(ColorTypeProperty, value)
RefreshColor()
End Set
End Property '颜色类别
Public Shared ReadOnly ColorTypeProperty As DependencyProperty =
DependencyProperty.Register("ColorType", GetType(ColorState), GetType(MyIconTextButton), New PropertyMetadata(ColorState.Black))
'点击事件
Public Event Click(sender As Object, e As RouteEventArgs)
Private IsMouseDown As Boolean = False
Private Sub MyIconTextButton_MouseUp() Handles Me.MouseLeftButtonUp
If Not IsMouseDown Then Return
Log("[Control] 按下带图标按钮:" & Text)
IsMouseDown = False
RaiseEvent Click(Me, New RouteEventArgs(True))
ModEvent.TryStartEvent(EventType, EventData)
RefreshColor()
End Sub
Private Sub MyIconTextButton_MouseDown() Handles Me.MouseLeftButtonDown
IsMouseDown = True
RefreshColor()
End Sub
Private Sub MyIconTextButton_MouseLeave() Handles Me.MouseLeave
IsMouseDown = False
RefreshColor()
End Sub
Public Property EventType As String
Get
Return GetValue(EventTypeProperty)
End Get
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(Nothing))
Public Property EventData As String
Get
Return GetValue(EventDataProperty)
End Get
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyIconTextButton), New PropertyMetadata(Nothing))
'动画
Private Const AnimationTimeOfMouseIn As Integer = 100 '鼠标指向动画长度
Private Const AnimationTimeOfMouseOut As Integer = 150 '鼠标移出动画长度
Private Sub RefreshColor(Optional obj = Nothing, Optional e = Nothing) Handles Me.MouseEnter, Me.Loaded, Me.IsEnabledChanged
Try
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not False.Equals(e) Then '防止默认属性变更触发动画,若强制不执行动画,则 e 为 False
Select Case ColorType
Case ColorState.Black
If IsMouseDown Then
'按下
AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", 70), "MyIconTextButton Color " & Uuid)
ElseIf IsMouseOver Then
'指向
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, "ColorBrushBg1", AnimationTimeOfMouseIn), "MyIconTextButton Color " & Uuid)
ElseIf IsEnabled Then
'正常
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush1", AnimationTimeOfMouseOut),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush1", AnimationTimeOfMouseOut)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
Else
'禁用
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrushGray5", 100),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrushGray5", 100)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
End If
Case ColorState.Highlight
If IsMouseDown Then
'按下
AniStart(AaColor(Me, BackgroundProperty, "ColorBrush6", 70), "MyIconTextButton Color " & Uuid)
ElseIf IsMouseOver Then
'指向
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseIn),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, "ColorBrushBg1", AnimationTimeOfMouseIn), "MyIconTextButton Color " & Uuid)
ElseIf IsEnabled Then
'正常
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrush3", AnimationTimeOfMouseOut),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseOut)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
Else
'禁用
AniStart({
AaColor(ShapeLogo, Shapes.Path.FillProperty, "ColorBrushGray5", 100),
AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrushGray5", 100)
}, "MyIconTextButton Checked " & Uuid)
AniStart(AaColor(Me, BackgroundProperty, ColorSemiTransparent - Background, AnimationTimeOfMouseOut), "MyIconTextButton Color " & Uuid)
End If
End Select
Else
'不使用动画
AniStop("MyIconTextButton Checked " & Uuid)
AniStop("MyIconTextButton Color " & Uuid)
Select Case ColorType
Case ColorState.Black
Background = ColorSemiTransparent
ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray5"))
Case ColorState.Highlight
Background = ColorSemiTransparent
ShapeLogo.SetResourceReference(Shapes.Path.FillProperty, If(IsEnabled, "ColorBrush3", "ColorBrushGray5"))
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush3", "ColorBrushGray5"))
End Select
End If
Catch ex As Exception
Log(ex, "刷新带图标按钮颜色出错")
End Try
End Sub
End Class
+189
View File
@@ -0,0 +1,189 @@
Public Class MyImage
Inherits Image
#Region "公开属性"
''' <summary>
''' 网络图片的缓存有效期。
''' 在这个时间后,才会重新尝试下载图片。
''' </summary>
Public FileCacheExpiredTime As New TimeSpan(7, 0, 0, 0) '7 天
''' <summary>
''' 是否允许将网络图片存储到本地用作缓存。
''' </summary>
Public Property EnableCache As Boolean
Get
Return GetValue(EnableCacheProperty)
End Get
Set(value As Boolean)
SetValue(EnableCacheProperty, value)
End Set
End Property
Public Shared Shadows ReadOnly EnableCacheProperty As DependencyProperty = DependencyProperty.Register(
"EnableCache", GetType(Boolean), GetType(MyImage), New PropertyMetadata(True))
''' <summary>
''' 与 Image 的 Source 类似。
''' 若输入以 http 开头的字符串,则会尝试下载图片然后显示,图片会保存为本地缓存。
''' 支持 WebP 格式的图片。
''' </summary>
Public Shadows Property Source As String '覆写 Image 的 Source 属性
Get
Return _Source
End Get
Set(value As String)
If value = "" Then value = Nothing
If _Source = value Then Return
_Source = value
If Not IsInitialized Then Return '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868)
Load()
End Set
End Property
Private _Source As String = ""
Public Shared Shadows ReadOnly SourceProperty As DependencyProperty = DependencyProperty.Register(
"Source", GetType(String), GetType(MyImage), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyImage).Source = e.NewValue.ToString())))
''' <summary>
''' 当 Source 首次下载失败时,会从该备用地址加载图片。
''' </summary>
Public Property FallbackSource As String
Get
Return _FallbackSource
End Get
Set(value As String)
_FallbackSource = value
End Set
End Property
Private _FallbackSource As String = Nothing
''' <summary>
''' 正在下载网络图片时显示的本地图片。
''' </summary>
Public Property LoadingSource As String
Get
Return _LoadingSource
End Get
Set(value As String)
_LoadingSource = value
End Set
End Property
Private _LoadingSource As String = "pack://application:,,,/images/Icons/NoIcon.png"
#End Region
''' <summary>
''' 实际被呈现的图片地址。
''' </summary>
Public Property ActualSource As String
Get
Return _ActualSource
End Get
Set(value As String)
If value = "" Then value = Nothing
If _ActualSource = value Then Return
_ActualSource = value
Try
Dim Bitmap As MyBitmap = If(value Is Nothing, Nothing, New MyBitmap(value)) '在这里先触发可能的文件读取,尽量避免在 UI 线程中读取文件
RunInUiWait(Sub() MyBase.Source = Bitmap)
Catch ex As Exception
Log(ex, $"加载图片失败({value})")
Try
If value.StartsWithF(PathTemp) AndAlso File.Exists(value) Then File.Delete(value)
Catch
End Try
End Try
End Set
End Property
Private _ActualSource As String = Nothing
Private Sub Load() _
Handles Me.Initialized '属性读取顺序修正:在完成 XAML 属性读取后再触发图片加载(#4868)
'空
If Source Is Nothing Then
ActualSource = Nothing
Return
End If
'本地图片
If Not Source.StartsWithF("http") Then
ActualSource = Source
Return
End If
'从缓存加载网络图片
Dim Url As String = Source
Dim Retried As Boolean = False
Dim TempPath As String = GetTempPath(Url)
Dim TempFile As New FileInfo(TempPath)
Dim EnableCache As Boolean = Me.EnableCache
If EnableCache AndAlso TempFile.Exists Then
ActualSource = TempPath
If (Date.Now - TempFile.LastWriteTime) < FileCacheExpiredTime Then Return '无需刷新缓存
End If
RunInNewThread(
Sub()
Dim TempDownloadingPath As String = Nothing
Try
RetryStart:
'下载
ActualSource = LoadingSource '显示加载中图片
TempDownloadingPath = TempPath & RandomInteger(0, 10000000)
Directory.CreateDirectory(GetPathFromFullPath(TempPath)) '重新实现下载,以避免携带 Header(#5072)
Using Client As New Net.WebClient
Client.DownloadFile(Url, TempDownloadingPath)
End Using
If Url <> Source AndAlso Url <> FallbackSource Then
'已经更换了地址
File.Delete(TempDownloadingPath)
ElseIf EnableCache Then
'保存缓存并显示
If File.Exists(TempPath) Then File.Delete(TempPath)
FileSystem.Rename(TempDownloadingPath, TempPath)
RunInUi(Sub() ActualSource = TempPath)
Else
'直接显示
RunInUiWait(Sub() ActualSource = TempDownloadingPath)
File.Delete(TempDownloadingPath)
End If
Catch ex As Exception
Try
If TempPath IsNot Nothing Then File.Delete(TempPath)
If TempDownloadingPath IsNot Nothing Then File.Delete(TempDownloadingPath)
Catch
End Try
If Not Retried Then
'更换备用地址
Log(ex, $"下载图片可重试地失败({Url})", LogLevel.Developer)
Retried = True
Url = If(FallbackSource, Source)
'空
If Url Is Nothing Then
ActualSource = Nothing
Return
End If
'本地图片
If Not Url.StartsWithF("http") Then
ActualSource = Url
Return
End If
'从缓存加载网络图片
TempPath = GetTempPath(Url)
TempFile = New FileInfo(TempPath)
If EnableCache AndAlso TempFile.Exists() Then
ActualSource = TempPath
If (Date.Now - TempFile.CreationTime) < FileCacheExpiredTime Then Return '无需刷新缓存
End If
'下载
If Source = Url Then Thread.Sleep(1000) '延迟 1s 重试
GoTo RetryStart
Else
Log(ex, $"下载图片失败({Url})", LogLevel.Hint)
End If
End Try
End Sub, "MyImage PicLoader " & GetUuid() & "#", ThreadPriority.BelowNormal)
End Sub
Public Shared Function GetTempPath(Url As String) As String
Return $"{PathTemp}MyImage\{GetHash(Url)}.png"
End Function
End Class
@@ -11,7 +11,7 @@
<ColumnDefinition x:Name="ColumnPaddingLeft" Width="0" />
<ColumnDefinition x:Name="ColumnLogo" Width="4" />
<ColumnDefinition Width="1*"/>
<ColumnDefinition x:Name="ColumnPaddingRight" Width="0" />
<ColumnDefinition x:Name="ColumnPaddingRight" Width="4" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
+117 -111
View File
@@ -1,4 +1,7 @@
Public Class MyListItem
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyListItem
Implements IMyRadio
Public Event Click(sender As Object, e As MouseButtonEventArgs)
@@ -15,7 +18,7 @@
If _RectBack Is Nothing Then
Dim Rect As New Border With {
.Name = "RectBack",
.CornerRadius = New CornerRadius(If(IsScaleAnimationEnabled, 6, 0)),
.CornerRadius = New CornerRadius(If(IsScaleAnimationEnabled OrElse Height > 40, 6, 0)),
.RenderTransform = If(IsScaleAnimationEnabled, New ScaleTransform(0.8, 0.8), Nothing),
.RenderTransformOrigin = New Point(0.5, 0.5),
.BorderThickness = New Thickness(GetWPFSize(1)),
@@ -104,42 +107,34 @@
ColumnPaddingLeft.Width = New GridLength(value)
End Set
End Property
Public Property PaddingRight As Integer
Get
Return ColumnPaddingRight.Width.Value
End Get
Set(value As Integer)
ColumnPaddingRight.Width = New GridLength(value)
End Set
End Property
''' <summary>
''' 右边距的最小值。
''' 在存在右侧按钮时,右边距会被自动设置为 5 + 按钮数 * 25。
''' </summary>
Public Property MinPaddingRight As Integer = 4
'按钮
Private _Buttons As IEnumerable
Public Property Buttons As IEnumerable
Private _Buttons As IEnumerable(Of MyIconButton)
Public Property Buttons As IEnumerable(Of MyIconButton)
Get
Return _Buttons
End Get
Set(value As IEnumerable)
Set(value As IEnumerable(Of MyIconButton))
_Buttons = value
'没有特殊按钮,移除原 Stack
If Not IsNothing(ButtonStack) Then
If ButtonStack IsNot Nothing Then
Children.Remove(ButtonStack)
ButtonStack = Nothing
End If
'获取按钮数量
Dim Count As Integer = 0
For Each Counter In value
Count += 1
Next
'添加新 Stack
Select Case Count
Select Case value.Count
Case 0
'没有按钮,不添加新的
Case 1
'只有一个按钮
For Each Btn As MyIconButton In value
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 23
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 23
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
With Btn
.Opacity = 0
.Margin = New Thickness(0, 0, 5, 0)
@@ -149,22 +144,18 @@
.SnapsToDevicePixels = False
.UseLayoutRounding = False
End With
SetColumn(Btn, 4)
SetColumnSpan(Btn, 4)
SetRowSpan(Btn, 4)
SetColumnSpan(Btn, 10) : SetRowSpan(Btn, 10)
Children.Add(Btn)
ButtonStack = Btn
Next
Case Else
'有复数按钮,使用 StackPanel
ButtonStack = New StackPanel With {.Opacity = 0, .Margin = New Thickness(0, 0, 5, 0), .SnapsToDevicePixels = False, .Orientation = Orientation.Horizontal, .HorizontalAlignment = HorizontalAlignment.Right, .VerticalAlignment = VerticalAlignment.Center, .UseLayoutRounding = False}
SetColumn(ButtonStack, 4)
SetColumnSpan(ButtonStack, 4)
SetRowSpan(ButtonStack, 4)
SetColumnSpan(ButtonStack, 10) : SetRowSpan(ButtonStack, 10)
'构造按钮
For Each Btn As MyIconButton In value
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 23
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 23
If Btn.Height.Equals(Double.NaN) Then Btn.Height = 25
If Btn.Width.Equals(Double.NaN) Then Btn.Width = 25
CType(ButtonStack, StackPanel).Children.Add(Btn)
Next
Children.Add(ButtonStack)
@@ -173,12 +164,17 @@
End Property
'标题
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabTitle.Inlines
End Get
End Property
Public Property Title As String
Get
Return GetValue(TitleProperty)
End Get
Set(value As String)
SetValue(TitleProperty, value)
SetValue(TitleProperty, value.Replace(vbCr, "").Replace(vbLf, ""))
End Set
End Property
Public Shared ReadOnly TitleProperty As DependencyProperty = DependencyProperty.Register("Title", GetType(String), GetType(MyListItem))
@@ -201,7 +197,7 @@
Return _Info
End Get
Set(value As String)
If _Info = value Then Exit Property
If _Info = value Then Return
value = value.Replace(vbCr, "").Replace(vbLf, "")
_Info = value
LabInfo.Text = value
@@ -216,42 +212,38 @@
Return _Logo
End Get
Set(value As String)
If _Logo = value Then Exit Property
If _Logo = value Then Return
_Logo = value
'删除旧 Logo
If Not IsNothing(PathLogo) Then Children.Remove(PathLogo)
'添加新 Logo
If Not _Logo = "" Then
If _Logo.ToLower.StartsWith("http") Then
If _Logo.StartsWithF("http", True) Then
'网络图片
PathLogo = New Image With {
PathLogo = New MyImage With {
.Tag = Me,
.IsHitTestVisible = LogoClickable,
.Source = New ImageSourceConverter().ConvertFromString(_Logo),
.Source = _Logo,
.RenderTransformOrigin = New Point(0.5, 0.5),
.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale},
.SnapsToDevicePixels = True, .UseLayoutRounding = False}
RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.Linear)
ElseIf _Logo.ToLower.EndsWith(".png") Then
ElseIf _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) OrElse _Logo.EndsWithF(".webp", True) Then
'位图
Dim Bitmap = New MyBitmap(_Logo)
PathLogo = New Canvas With {
.Tag = Me,
.IsHitTestVisible = LogoClickable,
.Background = Bitmap,
.Background = New MyBitmap(_Logo),
.RenderTransformOrigin = New Point(0.5, 0.5),
.RenderTransform = New ScaleTransform With {.ScaleX = LogoScale, .ScaleY = LogoScale},
.SnapsToDevicePixels = True, .UseLayoutRounding = False}
'If Bitmap.Pic.Width = 16 AndAlso Bitmap.Pic.Height = 16 Then
' '使用最适合 16x16 物品图片显示的大小
' RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.NearestNeighbor)
' PathLogo.HorizontalAlignment = HorizontalAlignment.Center : PathLogo.VerticalAlignment = VerticalAlignment.Center
' PathLogo.Width = GetWPFSize(Math.Floor(GetPixelSize(32) / 16) * 16) : PathLogo.Height = PathLogo.Width
'Else
PathLogo.HorizontalAlignment = HorizontalAlignment.Stretch : PathLogo.VerticalAlignment = VerticalAlignment.Stretch
RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.HighQuality)
'End If
.SnapsToDevicePixels = True, .UseLayoutRounding = False,
.HorizontalAlignment = HorizontalAlignment.Stretch, .VerticalAlignment = VerticalAlignment.Stretch
}
RenderOptions.SetBitmapScalingMode(PathLogo, BitmapScalingMode.Linear)
Else
'矢量图
PathLogo = New Shapes.Path With {
.Tag = Me,
.IsHitTestVisible = LogoClickable, .HorizontalAlignment = HorizontalAlignment.Center, .VerticalAlignment = VerticalAlignment.Center, .Stretch = Stretch.Uniform,
.Data = (New GeometryConverter).ConvertFromString(_Logo),
.RenderTransformOrigin = New Point(0.5, 0.5),
@@ -267,7 +259,7 @@
If LogoClickable Then
AddHandler PathLogo.MouseLeave, Sub(sender, e) IsLogoDown = False
AddHandler PathLogo.MouseLeftButtonDown, Sub(sender, e) IsLogoDown = True
AddHandler PathLogo.MouseLeftButtonUp, Sub(sender, e) If IsLogoDown Then IsLogoDown = False : RaiseEvent LogoClick(sender, e)
AddHandler PathLogo.MouseLeftButtonUp, Sub(sender, e) If IsLogoDown Then IsLogoDown = False : RaiseEvent LogoClick(sender.Tag, e)
End If
End If
'改变行距
@@ -286,6 +278,9 @@
End Property
'图标的点击
''' <summary>
''' 该 Logo 是否可用点击触发事件。需要在 Logo 属性之前设置。
''' </summary>
Public Property LogoClickable As Boolean = False
Private IsLogoDown As Boolean = False
@@ -302,7 +297,7 @@
Return _Type
End Get
Set(value As CheckType)
If _Type = value Then Exit Property
If _Type = value Then Return
_Type = value
'切换左栏大小
ColumnCheck.Width = New GridLength(If(_Type = CheckType.None OrElse _Type = CheckType.Clickable, If(Height < 40, 4, 2), 6))
@@ -318,7 +313,8 @@
'添加竖条控件
If IsNothing(RectCheck) Then
RectCheck = New Border With {.Width = 5, .Height = If(Checked, Double.NaN, 0), .CornerRadius = New CornerRadius(2, 2, 2, 2),
.VerticalAlignment = If(Checked, VerticalAlignment.Stretch, VerticalAlignment.Center), .HorizontalAlignment = HorizontalAlignment.Left, .UseLayoutRounding = False, .SnapsToDevicePixels = False,
.VerticalAlignment = If(Checked, VerticalAlignment.Stretch, VerticalAlignment.Center),
.HorizontalAlignment = HorizontalAlignment.Left, .UseLayoutRounding = False, .SnapsToDevicePixels = False,
.Margin = If(Checked, New Thickness(-1, 6, 0, 6), New Thickness(-1, 0, 0, 0))}
RectCheck.SetResourceReference(Border.BackgroundProperty, "ColorBrush3")
SetRowSpan(RectCheck, 4)
@@ -332,8 +328,8 @@
Private Sub OnSizeChanged() Handles Me.SizeChanged
ColumnCheck.Width = New GridLength(If(_Type = CheckType.None OrElse _Type = CheckType.Clickable, If(Height < 40, 4, 2), 6))
ColumnLogo.Width = New GridLength(If(_Logo = "", 0, 34) + If(Height < 40, 0, 4))
If Not IsNothing(PathLogo) Then
If _Logo.EndsWith(".png") Then
If PathLogo IsNot Nothing Then
If _Logo.EndsWithF(".png", True) OrElse _Logo.EndsWithF(".jpg", True) OrElse _Logo.EndsWithF(".webp", True) Then
PathLogo.Margin = New Thickness(4, 5, 3, 5)
Else
PathLogo.Margin = New Thickness(If(Height < 40, 6, 8), 8, If(Height < 40, 4, 6), 8)
@@ -349,7 +345,7 @@
Return _Checked
End Get
Set(value As Boolean)
SetChecked(value, False, True)
SetChecked(value, False, value <> _Checked) '仅在值发生变化时触发动画 (#4596)
End Set
End Property
''' <summary>
@@ -371,31 +367,31 @@
RaiseEvent Changed(Me, ChangedEventArgs)
If ChangedEventArgs.Handled Then
_Checked = RawValue
Exit Sub
Return
End If
End If
_Checked = value
Else
If value = _Checked Then Exit Sub
If value = _Checked Then Return
_Checked = value
If IsInitialized Then
RaiseEvent Changed(Me, ChangedEventArgs)
If ChangedEventArgs.Handled Then
_Checked = RawValue
Exit Sub
Return
End If
End If
End If
If value Then
Dim CheckEventArgs As New RouteEventArgs(user)
RaiseEvent Check(Me, CheckEventArgs)
If CheckEventArgs.Handled Then Exit Sub
If CheckEventArgs.Handled Then Return
End If
'保证只有一个单选 ListItem 选中
If Type = CheckType.RadioBox Then
If IsNothing(Parent) Then Exit Sub
If IsNothing(Parent) Then Return
Dim RadioboxList As New List(Of MyListItem)
Dim CheckedCount As Integer = 0
'收集控件列表与选中个数
@@ -447,7 +443,7 @@
RectCheck.VerticalAlignment = VerticalAlignment.Center
RectCheck.Margin = New Thickness(-1, 0, 0, 0)
End If
Anim.Add(AaColor(Me, ForegroundProperty, "ColorBrush3", 200))
Anim.Add(AaColor(Me, ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"), 200))
Else
'由有变无
If Not IsNothing(RectCheck) Then
@@ -461,17 +457,16 @@
AniStart(Anim, "MyListItem Checked " & Uuid)
Else
'不使用动画
AniStop("MyListItem Checked " & Uuid)
If Checked Then
'If Not IsNothing(RectCheck) Then RectCheck.Width = 4
If Not IsNothing(RectCheck) Then
RectCheck.Height = Double.NaN
RectCheck.Margin = New Thickness(-1, 6, 0, 6)
RectCheck.Opacity = 1
RectCheck.VerticalAlignment = VerticalAlignment.Stretch
End If
SetResourceReference(ForegroundProperty, "ColorBrush3")
SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
Else
'If Not IsNothing(RectCheck) Then RectCheck.Width = 0
If Not IsNothing(RectCheck) Then
RectCheck.Height = 0
RectCheck.Margin = New Thickness(-1, 0, 0, 0)
@@ -507,31 +502,26 @@
'触发点击事件
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
If IsMouseDown Then
RaiseEvent Click(sender, e)
If e.Handled Then Exit Sub
'触发自定义事件
If Not String.IsNullOrEmpty(EventType) Then
ModEvent.TryStartEvent(EventType, EventData)
e.Handled = True
End If
If e.Handled Then Exit Sub
'实际的单击处理
Select Case Type
Case CheckType.Clickable
Log("[Control] 按下单击列表项:" & Title)
Case CheckType.RadioBox
Log("[Control] 按下单选列表项:" & Title)
If Not Checked Then SetChecked(True, True, True)
Case CheckType.CheckBox
Log("[Control] 按下复选列表项(" & (Not Checked).ToString & "):" & Title)
SetChecked(Not Checked, True, True)
End Select
If Not IsMouseDown Then Return
RaiseEvent Click(sender, e)
If e.Handled Then Return
'触发自定义事件
If Not String.IsNullOrEmpty(EventType) Then
ModEvent.TryStartEvent(EventType, EventData)
e.Handled = True
End If
'AniStart({
' AaScaleTransform(Me, 1.004 - CType(RenderTransform, ScaleTransform).ScaleX, 150,, New AniEaseOutFluent),
' AaScaleTransform(Me, -0.004, 100, 150, New AniEaseInFluent)
' }, "MyListItem Scale " & Uuid)
If e.Handled Then Return
'实际的单击处理
Select Case Type
Case CheckType.Clickable
Log("[Control] 按下单击列表项:" & Title)
Case CheckType.RadioBox
Log("[Control] 按下单选列表项:" & Title)
If Not Checked Then SetChecked(True, True, True)
Case CheckType.CheckBox
Log("[Control] 按下复选列表项(" & (Not Checked).ToString & "):" & Title)
SetChecked(Not Checked, True, True)
End Select
End Sub
'鼠标点击判定
@@ -539,15 +529,12 @@
Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
If IsMouseDirectlyOver AndAlso Not Type = CheckType.None Then
IsMouseDown = True
If Not IsNothing(ButtonStack) Then ButtonStack.IsHitTestVisible = False
If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = False
End If
'AniStart({
' AaScaleTransform(Me, 0.985 - CType(RenderTransform, ScaleTransform).ScaleX, 50,, New AniEaseOutFluent)
' }, "MyListItem Scale " & Uuid)
End Sub
Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
IsMouseDown = False
If Not IsNothing(ButtonStack) Then ButtonStack.IsHitTestVisible = True
If ButtonStack IsNot Nothing Then ButtonStack.IsHitTestVisible = True
End Sub
'实现自定义事件
@@ -594,16 +581,20 @@
Time = 180
End If
End If
If StateLast = StateNew Then Exit Sub
If StateLast = StateNew Then Return
StateLast = StateNew
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
Dim Ani As New List(Of AniData)
If IsMouseOver AndAlso IsMouseOverAnimationEnabled Then
If ButtonStack IsNot Nothing Then Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
If ButtonStack IsNot Nothing Then
Ani.Add(AaOpacity(ButtonStack, 1 - ButtonStack.Opacity, Time * 0.7, Time * 0.3))
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
Math.Max(MinPaddingRight, 5 + Buttons.Count * 25) - ColumnPaddingRight.Width.Value, Time * 0.3, Time * 0.7))
End If
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush9"), Time),
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
})
If IsScaleAnimationEnabled Then
@@ -615,32 +606,44 @@
End If
End If
Else
If ButtonStack IsNot Nothing Then Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.5))
If ButtonStack IsNot Nothing Then
Ani.Add(AaOpacity(ButtonStack, -ButtonStack.Opacity, Time * 0.4))
Ani.Add(AaDouble(Sub(i) ColumnPaddingRight.Width = New GridLength(Math.Max(0, ColumnPaddingRight.Width.Value + i)),
MinPaddingRight - ColumnPaddingRight.Width.Value, Time * 0.4))
End If
Ani.Add(AaOpacity(RectBack, -RectBack.Opacity, Time))
If IsScaleAnimationEnabled Then Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
AaScaleTransform(Me, 1 - CType(Me.RenderTransform, ScaleTransform).ScaleX, Time * 3,, New AniEaseOutFluent),
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
AaScaleTransform(RectBack, -0.246, 1,,, True)
})
If IsScaleAnimationEnabled Then
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush7"), Time),
AaScaleTransform(Me, 1 - CType(RenderTransform, ScaleTransform).ScaleX, Time * 3,, New AniEaseOutFluent),
AaScaleTransform(RectBack, 0.996 - CType(RectBack.RenderTransform, ScaleTransform).ScaleX, Time,, New AniEaseOutFluent),
AaScaleTransform(RectBack, -0.246, 1,,, True)
})
End If
End If
AniStart(Ani, "ListItem Color " & Uuid)
Else
'无动画
If IsMouseOver AndAlso IsMouseOverAnimationEnabled Then
If ButtonStack IsNot Nothing Then ButtonStack.Opacity = 1
If ButtonStack IsNot Nothing Then
ButtonStack.Opacity = 1
ColumnPaddingRight.Width = New GridLength(Math.Max(MinPaddingRight, 5 + Buttons.Count * 25))
End If
'由于鼠标已经移入,所以直接实例化 RectBack
RectBack.Background = Color9
RectBack.Background = ColorBg1
RectBack.Opacity = 1
RectBack.RenderTransform = New ScaleTransform(1, 1)
Me.RenderTransform = New ScaleTransform(1, 1)
Else
If ButtonStack IsNot Nothing Then ButtonStack.Opacity = 0
If ButtonStack IsNot Nothing Then
ButtonStack.Opacity = 0
ColumnPaddingRight.Width = New GridLength(MinPaddingRight)
End If
Me.RenderTransform = New ScaleTransform(1, 1)
If _RectBack IsNot Nothing Then
If IsScaleAnimationEnabled Then RectBack.Background = Color7
If IsScaleAnimationEnabled Then RectBack.RenderTransform = New ScaleTransform(0.75, 0.75)
RectBack.Background = Color7
RectBack.Opacity = 0
RectBack.RenderTransform = New ScaleTransform(0.75, 0.75)
End If
End If
AniStop("ListItem Color " & Uuid)
@@ -649,15 +652,18 @@
Private Sub MyListItem_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
If Checked Then
SetResourceReference(ForegroundProperty, "ColorBrush3")
SetResourceReference(ForegroundProperty, If(Height < 40, "ColorBrush3", "ColorBrush2"))
Else
SetResourceReference(ForegroundProperty, "ColorBrush1")
End If
If EventType = "打开帮助" Then
ColumnPaddingRight.Width = New GridLength(MinPaddingRight)
If EventType = "打开帮助" AndAlso Not (Title <> "" AndAlso Info <> "") Then '#3266
Try
Dim NewElem = New HelpEntry(GetEventAbsoluteUrls(EventData, EventType)(0)).SetToListItem(Me)
Dim Unused = New HelpEntry(GetEventAbsoluteUrls(EventData, EventType)(0)).SetToListItem(Me)
Catch ex As Exception
Log(ex, "设置帮助 MyListItem 失败", LogLevel.Msgbox)
EventType = Nothing
EventData = Nothing
End Try
End If
End Sub
@@ -35,7 +35,7 @@ Public Class MyLoading
Return _ShowProgress
End Get
Set(value As Boolean)
If _ShowProgress = value Then Exit Property
If _ShowProgress = value Then Return
_ShowProgress = value
RefreshText()
End Set
@@ -46,7 +46,7 @@ Public Class MyLoading
Get
Return _Text
End Get
Set(ByVal value As String)
Set(value As String)
_Text = value
RefreshText()
End Set
@@ -57,7 +57,7 @@ Public Class MyLoading
Get
Return _TextError
End Get
Set(ByVal value As String)
Set(value As String)
_TextError = value
RefreshText()
End Set
@@ -67,29 +67,35 @@ Public Class MyLoading
''' </summary>
Public Property TextErrorInherit As Boolean = True
Private Sub RefreshText() Handles Me.IsErrorChanged, Me.Loaded
If InnerState = MyLoadingState.Error Then
If TextErrorInherit AndAlso State.IsLoader Then
Dim Ex As Exception = CType(State, Object).Error
If Ex Is Nothing Then
LabText.Text = "未知错误"
Private Sub RefreshText() Handles Me.IsErrorChanged, Me.Loaded, _State.ProgressChanged
RunInUi(
Sub()
If InnerState = MyLoadingState.Error Then
If TextErrorInherit AndAlso State.IsLoader Then
Dim Ex As Exception = CType(State, Object).Error
If Ex Is Nothing Then
LabText.Text = "未知错误"
Else
Do While Ex.InnerException IsNot Nothing
Ex = Ex.InnerException
Loop
LabText.Text = StrTrim(Ex.Message)
If {"远程主机强迫关闭了", "远程方已关闭传输流", "未能解析此远程名称", "由于目标计算机积极拒绝",
"操作已超时", "操作超时", "服务器超时", "连接超时"}.Any(Function(s) LabText.Text.Contains(s)) Then
LabText.Text = "网络环境不佳,请稍后重试,或使用 VPN 以改善网络环境"
End If
End If
Else
Do While Ex.InnerException IsNot Nothing
Ex = Ex.InnerException
Loop
LabText.Text = StrTrim(Ex.Message)
If LabText.Text.Contains("远程主机强迫关闭了一个现有的连接") OrElse LabText.Text.Contains("操作已超时") OrElse LabText.Text.Contains("操作超时") OrElse LabText.Text.Contains("服务器超时") OrElse LabText.Text.Contains("连接超时") Then LabText.Text = "网络环境不佳,请重试或尝试使用 VPN"
LabText.Text = TextError
End If
Else
LabText.Text = TextError
If ShowProgress AndAlso State.IsLoader Then
LabText.Text = Text & " - " & Math.Floor(CType(State, Object).Progress * 100) & "%"
Else
LabText.Text = Text
End If
End If
Else
If ShowProgress AndAlso State.IsLoader Then
LabText.Text = Text & " - " & Math.Floor(CType(State, Object).Progress * 100) & "%"
Else
LabText.Text = Text
End If
End If
End Sub)
End Sub
#End Region
@@ -136,7 +142,7 @@ Public Class MyLoading
Return _OuterState
End Get
Set(value As MyLoadingState)
If _OuterState = value Then Exit Property
If _OuterState = value Then Return
Dim OldValue = _OuterState
_OuterState = value
'引发事件
@@ -153,7 +159,7 @@ Public Class MyLoading
Return _InnerState
End Get
Set(value As MyLoadingState)
If _InnerState = value Then Exit Property
If _InnerState = value Then Return
Dim OldValue = _InnerState
_InnerState = value
'引发事件
@@ -177,49 +183,10 @@ Public Class MyLoading
Private IsLooping As Boolean = False
Private Sub AniLoop()
'这坨循环代码也是老屎坑了,救救.jpg
If Not HasAnimation OrElse IsLooping OrElse Not InnerState = MyLoadingState.Run OrElse AniSpeed > 10 OrElse Not IsLoaded Then Exit Sub
If Not HasAnimation OrElse IsLooping OrElse Not InnerState = MyLoadingState.Run OrElse AniSpeed > 10 OrElse Not IsLoaded Then Return
IsLooping = True
ErrorAnimationWaiting = True
If ShowProgress Then
RefreshText()
AniStart({
AaRotateTransform(PathPickaxe, -20 - CType(PathPickaxe.RenderTransform, RotateTransform).Angle, 350, 250, New AniEaseInBack(AniEasePower.Weak)),
AaCode(AddressOf RefreshText, 100), '这是为了省下一个 Timer 线程……
AaCode(AddressOf RefreshText, 200),
AaCode(AddressOf RefreshText, 300),
AaCode(AddressOf RefreshText, 400),
AaCode(AddressOf RefreshText, 500),
AaRotateTransform(PathPickaxe, 50, 900,, New AniEaseOutFluent, True),
AaRotateTransform(PathPickaxe, 25, 900,, New AniEaseOutElastic(AniEasePower.Weak)),
AaCode(Sub()
PathLeft.Opacity = 1
PathLeft.Margin = New Thickness(7, 41, 0, 0)
PathRight.Opacity = 1
PathRight.Margin = New Thickness(14, 41, 0, 0)
ErrorAnimationWaiting = False
RefreshText()
End Sub),
AaCode(AddressOf RefreshText, 100),
AaCode(AddressOf RefreshText, 200),
AaCode(AddressOf RefreshText, 300),
AaCode(AddressOf RefreshText, 400),
AaCode(AddressOf RefreshText, 500),
AaCode(AddressOf RefreshText, 600),
AaCode(AddressOf RefreshText, 700),
AaCode(AddressOf RefreshText, 800),
AaOpacity(PathLeft, -1, 100, 70),
AaX(PathLeft, -5, 180, 20, New AniEaseOutFluent),
AaY(PathLeft, -6, 180, 20, New AniEaseOutFluent),
AaOpacity(PathRight, -1, 100, 70),
AaX(PathRight, 5, 180, 20, New AniEaseOutFluent),
AaY(PathRight, -6, 180, 20, New AniEaseOutFluent),
AaCode(Sub()
IsLooping = False
AniLoop()
End Sub,, True)
}, "MyLoader Loop " & Uuid & "/" & GetUuid())
Else
AniStart({
AniStart({
AaRotateTransform(PathPickaxe, -20 - CType(PathPickaxe.RenderTransform, RotateTransform).Angle, 350, 250, New AniEaseInBack(AniEasePower.Weak)),
AaRotateTransform(PathPickaxe, 50, 900,, New AniEaseOutFluent, True),
AaRotateTransform(PathPickaxe, 25, 900,, New AniEaseOutElastic(AniEasePower.Weak)),
@@ -241,6 +208,8 @@ Public Class MyLoading
AniLoop()
End Sub,, True)
}, "MyLoader Loop " & Uuid & "/" & GetUuid())
If ShowProgress Then
End If
End Sub
@@ -291,6 +260,7 @@ Public Interface ILoadingTrigger
ReadOnly Property IsLoader As Boolean
Property LoadingState As MyLoadingState
Event LoadingStateChanged(NewState As MyLoadingState, OldState As MyLoadingState)
Event ProgressChanged(NewProgress As Double, OldProgress As Double)
End Interface
Public Class MyLoadingStateSimulator
@@ -301,7 +271,7 @@ Public Class MyLoadingStateSimulator
Return _LoadingState
End Get
Set(value As MyLoadingState)
If _LoadingState = value Then Exit Property
If _LoadingState = value Then Return
Dim OldState = _LoadingState
_LoadingState = value
RaiseEvent LoadingStateChanged(value, OldState)
@@ -310,4 +280,5 @@ Public Class MyLoadingStateSimulator
Public ReadOnly Property IsLoader As Boolean = False Implements ILoadingTrigger.IsLoader
Public Event LoadingStateChanged(NewState As MyLoadingState, OldState As MyLoadingState) Implements ILoadingTrigger.LoadingStateChanged
Public Event ProgressChanged(NewProgress As Double, OldProgress As Double) Implements ILoadingTrigger.ProgressChanged
End Class
@@ -6,6 +6,8 @@
Dim IconControl As Shapes.Path = GetTemplateChild("Icon")
If IconControl IsNot Nothing Then IconControl.Data = (New GeometryConverter).ConvertFromString(Icon)
End If
'对父级设置透明度
CType(Parent, ContextMenu).Opacity = Setup.Get("UiLauncherTransparent") / 1000 + 0.4
End Sub
'基础
@@ -35,7 +37,7 @@
Time = AnimationTimeOut
End If
'重复性验证
If ColorName = BackName Then Exit Sub
If ColorName = BackName Then Return
ColorName = BackName
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
@@ -2,22 +2,38 @@
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:PCL"
UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="500" HorizontalAlignment="Center" VerticalAlignment="Center">
<Border Name="PanBorder" CornerRadius="5" Width="{Binding ActualWidth, ElementName=PanMain, Mode=OneWay}" Height="{Binding ActualHeight, ElementName=PanMain, Mode=OneWay}" Background="#00FBFBFB">
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="40" />
</TransformGroup>
</Grid.RenderTransform>
<Border Name="PanBorder" CornerRadius="7" Background="#FBFBFB">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="15" ShadowDepth="0" Opacity="0" x:Name="EffectShadow" />
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="20" ShadowDepth="4" RenderingBias="Performance" Opacity="0.8" x:Name="EffectShadow" />
</Border.Effect>
<Grid Name="PanMain" VerticalAlignment="Top" Margin="22,22,22,23">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="13" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="7,-1,70,9" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle x:Name="ShapeLine" Grid.Row="1" Height="2" Fill="{Binding Foreground, ElementName=LabTitle}" />
<my:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanText" Margin="0,0,0,7" Padding="7,0,15,0"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
<TextBlock VerticalAlignment="Top" TextTrimming="None" TextWrapping="Wrap" Name="LabText" FontSize="15" LineHeight="18"
Foreground="#FF5C5C5C" FontWeight="Normal" Padding="1" />
</my:MyScrollViewer>
<my:MyTextBox Grid.Row="4" Margin="7,0,7,12" x:Name="TextArea" UseLayoutRounding="False" MaxLength="1000" MinWidth="450" />
<StackPanel Grid.Row="5" Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,8,0" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Border>
<StackPanel Name="PanMain" VerticalAlignment="Top">
<TextBlock FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="27,19,28,0" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle Height="2" Fill="{DynamicResource ColorBrush2}" Margin="20,9,20,15" Name="ShapeLine" Opacity="0" />
<Border Name="PanCaption" Padding="28,0,28,15">
<my:MyTextBox x:Name="TextCaption" UseLayoutRounding="False" MaxLength="1000" Width="450" Margin="1" />
</Border>
<StackPanel Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,22,20" Orientation="Horizontal">
<my:MyButton ColorType="Normal" Text="测试按钮1" x:Name="Btn1" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" Text="测试按钮2" x:Name="Btn2" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" Text="测试按钮3" x:Name="Btn3" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
</StackPanel>
</StackPanel>
</Grid>
@@ -9,26 +9,21 @@
InitializeComponent()
Btn1.Name = Btn1.Name & GetUuid()
Btn2.Name = Btn2.Name & GetUuid()
Btn3.Name = Btn3.Name & GetUuid()
MyConverter = Converter
LabTitle.Text = Converter.Title
TextCaption.Text = Converter.Content
TextCaption.HintText = Converter.HintText
TextCaption.ValidateRules = Converter.ValidateRules
LabText.Text = Converter.Text
PanText.Visibility = If(Converter.Text = "", Visibility.Collapsed, Visibility.Visible)
TextArea.Text = Converter.Content
TextArea.HintText = Converter.HintText
TextArea.ValidateRules = Converter.ValidateRules
Btn1.Text = Converter.Button1
If Converter.IsWarn Then
Btn1.ColorType = MyButton.ColorState.Red
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrushRedLight")
ShapeLine.SetResourceReference(Rectangle.FillProperty, "ColorBrushRedLight")
End If
Btn2.Text = Converter.Button2
Btn3.Text = Converter.Button3
Btn2.Visibility = If(Converter.Button2 = "", Visibility.Collapsed, Visibility.Visible)
Btn3.Visibility = If(Converter.Button3 = "", Visibility.Collapsed, Visibility.Visible)
'If Converter.Caption > 0 Then
' TextCaption.Focus()
' TextCaption.Select(Converter.Caption.Length - 1, 0)
'End If
ShapeLine.StrokeThickness = GetWPFSize(1)
Catch ex As Exception
Log(ex, "输入弹窗初始化失败", LogLevel.Hint)
@@ -40,39 +35,16 @@
'UI 初始化
If Btn2.IsVisible AndAlso Not Btn1.ColorType = MyButton.ColorState.Red Then Btn1.ColorType = MyButton.ColorState.Highlight
ShapeLine.StrokeThickness = GetWPFSize(1)
Measure(New Size(FrmMain.Width, FrmMain.Height))
Arrange(New Rect(0, 0, FrmMain.Width, FrmMain.Height))
If FrmMain.Width - ActualWidth < 20 Then Width = FrmMain.Width - GetWPFSize(2)
TextCaption.Focus()
TextArea.Focus()
TextArea.SelectionStart = TextArea.Text.Length
'动画
Opacity = 0
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, If(MyConverter.IsWarn, New MyColor(140, 80, 0, 0), New MyColor(90, 0, 0, 0)) - FrmMain.PanMsg.Background, 200), "PanMsg Background")
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(60, 0, 0, 0), 250, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(255, 0, 0, 0), 150, , New AniEaseInFluent),
AaOpacity(EffectShadow, 0.75, 400, 50),
AaWidth(ShapeLine, ShapeLine.ActualWidth, 250, 100, New AniEaseOutFluent),
AaOpacity(ShapeLine, 1, 200, 100),
AaWidth(LabTitle, LabTitle.ActualWidth, 200, 100, New AniEaseOutFluent),
AaOpacity(LabTitle, 1, 150, 150),
AaOpacity(PanCaption, 1, 150, 150),
AaOpacity(Btn1, 1, 150, 100),
AaOpacity(Btn2, 1, 150, 150),
AaOpacity(Btn3, 1, 150, 200),
AaCode(Sub()
ShapeLine.MinWidth = ShapeLine.ActualWidth
ShapeLine.HorizontalAlignment = HorizontalAlignment.Stretch
ShapeLine.Width = Double.NaN
LabTitle.Width = Double.NaN
LabTitle.TextTrimming = TextTrimming.CharacterEllipsis
End Sub, 350)
}, "MyMsgBox Start " & Uuid)
'动画初始化
ShapeLine.Width = 0
ShapeLine.HorizontalAlignment = HorizontalAlignment.Center
LabTitle.Width = 0
LabTitle.Opacity = 0
LabTitle.TextWrapping = TextWrapping.NoWrap
PanCaption.Opacity = 0
AaOpacity(Me, 1, 120, 60),
AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 300, 60, New AniEaseOutBack(AniEasePower.Weak)),
AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak))
}, "MyMsgBox " & Uuid)
'记录日志
Log("[Control] 输入弹窗:" & LabTitle.Text)
@@ -84,46 +56,37 @@
'结束线程阻塞
MyConverter.WaitFrame.Continue = False
Interop.ComponentDispatcher.PopModal()
'弹窗动画
LabTitle.TextTrimming = TextTrimming.None
LabTitle.TextWrapping = TextWrapping.NoWrap
'动画
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(-60, 0, 0, 0), 350, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(-255, 0, 0, 0), 300, 100, New AniEaseInFluent),
AaOpacity(EffectShadow, -0.75, 150),
AaWidth(ShapeLine, -ShapeLine.ActualWidth, 250, , New AniEaseInFluent),
AaOpacity(ShapeLine, -1, 150, 100),
AaWidth(LabTitle, -LabTitle.ActualWidth, 250),
AaOpacity(LabTitle, -1, 200),
AaOpacity(PanCaption, -1, 200),
AaOpacity(Btn1, -1, 150),
AaOpacity(Btn2, -1, 150, 50),
AaOpacity(Btn3, -1, 150, 100),
AaCode(
Sub()
If Not WaitingMyMsgBox.Any() Then
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(0, 0, 0, 0) - FrmMain.PanMsg.Background, 200, Ease:=New AniEaseOutFluent(AniEasePower.Weak)))
End If
End Sub, 30),
AaOpacity(Me, -Opacity, 80, 20),
AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 150, 0, New AniEaseOutFluent),
AaDouble(Sub(i) TransformRotate.Angle += i, 6 - TransformRotate.Angle, 150, 0, New AniEaseInFluent(AniEasePower.Weak)),
AaCode(Sub() CType(Parent, Grid).Children.Remove(Me), , True)
}, "MyMsgBox Close " & Uuid)
}, "MyMsgBox " & Uuid)
End Sub
Public Sub Btn1_Click() Handles Btn1.Click
If MyConverter.IsExited OrElse Not TextCaption.ValidateResult = "" Then Exit Sub
TextArea.Validate() '#5773
If MyConverter.IsExited OrElse Not TextArea.IsValidated Then Return
MyConverter.IsExited = True
MyConverter.Result = TextCaption.Text
MyConverter.Result = TextArea.Text
Close()
End Sub
Private Sub Btn2_Click() Handles Btn2.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = Nothing
Close()
End Sub
Private Sub Btn3_Click() Handles Btn3.Click
If MyConverter.IsExited Then Exit Sub
Public Sub Btn2_Click() Handles Btn2.Click
If MyConverter.IsExited Then Return
MyConverter.IsExited = True
MyConverter.Result = Nothing
Close()
End Sub
Private Sub TextCaption_ValidateChanged(sender As Object, e As EventArgs) Handles TextCaption.ValidateChanged
Btn1.IsEnabled = TextCaption.ValidateResult = ""
Private Sub TextCaption_ValidateChanged(sender As Object, e As EventArgs) Handles TextArea.ValidateChanged
Btn1.IsEnabled = TextArea.IsValidated
End Sub
Private Sub Drag(sender As Object, e As MouseButtonEventArgs) Handles PanBorder.MouseLeftButtonDown, LabTitle.MouseLeftButtonDown
@@ -1,27 +1,36 @@
<Grid x:Name="PanBack" x:Class="MyMsgSelect"
<Grid x:Class="MyMsgSelect"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:PCL"
UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="450" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Name="PanBorder" Grid.RowSpan="99" Width="{Binding ActualWidth, ElementName=PanBack, Mode=OneWay}" Height="{Binding ActualHeight, ElementName=PanBack, Mode=OneWay}" Background="#00FBFBFB" CornerRadius="5">
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="40" />
</TransformGroup>
</Grid.RenderTransform>
<Border Name="PanBorder" CornerRadius="7" Background="#FBFBFB">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="15" ShadowDepth="0" Opacity="0" x:Name="EffectShadow" />
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="20" ShadowDepth="4" RenderingBias="Performance" Opacity="0.8" x:Name="EffectShadow" />
</Border.Effect>
<Grid Name="PanMain" VerticalAlignment="Top" Margin="22,22,22,23">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="13" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="7,-1,70,9" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle x:Name="ShapeLine" Grid.Row="1" Height="2" Fill="{Binding Foreground, ElementName=LabTitle}" />
<my:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanCaption" Margin="0,0,0,17" Padding="7,0,15,0"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
<StackPanel x:Name="PanSelection" Orientation="Vertical" />
</my:MyScrollViewer>
<StackPanel Grid.Row="4" Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,8,0" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Border>
<TextBlock FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="28,19,28,0" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle Height="2" Grid.Row="1" Fill="{DynamicResource ColorBrush2}" Margin="20,9,20,13" Name="ShapeLine" Opacity="0" />
<my:MyScrollViewer x:Name="PanCaption" Grid.Row="2" Margin="19,0,19,20" Padding="9,0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" SnapsToDevicePixels="True" UseLayoutRounding="True" DeltaMuity="0.5">
<StackPanel x:Name="PanSelection" Orientation="Vertical" />
</my:MyScrollViewer>
<StackPanel Name="PanBtn" Grid.Row="3" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,22,20" Orientation="Horizontal">
<my:MyButton ColorType="Normal" Text="测试按钮1" x:Name="Btn1" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" IsEnabled="False" />
<my:MyButton ColorType="Normal" Text="测试按钮2" x:Name="Btn2" Margin="15,0,0,0" TextPadding="7" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" Text="测试按钮3" x:Name="Btn3" TextPadding="7" Margin="15,0,0,0" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Grid>
@@ -9,20 +9,18 @@
InitializeComponent()
Btn1.Name = Btn1.Name & GetUuid()
Btn2.Name = Btn2.Name & GetUuid()
Btn3.Name = Btn3.Name & GetUuid()
MyConverter = Converter
LabTitle.Text = Converter.Title
Btn1.Text = Converter.Button1
If Converter.IsWarn Then
Btn1.ColorType = MyButton.ColorState.Red
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrushRedLight")
ShapeLine.SetResourceReference(Rectangle.FillProperty, "ColorBrushRedLight")
End If
Btn2.Text = Converter.Button2
Btn3.Text = Converter.Button3
Btn2.Visibility = If(Converter.Button2 = "", Visibility.Collapsed, Visibility.Visible)
Btn3.Visibility = If(Converter.Button3 = "", Visibility.Collapsed, Visibility.Visible)
ShapeLine.StrokeThickness = GetWPFSize(1)
'添加选择控件
Btn1.IsEnabled = False
For Each Selection As IMyRadio In Converter.Content
PanSelection.Children.Add(Selection)
AddHandler Selection.Check, AddressOf OnChecked
@@ -30,7 +28,7 @@
CType(Selection, MyListItem).Type = MyListItem.CheckType.RadioBox
CType(Selection, MyListItem).MinHeight = 24
Else
CType(Selection, MyRadioBox).MinHeight = 26
CType(Selection, MyRadioBox).MinHeight = 24
End If
Next
@@ -44,38 +42,14 @@
'UI 初始化
If Btn2.IsVisible AndAlso Not Btn1.ColorType = MyButton.ColorState.Red Then Btn1.ColorType = MyButton.ColorState.Highlight
ShapeLine.StrokeThickness = GetWPFSize(1)
Measure(New Size(FrmMain.Width, FrmMain.Height))
Arrange(New Rect(0, 0, FrmMain.Width, FrmMain.Height))
If FrmMain.Width - ActualWidth < 20 Then Width = FrmMain.Width - GetWPFSize(2)
'动画
Opacity = 0
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, If(MyConverter.IsWarn, New MyColor(140, 80, 0, 0), New MyColor(90, 0, 0, 0)) - FrmMain.PanMsg.Background, 200), "PanMsg Background")
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(60, 0, 0, 0), 250, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(255, 0, 0, 0), 150, , New AniEaseInFluent),
AaOpacity(EffectShadow, 0.75, 400, 50),
AaWidth(ShapeLine, ShapeLine.ActualWidth, 250, 100, New AniEaseOutFluent),
AaOpacity(ShapeLine, 1, 200, 100),
AaWidth(LabTitle, LabTitle.ActualWidth, 200, 100, New AniEaseOutFluent),
AaOpacity(LabTitle, 1, 150, 150),
AaOpacity(PanCaption, 1, 150, 150),
AaOpacity(Btn1, 1, 150, 100),
AaOpacity(Btn2, 1, 150, 150),
AaOpacity(Btn3, 1, 150, 200),
AaCode(Sub()
ShapeLine.MinWidth = ShapeLine.ActualWidth
ShapeLine.HorizontalAlignment = HorizontalAlignment.Stretch
ShapeLine.Width = Double.NaN
LabTitle.Width = Double.NaN
LabTitle.TextTrimming = TextTrimming.CharacterEllipsis
End Sub, 350)
}, "MyMsgBox Start " & Uuid)
'动画初始化
ShapeLine.Width = 0
ShapeLine.HorizontalAlignment = HorizontalAlignment.Center
LabTitle.Width = 0
LabTitle.Opacity = 0
LabTitle.TextWrapping = TextWrapping.NoWrap
PanCaption.Opacity = 0
AaOpacity(Me, 1, 120, 60),
AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 300, 60, New AniEaseOutBack(AniEasePower.Weak)),
AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak))
}, "MyMsgBox " & Uuid)
'记录日志
Log("[Control] 选择弹窗:" & LabTitle.Text)
@@ -87,39 +61,29 @@
'结束线程阻塞
MyConverter.WaitFrame.Continue = False
Interop.ComponentDispatcher.PopModal()
'弹窗动画
LabTitle.TextTrimming = TextTrimming.None
LabTitle.TextWrapping = TextWrapping.NoWrap
'动画
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(-60, 0, 0, 0), 350, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(-255, 0, 0, 0), 300, 100, New AniEaseInFluent),
AaOpacity(EffectShadow, -0.75, 150),
AaWidth(ShapeLine, -ShapeLine.ActualWidth, 250, , New AniEaseInFluent),
AaOpacity(ShapeLine, -1, 150, 100),
AaWidth(LabTitle, -LabTitle.ActualWidth, 250),
AaOpacity(LabTitle, -1, 200),
AaOpacity(PanCaption, -1, 200),
AaOpacity(Btn1, -1, 150),
AaOpacity(Btn2, -1, 150, 50),
AaOpacity(Btn3, -1, 150, 100),
AaCode(
Sub()
If Not WaitingMyMsgBox.Any() Then
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(0, 0, 0, 0) - FrmMain.PanMsg.Background, 200, Ease:=New AniEaseOutFluent(AniEasePower.Weak)))
End If
End Sub, 30),
AaOpacity(Me, -Opacity, 80, 20),
AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 150, 0, New AniEaseOutFluent),
AaDouble(Sub(i) TransformRotate.Angle += i, 6 - TransformRotate.Angle, 150, 0, New AniEaseInFluent(AniEasePower.Weak)),
AaCode(Sub() CType(Parent, Grid).Children.Remove(Me), , True)
}, "MyMsgBox Close " & Uuid)
}, "MyMsgBox " & Uuid)
End Sub
Public Sub Btn1_Click() Handles Btn1.Click
If MyConverter.IsExited OrElse SelectedIndex = -1 Then Exit Sub
If MyConverter.IsExited OrElse SelectedIndex = -1 Then Return
MyConverter.IsExited = True
MyConverter.Result = SelectedIndex
Close()
End Sub
Private Sub Btn2_Click() Handles Btn2.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = Nothing
Close()
End Sub
Private Sub Btn3_Click() Handles Btn3.Click
If MyConverter.IsExited Then Exit Sub
Public Sub Btn2_Click() Handles Btn2.Click
If MyConverter.IsExited Then Return
MyConverter.IsExited = True
MyConverter.Result = Nothing
Close()
@@ -1,27 +1,38 @@
<Grid x:Name="PanBack" x:Class="MyMsgText"
<Grid x:Class="MyMsgText"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:my="clr-namespace:PCL"
UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="450" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="20">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="Auto" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<Border Name="PanBorder" Grid.RowSpan="99" Background="#00FBFBFB" CornerRadius="5">
RenderTransformOrigin="0,0.5" UseLayoutRounding="True" SnapsToDevicePixels="True" MinWidth="400" HorizontalAlignment="Center" VerticalAlignment="Center" Margin="25">
<Grid.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="40" />
</TransformGroup>
</Grid.RenderTransform>
<Border Name="PanBorder" CornerRadius="7" Background="#FBFBFB">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="15" ShadowDepth="0" Opacity="0" x:Name="EffectShadow" />
<DropShadowEffect Color="{DynamicResource ColorObject1}" BlurRadius="20" ShadowDepth="4" RenderingBias="Performance" Opacity="0.8" x:Name="EffectShadow" />
</Border.Effect>
<Grid Name="PanMain" VerticalAlignment="Top" Margin="22,22,22,23">
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="2" />
<RowDefinition Height="13" />
<RowDefinition Height="1*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<TextBlock Grid.Row="0" FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="7,-1,70,9" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle x:Name="ShapeLine" Grid.Row="1" Height="2" Fill="{Binding Foreground, ElementName=LabTitle}" />
<my:MyScrollViewer Grid.Row="3" VerticalAlignment="Top" x:Name="PanCaption" Margin="0,0,0,17" Padding="7,0,15,0"
VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" DeltaMult="0.7">
<TextBlock VerticalAlignment="Top" TextTrimming="None" TextWrapping="Wrap" Name="LabCaption" FontSize="15" LineHeight="18"
Foreground="#FF5C5C5C" FontWeight="Normal" Padding="1" />
</my:MyScrollViewer>
<StackPanel Grid.Row="4" Name="PanBtn" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,8,0" Orientation="Horizontal">
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮1" x:Name="Btn1" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮2" x:Name="Btn2" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" x:FieldModifier="public" Text="测试按钮3" x:Name="Btn3" Margin="12,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
</Border>
<TextBlock FontSize="23" TextTrimming="None" Foreground="{DynamicResource ColorBrush2}" HorizontalAlignment="Left" Name="LabTitle" Margin="28,19,28,0" Text="测试标题文本" VerticalAlignment="Top" SnapsToDevicePixels="False" UseLayoutRounding="False" />
<Rectangle Height="2" Grid.Row="1" Fill="{DynamicResource ColorBrush2}" Margin="20,9,20,13" Name="ShapeLine" Opacity="0" />
<my:MyScrollViewer VerticalAlignment="Top" x:Name="PanCaption" Grid.Row="2" Margin="19,0,19,20" Padding="9,0" VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Disabled" SnapsToDevicePixels="True" UseLayoutRounding="True" DeltaMuity="0.5">
<TextBlock VerticalAlignment="Top" TextTrimming="None" TextWrapping="Wrap" Name="LabCaption" FontSize="15" Foreground="#FF5C5C5C" FontWeight="Normal" Padding="1" />
</my:MyScrollViewer>
<StackPanel Name="PanBtn" Grid.Row="3" VerticalAlignment="Top" HorizontalAlignment="Right" Margin="150,0,22,20" Orientation="Horizontal">
<my:MyButton ColorType="Normal" Text="测试按钮1" x:Name="Btn1" Margin="15,0,0,0" TextPadding="7" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" Text="测试按钮2" x:Name="Btn2" Margin="15,0,0,0" TextPadding="7" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
<my:MyButton ColorType="Normal" Text="测试按钮3" x:Name="Btn3" TextPadding="7" Margin="15,0,0,0" Visibility="Visible" SnapsToDevicePixels="False" Padding="5,0" Opacity="0" UseLayoutRounding="False" />
</StackPanel>
</Grid>
@@ -12,12 +12,11 @@
Btn3.Name = Btn3.Name & GetUuid()
MyConverter = Converter
LabTitle.Text = Converter.Title
LabCaption.Text = Converter.Content
LabCaption.Text = Converter.Text
Btn1.Text = Converter.Button1
If Converter.IsWarn Then
Btn1.ColorType = MyButton.ColorState.Red
LabTitle.SetResourceReference(TextBlock.ForegroundProperty, "ColorBrushRedLight")
ShapeLine.SetResourceReference(Rectangle.FillProperty, "ColorBrushRedLight")
End If
Btn2.Text = Converter.Button2
Btn3.Text = Converter.Button3
@@ -35,37 +34,15 @@
'UI 初始化
If Btn2.IsVisible AndAlso Not Btn1.ColorType = MyButton.ColorState.Red Then Btn1.ColorType = MyButton.ColorState.Highlight
Measure(New Size(FrmMain.Width - 20, FrmMain.Height - 20))
Arrange(New Rect(0, 0, FrmMain.Width - 20, FrmMain.Height - 20))
Btn1.Focus()
'动画
Opacity = 0
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, If(MyConverter.IsWarn, New MyColor(140, 80, 0, 0), New MyColor(90, 0, 0, 0)) - FrmMain.PanMsg.Background, 200), "PanMsg Background")
AniStart({
AaColor(FrmMain.PanMsg, BackgroundProperty, New MyColor(60, 0, 0, 0), 250, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(255, 0, 0, 0), 150, , New AniEaseInFluent),
AaOpacity(EffectShadow, 0.75, 400, 50),
AaWidth(ShapeLine, ShapeLine.ActualWidth, 250, 100, New AniEaseOutFluent),
AaOpacity(ShapeLine, 1, 200, 100),
AaWidth(LabTitle, LabTitle.ActualWidth, 200, 150, New AniEaseOutFluent),
AaOpacity(LabTitle, 1, 150, 150),
AaOpacity(PanCaption, 1, 150, 150),
AaOpacity(Btn1, 1, 150, 100),
AaOpacity(Btn2, 1, 150, 150),
AaOpacity(Btn3, 1, 150, 200),
AaCode(Sub()
ShapeLine.MinWidth = ShapeLine.ActualWidth
ShapeLine.HorizontalAlignment = HorizontalAlignment.Stretch
ShapeLine.Width = Double.NaN
LabTitle.Width = Double.NaN
LabTitle.TextTrimming = TextTrimming.CharacterEllipsis
End Sub, 350)
}, "MyMsgBox Start " & Uuid)
'动画初始化
ShapeLine.Width = 0
ShapeLine.HorizontalAlignment = HorizontalAlignment.Center
LabTitle.Width = 0
LabTitle.Opacity = 0
LabTitle.TextWrapping = TextWrapping.NoWrap
PanCaption.Opacity = 0
AaOpacity(Me, 1, 120, 60),
AaDouble(Sub(i) TransformPos.Y += i, -TransformPos.Y, 300, 60, New AniEaseOutBack(AniEasePower.Weak)),
AaDouble(Sub(i) TransformRotate.Angle += i, -TransformRotate.Angle, 300, 60, New AniEaseOutFluent(AniEasePower.Weak))
}, "MyMsgBox " & Uuid)
'记录日志
Log("[Control] 普通弹窗:" & LabTitle.Text & vbCrLf & LabCaption.Text)
@@ -77,44 +54,50 @@
'结束线程阻塞
If MyConverter.ForceWait OrElse Not MyConverter.Button2 = "" Then MyConverter.WaitFrame.Continue = False
Interop.ComponentDispatcher.PopModal()
'弹窗动画
LabTitle.TextTrimming = TextTrimming.None
LabTitle.TextWrapping = TextWrapping.NoWrap
'动画
AniStart({
AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(-60, 0, 0, 0), 350, , New AniEaseInFluent),
AaColor(PanBorder, Border.BackgroundProperty, New MyColor(-255, 0, 0, 0), 300, 100, New AniEaseInFluent),
AaOpacity(EffectShadow, -0.75, 150),
AaWidth(ShapeLine, -ShapeLine.ActualWidth, 250, , New AniEaseInFluent(AniEasePower.Weak)),
AaOpacity(ShapeLine, -1, 200),
AaWidth(LabTitle, -LabTitle.ActualWidth, 250),
AaOpacity(LabTitle, -1, 200),
AaOpacity(PanCaption, -1, 200),
AaOpacity(Btn1, -1, 150),
AaOpacity(Btn2, -1, 150, 50),
AaOpacity(Btn3, -1, 150, 100),
AaCode(
Sub()
If Not WaitingMyMsgBox.Any() Then
AniStart(AaColor(FrmMain.PanMsg, Grid.BackgroundProperty, New MyColor(0, 0, 0, 0) - FrmMain.PanMsg.Background, 200, Ease:=New AniEaseOutFluent(AniEasePower.Weak)))
End If
End Sub, 30),
AaOpacity(Me, -Opacity, 80, 20),
AaDouble(Sub(i) TransformPos.Y += i, 20 - TransformPos.Y, 150, 0, New AniEaseOutFluent),
AaDouble(Sub(i) TransformRotate.Angle += i, 6 - TransformRotate.Angle, 150, 0, New AniEaseInFluent(AniEasePower.Weak)),
AaCode(Sub() CType(Parent, Grid).Children.Remove(Me), , True)
}, "MyMsgBox Close " & Uuid)
'动画初始化
ShapeLine.MinWidth = 0
}, "MyMsgBox " & Uuid)
End Sub
Public Sub Btn1_Click() Handles Btn1.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = 1
Close()
If MyConverter.IsExited Then Return
If MyConverter.Button1Action IsNot Nothing Then
MyConverter.Button1Action()
Else
MyConverter.IsExited = True
MyConverter.Result = 1
Close()
End If
End Sub
Private Sub Btn2_Click() Handles Btn2.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = 2
Close()
Public Sub Btn2_Click() Handles Btn2.Click
If MyConverter.IsExited Then Return
If MyConverter.Button2Action IsNot Nothing Then
MyConverter.Button2Action()
Else
MyConverter.IsExited = True
MyConverter.Result = 2
Close()
End If
End Sub
Private Sub Btn3_Click() Handles Btn3.Click
If MyConverter.IsExited Then Exit Sub
MyConverter.IsExited = True
MyConverter.Result = 3
Close()
Public Sub Btn3_Click() Handles Btn3.Click
If MyConverter.IsExited Then Return
If MyConverter.Button3Action IsNot Nothing Then
MyConverter.Button3Action()
Else
MyConverter.IsExited = True
MyConverter.Result = 3
Close()
End If
End Sub
Private Sub Drag(sender As Object, e As MouseButtonEventArgs) Handles PanBorder.MouseLeftButtonDown, LabTitle.MouseLeftButtonDown
+36 -25
View File
@@ -29,21 +29,29 @@
'逐个进入动画
Dim AniList As New List(Of AniData)
Dim Id As Integer = 0, Delay As Integer = 0
Dim Controls = GetAllAnimControls()
For Each Element As FrameworkElement In Controls
Element.Opacity = 0
Element.RenderTransform = New TranslateTransform(-25, 0)
AniList.Add(AaOpacity(Element, If(TypeOf Element Is TextBlock, 0.6, 1), 200, Delay, New AniEaseOutFluent(AniEasePower.Weak)))
AniList.Add(AaTranslateX(Element, 5, 200, Delay, New AniEaseOutFluent))
AniList.Add(AaTranslateX(Element, 20, 300, Delay, New AniEaseOutBack(AniEasePower.Weak)))
If TypeOf Element Is MyListItem Then
AniList.Add(AaCode(Sub()
CType(Element, MyListItem).IsMouseOverAnimationEnabled = True
CType(Element, MyListItem).RefreshColor(Me, New EventArgs)
End Sub, Delay + 280))
For Each Element As FrameworkElement In GetAllAnimControls(True)
If Element.Visibility = Visibility.Collapsed Then
'还原之前的隐藏动画可能导致的改变(#2436)
Element.Opacity = 1
Element.RenderTransform = New TranslateTransform(0, 0)
If TypeOf Element Is MyListItem Then CType(Element, MyListItem).IsMouseOverAnimationEnabled = True
Else
Element.Opacity = 0
Element.RenderTransform = New TranslateTransform(-25, 0)
If TypeOf Element Is MyListItem Then CType(Element, MyListItem).IsMouseOverAnimationEnabled = False
AniList.Add(AaOpacity(Element, If(TypeOf Element Is TextBlock, 0.6, 1), 100, Delay, New AniEaseOutFluent(AniEasePower.Weak)))
AniList.Add(AaTranslateX(Element, 5, 200, Delay, New AniEaseOutFluent))
AniList.Add(AaTranslateX(Element, 20, 300, Delay, New AniEaseOutBack(AniEasePower.Weak)))
If TypeOf Element Is MyListItem Then
AniList.Add(AaCode(
Sub()
CType(Element, MyListItem).IsMouseOverAnimationEnabled = True
CType(Element, MyListItem).RefreshColor(Me, New EventArgs)
End Sub, Delay + 280))
End If
Delay += Math.Max(15 - Id, 7) * 2
Id += 1
End If
Delay += Math.Max(8, 20 - Id) * 2.5
Id += 1
Next
AniStart(AniList, "PageLeft PageChange " & Uuid)
End If
@@ -56,8 +64,8 @@
RenderTransformOrigin = New Point(0.5, 0.5)
End If
AniStart({
AaScaleTransform(Me, 0.95 - CType(RenderTransform, ScaleTransform).ScaleX, 130,, New AniEaseInFluent(AniEasePower.Weak)),
AaOpacity(Me, -Opacity, 100, 30)
AaScaleTransform(Me, 0.95 - CType(RenderTransform, ScaleTransform).ScaleX, 110,, New AniEaseInFluent(AniEasePower.Weak)),
AaOpacity(Me, -Opacity, 80, 30)
}, "PageLeft PageChange " & Uuid)
Else
'逐个退出动画
@@ -65,8 +73,8 @@
Dim Id As Integer = 0
Dim Controls = GetAllAnimControls()
For Each Element As FrameworkElement In Controls
AniList.Add(AaOpacity(Element, -Element.Opacity, 60, 80 / Controls.Count * Id))
AniList.Add(AaTranslateX(Element, -6, 60, 80 / Controls.Count * Id))
AniList.Add(AaOpacity(Element, -Element.Opacity, 50, 70 / Controls.Count * Id))
AniList.Add(AaTranslateX(Element, -6, 50, 70 / Controls.Count * Id))
Id += 1
Next
AniStart(AniList, "PageLeft PageChange " & Uuid)
@@ -74,23 +82,22 @@
End Sub
'遍历获取所有需要生成动画的控件
Private Function GetAllAnimControls() As List(Of FrameworkElement)
Private Function GetAllAnimControls(Optional IgnoreInvisibility As Boolean = False) As List(Of FrameworkElement)
Dim AllControls As New List(Of FrameworkElement)
GetAllAnimControls(AnimatedControl, AllControls)
GetAllAnimControls(AnimatedControl, AllControls, IgnoreInvisibility)
Return AllControls
End Function
Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement))
If Element.Visibility = Visibility.Collapsed Then Exit Sub
Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
If Not IgnoreInvisibility AndAlso Element.Visibility = Visibility.Collapsed Then Return
If TypeOf Element Is MyTextButton Then
AllControls.Add(Element)
ElseIf TypeOf Element Is MyListItem Then
CType(Element, MyListItem).IsMouseOverAnimationEnabled = False
AllControls.Add(Element)
ElseIf TypeOf Element Is ContentControl Then
GetAllAnimControls(CType(Element, ContentControl).Content, AllControls)
GetAllAnimControls(CType(Element, ContentControl).Content, AllControls, IgnoreInvisibility)
ElseIf TypeOf Element Is Panel Then
For Each Element2 As FrameworkElement In CType(Element, Panel).Children
GetAllAnimControls(Element2, AllControls)
GetAllAnimControls(Element2, AllControls, IgnoreInvisibility)
Next
Else
AllControls.Add(Element)
@@ -98,3 +105,7 @@
End Sub
End Class
Public Interface IRefreshable
Sub Refresh()
End Interface
+157 -71
View File
@@ -2,6 +2,18 @@
Inherits AdornerDecorator
Public PageUuid As Integer = GetUuid()
'“返回顶部” 按钮检测的滚动区域
Public Property PanScroll As MyScrollViewer
Get
Return GetValue(PanScrollProperty)
End Get
Set(value As MyScrollViewer)
SetValue(PanScrollProperty, value)
End Set
End Property
Private Shared ReadOnly PanScrollProperty =
DependencyProperty.Register("PanScroll", GetType(MyScrollViewer), GetType(MyPageRight), New PropertyMetadata(Nothing))
'当前状态
Public Enum PageStates
Empty '默认状态,页面全空
@@ -12,7 +24,7 @@
LoaderExit '加载环退出动画
ContentEnter '内容进入动画
ContentStay '内容正常显示
ReloadExit '刷新导致的全部退出动画
ContentExit '刷新导致的全部退出动画,或页面内容退出(子页面更改)导致的全部退出动画
PageExit '切换页面导致的全部退出动画
End Enum
Private _PageState As PageStates = PageStates.Empty
@@ -21,7 +33,7 @@
Return _PageState
End Get
Set(value As PageStates)
If _PageState = value Then Exit Property
If _PageState = value Then Return
_PageState = value
If ModeDebug Then Log("[UI] 页面状态切换为 " & GetStringFromEnum(value))
End Set
@@ -48,7 +60,8 @@
''' <param name="RealLoader">在工作线程执行的加载器。</param>
''' <param name="FinishedInvoke">当加载器执行完成,在 UI 线程触发的 UI 初始化事件。</param>
Public Sub PageLoaderInit(LoaderUi As MyLoading, PanLoader As FrameworkElement, PanContent As FrameworkElement, PanAlways As FrameworkElement,
RealLoader As LoaderBase, FinishedInvoke As Action(Of LoaderBase), Optional InputInvoke As Func(Of Object) = Nothing,
RealLoader As LoaderBase,
Optional FinishedInvoke As Action(Of LoaderBase) = Nothing, Optional InputInvoke As Func(Of Object) = Nothing,
Optional AutoRun As Boolean = True)
'初始化参数
Me.PanLoader = PanLoader
@@ -59,14 +72,16 @@
Me.PageLoaderInputInvoke = InputInvoke
Me.PageLoaderAutoRun = AutoRun
'添加结束 Invoke
AddHandler RealLoader.PreviewFinish,
If FinishedInvoke IsNot Nothing Then
AddHandler RealLoader.PreviewFinish,
Sub()
Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ReloadExit
Do While PageState = MyPageRight.PageStates.PageExit OrElse PageState = MyPageRight.PageStates.ContentExit
Thread.Sleep(10) '不在退出动画时执行 UI 线程操作,避免退出动画被重置
Loop
RunInUiWait(Sub() FinishedInvoke(RealLoader))
Thread.Sleep(20) '由于大量初始化控件会导致掉帧,延迟触发 State 改变事件
End Sub
End If
AddHandler RealLoader.OnStateChangedUi, Sub(Loader As LoaderBase, NewState As LoadState, OldState As LoadState) RunInUi(Sub() PageLoaderState(Loader, NewState, OldState))
'隐藏 UI
PanLoader.Visibility = Visibility.Collapsed
@@ -74,7 +89,7 @@
If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed
'初次运行加载器
If PageLoaderAutoRun Then
If PageLoader.GetType.Name.StartsWith("LoaderTask") Then
If PageLoader.GetType.Name.StartsWithF("LoaderTask") Then
PageLoader.Start(CType(PageLoader, Object).StartGetInput(Nothing, PageLoaderInputInvoke))
Else
Dim Input = Nothing
@@ -82,18 +97,17 @@
PageLoader.Start(Input)
End If
End If
If PageLoader.State = LoadState.Finished Then
If PageLoader.State = LoadState.Finished AndAlso FinishedInvoke IsNot Nothing Then
RunInUiWait(Sub() FinishedInvoke(RealLoader)) '加载器已提前完成,直接触发事件
End If
'设置加载环
PageLoaderUi.State = RealLoader
AddHandler PageLoaderUi.Click, Sub() If RealLoader.State = LoadState.Failed Then PageLoaderRestart() '点击重试事件
End Sub
'重试
Public Sub PageLoaderRestart(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = True) '由外部调用的重试
If Not PageLoaderAutoRun Then Exit Sub
If PageLoader.GetType.Name.StartsWith("LoaderTask") Then
If Not PageLoaderAutoRun Then Return
If PageLoader.GetType.Name.StartsWithF("LoaderTask") Then
PageLoader.Start(CType(PageLoader, Object).StartGetInput(Input, PageLoaderInputInvoke), IsForceRestart:=IsForceRestart)
Else
If Input Is Nothing AndAlso PageLoaderInputInvoke IsNot Nothing Then Input = PageLoaderInputInvoke()
@@ -112,38 +126,45 @@
''' </summary>
Public Sub PageOnEnter()
If ModeDebug Then Log("[UI] 已触发 PageOnEnter")
RaiseEvent OnPageEnter()
RaiseEvent PageEnter()
Select Case PageState
Case PageStates.Empty
If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Aborted Then
If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then
'如果加载器在进入页面时不启动(例如 HiPer 联机),那么在此时就会有 State = Waiting
PageState = PageStates.ContentEnter
TriggerEnterAnimation(PanAlways, If(PanContent, Child))
ElseIf PageLoader.State = LoadState.Loading Then
PageState = PageStates.LoaderWait
AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
ElseIf PageLoader.State = LoadState.Failed Then
Else 'PageLoader.State = LoadState.Failed
PageState = PageStates.LoaderEnter
TriggerEnterAnimation(PanAlways, PanLoader)
ElseIf PageLoader.State = LoadState.Waiting Then
'由于 “页面加载器 Minecraft Version List 不应在 PageOnEnter 事件出现 Waiting 状态” 的神秘反馈添加的临时修复
End If
Case PageStates.ContentExit
'和上面的一样,但是不管 PanAlways
If PageLoader Is Nothing OrElse PageLoader.State = LoadState.Finished OrElse PageLoader.State = LoadState.Waiting OrElse PageLoader.State = LoadState.Aborted Then
PageState = PageStates.ContentEnter
TriggerEnterAnimation(If(PanContent, Child))
ElseIf PageLoader.State = LoadState.Loading Then
PageState = PageStates.LoaderWait
AniStart(AaCode(AddressOf PageOnLoaderWaitFinished, 200), "PageRight PageChange " & PageUuid)
Log("[Anim] 警告:页面加载器 " & PageLoader.Name & " 不应在 PageOnEnter 事件出现 " & GetStringFromEnum(PageLoader.State) & " 状态", LogLevel.Debug)
Else
Throw New Exception("页面加载器 " & PageLoader.Name & " 不应在 PageOnEnter 事件出现 " & GetStringFromEnum(PageLoader.State) & " 状态。")
Else 'PageLoader.State = LoadState.Failed
PageState = PageStates.LoaderEnter
TriggerEnterAnimation(PanLoader)
End If
Case PageStates.ContentEnter '重复调用 PageOnEnter,直接忽略
Case Else
Throw New Exception("在状态为 " & GetStringFromEnum(PageState) & " 时触发了 PageOnEnter 事件。")
End Select
End Sub
Public Event OnPageEnter()
Public Event PageEnter()
''' <summary>
''' 需要切换到其他页面。
''' 需要立即切换至 PageExit 或 Empty。
''' </summary>
Public Sub PageOnExit()
If ModeDebug Then Log("[UI] 已触发 PageOnExit")
RaiseEvent PageExit()
Select Case PageState
Case PageStates.ContentEnter, PageStates.ContentStay
PageState = PageStates.PageExit
@@ -154,18 +175,19 @@
Case PageStates.LoaderWait
PageState = PageStates.PageExit
TriggerExitAnimation(PanAlways)
Case PageStates.LoaderExit, PageStates.ReloadExit
Case PageStates.LoaderExit, PageStates.ContentExit
PageState = PageStates.PageExit
If PanAlways IsNot Nothing Then TriggerExitAnimation(PanAlways, If(PanContent, Child))
Case PageStates.PageExit, PageStates.Empty
End Select
End Sub
Public Event PageExit()
''' <summary>
''' 即将切换到其他页面,需要强制完成页面状态清理。
''' 需要立即切换至 Empty。
''' </summary>
Public Sub PageOnForceExit()
If PageState = PageStates.Empty Then Exit Sub
If PageState = PageStates.Empty Then Return
If ModeDebug Then Log("[UI] 已触发 PageOnForceExit")
PageState = PageStates.Empty
AniStop("PageRight PageChange " & PageUuid)
@@ -178,6 +200,29 @@
If PanAlways IsNot Nothing Then PanAlways.Visibility = Visibility.Collapsed
End If
End Sub
''' <summary>
''' PanContent 中的子页面改变,需要让当前内容退出,再显示新的内容。
''' 需要在 PageEnter 事件确认要显示的子页面有哪些。
''' </summary>
Public Sub PageOnContentExit()
If ModeDebug Then Log("[UI] 已触发 PageOnContentExit")
If PageLoader IsNot Nothing AndAlso PageLoader.State = LoadState.Loading Then
Throw New Exception("在调用 PageOnContentExit 时,加载器不能为 Loading 状态")
'Loading 的加载器可能触发进一步变化,难以预测会触发子页面的动画还是加载器完成的动画
End If
Select Case PageState
Case PageStates.ContentEnter, PageStates.ContentStay
PageState = PageStates.ContentExit
TriggerExitAnimation(PanContent)
Case PageStates.LoaderExit
PageState = PageStates.ContentExit
Case PageStates.LoaderEnter, PageStates.LoaderStayForce, PageStates.LoaderStay
PageState = PageStates.ContentExit
TriggerExitAnimation(PanLoader)
Case PageStates.LoaderWait, PageStates.Empty
PageOnEnter()
End Select
End Sub
'内部触发的事件
''' <summary>
@@ -205,8 +250,7 @@
Select Case PageState
Case PageStates.PageExit
PageState = PageStates.Empty
Case PageStates.ReloadExit
PageState = PageStates.Empty
Case PageStates.ContentExit
PageOnEnter()
Case PageStates.LoaderExit
PageState = PageStates.ContentEnter
@@ -258,20 +302,20 @@
Private Sub PageLoaderState(sender As Object, NewState As LoadState, OldState As LoadState)
Select Case NewState
Case LoadState.Failed, LoadState.Loading
If Not OldState = LoadState.Finished Then Exit Sub
If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Refresh)")
'重新开始运行
If OldState = LoadState.Failed OrElse OldState = LoadState.Loading Then Return
If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Start/Refresh)")
'(重新)开始运行
'需要从部分状态切换到 ReloadExit
Select Case PageState
Case PageStates.ContentEnter, PageStates.ContentStay
PageState = PageStates.ReloadExit
PageState = PageStates.ContentExit
TriggerExitAnimation(PanContent)
Case PageStates.LoaderExit, PageStates.ReloadExit
PageState = PageStates.ReloadExit
Case PageStates.LoaderExit
PageState = PageStates.ContentExit
End Select
Case LoadState.Finished
If Not OldState = LoadState.Loading Then Exit Sub
If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop)")
Case LoadState.Finished, LoadState.Aborted, LoadState.Waiting
If Not (OldState = LoadState.Failed OrElse OldState = LoadState.Loading) Then Return
If ModeDebug Then Log("[UI] 已触发 PageLoaderState (Stop/Abort)")
'运行结束
'需要从 LoaderWait 切换到 ContentEnter,或从 LoaderStay 切换到 LoaderExit
Select Case PageState
@@ -295,17 +339,13 @@
'逐个进入动画
Public Sub TriggerEnterAnimation(ParamArray Elements As FrameworkElement())
'去除 Nothing 项
Dim RealElements As New List(Of FrameworkElement)
For Each Element In Elements
If Element IsNot Nothing Then RealElements.Add(Element)
Next
Dim RealElements = Elements.Where(Function(e) e IsNot Nothing)
For Each Element In RealElements
Element.Visibility = Visibility.Visible '页面均处于默认的隐藏状态
Next
Dim AniList As New List(Of AniData)
Dim Delay As Integer = 0
'基础动画
For Each Element In RealElements
For Each Control As FrameworkElement In GetAllAnimControls(Element, True)
'还原被隐藏的卡片的消失动画
@@ -313,64 +353,110 @@
If Control.RenderTransform IsNot Nothing AndAlso TypeOf Control.RenderTransform Is TranslateTransform Then Control.RenderTransform = Nothing
Next
For Each Control As FrameworkElement In GetAllAnimControls(Element)
Control.Opacity = 0
Control.RenderTransform = New TranslateTransform(0, -16)
AniList.Add(AaOpacity(Control, 1, 150, Delay, New AniEaseOutFluent(AniEasePower.Weak)))
AniList.Add(AaTranslateY(Control, 5, 250, Delay, New AniEaseOutFluent))
AniList.Add(AaTranslateY(Control, 11, 350, Delay, New AniEaseOutBack))
Delay += 40
If TypeOf Control Is MyExtraTextButton Then
CType(Control, MyExtraTextButton).Show = True
Else
Control.Opacity = 0
Control.RenderTransform = New TranslateTransform(0, -16)
AniList.Add(AaOpacity(Control, 1, 100, Delay, New AniEaseOutFluent(AniEasePower.Weak)))
AniList.Add(AaTranslateY(Control, 5, 250, Delay, New AniEaseOutFluent))
AniList.Add(AaTranslateY(Control, 11, 350, Delay, New AniEaseOutBack))
Delay += 25
End If
Next
Next
'滚动条动画
Dim Scroll As MyScrollBar = GetFirstScrollViewer(RealElements)
If Scroll IsNot Nothing Then
If TypeOf Scroll.RenderTransform IsNot TranslateTransform Then Scroll.RenderTransform = New TranslateTransform(10, 0)
AniList.Add(AaTranslateX(Scroll, -CType(Scroll.RenderTransform, TranslateTransform).X, 350, 0, New AniEaseOutFluent))
End If
'结束
AniList.Add(AaCode(Sub() PageOnEnterAnimationFinished(),, True))
AniStart(AniList, "PageRight PageChange " & PageUuid)
End Sub
'逐个退出动画
Public Sub TriggerExitAnimation(ParamArray Elements As FrameworkElement())
'去除 Nothing 项
Dim RealElements As New List(Of FrameworkElement)
For Each Element In Elements
If Element IsNot Nothing Then RealElements.Add(Element)
Next
Dim RealElements = Elements.Where(Function(e) e IsNot Nothing)
Dim AniList As New List(Of AniData)
Dim Delay As Integer = 0
For Each Element In RealElements
For Each Control As FrameworkElement In GetAllAnimControls(Element)
Control.IsHitTestVisible = False
AniList.Add(AaOpacity(Control, -1, 90, Delay))
AniList.Add(AaTranslateY(Control, -6, 90, Delay))
Delay += 20
If TypeOf Control Is MyExtraTextButton Then
CType(Control, MyExtraTextButton).Show = False
Else
Control.IsHitTestVisible = False
AniList.Add(AaOpacity(Control, -1, 70, Delay))
AniList.Add(AaTranslateY(Control, -6, 70, Delay))
Delay += 15
End If
Next
Next
AniList.Add(AaCode(Sub()
For Each Element In RealElements
Element.Visibility = Visibility.Collapsed
Next
PageOnExitAnimationFinished()
End Sub,, True))
'滚动条动画
Dim Scroll As MyScrollBar = GetFirstScrollViewer(RealElements)
If Scroll IsNot Nothing Then
If TypeOf Scroll.RenderTransform IsNot TranslateTransform Then Scroll.RenderTransform = New TranslateTransform
AniList.Add(AaTranslateX(Scroll, 10 - CType(Scroll.RenderTransform, TranslateTransform).X, 90, 0, New AniEaseInFluent))
End If
'结束
AniList.Add(AaCode(
Sub()
For Each Element In RealElements
Element.Visibility = Visibility.Collapsed
Next
PageOnExitAnimationFinished()
End Sub,, True))
AniStart(AniList, "PageRight PageChange " & PageUuid)
End Sub
'遍历获取所有需要生成动画的控件
Friend Function GetAllAnimControls(Element As FrameworkElement, Optional IgnoreInvisibility As Boolean = False) As List(Of FrameworkElement)
''' <summary>
''' 禁用页面切换动画的控件列表。
''' </summary>
Public DisabledPageAnimControls As New List(Of FrameworkElement)
''' <summary>
''' 遍历获取所有需要生成动画的控件。
''' </summary>
Friend Function GetAllAnimControls(Element As FrameworkElement, Optional IgnoreInvisibility As Boolean = False) As IEnumerable(Of FrameworkElement)
Dim AllControls As New List(Of FrameworkElement)
GetAllAnimControls(Element, AllControls, IgnoreInvisibility)
Return AllControls
_GetAllAnimControls(Element, AllControls, IgnoreInvisibility)
Return AllControls.Except(DisabledPageAnimControls)
End Function
Private Sub GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
If Not IgnoreInvisibility AndAlso Element.Visibility = Visibility.Collapsed Then Exit Sub
If TypeOf Element Is MyCard OrElse TypeOf Element Is MyHint Then
Private Sub _GetAllAnimControls(Element As FrameworkElement, ByRef AllControls As List(Of FrameworkElement), IgnoreInvisibility As Boolean)
If Not IgnoreInvisibility AndAlso Element.Visibility = Visibility.Collapsed Then Return
If TypeOf Element Is MyCard OrElse TypeOf Element Is MyHint OrElse TypeOf Element Is MyExtraTextButton OrElse TypeOf Element Is TextBlock OrElse TypeOf Element Is MyTextButton Then
AllControls.Add(Element)
ElseIf TypeOf Element Is ContentControl Then
GetAllAnimControls(CType(Element, ContentControl).Content, AllControls, IgnoreInvisibility)
Dim Content = CType(Element, ContentControl).Content
If Content IsNot Nothing AndAlso TypeOf Content Is FrameworkElement Then _GetAllAnimControls(Content, AllControls, IgnoreInvisibility)
ElseIf TypeOf Element Is Panel Then
For Each Element2 As FrameworkElement In CType(Element, Panel).Children
GetAllAnimControls(Element2, AllControls, IgnoreInvisibility)
For Each Element2 In CType(Element, Panel).Children
If TypeOf Element2 Is FrameworkElement Then _GetAllAnimControls(Element2, AllControls, IgnoreInvisibility)
Next
End If
End Sub
'查找列表中的第一个滚动条
Private Function GetFirstScrollViewer(Elements As IEnumerable(Of FrameworkElement)) As MyScrollBar
Dim Viewer As MyScrollViewer = Nothing
For Each Element In Elements
If TypeOf Element Is MyScrollViewer Then
Viewer = Element
GoTo FindViewer
End If
For Each Control In LogicalTreeHelper.GetChildren(Element)
If TypeOf Control Is MyScrollViewer Then
Viewer = Control
GoTo FindViewer
End If
Next
Next
Return Nothing
FindViewer:
If Viewer.ComputedVerticalScrollBarVisibility <> Visibility.Visible Then Return Nothing
Return Viewer.ScrollBar
End Function
#End Region
End Class
@@ -3,7 +3,7 @@
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
FocusVisualStyle="{x:Null}"
MinWidth="20" x:Name="PanBack" UseLayoutRounding="False" SnapsToDevicePixels="False" MinHeight="20" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True">
<TextBlock IsHitTestVisible="False" x:Name="LabText" FontSize="13" Padding="0" Margin="26,0,0,0" Text="Radiobox" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<TextBlock IsHitTestVisible="False" x:Name="LabText" FontSize="13" Padding="0" Margin="26,0,0,0" Foreground="{DynamicResource ColorBrush1}" HorizontalAlignment="Left" VerticalAlignment="Center"/>
<Ellipse IsHitTestVisible="False" x:Name="ShapeBorder" StrokeThickness="1.1" HorizontalAlignment="Left" VerticalAlignment="Center" Width="18" Height="18" Stroke="{DynamicResource ColorBrush1}" Margin="1,0,0,0" Fill="{StaticResource ColorBrushHalfWhite}" />
<Ellipse IsHitTestVisible="False" x:Name="ShapeDot" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{Binding Stroke, ElementName=ShapeBorder}" Width="0" Height="0" Margin="10,0,0,0" StrokeThickness="0" />
<Ellipse IsHitTestVisible="False" x:Name="ShapeDot" HorizontalAlignment="Left" VerticalAlignment="Center" Fill="{Binding Stroke, ElementName=ShapeBorder}" Width="0" Height="0" Margin="10,0,0,0" StrokeThickness="0" />
</Grid>
@@ -1,4 +1,7 @@
Public Class MyRadioBox
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyRadioBox
Implements IMyRadio
'基础
@@ -10,59 +13,57 @@
Public Event Changed(sender As Object, e As RouteEventArgs) Implements IMyRadio.Changed
'自定义属性
Private _Checked As Boolean = False '是否选中
Public Property Checked As Boolean
Get
Return _Checked
Return GetValue(CheckedProperty)
End Get
Set(value As Boolean)
SetChecked(value, False, True)
SetChecked(value, False)
End Set
End Property
Public Shared ReadOnly CheckedProperty As DependencyProperty =
DependencyProperty.Register("Checked", GetType(Boolean), GetType(MyRadioBox), New PropertyMetadata(False,
Sub(d As MyRadioBox, e As DependencyPropertyChangedEventArgs)
'在使用 XAML 设置 Checked 属性时,不会触发 Checked_Set 方法,所以需要在这里手动触发 UI 改变
If Not d.IsLoaded Then d.SyncUI()
End Sub))
''' <summary>
''' 手动设置 Checked 属性。
''' </summary>
''' <param name="value">新的 Checked 属性。</param>
''' <param name="user">是否由用户引发。</param>
''' <param name="anime">是否执行动画。</param>
Public Sub SetChecked(value As Boolean, user As Boolean, anime As Boolean)
Public Sub SetChecked(value As Boolean, user As Boolean)
Try
'Preview 事件
If value AndAlso user Then
Dim e = New RouteEventArgs(user)
RaiseEvent PreviewCheck(Me, e)
If e.Handled Then
Radiobox_MouseLeave()
Exit Sub
Return
End If
End If
'自定义属性基础
Dim IsChanged As Boolean = False
If IsLoaded AndAlso Not value = _Checked Then RaiseEvent PreviewChange(Me, New RouteEventArgs(user))
If Not value = _Checked Then
_Checked = value
If IsLoaded AndAlso Not value = Checked Then RaiseEvent PreviewChange(Me, New RouteEventArgs(user))
If Not value = Checked Then
SetValue(CheckedProperty, value)
IsChanged = True
End If
'保证只有一个单选框选中
If Parent Is Nothing Then Exit Sub
If Parent Is Nothing Then Return
Dim RadioboxList As New List(Of MyRadioBox)
Dim CheckedCount As Integer = 0
'收集控件列表与选中个数
For Each Control In CType(Parent, Object).Children
For Each Control In CType(Parent, Object).Children '收集控件列表与选中个数
If TypeOf Control Is MyRadioBox Then
RadioboxList.Add(Control)
If Control.Checked Then CheckedCount += 1
End If
Next
'判断选中情况
Select Case CheckedCount
Select Case CheckedCount '判断选中情况
Case 0
'没有任何单选框被选中,选择第一个
RadioboxList(0).Checked = True
@@ -87,67 +88,74 @@
Next
End If
End Select
'End If
'更改动画
If Not IsChanged Then Exit Sub
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso anime Then '防止默认属性变更触发动画
If Checked Then
'由无变有
If ShapeDot.Opacity < 0.01 Then ShapeDot.Opacity = 1
AniStart({
AaScale(ShapeBorder, 10 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent(AniEasePower.Weak), , True),
AaScale(ShapeBorder, 8, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.6, New AniEaseOutBack, , True)
}, "MyRadioBox Border " & Uuid)
AniStart({
AaScale(ShapeDot, 9 - ShapeDot.Width, AnimationTimeOfCheck * 2.6,, New AniEaseOutBack(AniEasePower.Weak), , True),
AaOpacity(ShapeDot, 1 - ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.6)
}, "MyRadioBox Dot " & Uuid)
AniStart({
AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush2", "ColorBrushGray4")), AnimationTimeOfCheck)
}, "MyRadioBox BorderColor " & Uuid)
Else
'由有变无
AniStart({
AaScale(ShapeBorder, 18 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True)
}, "MyRadioBox Border " & Uuid)
AniStart({
AaScale(ShapeDot, -ShapeDot.Width, AnimationTimeOfCheck, , New AniEaseInFluent, , True),
AaOpacity(ShapeDot, -ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.2)
}, "MyRadioBox Dot " & Uuid)
AniStart({
AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush1", "ColorBrushGray4")), AnimationTimeOfCheck)
}, "MyRadioBox BorderColor " & Uuid)
End If
Else
'不使用动画
AniStop("MyRadioBox Border " & Uuid)
AniStop("MyRadioBox Dot " & Uuid)
AniStop("MyRadioBox BorderColor " & Uuid)
If Checked Then
ShapeDot.Width = 9
ShapeDot.Height = 9
ShapeDot.Opacity = 1
ShapeDot.Margin = New Thickness(5.5, 0, 0, 0)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4"))
Else
ShapeDot.Width = 0
ShapeDot.Height = 0
ShapeDot.Opacity = 0
ShapeDot.Margin = New Thickness(10, 0, 0, 0)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
End If
End If
'触发事件
If Checked Then RaiseEvent Check(Me, New RouteEventArgs(user))
RaiseEvent Changed(Me, New RouteEventArgs(user))
If IsChanged Then
If Checked Then RaiseEvent Check(Me, New RouteEventArgs(user))
RaiseEvent Changed(Me, New RouteEventArgs(user))
End If
'更改动画
SyncUI()
Catch ex As Exception
Log(ex, "单选框勾选改变错误", LogLevel.Hint)
End Try
End Sub
Private Sub SyncUI()
If AniControlEnabled = 0 AndAlso IsLoaded Then '防止默认属性变更触发动画
If Checked Then
'由无变有
If ShapeDot.Opacity < 0.01 Then ShapeDot.Opacity = 1
AniStart({
AaScale(ShapeBorder, 10 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent(AniEasePower.Weak), , True),
AaScale(ShapeBorder, 8, AnimationTimeOfCheck * 2, AnimationTimeOfCheck * 0.6, New AniEaseOutBack, , True)
}, "MyRadioBox Border " & Uuid)
AniStart({
AaScale(ShapeDot, 9 - ShapeDot.Width, AnimationTimeOfCheck * 2.6,, New AniEaseOutBack(AniEasePower.Weak), , True),
AaOpacity(ShapeDot, 1 - ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.6)
}, "MyRadioBox Dot " & Uuid)
AniStart({
AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush2", "ColorBrushGray4")), AnimationTimeOfCheck)
}, "MyRadioBox BorderColor " & Uuid)
Else
'由有变无
AniStart({
AaScale(ShapeBorder, 18 - ShapeBorder.Width, AnimationTimeOfCheck, , New AniEaseOutFluent, , True)
}, "MyRadioBox Border " & Uuid)
AniStart({
AaScale(ShapeDot, -ShapeDot.Width, AnimationTimeOfCheck, , New AniEaseInFluent, , True),
AaOpacity(ShapeDot, -ShapeDot.Opacity, AnimationTimeOfCheck * 0.5, AnimationTimeOfCheck * 0.2)
}, "MyRadioBox Dot " & Uuid)
AniStart({
AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsMouseOver, "ColorBrush3", If(IsEnabled, "ColorBrush1", "ColorBrushGray4")), AnimationTimeOfCheck)
}, "MyRadioBox BorderColor " & Uuid)
End If
Else
'不使用动画
AniStop("MyRadioBox Border " & Uuid)
AniStop("MyRadioBox Dot " & Uuid)
AniStop("MyRadioBox BorderColor " & Uuid)
If Checked Then
ShapeDot.Width = 9
ShapeDot.Height = 9
ShapeDot.Opacity = 1
ShapeDot.Margin = New Thickness(5.5, 0, 0, 0)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush2", "ColorBrushGray4"))
Else
ShapeDot.Width = 0
ShapeDot.Height = 0
ShapeDot.Opacity = 0
ShapeDot.Margin = New Thickness(10, 0, 0, 0)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
End If
End If
End Sub
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabText.Inlines
End Get
End Property
Public Property Text As String
Get
Return GetValue(TextProperty)
@@ -157,33 +165,31 @@
End Set
End Property '内容
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyRadioBox), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If Not IsNothing(sender) Then CType(sender, MyRadioBox).LabText.Text = e.NewValue
End Sub)))
Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyRadioBox).LabText.Text = e.NewValue)))
'点击事件
Private MouseDowned As Boolean = False
Private AllowMouseDown As Boolean = True
Private Sub Radiobox_MouseUp() Handles Me.MouseLeftButtonUp
If Not MouseDowned Then Exit Sub
MouseDowned = False
If Not MouseDowned Then Return
Log("[Control] 按下单选框:" & Text)
SetChecked(True, True, True)
AniStart(AaColor(ShapeBorder, Shapes.Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
SetChecked(True, True)
MouseDowned = False
AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
End Sub
Private Sub Radiobox_MouseDown() Handles Me.MouseLeftButtonDown
MouseDowned = True
Focus()
AniStart(AaColor(ShapeBorder, Shapes.Ellipse.FillProperty, "ColorBrush9", 100), "MyRadioBox Background " & Uuid)
AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushBg1", 100), "MyRadioBox Background " & Uuid)
If Not Checked Then
AniStart(AaScale(ShapeBorder, 16.5 - ShapeBorder.Width, 1000, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyRadioBox Border " & Uuid)
End If
End Sub
Private Sub Radiobox_MouseLeave() Handles Me.MouseLeave
If Not MouseDowned Then Exit Sub
If Not MouseDowned Then Return
MouseDowned = False
AniStart(AaColor(ShapeBorder, Shapes.Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
AniStart(AaColor(ShapeBorder, Ellipse.FillProperty, "ColorBrushHalfWhite", 100), "MyRadioBox Background " & Uuid)
If Not Checked Then
AniStart(AaScale(ShapeBorder, 18 - ShapeBorder.Width, 400, , New AniEaseOutFluent(AniEasePower.Strong), Absolute:=True), "MyRadioBox Border " & Uuid)
End If
@@ -218,11 +224,13 @@
AniStart(AaColor(LabText, TextBlock.ForegroundProperty, "ColorBrush3", AnimationTimeOfMouseIn), "MyRadioBox TextColor " & Uuid)
End Sub
Private Sub Radiobox_MouseLeaveAnimation() Handles Me.MouseLeave
If Not Me.IsEnabled Then Exit Sub 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
If Not Me.IsEnabled Then Return 'MouseLeave 比 IsEnabledChanged 后执行,所以如果自定义事件修改了 IsEnabled,将导致显示错误
If IsLoaded AndAlso AniControlEnabled = 0 Then
AniStart(AaColor(ShapeBorder, Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox BorderColor " & Uuid)
AniStart(AaColor(LabText, TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"), AnimationTimeOfMouseOut), "MyRadioBox TextColor " & Uuid)
Else
AniStop("MyRadioBox BorderColor " & Uuid)
AniStop("MyRadioBox TextColor " & Uuid)
ShapeBorder.SetResourceReference(Ellipse.StrokeProperty, If(IsEnabled, If(Checked, "ColorBrush2", "ColorBrush1"), "ColorBrushGray4"))
LabText.SetResourceReference(TextBlock.ForegroundProperty, If(IsEnabled, "ColorBrush1", "ColorBrushGray4"))
End If
@@ -1,4 +1,7 @@
Public Class MyRadioButton
Imports System.Windows.Markup
<ContentProperty("Inlines")>
Public Class MyRadioButton
'基础
@@ -59,7 +62,7 @@
'保证只有一个单选框选中
If IsNothing(Parent) Then Exit Sub
If IsNothing(Parent) Then Return
Dim RadioboxList As New List(Of MyRadioButton)
Dim CheckedCount As Integer = 0
'收集控件列表与选中个数
@@ -98,7 +101,7 @@
'更改动画
If Not IsChanged Then Exit Sub
If Not IsChanged Then Return
RefreshColor(Nothing, anime)
'触发事件
@@ -108,6 +111,12 @@
Log(ex, "单选按钮勾选改变错误", LogLevel.Hint)
End Try
End Sub
Public ReadOnly Property Inlines As InlineCollection
Get
Return LabText.Inlines
End Get
End Property
Public Property Text As String
Get
Return GetValue(TextProperty)
@@ -117,9 +126,7 @@
End Set
End Property '内容
Public Shared ReadOnly TextProperty As DependencyProperty = DependencyProperty.Register("Text", GetType(String), GetType(MyRadioButton), New PropertyMetadata(New PropertyChangedCallback(
Sub(sender As DependencyObject, e As DependencyPropertyChangedEventArgs)
If Not IsNothing(sender) Then CType(sender, MyRadioButton).LabText.Text = e.NewValue
End Sub)))
Sub(sender, e) If sender IsNot Nothing Then CType(sender, MyRadioButton).LabText.Text = e.NewValue)))
Public Enum ColorState
White
Highlight
@@ -137,16 +144,20 @@
'点击事件
Public Event PreviewClick(sender As Object, e As RouteEventArgs)
Private IsMouseDown As Boolean = False
Private Sub Radiobox_MouseUp() Handles Me.MouseLeftButtonUp
If Checked Then Exit Sub
If Not IsMouseDown Then Exit Sub
If Checked Then Return
If Not IsMouseDown Then Return
Log("[Control] 按下单选按钮:" & Text)
IsMouseDown = False
Dim e As New RouteEventArgs(True)
RaiseEvent PreviewClick(Me, e)
If e.Handled Then Return
SetChecked(True, True, True)
End Sub
Private Sub Radiobox_MouseDown() Handles Me.MouseLeftButtonDown
If Checked Then Exit Sub
If Checked Then Return
IsMouseDown = True
RefreshColor()
End Sub
@@ -248,7 +259,7 @@
End If
Catch ex As Exception
Log(ex, "刷新按钮颜色出错")
Log(ex, "刷新单选按钮颜色出错")
End Try
End Sub
+3 -3
View File
@@ -128,7 +128,7 @@ Public Class MyResizer
Private Declare Function GetMonitorInfo Lib "user32" (hMonitor As IntPtr, lpmi As MONITORINFO) As Boolean
Friend Declare Function MonitorFromWindow Lib "User32" (handle As IntPtr, flags As Integer) As IntPtr
Private Declare Function MonitorFromWindow Lib "User32" (handle As IntPtr, flags As Integer) As IntPtr
Private Sub connectMouseHandlers(element As UIElement)
AddHandler element.MouseLeftButtonDown, AddressOf Me.element_MouseLeftButtonDown
@@ -301,7 +301,7 @@ Public Class MyResizer
End Sub
Private Sub updateMouseDown()
Dim flag As Boolean = Mouse.LeftButton = MouseButtonState.Released
Dim flag = (GetAsyncKeyState(&H1) And &H8000) = 0 '调用原生API判断鼠标是否抬起,如果使用WPF的API的话鼠标不在窗口上时不会更新状态 (#5655)
If flag Then
resizeRight = False
resizeLeft = False
@@ -311,5 +311,5 @@ Public Class MyResizer
End Sub
Private Declare Function GetCursorPos Lib "user32.dll" (<Out()> ByRef lpPoint As PointAPI) As Boolean
Private Declare Function GetAsyncKeyState Lib "user32.dll" (vKey As Integer) As Short
End Class
@@ -1,20 +1,35 @@
Public Class MyScrollViewer
Inherits ScrollViewer
Public Property DeltaMuity As Double = 1
Public Property DeltaMult As Double = 1
Private RealOffset As Double
Private Sub MyScrollViewer_PreviewMouseWheel(sender As Object, e As MouseWheelEventArgs) Handles Me.PreviewMouseWheel
If e.Delta = 0 OrElse ActualHeight = 0 OrElse ScrollableHeight = 0 Then Exit Sub
Dim SourceTypeName As String = e.Source.GetType.Name
If Content.TemplatedParent Is Nothing AndAlso (SourceTypeName.Contains("Combo") OrElse SourceTypeName = "MyTextBox") Then Exit Sub '确定可视树,防止滚动问题
PerformVerticalOffsetDelta(-e.Delta)
If e.Delta = 0 OrElse ActualHeight = 0 OrElse ScrollableHeight = 0 Then Return
Dim SourceType = e.Source.GetType
If Content.TemplatedParent Is Nothing AndAlso (
(GetType(ComboBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, ComboBox).IsDropDownOpen) OrElse
(GetType(TextBox).IsAssignableFrom(SourceType) AndAlso CType(e.Source, TextBox).AcceptsReturn) OrElse
GetType(ComboBoxItem).IsAssignableFrom(SourceType) OrElse
TypeOf e.Source Is CheckBox) Then
'如果当前是在对有滚动条的下拉框或文本框执行,则不接管操作
Return
End If
e.Handled = True
PerformVerticalOffsetDelta(-e.Delta)
'关闭 Tooltip (#2552)
For Each TooltipBorder In Application.ShowingTooltips
AniStart(AaOpacity(TooltipBorder, -1, 100), $"Hide Tooltip {GetUuid()}")
Next
End Sub
Public Sub PerformVerticalOffsetDelta(Delta As Double)
AniStart(AaDouble(Sub(AnimDelta As Double)
RealOffset = MathRange(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight)
ScrollToVerticalOffset(RealOffset)
End Sub, Delta * DeltaMuity, 300,, New AniEaseOutFluent(6)))
AniStart(
AaDouble(
Sub(AnimDelta As Double)
RealOffset = MathClamp(RealOffset + AnimDelta, 0, ExtentHeight - ActualHeight)
ScrollToVerticalOffset(RealOffset)
End Sub, Delta * DeltaMult, 300,, New AniEaseOutFluent(6)))
End Sub
Private Sub MyScrollViewer_ScrollChanged(sender As Object, e As ScrollChangedEventArgs) Handles Me.ScrollChanged
RealOffset = VerticalOffset
@@ -24,4 +39,12 @@
FrmMain.BtnExtraBack.ShowRefresh()
End Sub
Public ScrollBar As MyScrollBar
Private Sub Load() Handles Me.Loaded
ScrollBar = GetTemplateChild("PART_VerticalScrollBar")
End Sub
Private Sub MyScrollViewer_PreviewGotKeyboardFocus(sender As Object, e As KeyboardFocusChangedEventArgs) Handles Me.PreviewGotKeyboardFocus
If e.NewFocus IsNot Nothing AndAlso TypeOf e.NewFocus Is MySlider Then e.Handled = True '#3854,阻止获得焦点时自动滚动
End Sub
End Class
@@ -8,7 +8,7 @@
d:DesignHeight="450" d:DesignWidth="800"
Height="40">
<Grid>
<local:MyTextBox HasAnimation="False" x:Name="TextBox" BorderThickness="0" Padding="32,0,40,0" MaxLength="50" FontSize="13.5" UseLayoutRounding="False" SnapsToDevicePixels="False" VerticalContentAlignment="Center" />
<local:MyTextBox HasBackground="False" x:Name="TextBox" BorderThickness="0" Padding="32,0,40,0" MaxLength="50" FontSize="13.5" UseLayoutRounding="False" SnapsToDevicePixels="False" VerticalContentAlignment="Center" />
<Path Width="14" Margin="14,0,0,0" IsHitTestVisible="False" Height="14" Fill="{DynamicResource ColorBrush1}" Stretch="Uniform" Data="M675.9168 242.816C556.3008 123.2 362.4448 123.2 242.8288 242.816 123.2128 362.432 123.2128 556.288 242.8288 675.904 362.4448 795.52 556.3008 795.52 675.9168 675.904 795.5328 556.288 795.5328 362.432 675.9168 242.816L675.9168 242.816ZM1000.7168 892.48C1030.6048 922.368 1030.6048 970.816 1000.7168 1000.704 970.8288 1030.656 922.3808 1030.656 892.4288 1000.704L730.0608 838.336C728.1408 836.416 727.4368 833.92 725.7728 831.872 546.3168 960.448 295.7568 945.408 134.5408 784.192-44.8512 604.8-44.8512 313.92 134.5408 134.528 313.9328-44.864 604.8128-44.864 784.2048 134.528 945.4208 295.744 960.4608 546.304 831.8848 725.76 833.9328 727.424 836.4288 728.128 838.3488 730.048L1000.7168 892.48Z" HorizontalAlignment="Left" />
<local:MyIconButton x:Name="BtnClear" IsHitTestVisible="False" Opacity="0" Width="24" Margin="0,0,10,0" LogoScale="0.75" Height="24" Logo="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" HorizontalAlignment="Right" Theme="Black" />
</Grid>
@@ -1,7 +1,7 @@
Class MySearchBox
Inherits MyCard
Public Event TextChanged(ByVal sender As Object, ByVal e As EventArgs)
Public Event TextChanged(sender As Object, e As EventArgs)
Private Sub MySearchBox_Loaded(sender As Object, e As RoutedEventArgs) Handles Me.Loaded
TextBox.Focus()
End Sub
@@ -11,7 +11,7 @@
Get
Return TextBox.HintText
End Get
Set(ByVal value As String)
Set(value As String)
TextBox.HintText = value
End Set
End Property
@@ -19,7 +19,7 @@
Get
Return TextBox.Text
End Get
Set(ByVal value As String)
Set(value As String)
TextBox.Text = value
End Set
End Property
@@ -6,11 +6,13 @@
mc:Ignorable="d"
d:DesignHeight="16" d:DesignWidth="162"
FocusVisualStyle="{x:Null}"
MinHeight="16" UseLayoutRounding="False" SnapsToDevicePixels="False" BorderBrush="{DynamicResource ColorBrush1}" Name="PanBack" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True">
MinHeight="16" UseLayoutRounding="False" SnapsToDevicePixels="False" BorderBrush="{DynamicResource ColorBrushBg0}" Name="PanBack" Background="{StaticResource ColorBrushSemiTransparent}" Focusable="True">
<Grid x:Name="PanMain" MinHeight="16" MaxHeight="16" IsHitTestVisible="False">
<Line Height="4" Name="LineBack" Stroke="{StaticResource ColorBrushGray5}" StrokeThickness="1.1" X2="10000" Y1="2" Y2="2" HorizontalAlignment="Right" Width="0" SnapsToDevicePixels="True" Margin="0,0,1,0" />
<Line Height="4" Name="LineFore" Stroke="{Binding ElementName=PanBack, Path=BorderBrush}" StrokeThickness="1.1" X2="10000" Y1="2" Y2="2" Width="0" HorizontalAlignment="Left" SnapsToDevicePixels="True" Margin="1,0,0,0" />
<Ellipse HorizontalAlignment="Left" Width="16" Stroke="{Binding BorderBrush, ElementName=PanBack}" StrokeThickness="1.1" Fill="{StaticResource ColorBrushHalfWhite}" Name="ShapeDot" Height="16" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Line Height="4" Name="LineBack" Stroke="{DynamicResource ColorBrushBg0}" Opacity="0.3" StrokeThickness="1" X2="10000" Y1="2" Y2="2" HorizontalAlignment="Right" Width="0" SnapsToDevicePixels="True" Margin="0,0,1,0" />
<Line Height="4" Name="LineFore" Stroke="{Binding ElementName=PanBack, Path=BorderBrush}" StrokeThickness="2" X2="10000" Y1="2" Y2="2" Width="0" HorizontalAlignment="Left" SnapsToDevicePixels="True" Margin="1,0,0,0" />
<Ellipse HorizontalAlignment="Left" Width="10" Height="10"
Stroke="{Binding BorderBrush, ElementName=PanBack}" StrokeThickness="1.2"
Fill="{DynamicResource ColorBrushBg0}" Name="ShapeDot" VerticalAlignment="Center" RenderTransformOrigin="0.5,0.5">
<Ellipse.RenderTransform>
<ScaleTransform />
</Ellipse.RenderTransform>
@@ -14,7 +14,7 @@
Return _MaxValue
End Get
Set(value As Integer)
If value = _MaxValue Then Exit Property
If value = _MaxValue Then Return
_MaxValue = value
RefreshWidth(Nothing, Nothing)
End Set
@@ -28,8 +28,8 @@
Set(newValue As Integer)
Try
newValue = MathRange(newValue, 0, MaxValue)
If _Value = newValue Then Exit Property
newValue = MathClamp(newValue, 0, MaxValue)
If _Value = newValue Then Return
'触发 Preview 事件,修改新值
Dim OldValue = _Value
@@ -40,18 +40,18 @@
If e.Handled Then
_Value = OldValue
DragStop()
Exit Property
Return
End If
End If
If IsLoaded AndAlso AniControlEnabled = 0 Then
If ActualWidth < 16 Then Exit Property
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - 16)
Dim DeltaProcess As Double = Math.Abs(LineFore.Width / (ActualWidth - 16) - _Value / MaxValue)
If ActualWidth < ShapeDot.Width Then Return
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - ShapeDot.Width)
Dim DeltaProcess As Double = Math.Abs(LineFore.Width / (ActualWidth - ShapeDot.Width) - _Value / MaxValue)
Dim Time As Double = (1 - Math.Pow(1 - DeltaProcess, 3)) * 300 + If(ChangeByKey, 100, 0)
AniStart({
AaWidth(LineFore, Math.Max(0, NewWidth + If(NewWidth < 0.5, 0, 0.5)) - LineFore.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
AaWidth(LineBack, Math.Max(0, ActualWidth - 16 - NewWidth + If(ActualWidth - 16 - NewWidth < 0.5, 0, 0.5)) - LineBack.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
AaWidth(LineBack, Math.Max(0, ActualWidth - ShapeDot.Width - NewWidth + If(ActualWidth - ShapeDot.Width - NewWidth < 0.5, 0, 0.5)) - LineBack.Width, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear)),
AaX(ShapeDot, NewWidth - ShapeDot.Margin.Left, Time,, If(Time > 50, New AniEaseOutFluent, New AniEaseLinear))
}, "MySlider Progress " & Uuid)
Else
@@ -67,9 +67,9 @@
Private Sub RefreshWidth(sender As Object, e As SizeChangedEventArgs) Handles Me.SizeChanged
If Not IsNothing(e) Then PanMain.Width = e.NewSize.Width
AniStop("MySlider Progress " & Uuid)
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - 16)
Dim NewWidth As Double = _Value / MaxValue * (ActualWidth - ShapeDot.Width)
LineFore.Width = Math.Max(0, NewWidth + If(NewWidth < 0.5, 0, 0.5))
LineBack.Width = Math.Max(0, ActualWidth - 16 - NewWidth + If(ActualWidth - 16 - NewWidth < 0.5, 0, 0.5))
LineBack.Width = Math.Max(0, ActualWidth - ShapeDot.Width - NewWidth + If(ActualWidth - ShapeDot.Width - NewWidth < 0.5, 0, 0.5))
SetLeft(ShapeDot, NewWidth)
End Sub
@@ -79,32 +79,36 @@
Private Sub DragStart(sender As Object, e As MouseButtonEventArgs) Handles Me.MouseLeftButtonDown
e.Handled = True '防止 ScrollViewer 失焦问题
DragControl = Me
RefreshColor()
FrmMain.DragDoing()
AniStart({
AaScaleTransform(ShapeDot, 0.8 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 75,, New AniEaseOutFluent)
AaScaleTransform(ShapeDot, 1.3 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 40,, New AniEaseOutFluent)
}, "MySlider Scale " & Uuid)
'更新 Popup
If GetHintText IsNot Nothing Then
TextHint.Text = GetHintText.DynamicInvoke(Value)
Popup.IsOpen = True
AniStop("MySlider KeyPopup " & Uuid)
End If
RefreshPopup()
AniStop("MySlider KeyPopup " & Uuid)
End Sub
Public Sub DragDoing()
Dim Percent As Double = MathRange((Mouse.GetPosition(PanMain).X - 8) / (ActualWidth - 16), 0, 1)
Dim Percent As Double = MathClamp((Mouse.GetPosition(PanMain).X - ShapeDot.Width / 2) / (ActualWidth - ShapeDot.Width), 0, 1)
Dim NewValue As Integer = Percent * MaxValue
If Not NewValue = Value Then
Value = NewValue
End If
'更新 Popup
If GetHintText IsNot Nothing Then TextHint.Text = GetHintText.DynamicInvoke(NewValue)
RefreshPopup()
End Sub
Public Sub DragStop()
RefreshColor()
AniStart({
AaScaleTransform(ShapeDot, 1 - CType(ShapeDot.RenderTransform, ScaleTransform).ScaleX, 200,, New AniEaseOutFluent)
}, "MySlider Scale " & Uuid)
If GetHintText IsNot Nothing Then Popup.IsOpen = False
Popup.IsOpen = False
End Sub
Public Sub RefreshPopup()
If GetHintText Is Nothing Then Return
Popup.IsOpen = True
TextHint.Text = GetHintText.DynamicInvoke(Value)
Dim typeface As New Typeface(TextHint.FontFamily, TextHint.FontStyle, TextHint.FontWeight, TextHint.FontStretch)
Dim formattedText As New FormattedText(TextHint.Text, Thread.CurrentThread.CurrentCulture, TextHint.FlowDirection, typeface, TextHint.FontSize, TextHint.Foreground, DPI)
TextHint.Width = formattedText.Width '使用手动测量的宽度修复 #1057
End Sub
'指向动画
@@ -113,28 +117,39 @@
Try
'判断当前颜色
Dim ColorName As String
Dim ForegroundName As String, DotFillName As String
Dim AnimationTime As Integer
If IsEnabled Then
If IsMouseOver OrElse (Not IsNothing(DragControl) AndAlso DragControl.Equals(Me)) Then
ColorName = "ColorBrush3"
AnimationTime = 100
If Not IsNothing(DragControl) AndAlso DragControl.Equals(Me) Then
ForegroundName = "ColorBrush3"
DotFillName = "ColorBrush3"
AnimationTime = 40
ElseIf IsMouseOver Then
ForegroundName = "ColorBrush3"
DotFillName = "ColorBrush3"
AnimationTime = 40
Else
ColorName = "ColorBrush1"
AnimationTime = 200
ForegroundName = "ColorBrushBg0"
DotFillName = "ColorBrushBg0"
AnimationTime = 100
End If
Else
ColorName = "ColorBrushGray4"
ForegroundName = "ColorBrushGray5"
DotFillName = "ColorBrushGray5"
AnimationTime = 200
End If
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
AniStart({AaColor(Me, BorderBrushProperty, ColorName, AnimationTime)}, "MySlider Color " & Uuid)
AniStart({
AaColor(Me, BorderBrushProperty, ForegroundName, AnimationTime),
AaColor(ShapeDot, Ellipse.FillProperty, DotFillName, AnimationTime)
}, "MySlider Color " & Uuid)
Else
'无动画
AniStop("MySlider Color " & Uuid)
SetResourceReference(BorderBrushProperty, ColorName)
SetResourceReference(BorderBrushProperty, ForegroundName)
ShapeDot.SetResourceReference(Ellipse.FillProperty, DotFillName)
End If
Catch ex As Exception
@@ -150,7 +165,7 @@
End Sub
Private Sub MySlider_KeyDown(sender As Object, e As KeyEventArgs) Handles Me.KeyDown
'拒绝一边拖动一边用按键改变
If ReferenceEquals(Me, DragControl) Then Exit Sub
If ReferenceEquals(Me, DragControl) Then Return
'改变值
If e.Key = Key.Left Then
ChangeByKey = True
@@ -163,12 +178,11 @@
ChangeByKey = False
e.Handled = True
Else
Exit Sub
Return
End If
'更新 Popup
If GetHintText IsNot Nothing Then
TextHint.Text = GetHintText.DynamicInvoke(Value)
Popup.IsOpen = True
RefreshPopup()
AniStop("MySlider KeyPopup " & Uuid)
AniStart(AaCode(Sub() Popup.IsOpen = False, 700 * AniSpeed), "MySlider KeyPopup " & Uuid)
End If
+108 -91
View File
@@ -3,8 +3,18 @@
'自定义属性
Public Property HasAnimation As Boolean = True
Public Property HasBackground As Boolean = True
Public Property ShowValidateResult As Boolean = True
Public Property CornerRadius As CornerRadius
Get
Return GetValue(CornerRadiusProperty)
End Get
Set(value As CornerRadius)
SetValue(CornerRadiusProperty, value)
End Set
End Property
Public Shared ReadOnly CornerRadiusProperty As DependencyProperty =
DependencyProperty.Register("CornerRadius", GetType(CornerRadius), GetType(MyTextBox), New PropertyMetadata(New CornerRadius(3)))
'额外控件初始化
@@ -26,7 +36,7 @@
End Property
Public Overrides Sub OnApplyTemplate()
MyBase.OnApplyTemplate()
If HintText = "" OrElse labHint.Text <> "" Then Exit Sub
If HintText = "" OrElse labHint.Text <> "" Then Return
labHint.Text = If(Text = "", HintText, "")
End Sub
@@ -62,7 +72,24 @@
SetValue(ValidateResultProperty, value)
End Set
End Property
Public Shared ReadOnly ValidateResultProperty As DependencyProperty = DependencyProperty.Register("ValidateResult", GetType(String), GetType(MyTextBox), New PropertyMetadata(""))
Public Shared ReadOnly ValidateResultProperty As DependencyProperty =
DependencyProperty.Register("ValidateResult", GetType(String), GetType(MyTextBox), New PropertyMetadata("",
Sub(d As MyTextBox, e As DependencyPropertyChangedEventArgs)
d.SetValue(IsValidatedPropertyKey, String.IsNullOrEmpty(e.NewValue))
End Sub))
''' <summary>
''' 是否通过了输入验证。
''' </summary>
Public ReadOnly Property IsValidated As Boolean
Get
Return GetValue(IsValidatedProperty)
End Get
End Property
Private Shared ReadOnly IsValidatedPropertyKey As DependencyPropertyKey =
DependencyProperty.RegisterReadOnly("IsValidated", GetType(Boolean), GetType(MyTextBox), New PropertyMetadata(True))
Public Shared ReadOnly IsValidatedProperty As DependencyProperty = IsValidatedPropertyKey.DependencyProperty
''' <summary>
''' 输入验证的规则。
''' </summary>
@@ -81,90 +108,87 @@
''' </summary>
Public Sub Validate() Handles Me.Loaded
'执行输入验证
ValidateResult = ""
For Each ValidateRule As Validate In ValidateRules
ValidateResult = ValidateRule.Validate(Text)
If IsNothing(ValidateResult) OrElse Not ValidateResult = "" Then Exit For
Next
Dim NewResult As Integer = If(ValidateResult = "", 0, 1)
ValidateResult = ModValidate.Validate(Text, ValidateRules)
'根据结果改变样式
If ShownValidateResult <> NewResult Then
If ShownValidateResult <> If(IsValidated, ValidateState.Success, ValidateState.FailedAndShowDetail) Then
If IsLoaded AndAlso labWrong IsNot Nothing Then
ChangeValidateResult(ValidateResult = "", True)
ChangeValidateResult(IsValidated, True)
Else
RunInNewThread(Sub()
Thread.Sleep(30)
RunInUi(Sub() ChangeValidateResult(NewResult, False))
End Sub, "DelayedValidate Change")
RunInNewThread(
Sub()
Thread.Sleep(30)
RunInUi(Sub() ChangeValidateResult(IsValidated, False))
End Sub, "DelayedValidate Change")
End If
End If
'更新错误信息
If ShowValidateResult AndAlso Not ValidateResult = "" Then
If ShowValidateResult AndAlso Not IsValidated Then
If IsLoaded AndAlso labWrong IsNot Nothing Then
labWrong.Text = ValidateResult
Else
RunInNewThread(Sub()
Dim IsFinished As Boolean = False
Do Until IsFinished
Thread.Sleep(20)
RunInUiWait(Sub()
If labWrong IsNot Nothing Then
labWrong.Text = ValidateResult
IsFinished = True
End If
If Not IsLoaded Then IsFinished = True
End Sub)
Loop
End Sub, "DelayedValidate Text")
RunInNewThread(
Sub()
Dim IsFinished As Boolean = False
Do Until IsFinished
Thread.Sleep(20)
RunInUiWait(
Sub()
If labWrong IsNot Nothing Then
labWrong.Text = ValidateResult
IsFinished = True
End If
If Not IsLoaded Then IsFinished = True
End Sub)
Loop
End Sub, "DelayedValidate Text")
End If
End If
End Sub
Private ShownValidateResult As Integer = -1
Private Sub ChangeValidateResult(NewResult As Boolean, IsLoaded As Boolean)
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso IsTextChanged AndAlso labWrong IsNot Nothing Then
If NewResult Then
''' <summary>
''' 强制显示结果为正常,类似尚未输入过文本的状态。不影响实际的检查结果。
''' </summary>
Public Sub ForceShowAsSuccess()
IsTextChanged = False
ChangeValidateResult(IsValidated, True)
End Sub
Private ShownValidateResult As ValidateState = ValidateState.NotInited
Private Sub ChangeValidateResult(IsSuccessful As Boolean, IsLoaded As Boolean)
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso labWrong IsNot Nothing Then
If IsSuccessful OrElse Not IsTextChanged Then
'变为正确
ShownValidateResult = 0
ShownValidateResult = If(IsSuccessful, ValidateState.Success, ValidateState.FailedButTextNotChanged)
AniStart({
AaOpacity(labWrong, -labWrong.Opacity, 150),
AaHeight(labWrong, -labWrong.Height, 150,, New AniEaseOutFluent),
AaCode(Sub() labWrong.Visibility = Visibility.Collapsed,, True)
}, "MyTextBox Validate " & Uuid)
AaOpacity(labWrong, -labWrong.Opacity, 150),
AaHeight(labWrong, -labWrong.Height, 150,, New AniEaseOutFluent),
AaCode(Sub() labWrong.Visibility = Visibility.Collapsed,, True)
}, "MyTextBox Validate " & Uuid)
ElseIf ShowValidateResult Then
'变为错误
ShownValidateResult = 1
ShownValidateResult = ValidateState.FailedAndShowDetail
labWrong.Visibility = Visibility.Visible
AniStart({
AaOpacity(labWrong, 1 - labWrong.Opacity, 170),
AaHeight(labWrong, 21 - labWrong.Height, 300,, New AniEaseOutBack(AniEasePower.Weak))
}, "MyTextBox Validate " & Uuid)
AaOpacity(labWrong, 1 - labWrong.Opacity, 150),
AaHeight(labWrong, 21 - labWrong.Height, 150,, New AniEaseOutFluent)
}, "MyTextBox Validate " & Uuid)
Else
'变为错误,但不显示文本
ShownValidateResult = 2
ShownValidateResult = ValidateState.FailedAndHideDetail
End If
Else
ShownValidateResult = 3
'AniStop("MyTextBox Validate " & Uuid)
'If NewResult Then
' '变为正确
' labWrong.Opacity = 0
' labWrong.Height = 0
' labWrong.Visibility = Visibility.Collapsed
'Else
' '变为错误
' labWrong.Visibility = Visibility.Visible
' labWrong.Text = ValidateResult
' labWrong.Opacity = 1
' labWrong.Height = 20.5
'End If
'Dim OriginalEnabled As Integer = AniControlEnabled
'AniControlEnabled += 1
'RefreshColor()
'AniControlEnabled = OriginalEnabled
ShownValidateResult = ValidateState.NotLoaded
End If
RefreshColor()
RaiseEvent ValidateChanged(Me, New EventArgs)
End Sub
Private Enum ValidateState
NotInited
Success
FailedButTextNotChanged
FailedAndShowDetail
FailedAndHideDetail
NotLoaded
End Enum
'提示文本
@@ -172,16 +196,19 @@
''' 是否已经由用户输入过文本,若尚未输入过,则不显示输入检查的失败。
''' </summary>
Private IsTextChanged As Boolean = False
Private _HintText As String = ""
Public Property HintText As String
Get
Return _HintText
Return GetValue(HintTextProperty)
End Get
Set(value As String)
_HintText = value
If labHint IsNot Nothing Then labHint.Text = If(Text = "", HintText, "")
SetValue(HintTextProperty, value)
End Set
End Property
Public Shared ReadOnly HintTextProperty As DependencyProperty =
DependencyProperty.Register("HintText", GetType(String), GetType(MyTextBox), New PropertyMetadata("",
Sub(t As MyTextBox, e As DependencyPropertyChangedEventArgs)
If t.labHint IsNot Nothing Then t.labHint.Text = If(t.Text = "", t.HintText, "")
End Sub))
Private Sub MyTextBox_TextChanged(sender As MyTextBox, e As TextChangedEventArgs) Handles Me.TextChanged
Try
'改变提示文本
@@ -190,11 +217,11 @@
IsTextChanged = IsLoaded
'进行输入验证
Validate()
If Not ValidateResult = "" Then Exit Sub
If Not IsValidated Then Return
'改变文本
RaiseEvent ValidatedTextChanged(sender, e)
Catch ex As Exception
Log(ex, "进行输入验证时出错", LogLevel.Assert)
Log(ex, "进行输入验证时出错", LogLevel.Critical)
End Try
End Sub
@@ -202,47 +229,37 @@
Private Sub RefreshColor() Handles Me.IsEnabledChanged, Me.MouseEnter, Me.MouseLeave, Me.GotFocus, Me.LostFocus
Try
'手动关闭动画
If Not HasAnimation Then Exit Sub
'不对 ComboBox 从属进行动画
If TemplatedParent IsNot Nothing AndAlso TypeOf TemplatedParent Is MyComboBox Then Exit Sub
If TemplatedParent IsNot Nothing AndAlso TypeOf TemplatedParent Is MyComboBox Then Return
'判断当前颜色
Dim ForeColorName As String, BackColorName As String
Dim AnimationTime As Integer
If IsEnabled Then
If ValidateResult = "" OrElse Not IsTextChanged Then
If IsValidated OrElse Not IsTextChanged Then
If IsFocused Then
ForeColorName = "ColorBrush4"
BackColorName = "ColorBrush9"
AnimationTime = 60
ElseIf IsMouseOver Then
ForeColorName = "ColorBrush3"
BackColorName = "ColorBrush7"
AnimationTime = 10
ElseIf IsMouseOver Then
ForeColorName = "ColorBrush4"
BackColorName = "ColorBrush7"
AnimationTime = 100
Else '未选中
ForeColorName = "ColorBrushBg0"
BackColorName = "ColorBrushHalfWhite"
AnimationTime = 100
Else
ForeColorName = "ColorBrush1"
BackColorName = "ColorBrushHalfWhite"
AnimationTime = 200
End If
Else
ForeColorName = "ColorBrushRedLight"
BackColorName = "ColorBrushRedBack"
AnimationTime = 200
'If IsFocused OrElse IsMouseOver Then
' ForeColorName = "ColorBrushRedLight"
' BackColorName = "ColorBrushRedBack"
' AnimationTime = 100
'Else
' ForeColorName = "ColorBrushRedDark"
' BackColorName = "ColorBrushHalfWhite"
' AnimationTime = 200
'End If
End If
Else
ForeColorName = "ColorBrushGray4"
BackColorName = "ColorBrushHalfWhite"
ForeColorName = "ColorBrushGray5"
BackColorName = "ColorBrushGray6"
AnimationTime = 200
End If
If Not HasBackground Then BackColorName = "ColorBrushTransparent"
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
'有动画
@@ -263,7 +280,7 @@
End Sub
Private Sub RefreshTextColor() Handles Me.IsEnabledChanged
Dim NewColor As MyColor = If(IsEnabled, ColorGray1, ColorGray4)
If CType(Foreground, SolidColorBrush).Color.R = NewColor.R Then Exit Sub
If CType(Foreground, SolidColorBrush).Color.R = NewColor.R Then Return
If IsLoaded AndAlso AniControlEnabled = 0 AndAlso Not Text = "" Then
'有动画
AniStart({AaColor(Me, ForegroundProperty, If(IsEnabled, "ColorBrushGray1", "ColorBrushGray4"), 200)}, "MyTextBox TextColor " & Uuid)
@@ -72,7 +72,7 @@
Time = AnimationTimeOut
End If
'重复性验证
If ColorName = ForeName Then Exit Sub
If ColorName = ForeName Then Return
ColorName = ForeName
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
@@ -90,21 +90,21 @@
Get
Return GetValue(EventTypeProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventTypeProperty, value)
End Set
End Property
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register("EventType", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing))
Public Shared ReadOnly EventTypeProperty As DependencyProperty = DependencyProperty.Register(
"EventType", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing))
Public Property EventData As String
Get
Return GetValue(EventDataProperty)
End Get
Set(ByVal value As String)
Set(value As String)
SetValue(EventDataProperty, value)
End Set
End Property
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register("EventData", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing))
Public Shared ReadOnly EventDataProperty As DependencyProperty = DependencyProperty.Register(
"EventData", GetType(String), GetType(MyTextButton), New PropertyMetadata(Nothing))
End Class
+30 -26
View File
@@ -1,16 +1,22 @@
<Window
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Name="WindMain" x:Class="FormMain" Style="{StaticResource MyWindow}"
AllowDrop="True" Topmost="True" Title="Plain Craft Launcher 2 " AllowsTransparency="True" MinHeight="450" MinWidth="760" ScrollViewer.VerticalScrollBarVisibility="Disabled" Icon="/Plain Craft Launcher 2;component/Images/icon.ico" Left="-10000" WindowStyle="None" ResizeMode="CanMinimize" Background="{x:Null}" d:DesignWidth="870" d:DesignHeight="520" Width="850" Height="500" RenderTransformOrigin="0.5,0.5">
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" mc:Ignorable="d"
x:Name="WindMain" x:Class="FormMain" Style="{StaticResource MyWindow}"
AllowDrop="True" Topmost="True" Title="Plain Craft Launcher " AllowsTransparency="True" MinHeight="470" MinWidth="810"
ScrollViewer.VerticalScrollBarVisibility="Disabled" Icon="/Plain Craft Launcher 2;component/Images/icon.ico" WindowStyle="None"
ResizeMode="CanMinimize" Background="{x:Null}" d:DesignWidth="870" d:DesignHeight="520" Width="850" Height="500"
RenderTransformOrigin="0.5,0.5">
<Window.TaskbarItemInfo>
<TaskbarItemInfo ThumbnailClipMargin="{Binding Margin, ElementName=PanForm}" />
</Window.TaskbarItemInfo>
<Grid x:Name="PanBack" SnapsToDevicePixels="True" UseLayoutRounding="True" Margin="1" RenderTransformOrigin="0.5,0.5">
<Grid x:Name="PanBack" SnapsToDevicePixels="True" UseLayoutRounding="True" Margin="10" RenderTransformOrigin="0.5,0.5">
<Grid.RenderTransform>
<ScaleTransform ScaleX="0.95" ScaleY="0.95" />
<TransformGroup>
<RotateTransform x:Name="TransformRotate" Angle="-4" />
<TranslateTransform x:Name="TransformPos" X="0" Y="60" />
</TransformGroup>
</Grid.RenderTransform>
<Rectangle x:Name="ResizerT" Stroke="{x:Null}" StrokeThickness="0.0001" Height="8" VerticalAlignment="Top" Margin="13,0" Cursor="SizeNS">
<Rectangle.Fill>
@@ -93,12 +99,10 @@
<Grid x:Name="PanTitle" Height="48">
<Grid.Background>
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0">
<GradientStop Color="{StaticResource ColorObject3}" Offset="0"/>
<GradientStop Color="{StaticResource ColorObject2}" Offset="0.5"/>
<GradientStop Color="{StaticResource ColorObject3}" Offset="1"/>
<GradientStop Color="{StaticResource ColorObject4}" Offset="0"/>
</LinearGradientBrush>
</Grid.Background>
<Image x:Name="ImgTitle" IsHitTestVisible="False" Stretch="UniformToFill" IsEnabled="False" RenderOptions.BitmapScalingMode="LowQuality" />
<local:MyImage x:Name="ImgTitle" IsHitTestVisible="False" Stretch="UniformToFill" IsEnabled="False" RenderOptions.BitmapScalingMode="LowQuality" />
<local:MyIconButton x:Name="BtnTitleClose" HorizontalAlignment="Right" Height="28" VerticalAlignment="Center" Width="28" Margin="0,0,12,0" Theme="White"
LogoScale="0.72" Logo="F1 M2,0 L0,2 8,10 0,18 2,20 10,12 18,20 20,18 12,10 20,2 18,0 10,8 2,0Z" />
<local:MyIconButton x:Name="BtnTitleMin" HorizontalAlignment="Right" Height="28" VerticalAlignment="Center" Width="28" Margin="0,0,44,0" Theme="White"
@@ -109,26 +113,26 @@
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Path x:Name="ShapeTitleLogo" Data="M26,29 v-25 h5 a7,7 180 0 1 0,14 h-5 M61,6.5 a10,11.5 180 1 0 0,18 M68,2.5 v24.5 h12 M98,2 v27 M107,2 v27" SnapsToDevicePixels="False" UseLayoutRounding="False" IsHitTestVisible="False" HorizontalAlignment="Left" Margin="19,15.5,0,15.5" Stretch="fill" Stroke="White" StrokeThickness="1.9" Width="53" />
<Path x:Name="ShapeTitleLogo" Data="M26,29 v-25 h6 a7,7 180 0 1 0,14 h-6 M62.5,6.5 a10,11.5 180 1 0 0,18 M71,2.5 v24.5 h13.5" SnapsToDevicePixels="False" UseLayoutRounding="False" IsHitTestVisible="False" HorizontalAlignment="Left" Margin="19,15.5,0,15.5" Stretch="fill" Stroke="White" StrokeThickness="2.2" Width="39" />
<TextBlock x:Name="LabTitleLogo" Visibility="Collapsed" SnapsToDevicePixels="False" UseLayoutRounding="False" IsHitTestVisible="False" HorizontalAlignment="Left" Margin="18,0,0,0" Foreground="White" FontSize="17" VerticalAlignment="Center" />
<Image x:Name="ImageTitleLogo" SnapsToDevicePixels="False" UseLayoutRounding="False" IsHitTestVisible="False" HorizontalAlignment="Left" Margin="7" VerticalAlignment="Center" Visibility="Collapsed" />
<local:MyImage x:Name="ImageTitleLogo" SnapsToDevicePixels="False" UseLayoutRounding="False" IsHitTestVisible="False" HorizontalAlignment="Left" Margin="7" VerticalAlignment="Center" Visibility="Collapsed" />
<StackPanel Grid.Column="1" x:Name="PanTitleSelect" HorizontalAlignment="Left" Height="27" VerticalAlignment="Center" Orientation="Horizontal" Margin="13,0">
<local:MyRadioButton x:Name="BtnTitleSelect0" Text="{DynamicResource LangTitleHome}" Tag="0" Margin="5,0" Checked="True" Padding="2,0"
LogoScale="0.95" Logo="M985.403 552.96C985.403 812.702 773.041 1024 512 1024S38.597 812.702 38.597 552.96c0-158.208 79.163-304.955 211.771-392.625 31.074-20.52 72.94-11.973 93.46 19.101s12.012 72.94-19.062 93.46c-94.681 62.622-151.237 167.306-151.237 280.064 0 185.344 151.788 336.108 338.471 336.108S850.471 738.304 850.471 552.96c0-114.649-57.974-220.278-155.096-282.585-31.35-20.125-40.448-61.833-20.362-93.184s61.794-40.448 93.184-20.4c135.995 87.236 217.206 235.362 217.206 396.169zM512 560.128c37.258 0 67.466-30.208 67.466-67.466V67.466C579.466 30.208 549.258 0 512 0s-67.466 30.208-67.466 67.466v425.196c0 37.258 30.208 67.466 67.466 67.466z" />
<local:MyRadioButton x:Name="BtnTitleSelect1" Text="{DynamicResource LangTitleDownload}" Tag="1" Margin="5,0" Padding="2,0"
LogoScale="0.9" Logo="M955.076923 610.461538h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462v196.923077c0 15.753846-13.784615 29.538462-29.538461 29.538461h-649.846154c-15.753846 0-29.538462-13.784615-29.538461-29.538461v-196.923077c0-15.753846-13.784615-29.538462-29.538462-29.538462h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462V905.846154c0 43.323077 35.446154 78.769231 78.769231 78.769231h787.692308c43.323077 0 78.769231-35.446154 78.769231-78.769231V640c0-15.753846-13.784615-29.538462-29.538462-29.538462zM492.307692 740.430769c11.815385 11.815385 29.538462 11.815385 41.353846 0l265.846154-265.846154c11.815385-11.815385 11.815385-29.538462 0-41.353846l-41.353846-41.353846c-11.815385-11.815385-29.538462-11.815385-41.353846 0l-110.276923 110.276923c-11.815385 11.815385-33.476923 3.938462-33.476923-13.784615V68.923077C571.076923 53.169231 555.323077 39.384615 541.538462 39.384615h-59.076924c-15.753846 0-29.538462 13.784615-29.538461 29.538462v417.476923c0 17.723077-21.661538 25.6-33.476923 13.784615l-110.276923-110.276923c-11.815385-11.815385-29.538462-11.815385-41.353846 0L226.461538 433.230769c-11.815385 11.815385-11.815385 29.538462 0 41.353846L492.307692 740.430769z" />
<local:MyRadioButton x:Name="BtnTitleSelect0" Text="启动" Tag="0" Margin="5,0" Checked="True" Padding="2,0"
LogoScale="0.9" Logo="M52.1,164.5c-1.4,0-3.1-0.5-4.2-1.3c-2.6-1.7-4-4.2-4-7V43.8c0-2.9,1.6-5.8,4.1-7c1.2-0.8,2.7-1.2,4.1-1.2c1.5,0,2.9,0.4,4.2,1.2L153.1,93c0,0,0.1,0,0.1,0.1c2.6,1.7,4,4.2,4,7c0,3-1.7,5.8-4.2,7.1l-96.8,56.2C55.1,164,53.5,164.5,52.1,164.5z M60.4,142.1l72.1-42.1L60.4,58.2V142.1z" />
<local:MyRadioButton x:Name="BtnTitleSelect1" Text="下载" Tag="1" Margin="5,0" Padding="2,0"
LogoScale="0.9" Logo="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
<local:MyRadioButton x:Name="BtnTitleSelect2" Text="联机" Tag="2" Margin="5,0" Padding="2,0"
LogoScale="1.05" Logo="M512 817c-48.601 0-88-39.399-88-88s39.399-88 88-88 88 39.399 88 88-39.399 88-88 88zM237.671 565.74C308.335 474.58 397.369 429 504.774 429c118.433 0 214.225 55.421 287.377 166.264l-53.407 30.369c-13.84 7.87-31.362 4.367-41.114-8.219-50.291-64.911-114.577-97.367-192.856-97.367-86.851 0-156.835 40.318-209.95 120.953l-47.995-28.02c-15.263-8.91-20.412-28.507-11.502-43.77a32 32 0 0 1 2.344-3.47zM107.691 419.47C205.24 278.491 337.805 208 505.379 208c178.77 0 317.694 80.224 416.772 240.672l-56.54 31.73c-13.686 7.68-30.922 4.303-40.697-7.975C735.581 360.213 629.07 303.009 505.38 300.815 373.997 298.485 261.637 362.88 168.3 494l-50.116-28.505c-15.362-8.738-20.732-28.275-11.994-43.637a32 32 0 0 1 1.5-2.387z"/>
<local:MyRadioButton x:Name="BtnTitleSelect3" Text="{DynamicResource LangTitleSetup}" Tag="3" Margin="5,0" Padding="2,0"
<local:MyRadioButton x:Name="BtnTitleSelect3" Text="设置" Tag="3" Margin="5,0" Padding="2,0"
LogoScale="1.1" Logo="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z"/>
<local:MyRadioButton x:Name="BtnTitleSelect4" Text="{DynamicResource LangTitleOther}" Tag="4" Margin="5,0" Padding="2,0"
LogoScale="0.93" Logo="M364.145778 0h-273.066667C40.846222 0 0 40.846222 0 91.022222v273.066667C0 414.264889 40.846222 455.111111 91.136 455.111111h273.066667C414.321778 455.111111 455.111111 414.264889 455.111111 364.032V91.022222C455.111111 40.846222 414.321778 0 364.145778 0zM341.333333 341.333333H113.777778V113.777778h227.555555v227.555555zM933.034667 0h-273.066667C609.792 0 568.888889 40.846222 568.888889 91.022222v273.066667c0 50.176 40.903111 91.022222 91.136 91.022222h273.066667C983.210667 455.111111 1024 414.264889 1024 364.032V91.022222c0-50.176-40.789333-91.022222-90.965333-91.022222zM910.222222 341.333333h-227.555555V113.777778h227.555555v227.555555zM364.145778 568.888889h-273.066667C40.846222 568.888889 0 609.735111 0 659.911111v273.066667c0 50.176 40.846222 91.022222 91.136 91.022222h273.066667C414.321778 1024 455.111111 983.153778 455.111111 932.920889v-273.066667C455.111111 609.735111 414.321778 568.888889 364.145778 568.888889zM341.333333 910.222222H113.777778v-227.555555h227.555555v227.555555zM933.034667 568.888889h-273.066667c-50.176 0-91.079111 40.846222-91.079111 91.022222v273.066667c0 50.176 40.903111 91.022222 91.136 91.022222h273.066667c50.119111 0 90.908444-40.846222 90.908444-91.079111v-273.066667c0-50.119111-40.789333-90.965333-90.965333-90.965333zM910.222222 910.222222h-227.555555v-227.555555h227.555555v227.555555z"/>
<local:MyRadioButton x:Name="BtnTitleSelect4" Text="更多" Tag="4" Margin="5,0" Padding="2,0"
LogoScale="0.93" Logo="M364 0h-273C40 0 0 40 0 91v273C0 414 40 455 91 455h273C414 455 455 414 455 364V91C455 40 414 0 364 0zM341 341H113V113h227v227zM933 0h-273C609 0 568 40 568 91v273c0 50 40 91 91 91h273C983 455 1024 414 1024 364V91c0-50-40-91-90-91zM910 341h-227V113h227v227zM364 568h-273C40 568 0 609 0 659v273c0 50 40 91 91 91h273C414 1024 455 983 455 932v-273C455 609 414 568 364 568zM341 910H113v-227h227v227zM933 568h-273c-50 0-91 40-91 91v273c0 50 40 91 91 91h273c50 0 90-40 90-91v-273c0-50-40-90-90-90zM910 910h-227v-227h227v227z"/>
</StackPanel>
</Grid>
<Grid x:Name="PanTitleInner" Visibility="Collapsed" Margin="-16,0,0,0" Opacity="0" HorizontalAlignment="Left" Width="{Binding ActualWidth, ElementName=PanTitle, Mode=OneWay}">
<local:MyIconButton HorizontalAlignment="Left" Theme="White" x:Name="BtnTitleInner" Margin="12,0,0,0" Height="28" Width="28"
LogoScale="0.87" Logo="M1097.162313 584.707482 250.272424 584.707482 562.833701 896.95123C591.749274 925.859979 591.749274 972.659975 562.833701 1001.568724 533.91812 1030.477473 487.058315 1030.477473 458.142742 1001.568724L21.580946 565.451235C6.757449 550.631234-0.361728 531.131238 0.028357 511.679985L0.028357 511.631236 0.028357 511.582486C-0.361728 492.13124 6.757449 472.582488 21.580946 457.762487L458.142742 21.644997C487.058315-7.215002 533.91812-7.215002 562.833701 21.644997 591.749274 50.553746 591.749274 97.4025 562.833701 126.262499L250.272424 438.55499 1097.162313 438.55499C1137.585605 438.55499 1170.304578 471.266238 1170.304578 511.631236 1170.304578 551.947483 1137.585605 584.707482 1097.162313 584.707482L1097.162313 584.707482Z" />
<TextBlock SnapsToDevicePixels="False" IsHitTestVisible="False" Name="LabTitleInner" VerticalAlignment="Center" Margin="47,1,0,0" HorizontalAlignment="Left" Foreground="{DynamicResource ColorBrush8}" FontSize="15" />
LogoScale="0.87" Logo="M1097 584 250 584 562 896C591 925 591 972 562 1001 533 1030 487 1030 458 1001L21 565C6 550-0 531 0 511L0 511 0 511C-0 492 6 472 21 457L458 21C487-7 533-7 562 21 591 50 591 97 562 126L250 438 1097 438C1137 438 1170 471 1170 511 1170 551 1137 584 1097 584L1097 584Z" />
<TextBlock SnapsToDevicePixels="False" IsHitTestVisible="False" Name="LabTitleInner" VerticalAlignment="Center" Margin="47,1,60,0" HorizontalAlignment="Left" Foreground="{DynamicResource ColorBrush8}" FontSize="15" />
</Grid>
</Grid>
<Grid x:Name="PanLeft" Grid.Row="1" HorizontalAlignment="Left" SnapsToDevicePixels="True">
@@ -139,7 +143,7 @@
<Rectangle x:Name="RectLeftBackground" Width="0" Fill="{DynamicResource ColorBrushBackgroundTransparentSidebar}" IsHitTestVisible="False" />
<Rectangle x:Name="RectLeftShadow" Width="4" HorizontalAlignment="Left" IsHitTestVisible="False" Grid.Column="1" >
<Rectangle.Fill>
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0" Opacity="0.085">
<LinearGradientBrush EndPoint="1,0" StartPoint="0,0" Opacity="0.04">
<GradientStop Color="#000000" Offset="0"/>
<GradientStop Color="#00000000" Offset="1"/>
</LinearGradientBrush>
@@ -160,12 +164,12 @@
</Border>
</Border>
</Grid>
<StackPanel x:Name="PanHint" UseLayoutRounding="True" SnapsToDevicePixels="True" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,25" IsHitTestVisible="False" Grid.RowSpan="2" />
<StackPanel x:Name="PanHint" IsHitTestVisible="False" UseLayoutRounding="True" SnapsToDevicePixels="True" HorizontalAlignment="Left" VerticalAlignment="Bottom" Margin="0,0,0,20" Grid.RowSpan="2" />
<StackPanel HorizontalAlignment="Right" VerticalAlignment="Bottom" Grid.Row="1" Margin="15">
<local:MyExtraButton x:Name="BtnExtraBack" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="返回顶部" Visibility="Collapsed"
Logo="M858.496 188.9024 173.1072 188.9024c-30.2848 0-54.8352-24.5504-54.8352-54.8352L118.272 106.6496c0-30.2848 24.5504-54.8352 54.8352-54.8352l685.3888 0c30.2848 0 54.8352 24.5504 54.8352 54.8352l0 27.4176C913.3312 164.352 888.7808 188.9024 858.496 188.9024L858.496 188.9024zM150.6048 550.8608c0 0 300.0064-240.3584 303.0272-243.328 13.9776-13.5936 31.1808-21.8624 48.8192-24.7552 1.7152-0.3072 3.4304-0.5888 5.1456-0.768 2.7392-0.3072 5.4528-0.3584 8.192-0.3328 2.7392-0.0256 5.4272 0.0256 8.1664 0.3328 1.7408 0.1792 3.4304 0.4864 5.1456 0.768 17.664 2.8928 34.8672 11.1616 48.8192 24.7552 3.0464 2.944 303.0016 243.328 303.0016 243.328 32.384 31.5136 29.6192 63.9744-2.7392 95.5136-32.3328 31.5392-75.648 2.9696-108.0064-28.544l-185.8816-147.1232 0 485.8368c0 30.3104-24.5248 54.8608-54.8352 54.8608l-27.392 0c-30.2848 0-54.8352-24.5504-54.8352-54.8608L447.232 470.7072l-185.8304 147.0976c-32.3584 31.5392-75.6992 60.1344-108.032 28.5696C121.0368 614.8352 118.272 582.3744 150.6048 550.8608L150.6048 550.8608zM150.6048 550.8608" />
<local:MyExtraButton x:Name="BtnExtraDownload" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="下载管理" Visibility="Collapsed"
Logo="M955.076923 610.461538h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462v196.923077c0 15.753846-13.784615 29.538462-29.538461 29.538461h-649.846154c-15.753846 0-29.538462-13.784615-29.538461-29.538461v-196.923077c0-15.753846-13.784615-29.538462-29.538462-29.538462h-59.076923c-15.753846 0-29.538462 13.784615-29.538462 29.538462V905.846154c0 43.323077 35.446154 78.769231 78.769231 78.769231h787.692308c43.323077 0 78.769231-35.446154 78.769231-78.769231V640c0-15.753846-13.784615-29.538462-29.538462-29.538462zM492.307692 740.430769c11.815385 11.815385 29.538462 11.815385 41.353846 0l265.846154-265.846154c11.815385-11.815385 11.815385-29.538462 0-41.353846l-41.353846-41.353846c-11.815385-11.815385-29.538462-11.815385-41.353846 0l-110.276923 110.276923c-11.815385 11.815385-33.476923 3.938462-33.476923-13.784615V68.923077C571.076923 53.169231 555.323077 39.384615 541.538462 39.384615h-59.076924c-15.753846 0-29.538462 13.784615-29.538461 29.538462v417.476923c0 17.723077-21.661538 25.6-33.476923 13.784615l-110.276923-110.276923c-11.815385-11.815385-29.538462-11.815385-41.353846 0L226.461538 433.230769c-11.815385 11.815385-11.815385 29.538462 0 41.353846L492.307692 740.430769z" />
Logo="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
<local:MyExtraButton x:Name="BtnExtraApril" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="投降" Visibility="Collapsed"
Logo="M124.96 32c-28.64 0-60.064 23.2-60.064 51.904v856.192c0 28.576 30.688 51.904 59.296 51.904s60.064-23.328 60.064-51.904V83.904C184.256 55.2 153.536 32 124.96 32z m616.352 71.264c-168.416 0-168.416-69.024-336.8-69.024-97.216 0-172.256 45.344-172.256 45.344l-0.736 516.736s75.776-45.28 172.96-45.28c168.416 0 168.416 69.024 336.8 69.024 105.344 0 211.168-55.328 211.168-55.328V48.064c0.032 0-105.792 55.2-211.136 55.2z m0 0" />
<local:MyExtraButton x:Name="BtnExtraShutdown" HorizontalAlignment="Right" VerticalAlignment="Center" ToolTip="关闭 Minecraft" Visibility="Collapsed"
File diff suppressed because it is too large. Load diff
Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 312 B

After

Width:  |  Height:  |  Size: 3.8 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 999 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 912 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1001 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 861 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 958 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 947 B

@@ -577,10 +577,10 @@ Public Module ModAnimation
Public Class AniEaseLinear
Inherits AniEase
Public Overrides Function GetValue(t As Double) As Double
Return MathRange(t, 0, 1)
Return MathClamp(t, 0, 1)
End Function
Public Overrides Function GetDelta(t1 As Double, t0 As Double) As Double
Return MathRange(t1, 0, 1) - MathRange(t0, 0, 1)
Return MathClamp(t1, 0, 1) - MathClamp(t0, 0, 1)
End Function
End Class
@@ -595,7 +595,7 @@ Public Module ModAnimation
p = Power
End Sub
Public Overrides Function GetValue(t As Double) As Double
Return MathRange(t, 0, 1) ^ p
Return MathClamp(t, 0, 1) ^ p
End Function
End Class
''' <summary>
@@ -608,7 +608,7 @@ Public Module ModAnimation
p = Power
End Sub
Public Overrides Function GetValue(t As Double) As Double
Return 1 - MathRange(1 - t, 0, 1) ^ p
Return 1 - MathClamp(1 - t, 0, 1) ^ p
End Function
End Class
''' <summary>
@@ -624,6 +624,26 @@ Public Module ModAnimation
Return Ease.GetValue(t)
End Function
End Class
''' <summary>
''' 以特定速度开始的平滑结束。
''' </summary>
Public Class AniEaseOutFluentWithInitial
Inherits AniEase
Private ReadOnly alpha As Double '(初速度 / 平均速度) – 1
''' <param name="InitialPixelPerSecond">初速度,px/s</param>
''' <param name="TotalSecond">总时长,s</param>
''' <param name="TotalDistance">总路程,px</param>
Public Sub New(InitialPixelPerSecond As Double, TotalSecond As Double, TotalDistance As Double)
Dim v0_norm As Double = InitialPixelPerSecond * TotalSecond / TotalDistance '归一化初速度
alpha = v0_norm - 1.0
If alpha < 0 Then alpha = 0 '初速度小于平均速度时,退化为线性
End Sub
Public Overrides Function GetValue(percent As Double) As Double
Dim p As Double = MathClamp(percent, 0, 1)
If alpha = 0 Then Return p '退化到线性
Return (alpha + 1) * p / (1 + alpha * p)
End Function
End Class
'Back / 回弹
''' <summary>
@@ -636,7 +656,7 @@ Public Module ModAnimation
p = 3 - Power * 0.5
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = MathRange(t, 0, 1)
t = MathClamp(t, 0, 1)
Return t ^ p * Math.Cos(1.5 * Math.PI * (1 - t))
End Function
End Class
@@ -650,7 +670,7 @@ Public Module ModAnimation
p = 3 - Power * 0.5
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = MathRange(t, 0, 1)
t = MathClamp(t, 0, 1)
Return 1 - (1 - t) ^ p * Math.Cos(1.5 * Math.PI * t)
End Function
End Class
@@ -694,7 +714,7 @@ Public Module ModAnimation
p = Power + 4
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = MathRange(t, 0, 1)
t = MathClamp(t, 0, 1)
Return t ^ ((p - 1) * 0.25) * Math.Cos((p - 3.5) * Math.PI * (1 - t) ^ 1.5)
End Function
End Class
@@ -708,7 +728,7 @@ Public Module ModAnimation
p = Power + 4
End Sub
Public Overrides Function GetValue(t As Double) As Double
t = 1 - MathRange(t, 0, 1)
t = 1 - MathClamp(t, 0, 1)
Return 1 - t ^ ((p - 1) * 0.25) * Math.Cos((p - 3.5) * Math.PI * (1 - t) ^ 1.5)
End Function
End Class
@@ -766,7 +786,7 @@ Public Module ModAnimation
''' <summary>
''' 开始动画执行。
''' </summary>
Public Sub AniStartRun()
Public Sub AniStart()
'初始化计时器
AniLastTick = GetTimeTick()
AniFPSTimer = AniLastTick
@@ -777,12 +797,12 @@ Public Module ModAnimation
Log("[Animation] 动画线程开始")
Do While True
'两帧之间的间隔时间
Dim DeltaTime As Long = MathRange(GetTimeTick() - AniLastTick, 0, 10000)
Dim DeltaTime As Long = MathClamp(GetTimeTick() - AniLastTick, 0, 100000)
If DeltaTime < 3 Then GoTo Sleeper
AniLastTick = GetTimeTick()
'记录 FPS
If ModeDebug Then
If MathRange(AniLastTick - AniFPSTimer, 0, 10000) >= 500 Then
If MathClamp(AniLastTick - AniFPSTimer, 0, 100000) >= 500 Then
AniFPS = AniFPSCounter
AniFPSCounter = 0
AniFPSTimer = AniLastTick
@@ -807,7 +827,7 @@ Sleeper:
Thread.Sleep(1)
Loop
Catch ex As Exception
Log(ex, "动画帧执行失败", LogLevel.Assert)
Log(ex, "动画帧执行失败", LogLevel.Critical)
End Try
End Sub, "Animation", ThreadPriority.AboveNormal)
End Sub
@@ -869,7 +889,7 @@ NextAni:
Loop
'如果当前动画组都执行完毕则删除
If Entry.Data.Count = 0 Then
If Not Entry.Data.Any() Then
'为了避免新添加的动画影响顺序,不能 RemoveAt(i)
'为了允许动画在执行中添加同名动画组,不能按名字移除
For Current = 0 To AniGroups.Count - 1
@@ -904,7 +924,7 @@ NextAni:
Case AniTypeSub.Y
DeltaTop(Ani.Obj, Delta)
Case AniTypeSub.Opacity
Ani.Obj.Opacity = MathRange(Ani.Obj.Opacity + Delta, 0, 1)
Ani.Obj.Opacity = MathClamp(Ani.Obj.Opacity + Delta, 0, 1)
Case AniTypeSub.Width
Dim Obj As FrameworkElement = Ani.Obj
Obj.Width = Math.Max(If(Double.IsNaN(Obj.Width), Obj.ActualWidth, Obj.Width) + Delta, 0)
File diff suppressed because it is too large. Load diff
+110 -116
View File
@@ -85,23 +85,24 @@
Return _State
End Get
Set(value As LoadState)
If _State = value Then Exit Property
If _State = value Then Return
Dim OldState = _State
If value = LoadState.Finished AndAlso Setup.Get("SystemDebugDelay") Then Thread.Sleep(RandomInteger(100, 2000))
_State = value
Log("[Loader] 加载器 " & Name & " 状态改变:" & GetStringFromEnum(value))
'实现 ILoadingTrigger 接口与 OnStateChanged 回调
RunInUi(Sub()
Select Case value
Case LoadState.Loading
LoadingState = MyLoading.MyLoadingState.Run
Case LoadState.Failed
LoadingState = MyLoading.MyLoadingState.Error
Case Else
LoadingState = MyLoading.MyLoadingState.Stop
End Select
RaiseEvent OnStateChangedUi(Me, value, OldState)
End Sub)
RunInUi(
Sub()
Select Case value
Case LoadState.Loading
LoadingState = MyLoading.MyLoadingState.Run
Case LoadState.Failed
LoadingState = MyLoading.MyLoadingState.Error
Case Else
LoadingState = MyLoading.MyLoadingState.Stop
End Select
RaiseEvent OnStateChangedUi(Me, value, OldState)
End Sub)
If HasOnStateChangedThread Then RunInThread(Sub() RaiseEvent OnStateChangedThread(Me, value, OldState))
End Set
End Property
@@ -111,7 +112,7 @@
Return _LoadingState
End Get
Set(value As MyLoading.MyLoadingState)
If _LoadingState = value Then Exit Property
If _LoadingState = value Then Return
Dim OldState = _LoadingState
_LoadingState = value
RaiseEvent LoadingStateChanged(value, OldState)
@@ -153,10 +154,14 @@
End Select
End Get
Set(value As Double)
If _Progress = value Then Return
Dim OldValue = _Progress
_Progress = value
RaiseEvent ProgressChanged(value, OldValue)
End Set
End Property
Private _Progress As Double = -1
Public Event ProgressChanged(NewProgress As Double, OldProgress As Double) Implements ILoadingTrigger.ProgressChanged
''' <summary>
''' 计算总进度时的权重。它应该为预计时间(秒)。
''' </summary>
@@ -179,7 +184,7 @@
Thread.Sleep(10)
Loop
If State = LoadState.Finished Then
Exit Sub
Return
ElseIf State = LoadState.Aborted Then
Throw New ThreadInterruptedException("加载器执行已中断。")
ElseIf IsNothing([Error]) Then
@@ -202,7 +207,7 @@
If Timeout < 0 Then Throw New TimeoutException(TimeoutMessage)
Loop
If State = LoadState.Finished Then
Exit Sub
Return
ElseIf State = LoadState.Aborted Then
Throw New ThreadInterruptedException("加载器执行已中断。")
ElseIf IsNothing([Error]) Then
@@ -236,10 +241,16 @@
''' </summary>
Public ReadOnly Property IsAborted As Boolean
Get
Return LastRunningThread Is Nothing OrElse Not ReferenceEquals(Thread.CurrentThread, LastRunningThread)
Return IsAbortedWithThread(Thread.CurrentThread)
End Get
End Property
''' <summary>
''' 当前执行线程是否应当中断。需要手动提供加载器线程,用于需要跨线程检查的情况。
''' </summary>
Public Function IsAbortedWithThread(Thread As Thread) As Boolean
Return LastRunningThread Is Nothing OrElse Not ReferenceEquals(Thread, LastRunningThread) OrElse State = LoadState.Aborted
End Function
''' <summary>
''' 在输入相同时使用原有结果的超时,单位为毫秒。
''' </summary>
Public ReloadTimeout As Integer = -1
@@ -256,7 +267,7 @@
Public Output As OutputType = Nothing
'获取输入
Public Function StartGetInput(Optional Input As InputType = Nothing, Optional InputDelegate As Func(Of Object) = Nothing) As InputType
Public Function StartGetInput(Optional Input As InputType = Nothing, Optional InputDelegate As Func(Of Object) = Nothing) As InputType 'InputDelegate 参数存在匿名调用
If InputDelegate Is Nothing Then InputDelegate = Me.InputDelegate
Dim NewInput As InputType = Nothing '若 InputType 不能为 Nothing,则会导致 Input Is Nothing 永远失败,因此需要额外判断
If (Input Is Nothing OrElse (NewInput IsNot Nothing AndAlso Input.Equals(NewInput))) AndAlso InputDelegate IsNot Nothing Then
@@ -277,15 +288,13 @@
End SyncLock
End Try
'检验输入以确定情况
If (Not IsForceRestart) AndAlso '不要求强行重启
((Input IsNot Nothing AndAlso Input.Equals(Me.Input)) OrElse (Input Is Nothing AndAlso Me.Input Is Nothing)) AndAlso '输入相同
(State = LoadState.Loading OrElse State = LoadState.Finished) AndAlso '正在加载或已加载成功
If IsForceRestart Then Return True '强制要求重启
If ((Input Is Nothing) <> (Me.Input Is Nothing)) OrElse (Input IsNot Nothing AndAlso Not Input.Equals(Me.Input)) Then Return True '输入不同
If (State = LoadState.Loading OrElse State = LoadState.Finished) AndAlso '正在加载或已结束
(IgnoreReloadTimeout OrElse ReloadTimeout = -1 OrElse LastFinishedTime = 0 OrElse GetTimeTick() - LastFinishedTime < ReloadTimeout) Then '没有超时
'如果输入相同且未出错则不重试
Return False
Return False '则不重试
Else
'需要开始
Return True
Return True '需要开始
End If
End Function
Public Overrides Sub Start(Optional Input As Object = Nothing, Optional IsForceRestart As Boolean = False)
@@ -296,48 +305,53 @@
Me.Input = Input
SyncLock LockState
State = LoadState.Loading
Progress = -1
End SyncLock
Else
Exit Sub
Return
End If
LastRunningThread = New Thread(
Sub()
Try
IsForceRestarting = IsForceRestart
If ModeDebug Then Log("[Loader] 加载线程 " & Name & " (" & Thread.CurrentThread.ManagedThreadId & ") 已启动")
LoadDelegate(Me)
If IsAborted Then
Log("[Loader] 加载线程 " & Name & " (" & Thread.CurrentThread.ManagedThreadId & ") 已中断但线程正常运行至结束,输出被弃用(最新线程:" & If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId) & ")", LogLevel.Developer)
Else
RaisePreviewFinish()
State = LoadState.Finished
LastFinishedTime = GetTimeTick() '未中断,本次输出有效
End If
Catch ex As ThreadInterruptedException
If ModeDebug Then Log(ex, "加载线程 " & Name & " (" & Thread.CurrentThread.ManagedThreadId & ") 已触发线程中断")
'如果线程是因为判断到 IsAborted 而提前中止,则代表已有新线程被重启,此时不应当改为 Aborted
'如果线程是在没有 IsAborted 时手动引发了 ThreadInterruptedException,则代表没有重启线程,这通常代表用户手动取消,应当改为 Aborted
If Not IsAborted Then State = LoadState.Aborted
Catch ex As Exception
If IsAborted Then Exit Sub
Log(ex, "加载线程 " & Name & " (" & Thread.CurrentThread.ManagedThreadId & ") 发生运行时错误", LogLevel.Developer)
[Error] = ex
State = LoadState.Failed
End Try
End Sub) With {.Name = Name, .Priority = ThreadPriority}
Sub()
Try
IsForceRestarting = IsForceRestart
If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已{If(IsForceRestarting, "强制", "")}启动")
LoadDelegate(Me)
If IsAborted Then
Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已中断但线程正常运行至结束,输出被弃用(最新线程:{If(LastRunningThread Is Nothing, -1, LastRunningThread.ManagedThreadId)})", LogLevel.Developer)
Return
End If
If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已完成")
RaisePreviewFinish()
State = LoadState.Finished
LastFinishedTime = GetTimeTick() '未中断,本次输出有效
Catch ex As CancelledException
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发取消中断,已完成 {Math.Round(Progress * 100)}%")
If Not IsAborted Then State = LoadState.Aborted
Catch ex As ThreadInterruptedException
If ModeDebug Then Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 已触发线程中断,已完成 {Math.Round(Progress * 100)}%")
'如果线程是因为判断到 IsAborted 而提前中止,则代表已有新线程被重启,此时不应当改为 Aborted
'如果线程是在没有 IsAborted 时手动引发了 ThreadInterruptedException,则代表没有重启线程,这通常代表用户手动取消,应当改为 Aborted
If Not IsAborted Then State = LoadState.Aborted
Catch ex As Exception
If IsAborted Then Return
Log(ex, $"加载线程 {Name} ({Thread.CurrentThread.ManagedThreadId}) 出错,已完成 {Math.Round(Progress * 100)}%", LogLevel.Developer)
[Error] = ex
State = LoadState.Failed
End Try
End Sub) With {.Name = "L/" & Name, .Priority = ThreadPriority}
LastRunningThread.Start() '不能使用 RunInNewThread,否则在函数返回前线程就会运行完,导致误判 IsAborted
End Sub
Public Overrides Sub Abort()
If State <> LoadState.Loading Then Exit Sub
If State <> LoadState.Loading Then Return
SyncLock LockState
State = LoadState.Aborted
End SyncLock
TriggerThreadAbort()
End Sub
Private Sub TriggerThreadAbort()
If LastRunningThread Is Nothing Then Exit Sub
If ModeDebug Then Log("[Loader] 加载线程 " & Name & " (" & LastRunningThread.ManagedThreadId & ") 已中断")
If LastRunningThread Is Nothing Then Return
If ModeDebug Then Log($"[Loader] 加载线程 {Name} ({LastRunningThread.ManagedThreadId}) 已中断")
If LastRunningThread.IsAlive Then LastRunningThread.Interrupt()
LastRunningThread = Nothing
End Sub
@@ -406,7 +420,7 @@
'改变状态
SyncLock LockState
If State = LoadState.Loading Then
Exit Sub
Return
Else
State = LoadState.Loading
End If
@@ -418,7 +432,7 @@
Loader.State = LoadState.Waiting
Next
End If
Update()
RunInThread(AddressOf Update)
End Sub
Public Overrides Sub Abort()
'改变状态
@@ -426,19 +440,16 @@
If State = LoadState.Loading OrElse State = LoadState.Waiting Then
State = LoadState.Aborted
Else
Exit Sub
Return
End If
End SyncLock
RunInThread(Sub()
'中断加载器
For Each Loader In Loaders
Loader.Abort()
Next
'从列表删除
SyncLock LoaderTaskbarLock
If LoaderTaskbar.Contains(Me) Then LoaderTaskbar.Remove(Me)
End SyncLock
End Sub)
RunInThread(
Sub()
'中断加载器
For Each Loader In Loaders
Loader.Abort()
Next
End Sub)
End Sub
''' <summary>
@@ -460,7 +471,7 @@
Case Else
'完蛋,出错了
SyncLock LockState
If State >= LoadState.Finished Then Exit Sub
If State >= LoadState.Finished Then Return
[Error] = New Exception(Loader.Name & "失败", Loader.Error)
State = Loader.State
End SyncLock
@@ -468,52 +479,53 @@
Loader.Abort()
Next
FrmMain.BtnExtraDownload.ShowRefresh()
Exit Sub
Return
End Select
End Sub
''' <summary>
''' 触发一次更新,以启动新加载器或完成。
''' </summary>
Private Sub Update()
If State = LoadState.Finished OrElse State = LoadState.Failed OrElse State = LoadState.Aborted Then Exit Sub
If State = LoadState.Finished OrElse State = LoadState.Failed OrElse State = LoadState.Aborted Then Return
Dim IsFinished As Boolean = True
Dim Ignore As Boolean = False
Dim Blocked As Boolean = False
Dim Input As Object = Me.Input
For Each Loader In Loaders
Select Case Loader.State
Case LoadState.Finished
'检查是否需要重启
If Loader.GetType.Name.StartsWith("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
'UNDONE: 这里的 IgnoreReloadTimeout 导致加载器不会重启,也就是微软登录不会自动重新登录
If Loader.GetType.Name.StartsWithF("LoaderTask") Then '类型名后面带有泛型,必须用 StartsWith
If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
If ModeDebug Then Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name)
Log("[Loader] 由于输入条件变更,重启已完成的加载器 " & Loader.Name)
GoTo Restart
End If
'更新下一个加载器的输入
Input = CType(Loader, Object).Output
End If
'如果不让继续启动,且已有加载器正在加载中,就不继续启动
If Loader.Block AndAlso Not IsFinished Then Blocked = True
Case LoadState.Loading
'检查是否需要重启
If Loader.GetType.Name.StartsWith("LoaderTask") Then
If Loader.GetType.Name.StartsWithF("LoaderTask") Then
If CType(Loader, Object).ShouldStart(If(Input IsNot Nothing AndAlso Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IgnoreReloadTimeout:=True) Then
If ModeDebug Then Log("[Loader] 由于输入条件变更,重启进行中的加载器 " & Loader.Name, LogLevel.Developer)
Log("[Loader] 由于输入条件变更,重启进行中的加载器 " & Loader.Name, LogLevel.Developer)
GoTo Restart
End If
End If
'已经有正在加载中的了,不需要再启动了
IsFinished = False
Ignore = True
Blocked = True
Case Else
Restart:
'未启动,则启动加载器
IsFinished = False
If Ignore Then Continue For
If Blocked Then Continue For
If Input IsNot Nothing Then
'若输入类型与下一个加载器相同才继续
Dim LoaderType As String = Loader.GetType.Name
If LoaderType.StartsWith("LoaderTask") OrElse LoaderType.StartsWith("LoaderCombo") Then
If LoaderType.StartsWithF("LoaderTask") OrElse LoaderType.StartsWithF("LoaderCombo") Then
Loader.Start(If(Loader.GetType.GenericTypeArguments.First Is Input.GetType, Input, Nothing), IsForceRestarting)
ElseIf LoaderType.StartsWith("LoaderDownload") Then
ElseIf LoaderType.StartsWithF("LoaderDownload") Then
Loader.Start(If(TypeOf Input Is List(Of NetFile), Input, Nothing), IsForceRestarting)
Else
Throw New Exception("未知的加载器类型(" & LoaderType & ")")
@@ -521,8 +533,8 @@ Restart:
Else
Loader.Start(IsForceRestart:=IsForceRestarting)
End If
'如果不让继续启动,那就不启动呗
If Loader.Block Then Ignore = True
'阻止继续
If Loader.Block Then Blocked = True
End Select
Next
If IsFinished Then
@@ -539,7 +551,7 @@ Restart:
Public Shared Sub GetLoaderList(Loader As Object, ByRef List As List(Of LoaderBase), Optional RequireShow As Boolean = True)
For Each SubLoader In Loader.Loaders
If SubLoader.Show OrElse Not RequireShow Then List.Add(SubLoader)
If SubLoader.GetType.Name.StartsWith("LoaderCombo") Then GetLoaderList(SubLoader, List)
If SubLoader.GetType.Name.StartsWithF("LoaderCombo") Then GetLoaderList(SubLoader, List)
Next
End Sub
''' <summary>
@@ -560,48 +572,37 @@ Restart:
End Class
'任务栏进度条
Public LoaderTaskbarLock As New Object
Public LoaderTaskbar As New List(Of LoaderBase)
Public LoaderTaskbar As New SafeList(Of LoaderBase)
Public LoaderTaskbarProgress As Double = 0 '平滑后的进度
Private LoaderTaskbarProgressLast As Shell.TaskbarItemProgressState = Shell.TaskbarItemProgressState.None
Public Sub LoaderTaskbarAdd(Loader As LoaderBase)
Public Sub LoaderTaskbarAdd(Of T)(Loader As LoaderCombo(Of T))
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRemove(Loader)
SyncLock LoaderTaskbarLock
LoaderTaskbar.Add(Loader)
End SyncLock
LoaderTaskbar.Add(Loader)
Log($"[Taskbar] {Loader.Name} 已加入任务列表")
End Sub
Public Sub LoaderTaskbarProgressRefresh()
Try
Dim NewState As Shell.TaskbarItemProgressState
Dim NewProgress As Double = LoaderTaskbarProgressGet()
'检查任务是否完成,若完成则移除
SyncLock LoaderTaskbarLock
'外显任务是否已经全部完成
Dim IsAllDownloadTaskCompleted As Boolean = True
For Each Loader In LoaderTaskbar
If Loader.Show AndAlso Loader.State = LoadState.Loading Then IsAllDownloadTaskCompleted = False
Next
'若单个任务已中止或全部任务已完成,则刷新并移除
Dim RemovedTask As New List(Of LoaderBase)
For i = 0 To LoaderTaskbar.Count - 1
If (IsAllDownloadTaskCompleted OrElse LoaderTaskbar(i).State = LoadState.Aborted) AndAlso LoaderTaskbar(i).Show Then
If FrmSpeedLeft IsNot Nothing Then FrmSpeedLeft.TaskRefresh(LoaderTaskbar(i))
RemovedTask.Add(LoaderTaskbar(i))
End If
Next
For Each Task In RemovedTask
'若单个任务已中止,或全部任务已完成,则刷新并移除
For Each Task In LoaderTaskbar
If LoaderTaskbar.All(Function(l) l.State <> LoadState.Loading) OrElse
(Task.State = LoadState.Waiting OrElse Task.State = LoadState.Aborted) Then
FrmSpeedLeft?.TaskRefresh(Task)
LoaderTaskbar.Remove(Task)
Next
End SyncLock
Log($"[Taskbar] {Task.Name} 已移出任务列表")
End If
Next
'更新平滑后的进度
If NewProgress <= 0 OrElse NewProgress >= 1 OrElse LoaderTaskbarProgress > NewProgress Then
LoaderTaskbarProgress = NewProgress
Else
LoaderTaskbarProgress = LoaderTaskbarProgress * 0.9 + NewProgress * 0.1
End If
RunInUi(Sub() FrmMain.BtnExtraDownload.Progress = LoaderTaskbarProgress)
'更新任务栏信息
If LoaderTaskbar.Count = 0 OrElse LoaderTaskbarProgress = 1 Then
If Not LoaderTaskbar.Any() OrElse LoaderTaskbarProgress = 1 Then
NewState = Shell.TaskbarItemProgressState.None
ElseIf LoaderTaskbarProgress < 0.015 Then
NewState = Shell.TaskbarItemProgressState.Indeterminate
@@ -620,15 +621,8 @@ Restart:
End Sub
Public Function LoaderTaskbarProgressGet() As Double
Try
Dim Total As Double = 0, Count As Integer = 0
SyncLock LoaderTaskbarLock
For i = 0 To LoaderTaskbar.Count - 1
Total += LoaderTaskbar(i).Progress
Count += 1 '避免多线程影响导致计数出错
Next
End SyncLock
If Count = 0 Then Return 1
Return MathRange(Total / Count, 0, 1)
If Not LoaderTaskbar.Any Then Return 1
Return MathClamp(LoaderTaskbar.Select(Function(l) l.Progress).Average(), 0, 1)
Catch ex As Exception
Log(ex, "获取任务栏进度出错", LogLevel.Feedback)
Return 0.5
@@ -677,7 +671,7 @@ Restart:
Log(ex, "文件夹加载器启动检测出错")
End Try
'写入检查数据
DictionaryAdd(LoaderFolderDictionary, Loader, Value)
LoaderFolderDictionary(Loader) = Value
'开始检查
If Type = LoaderFolderRunType.UpdateOnly Then Return False
If WaitForExit Then
File diff suppressed because it is too large. Load diff
@@ -1,11 +1,28 @@
'提供不同的输入验证方法,名称以 Validate 开头
Public Module ModValidate
''' <summary>
''' 进行输入验证,并返回错误原因。
''' 如果没有错误则返回空字符串。
''' </summary>
Public Function Validate(Text As String, ValidateRules As IEnumerable(Of Validate)) As String
Dim Result As String = ""
For Each ValidateRule As Validate In ValidateRules
Result = ValidateRule.Validate(Text)
If Result Is Nothing Then Return ""
If Result <> "" Then Return Result
Next
Return Result
End Function
End Module
''' <summary>
''' 输入验证规则基类。要查看所有的输入验证规则,可在输入 Validate 后查看自动补全。
''' </summary>
Public MustInherit Class Validate
''' <summary>
''' 验证某字符串是否符合验证要求。若符合,返回空字符串;若不符合,返回错误原因。
''' 验证某字符串是否符合验证要求。若符合,返回空字符串;若不符合,返回错误原因;若需要中断检查并直接通过,返回 Nothing。
''' </summary>
Public MustOverride Function Validate(Str As String) As String
End Class
@@ -15,6 +32,8 @@ End Class
''' </summary>
Public Class ValidateNullable
Inherits Validate
Public Sub New()
End Sub
Public Overrides Function Validate(Str As String) As String
If IsNothing(Str) OrElse String.IsNullOrEmpty(Str) Then Return Nothing
Return ""
@@ -26,6 +45,8 @@ End Class
''' </summary>
Public Class ValidateNullOrEmpty
Inherits Validate
Public Sub New()
End Sub
Public Overrides Function Validate(Str As String) As String
If IsNothing(Str) OrElse String.IsNullOrEmpty(Str) Then Return "输入内容不能为空!"
Return ""
@@ -37,6 +58,8 @@ End Class
''' </summary>
Public Class ValidateNullOrWhiteSpace
Inherits Validate
Public Sub New()
End Sub
Public Overrides Function Validate(Str As String) As String
If IsNothing(Str) OrElse String.IsNullOrWhiteSpace(Str) Then Return "输入内容不能为空!"
Return ""
@@ -49,10 +72,10 @@ End Class
Public Class ValidateRegex
Inherits Validate
Public Property Regex As String
Public Property ErrorDescription As String = ""
Public Property ErrorDescription As String = "正则检查失败!"
Public Sub New()
End Sub '用于 XAML 初始化
Public Sub New(Regex As String, Optional ErrorDescription As String = "")
Public Sub New(Regex As String, Optional ErrorDescription As String = "正则检查失败!")
Me.Regex = Regex
Me.ErrorDescription = ErrorDescription
End Sub
@@ -70,7 +93,7 @@ Public Class ValidateHttp
Public Sub New()
End Sub '用于 XAML 初始化
Public Overrides Function Validate(Str As String) As String
If Str.EndsWith("/") Then Str = Str.Substring(0, Str.Length - 1)
If Str.EndsWithF("/") Then Str = Str.Substring(0, Str.Length - 1)
If Not RegexCheck(Str, "^(http[s]?)\://") Then Return "输入的网址无效!"
Return ""
End Function
@@ -113,9 +136,9 @@ Public Class ValidateLength
Me.Max = Max
End Sub
Public Overrides Function Validate(Str As String) As String
If Len(Str) <> Max AndAlso Max = Min Then Return "长度必须为 " & Max & " 个字符!"
If Len(Str) > Max Then Return "长度最长为 " & Max & " 个字符!"
If Len(Str) < Min Then Return "长度至少需 " & Min & " 个字符!"
If Len(Str) <> Max AndAlso Max = Min Then Return $"长度必须为 {Max} 个字符!"
If Len(Str) > Max Then Return $"长度最长为 {Max} 个字符!"
If Len(Str) < Min Then Return $"长度至少需 {Min} 个字符!"
Return ""
End Function
End Class
@@ -128,13 +151,13 @@ Public Class ValidateExcept
Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
Public Property ErrorMessage As String
Public Sub New()
ErrorMessage = "输入内容不能包含 %!"
ErrorMessage = "输入内容不能包含 %"
End Sub '用于 XAML 初始化
Public Sub New(Excepts As ObjectModel.Collection(Of String), Optional ErrorMessage As String = "输入内容不能包含 %!")
Public Sub New(Excepts As ObjectModel.Collection(Of String), Optional ErrorMessage As String = "输入内容不能包含 %")
Me.Excepts = Excepts
Me.ErrorMessage = ErrorMessage
End Sub
Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能包含 %!")
Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能包含 %")
Me.Excepts = New ObjectModel.Collection(Of String)
Me.ErrorMessage = ErrorMessage
For Each Data As String In Excepts
@@ -143,7 +166,7 @@ Public Class ValidateExcept
End Sub
Public Overrides Function Validate(Str As String) As String
For Each Ch As String In Excepts
If Str.IndexOf(Ch, StringComparison.OrdinalIgnoreCase) >= 0 Then
If Str.IndexOfF(Ch, True) >= 0 Then
If IsNothing(ErrorMessage) Then ErrorMessage = ""
Return ErrorMessage.Replace("%", Ch)
End If
@@ -161,12 +184,14 @@ Public Class ValidateExceptSame
Public Property Excepts As ObjectModel.Collection(Of String) = New ObjectModel.Collection(Of String)
Public Property ErrorMessage As String
Public Property IgnoreCase As Boolean = False
Public Sub New(Excepts As ObjectModel.Collection(Of String), Optional ErrorMessage As String = "输入内容不能为 %!", Optional IgnoreCase As Boolean = False)
Public Sub New()
End Sub
Public Sub New(Excepts As ObjectModel.Collection(Of String), Optional ErrorMessage As String = "输入内容不能为 %", Optional IgnoreCase As Boolean = False)
Me.Excepts = Excepts
Me.ErrorMessage = ErrorMessage
Me.IgnoreCase = IgnoreCase
End Sub
Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能为 %!", Optional IgnoreCase As Boolean = False)
Public Sub New(Excepts As IEnumerable, Optional ErrorMessage As String = "输入内容不能为 %", Optional IgnoreCase As Boolean = False)
Me.Excepts = New ObjectModel.Collection(Of String)
For Each Data As String In Excepts
Me.Excepts.Add(Data)
@@ -197,6 +222,8 @@ Public Class ValidateFolderName
Public Property UseMinecraftCharCheck As Boolean = True
Public Property IgnoreCase As Boolean = True
Private ReadOnly PathIgnore As IEnumerable(Of DirectoryInfo)
Public Sub New()
End Sub
Public Sub New(Path As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
Me.Path = Path
Me.IgnoreCase = IgnoreCase
@@ -208,21 +235,23 @@ Public Class ValidateFolderName
Try
'检查是否为空
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
If LengthCheck <> "" Then Return LengthCheck
'检查空格
If Str.StartsWith(" ") Then Return "文件夹名不能以空格开头!"
If Str.EndsWith(" ") Then Return "文件夹名不能以空格结尾!"
If Str.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
If Str.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
'检查长度
LengthCheck = New ValidateLength(1, 100).Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
If LengthCheck <> "" Then Return LengthCheck
'检查尾部小数点
If Str.EndsWith(".") Then Return "文件夹名不能以小数点结尾!"
If Str.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
'检查特殊字符
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件夹名不可包含 % 字符!").Validate(Str)
If Not CharactCheck = "" Then Return CharactCheck
If CharactCheck <> "" Then Return CharactCheck
'检查特殊字符串
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(Str)
If Not InvalidStrCheck = "" Then Return InvalidStrCheck
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!", True).Validate(Str)
If InvalidStrCheck <> "" Then Return InvalidStrCheck
'检查 NTFS 8.3 文件名(#4505)
If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!"
'检查文件夹重名
Dim Arr As New List(Of String)
If PathIgnore IsNot Nothing Then
@@ -240,6 +269,63 @@ Public Class ValidateFolderName
End Function
End Class
''' <summary>
''' 对文件名的粗略的特化检测。
''' </summary>
Public Class ValidateFileName
Inherits Validate
Public Property Name As String
Public Property UseMinecraftCharCheck As Boolean = True
Public Property IgnoreCase As Boolean = True
Public Property ParentFolder As String = Nothing
Public Property RequireParentFolderExists = True
Public Sub New()
End Sub
Public Sub New(Name As String, Optional UseMinecraftCharCheck As Boolean = True, Optional IgnoreCase As Boolean = True)
Me.Name = Name
Me.IgnoreCase = IgnoreCase
Me.UseMinecraftCharCheck = UseMinecraftCharCheck
End Sub
Public Overrides Function Validate(Str As String) As String
Try
'检查是否为空
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
'检查空格
If Str.StartsWithF(" ") Then Return "文件名不能以空格开头!"
If Str.EndsWithF(" ") Then Return "文件名不能以空格结尾!"
'检查长度
LengthCheck = New ValidateLength(1, 253).Validate(Str & If(ParentFolder, ""))
If LengthCheck <> "" Then Return LengthCheck
'检查尾部小数点
If Str.EndsWithF(".") Then Return "文件名不能以小数点结尾!"
'检查特殊字符
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "文件名不可包含 % 字符!").Validate(Str)
If CharactCheck <> "" Then Return CharactCheck
'检查特殊字符串
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件名不可为 %!", True).Validate(Str)
If InvalidStrCheck <> "" Then Return InvalidStrCheck
'检查 NTFS 8.3 文件名(#4505)
If RegexCheck(Str, ".{2,}~\d") Then Return "文件名不能包含这一特殊格式!"
'检查文件重名
If ParentFolder IsNot Nothing Then
Dim DirInfo As New DirectoryInfo(ParentFolder)
If DirInfo.Exists Then
Dim SameNameCheck = New ValidateExceptSame(DirInfo.EnumerateFiles("*").Select(Function(f) f.Name),
"不可与现有文件重名!", IgnoreCase).Validate(Str)
If Not SameNameCheck = "" Then Return SameNameCheck
Else
If RequireParentFolderExists Then Return $"父文件夹不存在:{ParentFolder}"
End If
End If
Return ""
Catch ex As Exception
Log(ex, "检查文件名出错")
Return "错误:" & ex.Message
End Try
End Function
End Class
''' <summary>
''' 要求输入一个可用的文件夹路径。
''' </summary>
@@ -254,23 +340,23 @@ Public Class ValidateFolderPath
Public Overrides Function Validate(Str As String) As String
'去除尾部斜线,统一为 \
Str = Str.Replace("/", "\")
If Not Str.TrimEnd("\").EndsWith(":") Then Str = Str.TrimEnd("\")
If Not Str.TrimEnd("\").EndsWithF(":") Then Str = Str.TrimEnd("\")
'检查是否为空
Dim LengthCheck As String = New ValidateNullOrWhiteSpace().Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
If LengthCheck <> "" Then Return LengthCheck
'检查长度
LengthCheck = New ValidateLength(1, 254).Validate(Str)
If Not LengthCheck = "" Then Return LengthCheck
If LengthCheck <> "" Then Return LengthCheck
'检查开头
If Str.StartsWith("\\Mac\") Then GoTo Fin
If Str.StartsWithF("\\Mac\") Then GoTo Fin
For Each Drive As DriveInfo In My.Computer.FileSystem.Drives
If Str.ToUpper = Drive.Name Then Return ""
If Str.ToUpper.StartsWith(Drive.Name) Then GoTo Fin
If Str.StartsWithF(Drive.Name, True) Then GoTo Fin
Next
Return "文件夹路径头存在错误!"
Fin:
'对首层以外的路径检查
For i = If(Str.StartsWith("\\Mac\"), 2, 1) To Str.Split("\").Count - 1
For i = If(Str.StartsWithF("\\Mac\"), 2, 1) To Str.Split("\").Count - 1
Dim SubStr As String = Str.Split("\")(i)
'检查是否为空
Dim SubLengthCheck As String = New ValidateNullOrWhiteSpace().Validate(SubStr)
@@ -279,36 +365,15 @@ Fin:
Dim CharactCheck As String = New ValidateExcept(IO.Path.GetInvalidFileNameChars() & If(UseMinecraftCharCheck, "!;", ""), "路径中存在无效字符!").Validate(SubStr)
If Not CharactCheck = "" Then Return CharactCheck
'检查头部空格
If SubStr.StartsWith(" ") Then Return "文件夹名不能以空格开头!"
If SubStr.EndsWith(" ") Then Return "文件夹名不能以空格结尾!"
If SubStr.StartsWithF(" ") Then Return "文件夹名不能以空格开头!"
If SubStr.EndsWithF(" ") Then Return "文件夹名不能以空格结尾!"
'检查尾部小数点
If SubStr.EndsWith(".") Then Return "文件夹名不能以小数点结尾!"
If SubStr.EndsWithF(".") Then Return "文件夹名不能以小数点结尾!"
'检查特殊字符串
Dim InvalidStrCheck As String = New ValidateExceptSame({"CON", "PRN", "AUX", "CLOCK$", "NUL", "COM0", "COM1", "COM2", "COM3", "COM4", "COM5", "COM6", "COM7", "COM8", "COM9", "LPT0", "LPT1", "LPT2", "LPT3", "LPT4", "LPT5", "LPT6", "LPT7", "LPT8", "LPT9"}, "文件夹名不可为 %!").Validate(SubStr)
If Not InvalidStrCheck = "" Then Return InvalidStrCheck
Next
Return ""
End Function
End Class
''' <summary>
''' 敏感词过滤。
''' </summary>
Public Class ValidateFilter
Inherits Validate
Private Shared Excepts As String() = SecretDecrypt(SecretSensitiveWordsRaw).Split("|")
Public Sub New()
End Sub '用于 XAML 初始化
Public Overrides Function Validate(Str As String) As String
'提取无间隔符的字符串
Dim RealStr As String = ""
For Each St In If(Str, "").ToLower
If String.IsNullOrWhiteSpace(St.ToString) OrElse ("!@#$%^&*()_+-={}[]|\;':"",./<>? ~ ·!¥…()—,。、《》?‘;:【】{}" & vbLQ & vbRQ).ToCharArray.Contains(St) Then Continue For
RealStr += St
Next
'检查
For Each Except In Excepts
If RealStr.Contains(Except) Then Return "存在敏感内容!"
'检查 NTFS 8.3 文件名(#4505)
If RegexCheck(Str, ".{2,}~\d") Then Return "文件夹名不能包含这一特殊格式!"
Next
Return ""
End Function
+51 -42
View File
@@ -1,11 +1,13 @@
'一个万能的自动图片类型转换工具类
Imports System.Drawing.Imaging
Public Class MyBitmap
''' <summary>
''' 位图缓存。
''' </summary>
Public Shared BitmapCache As New Dictionary(Of String, MyBitmap)
Public Shared BitmapCache As New Concurrent.ConcurrentDictionary(Of String, MyBitmap)
''' <summary>
''' 存储的图片
@@ -15,35 +17,43 @@ Public Class MyBitmap
'自动类型转换
'支持的类:Image,ImageSource,Bitmap,ImageBrush,BitmapSource
Public Shared Widening Operator CType(Image As System.Drawing.Image) As MyBitmap
If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Image
If Image Is Nothing Then Return Nothing
Return Image.Pic
End Operator
Public Shared Widening Operator CType(Image As ImageSource) As MyBitmap
If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As ImageSource
If Image Is Nothing Then Return Nothing
Dim Bitmap = Image.Pic
Dim rect = New System.Drawing.Rectangle(0, 0, Bitmap.Width, Bitmap.Height)
Dim bitmapData = Bitmap.LockBits(rect, System.Drawing.Imaging.ImageLockMode.ReadWrite, System.Drawing.Imaging.PixelFormat.Format32bppArgb)
Dim bitmapData = Bitmap.LockBits(rect, ImageLockMode.ReadWrite, PixelFormat.Format32bppArgb)
Try
Dim size = rect.Width * rect.Height * 4
Return BitmapSource.Create(Bitmap.Width, Bitmap.Height, DPI, DPI, PixelFormats.Bgra32, Nothing, bitmapData.Scan0, size, bitmapData.Stride)
Return BitmapSource.Create(Bitmap.Width, Bitmap.Height, Bitmap.HorizontalResolution, Bitmap.VerticalResolution, PixelFormats.Bgra32, Nothing, bitmapData.Scan0, size, bitmapData.Stride)
Finally
Bitmap.UnlockBits(bitmapData)
End Try
End Operator
Public Shared Widening Operator CType(Image As System.Drawing.Bitmap) As MyBitmap
If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As System.Drawing.Bitmap
If Image Is Nothing Then Return Nothing
Return Image.Pic
End Operator
Public Shared Widening Operator CType(Image As ImageBrush) As MyBitmap
If Image Is Nothing Then Return Nothing
Return New MyBitmap(Image)
End Operator
Public Shared Widening Operator CType(Image As MyBitmap) As ImageBrush
If Image Is Nothing Then Return Nothing
Return New ImageBrush(New MyBitmap(Image.Pic))
End Operator
@@ -52,29 +62,39 @@ Public Class MyBitmap
End Sub
Public Sub New(FilePathOrResourceName As String)
Try
If FilePathOrResourceName.StartsWith(PathImage) Then
FilePathOrResourceName = FilePathOrResourceName.Replace("pack://application:,,,/images/", PathImage)
If FilePathOrResourceName.StartsWithF(PathImage) Then
'使用缓存
If BitmapCache.ContainsKey(FilePathOrResourceName) Then
Pic = BitmapCache(FilePathOrResourceName).Pic
Else
Pic = New MyBitmap(CType((New ImageSourceConverter).ConvertFromString(FilePathOrResourceName), ImageSource))
BitmapCache.Add(FilePathOrResourceName, Pic)
BitmapCache.TryAdd(FilePathOrResourceName, Pic)
End If
Else
'使用这种自己接管 FileStream 的方法加载才能解除文件占用
Using InputStream As New FileStream(FilePathOrResourceName, FileMode.Open)
Pic = New System.Drawing.Bitmap(InputStream)
InputStream.Dispose()
'判断是否为 WebP 文件头
Dim Header(1) As Byte
InputStream.Read(Header, 0, 2)
InputStream.Seek(0, SeekOrigin.Begin)
If Header(0) = 82 AndAlso Header(1) = 73 Then
'读取 WebP
Dim FileBytes(InputStream.Length - 1) As Byte
InputStream.Read(FileBytes, 0, FileBytes.Length)
Pic = WebPDecoder.DecodeFromBytes(FileBytes) '将代码隔离在另外一个类中,这样只要不走进这个分支就不会加载 Imazen.WebP.dll
Else
Pic = New System.Drawing.Bitmap(InputStream)
End If
End Using
End If
Catch ex As Exception
Pic = My.Application.TryFindResource(FilePathOrResourceName)
If Pic Is Nothing Then
Pic = New System.Drawing.Bitmap(1, 1)
Log(ex, "加载位图失败(" & FilePathOrResourceName & ")")
Throw
Throw New Exception($"加载 MyBitmap 失败({FilePathOrResourceName})", ex)
Else
Log(ex, "指定类型有误的位图加载(" & FilePathOrResourceName & ")", LogLevel.Developer)
Log(ex, $"指定类型有误的 MyBitmap 加载({FilePathOrResourceName})", LogLevel.Developer)
Exit Try
End If
End Try
@@ -101,46 +121,35 @@ Public Class MyBitmap
Pic = New System.Drawing.Bitmap(MS)
End Using
End Sub
''' <summary>
''' 获取旋转的图片,这个方法不会导致原对象改变且会返回一个新的对象。图片长宽必须相等。
''' </summary>
''' <param name="angle">旋转角度(单位为角度)。</param>
Public Function Rotation(angle As Double) As System.Drawing.Bitmap
With Me
Dim img As System.Drawing.Image = Me.Pic
Dim bitSize As Single = img.Width
Dim bmp As New System.Drawing.Bitmap(CInt(bitSize), CInt(bitSize))
Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
g.TranslateTransform(bitSize / 2, bitSize / 2)
g.RotateTransform(angle)
g.TranslateTransform(-bitSize / 2, -bitSize / 2)
g.DrawImage(img, New System.Drawing.Rectangle(0, 0, img.Width, img.Width))
End Using
Return bmp
End With
End Function
Private Class WebPDecoder '将代码隔离在另外一个类中,这样只要不调用这个方法就不会加载 Imazen.WebP.dll
Public Shared Function DecodeFromBytes(Bytes As Byte()) As System.Drawing.Bitmap
If Is32BitSystem Then Throw New Exception("不支持在 32 位系统下加载 WebP 图片。")
Dim Decoder As New Imazen.WebP.SimpleDecoder()
Return Decoder.DecodeFromBytes(Bytes, Bytes.Length)
End Function
End Class
''' <summary>
''' 获取裁切的图片,这个方法不会导致原对象改变且会返回一个新的对象。
''' </summary>
Public Function Clip(rect As System.Drawing.Rectangle) As System.Drawing.Bitmap
With Me
Dim img As System.Drawing.Image = Pic
Dim bmp As New System.Drawing.Bitmap(rect.Width, rect.Height)
Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
g.DrawImageUnscaled(img, rect)
End Using
Return bmp
End With
Public Function Clip(X As Integer, Y As Integer, Width As Integer, Height As Integer) As MyBitmap
Dim bmp As New System.Drawing.Bitmap(Width, Height, Pic.PixelFormat)
bmp.SetResolution(Pic.HorizontalResolution, Pic.VerticalResolution)
Using g As System.Drawing.Graphics = System.Drawing.Graphics.FromImage(bmp)
g.InterpolationMode = System.Drawing.Drawing2D.InterpolationMode.NearestNeighbor
g.TranslateTransform(-X, -Y)
g.DrawImage(Pic, New System.Drawing.Rectangle(0, 0, Pic.Width, Pic.Height))
End Using
Return bmp
End Function
''' <summary>
''' 获取左右翻转的图片,这个方法不会导致原对象改变。
''' 获取旋转或翻转后的图片,这个方法不会导致原对象改变且会返回一个新的对象。
''' </summary>
Public Function LeftRightFilp() As System.Drawing.Bitmap
Public Function RotateFlip(Type As System.Drawing.RotateFlipType) As MyBitmap
Dim bmp As New System.Drawing.Bitmap(Pic)
bmp.RotateFlip(System.Drawing.RotateFlipType.RotateNoneFlipX)
bmp.SetResolution(Pic.HorizontalResolution, Pic.VerticalResolution)
bmp.RotateFlip(Type)
Return bmp
End Function
@@ -150,7 +159,7 @@ Public Class MyBitmap
Public Sub Save(FilePath As String)
Dim encoder As BitmapEncoder = New PngBitmapEncoder()
encoder.Frames.Add(BitmapFrame.Create(Me))
Using fileStream = New System.IO.FileStream(FilePath, FileMode.Create)
Using fileStream As New FileStream(FilePath, FileMode.Create)
encoder.Save(fileStream)
End Using
End Sub
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -0,0 +1,786 @@
Public Module ModJava
Public JavaListCacheVersion As Integer = 7
''' <summary>
''' 目前所有可用的 Java。
''' </summary>
Public JavaList As New List(Of JavaEntry)
Public Class JavaEntry
'路径
''' <summary>
''' Java.exe 文件的完整路径。
''' </summary>
Public ReadOnly Property PathJava As String
Get
Return PathFolder & "java.exe"
End Get
End Property
''' <summary>
''' Javaw.exe 文件的完整路径。
''' </summary>
Public ReadOnly Property PathJavaw As String
Get
Return PathFolder & "javaw.exe"
End Get
End Property
''' <summary>
''' Javaw.exe 文件所在文件夹的路径,以 \ 结尾。
''' </summary>
Public PathFolder As String
''' <summary>
''' 是否为用户手动导入的 Java。
''' </summary>
Public IsUserImport As Boolean
'版本信息
''' <summary>
''' Java 的详细版本。若不足 4 位会在前方补 1,例如 1.16.0.1。
''' 其大版本号为 Minor。
''' </summary>
Public Version As Version
''' <summary>
''' Java 的大版本号。
''' </summary>
Public ReadOnly Property VersionCode As Integer
Get
Return Version.Minor
End Get
End Property
''' <summary>
''' 是否为 Java Runtime Environment。
''' </summary>
Public IsJre As Boolean
''' <summary>
''' 是否为 64 位 Java。
''' </summary>
Public Is64Bit As Boolean
''' <summary>
''' 是否已设置环境变量。
''' </summary>
Public ReadOnly Property HasEnvironment As Boolean
Get
If PathFolder Is Nothing OrElse PathEnv Is Nothing Then Return False
Return PathEnv.Replace("\", "").Replace("/", "").ContainsF(PathFolder.Replace("\", ""), True)
End Get
End Property
'序列化
Public Function ToJson() As JObject
Return New JObject({New JProperty("Path", PathFolder), New JProperty("VersionString", Version.ToString), New JProperty("IsJre", IsJre), New JProperty("Is64Bit", Is64Bit), New JProperty("IsUserImport", IsUserImport)})
End Function
Public Shared Function FromJson(Data As JObject) As JavaEntry
Return New JavaEntry(Data("Path"), Data("IsUserImport")) With {.Version = New Version(Data("VersionString")), .IsJre = Data("IsJre"), .Is64Bit = Data("Is64Bit")}
End Function
''' <summary>
''' 转化为用户友好的字符串输出。
''' </summary>
Public Overrides Function ToString() As String
Dim VersionString = Version.ToString
If VersionString.StartsWithF("1.") Then VersionString = Mid(VersionString, 3)
Return If(IsJre, "JRE ", "JDK ") & VersionCode & " (" & VersionString & ")" & If(Is64Bit, "", ",32 位") & If(IsUserImport, ",手动导入", "") & ":" & PathFolder
End Function
'构造
''' <summary>
''' 输入 javaw.exe 文件所在文件夹的路径,不限制结尾。
''' </summary>
Public Sub New(Folder As String, IsUserImport As Boolean)
If Not Folder.EndsWithF("\") Then Folder += "\"
PathFolder = Folder.Replace("/", "\")
Me.IsUserImport = IsUserImport
End Sub
'方法
Private IsChecked As Boolean = False
''' <summary>
''' 检查并获取 Java 详细信息。在 Java 存在异常时抛出错误。
''' </summary>
Public Sub Check()
If IsChecked Then Return
Dim Output As String = Nothing
Try
'确定文件存在
If Not File.Exists(PathJavaw) Then
Throw New FileNotFoundException("未找到 javaw.exe 文件", PathJavaw)
End If
If Not File.Exists(PathFolder & "java.exe") Then
Throw New FileNotFoundException("未找到 java.exe 文件", PathFolder & "java.exe")
End If
If File.Exists(PathFolder & "pdf-bookmark") Then
Throw New Exception("不兼容 PDF Bookmark 的 Java") '#5326
End If
IsJre = Not File.Exists(PathFolder & "javac.exe")
'运行 -version
Output = ShellAndGetOutput(PathFolder & "java.exe", "-version", 15000).ToLower
If Output = "" Then Throw New ApplicationException("尝试运行该 Java 失败")
If ModeDebug Then Log("[Java] Java 检查输出:" & PathFolder & "java.exe" & vbCrLf & Output)
If Output.Contains("/lib/ext exists") Then Throw New ApplicationException("无法运行该 Java,请在删除 Java 文件夹中的 /lib/ext 文件夹后再试")
If Output.Contains("a fatal error") Then Throw New ApplicationException("无法运行该 Java,该 Java 或系统存在问题")
'获取详细信息
Dim VersionString = If(RegexSeek(Output, "(?<=version "")[^""]+"), If(RegexSeek(Output, "(?<=openjdk )[0-9]+"), "")).Replace("_", ".").Split("-").First
If VersionString.Split(".").Count > 4 Then VersionString = VersionString.Replace(".0.", ".") '#3493,VersionString = "21.0.2.0.2"
Do While VersionString.Split(".").Count < 4
If VersionString.StartsWithF("1.") Then
VersionString = VersionString & ".0"
Else
VersionString = "1." & VersionString
End If
Loop
If VersionString = "" Then Throw New ApplicationException($"未找到该 Java 的版本号{If(Output.Length < 500, $"{vbCrLf}输出为:{vbCrLf}{Output}", "")}")
Version = New Version(VersionString)
If Version.Minor = 0 Then
Log("[Java] 疑似 X.0.X.X 格式版本号:" & Version.ToString)
Version = New Version(1, Version.Major, Version.Build, Version.Revision)
End If
Is64Bit = Output.Contains("64-bit")
If Version.Minor <= 4 OrElse Version.Minor >= 100 Then Throw New ApplicationException("分析详细信息失败,获取的版本为 " & Version.ToString)
'基于 #3649,在 64 位系统上禁用 32 位 Java
If Not Is64Bit AndAlso Not Is32BitSystem Then Throw New Exception("该 Java 为 32 位版本,请安装 64 位的 Java")
'基于 #2249 发现 JRE 17 似乎也导致了 Forge 安装失败,干脆禁用更多版本的 JRE
If IsJre AndAlso VersionCode >= 16 Then Throw New Exception("由于高版本 JRE 对游戏的兼容性很差,因此不再允许使用。你可以使用对应版本的 JDK,而非 JRE!")
Catch ex As ApplicationException
Throw ex
Catch ex As ThreadInterruptedException
Throw ex
Catch ex As Exception
Log("[Java] 检查失败的 Java 输出:" & PathFolder & "java.exe" & vbCrLf & If(Output, "无程序输出"))
Throw New Exception("检查 Java 失败(" & If(PathJavaw, "Nothing") & ")", ex)
End Try
IsChecked = True
End Sub
End Class
''' <summary>
''' Path 环境变量。
''' </summary>
Private ReadOnly Property PathEnv As String
Get
If _PathEnv Is Nothing Then _PathEnv = If(Environment.GetEnvironmentVariable("Path"), "")
Return _PathEnv
End Get
End Property
Private _PathEnv As String = Nothing
''' <summary>
''' JAVA_HOME 环境变量。
''' </summary>
Private ReadOnly Property PathJavaHome As String
Get
If _PathJavaHome Is Nothing Then _PathJavaHome = If(Environment.GetEnvironmentVariable("JAVA_HOME"), "")
Return _PathJavaHome
End Get
End Property
Private _PathJavaHome As String = Nothing
''' <summary>
''' 初始化 Java 列表,但除非没有 Java,否则不进行检查。
''' </summary>
Public Sub JavaListInit()
JavaList = New List(Of JavaEntry)
Try
If Setup.Get("CacheJavaListVersion") < JavaListCacheVersion Then
'不使用缓存
Log("[Java] 要求 Java 列表缓存更新")
Setup.Set("CacheJavaListVersion", JavaListCacheVersion)
Else
'使用缓存
For Each JsonEntry In GetJson(Setup.Get("LaunchArgumentJavaAll"))
JavaList.Add(JavaEntry.FromJson(JsonEntry))
Next
End If
If Not JavaList.Any() Then
Log("[Java] 初始化未找到可用的 Java,将自动触发搜索", LogLevel.Developer)
JavaSearchLoader.Start(0)
Else
Log("[Java] 缓存中有 " & JavaList.Count & " 个可用的 Java:")
JavaList.ForEach(Sub(j) Log($"[Java] - {j}"))
End If
Catch ex As Exception
Log(ex, "初始化 Java 列表失败", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaAll", "[]")
End Try
End Sub
''' <summary>
''' 防止多个需要 Java 的部分同时要求下载 Java(#3797)。
''' </summary>
Public JavaLock As New Object
''' <summary>
''' 根据要求返回最适合的 Java,若找不到则返回 Nothing。
''' 最小与最大版本在与输入相同时也会通过。
''' 必须在工作线程调用,且必须包括 SyncLock JavaLock。
''' </summary>
Public Function JavaSelect(CancelException As String, Optional MinVersion As Version = Nothing, Optional MaxVersion As Version = Nothing,
Optional RelatedVersion As McVersion = Nothing) As JavaEntry
Try
Dim AllowedJavaList As New List(Of JavaEntry)
'添加特定的 Java
Dim JavaPreList As New Dictionary(Of String, Boolean)
If PathMcFolder.Split("\").Count > 3 AndAlso Not PathMcFolder.Contains("AppData\Roaming") Then
JavaSearchFolder(GetPathFromFullPath(PathMcFolder), JavaPreList, False, True) 'Minecraft 文件夹的父文件夹(如果不是根目录或 %APPDATA% 的话)
End If
JavaSearchFolder(PathMcFolder, JavaPreList, False, True) 'Minecraft 文件夹
JavaPreList = JavaPreList.Where(Function(j) Not j.Key.Contains(".minecraft\runtime")).
ToDictionary(Function(j) j.Key, Function(j) j.Value) '排除官启自带 Java(#4286)
If RelatedVersion IsNot Nothing Then JavaSearchFolder(RelatedVersion.Path, JavaPreList, False, True) '所选版本文件夹
Dim TargetJavaList As New List(Of JavaEntry)
For Each Entry In JavaPreList
TargetJavaList.Add(New JavaEntry(Entry.Key, Entry.Value))
Next
'检查特定的 Java
If TargetJavaList.Any Then
TargetJavaList = JavaCheckList(TargetJavaList)
Log("[Java] 检查后找到 " & TargetJavaList.Count & " 个特定路径下的 Java:")
For Each Java In TargetJavaList
Log($"[Java] - {Java}")
Next
End If
#Region "添加用户指定的 Java,储存到 UserJava 中"
Dim UserJava As JavaEntry = Nothing
'获取版本独立设置中指定的 Java
Dim VersionSelect As String = ""
If RelatedVersion IsNot Nothing Then
VersionSelect = Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)
If VersionSelect.StartsWithF("{") Then
Try
UserJava = JavaEntry.FromJson(GetJson(VersionSelect))
UserJava.Check()
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
UserJava = Nothing
Setup.Reset("VersionArgumentJavaSelect", Version:=RelatedVersion)
Log(ex, "版本独立设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
End Try
End If
End If
'获取全局设置中指定的 Java
If UserJava Is Nothing AndAlso VersionSelect <> "" AndAlso Setup.Get("LaunchArgumentJavaSelect") <> "" Then
Try
UserJava = JavaEntry.FromJson(GetJson(Setup.Get("LaunchArgumentJavaSelect")))
UserJava.Check()
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
UserJava = Nothing
Setup.Reset("LaunchArgumentJavaSelect")
Log(ex, "全局设置中指定的 Java 已无法使用,此设置已重置", LogLevel.Hint)
End Try
End If
'添加到特定 Java 列表
If UserJava IsNot Nothing Then
Log($"[Java] 用户指定的 Java:{UserJava}")
TargetJavaList.Add(UserJava)
End If
#End Region
RetryGet:
'等待进行中的搜索结束
If JavaSearchLoader.State <> LoadState.Finished AndAlso JavaSearchLoader.State <> LoadState.Waiting Then JavaSearchLoader.WaitForExit()
Select Case JavaSearchLoader.State
Case LoadState.Failed
Throw JavaSearchLoader.Error
Case LoadState.Aborted
Throw New ThreadInterruptedException("Java 搜索加载器已中断")
End Select
'生成完整的 Java 列表
Dim AllJavaList As New List(Of JavaEntry)
AllJavaList.AddRange(TargetJavaList)
AllJavaList.AddRange(JavaList)
'根据选定条件进行过滤
For Each Java In AllJavaList
If MinVersion IsNot Nothing AndAlso Java.Version < MinVersion Then Continue For
If MaxVersion IsNot Nothing AndAlso Java.Version > MaxVersion Then Continue For
If Java.Is64Bit AndAlso Is32BitSystem Then Continue For
AllowedJavaList.Add(Java)
Next
'若未找到适合的 Java,尝试触发搜索
If Not AllowedJavaList.Any() AndAlso JavaSearchLoader.State = LoadState.Waiting Then
Log("[Java] 未找到满足条件的 Java,尝试进行搜索")
JavaSearchLoader.Start(IsForceRestart:=True)
GoTo RetryGet
End If
#Region "检查用户指定的 Java 是否可用"
'确保指定的 Java 可用
If UserJava Is Nothing Then GoTo ExitUserJavaCheck
If AllowedJavaList.Any(Function(j) j.PathFolder = UserJava.PathFolder) Then
Log("[Java] 使用用户指定的 Java:" & UserJava.PathFolder)
AllowedJavaList = New List(Of JavaEntry) From {UserJava}
GoTo UserPass
End If
'指定的 Java 不可用,弹窗要求选择
Log("[Java] 发现用户指定的不兼容 Java:" & UserJava.ToString)
Log($"[Java] 目前实际可用的 Java 列表:")
For Each Java In AllowedJavaList
Log($"[Java] - {Java}")
Next
Dim Requirement As String = ""
Dim ShowRevision As Boolean = False
If (MinVersion Is Nothing OrElse MinVersion.Minor = 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 999) Then
ShowRevision = MaxVersion.MinorRevision < 999
Requirement = "最高兼容到 Java " & MaxVersion.Minor & If(ShowRevision, "." & MaxVersion.MajorRevision & "." & MaxVersion.MinorRevision, "")
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion Is Nothing OrElse MaxVersion.Minor >= 999) Then
ShowRevision = MinVersion.MinorRevision > 0 OrElse MinVersion.MajorRevision > 0
Requirement = "至少需要 Java " & MinVersion.Minor & If(ShowRevision, "." & MinVersion.MajorRevision & "." & MinVersion.MinorRevision, "")
ElseIf (MinVersion IsNot Nothing AndAlso MinVersion.Minor > 0) AndAlso (MaxVersion IsNot Nothing AndAlso MaxVersion.Minor < 999) Then
ShowRevision = MinVersion.MinorRevision > 0 OrElse MinVersion.MajorRevision > 0 OrElse MaxVersion.MinorRevision < 999
Dim Left As String = MinVersion.Minor & If(ShowRevision, "." & MinVersion.MajorRevision & "." & MinVersion.MinorRevision, "")
Dim Right As String = MaxVersion.Minor & If(ShowRevision, "." & MaxVersion.MajorRevision & "." & MaxVersion.MinorRevision, "")
Requirement = "需要 Java " & If(Left = Right, Left, Left & " ~ " & Right)
End If
Dim JavaCurrent As String = UserJava.VersionCode & If(ShowRevision, "." & UserJava.Version.MajorRevision & "." & UserJava.Version.MinorRevision, "")
If RelatedVersion IsNot Nothing AndAlso Setup.Get("VersionAdvanceJava", RelatedVersion) Then
'直接跳过弹窗
Log("[Java] 设置中指定了使用 Java " & JavaCurrent & ",但当前版本" & Requirement & ",这可能会导致游戏崩溃!", LogLevel.Debug)
AllowedJavaList = New List(Of JavaEntry) From {UserJava}
Else
Select Case MyMsgBox("你在设置中手动指定了使用 Java " & JavaCurrent & ",但当前" & Requirement & "。" & vbCrLf &
"如果强制使用该 Java,可能导致游戏崩溃。" & vbCrLf &
"你也可以将 游戏 Java 设置修改为 自动选择合适的 Java。" & vbCrLf &
vbCrLf &
" - 指定的 Java:" & UserJava.ToString,
"Java 兼容性警告", "让 PCL 自动选择", "强制使用该 Java", "取消")
Case 1 '让 PCL 自动选择
Case 2 '强制使用指定的 Java
Log("[Java] 已强制使用用户指定的不兼容 Java")
AllowedJavaList = New List(Of JavaEntry) From {UserJava}
Case 3 '取消启动
Throw New Exception(CancelException)
End Select
End If
ExitUserJavaCheck:
#End Region
'若依然未找到适合的 Java,直接返回
If Not AllowedJavaList.Any() Then Return Nothing
'优先使用特定目录下的 Java
For Each Java In AllowedJavaList
'如果在官启文件夹启动,会将官启自带 Java 错误视作 MC 文件夹指定 Java,导致了 #2054 的第二例
If Java.PathFolder.Contains(".minecraft\cache\java") Then Continue For
If Java.PathFolder.Contains("PCL\MyDownload\") Then Continue For '#5780
If TargetJavaList.Contains(Java) Then
'直接使用指定的 Java
AllowedJavaList = New List(Of JavaEntry) From {Java}
Log("[Java] 优先使用特定路径下的 Java:" & Java.ToString)
GoTo UserPass
End If
Next
UserPass:
'对适合的 Java 进行排序
AllowedJavaList = AllowedJavaList.Sort(AddressOf JavaSorter)
Log($"[Java] 排序后的 Java 优先顺序:")
For Each Java In AllowedJavaList
Log($"[Java] - {Java}")
Next
'检查选定的 Java,若测试失败则尝试进行搜索
Dim SelectedJava = AllowedJavaList.First
Try
SelectedJava.Check()
Catch ex As ThreadInterruptedException
Throw
Catch ex As Exception
If ex.InnerException IsNot Nothing AndAlso TypeOf (ex.InnerException) Is ThreadInterruptedException Then Throw ex.InnerException
Log(ex, "最终选定的 Java 已无法使用,尝试进行搜索")
AllowedJavaList = New List(Of JavaEntry)
JavaSearchLoader.Start(IsForceRestart:=True)
GoTo RetryGet
End Try
'返回
Log("[Java] 最终选定的 Java:" & AllowedJavaList.First.ToString)
Return SelectedJava
Catch ex As ThreadInterruptedException
Log(ex, "查找符合条件的 Java 时出现加载器中断")
Return Nothing
Catch ex As Exception
If ex.Message = "$$" Then Throw ex
Log(ex, "查找符合条件的 Java 失败", LogLevel.Feedback)
Return Nothing
End Try
End Function
''' <summary>
''' 是否强制指定了 64 位 Java。如果没有强制指定,返回是否安装了 64 位 Java。
''' </summary>
Public Function JavaIs64Bit(Optional RelatedVersion As McVersion = Nothing) As Boolean
Try
'检查强制指定
Dim UserSetup As String = Setup.Get("LaunchArgumentJavaSelect")
If RelatedVersion IsNot Nothing Then
Dim UserSetupVersion As String = Setup.Get("VersionArgumentJavaSelect", Version:=RelatedVersion)
If UserSetupVersion <> "使用全局设置" Then UserSetup = UserSetupVersion
End If
If UserSetup <> "" Then
Dim UserJava As JavaEntry = Nothing
Try
UserJava = JavaEntry.FromJson(GetJson(UserSetup))
Catch ex As Exception
Log(ex, "版本指定的 Java 信息已损坏,已重置版本设置中指定的 Java")
Setup.Set("VersionArgumentJavaSelect", "使用全局设置", Version:=RelatedVersion)
GoTo NoUserJava
End Try
For Each Java In JavaList
If Java.PathFolder = UserJava.PathFolder Then Return UserJava.Is64Bit
Next
End If
NoUserJava:
'检查列表
For Each Java In JavaList
If Java.Is64Bit Then Return True
Next
Return False
Catch ex As Exception
Log(ex, "检查 Java 类别时出错", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaSelect", "")
Return True
End Try
End Function
''' <summary>
''' 将 Java 按照适用性排序。
''' </summary>
Public Function JavaSorter(Left As JavaEntry, Right As JavaEntry) As Boolean
Dim PathInfo As New DirectoryInfo(ShortenPath(Path))
Dim PathMcInfo As New DirectoryInfo(ShortenPath(PathMcFolder))
'1. 尽量在当前文件夹或当前 Minecraft 文件夹
Dim ProgramPathParent As String, MinecraftPathParent As String = ""
ProgramPathParent = If(PathInfo.Parent, PathInfo).FullName
If PathMcFolder <> "" Then MinecraftPathParent = If(PathMcInfo.Parent, PathMcInfo).FullName
If Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Not Right.PathFolder.StartsWithF(ProgramPathParent) Then Return True
If Not Left.PathFolder.StartsWithF(ProgramPathParent) AndAlso Right.PathFolder.StartsWithF(ProgramPathParent) Then Return False
If PathMcFolder <> "" Then
If Left.PathFolder.StartsWithF(MinecraftPathParent) AndAlso Not Right.PathFolder.StartsWithF(MinecraftPathParent) Then Return True
If Not Left.PathFolder.StartsWithF(MinecraftPathParent) AndAlso Right.PathFolder.StartsWithF(MinecraftPathParent) Then Return False
End If
'2. 尽量使用 64 位
If Left.Is64Bit AndAlso Not Right.Is64Bit Then Return True
If Not Left.Is64Bit AndAlso Right.Is64Bit Then Return False
'3. 尽量不使用 JDK
If Left.IsJre AndAlso Not Right.IsJre Then Return True
If Not Left.IsJre AndAlso Right.IsJre Then Return False
'4. Java 大版本
If Left.VersionCode <> Right.VersionCode Then
' Java 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23...
Dim Weight = {0, 1, 2, 3, 4, 5, 6, 14, 30, 10, 12, 15, 13, 9, 8, 7, 11, 31, 29, 16, 17, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18}
Return Weight.ElementAtOrDefault(Left.VersionCode) >= Weight.ElementAtOrDefault(Right.VersionCode)
End If
'5. 最次级版本号更接近 51
Return Math.Abs(Left.Version.Revision - 51) <= Math.Abs(Right.Version.Revision - 51)
End Function
#Region "搜索"
''' <summary>
''' 模糊搜索并获取所有可用的 Java,并在结束后更新设置页面显示。输出将直接写入 JavaList。
''' </summary>
Public JavaSearchLoader As New LoaderTask(Of Integer, Integer)("查找 Java", AddressOf JavaSearchLoaderSub) With {.ProgressWeight = 2}
Private Sub JavaSearchLoaderSub(Loader As LoaderTask(Of Integer, Integer))
If FrmSetupLaunch IsNot Nothing Then
RunInUiWait(
Sub()
FrmSetupLaunch.ComboArgumentJava.Items.Clear()
FrmSetupLaunch.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
End Sub)
End If
If FrmVersionSetup IsNot Nothing Then
RunInUiWait(
Sub()
FrmVersionSetup.ComboArgumentJava.Items.Clear()
FrmVersionSetup.ComboArgumentJava.Items.Add(New ComboBoxItem With {.Content = "加载中……", .IsSelected = True})
End Sub)
End If
Try
'可能包含 Java 的文件夹列表,以 “\” 结尾,且仅包含 “\”
'Key:文件夹地址
'Value: 是否为玩家手动导入
Dim JavaPreList As New Dictionary(Of String, Boolean)
#Region "模糊查找可能可用的 Java"
'查找环境变量中的 Java
For Each PathInEnv As String In Split((PathEnv & ";" & PathJavaHome).Replace("\\", "\").Replace("/", "\"), ";")
PathInEnv = PathInEnv.Trim(" """.ToCharArray())
If PathInEnv = "" Then Continue For
If Not PathInEnv.EndsWithF("\") Then PathInEnv += "\"
'粗略检查有效性
If File.Exists(PathInEnv & "javaw.exe") Then JavaPreList(PathInEnv) = False
Next
'查找磁盘中的 Java
For Each Disk As DriveInfo In DriveInfo.GetDrives()
If Disk.DriveType = DriveType.Network Then Continue For '跳过网络驱动器(#3705)
JavaSearchFolder(Disk.Name, JavaPreList, False)
Next
'查找 .jdks 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.UserProfile) & "\.jdks\", JavaPreList, False)
'查找 APPDATA 文件夹中的 Java
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\", JavaPreList, False)
JavaSearchFolder(Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData) & "\", JavaPreList, False)
'查找启动器目录中的 Java
JavaSearchFolder(Path, JavaPreList, False, IsFullSearch:=True)
'查找所选 Minecraft 文件夹中的 Java
If Not String.IsNullOrWhiteSpace(PathMcFolder) AndAlso Path <> PathMcFolder Then
JavaSearchFolder(PathMcFolder, JavaPreList, False, IsFullSearch:=True)
End If
'若不全为符号链接,则清除符号链接的地址
Dim JavaWithoutReparse As New Dictionary(Of String, Boolean)
For Each Pair In JavaPreList
Dim Folder As String = Pair.Key.Replace("\\", "\").Replace("/", "\")
Dim Info As FileSystemInfo = New FileInfo(Folder & "javaw.exe")
Do
If Info.Attributes.HasFlag(FileAttributes.ReparsePoint) Then
Log("[Java] 位于 " & Folder & " 的 Java 包含符号链接")
Continue For
End If
Info = If(TypeOf Info Is FileInfo, CType(Info, FileInfo).Directory, CType(Info, DirectoryInfo).Parent)
Loop While Info IsNot Nothing
Log("[Java] 位于 " & Folder & " 的 Java 不含符号链接")
JavaWithoutReparse.Add(Pair.Key, Pair.Value)
Next
If JavaWithoutReparse.Any Then JavaPreList = JavaWithoutReparse
'若不全为特殊引用,则清除特殊引用的地址
Dim JavaWithoutInherit As New Dictionary(Of String, Boolean)
For Each Pair In JavaPreList
If Pair.Key.Contains("java8path_target_") OrElse Pair.Key.Contains("javapath_target_") OrElse Pair.Key.Contains("javatmp") OrElse Pair.Key.ContainsF("system32") Then
Log("[Java] 位于 " & Pair.Key & " 的 Java 位于特殊路径,不应优先使用")
Else
JavaWithoutInherit.Add(Pair.Key, Pair.Value)
End If
Next
If JavaWithoutInherit.Any Then JavaPreList = JavaWithoutInherit
#End Region
#Region "添加玩家手动导入的 Java"
Dim ImportedJava As String = Setup.Get("LaunchArgumentJavaAll")
Try
For Each JavaJsonObject In GetJson(ImportedJava)
Dim Entry = JavaEntry.FromJson(JavaJsonObject)
If Entry.IsUserImport Then JavaPreList(Entry.PathFolder) = True
Next
Catch ex As Exception
Log(ex, "Java 列表已损坏", LogLevel.Feedback)
Setup.Set("LaunchArgumentJavaAll", "[]")
End Try
#End Region
'确保可用并获取详细信息,转入正式列表
Dim NewJavaList As New List(Of JavaEntry)
For Each Entry In JavaPreList.Distinct(Function(a, b) a.Key.ToLower = b.Key.ToLower) '#794
NewJavaList.Add(New JavaEntry(Entry.Key, Entry.Value))
Next
NewJavaList = JavaCheckList(NewJavaList).Sort(AddressOf JavaSorter)
'修改设置项
Dim AllList As New JArray
For Each Java In NewJavaList
AllList.Add(Java.ToJson)
Next
Setup.Set("LaunchArgumentJavaAll", AllList.ToString(Newtonsoft.Json.Formatting.None))
JavaList = NewJavaList
Catch ex As Exception
Log(ex, "搜索 Java 时出错", LogLevel.Feedback)
JavaList = New List(Of JavaEntry)
End Try
Log("[Java] Java 搜索完成,发现 " & JavaList.Count & " 个 Java")
If FrmSetupLaunch IsNot Nothing Then RunInUi(Sub() FrmSetupLaunch.RefreshJavaComboBox())
If FrmVersionSetup IsNot Nothing Then RunInUi(Sub() FrmVersionSetup.RefreshJavaComboBox())
End Sub
''' <summary>
''' 多线程检查列表中的所有 Java 项。
''' </summary>
Private Function JavaCheckList(JavaEntries As List(Of JavaEntry)) As List(Of JavaEntry)
Log("[Java] 开始确认列表 Java 状态,共 " & JavaEntries.Count & " 项")
JavaCheckList = New List(Of JavaEntry)
Dim ListLock As New Object
'启动检查线程
Dim CheckThreads As New List(Of Thread)
For Each Entry In JavaEntries
Dim CheckThread As New Thread(
Sub()
Try
Entry.Check()
If ModeDebug Then Log("[Java] - " & Entry.ToString)
SyncLock ListLock
JavaCheckList.Add(Entry)
End SyncLock
Catch ex As ThreadInterruptedException
Catch ex As Exception
If Entry.IsUserImport Then
Log(ex, "位于 " & Entry.PathFolder & " 的 Java 存在异常,将被自动移除", LogLevel.Hint)
Else
Log(ex, "位于 " & Entry.PathFolder & " 的 Java 存在异常")
End If
End Try
End Sub)
CheckThreads.Add(CheckThread)
CheckThread.Start()
Next
'等待构造线程完成
Wait:
Thread.Sleep(10)
For Each CheckThread In CheckThreads
If CheckThread.IsAlive Then GoTo Wait
Next
End Function
''' <summary>
''' 模糊搜索指定文件夹下的 Java,并只进行粗略的检查。这不会搜索全部路径。
''' </summary>
''' <param name="OriginalPath">开始搜索的起始路径,不限制结尾。</param>
''' <param name="IsFullSearch">搜索当前文件夹下的全部文件夹(此参数不会传递到子文件夹)。</param>
Private Sub JavaSearchFolder(OriginalPath As String, ByRef Results As Dictionary(Of String, Boolean), Source As Boolean, Optional IsFullSearch As Boolean = False)
Try
Log("[Java] 开始" & If(IsFullSearch, "完全", "部分") & "遍历查找:" & OriginalPath)
JavaSearchFolder(New DirectoryInfo(ShortenPath(OriginalPath)), Results, Source, IsFullSearch)
Catch ex As UnauthorizedAccessException
Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath)
Catch ex As Exception
Log(ex, "遍历查找 Java 时出错(" & OriginalPath & ")")
End Try
End Sub
''' <summary>
''' 模糊搜索指定文件夹下的 Java,并只进行粗略的检查。这不会搜索全部路径。
''' </summary>
''' <param name="OriginalPath">开始搜索的起始路径,不限制结尾。</param>
''' <param name="IsFullSearch">搜索当前文件夹下的全部文件夹(此参数不会传递到子文件夹)。</param>
Private Sub JavaSearchFolder(OriginalPath As DirectoryInfo, ByRef Results As Dictionary(Of String, Boolean), Source As Boolean, Optional IsFullSearch As Boolean = False)
Try
'确认目录存在
If Not OriginalPath.Exists Then Return
Dim Path As String = OriginalPath.FullName.Replace("\\", "\")
If Not Path.EndsWithF("\") Then Path += "\"
'若该目录有 Java,则加入结果
If File.Exists(Path & "javaw.exe") Then Results(Path) = Source
'查找其下的所有文件夹
'不应使用网易的 Java:https://github.com/Meloong-Git/PCL/issues/1279#issuecomment-2761489121
Dim Keywords = {"java", "jdk", "env", "环境", "run", "软件", "jre", "mc", "dragon", "bin",
"soft", "cache", "temp", "corretto", "roaming", "users", "craft", "program", "世界", "net",
"游戏", "oracle", "game", "file", "data", "jvm", "服务", "server", "客户", "client", "整合",
"应用", "运行", "前置", "mojang", "官启", "新建文件夹", "eclipse", "microsoft", "hotspot",
"runtime", "x86", "x64", "forge", "原版", "optifine", "官方", "启动", "hmcl", "mod", "高清",
"download", "launch", "程序", "path", "version", "baka", "pcl", "zulu", "local", "packages",
"4297127d64ec6", "1.", "启动"}
For Each FolderInfo As DirectoryInfo In OriginalPath.EnumerateDirectories
If FolderInfo.Attributes.HasFlag(FileAttributes.ReparsePoint) Then Continue For '跳过符号链接
Dim SearchEntry = GetFolderNameFromPath(FolderInfo.Name).ToLower '用于搜索的字符串
If IsFullSearch OrElse
OriginalPath.Name.ToLower = "users" OrElse Val(SearchEntry) > 0 OrElse Keywords.Any(Function(w) SearchEntry.Contains(w)) OrElse SearchEntry = "bin" Then
JavaSearchFolder(FolderInfo, Results, Source)
End If
Next
Catch ex As UnauthorizedAccessException
Log("[Java] 遍历查找 Java 时遭遇无权限的文件夹:" & OriginalPath.FullName)
Catch ex As Exception
Log(ex, "遍历查找 Java 时出错(" & OriginalPath.FullName & ")")
End Try
End Sub
#End Region
#Region "下载"
''' <summary>
''' 提示 Java 缺失,并弹窗确认是否自动下载。返回玩家选择是否下载。
''' </summary>
Public Function JavaDownloadConfirm(VersionDescription As String, Optional ForcedManualDownload As Boolean = False) As Boolean
If ForcedManualDownload Then
MyMsgBox($"PCL 未找到 {VersionDescription}。" & vbCrLf &
$"请自行搜索并安装 {VersionDescription},安装后在 设置 → 启动选项 → 游戏 Java 中重新搜索或导入。",
"未找到 Java")
Return False
Else
Return MyMsgBox($"PCL 未找到 {VersionDescription},是否需要 PCL 自动下载?" & vbCrLf &
$"如果你已经安装了 {VersionDescription},可以在 设置 → 启动选项 → 游戏 Java 中手动导入。",
"自动下载 Java?", "自动下载", "取消") = 1
End If
End Function
''' <summary>
''' 获取下载 Java 8/14/17/21 的加载器。需要开启 IsForceRestart 以正常刷新 Java 列表。
''' </summary>
Public Function JavaFixLoaders(Version As Integer) As LoaderCombo(Of Integer)
Dim JavaDownloadLoader As New LoaderDownload("下载 Java 文件", New List(Of NetFile)) With {.ProgressWeight = 10}
Dim Loader = New LoaderCombo(Of Integer)($"下载 Java {Version}", {
New LoaderTask(Of Integer, List(Of NetFile))("获取 Java 下载信息", AddressOf JavaFileList) With {.ProgressWeight = 2},
JavaDownloadLoader,
JavaSearchLoader
})
AddHandler JavaDownloadLoader.OnStateChangedThread,
Sub(Raw As LoaderBase, NewState As LoadState, OldState As LoadState)
If (NewState = LoadState.Failed OrElse NewState = LoadState.Aborted) AndAlso LastJavaBaseDir IsNot Nothing Then
Log($"[Java] 由于下载未完成,清理未下载完成的 Java 文件:{LastJavaBaseDir}", LogLevel.Debug)
DeleteDirectory(LastJavaBaseDir)
ElseIf NewState = LoadState.Finished Then
LastJavaBaseDir = Nothing
End If
End Sub
JavaDownloadLoader.HasOnStateChangedThread = True
Return Loader
End Function
Private LastJavaBaseDir As String = Nothing '用于在下载中断或失败时删除未完成下载的 Java 文件夹,防止残留只下了一半但 -version 能跑的 Java
Private Sub JavaFileList(Loader As LoaderTask(Of Integer, List(Of NetFile)))
Log("[Java] 开始获取 Java 下载信息")
Dim IndexFileStr As String = NetRequestByLoader(DlVersionListOrder(
{"https://piston-meta.mojang.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"},
{"https://bmclapi2.bangbang93.com/v1/products/java-runtime/2ec0cc96c44e5a76b9c8b7c39df7210883d12871/all.json"}
), IsJson:=True)
'获取下载地址
Dim MainEntry As JObject = CType(GetJson(IndexFileStr), JObject)($"windows-x{If(Is32BitSystem, "86", "64")}")
Dim Entries = MainEntry.Children.Reverse. '选择最靠后的一项(最新)
SelectMany(Function(e As JProperty) CType(e.Value, JArray).Select(Function(v) New KeyValuePair(Of String, JObject)(e.Name, v)))
Dim TargetEntry = Entries.First(Function(t) t.Value("version")("name").ToString.StartsWithF(Loader.Input))
Dim Address As String = TargetEntry.Value("manifest")("url")
Log($"[Java] 准备下载 Java {TargetEntry.Value("version")("name")}({TargetEntry.Key}):{Address}")
'获取文件列表
Dim ListFileStr As String = NetRequestByLoader(DlSourceOrder({Address}, {Address.Replace("piston-meta.mojang.com", "bmclapi2.bangbang93.com")}), IsJson:=True)
LastJavaBaseDir = Environment.GetFolderPath(Environment.SpecialFolder.ApplicationData) & "\.minecraft\runtime\" & TargetEntry.Key & "\"
Dim Results As New List(Of NetFile)
For Each File As JProperty In CType(GetJson(ListFileStr), JObject)("files")
If CType(File.Value, JObject)("downloads")?("raw") Is Nothing Then Continue For
Dim Info As JObject = CType(File.Value, JObject)("downloads")("raw")
Dim Checker As New FileChecker(ActualSize:=Info("size"), Hash:=Info("sha1"))
If Checker.Hash = "12976a6c2b227cbac58969c1455444596c894656" OrElse Checker.Hash = "c80e4bab46e34d02826eab226a4441d0970f2aba" OrElse Checker.Hash = "84d2102ad171863db04e7ee22a259d1f6c5de4a5" Then
'跳过 3 个无意义大量重复文件(#3827)
Continue For
End If
If Checker.Check(LastJavaBaseDir & File.Name) Is Nothing Then Continue For '跳过已存在的文件
Dim Url As String = Info("url")
Results.Add(New NetFile(DlSourceOrder({Url}, {Url.Replace("piston-data.mojang.com", "bmclapi2.bangbang93.com")}), LastJavaBaseDir & File.Name, Checker))
Next
Loader.Output = Results
Log($"[Java] 需要下载 {Results.Count} 个文件,目标文件夹:{LastJavaBaseDir}")
End Sub
#End Region
End Module
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
File diff suppressed because it is too large. Load diff
@@ -6,21 +6,21 @@
Public HasRunningMinecraft As Boolean = False
Private Sub WatcherStateChanged()
Dim IsRunning As Boolean = False
Dim IsCrashed As Boolean = False
Dim TriggerLauncherShutdown As Boolean = True
For Each Watcher In McWatcherList
If Watcher.State = Watcher.MinecraftState.Loading OrElse Watcher.State = Watcher.MinecraftState.Running Then
IsRunning = True
Exit For
ElseIf Watcher.State = Watcher.MinecraftState.Crashed Then
IsCrashed = True
ElseIf Watcher.State = Watcher.MinecraftState.Crashed OrElse Watcher.State = Watcher.MinecraftState.Canceled Then
TriggerLauncherShutdown = False
End If
Next
If IsWatcherRunning = IsRunning Then Exit Sub
If IsWatcherRunning = IsRunning Then Return
IsWatcherRunning = IsRunning
If IsWatcherRunning Then
MinecraftStart()
Else
MinecraftStop(IsCrashed)
MinecraftStop(TriggerLauncherShutdown)
End If
End Sub
Private Sub MinecraftStart()
@@ -28,7 +28,7 @@
HasRunningMinecraft = True
FrmMain.BtnExtraShutdown.ShowRefresh()
End Sub
Private Sub MinecraftStop(HasMinecraftCrashed As Boolean)
Private Sub MinecraftStop(TriggerLauncherShutdown As Boolean)
McLaunchLog("[全局] 已无运行中的 Minecraft")
HasRunningMinecraft = False
FrmMain.BtnExtraShutdown.ShowRefresh()
@@ -42,10 +42,10 @@
Select Case Setup.Get("LaunchArgumentVisible")
Case 2
'直接关闭
If HasMinecraftCrashed Then
RunInUi(Sub() FrmMain.Hidden = False)
Else
If TriggerLauncherShutdown Then
RunInUi(Sub() FrmMain.EndProgram(False))
Else
RunInUi(Sub() FrmMain.Hidden = False)
End If
Case 3
'恢复
@@ -73,7 +73,7 @@
'更改列表
Dim NewWatcherList As New List(Of Watcher)
For Each Watch In McWatcherList
If Watch.State = MinecraftState.Crashed OrElse Watch.State = MinecraftState.Ended Then Continue For
If Watch.State = MinecraftState.Crashed OrElse Watch.State = MinecraftState.Ended OrElse Watch.State = MinecraftState.Canceled Then Continue For
NewWatcherList.Add(Watch)
Next
NewWatcherList.Add(Me)
@@ -81,35 +81,34 @@
WatcherStateChanged()
'初始化进程与日志读取
Me.GameProcess = Loader.Input
GameProcess = Loader.Input
GameProcess.BeginOutputReadLine()
GameProcess.BeginErrorReadLine()
AddHandler GameProcess.OutputDataReceived, AddressOf LogReceived
AddHandler GameProcess.ErrorDataReceived, AddressOf LogReceived
'初始化时钟
RunInNewThread(Sub()
Try
MinecraftBeforeLaunch = GetAllMinecraftWindowHandle(False).Keys.ToList
Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse Loader.State = LoadState.Aborted
TimerWindow()
TimerLog()
If State = MinecraftState.Loading Then ProgressUpdate()
'设置窗口标题
For i = 1 To 3
If IsWindowFinished AndAlso WindowTitle <> "" AndAlso State = MinecraftState.Running AndAlso Not GameProcess.HasExited Then
Dim RealTitle As String = WindowTitle.Replace("{time}", Date.Now.ToShortTimeString)
SetWindowText(WindowHandle, RealTitle.ToCharArray)
End If
Thread.Sleep(64)
Next
Loop
WatcherLog("Minecraft 日志监控已退出")
Catch ex As Exception
Log(ex, "Minecraft 日志监控主循环出错", LogLevel.Feedback)
State = MinecraftState.Ended
End Try
End Sub, "Minecraft Watcher PID " & PID)
RunInNewThread(
Sub()
Try
Do Until State = MinecraftState.Ended OrElse State = MinecraftState.Crashed OrElse State = MinecraftState.Canceled OrElse Loader.State = LoadState.Aborted
TimerWindow()
TimerLog()
'设置窗口标题
For i = 1 To 3
If IsWindowFinished AndAlso IsWindowAppeared AndAlso WindowTitle <> "" AndAlso State = MinecraftState.Running AndAlso Not GameProcess.HasExited Then
Dim RealTitle As String = WindowTitle.Replace("{date}", Date.Now.ToString("yyyy/M/d")).Replace("{time}", Date.Now.ToString("HH:mm:ss"))
SetWindowText(WindowHandle, RealTitle.ToCharArray)
End If
Thread.Sleep(64)
Next
Loop
WatcherLog("Minecraft 日志监控已退出")
Catch ex As Exception
Log(ex, "Minecraft 日志监控主循环出错", LogLevel.Feedback)
State = MinecraftState.Ended
End Try
End Sub, "Minecraft Watcher PID " & PID)
End Sub
'状态
@@ -118,8 +117,8 @@
Get
Return _State
End Get
Set(ByVal value As MinecraftState)
If _State = value Then Exit Property
Set(value As MinecraftState)
If _State = value Then Return
_State = value
WatcherStateChanged()
End Set
@@ -129,6 +128,7 @@
Running
Crashed
Ended
Canceled
End Enum
'日志
@@ -144,13 +144,14 @@
'输出文本
Dim Copyed As New List(Of String)
SyncLock WaitingLogLock
If WaitingLog.Count = 0 Then Exit Sub
If Not WaitingLog.Any() Then Return
Copyed = WaitingLog
WaitingLog = New List(Of String)(1000)
End SyncLock
For Each Str As String In Copyed
GameLog(Str)
Next
If State = MinecraftState.Loading Then ProgressUpdate()
'游戏退出检查
If GameProcess.HasExited Then
WatcherLog("Minecraft 已退出,返回值:" & GameProcess.ExitCode)
@@ -167,7 +168,7 @@
'返回值不为 0 且未结束
WatcherLog("Minecraft 返回值异常,可能已崩溃")
Crashed()
Else
ElseIf State <> MinecraftState.Crashed Then
'正常关闭
State = MinecraftState.Ended
End If
@@ -179,8 +180,9 @@
Public LatestLog As New Queue(Of String)
Private Sub GameLog(Text As String)
'预处理
If Text Is Nothing Then Exit Sub
If Text Is Nothing Then Return
Text = Text.Replace(vbCrLf, vbCr).Replace(vbLf, vbCr).Replace(vbCr, vbCrLf)
'If Text.Contains("�����") Then Hint("检测到错误的日志编码:" & Text)
'加入预存储
LatestLog.Enqueue(Text)
If LatestLog.Count >= 501 Then LatestLog.Dequeue()
@@ -192,7 +194,7 @@
If LogProgress < 2 AndAlso Text.Contains("Setting user:") Then
WatcherLog("日志 2/5:游戏用户已设置") '仅确保支持 Minecraft 1.7+
LogProgress = 2
ElseIf LogProgress < 3 AndAlso Text.ToLower.Contains("lwjgl version") Then
ElseIf LogProgress < 3 AndAlso Text.ContainsF("lwjgl version", True) Then
WatcherLog("日志 3/5:LWJGL 版本已确认")
LogProgress = 3
ElseIf LogProgress < 4 AndAlso (Text.Contains("OpenAL initialized") OrElse Text.Contains("Starting up SoundSystem")) Then
@@ -206,7 +208,7 @@
'Log(Text)
'关闭与崩溃检测
If Not Text.Contains("[CHAT]") Then
If Text.Contains("Someone is closing me!") Then
If Text.Contains("Someone is closing me!") OrElse Text.Contains("Restarting Minecraft with command") Then '#1258
WatcherLog("识别为关闭的 Log:" & Text)
State = MinecraftState.Ended
ElseIf Text.Contains("Crash report saved to") OrElse Text.Contains("This crash report has been saved to:") Then
@@ -248,69 +250,90 @@
'窗口检查
Private IsWindowAppeared As Boolean = False
''' <summary>
''' 窗口检查是否已经完成。这不一定代表着找到了窗口(如果没有找到,IsWindowAppeared 仍为 False)。
''' </summary>
Private IsWindowFinished As Boolean = False
Private WindowHandle As IntPtr
Private MinecraftBeforeLaunch As List(Of IntPtr)
Private Sub TimerWindow()
Try
If GameProcess.HasExited Then Exit Sub
If Not IsWindowFinished Then
'获取全部窗口,检查是否有新增的
Dim MinecraftWindows = GetAllMinecraftWindowHandle(True)
For Each Window In MinecraftBeforeLaunch
If MinecraftWindows.ContainsKey(Window) Then MinecraftWindows.Remove(Window)
Next
If MinecraftWindows.Count = 0 Then Exit Sub
'已找到窗口
If MinecraftWindows.Values(0) Then
'已找到 Minecraft 窗口
WindowHandle = MinecraftWindows.Keys(0)
WatcherLog("Minecraft 窗口已加载:" & WindowHandle.ToInt64)
IsWindowFinished = True
'最大化
Thread.Sleep(3000) '1.7.10 LiteLoader 不延迟会显示错误
If Setup.Get("LaunchArgumentWindowType") = 4 Then ShowWindow(WindowHandle, 3)
ElseIf Not IsWindowAppeared Then
'已找到 FML 窗口
WatcherLog("FML 窗口已加载:" & MinecraftWindows.Keys(0).ToInt64)
If GameProcess.HasExited Then Return
If IsWindowFinished Then Return
'获取全部窗口,检查是否有新增的
Dim MinecraftWindow As KeyValuePair(Of IntPtr, String)? = Nothing
Try
MinecraftWindow = TryGetMinecraftWindow()
Catch ex As ComponentModel.Win32Exception
'拒绝访问(#1062)
Log(ex, "由于反作弊或安全软件拦截,PCL 无法操作游戏窗口", LogLevel.Hint)
IsWindowFinished = True
End Try
If MinecraftWindow Is Nothing Then Return
Dim MinecraftWindowName = MinecraftWindow.Value.Value, MinecraftWindowHandle = MinecraftWindow.Value.Key
'已找到窗口
If Not MinecraftWindowName.StartsWithF("FML") AndAlso Not MinecraftWindowName.StartsWithF("Quilt Loader") Then
'已找到 Minecraft 窗口
WindowHandle = MinecraftWindowHandle
WatcherLog($"Minecraft 窗口已加载:{MinecraftWindowName}({MinecraftWindowHandle.ToInt64})")
IsWindowFinished = True
'最大化
If Setup.Get("LaunchArgumentWindowType") = 4 Then
RunInNewThread(
Sub()
Try
'如果最大化导致屏幕渲染大小不对,那是 MC 的 Bug,不是我的 Bug
'……虽然我很想这样说,但总有人反馈,算了
Thread.Sleep(2000)
ShowWindow(WindowHandle, 3)
WatcherLog($"已最大化 Minecraft 窗口:{MinecraftWindowHandle.ToInt64}")
Catch ex As Exception
Log(ex, "最大化 Minecraft 窗口时出现错误")
End Try
End Sub, "MinecraftWindowMaximize")
End If
IsWindowAppeared = True
ElseIf Not IsWindowAppeared Then
'已找到 Mod Loader 窗口
WatcherLog("Mod Loader 窗口已加载:" & MinecraftWindowName & "(" & MinecraftWindowHandle.ToInt64 & ")")
End If
IsWindowAppeared = True
Catch ex As Exception
Log(ex, "检查 Minecraft 窗口失败", LogLevel.Feedback)
End Try
End Sub
''' <summary>
''' 获取所有 Minecraft 窗口句柄。
''' Value: 是否为 Minecraft 窗口,而不是 FML 窗口。
''' 获取可能是当前进程对应的 Minecraft 窗口的句柄和标题。
''' Nothing 代表未找到。
''' </summary>
''' <param name="CanUseFml">是否包含 FML 窗口</param>
Private Function GetAllMinecraftWindowHandle(CanUseFml As Boolean) As Dictionary(Of IntPtr, Boolean)
Dim AllList As New Dictionary(Of IntPtr, Boolean)
EnumWindows(Sub(hwnd As IntPtr, lParam As Integer)
'检查类名
Dim str As New StringBuilder(512)
GetClassName(hwnd, str, str.Capacity)
Dim ClassName As String = str.ToString
If Not (ClassName = "GLFW30" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Exit Sub
'检查窗口标题名
str = New StringBuilder(512)
GetWindowText(hwnd, str, str.Capacity)
Dim WindowText As String = str.ToString
If CanUseFml AndAlso WindowText.StartsWith("FML") Then
AllList.Add(hwnd, False)
ElseIf Not (WindowText.StartsWith("GLFW") OrElse WindowText = "PopupMessageWindow") Then
'有的 Mod 可以修改窗口标题,不能检测是否为 Minecraft 打头
'部分版本会搞个 GLFW message window 出来所以得反选
AllList.Add(hwnd, True)
End If
'If WindowText.StartsWith("Minecraft") Then
' AllList.Add(hwnd, True)
'ElseIf CanUseFml AndAlso WindowText.StartsWith("FML") Then
' AllList.Add(hwnd, False)
'End If
End Sub, 0)
Return AllList
Private Function TryGetMinecraftWindow() As KeyValuePair(Of IntPtr, String)?
TryGetMinecraftWindow = Nothing
EnumWindows(
Sub(hwnd As IntPtr, lParam As Integer)
If TryGetMinecraftWindow IsNot Nothing Then Return
'检查类名
Dim str As New StringBuilder(512)
GetClassName(hwnd, str, str.Capacity)
Dim ClassName As String = str.ToString
If Not (ClassName = "GLFW30" OrElse ClassName = "LWJGL" OrElse ClassName = "SunAwtFrame") Then Return
'获取窗口标题名
str = New StringBuilder(512)
GetWindowText(hwnd, str, str.Capacity)
Dim WindowText As String = str.ToString
'有的 Mod 可以修改窗口标题,所以不能检测是否为 Minecraft 打头,这并不准确
'部分版本会搞个 GLFW message window 出来所以得反选
If Not (WindowText.StartsWithF("FML") OrElse (WindowText <> "PopupMessageWindow") AndAlso Not WindowText.StartsWithF("GLFW")) Then Return
'获取窗口关联的进程
Dim ProcessId As Integer
GetWindowThreadProcessId(hwnd, ProcessId)
Try
If Process.GetProcessById(ProcessId).StartTime < GameProcess.StartTime Then Return '需要是此后启动的进程
Catch ex As Exception
Log(ex, "枚举 Minecraft 窗口进程失败")
Return
End Try
'返回
TryGetMinecraftWindow = New KeyValuePair(Of IntPtr, String)(hwnd, WindowText)
End Sub, 0)
Return TryGetMinecraftWindow
End Function
Private Delegate Sub EnumWindowsSub(hwnd As IntPtr, lParam As Integer)
Private Declare Function EnumWindows Lib "user32" (hWnd As EnumWindowsSub, lParam As Integer) As Boolean
@@ -318,35 +341,36 @@
Private Declare Function GetWindowText Lib "user32" Alias "GetWindowTextA" (hWnd As Integer, str As StringBuilder, maxCount As Integer) As Integer
Private Declare Function SetWindowText Lib "user32" Alias "SetWindowTextA" (hWnd As Integer, str As String) As Boolean
Private Declare Function ShowWindow Lib "user32" (hWnd As IntPtr, cmdWindow As UInteger) As Boolean
Private Declare Function GetWindowThreadProcessId Lib "user32" (hWnd As IntPtr, ByRef lpdwProcessId As Integer) As Integer
'崩溃处理
Private Sub Crashed()
If State = MinecraftState.Crashed OrElse State = MinecraftState.Ended Then Exit Sub
If State = MinecraftState.Crashed OrElse State = MinecraftState.Ended Then Return
State = MinecraftState.Crashed
'崩溃分析
WatcherLog("Minecraft 已崩溃,将在 2 秒后开始崩溃分析")
Hint("检测到 Minecraft 出现错误,错误分析已开始……")
RunInNewThread(Sub()
Try
Thread.Sleep(2000)
WatcherLog("崩溃分析开始")
Dim Analyzer As New CrashAnalyzer(PID)
Analyzer.Collect(Version.PathIndie, LatestLog.ToList)
Analyzer.Prepare()
Analyzer.Analyze(Version)
Analyzer.Output(False, New List(Of String) From
{Version.Path & Version.Name & ".json",
Path & "PCL\Log1.txt",
Path & "PCL\LatestLaunch.bat"})
Catch ex As Exception
Log(ex, "崩溃分析失败", LogLevel.Feedback)
End Try
End Sub, "Crash Analyzer")
FeedbackInfo()
RunInNewThread(
Sub()
Try
Thread.Sleep(2000)
WatcherLog("崩溃分析开始")
Dim Analyzer As New CrashAnalyzer(PID)
Analyzer.Collect(Version.PathIndie, LatestLog.ToList)
Analyzer.Prepare()
Analyzer.Analyze(Version)
Analyzer.Output(False, New List(Of String) From
{Version.Path & Version.Name & ".json", Path & "PCL\Log1.txt", Path & "PCL\LatestLaunch.bat"})
Catch ex As Exception
Log(ex, "崩溃分析失败", LogLevel.Feedback)
End Try
End Sub, "Crash Analyzer")
End Sub
'强制关闭
Public Sub Kill()
State = MinecraftState.Ended
State = MinecraftState.Canceled
WatcherLog("尝试强制结束 Minecraft 进程")
Try
If Not GameProcess.HasExited Then GameProcess.Kill()
@@ -0,0 +1,8 @@
Public Module ModDevelop
#If DEBUG Then
Public Sub Start()
End Sub
#End If
End Module
+90 -65
View File
@@ -1,7 +1,7 @@
Public Module ModEvent
Public Sub TryStartEvent(Type As String, Data As String)
If String.IsNullOrWhiteSpace(Type) Then Exit Sub
If String.IsNullOrWhiteSpace(Type) Then Return
Dim RealData As String() = {""}
If Data IsNot Nothing Then RealData = Data.Split("|")
StartEvent(Type, RealData)
@@ -13,83 +13,110 @@
Case "打开网页"
Data(0) = Data(0).Replace("\", "/")
If Not (Data(0).StartsWith("http://") OrElse Data(0).StartsWith("https://")) Then
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败")
Exit Sub
If Not Data(0).Contains("://") OrElse Data(0).StartsWithF("file", True) Then '为了支持更多协议(#2200)
MyMsgBox("EventData 必须为一个网址。" & vbCrLf & "如果想要启动程序,请将 EventType 改为 打开文件。", "事件执行失败")
Return
End If
Hint("正在打开网页,请稍候……")
Hint("正在开启中,请稍候……")
OpenWebsite(Data(0))
Case "打开文件", "打开帮助"
RunInThread(Sub()
Try
Case "打开文件", "打开帮助", "执行命令"
RunInThread(
Sub()
Try
'确认实际路径
Dim ActualPaths = GetEventAbsoluteUrls(Data(0), Type)
Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1)
Log($"[Control] 打开类自定义事件实际路径:{Location},工作目录:{WorkingDir}")
'执行
If Type = "打开帮助" Then
PageOtherHelp.EnterHelpPage(Location)
Else
If Not Setup.Get("HintCustomCommand") Then
Select Case MyMsgBox(
"即将执行:" & Location & If(Data.Length >= 2, " " & Data(1), "") & vbCrLf &
"请在确认该操作没有安全隐患后继续。", "执行确认", "继续", "继续且今后不再要求确认", "取消")
Case 2
Setup.Set("HintCustomCommand", True)
Case 3
Return
End Select
End If
Dim Info As New ProcessStartInfo With {
.Arguments = If(Data.Length >= 2, Data(1), ""),
.FileName = Location,
.WorkingDirectory = ShortenPath(WorkingDir)
}
Process.Start(Info)
End If
Catch ex As Exception
Log(ex, "执行打开类自定义事件失败", LogLevel.Msgbox)
End Try
End Sub)
'确认实际路径
Dim ActualPaths = GetEventAbsoluteUrls(Data(0), Type)
Dim Location = ActualPaths(0), WorkingDir = ActualPaths(1)
'执行
If Type = "打开文件" Then
Dim Info As New ProcessStartInfo With {
.Arguments = If(Data.Length >= 2, Data(1), ""),
.FileName = Location,
.WorkingDirectory = WorkingDir
}
Process.Start(Info)
Else '打开帮助
PageOtherHelp.EnterHelpPage(Location)
End If
Catch ex As Exception
Log(ex, "执行打开类自定义事件失败", LogLevel.Msgbox)
End Try
End Sub)
Case "启动游戏"
'初始化与前置条件检测
If Not (FrmLaunchLeft.BtnLaunch.IsEnabled AndAlso FrmLaunchLeft.BtnLaunch.Visibility = Visibility.Visible AndAlso FrmLaunchLeft.BtnLaunch.IsHitTestVisible) Then
Hint("已有游戏正在启动中!", HintType.Critical) : Exit Sub
If Data(0) = "\current" Then
If McVersionCurrent Is Nothing Then
Hint("请先选择一个 Minecraft 版本!", HintType.Critical)
Return
Else
Data(0) = McVersionCurrent.Name
End If
End If
If Not Directory.Exists(PathMcFolder & "versions\" & Data(0)) Then
Hint("未在当前 Minecraft 文件夹找到版本 " & Data(0) & "!", HintType.Critical) : Exit Sub
If McLaunchStart(New McLaunchOptions With
{.ServerIp = If(Data.Length >= 2, Data(1), Nothing), .Version = New McVersion(Data(0))}) Then
Hint("正在启动 " & Data(0) & "……")
End If
Dim ButtonVersion As New McVersion(Data(0))
ButtonVersion.Load()
If ButtonVersion.State = McVersionState.Error Then
Hint("无法启动 " & Data(0) & ":" & ButtonVersion.Info, HintType.Critical) : Exit Sub
End If
'实际启动
McVersionCurrent = ButtonVersion
Setup.Set("LaunchVersionSelect", McVersionCurrent.Name)
FrmLaunchLeft.PageLaunchLeft_Loaded()
FrmLaunchLeft.RefreshButtonsUI()
FrmMain.AprilGiveup()
FrmLaunchLeft.LaunchButtonClick(If(Data.Length >= 2, Data(1), ""))
FrmMain.PageChange(FormMain.PageType.Launch)
Case "复制文本"
ClipboardSet(Join(Data, "|"))
Case "刷新主页"
FrmLaunchRight.ForceRefresh()
If Data(0) = "" Then Hint("已刷新主页!", HintType.Finish)
Case "刷新帮助"
PageOtherLeft.RefreshHelp()
Case "今日人品"
PageOtherTest.Jrrp()
Case "内存优化"
RunInThread(Sub() PageOtherTest.MemoryOptimize(True))
Case "清理垃圾"
RunInThread(Sub() PageOtherTest.RubbishClear())
Case "弹出窗口"
MyMsgBox(Data(1).Replace("\n", vbCrLf), Data(0).Replace("\n", vbCrLf))
Case "切换页面"
FrmMain.PageChange(Val(Data(0)), Val(Data(1)))
Case "导入整合包", "安装整合包"
RunInUi(Sub() ModpackInstall())
Case "下载文件"
Data(0) = Data(0).Replace("\", "/")
If Not (Data(0).StartsWith("http://") OrElse Data(0).StartsWith("https://")) Then
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL2 不支持其他乱七八糟的协议。", "事件执行失败")
Exit Sub
If Not (Data(0).StartsWithF("http://", True) OrElse Data(0).StartsWithF("https://", True)) Then
MyMsgBox("EventData 必须为以 http:// 或 https:// 开头的网址。" & vbCrLf & "PCL 不支持其他乱七八糟的下载协议。", "事件执行失败")
Return
End If
PageOtherTest.StartCustomDownload(Data(0))
Try
Select Case Data.Length
Case 1
PageOtherTest.StartCustomDownload(Data(0), GetFileNameFromPath(Data(0)))
Case 2
PageOtherTest.StartCustomDownload(Data(0), Data(1))
Case Else
PageOtherTest.StartCustomDownload(Data(0), Data(1), Data(2))
End Select
Catch
PageOtherTest.StartCustomDownload(Data(0), "未知")
End Try
Case Else
MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL2 是否为最新版本。", "事件执行失败")
MyMsgBox("未知的事件类型:" & Type & vbCrLf & "请检查事件类型填写是否正确,或者 PCL 是否为最新版本。", "事件执行失败")
End Select
Catch ex As Exception
Log(ex, "事件执行失败", LogLevel.Msgbox)
@@ -103,16 +130,15 @@
Public Function GetEventAbsoluteUrls(RelativeUrl As String, EventType As String) As String()
'网页确认
If RelativeUrl.ToLower.StartsWith("http") Then
If RelativeUrl.StartsWithF("http", True) Then
If RunInUi() Then
Throw New Exception("MyListItem 在界面初始化时就需要获取帮助标题等信息,这会导致程序在网络请求时卡死。" & vbCrLf &
"因此,请换用 MyListItem 以外的控件(例如 MyButton)作为联网帮助页面的入口!")
Throw New Exception("能打开联网帮助页面的 MyListItem 必须手动设置 Title、Info 属性!")
End If
'获取文件名
Dim RawFileName As String
Try
RawFileName = GetFileNameFromPath(RelativeUrl)
If Not RawFileName.ToLower.EndsWith(".json") Then Throw New Exception("未指向 .json 后缀的文件")
If Not RawFileName.EndsWithF(".json", True) Then Throw New Exception("未指向 .json 后缀的文件")
Catch ex As Exception
Throw New Exception("联网帮助页面须指向一个帮助 JSON 文件,并在同路径下包含相应 XAML 文件!" & vbCrLf &
"例如:" & vbCrLf &
@@ -120,13 +146,11 @@
" - https://www.baidu.com/test.xaml(同时也需要包含这个文件)", ex)
End Try
'下载文件
Dim LocalTemp1 As String = PathTemp & "CustomEvent\" & RawFileName
Dim LocalTemp2 As String = PathTemp & "CustomEvent\" & RawFileName.Replace(".json", ".xaml")
Log("[Event] 转换网络资源:" & RelativeUrl & " -> " & LocalTemp1)
Hint("正在获取资源,请稍候……")
Dim LocalTemp As String = RequestTaskTempFolder() & RawFileName
Log("[Event] 转换网络资源:" & RelativeUrl & " -> " & LocalTemp)
Try
NetDownload(RelativeUrl, LocalTemp1)
NetDownload(RelativeUrl.Replace(".json", ".xaml"), LocalTemp1.Replace(".json", ".xaml"))
NetDownloadByClient(RelativeUrl, LocalTemp)
NetDownloadByClient(RelativeUrl.Replace(".json", ".xaml"), LocalTemp.Replace(".json", ".xaml"))
Catch ex As Exception
Throw New Exception("下载指定的文件失败!" & vbCrLf &
"注意,联网帮助页面须指向一个帮助 JSON 文件,并在同路径下包含相应 XAML 文件!" & vbCrLf &
@@ -134,12 +158,13 @@
" - https://www.baidu.com/test.json(填写这个路径)" & vbCrLf &
" - https://www.baidu.com/test.xaml(同时也需要包含这个文件)", ex)
End Try
RelativeUrl = LocalTemp1
RelativeUrl = LocalTemp
End If
RelativeUrl = RelativeUrl.Replace("/", "\").ToLower.TrimStart("\")
'确认实际路径
Dim Location As String, WorkingDir As String = Path & "PCL"
HelpTryExtract()
If RelativeUrl.Contains(":\") Then
'绝对路径
Location = RelativeUrl
@@ -158,7 +183,7 @@
Location = PathTemp & "Help\" & RelativeUrl
WorkingDir = PathTemp & "Help\"
Log("[Control] 自定义事件中由相对 PCL 自带帮助文件夹的路径" & EventType & ":" & Location)
ElseIf EventType = "打开文件" Then
ElseIf EventType = "打开文件" OrElse EventType = "执行命令" Then
'直接使用原有路径启动程序
Location = RelativeUrl
Log("[Control] 自定义事件中直接" & EventType & ":" & Location)
+979
View File
@@ -0,0 +1,979 @@
Imports System.Windows.Interop
Imports System.Windows.Threading
Public Module ModMain
#Region "弹出提示"
''' <summary>
''' 提示信息的种类。
''' </summary>
Public Enum HintType
''' <summary>
''' 信息,通常是蓝色的“i”。
''' </summary>
''' <remarks></remarks>
Info
''' <summary>
''' 已完成,通常是绿色的“√”。
''' </summary>
''' <remarks></remarks>
Finish
''' <summary>
''' 错误,通常是红色的“×”。
''' </summary>
''' <remarks></remarks>
Critical
End Enum
Private Structure HintMessage
Public Text As String
Public Type As HintType
Public Log As Boolean
End Structure
''' <summary>
''' 等待弹出的提示列表。以 {String, HintType, Log As Boolean} 形式存储为数组。
''' </summary>
Private HintWaiting As SafeList(Of HintMessage) = If(HintWaiting, New SafeList(Of HintMessage))
''' <summary>
''' 在窗口左下角弹出提示文本。
''' </summary>
Public Sub Hint(Text As String, Optional Type As HintType = HintType.Info, Optional Log As Boolean = True)
If HintWaiting Is Nothing Then HintWaiting = New SafeList(Of HintMessage)
HintWaiting.Add(New HintMessage With {.Text = If(Text, ""), .Type = Type, .Log = Log})
End Sub
Private Sub HintTick()
Try
'Tag 存储了:{ 是否可以重用, Uuid }
If Not HintWaiting.Any() Then Return
Do While HintWaiting.Any
''清除空提示
'If IsNothing(HintWaiting(0)) OrElse IsNothing(HintWaiting(0)(0)) Then
' HintWaiting.RemoveAt(0)
' Continue Do
'End If
Dim CurrentHint = HintWaiting(0)
'去回车
CurrentHint.Text = CurrentHint.Text.Replace(vbCrLf, " ").Replace(vbCr, " ").Replace(vbLf, " ")
'超量提示直接忽略
If FrmMain.PanHint.Children.Count >= 20 Then GoTo EndHint
'检查是否有重复提示
Dim DoubleStack As Border = Nothing
For Each stack As Border In FrmMain.PanHint.Children
If stack.Tag(0) AndAlso CType(stack.Child, TextBlock).Text = CurrentHint.Text Then DoubleStack = stack
Next
'获取渐变颜色
Dim TargetColor0, TargetColor1 As MyColor
Dim Percent As Double = 0.3
Select Case CurrentHint.Type
Case HintType.Info
TargetColor0 = New MyColor(215, 37, 155, 252)
TargetColor1 = New MyColor(215, 10, 142, 252)
Case HintType.Finish
TargetColor0 = New MyColor(215, 33, 177, 33)
TargetColor1 = New MyColor(215, 29, 160, 29)
Case Else 'HintType.Critical
TargetColor0 = New MyColor(215, 255, 53, 11)
TargetColor1 = New MyColor(215, 255, 43, 0)
End Select
If Not IsNothing(DoubleStack) Then
'有重复提示,且该提示的进入动画已播放
If Not AniIsRun("Hint Show " & DoubleStack.Tag(1)) Then
AniStop("Hint Hide " & DoubleStack.Tag(1))
Dim Delay As Double = (800 + MathClamp(CurrentHint.Text.Length, 5, 23) * 180) * AniSpeed
AniStart({
AaX(DoubleStack, -12 - DoubleStack.Margin.Left, 50,, New AniEaseOutFluent),
AaX(DoubleStack, -8, 50, 50, New AniEaseInFluent),
AaX(DoubleStack, 8, 50, 100, New AniEaseOutFluent),
AaX(DoubleStack, -8, 50, 150, New AniEaseInFluent),
AaDouble(Sub(i)
Percent += i
Dim Gradient As LinearGradientBrush = DoubleStack.Background
Gradient.GradientStops(0).Color = TargetColor0 * Percent + New MyColor(255, 255, 255) * (1 - Percent)
Gradient.GradientStops(1).Color = TargetColor1 * Percent + New MyColor(255, 255, 255) * (1 - Percent)
End Sub, 0.7, 250),
AaX(DoubleStack, -50, 200, Delay, New AniEaseInFluent),
AaOpacity(DoubleStack, -1, 150, Delay),
AaCode(Sub() DoubleStack.Tag(0) = False, Delay),
AaHeight(DoubleStack, -26, 100,, New AniEaseOutFluent, True),
AaCode(Sub() FrmMain.PanHint.Children.Remove(DoubleStack), , True)
}, "Hint Hide " & DoubleStack.Tag(1))
End If
Else
'准备控件
Dim NewHintControl As New Border With {.Tag = {True, GetUuid()}, .Margin = New Thickness(-70, 0, 20, 0), .Opacity = 0, .Height = 0, .HorizontalAlignment = HorizontalAlignment.Left, .CornerRadius = New CornerRadius(0, 6, 6, 0)}
NewHintControl.Background = New LinearGradientBrush(New GradientStopCollection(New List(Of GradientStop) From {
New GradientStop(TargetColor0 * Percent + New MyColor(255, 255, 255) * (1 - Percent), 0),
New GradientStop(TargetColor1 * Percent + New MyColor(255, 255, 255) * (1 - Percent), 1)}), 90)
NewHintControl.Child = New TextBlock With {.TextTrimming = TextTrimming.CharacterEllipsis, .FontSize = 13, .Text = CurrentHint.Text, .Foreground = New MyColor(255, 255, 255), .Margin = New Thickness(33, 5, 8, 5)}
'AddHandler NewHintControl.MouseLeftButtonDown, AddressOf HideAllHint
FrmMain.PanHint.Children.Add(NewHintControl)
'控件动画
Dim Animations As New List(Of AniData)
If FrmMain.PanHint.Children.Count > 1 Then
'已有提示
Animations.Add(AaHeight(NewHintControl, 26, 150, , New AniEaseOutFluent))
Else
'是唯一提示
NewHintControl.Height = 26
End If
'开始动画
Animations.AddRange({
AaX(NewHintControl, 30, 400, , New AniEaseOutElastic(AniEasePower.Weak)),
AaX(NewHintControl, 20, 200, , New AniEaseOutFluent),
AaOpacity(NewHintControl, 1, 100),
AaDouble(Sub(i)
Percent += i
Dim Gradient As LinearGradientBrush = NewHintControl.Background
Gradient.GradientStops(0).Color = TargetColor0 * Percent + New MyColor(255, 255, 255) * (1 - Percent)
Gradient.GradientStops(1).Color = TargetColor1 * Percent + New MyColor(255, 255, 255) * (1 - Percent)
End Sub, 0.7, 250, 100)
})
AniStart(Animations, "Hint Show " & NewHintControl.Tag(1))
'结束动画
Dim Delay As Double = (800 + MathClamp(CurrentHint.Text.Length, 5, 23) * 180) * AniSpeed
AniStart({
AaX(NewHintControl, -50, 200, Delay, New AniEaseInFluent),
AaOpacity(NewHintControl, -1, 150, Delay),
AaCode(Sub() NewHintControl.Tag(0) = False, Delay),
AaHeight(NewHintControl, -26, 100,, New AniEaseOutFluent, True),
AaCode(Sub() FrmMain.PanHint.Children.Remove(NewHintControl), , True)
}, "Hint Hide " & NewHintControl.Tag(1))
End If
'结束处理
EndHint:
If CurrentHint.Log Then Log("[UI] 弹出提示:" & CurrentHint.Text)
HintWaiting.RemoveAt(0)
Loop
Catch ex As Exception
Log(ex, "显示弹出提示失败", LogLevel.Normal)
End Try
End Sub
Private Sub HideAllHint()
For Each Control As Border In FrmMain.PanHint.Children
Control.IsHitTestVisible = False
AniStart({
AaX(Control, -50, 200, , New AniEaseInFluent),
AaOpacity(Control, -1, 150, , New AniEaseInFluent),
AaCode(Sub() Control.Tag(0) = False),
AaHeight(Control, -26, 100,, New AniEaseOutFluent, True),
AaCode(Sub() FrmMain.PanHint.Children.Remove(Control), , True)
}, "Hint Hide " & Control.Tag(1))
Next
End Sub
#End Region
#Region "弹窗"
''' <summary>
''' 存储弹窗信息的转换器。
''' </summary>
Public Class MyMsgBoxConverter
Public Type As MyMsgBoxType
Public Title As String
Public Text As String
''' <summary>
''' 输入模式:文本框的文本。
''' 选择模式:需要放进去的 List(Of MyListItem)。
''' 登录模式:登录步骤 1 中返回的 JSON。
''' </summary>
Public Content As Object
''' <summary>
''' 输入模式:输入验证规则。
''' </summary>
Public ValidateRules As ObjectModel.Collection(Of Validate)
''' <summary>
''' 输入模式:提示文本。
''' </summary>
Public HintText As String = ""
''' <summary>
''' 有多个按钮时,是否给第一个按钮加高亮。
''' </summary>
Public HighLight As Boolean
Public Button1 As String = "确定"
Public Button2 As String = ""
Public Button3 As String = ""
''' <summary>
''' 点击第一个按钮将执行该方法,不关闭弹窗。
''' </summary>
Public Button1Action As Action = Nothing
''' <summary>
''' 点击第二个按钮将执行该方法,不关闭弹窗。
''' </summary>
Public Button2Action As Action = Nothing
''' <summary>
''' 点击第三个按钮将执行该方法,不关闭弹窗。
''' </summary>
Public Button3Action As Action = Nothing
Public IsWarn As Boolean = False
Public ForceWait As Boolean = False
Public WaitFrame As New DispatcherFrame(True)
''' <summary>
''' 弹窗是否已经关闭。
''' </summary>
Public IsExited As Boolean = False
''' <summary>
''' 输入模式:输入的文本。若点击了 非 第一个按钮,则为 Nothing。
''' 选择模式:点击的按钮编号,从 1 开始。
''' 登录模式:字符串数组 {AccessToken, RefreshToken} 或一个 Exception。
''' </summary>
Public Result As Object
End Class
Public Enum MyMsgBoxType
Text
[Select]
Input
Login
End Enum
''' <summary>
''' 显示弹窗,返回点击按钮的编号(从 1 开始)。
''' </summary>
''' <param name="Title">弹窗的标题。</param>
''' <param name="Caption">弹窗的内容。</param>
''' <param name="Button1">显示的第一个按钮,默认为“确定”。</param>
''' <param name="Button2">显示的第二个按钮,默认为空。</param>
''' <param name="Button3">显示的第三个按钮,默认为空。</param>
''' <param name="Button1Action">点击第一个按钮将执行该方法,不关闭弹窗。</param>
''' <param name="Button2Action">点击第二个按钮将执行该方法,不关闭弹窗。</param>
''' <param name="Button3Action">点击第三个按钮将执行该方法,不关闭弹窗。</param>
''' <param name="IsWarn">是否为警告弹窗,若为 True,弹窗配色和背景会变为红色。</param>
Public Function MyMsgBox(Caption As String, Optional Title As String = "提示",
Optional Button1 As String = "确定", Optional Button2 As String = "", Optional Button3 As String = "",
Optional IsWarn As Boolean = False, Optional HighLight As Boolean = True, Optional ForceWait As Boolean = False,
Optional Button1Action As Action = Nothing, Optional Button2Action As Action = Nothing, Optional Button3Action As Action = Nothing) As Integer
'将弹窗列入队列
Dim Converter As New MyMsgBoxConverter With {.Type = MyMsgBoxType.Text, .Button1 = Button1, .Button2 = Button2, .Button3 = Button3, .Text = Caption, .IsWarn = IsWarn, .Title = Title, .HighLight = HighLight, .ForceWait = True, .Button1Action = Button1Action, .Button2Action = Button2Action, .Button3Action = Button3Action}
WaitingMyMsgBox.Add(Converter)
If RunInUi() Then
'若为 UI 线程,立即执行弹窗刻, 避免快速(连点器)点击时多次弹窗
MyMsgBoxTick()
End If
If Button2.Length > 0 OrElse ForceWait Then
'若有多个按钮则开始等待
If FrmMain Is Nothing OrElse FrmMain.PanMsg Is Nothing AndAlso RunInUi() Then
'主窗体尚未加载,用老土的弹窗来替代
WaitingMyMsgBox.Remove(Converter)
If Button2.Length > 0 Then
Dim RawResult As MsgBoxResult = MsgBox(Caption, If(Button3.Length > 0, MsgBoxStyle.YesNoCancel, MsgBoxStyle.YesNo) + If(IsWarn, MsgBoxStyle.Critical, MsgBoxStyle.Question), Title)
Select Case RawResult
Case MsgBoxResult.Yes
Converter.Result = 1
Case MsgBoxResult.No
Converter.Result = 2
Case MsgBoxResult.Cancel
Converter.Result = 3
End Select
Else
MsgBox(Caption, MsgBoxStyle.OkOnly + If(IsWarn, MsgBoxStyle.Critical, MsgBoxStyle.Question), Title)
Converter.Result = 1
End If
Log("[Control] 主窗体加载完成前出现意料外的等待弹窗:" & Button1 & "," & Button2 & "," & Button3, LogLevel.Debug)
Else
Try
FrmMain.DragStop()
ComponentDispatcher.PushModal()
Dispatcher.PushFrame(Converter.WaitFrame)
Finally
ComponentDispatcher.PopModal()
End Try
End If
Log("[Control] 普通弹框返回:" & If(Converter.Result, "null"))
Return Converter.Result
Else
'不进行等待,直接返回
Return 1
End If
End Function
''' <summary>
''' 显示输入框并返回输入的文本。若点击第二个按钮,则返回 Nothing。
''' </summary>
''' <param name="Title">弹窗的标题。</param>
''' <param name="ValidateRules">文本框的输入检测。</param>
''' <param name="Text">弹窗的介绍文本。</param>
''' <param name="DefaultInput">文本框的默认内容。</param>
''' <param name="HintText">文本框的提示内容。</param>
''' <param name="Button1">显示的第一个按钮,默认为“确定”。</param>
''' <param name="Button2">显示的第二个按钮,默认为“取消”。</param>
''' <param name="IsWarn">是否为警告弹窗,若为 True,弹窗配色和背景会变为红色。</param>
Public Function MyMsgBoxInput(Title As String, Optional Text As String = "", Optional DefaultInput As String = "", Optional ValidateRules As ObjectModel.Collection(Of Validate) = Nothing, Optional HintText As String = "", Optional Button1 As String = "确定", Optional Button2 As String = "取消", Optional IsWarn As Boolean = False) As String
'将弹窗列入队列
Dim Converter As New MyMsgBoxConverter With {.Text = Text, .HintText = HintText, .Type = MyMsgBoxType.Input, .ValidateRules = If(ValidateRules, New ObjectModel.Collection(Of Validate)), .Button1 = Button1, .Button2 = Button2, .Content = DefaultInput, .IsWarn = IsWarn, .Title = Title}
WaitingMyMsgBox.Add(Converter)
'虽然我也不知道这是啥但是能用就成了 :)
Try
If FrmMain IsNot Nothing Then FrmMain.DragStop()
ComponentDispatcher.PushModal()
Dispatcher.PushFrame(Converter.WaitFrame)
Finally
ComponentDispatcher.PopModal()
End Try
Log("[Control] 输入弹框返回:" & If(Converter.Result, "null"))
Return Converter.Result
End Function
''' <summary>
''' 显示选择框并返回选择的第几项(从 0 开始)。若点击第二个按钮,则返回 Nothing。
''' </summary>
''' <param name="Title">弹窗的标题。</param>
''' <param name="Button1">显示的第一个按钮,默认为 “确定”。</param>
''' <param name="Button2">显示的第二个按钮,默认为空。</param>
''' <param name="IsWarn">是否为警告弹窗,若为 True,弹窗配色和背景会变为红色。</param>
Public Function MyMsgBoxSelect(Selections As List(Of IMyRadio), Optional Title As String = "提示", Optional Button1 As String = "确定", Optional Button2 As String = "", Optional IsWarn As Boolean = False) As Integer?
'将弹窗列入队列
Dim Converter As New MyMsgBoxConverter With {.Type = MyMsgBoxType.Select, .Button1 = Button1, .Button2 = Button2, .Content = Selections, .IsWarn = IsWarn, .Title = Title}
WaitingMyMsgBox.Add(Converter)
'虽然我也不知道这是啥但是能用就成了 :)
Try
If FrmMain IsNot Nothing Then FrmMain.DragStop()
ComponentDispatcher.PushModal()
Dispatcher.PushFrame(Converter.WaitFrame)
Finally
ComponentDispatcher.PopModal()
End Try
Log("[Control] 选择弹框返回:" & If(Converter.Result, "null"))
Return Converter.Result
End Function
''' <summary>
''' 等待显示的弹窗。
''' </summary>
Public WaitingMyMsgBox As List(Of MyMsgBoxConverter) = If(WaitingMyMsgBox, New List(Of MyMsgBoxConverter))
Public Sub MyMsgBoxTick()
Try
If FrmMain Is Nothing OrElse FrmMain.PanMsg Is Nothing OrElse FrmMain.WindowState = WindowState.Minimized Then Return
If FrmMain.PanMsg.Children.Count > 0 Then
'弹窗中
FrmMain.PanMsg.Visibility = Visibility.Visible
ElseIf WaitingMyMsgBox.Any Then
'没有弹窗,显示一个等待的弹窗
FrmMain.PanMsg.Visibility = Visibility.Visible
Select Case CType(WaitingMyMsgBox(0), MyMsgBoxConverter).Type
Case MyMsgBoxType.Input
FrmMain.PanMsg.Children.Add(New MyMsgInput(WaitingMyMsgBox(0)))
Case MyMsgBoxType.Select
FrmMain.PanMsg.Children.Add(New MyMsgSelect(WaitingMyMsgBox(0)))
Case MyMsgBoxType.Text
FrmMain.PanMsg.Children.Add(New MyMsgText(WaitingMyMsgBox(0)))
Case MyMsgBoxType.Login
FrmMain.PanMsg.Children.Add(New MyMsgLogin(WaitingMyMsgBox(0)))
End Select
WaitingMyMsgBox.RemoveAt(0)
Else
'没有弹窗,没有等待的弹窗
If Not FrmMain.PanMsg.Visibility = Visibility.Collapsed Then FrmMain.PanMsg.Visibility = Visibility.Collapsed
End If
Catch ex As Exception
Log(ex, "处理等待中的弹窗失败", LogLevel.Feedback)
End Try
End Sub
#End Region
#Region "页面声明"
'在最后进行页面声明,避免颜色尚未加载完毕
'窗体声明
Public FrmMain As FormMain
Public FrmStart As SplashScreen
'页面声明(出于单元测试考虑,初始化页面已转入 FormMain 中)
Public FrmLaunchLeft As PageLaunchLeft
Public FrmLaunchRight As PageLaunchRight
Public FrmSelectLeft As PageSelectLeft
Public FrmSelectRight As PageSelectRight
Public FrmSpeedLeft As PageSpeedLeft
Public FrmSpeedRight As PageSpeedRight
'联机页面声明
Public FrmLinkLeft As PageLinkLeft
Public FrmLinkIoi As PageLinkIoi
Public FrmLinkHiper As PageLinkHiper
Public FrmLinkHelp As PageOtherHelpDetail
Public FrmLinkFeedback As PageLinkFeedback
'下载页面声明
Public FrmDownloadLeft As PageDownloadLeft
Public FrmDownloadInstall As PageDownloadInstall
Public FrmDownloadClient As PageDownloadClient
Public FrmDownloadOptiFine As PageDownloadOptiFine
Public FrmDownloadLiteLoader As PageDownloadLiteLoader
Public FrmDownloadForge As PageDownloadForge
Public FrmDownloadNeoForge As PageDownloadNeoForge
Public FrmDownloadFabric As PageDownloadFabric
Public FrmDownloadMod As PageDownloadMod
Public FrmDownloadPack As PageDownloadPack
Public FrmDownloadDataPack As PageDownloadDataPack
Public FrmDownloadShader As PageDownloadShader
Public FrmDownloadResourcePack As PageDownloadResourcePack
'设置页面声明
Public FrmSetupLeft As PageSetupLeft
Public FrmSetupLaunch As PageSetupLaunch
Public FrmSetupUI As PageSetupUI
Public FrmSetupSystem As PageSetupSystem
Public FrmSetupLink As PageSetupLink
'其他页面声明
Public FrmOtherLeft As PageOtherLeft
Public FrmOtherHelp As PageOtherHelp
Public FrmOtherAbout As PageOtherAbout
Public FrmOtherTest As PageOtherTest
'登录页面声明
Public FrmLoginLegacy As PageLoginLegacy
Public FrmLoginNide As PageLoginNide
Public FrmLoginNideSkin As PageLoginNideSkin
Public FrmLoginAuth As PageLoginAuth
Public FrmLoginAuthSkin As PageLoginAuthSkin
Public FrmLoginMs As PageLoginMs
Public FrmLoginMsSkin As PageLoginMsSkin
'版本设置页面声明
Public FrmVersionLeft As PageVersionLeft
Public FrmVersionOverall As PageVersionOverall
Public FrmVersionMod As PageVersionMod
Public FrmVersionModDisabled As PageVersionModDisabled
Public FrmVersionSetup As PageVersionSetup
Public FrmVersionExport As PageVersionExport
'资源信息分页声明
Public FrmDownloadCompDetail As PageDownloadCompDetail
#End Region
#Region "帮助"
Public Class HelpEntry
''' <summary>
''' 原始信息路径。用于刷新。
''' </summary>
Public RawPath As String
'基础
''' <summary>
''' 显示标题。
''' </summary>
Public Title As String
''' <summary>
''' 显示描述。
''' </summary>
Public Desc As String
''' <summary>
''' 检索关键字。
''' </summary>
Public Search As String
''' <summary>
''' 用于分类的标签列表。
''' </summary>
Public Types As List(Of String)
'显示(可选)
''' <summary>
''' 帮助项的自定义图标。可能为 Nothing。
''' </summary>
Public Logo As String = Nothing
''' <summary>
''' 是否显示在搜索结果。默认为 True。
''' </summary>
Public ShowInSearch As Boolean = True
''' <summary>
''' 是否在公开版的 PCL 中显示(这会影响主页与搜索)。默认为 True。
''' </summary>
Public ShowInPublic As Boolean = True
''' <summary>
''' 是否在快照版的 PCL 中显示(这会影响主页与搜索)。默认为 True。
''' </summary>
Public ShowInSnapshot As Boolean = True
'动作
''' <summary>
''' 是否为 “执行事件”。
''' </summary>
Public IsEvent As Boolean
Public EventType As String
Public EventData As String
''' <summary>
''' 若非执行事件,其对应的 .xaml 本地文件内容。
''' </summary>
Public XamlContent As String
'转换
''' <summary>
''' 从文件初始化 HelpEntry 对象,失败会抛出异常。
''' </summary>
Public Sub New(FilePath As String)
RawPath = FilePath
Dim JsonData As JObject = GetJson(HelpArgumentReplace(ReadFile(FilePath)))
If JsonData Is Nothing Then Throw New FileNotFoundException("未找到帮助文件:" & FilePath, FilePath)
'加载常规信息
If JsonData("Title") IsNot Nothing Then
Title = JsonData("Title")
Else
Throw New ArgumentException("未找到 Title 项")
End If
Desc = If(JsonData("Description"), "")
Search = If(JsonData("Keywords"), "")
Logo = JsonData("Logo") '为保持 Nothing,不要加 If
ShowInSearch = If(JsonData("ShowInSearch"), ShowInSearch)
ShowInPublic = If(JsonData("ShowInPublic"), ShowInPublic)
ShowInSnapshot = If(JsonData("ShowInSnapshot"), ShowInSnapshot)
Types = New List(Of String)
For Each NameOfType In If(JsonData("Types"), GetJson("[]"))
Types.Add(NameOfType)
Next
'加载事件信息
If If(JsonData("IsEvent"), False) Then
EventType = JsonData("EventType")
If EventType Is Nothing Then Throw New ArgumentException("未找到 EventType 项")
EventData = If(JsonData("EventData"), "")
IsEvent = True
Else
Dim XamlAddress As String = FilePath.ToLower.Replace(".json", ".xaml")
If File.Exists(XamlAddress) Then
XamlContent = ReadFile(XamlAddress)
IsEvent = False
Else
Throw New FileNotFoundException("未找到帮助条目 .json 对应的 .xaml 文件(" & XamlAddress & ")")
End If
End If
End Sub
''' <summary>
''' 获取该 HelpEntry 对应的 MyListItem。
''' </summary>
Public Function ToListItem() As MyListItem
Return SetToListItem(New MyListItem)
End Function
''' <summary>
''' 将属性设置入一个现有的 ListItem。
''' </summary>
Public Function SetToListItem(Item As MyListItem) As MyListItem
Dim Logo As String
If IsEvent Then
If EventType = "弹出窗口" Then
Logo = PathImage & "Blocks/GrassPath.png"
Else
Logo = PathImage & "Blocks/CommandBlock.png"
End If
Else
Logo = PathImage & "Blocks/Grass.png"
End If
'设置属性
With Item
.SnapsToDevicePixels = True
.Title = Title
.Info = Desc
.Logo = If(Me.Logo, Logo)
.Height = 42
.Type = MyListItem.CheckType.Clickable
.Tag = Me
.EventType = Nothing
.EventData = Nothing
End With
'项目的点击事件
AddHandler Item.Click, Sub(sender, e) PageOtherHelp.OnItemClick(sender.Tag)
Return Item
End Function
End Class
Public HelpLoader As New LoaderTask(Of Integer, List(Of HelpEntry))("Help Page", AddressOf HelpLoad,, ThreadPriority.BelowNormal)
Private ReadOnly HelpLoadLock As New Object
''' <summary>
''' 初始化帮助列表对象。
''' </summary>
Private Sub HelpLoad(Loader As LoaderTask(Of Integer, List(Of HelpEntry)))
SyncLock HelpLoadLock '避免重复解压文件导致出错
Try
'解压内置文件
HelpTryExtract()
'遍历文件
Dim FileList As New List(Of String)
Try
Dim IgnoreList As New List(Of String)
'读取自定义文件
If Directory.Exists(Path & "PCL\Help\") Then
For Each File In EnumerateFiles(Path & "PCL\Help\")
Select Case File.Extension.ToLower
Case ".helpignore"
'加载忽略列表
Log("[Help] 发现 .helpignore 文件:" & File.FullName)
For Each Line In ReadFile(File.FullName).Split(vbCrLf.ToCharArray)
Dim RealString As String = Line.BeforeFirst("#").Trim
If String.IsNullOrWhiteSpace(RealString) Then Continue For
IgnoreList.Add(RealString)
If ModeDebug Then Log("[Help] > " & RealString)
Next
Case ".json"
FileList.Add(File.FullName)
End Select
Next
End If
Log("[Help] 已扫描 PCL 文件夹下的帮助文件,目前总计 " & FileList.Count & " 条")
'读取自带文件
For Each File In EnumerateFiles(PathTemp & "Help")
'跳过非 json 文件与以 . 开头的文件夹
If File.Extension.ToLower <> ".json" OrElse File.Directory.FullName.Replace(PathTemp & "Help", "").Contains("\.") Then Continue For
'检查忽略列表
Dim RealPath As String = File.FullName.Replace(PathTemp & "Help\", "")
For Each Ignore In IgnoreList
If RegexCheck(RealPath, Ignore) Then
If ModeDebug Then Log("[Help] 已忽略 " & RealPath & ":" & Ignore)
GoTo NextFile
End If
Next
FileList.Add(File.FullName)
NextFile:
Next
Log("[Help] 已扫描缓存文件夹下的帮助文件,目前总计 " & FileList.Count & " 条")
Catch ex As Exception
Log(ex, "检查帮助文件夹失败", LogLevel.Msgbox)
End Try
If Loader.IsAborted Then Return
'将文件实例化
Dim Dict As New List(Of HelpEntry)
For Each FilePath As String In FileList
Try
Dim Entry As New HelpEntry(FilePath)
Dict.Add(Entry)
If ModeDebug Then Log("[Help] 已加载的帮助条目:" & Entry.Title & " ← " & FilePath)
Catch ex As Exception
Log(ex, "初始化帮助条目失败(" & FilePath & ")", LogLevel.Msgbox)
End Try
Next
'回设
If Not Dict.Any() Then Throw New Exception("未找到可用的帮助;若不需要帮助页面,可以在 设置 → 个性化 → 功能隐藏 中将其隐藏")
If Loader.IsAborted Then Return
Loader.Output = Dict
Catch ex As Exception
Log(ex, "帮助列表初始化失败")
Throw
End Try
End SyncLock
End Sub
''' <summary>
''' 尝试解压内置帮助文件。
''' </summary>
Public Sub HelpTryExtract()
If Setup.Get("SystemHelpVersion") <> VersionCode OrElse Not File.Exists(PathTemp & "Help\启动器\备份设置.xaml") Then
DeleteDirectory(PathTemp & "Help")
Directory.CreateDirectory(PathTemp & "Help")
WriteFile(PathTemp & "Cache\Help.zip", GetResources("Help"))
ExtractFile(PathTemp & "Cache\Help.zip", PathTemp & "Help", Encoding.UTF8)
Setup.Set("SystemHelpVersion", VersionCode)
Log("[Help] 已解压内置帮助文件,目前状态:" & File.Exists(PathTemp & "Help\启动器\备份设置.xaml"), LogLevel.Debug)
End If
End Sub
''' <summary>
''' 对帮助文件约定的替换标记进行处理,如果遇到需要转义的字符会进行转义。
''' </summary>
Public Function HelpArgumentReplace(Xaml As String) As String
Dim Result = Xaml.Replace("{path}", EscapeXML(Path))
Result = Result.RegexReplaceEach("\{hint\}", Function() EscapeXML(PageOtherTest.GetRandomHint()))
Result = Result.RegexReplaceEach("\{cave\}", Function() EscapeXML(PageOtherTest.GetRandomCave()))
Return Result
End Function
#End Region
#Region "愚人节"
Public IsAprilEnabled As Boolean = Date.Now.Month = 4 AndAlso Date.Now.Day = 1
Public IsAprilGiveup As Boolean = False
Private AprilSpeed As New Vector(0, 0)
Private AprilIdieCount As Integer = 0, AprilMousePosLast As New Point(0, 0)
Private AprilDistance As Integer = 0
Private Sub TimerFool()
Try
If FrmLaunchLeft Is Nothing OrElse FrmLaunchLeft.AprilPosTrans Is Nothing OrElse FrmMain.lastMouseArg Is Nothing Then Return
If IsAprilGiveup OrElse FrmMain.PageCurrent <> FormMain.PageType.Launch OrElse AniControlEnabled <> 0 OrElse Not FrmLaunchLeft.BtnLaunch.IsLoaded Then Return
'计算是否空闲
Dim MousePos = FrmMain.lastMouseArg.GetPosition(FrmMain)
If MousePos = AprilMousePosLast Then
AprilIdieCount += 1
Else
AprilMousePosLast = MousePos
AprilIdieCount = 0
End If
'计算躲避移动
Dim Direction As Vector
Dim Distance As Double
Dim ButtonWidth = FrmLaunchLeft.BtnLaunch.ActualWidth / 2, ButtonHeight = FrmLaunchLeft.BtnLaunch.ActualHeight / 2
Dim Vec As Vector = FrmMain.lastMouseArg.GetPosition(FrmLaunchLeft.BtnLaunch) - New Vector(ButtonWidth, ButtonHeight)
Dim Dir As New Vector(Vec.X, Vec.Y)
Dir.Normalize()
Direction = -Dir
Distance = New Vector(Math.Max(0, Math.Abs(Vec.X) - ButtonWidth), Math.Max(0, Math.Abs(Vec.Y) - ButtonHeight)).Length
Dim BreathScale = Math.Sin(Timer150Count / 37.5 * Math.PI)
Dim Acc = Math.Max(0, BreathScale * 0.25 - 0.65 - Math.Log((Distance + 0.4) / 200)) * Direction '加速度
'计算回归移动
If AprilIdieCount >= 64 * 5 Then
Dim SafeDist As Vector = FrmMain.lastMouseArg.GetPosition(FrmMain.PanMain) - New Vector(ButtonWidth, FrmMain.PanMain.ActualHeight - ButtonHeight * 3)
Dim Back As New Vector(FrmLaunchLeft.AprilPosTrans.X, FrmLaunchLeft.AprilPosTrans.Y)
If SafeDist.Length > 250 AndAlso Back.Length > 0.4 Then
Acc -= Back * 0.0005
Back.Normalize()
Acc -= Back * 0.15
End If
End If
'回到边界
Dim Relative As Point = FrmLaunchLeft.BtnLaunch.TranslatePoint(New Point(0, 0), FrmMain.PanForm)
If Relative.X < -ButtonWidth * 2 Then
FrmLaunchLeft.AprilPosTrans.X += FrmMain.PanForm.ActualWidth + ButtonWidth * 2 '离开左边界
AprilSpeed.X -= 80
If Relative.Y < 0 Then
FrmLaunchLeft.AprilPosTrans.Y += ButtonHeight * 2.5
ElseIf Relative.Y > FrmMain.PanForm.ActualHeight - ButtonHeight * 2 Then
FrmLaunchLeft.AprilPosTrans.Y -= ButtonHeight * 2.5
End If
ElseIf Relative.X > FrmMain.PanForm.ActualWidth Then
FrmLaunchLeft.AprilPosTrans.X -= FrmMain.PanForm.ActualWidth + ButtonWidth * 2 '离开右边界
AprilSpeed.X += 80
If Relative.Y < 0 Then
FrmLaunchLeft.AprilPosTrans.Y += ButtonHeight * 2.5
ElseIf Relative.Y > FrmMain.PanForm.ActualHeight - ButtonHeight * 2 Then
FrmLaunchLeft.AprilPosTrans.Y -= ButtonHeight * 2.5
End If
ElseIf Relative.Y < -ButtonHeight * 2 Then
FrmLaunchLeft.AprilPosTrans.Y += FrmMain.PanForm.ActualHeight + ButtonHeight * 2 '离开上边界
AprilSpeed.Y -= 25
If Relative.X < 0 Then
FrmLaunchLeft.AprilPosTrans.X += ButtonWidth * 2
ElseIf Relative.X > FrmMain.PanForm.ActualWidth - ButtonWidth * 2 Then
FrmLaunchLeft.AprilPosTrans.X -= ButtonWidth * 2
End If
ElseIf Relative.Y > FrmMain.PanForm.ActualHeight Then
FrmLaunchLeft.AprilPosTrans.Y -= FrmMain.PanForm.ActualHeight + ButtonHeight * 2 '离开下边界
AprilSpeed.Y += 25
If Relative.X < 0 Then
FrmLaunchLeft.AprilPosTrans.X += ButtonWidth * 2
ElseIf Relative.X > FrmMain.PanForm.ActualWidth - ButtonWidth * 2 Then
FrmLaunchLeft.AprilPosTrans.X -= ButtonWidth * 2
End If
End If
'移动
AprilSpeed = AprilSpeed * 0.8 + Acc
Dim SpeedValue = Math.Min(60, AprilSpeed.Length)
If SpeedValue < 0.01 Then Return
AprilSpeed.Normalize()
AprilSpeed *= SpeedValue
AprilDistance += SpeedValue
FrmLaunchLeft.AprilPosTrans.X += AprilSpeed.X
FrmLaunchLeft.AprilPosTrans.Y += AprilSpeed.Y
'大小改变
FrmLaunchLeft.AprilScaleTrans.ScaleX = MathClamp(1 - (Math.Abs(Direction.X) - Math.Abs(Direction.Y)) * (SpeedValue / 160), 0.2, 1.8)
FrmLaunchLeft.AprilScaleTrans.ScaleY = MathClamp(1 - (Math.Abs(Direction.Y) - Math.Abs(Direction.X)) * (SpeedValue / 100), 0.2, 1.8)
'放弃提示
If AprilDistance > 4000 Then
AprilDistance = -4000
Select Case RandomInteger(0, 3)
Case 0
Hint("放弃吧!只需要点一下右下角的小白旗……")
Case 1
Hint("看到右下角的那面小白旗了吗?")
Case 2
Hint("这里建议点一下右下角的小白旗投降呢.jpg")
Case 3
Hint("右下角的小白旗永远等着你……")
End Select
End If
Catch ex As Exception
Log(ex, "愚人节移动出错", LogLevel.Feedback)
End Try
End Sub
#End Region
#Region "系统"
''' <summary>
''' 把某个 PCL 窗口拖到最前面。
''' </summary>
Public Sub ShowWindowToTop(Handle As IntPtr)
Try
PostMessage(Handle, 400 * 16 + 2, 0, 0)
SetForegroundWindow(Handle) '不在这里放不行,神秘 WinAPI,建议别动
Catch ex As Exception
Log(ex, "设置窗口置顶失败", LogLevel.Hint)
End Try
End Sub
Public Declare Function FindWindow Lib "user32" Alias "FindWindowA" (ClassName As String, WindowName As String) As IntPtr
Public Declare Function SetForegroundWindow Lib "user32" (hWnd As IntPtr) As Integer
Private Declare Function PostMessage Lib "user32" Alias "PostMessageA" (hWnd As IntPtr, msg As UInteger, wParam As Long, lParam As Long) As Boolean
''' <summary>
''' 将特定程序设置为使用高性能显卡启动。
''' 如果失败,则抛出异常。
''' </summary>
Public Sub SetGPUPreference(Executeable As String)
Const REG_KEY As String = "Software\Microsoft\DirectX\UserGpuPreferences"
Const REG_VALUE As String = "GpuPreference=2;"
'查看现有设置
Using ReadOnlyKey = My.Computer.Registry.CurrentUser.OpenSubKey(REG_KEY, False)
If ReadOnlyKey IsNot Nothing Then
Dim CurrentValue = ReadOnlyKey.GetValue(Executeable)
If REG_VALUE = CurrentValue?.ToString() Then
Log($"[System] 无需调整显卡设置:{Executeable}")
Return
End If
Else
'创建父级键
Log($"[System] 需要创建显卡设置的父级键")
My.Computer.Registry.CurrentUser.CreateSubKey(REG_KEY)
End If
End Using
'写入新设置
Using WriteKey = My.Computer.Registry.CurrentUser.OpenSubKey(REG_KEY, True)
WriteKey.SetValue(Executeable, REG_VALUE)
Log($"[System] 已调整显卡设置:{Executeable}")
End Using
End Sub
#End Region
#Region "任务缓存"
Private IsTaskTempCleared As Boolean = False
Private IsTaskTempClearing As Boolean = False
''' <summary>
''' 尝试清理任务缓存文件夹。
''' 在整次运行中只会实际清理一次。
''' </summary>
Public Sub TryClearTaskTemp()
If Not IsTaskTempCleared Then
IsTaskTempCleared = True
IsTaskTempClearing = True
Try
Log("[System] 开始清理任务缓存文件夹")
DeleteDirectory($"{OsDrive}ProgramData\PCL\TaskTemp\")
DeleteDirectory($"{PathTemp}TaskTemp\")
Log("[System] 已清理任务缓存文件夹")
Catch ex As Exception
Log(ex, "清理任务缓存文件夹失败")
Finally
IsTaskTempClearing = False
End Try
ElseIf IsTaskTempClearing Then
'等待另一个清理步骤完成
Do While IsTaskTempClearing
Thread.Sleep(1)
Loop
End If
End Sub
''' <summary>
''' 申请一个可用于任务缓存的临时文件夹,以 \ 结尾。这些文件夹无需进行后续清理。
''' 若所有缓存位置均没有权限,会抛出异常。
''' </summary>
''' <param name="RequireNonSpace">是否要求路径不包含空格。</param>
Public Function RequestTaskTempFolder(Optional RequireNonSpace As Boolean = False) As String
TryClearTaskTemp()
Dim ResultFolder As String
Try
ResultFolder = $"{PathTemp}TaskTemp\{GetUuid()}-{RandomInteger(0, 1000000)}\"
If RequireNonSpace AndAlso ResultFolder.Contains(" ") Then Exit Try '带空格
Directory.CreateDirectory(ResultFolder)
CheckPermissionWithException(ResultFolder)
Return ResultFolder
Catch
End Try
'使用备用路径
ResultFolder = $"{OsDrive}ProgramData\PCL\TaskTemp\{GetUuid()}-{RandomInteger(0, 1000000)}\"
Directory.CreateDirectory(ResultFolder)
CheckPermission(ResultFolder)
Return ResultFolder
End Function
#End Region
Public DragControl = Nothing
Private Timer4Count As Integer = 0
Private Timer150Count As Integer = 0
Private Sub TimerMain()
Try
#Region "每 50ms 执行一次的代码"
HintTick()
MyMsgBoxTick()
FrmMain.DragTick()
LoaderTaskbarProgressRefresh()
If ThemeDontClick = 2 Then ThemeRefresh()
#End Region
Catch ex As Exception
Log(ex, "短程主时钟执行异常", LogLevel.Critical)
End Try
Timer4Count += 1
If Timer4Count = 4 Then
Timer4Count = 0
Try
#Region "每 250ms 执行一次的代码"
If ThemeNow = 12 Then ThemeRefresh()
#End Region
Catch ex As Exception
Log(ex, "中程主时钟执行异常", LogLevel.Debug)
End Try
End If
Timer150Count += 1
If Timer150Count = 150 Then
Timer150Count = 0
Try
#Region "每 7.5s 执行一次的代码"
If FrmMain.BtnExtraApril_ShowCheck AndAlso AprilDistance <> 0 Then FrmMain.BtnExtraApril.Ribble()
'以未知原因窗口被丢到一边去的修复(Top、Left = -25600),还有 #745
RunInUi(
Sub()
If Not FrmMain.Hidden Then
If FrmMain.Top < -9000 Then FrmMain.Top = 100
If FrmMain.Left < -9000 Then FrmMain.Left = 100 '窗口拉至最大时 Left = -18.8
End If
End Sub)
#End Region
Catch ex As Exception
Log(ex, "长程主时钟执行异常", LogLevel.Critical)
End Try
End If
End Sub
Public Sub TimerMainStart()
RunInNewThread(
Sub()
Try
Do While True
RunInUiWait(AddressOf TimerMain)
Thread.Sleep(50 * 0.98)
Loop
Catch ex As Exception
Log(ex, "程序主时钟出错", LogLevel.Feedback)
End Try
End Sub, "Timer Main")
If Not IsAprilEnabled Then Return
RunInNewThread(
Sub()
Try
Dim LastTime = My.Computer.Clock.TickCount
Do While True
If LastTime <> My.Computer.Clock.TickCount Then
LastTime = My.Computer.Clock.TickCount
RunInUiWait(AddressOf TimerFool)
End If
Thread.Sleep(1)
Loop
Catch ex As Exception
Log(ex, "愚人节主时钟出错", LogLevel.Feedback)
End Try
End Sub, "Timer Main Fool")
End Sub
End Module
+138 -85
View File
@@ -5,7 +5,7 @@
''' <summary>
''' 接下来要播放的音乐文件路径。未初始化时为 Nothing。
''' </summary>
Public MusicToplayList As List(Of String) = Nothing
Public MusicWaitingList As List(Of String) = Nothing
''' <summary>
''' 全部音乐文件路径。未初始化时为 Nothing。
''' </summary>
@@ -14,28 +14,27 @@
''' 初始化音乐播放列表。
''' </summary>
''' <param name="ForceReload">强制全部重新载入列表。</param>
''' <param name="IgnoreFirst">在重载列表时避免让某项成为第一项。</param>
Private Sub MusicListInit(ForceReload As Boolean, Optional IgnoreFirst As String = "")
''' <param name="PreventFirst">在重载列表时避免让某项成为第一项。</param>
Private Sub MusicListInit(ForceReload As Boolean, Optional PreventFirst As String = Nothing)
If ForceReload Then MusicAllList = Nothing
Try
'初始化全部可用音乐列表
If MusicAllList Is Nothing Then
MusicAllList = New List(Of String)
Directory.CreateDirectory(Path & "PCL\Musics\")
For Each File In My.Computer.FileSystem.GetFiles(Path & "PCL\Musics\", FileIO.SearchOption.SearchAllSubDirectories, "*.*")
For Each File In EnumerateFiles(Path & "PCL\Musics\")
'文件夹可能会被加入 .ini 文件夹配置文件、一些乱七八糟的 .jpg 文件啥的
Dim Extend As String = File.Split(".").Last.ToLower
If Not (Extend = "ini" OrElse Extend = "jpg" OrElse Extend = "txt" OrElse Extend = "cfg" OrElse Extend = "png") Then
MusicAllList.Add(File)
End If
Dim Ext As String = File.Extension.ToLower
If {".ini", ".jpg", ".txt", ".cfg", ".lrc", ".db", ".png"}.Contains(Ext) Then Continue For
MusicAllList.Add(File.FullName)
Next
End If
'打乱顺序播放
MusicToplayList = RandomChaos(New List(Of String)(MusicAllList))
If Not IgnoreFirst = "" AndAlso Not MusicToplayList.Count = 0 AndAlso MusicToplayList(0) = IgnoreFirst Then
MusicWaitingList = If(Setup.Get("UiMusicRandom"), Shuffle(New List(Of String)(MusicAllList)), New List(Of String)(MusicAllList))
If PreventFirst IsNot Nothing AndAlso MusicWaitingList.FirstOrDefault = PreventFirst Then
'若需要避免成为第一项的为第一项,则将它放在最后
MusicToplayList.RemoveAt(0)
MusicToplayList.Add(IgnoreFirst)
MusicWaitingList.RemoveAt(0)
MusicWaitingList.Add(PreventFirst)
End If
Catch ex As Exception
Log(ex, "初始化音乐列表失败", LogLevel.Feedback)
@@ -43,15 +42,19 @@
End Sub
''' <summary>
''' 获取下一首播放的音乐路径并将其从列表中移除。
''' 如果没有,可能会返回 Nothing。
''' </summary>
Private Function DequeueNextMusicAddress() As String
'初始化,确保存在音乐
If MusicAllList Is Nothing Then MusicListInit(False)
If MusicAllList.Count = 0 Then Throw New Exception("在没有音乐时尝试获取音乐路径")
If MusicAllList Is Nothing OrElse Not MusicAllList.Any() OrElse Not MusicWaitingList.Any() Then MusicListInit(False)
'出列下一个音乐,如果出列结束则生成新列表
DequeueNextMusicAddress = MusicToplayList(0)
MusicToplayList.RemoveAt(0)
If MusicToplayList.Count = 0 Then MusicListInit(False, DequeueNextMusicAddress)
If MusicWaitingList.Any() Then
DequeueNextMusicAddress = MusicWaitingList(0)
MusicWaitingList.RemoveAt(0)
Else
DequeueNextMusicAddress = Nothing
End If
If Not MusicWaitingList.Any() Then MusicListInit(False, DequeueNextMusicAddress)
End Function
#End Region
@@ -62,35 +65,45 @@
''' 刷新背景音乐按钮 UI 与设置页 UI。
''' </summary>
Private Sub MusicRefreshUI()
RunInUi(Sub()
Try
RunInUi(
Sub()
Try
If MusicAllList.Count = 0 Then
'无背景音乐
FrmMain.BtnExtraMusic.Show = False
If Not MusicAllList.Any() Then
'无背景音乐
FrmMain.BtnExtraMusic.Show = False
Else
'有背景音乐
FrmMain.BtnExtraMusic.Show = True
Dim ToolTipText As String
If MusicState = MusicStates.Pause Then
FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
FrmMain.BtnExtraMusic.LogoScale = 0.8
ToolTipText = "已暂停:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
If MusicAllList.Count > 1 Then
ToolTipText += vbCrLf & "左键恢复播放,右键播放下一曲。"
Else
'有背景音乐
FrmMain.BtnExtraMusic.Show = True
Dim ToolTipText As String = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
If MusicState = MusicStates.Pause Then
FrmMain.BtnExtraMusic.Logo = Logo.IconPlay
FrmMain.BtnExtraMusic.LogoScale = 0.8
If MusicAllList.Count > 1 Then ToolTipText += vbCrLf & "左键播放,右键播放下一曲。"
Else
FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
FrmMain.BtnExtraMusic.LogoScale = 1
If MusicAllList.Count > 1 Then ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
End If
FrmMain.BtnExtraMusic.ToolTip = ToolTipText
ToolTipService.SetVerticalOffset(FrmMain.BtnExtraMusic, If(ToolTipText.Contains(vbLf), 10, 16))
ToolTipText += vbCrLf & "左键恢复播放,右键重新从头播放。"
End If
If FrmSetupUI IsNot Nothing Then FrmSetupUI.MusicRefreshUI()
Else
FrmMain.BtnExtraMusic.Logo = Logo.IconMusic
FrmMain.BtnExtraMusic.LogoScale = 1
ToolTipText = "正在播放:" & GetFileNameWithoutExtentionFromPath(MusicCurrent)
If MusicAllList.Count > 1 Then
ToolTipText += vbCrLf & "左键暂停,右键播放下一曲。"
Else
ToolTipText += vbCrLf & "左键暂停,右键重新从头播放。"
End If
End If
FrmMain.BtnExtraMusic.ToolTip = ToolTipText
ToolTipService.SetVerticalOffset(FrmMain.BtnExtraMusic, If(ToolTipText.Contains(vbLf), 10, 16))
End If
If FrmSetupUI IsNot Nothing Then FrmSetupUI.MusicRefreshUI()
Catch ex As Exception
Log(ex, "刷新背景音乐 UI 失败", LogLevel.Feedback)
End Try
End Sub)
Catch ex As Exception
Log(ex, "刷新背景音乐 UI 失败", LogLevel.Feedback)
End Try
End Sub)
End Sub
''' <summary>
@@ -106,7 +119,8 @@
Case MusicStates.Play
MusicPause()
Case Else
Hint("音乐目前为停止状态!", HintType.Critical)
Log("[Music] 音乐目前为停止状态,已强制尝试开始播放", LogLevel.Debug)
MusicRefreshPlay(False)
End Select
End If
End Sub
@@ -116,13 +130,18 @@
''' </summary>
Public Sub MusicControlNext()
If MusicAllList.Count = 1 Then
Hint("播放列表中仅有一首歌曲!")
MusicStartPlay(MusicCurrent)
Hint("重新播放:" & GetFileNameFromPath(MusicCurrent), HintType.Finish)
Else
Dim Address As String = DequeueNextMusicAddress()
MusicStartPlay(Address)
Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish)
MusicRefreshUI()
If Address Is Nothing Then
Hint("没有可以播放的音乐!", HintType.Critical)
Else
MusicStartPlay(Address)
Hint("正在播放:" & GetFileNameFromPath(Address), HintType.Finish)
End If
End If
MusicRefreshUI()
End Sub
#End Region
@@ -161,7 +180,7 @@
Try
MusicListInit(True)
If MusicAllList.Count = 0 Then
If Not MusicAllList.Any() Then
If MusicNAudio Is Nothing Then
If ShowHint Then Hint("未检测到可用的背景音乐!", HintType.Critical)
Else
@@ -170,11 +189,15 @@
End If
Else
Dim Address As String = DequeueNextMusicAddress()
Try
MusicStartPlay(Address, IsFirstLoad)
If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False)
Catch
End Try
If Address Is Nothing Then
If ShowHint Then Hint("没有可以播放的音乐!", HintType.Critical)
Else
Try
MusicStartPlay(Address, IsFirstLoad)
If ShowHint Then Hint("背景音乐已刷新:" & GetFileNameFromPath(Address), HintType.Finish, False)
Catch
End Try
End If
End If
MusicRefreshUI()
@@ -186,8 +209,10 @@
''' 开始播放音乐。
''' </summary>
Private Sub MusicStartPlay(Address As String, Optional IsFirstLoad As Boolean = False)
If Address Is Nothing Then Return
Log("[Music] 播放开始:" & Address)
RunInNewThread(Sub() MusicLoop(Address, IsFirstLoad), "Music", ThreadPriority.BelowNormal)
MusicCurrent = Address
RunInNewThread(Sub() MusicLoop(IsFirstLoad), "Music", ThreadPriority.BelowNormal)
End Sub
'播放与暂停
@@ -197,13 +222,15 @@
''' </summary>
Public Function MusicPause() As Boolean
If MusicState = MusicStates.Play Then
RunInThread(Sub()
MusicNAudio.Pause()
MusicRefreshUI()
Log("[Music] 已暂停播放")
End Sub)
RunInThread(
Sub()
Log("[Music] 已暂停播放")
MusicNAudio?.Pause()
MusicRefreshUI()
End Sub)
Return True
Else
Log($"[Music] 无需暂停播放,当前状态为 {MusicState}")
Return False
End If
End Function
@@ -211,22 +238,29 @@
''' 继续音乐播放,返回是否成功切换了状态。
''' </summary>
Public Function MusicResume() As Boolean
If MusicState = MusicStates.Pause Then
RunInThread(Sub()
MusicNAudio.Play()
MusicRefreshUI()
Log("[Music] 已恢复播放")
End Sub)
Return True
Else
If MusicState = MusicStates.Play OrElse Not MusicAllList.Any() Then
Log($"[Music] 无需继续播放,当前状态为 {MusicState}")
Return False
Else
RunInThread(
Sub()
Log("[Music] 已恢复播放")
Try
MusicNAudio?.Play()
Catch 'https://github.com/Meloong-Git/PCL/pull/5415#issuecomment-2751135223
MusicNAudio?.Stop()
MusicNAudio?.Play()
End Try
MusicRefreshUI()
End Sub)
Return True
End If
End Function
#End Region
''' <summary>
''' 当前正在播放的 NAudio.Wave.WaveOut。
''' 当前正在播放的 NAudio.Wave.WaveOutEvent。
''' </summary>
Public MusicNAudio = Nothing
''' <summary>
@@ -237,15 +271,15 @@
''' <summary>
''' 在 MusicUuid 不变的前提下,持续播放某地址的音乐,且在播放结束后随机播放下一曲。
''' </summary>
Private Sub MusicLoop(Address As String, Optional IsFirstLoad As Boolean = False)
MusicCurrent = Address
Dim CurrentWave As NAudio.Wave.WaveOut = Nothing
Private Sub MusicLoop(Optional IsFirstLoad As Boolean = False)
Dim CurrentWave As NAudio.Wave.WaveOutEvent = Nothing
Dim Reader As NAudio.Wave.WaveStream = Nothing
Try
'开始播放
CurrentWave = New NAudio.Wave.WaveOut()
CurrentWave = New NAudio.Wave.WaveOutEvent()
MusicNAudio = CurrentWave
Reader = New NAudio.Wave.AudioFileReader(Address)
CurrentWave.DeviceNumber = -1
Reader = New NAudio.Wave.AudioFileReader(MusicCurrent)
CurrentWave.Init(Reader)
CurrentWave.Play()
'第一次打开的暂停
@@ -259,22 +293,41 @@
PreviousVolume = Setup.Get("UiMusicVolume")
CurrentWave.Volume = PreviousVolume / 1000
End If
Thread.Sleep(50)
'更新进度条
Dim Percent = Reader.CurrentTime.TotalMilliseconds / Reader.TotalTime.TotalMilliseconds
RunInUi(Sub() FrmMain.BtnExtraMusic.Progress = Percent)
Thread.Sleep(100)
End While
'当前音乐已播放结束,继续下一曲
If CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped AndAlso MusicAllList.Count > 0 Then MusicStartPlay(DequeueNextMusicAddress)
If CurrentWave.PlaybackState = NAudio.Wave.PlaybackState.Stopped AndAlso MusicAllList.Any Then MusicStartPlay(DequeueNextMusicAddress)
Catch ex As Exception
If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then
Hint("播放音乐失败(" & GetFileNameFromPath(Address) & "):PCL2 不支持播放音频属性在中途发生变化的音乐", HintType.Critical)
ElseIf Not (Address.ToLower.EndsWith(".wav") OrElse Address.ToLower.EndsWith(".mp3") OrElse Address.ToLower.EndsWith(".flac")) Then
Hint("播放音乐失败(" & GetFileNameFromPath(Address) & "):PCL2 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Critical)
Else
Log(ex, "播放音乐失败(" & GetFileNameFromPath(Address) & ")", LogLevel.Hint)
Log(ex, "播放音乐出现内部错误(" & MusicCurrent & ")", LogLevel.Developer)
If TypeOf ex Is NAudio.MmException AndAlso ex.Message.Contains("AlreadyAllocated") Then
Hint("你的音频设备正被其他程序占用。请在关闭占用的程序后重启 PCL,才能恢复音乐播放功能!", HintType.Critical)
Thread.Sleep(1000000000)
End If
Log(ex, "播放音乐失败(" & Address & ")", LogLevel.Developer)
If MusicAllList.Count > 1 Then
Thread.Sleep(1000)
MusicStartPlay(DequeueNextMusicAddress)
If TypeOf ex Is NAudio.MmException AndAlso (ex.Message.Contains("NoDriver") OrElse ex.Message.Contains("BadDeviceId")) Then
Hint("由于音频设备变更,音乐播放功能在重启 PCL 后才能恢复!", HintType.Critical)
Thread.Sleep(1000000000)
End If
If ex.Message.Contains("Got a frame at sample rate") OrElse ex.Message.Contains("does not support changes to") Then
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 不支持播放音频属性在中途发生变化的音乐", HintType.Critical)
ElseIf Not (MusicCurrent.EndsWithF(".wav", True) OrElse MusicCurrent.EndsWithF(".mp3", True) OrElse MusicCurrent.EndsWithF(".flac", True)) OrElse
ex.Message.Contains("0xC00D36C4") Then '#5096:不支持给定的 URL 的字节流类型。 (异常来自 HRESULT:0xC00D36C4)
Hint("播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & "):PCL 可能不支持此音乐格式,请将格式转换为 .wav、.mp3 或 .flac 后再试", HintType.Critical)
Else
Log(ex, "播放音乐失败(" & GetFileNameFromPath(MusicCurrent) & ")", LogLevel.Hint)
End If
'将播放错误的音乐从列表中移除
MusicAllList.Remove(MusicCurrent)
MusicWaitingList.Remove(MusicCurrent)
MusicRefreshUI()
'等待 2 秒后继续播放
Thread.Sleep(2000)
If TypeOf ex Is FileNotFoundException Then
MusicRefreshPlay(True, IsFirstLoad)
Else
MusicStartPlay(DequeueNextMusicAddress(), IsFirstLoad)
End If
Finally
If CurrentWave IsNot Nothing Then CurrentWave.Dispose()
+284
View File
@@ -0,0 +1,284 @@
'由于包含加解密等安全信息,本文件中的部分代码已被删除
Imports System.Security.Cryptography
Friend Module ModSecret
#Region "杂项"
'在开源版的注册表与常规版的注册表隔离,以防数据冲突
Public Const RegFolder As String = "PCLDebug"
'用于微软登录的 ClientId
Public OAuthClientId As String = If(Environment.GetEnvironmentVariable("PCL_MS_CLIENT_ID"), "")
'CurseForge API Key
Public CurseForgeAPIKey As String = If(Environment.GetEnvironmentVariable("PCL_CURSEFORGE_API_KEY"), "")
Friend Sub SecretOnApplicationStart()
'提升 UI 线程优先级
Thread.CurrentThread.Priority = ThreadPriority.Highest
'确保 .NET Framework 版本
Try
Dim VersionTest As New FormattedText("", Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Fonts.SystemTypefaces.First, 96, New MyColor, DPI)
Catch ex As UriFormatException '修复 #3555
Environment.SetEnvironmentVariable("windir", Environment.GetEnvironmentVariable("SystemRoot"), EnvironmentVariableTarget.User)
Dim VersionTest As New FormattedText("", Globalization.CultureInfo.CurrentCulture, FlowDirection.LeftToRight, Fonts.SystemTypefaces.First, 96, New MyColor, DPI)
End Try
'检测当前文件夹权限
Try
Directory.CreateDirectory(Path & "PCL")
Catch ex As Exception
MsgBox($"PCL 无法创建 PCL 文件夹({Path & "PCL"}),请尝试:" & vbCrLf &
"1. 将 PCL 移动到其他文件夹" & If(Path.StartsWithF("C:", True), ",例如 C 盘和桌面以外的其他位置。", "。") & vbCrLf &
"2. 删除当前目录中的 PCL 文件夹,然后再试。" & vbCrLf &
"3. 右键 PCL 选择属性,打开 兼容性 中的 以管理员身份运行此程序。",
MsgBoxStyle.Critical, "运行环境错误")
Environment.[Exit](ProcessReturnValues.Cancel)
End Try
If Not CheckPermission(Path & "PCL") Then
MsgBox("PCL 没有对当前文件夹的写入权限,请尝试:" & vbCrLf &
"1. 将 PCL 移动到其他文件夹" & If(Path.StartsWithF("C:", True), ",例如 C 盘和桌面以外的其他位置。", "。") & vbCrLf &
"2. 删除当前目录中的 PCL 文件夹,然后再试。" & vbCrLf &
"3. 右键 PCL 选择属性,打开 兼容性 中的 以管理员身份运行此程序。",
MsgBoxStyle.Critical, "运行环境错误")
Environment.[Exit](ProcessReturnValues.Cancel)
End If
'开源版本提示
MyMsgBox($"该版本中无法使用以下特性:
- CurseForge API 调用:需要你自行申请 API Key,然后添加到 ModSecret.vb 的开头
- 正版登录:需要你自行申请 Client ID,然后添加到 ModSecret.vb 的开头
- 更新与联网通知:避免滥用隐患
- 主题切换:这是需要赞助解锁的纪念性质的功能,别让赞助者太伤心啦……
- 百宝箱:开发早期往里面塞了些开发工具,整理起来太麻烦了", "开源版本说明")
End Sub
''' <summary>
''' 获取设备标识码。
''' </summary>
Friend Function SecretGetUniqueAddress() As String
Return "0000-0000-0000-0000"
End Function
Friend Sub SecretLaunchJvmArgs(ByRef DataList As List(Of String))
Dim DataJvmCustom As String = Setup.Get("VersionAdvanceJvm", Version:=McVersionCurrent)
DataList.Insert(0, If(DataJvmCustom = "", Setup.Get("LaunchAdvanceJvm"), DataJvmCustom)) '可变 JVM 参数
McLaunchLog("当前剩余内存:" & Math.Round(My.Computer.Info.AvailablePhysicalMemory / 1024 / 1024 / 1024 * 10) / 10 & "G")
DataList.Add("-Xmn" & Math.Floor(PageVersionSetup.GetRam(McVersionCurrent) * 1024 * 0.15) & "m")
DataList.Add("-Xmx" & Math.Floor(PageVersionSetup.GetRam(McVersionCurrent) * 1024) & "m")
If Not DataList.Any(Function(d) d.Contains("-Dlog4j2.formatMsgNoLookups=true")) Then DataList.Add("-Dlog4j2.formatMsgNoLookups=true")
End Sub
#End Region
#Region "网络鉴权"
Friend Function SecretCdnSign(UrlWithMark As String) As String
If Not UrlWithMark.EndsWithF("{CDN}") Then Return UrlWithMark
Return UrlWithMark.Replace("{CDN}", "").Replace(" ", "%20")
End Function
''' <summary>
''' 设置 Headers 的 UA、Referer。
''' </summary>
Friend Sub SecretHeadersSign(Url As String, ByRef Req As HttpRequestMessage, Optional UseBrowserUserAgent As Boolean = False)
If Url.Contains("baidupcs.com") OrElse Url.Contains("baidu.com") Then
Req.Headers.Add("User-Agent", "LogStatistic") '#4951
ElseIf UseBrowserUserAgent Then
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode} Mozilla/5.0 AppleWebKit/537.36 Chrome/63.0.3239.132 Safari/537.36")
Else
Req.Headers.Add("User-Agent", $"PCL2/{VersionStandardCode}")
End If
Req.Headers.Add("Referer", $"http://{VersionCode}.open.pcl2.server/")
If Url.Contains("api.curseforge.com") Then Req.Headers.Add("x-api-key", CurseForgeAPIKey)
End Sub
#End Region
#Region "字符串加解密"
''' <summary>
''' 获取八位密钥。
''' </summary>
Private Function SecretKeyGet(Key As String) As String
Return "00000000"
End Function
''' <summary>
''' 加密字符串。
''' </summary>
Friend Function SecretEncrypt(SourceString As String, Optional Key As String = "") As String
Key = SecretKeyGet(Key)
Dim btKey As Byte() = Encoding.UTF8.GetBytes(Key)
Dim btIV As Byte() = Encoding.UTF8.GetBytes("87160295")
Dim des As New DESCryptoServiceProvider
Using MS As New MemoryStream
Dim inData As Byte() = Encoding.UTF8.GetBytes(SourceString)
Using cs As New CryptoStream(MS, des.CreateEncryptor(btKey, btIV), CryptoStreamMode.Write)
cs.Write(inData, 0, inData.Length)
cs.FlushFinalBlock()
Return Convert.ToBase64String(MS.ToArray())
End Using
End Using
End Function
''' <summary>
''' 解密字符串。
''' </summary>
Friend Function SecretDecrypt(SourceString As String, Optional Key As String = "") As String
Key = SecretKeyGet(Key)
Dim btKey As Byte() = Encoding.UTF8.GetBytes(Key)
Dim btIV As Byte() = Encoding.UTF8.GetBytes("87160295")
Dim des As New DESCryptoServiceProvider
Using MS As New MemoryStream
Dim inData As Byte() = Convert.FromBase64String(SourceString)
Using cs As New CryptoStream(MS, des.CreateDecryptor(btKey, btIV), CryptoStreamMode.Write)
cs.Write(inData, 0, inData.Length)
cs.FlushFinalBlock()
Return Encoding.UTF8.GetString(MS.ToArray())
End Using
End Using
End Function
#End Region
#Region "主题"
Public Color1 As New MyColor(52, 61, 74)
Public Color2 As New MyColor(11, 91, 203)
Public Color3 As New MyColor(19, 112, 243)
Public Color4 As New MyColor(72, 144, 245)
Public Color5 As New MyColor(150, 192, 249)
Public Color6 As New MyColor(213, 230, 253)
Public Color7 As New MyColor(222, 236, 253)
Public Color8 As New MyColor(234, 242, 254)
Public ColorBg0 As New MyColor(150, 192, 249)
Public ColorBg1 As New MyColor(190, Color7)
Public ColorGray1 As New MyColor(64, 64, 64)
Public ColorGray2 As New MyColor(115, 115, 115)
Public ColorGray3 As New MyColor(140, 140, 140)
Public ColorGray4 As New MyColor(166, 166, 166)
Public ColorGray5 As New MyColor(204, 204, 204)
Public ColorGray6 As New MyColor(235, 235, 235)
Public ColorGray7 As New MyColor(240, 240, 240)
Public ColorGray8 As New MyColor(245, 245, 245)
Public ColorSemiTransparent As New MyColor(1, Color8)
Public ThemeNow As Integer = -1
Public ColorHue As Integer = 210, ColorSat As Integer = 85, ColorLightAdjust As Integer = 0, ColorHueTopbarDelta As Object = 0
Public ThemeDontClick As Integer = 0
Public Sub ThemeRefresh(Optional NewTheme As Integer = -1)
Try
If ThemeNow = NewTheme AndAlso NewTheme >= 0 Then Return
If NewTheme >= 0 Then ThemeNow = NewTheme
Color1 = New MyColor().FromHSL2(ColorHue, ColorSat * 0.2, 25 + ColorLightAdjust * 0.3)
Color2 = New MyColor().FromHSL2(ColorHue, ColorSat, 45 + ColorLightAdjust)
Color3 = New MyColor().FromHSL2(ColorHue, ColorSat, 55 + ColorLightAdjust)
Color4 = New MyColor().FromHSL2(ColorHue, ColorSat, 65 + ColorLightAdjust)
Color5 = New MyColor().FromHSL2(ColorHue, ColorSat, 80 + ColorLightAdjust * 0.4)
Color6 = New MyColor().FromHSL2(ColorHue, ColorSat, 91 + ColorLightAdjust * 0.1)
Color7 = New MyColor().FromHSL2(ColorHue, ColorSat, 95)
Color8 = New MyColor().FromHSL2(ColorHue, ColorSat, 97)
ColorBg0 = Color4 * 0.4 + Color5 * 0.4 + ColorGray4 * 0.2
ColorBg1 = New MyColor(190, Color7)
ColorSemiTransparent = New MyColor(1, Color8)
Application.Current.Resources("ColorBrush1") = New SolidColorBrush(Color1)
Application.Current.Resources("ColorBrush2") = New SolidColorBrush(Color2)
Application.Current.Resources("ColorBrush3") = New SolidColorBrush(Color3)
Application.Current.Resources("ColorBrush4") = New SolidColorBrush(Color4)
Application.Current.Resources("ColorBrush5") = New SolidColorBrush(Color5)
Application.Current.Resources("ColorBrush6") = New SolidColorBrush(Color6)
Application.Current.Resources("ColorBrush7") = New SolidColorBrush(Color7)
Application.Current.Resources("ColorBrush8") = New SolidColorBrush(Color8)
Application.Current.Resources("ColorBrushBg0") = New SolidColorBrush(ColorBg0)
Application.Current.Resources("ColorBrushBg1") = New SolidColorBrush(ColorBg1)
Application.Current.Resources("ColorObject1") = CType(Color1, Color)
Application.Current.Resources("ColorObject2") = CType(Color2, Color)
Application.Current.Resources("ColorObject3") = CType(Color3, Color)
Application.Current.Resources("ColorObject4") = CType(Color4, Color)
Application.Current.Resources("ColorObject5") = CType(Color5, Color)
Application.Current.Resources("ColorObject6") = CType(Color6, Color)
Application.Current.Resources("ColorObject7") = CType(Color7, Color)
Application.Current.Resources("ColorObject8") = CType(Color8, Color)
Application.Current.Resources("ColorObjectBg0") = CType(ColorBg0, Color)
Application.Current.Resources("ColorObjectBg1") = CType(ColorBg1, Color)
ThemeRefreshMain()
Catch ex As Exception
Log(ex, "刷新主题颜色失败", LogLevel.Hint)
End Try
End Sub
Public Sub ThemeRefreshMain()
RunInUi(
Sub()
If Not FrmMain.IsLoaded Then Return
'顶部条背景
Dim Brush = New LinearGradientBrush With {.EndPoint = New Point(1, 0), .StartPoint = New Point(0, 0)}
If TypeOf ColorHueTopbarDelta Is Integer Then
Brush.GradientStops.Add(New GradientStop With {.Offset = 0, .Color = New MyColor().FromHSL2(ColorHue - ColorHueTopbarDelta, ColorSat, 48 + ColorLightAdjust)})
Brush.GradientStops.Add(New GradientStop With {.Offset = 0.5, .Color = New MyColor().FromHSL2(ColorHue, ColorSat, 54 + ColorLightAdjust)})
Brush.GradientStops.Add(New GradientStop With {.Offset = 1, .Color = New MyColor().FromHSL2(ColorHue + ColorHueTopbarDelta, ColorSat, 48 + ColorLightAdjust)})
Else
Brush.GradientStops.Add(New GradientStop With {.Offset = 0, .Color = New MyColor().FromHSL2(ColorHue + ColorHueTopbarDelta(0), ColorSat, 48 + ColorLightAdjust)})
Brush.GradientStops.Add(New GradientStop With {.Offset = 0.5, .Color = New MyColor().FromHSL2(ColorHue + ColorHueTopbarDelta(1), ColorSat, 54 + ColorLightAdjust)})
Brush.GradientStops.Add(New GradientStop With {.Offset = 1, .Color = New MyColor().FromHSL2(ColorHue + ColorHueTopbarDelta(2), ColorSat, 48 + ColorLightAdjust)})
End If
FrmMain.PanTitle.Background = Brush
FrmMain.PanTitle.Background.Freeze()
'主页面背景
If Setup.Get("UiBackgroundColorful") Then
Brush = New LinearGradientBrush With {.EndPoint = New Point(0.1, 1), .StartPoint = New Point(0.9, 0)}
Brush.GradientStops.Add(New GradientStop With {.Offset = -0.1, .Color = New MyColor().FromHSL2(ColorHue - 15, ColorSat * 0.8, 91)})
Brush.GradientStops.Add(New GradientStop With {.Offset = 0.4, .Color = New MyColor().FromHSL2(ColorHue, ColorSat * 0.8, 91)})
Brush.GradientStops.Add(New GradientStop With {.Offset = 1.1, .Color = New MyColor().FromHSL2(ColorHue + 15, ColorSat * 0.8, 91)})
FrmMain.PanForm.Background = Brush
Else
FrmMain.PanForm.Background = New MyColor(245, 245, 245)
End If
FrmMain.PanForm.Background.Freeze()
End Sub)
End Sub
Friend Sub ThemeCheckAll(EffectSetup As Boolean)
End Sub
Friend Function ThemeCheckOne(Id As Integer) As Boolean
Return True
End Function
Friend Function ThemeUnlock(Id As Integer, Optional ShowDoubleHint As Boolean = True, Optional UnlockHint As String = Nothing) As Boolean
Return False
End Function
Friend Function ThemeCheckGold(Optional Code As String = Nothing) As Boolean
Return False
End Function
Friend Function DonateCodeInput() As Boolean?
Return Nothing
End Function
#End Region
#Region "更新"
Public IsUpdateStarted As Boolean = False
Public IsUpdateWaitingRestart As Boolean = False
Public Sub UpdateCheckByButton()
Hint("该版本中不包含更新功能……")
End Sub
Public Sub UpdateStart(BaseUrl As String, Slient As Boolean, Optional ReceivedKey As String = Nothing, Optional ForceValidated As Boolean = False)
End Sub
Public Sub UpdateRestart(TriggerRestartAndByEnd As Boolean)
End Sub
Public Sub UpdateReplace(ProcessId As Integer, OldFileName As String, NewFileName As String, TriggerRestart As Boolean)
End Sub
''' <summary>
''' 确保 PathTemp 下的 Latest.exe 是最新正式版的 PCL,它会被用于整合包打包。
''' 如果不是,则下载一个。
''' </summary>
Friend Sub DownloadLatestPCL(Optional LoaderToSyncProgress As LoaderBase = Nothing)
'注意:如果要自行实现这个功能,请换用另一个文件路径,以免与官方版本冲突
End Sub
#End Region
#Region "联网通知"
Public ServerLoader As New LoaderTask(Of Integer, Integer)("PCL 服务", Sub() Log("[Server] 该版本中不包含更新通知功能……"), Priority:=ThreadPriority.BelowNormal)
#End Region
End Module
@@ -1,59 +0,0 @@
Imports System.Net
Public Class CookieWebClient
Inherits WebClient
Public Sub New(container As CookieContainer, Headers As Dictionary(Of String, String))
Me.New(container)
For Each keyVal In Headers
Me.Headers(keyVal.Key) = keyVal.Value
Next
End Sub
Public Sub New()
Me.New(New CookieContainer())
End Sub
Public Sub New(container As CookieContainer)
Me.container = container
End Sub
Private Shadows ReadOnly container As New CookieContainer()
''' <summary>
''' 以毫秒为单位的超时。
''' </summary>
Public Timeout As Integer = 600000
Protected Overrides Function GetWebRequest(ByVal address As Uri) As WebRequest
Dim r As WebRequest = MyBase.GetWebRequest(address)
Dim request = TryCast(r, HttpWebRequest)
If request IsNot Nothing Then
request.CookieContainer = container
request.Timeout = Timeout
End If
Return r
End Function
Protected Overrides Function GetWebResponse(ByVal request As WebRequest, ByVal result As IAsyncResult) As WebResponse
Dim response As WebResponse = MyBase.GetWebResponse(request, result)
ReadCookies(response)
Return response
End Function
Protected Overrides Function GetWebResponse(ByVal request As WebRequest) As WebResponse
Dim response As WebResponse = MyBase.GetWebResponse(request)
ReadCookies(response)
Return response
End Function
Private Sub ReadCookies(ByVal r As WebResponse)
Dim response = TryCast(r, HttpWebResponse)
If response IsNot Nothing Then
Dim cookies As CookieCollection = response.Cookies
container.Add(cookies)
End If
End Sub
End Class
+151
View File
@@ -0,0 +1,151 @@
'来源:https://blog.csdn.net/simpleman2000/article/details/140952294
Imports System.ComponentModel
Imports System.Runtime.InteropServices
Imports System.Windows.Interop
Public Class DragHelper
Public Event DragDrop As EventHandler
Public Property DropFilePaths As String()
Get
Return _DropFilePathsBackingField
End Get
Private Set(value As String())
_DropFilePathsBackingField = value
End Set
End Property
Private _DropFilePathsBackingField As String()
Public Property DropPoint As POINT
Get
Return _DropPointBackingField
End Get
Private Set(value As POINT)
_DropPointBackingField = value
End Set
End Property
Private _DropPointBackingField As POINT
Public Property HwndIntPtrSource As HwndSource
Public Sub AddHook()
RemoveDragHook()
HwndIntPtrSource.AddHook(AddressOf WndProc)
Dim handle As IntPtr = HwndIntPtrSource.Handle
If IsUserAnAdmin() Then RevokeDragDrop(handle)
DragAcceptFiles(handle, True)
ChangeMessageFilter(handle)
End Sub
Public Sub RemoveDragHook()
HwndIntPtrSource.RemoveHook(AddressOf WndProc)
DragAcceptFiles(HwndIntPtrSource.Handle, False)
End Sub
Private Function WndProc(hwnd As IntPtr, msg As Integer, wParam As IntPtr, lParam As IntPtr, ByRef handled As Boolean) As IntPtr
Dim filePaths As String() = Nothing
Dim point As New POINT()
If TryGetDropInfo(msg, wParam, filePaths, point) Then
DropPoint = point
DropFilePaths = filePaths
RaiseEvent DragDrop(Me, EventArgs.Empty)
handled = True
End If
Return IntPtr.Zero
End Function
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function ChangeWindowMessageFilterEx(hWnd As IntPtr, msg As UInteger, action As UInteger, ByRef pChangeFilterStruct As CHANGEFILTERSTRUCT) As Boolean
End Function
<DllImport("user32.dll", SetLastError:=True)>
Private Shared Function ChangeWindowMessageFilter(msg As UInteger, flags As UInteger) As Boolean
End Function
<DllImport("shell32.dll")>
Private Shared Sub DragAcceptFiles(hWnd As IntPtr, fAccept As Boolean)
End Sub
<DllImport("shell32.dll", CharSet:=CharSet.Unicode)>
Private Shared Function DragQueryFile(hWnd As IntPtr, iFile As UInteger, lpszFile As StringBuilder, cch As Integer) As UInteger
End Function
<DllImport("shell32.dll")>
Private Shared Function DragQueryPoint(hDrop As IntPtr, ByRef lppt As POINT) As Boolean
End Function
<DllImport("shell32.dll")>
Private Shared Sub DragFinish(hDrop As IntPtr)
End Sub
<DllImport("ole32.dll")>
Private Shared Function RevokeDragDrop(hWnd As IntPtr) As Integer
End Function
<DllImport("shell32.dll")>
Private Shared Function IsUserAnAdmin() As Boolean
End Function
<StructLayout(LayoutKind.Sequential)>
Public Structure POINT
Public X As Integer
Public Y As Integer
End Structure
<StructLayout(LayoutKind.Sequential)>
Private Structure CHANGEFILTERSTRUCT
Public cbSize As UInteger
Public ExtStatus As UInteger
End Structure
Private Const WM_COPYGLOBALDATA As UInteger = &H49
Private Const WM_COPYDATA As UInteger = &H4A
Private Const WM_DROPFILES As UInteger = &H233
Private Const MSGFLT_ALLOW As UInteger = 1
Private Const MSGFLT_ADD As UInteger = 1
Private Const MAX_PATH As Integer = 260
Private Shared Sub ChangeMessageFilter(handle As IntPtr)
Dim ver As Version = Environment.OSVersion.Version
Dim isVistaOrHigher As Boolean = ver >= New Version(6, 0)
Dim isNt61OrHiger As Boolean = ver >= New Version(6, 1)
If isVistaOrHigher Then
Dim status As New CHANGEFILTERSTRUCT With {.cbSize = 8}
For Each msg As UInteger In New UInteger() {WM_DROPFILES, WM_COPYGLOBALDATA, WM_COPYDATA}
Dim [error] As Boolean = False
If isNt61OrHiger Then
[error] = Not ChangeWindowMessageFilterEx(handle, msg, MSGFLT_ALLOW, status)
Else
[error] = Not ChangeWindowMessageFilter(msg, MSGFLT_ADD)
End If
If [error] Then Throw New Win32Exception(Marshal.GetLastWin32Error())
Next
End If
End Sub
Private Shared Function TryGetDropInfo(msg As Integer, wParam As IntPtr, ByRef dropFilePaths As String(), ByRef dropPoint As POINT) As Boolean
dropFilePaths = Nothing
dropPoint = New POINT()
If msg <> WM_DROPFILES Then Return False
Dim fileCount As UInteger = DragQueryFile(wParam, UInteger.MaxValue, Nothing, 0)
ReDim dropFilePaths(CInt(fileCount) - 1)
For i As UInteger = 0 To fileCount - 1
Dim sb As New StringBuilder(MAX_PATH)
Dim result As UInteger = DragQueryFile(wParam, i, sb, sb.Capacity)
If result > 0 Then dropFilePaths(i) = sb.ToString()
Next
DragQueryPoint(wParam, dropPoint)
DragFinish(wParam)
Return True
End Function
End Class
@@ -1,4 +1,4 @@
Imports System.Reflection
Imports System.Reflection
Imports System.Resources
Imports System.Runtime.InteropServices
@@ -8,11 +8,11 @@ Imports System.Runtime.InteropServices
'查看程序集特性的值
<Assembly: AssemblyTitle("Plain Craft Launcher 2 启动器")>
<Assembly: AssemblyTitle("Plain Craft Launcher 启动器")>
<Assembly: AssemblyDescription("Minecraft 启动器 (制作:龙腾猫跃)")>
<Assembly: AssemblyCompany("")>
<Assembly: AssemblyProduct("Plain Craft Launcher 2")>
<Assembly: AssemblyCopyright("Copyright © 龙腾猫跃 2016-2022. All Rights Reserved.")>
<Assembly: AssemblyProduct("Plain Craft Launcher")>
<Assembly: AssemblyCopyright("Copyright © 龙腾猫跃 2016. All Rights Reserved.")>
<Assembly: AssemblyConfiguration("PCL2 Config Mark")>
<Assembly: ComVisible(False)>
@@ -51,6 +51,6 @@ Imports System.Runtime.InteropServices
' 可以指定所有值,也可以使用以下所示的 "*" 预置版本号和修订号
' 方法是按如下所示使用“*”
<Assembly: AssemblyVersion("2.3.4.0")>
<Assembly: AssemblyFileVersion("2.3.4.0")>
<Assembly: AssemblyVersion("2.10.5.0")>
<Assembly: AssemblyFileVersion("2.10.5.0")>
<Assembly: NeutralResourcesLanguage("")>
+58 -8
View File
@@ -63,9 +63,9 @@ Namespace My.Resources
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Custom() As Byte()
Friend ReadOnly Property CacheCow_Client() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Custom", resourceCulture)
Dim obj As Object = ResourceManager.GetObject("CacheCow.Client", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
@@ -73,9 +73,29 @@ Namespace My.Resources
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Dialogs() As Byte()
Friend ReadOnly Property CacheCow_Client_FileStore() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Dialogs", resourceCulture)
Dim obj As Object = ResourceManager.GetObject("CacheCow.Client.FileStore", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property CacheCow_Common() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("CacheCow.Common", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Custom() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Custom", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
@@ -100,6 +120,16 @@ Namespace My.Resources
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Imazen_WebP() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Imazen.WebP", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
@@ -113,9 +143,9 @@ Namespace My.Resources
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Json() As Byte()
Friend ReadOnly Property libwebp64() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Json", resourceCulture)
Dim obj As Object = ResourceManager.GetObject("libwebp64", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
@@ -143,9 +173,29 @@ Namespace My.Resources
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property STUN() As Byte()
Friend ReadOnly Property Newtonsoft_Json() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("STUN", resourceCulture)
Dim obj As Object = ResourceManager.GetObject("Newtonsoft.Json", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property Ookii_Dialogs_Wpf() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("Ookii.Dialogs.Wpf", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
'''<summary>
''' 查找 System.Byte[] 类型的本地化资源。
'''</summary>
Friend ReadOnly Property System_Net_Http_Formatting() As Byte()
Get
Dim obj As Object = ResourceManager.GetObject("System.Net.Http.Formatting", resourceCulture)
Return CType(obj,Byte())
End Get
End Property
@@ -118,32 +118,47 @@
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<assembly alias="System.Windows.Forms" name="System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089" />
<data name="CacheCow.Client" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CacheCow.Client.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CacheCow.Client.FileStore" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CacheCow.Client.FileStore.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="CacheCow.Common" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\CacheCow.Common.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Custom" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\custom.xaml;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Dialogs" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\ookii.dialogs.wpf.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ForgeInstaller" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\forge-installer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Help" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Help.zip;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Imazen.WebP" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Imazen.WebP.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="JavaWrapper" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\java-wrapper.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Json" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Newtonsoft.Json.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<data name="libwebp64" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\libwebp64.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="ModData" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\ModData.json;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<value>..\Resources\ModData.txt;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="NAudio" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\NAudio.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="STUN" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\STUN.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
<data name="Newtonsoft.Json" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\Newtonsoft.Json.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Ookii.Dialogs.Wpf" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\resources\ookii.dialogs.wpf.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="System.Net.Http.Formatting" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\System.Net.Http.Formatting.dll;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</data>
<data name="Transformer" type="System.Resources.ResXFileRef, System.Windows.Forms">
<value>..\Resources\transformer.jar;System.Byte[], mscorlib, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
@@ -0,0 +1,84 @@
<Grid x:Class="MyCompItem"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:PCL"
x:Name="PanBack" Height="64"
RenderTransformOrigin="0.5,0.5" Background="{StaticResource ColorBrushSemiTransparent}" SnapsToDevicePixels="True">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="7" />
<ColumnDefinition Width="50" />
<ColumnDefinition Width="8" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="1*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="1*" />
<RowDefinition Height="17" />
<RowDefinition Height="18" />
<RowDefinition Height="16" />
<RowDefinition Height="1.1*" />
</Grid.RowDefinitions>
<!-- Logo -->
<Border Grid.Column="1" Grid.Row="1" Grid.RowSpan="3" IsHitTestVisible="False" SnapsToDevicePixels="True" UseLayoutRounding="True"
HorizontalAlignment="Right" VerticalAlignment="Center" Width="50" Height="50">
<Border.Clip>
<RectangleGeometry Rect="0,0,50,50" RadiusX="6" RadiusY="6" />
</Border.Clip>
<local:MyImage x:Name="PathLogo" RenderOptions.BitmapScalingMode="HighQuality" FallbackSource="pack://application:,,,/images/Icons/NoIcon.png" />
</Border>
<!-- 标题 -->
<StackPanel Grid.Column="3" Grid.ColumnSpan="2" Grid.Row="1" VerticalAlignment="Bottom" Margin="0,1,0,0" Orientation="Horizontal"
IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False">
<TextBlock x:Name="LabTitle" TextTrimming="WordEllipsis" FontSize="14" Foreground="{DynamicResource ColorBrush1}" />
<TextBlock x:Name="LabTitleRaw" TextTrimming="WordEllipsis" FontSize="12" Foreground="{StaticResource ColorBrushGray1}" Opacity="0.4" VerticalAlignment="Bottom" Visibility="Collapsed" />
</StackPanel>
<!-- Tag 与 详情 -->
<StackPanel x:Name="PanTags" Grid.Row="2" Grid.Column="3" Orientation="Horizontal" VerticalAlignment="Bottom" Margin="-1,0,1,0" Visibility="Collapsed">
<!--<Border Background="{DynamicResource ColorBrush6}" Padding="3,1" CornerRadius="3" Margin="0,0,4,0" SnapsToDevicePixels="True" UseLayoutRounding="False">
<TextBlock Text="科技" Foreground="{DynamicResource ColorBrush2}" FontSize="11" />
</Border>-->
</StackPanel>
<TextBlock x:Name="LabInfo" Grid.Row="2" Grid.Column="4" VerticalAlignment="Bottom" Margin="0,0,3,0.5"
TextTrimming="CharacterEllipsis" FontSize="12" Foreground="{StaticResource ColorBrushGray3}"
IsHitTestVisible="True" SnapsToDevicePixels="False" UseLayoutRounding="False"
ToolTipService.InitialShowDelay="100" ToolTipService.BetweenShowDelay="100"
ToolTipService.Placement="Relative" ToolTipService.PlacementRectangle="-16,-10,500,10000">
<TextBlock.ToolTip>
<ToolTip x:Name="ToolTipInfo" Style="{StaticResource ExtendTextToolTip}" />
</TextBlock.ToolTip>
</TextBlock>
<!-- 下边栏 -->
<Grid Grid.Row="3" Grid.Column="3" Grid.ColumnSpan="2" VerticalAlignment="Bottom"
IsHitTestVisible="False" SnapsToDevicePixels="False" UseLayoutRounding="False">
<Grid.ColumnDefinitions>
<ColumnDefinition x:Name="ColumnVersion1" Width="Auto" />
<ColumnDefinition x:Name="ColumnVersion2" Width="Auto" SharedSizeGroup="CompItemVersion" />
<ColumnDefinition x:Name="ColumnVersion3" Width="0.7*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="55" />
<ColumnDefinition Width="1*" />
<ColumnDefinition x:Name="ColumnTime1" Width="Auto" />
<ColumnDefinition x:Name="ColumnTime2" Width="Auto" MinWidth="57" SharedSizeGroup="CompItemTime" />
<ColumnDefinition x:Name="ColumnTime3" Width="1*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" SharedSizeGroup="CompItemSource" />
<ColumnDefinition Width="1.7*" />
</Grid.ColumnDefinitions>
<Path x:Name="PathVersion" Grid.Column="0" Fill="{StaticResource ColorBrushGray3}" Stretch="Uniform" Height="11"
Data="M940.4 463.7L773.3 174.2c-17.3-30-49.2-48.4-83.8-48.4H340.2c-34.6 0-66.5 18.5-83.8 48.4L89.2 463.7c-17.3 30-17.3 66.9 0 96.8L256.4 850c17.3 30 49.2 48.4 83.8 48.4h349.2c34.6 0 66.5-18.5 83.8-48.4l167.2-289.5c17.3-29.9 17.3-66.8 0-96.8z m-94.6 96.8L725.9 768.1c-17.3 30-49.2 48.4-83.8 48.4H387.5c-34.6 0-66.5-18.5-83.8-48.4L183.9 560.5c-17.3-30-17.3-66.9 0-96.8l119.8-207.5c17.3-30 49.2-48.4 83.8-48.4h254.6c34.6 0 66.5 18.5 83.8 48.4l119.8 207.5c17.3 30 17.3 66.9 0.1 96.8z M522.3 321.2c-2.5-0.1-5-0.2-7.5-0.2-119.9 0-214 110.3-186.3 235 15.8 70.9 71.5 126.6 142.4 142.4 17.5 3.9 34.7 5.4 51.4 4.7 102.1-3.9 183.6-87.9 183.6-191 0.1-103-81.5-187-183.6-190.9z m68.6 269.1c-18.5 18-43 28.9-68.6 30.7l-6 0.3c-30.2 0.4-58.6-11.4-79.7-33-19.5-20.1-30.7-47-30.9-75-0.3-29.6 11.1-57.4 32-78.3 20.6-20.6 48-32 77.2-32 2.5 0 5 0.1 7.5 0.3 26.7 1.8 51.5 13.2 70.5 32.5 19.6 20 30.8 46.9 31.2 74.9 0.2 30.2-11.5 58.6-33.2 79.6z" />
<TextBlock x:Name="LabVersion" Grid.Column="1" Margin="4,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray3}" FontSize="12"
TextTrimming="WordEllipsis" />
<Path x:Name="PathDownload" Grid.Column="3" Fill="{StaticResource ColorBrushGray4}" Stretch="Uniform" Height="10.5"
Data="M955 610h-59c-15 0-29 13-29 29v196c0 15-13 29-29 29h-649c-15 0-29-13-29-29v-196c0-15-13-29-29-29h-59c-15 0-29 13-29 29V905c0 43 35 78 78 78h787c43 0 78-35 78-78V640c0-15-13-29-29-29zM492 740c11 11 29 11 41 0l265-265c11-11 11-29 0-41l-41-41c-11-11-29-11-41 0l-110 110c-11 11-33 3-33-13V68C571 53 555 39 541 39h-59c-15 0-29 13-29 29v417c0 17-21 25-33 13l-110-110c-11-11-29-11-41 0L226 433c-11 11-11 29 0 41L492 740z" />
<TextBlock x:Name="LabDownload" Grid.Column="4" Margin="5,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray4}" FontSize="12" />
<Path x:Name="PathTime" Grid.Column="6" Fill="{StaticResource ColorBrushGray4}" Stretch="Uniform" Height="11.5" Margin="0,0,1,0"
Data="M810 403l-39 39c-10 10-28 10-39 0l-162-162v412c0 15-12 28-28 28h-56c-15 0-28-12-28-28v-412l-162 162c-10 10-28 10-39 0l-39-39c-10-10-10-28 0-39l278-278c10-10 28-10 39 0l278 278c10 10 10 28-0 39zM568 946h-112v-112h112v112z" />
<TextBlock x:Name="LabTime" Grid.Column="7" Margin="5,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray4}" FontSize="12" />
<Path x:Name="PathSource" Grid.Column="9" Fill="{StaticResource ColorBrushGray4}" Stretch="Uniform" Height="11.5"
Data="M511 143c-203 0-369 165-369 369 0 203 165 369 369 369s369-165 369-369c0-203-165-369-369-369z m0 673c-29 0-68-59-89-159l178 0c-20 100-59 159-89 159z m-98-224c-2-24-3-51-3-79 0-29 1-57 4-83l197 0c2 25 4 53 4 83 0 28-1 54-3 79l-198-0z m98-383c29 0 67 58 88 156l-177-0c20-98 59-155 88-155z m164 221l128 0c7 26 11 54 11 82 0 27-3 54-10 80l-129-0c2-26 3-52 3-79 0-28-1-56-4-83z m101-64l-110-0c-7-37-16-72-28-102-4-11-9-22-15-33 66 25 121 74 155 135z m-376-135c-5 10-10 21-15 33-12 30-21 64-28 102l-110-0c34-60 89-109 154-134z m-181 199l128 0c-2 27-3 54-3 83 0 27 1 53 3 79l-127-0v6c-8-27-12-55-12-85-0-29 3-57 11-83z m24 227l112 0c7 38 16 74 29 105 4 11 9 22 15 33-67-26-122-76-156-139zM621 795c5-10 10-21 15-33 12-30 22-66 29-105l111 0c-34 62-89 111-156 137z" />
<TextBlock x:Name="LabSource" Grid.Column="10" Margin="5,0,2,0" VerticalAlignment="Center" Foreground="{StaticResource ColorBrushGray4}" FontSize="12" />
</Grid>
</Grid>
@@ -1,78 +1,83 @@
Public Class MyCfItem
Public Class MyCompItem
#Region "基础属性"
Public Uuid As Integer = GetUuid()
#Region "Logo"
'Public CacheLogo As Boolean = True '是否缓存 Logo:通过下载量确定是否为默认页
Private _Logo As String = ""
'Logo
Public Property Logo As String
Get
Return _Logo
Return PathLogo.Source
End Get
Set(value As String)
If _Logo = value OrElse value Is Nothing Then Exit Property
_Logo = value
Dim FileAddress = PathTemp & "CFLogo\" & GetHash(_Logo) & ".png"
Try
If _Logo.ToLower.StartsWith("http") Then
'网络图片
If File.Exists(FileAddress) Then
PathLogo.Source = New MyBitmap(FileAddress)
Else
PathLogo.Source = New MyBitmap("pack://application:,,,/images/Icons/NoIcon.png")
RunInNewThread(Sub() LogoLoader(FileAddress), "CurseForge Logo Loader " & Uuid & "#", ThreadPriority.BelowNormal)
End If
Else
'位图
PathLogo.Source = New MyBitmap(_Logo)
End If
Catch ex As IOException
Log(ex, "加载 CurseForge 工程图标时读取失败(" & FileAddress & ")")
Catch ex As ArgumentException
'考虑缓存的图片本身可能有误
Log(ex, "可视化 CurseForge 工程图标失败(" & FileAddress & ")")
Try
File.Delete(FileAddress)
Log("[Download] 已清理损坏的 CurseForge 工程图标:" & FileAddress)
Catch exx As Exception
Log(exx, "清理损坏的 CurseForge 工程图标缓存失败(" & FileAddress & ")", LogLevel.Hint)
End Try
Catch ex As Exception
Log(ex, "加载 CurseForge 工程图标失败(" & value & ")")
End Try
PathLogo.Source = value
End Set
End Property
Private Sub LogoLoader(Address As String)
Dim Retry As Boolean = False
Dim DownloadEnd As String = GetUuid()
RetryStart:
Try
NetDownload(_Logo, Address & DownloadEnd)
RunInUiWait(Sub()
Try
'在地址更换时取消加载
If Not Address = PathTemp & "CFLogo\" & GetHash(_Logo) & ".png" Then Exit Sub
'在完成正常加载后才保存缓存图片
PathLogo.Source = New MyBitmap(Address & DownloadEnd)
Catch ex As Exception
Log(ex, "读取 CurseForge 工程图标失败(" & Address & ")", LogLevel.Hint)
End Try
End Sub)
If File.Exists(Address) Then
File.Delete(Address & DownloadEnd)
Else
FileIO.FileSystem.MoveFile(Address & DownloadEnd, Address)
End If
Catch ex As Exception
If Not Retry Then
Retry = True
GoTo RetryStart
Else
Log(ex, "下载 CurseForge 工程图标失败")
End If
End Try
'标题
Public Property Title As String
Get
Return LabTitle.Text
End Get
Set(value As String)
If LabTitle.Text = value Then Return
LabTitle.Text = value
End Set
End Property
'副标题
Public Property SubTitle As String
Get
Return If(LabTitleRaw?.Text, "")
End Get
Set(value As String)
If LabTitleRaw.Text = value Then Return
LabTitleRaw.Text = value
LabTitleRaw.Visibility = If(value = "", Visibility.Collapsed, Visibility.Visible)
End Set
End Property
'描述
Public Property Description As String
Get
Return LabInfo.Text
End Get
Set(value As String)
If LabInfo.Text = value Then Return
LabInfo.Text = value
End Set
End Property
'指向时扩展描述
Private Sub LabInfo_MouseEnter(sender As Object, e As MouseEventArgs) Handles LabInfo.MouseEnter
If IsTextTrimmed(LabInfo) Then
ToolTipInfo.Content = LabInfo.Text
ToolTipInfo.Width = LabInfo.ActualWidth + 25
LabInfo.ToolTip = ToolTipInfo
Else
LabInfo.ToolTip = Nothing
End If
End Sub
Private Function IsTextTrimmed(textBlock As TextBlock) As Boolean
Dim typeface As New Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch)
Dim formattedText As New FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground, DPI)
Return formattedText.Width > textBlock.ActualWidth
End Function
'Tag
Public WriteOnly Property Tags As List(Of String)
Set(value As List(Of String))
PanTags.Children.Clear()
PanTags.Visibility = If(value.Any(), Visibility.Visible, Visibility.Collapsed)
For Each TagText In value
Dim NewTag = GetObjectFromXML(
"<Border xmlns=""http://schemas.microsoft.com/winfx/2006/xaml/presentation""
Background=""#11000000"" Padding=""3,1"" CornerRadius=""3"" Margin=""0,0,3,0""
SnapsToDevicePixels=""True"" UseLayoutRounding=""False"">
<TextBlock Text=""" & TagText & """ Foreground=""#868686"" FontSize=""11"" />
</Border>")
PanTags.Children.Add(NewTag)
Next
End Set
End Property
#End Region
@@ -83,15 +88,58 @@ RetryStart:
Private Sub Button_MouseUp(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonUp
If IsMouseDown Then
RaiseEvent Click(sender, e)
If e.Handled Then Exit Sub
Log("[Control] 按下 CurseForge 工程列表项:" & LabTitle.Text)
If e.Handled Then Return
Log("[Control] 按下资源工程列表项:" & LabTitle.Text)
End If
End Sub
Private Sub MyCompItem_Click(sender As MyCompItem, e As EventArgs) Handles Me.Click
'记录当前展开的卡片标题(#2712)
Dim Titles As New List(Of String)
If FrmMain.PageCurrent.Page = FormMain.PageType.CompDetail Then
For Each Card As MyCard In FrmDownloadCompDetail.PanResults.Children
If Card.Title <> "" AndAlso Not Card.IsSwaped Then Titles.Add(Card.Title)
Next
Log("[Comp] 记录当前已展开的卡片:" & String.Join("、", Titles))
FrmMain.PageCurrent.Additional(1) = Titles
End If
'打开详情页
Dim TargetType As CompType
Dim TargetVersion As String = Nothing
Dim TargetLoader As CompModLoaderType = CompModLoaderType.Any
If FrmMain.PageCurrent.Page = FormMain.PageType.Download Then
'从下载页进入
Select Case FrmMain.PageCurrentSub
Case FormMain.PageSubType.DownloadMod
TargetType = CompType.Mod
TargetVersion = FrmDownloadMod.Content.Loader.Input.GameVersion
TargetLoader = FrmDownloadMod.Content.Loader.Input.ModLoader
Case FormMain.PageSubType.DownloadPack
TargetType = CompType.ModPack
TargetVersion = FrmDownloadPack.Content.Loader.Input.GameVersion
Case FormMain.PageSubType.DownloadDataPack
TargetType = CompType.DataPack
TargetVersion = FrmDownloadDataPack.Content.Loader.Input.GameVersion
Case FormMain.PageSubType.DownloadResourcePack
TargetType = CompType.ResourcePack
TargetVersion = FrmDownloadResourcePack.Content.Loader.Input.GameVersion
Case FormMain.PageSubType.DownloadShader
TargetType = CompType.Shader
TargetVersion = FrmDownloadShader.Content.Loader.Input.GameVersion
End Select
Else
'从详情页进入(查看前置)
TargetType = CompType.Any '允许任意类别
TargetVersion = FrmMain.PageCurrent.Additional(2)
TargetLoader = FrmMain.PageCurrent.Additional(3)
End If
FrmMain.PageChange(New FormMain.PageStackData With {.Page = FormMain.PageType.CompDetail,
.Additional = {sender.Tag, New List(Of String), TargetVersion, TargetLoader, TargetType}})
End Sub
'鼠标点击判定
Private IsMouseDown As Boolean = False
Private Sub Button_MouseDown(sender As Object, e As MouseButtonEventArgs) Handles Me.PreviewMouseLeftButtonDown
If IsMouseOver Then IsMouseDown = True
If IsMouseOver AndAlso CanInteraction Then IsMouseDown = True
End Sub
Private Sub Button_MouseLeave(sender As Object, e As Object) Handles Me.MouseLeave, Me.PreviewMouseLeftButtonUp
IsMouseDown = False
@@ -132,9 +180,12 @@ RetryStart:
#End Region
Private StateLast As String
Public HasAnimation As Boolean = True
''' <summary>
''' 是否允许交互。目前仅用于 PageDownloadCompDetail 的顶部栏展示:若关闭碰撞检测,则无法展开 Tooltip。
''' </summary>
Public Property CanInteraction As Boolean = True
Public Sub RefreshColor(sender As Object, e As EventArgs) Handles Me.MouseEnter, Me.MouseLeave, Me.MouseLeftButtonDown, Me.MouseLeftButtonUp
If Not HasAnimation Then Exit Sub
If Not CanInteraction Then Return
'判断当前颜色
Dim StateNew As String, Time As Integer
If IsMouseOver Then
@@ -149,7 +200,7 @@ RetryStart:
StateNew = "Idle"
Time = 180
End If
If StateLast = StateNew Then Exit Sub
If StateLast = StateNew Then Return
StateLast = StateNew
'触发颜色动画
If IsLoaded AndAlso AniControlEnabled = 0 Then '防止默认属性变更触发动画
@@ -157,7 +208,7 @@ RetryStart:
Dim Ani As New List(Of AniData)
If IsMouseOver Then
Ani.AddRange({
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrush9"), Time),
AaColor(RectBack, Border.BackgroundProperty, If(IsMouseDown, "ColorBrush6", "ColorBrushBg1"), Time),
AaOpacity(RectBack, 1 - RectBack.Opacity, Time,, New AniEaseOutFluent)
})
If IsMouseDown Then
@@ -173,28 +224,12 @@ RetryStart:
AaScaleTransform(RectBack, -0.196, 1,,, True)
})
End If
AniStart(Ani, "CfItem Color " & Uuid)
AniStart(Ani, "CompItem Color " & Uuid)
Else
'无动画
AniStop("CfItem Color " & Uuid)
AniStop("CompItem Color " & Uuid)
If _RectBack IsNot Nothing Then RectBack.Opacity = 0
End If
End Sub
'指向时扩展描述
Private Sub LabInfo_MouseEnter(sender As Object, e As MouseEventArgs) Handles LabInfo.MouseEnter
If IsTextTrimmed(LabInfo) Then
ToolTipInfo.Content = LabInfo.Text
ToolTipInfo.Width = LabInfo.ActualWidth + 25
LabInfo.ToolTip = ToolTipInfo
Else
LabInfo.ToolTip = Nothing
End If
End Sub
Private Function IsTextTrimmed(textBlock As TextBlock) As Boolean
Dim typeface As New Typeface(textBlock.FontFamily, textBlock.FontStyle, textBlock.FontWeight, textBlock.FontStretch)
Dim formattedText As New FormattedText(textBlock.Text, Thread.CurrentThread.CurrentCulture, textBlock.FlowDirection, typeface, textBlock.FontSize, textBlock.Foreground, DPI)
Return formattedText.Width > textBlock.ActualWidth
End Function
End Class
Loaded 100 of 232 files, more files were not shown because too many files have changed in this diff. Show more