diff --git a/PCL.Core/App/Localization/Languages/en-US.xaml b/PCL.Core/App/Localization/Languages/en-US.xaml index c090e7a13e..2ab64259ad 100644 --- a/PCL.Core/App/Localization/Languages/en-US.xaml +++ b/PCL.Core/App/Localization/Languages/en-US.xaml @@ -598,7 +598,7 @@ Download the latest version Select a target Minecraft instance - Select an instance… + Select instances… Select a folder… Download to the current instance Select a download destination diff --git a/PCL.Core/App/Localization/Languages/zh-CN.xaml b/PCL.Core/App/Localization/Languages/zh-CN.xaml index 9bae29f93c..0d6318c996 100644 --- a/PCL.Core/App/Localization/Languages/zh-CN.xaml +++ b/PCL.Core/App/Localization/Languages/zh-CN.xaml @@ -598,7 +598,7 @@ 快速下载最新版本 选择要下载到的 Minecraft 实例 - 选择一个实例… + 选择实例… 选择一个文件夹… 下载到当前选中实例 选择下载方式 diff --git a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs index c489762258..d978020881 100644 --- a/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs +++ b/Plain Craft Launcher 2/Controls/MyMsg/MyMsgSelect.xaml.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Windows; using System.Windows.Controls; using System.Windows.Input; @@ -82,11 +82,13 @@ private void InitializeSelectionList(object content) { PanSelection.Children.Add((UIElement)selection); selection.Check += (sender, e) => OnChecked((IMyRadio)sender, e); + selection.Changed += (_, _) => _UpdateCheckedState(); // 3. Property configuration based on specific type if (selection is MyListItem listItem) { - listItem.Type = MyListItem.CheckType.RadioBox; + listItem.Type = + myConverter.MultiSelect ? MyListItem.CheckType.CheckBox : MyListItem.CheckType.RadioBox; listItem.MinHeight = 24.0; } else if (selection is MyRadioBox radioBox) @@ -163,10 +165,26 @@ private void Close() public void Btn1_Click(object sender, MouseButtonEventArgs e) { - if (myConverter.IsExited || selectedIndex == -1) + if (myConverter.IsExited) return; - myConverter.IsExited = true; - myConverter.Result = selectedIndex; + if (myConverter.MultiSelect) + { + var indices = new List(); + for (var i = 0; i < PanSelection.Children.Count; i++) + if (PanSelection.Children[i] is MyListItem { Checked: true }) + indices.Add(i); + if (indices.Count == 0) + return; + myConverter.IsExited = true; + myConverter.Result = indices; + } + else + { + if (selectedIndex == -1) + return; + myConverter.IsExited = true; + myConverter.Result = selectedIndex; + } Close(); } @@ -181,10 +199,24 @@ public void Btn2_Click(object sender, MouseButtonEventArgs e) private void OnChecked(IMyRadio sender, EventArgs e) { + if (myConverter.MultiSelect) + return; Btn1.IsEnabled = true; selectedIndex = PanSelection.Children.IndexOf((UIElement)sender); } + private void _UpdateCheckedState() + { + // 多选 + if (!myConverter.MultiSelect) + return; + var checkedCount = 0; + foreach (var child in PanSelection.Children) + if (child is MyListItem { Checked: true }) + checkedCount += 1; + Btn1.IsEnabled = checkedCount > 0; + } + private void Drag(object sender, MouseButtonEventArgs e) { try diff --git a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs index 771943c813..be64a00ea3 100644 --- a/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs +++ b/Plain Craft Launcher 2/Modules/Minecraft/ModComp.cs @@ -3540,9 +3540,11 @@ public static void QuickDownload(CompProject project) break; case 2: // 询问并下载到选择的实例 { - var instance = _QuickDownloadPickInstance(project, files); - if (instance is null) return; - _QuickDownloadToInstance(project, files, instance); + var instances = _QuickDownloadPickInstances(project, files); + if (instances is null) return; + var startedTargets = new HashSet(StringComparer.OrdinalIgnoreCase); + foreach (var instance in instances) + _QuickDownloadToInstance(project, files, instance, startedTargets); break; } case 3: // 询问并下载到一个路径 @@ -3562,7 +3564,8 @@ public static void QuickDownload(CompProject project) } /// 下载到指定实例的最新兼容版本。 - private static void _QuickDownloadToInstance(CompProject project, List files, McInstance? instance) + private static void _QuickDownloadToInstance(CompProject project, List files, McInstance? instance, + ISet? startedTargets = null) { if (instance is null) { @@ -3582,12 +3585,15 @@ private static void _QuickDownloadToInstance(CompProject project, List var folder = instance.PathIndie + _GetSubFolder(project.Type); Directory.CreateDirectory(folder); var target = Path.Combine(folder, CompFileNameGet(project, file)); + //只下载一次,避免并发写同一文件 + if (startedTargets is not null && !startedTargets.Add(target)) + return; _StartQuickDownload(file, target); HintService.Hint(Lang.Text("Download.Comp.QuickDownload.Hint.DownloadStarted", project.RawName), HintType.Success); } /// 弹实例列表让用户选择,返回选中的实例(兼容者优先、当前选中实例居首);取消或无兼容实例返回 null。 - private static McInstance? _QuickDownloadPickInstance(CompProject project, List files) + private static List? _QuickDownloadPickInstances(CompProject project, List files) { var needLoad = ModInstanceList.mcInstanceListLoader.State != ModBase.LoadState.Finished; if (needLoad) @@ -3612,18 +3618,18 @@ private static void _QuickDownloadToInstance(CompProject project, List .OrderBy(v => v == current ? 0 : 1) .ThenBy(v => v.Name) .ToList(); - int? idx = ModBase.RunInUiWait(() => + var indices = ModBase.RunInUiWait(() => { var options = compatible - .Select(v => (IMyRadio)new MyRadioBox { Text = v.Name }) + .Select(v => new MyListItem { Title = v.Name }) .ToList(); - return ModMain.MyMsgBoxSelect(options, + return ModMain.MyMsgBoxMultiSelect(options, Lang.Text("Download.Comp.QuickDownload.ChooseInstance.Title"), button1: Lang.Text("Common.Action.Continue"), button2: Lang.Text("Common.Action.Cancel")); }); - if (idx is null) return null; - return compatible[idx.Value]; + if (indices is null) return null; + return indices.Select(i => compatible[i]).ToList(); } /// 下载最新版本到用户选择的文件夹。 diff --git a/Plain Craft Launcher 2/Modules/ModMain.cs b/Plain Craft Launcher 2/Modules/ModMain.cs index c1ecd882a1..f33362a7bb 100644 --- a/Plain Craft Launcher 2/Modules/ModMain.cs +++ b/Plain Craft Launcher 2/Modules/ModMain.cs @@ -1,4 +1,4 @@ -using System.Collections; +using System.Collections; using System.Collections.ObjectModel; using System.IO; using System.Runtime.InteropServices; @@ -262,6 +262,11 @@ public class MyMsgBoxConverter public bool ForceWait; + /// + /// 选择模式:是否允许勾选多个选项 + /// + public bool MultiSelect; + /// /// 有多个按钮时,是否给第一个按钮加高亮。 /// @@ -581,6 +586,44 @@ public static string MyMsgBoxInput(string title, string text = "", string defaul return (int?)converter.Result; } + /// + /// 显示多选选择框并返回勾选的所有项索引(从 0 开始)。若点击第二个按钮,则返回 Nothing。 + /// + /// 需要展示的可勾选列表项。 + /// 弹窗的标题。 + /// 显示的第一个按钮,默认为 “确定”。 + /// 显示的第二个按钮,默认为空。 + /// 是否为警告弹窗,若为 True,弹窗配色和背景会变为红色。 + public static List? MyMsgBoxMultiSelect(List selections, string? title = null, + string? button1 = null, string? button2 = "", bool isWarn = false) + { + title ??= GetDefaultDialogTitle(); + button1 ??= GetDefaultConfirmText(); + button2 ??= ""; + // 将弹窗列入队列 + var converter = new MyMsgBoxConverter + { + Type = MyMsgBoxType.Select, MultiSelect = true, Button1 = button1, Button2 = button2, Content = selections, + IsWarn = isWarn, Title = title + }; + WaitingMyMsgBox.Add(converter); + // 虽然我也不知道这是啥但是能用就成了 :) + try + { + if (frmMain is not null) + frmMain.DragStop(); + ComponentDispatcher.PushModal(); + Dispatcher.PushFrame(converter.WaitFrame); + } + finally + { + ComponentDispatcher.PopModal(); + } + + ModBase.Log($"[Control] 多选弹框返回:{converter.Result ?? "null"}"); + return (List?)converter.Result; + } + public static void MyMsgBoxTick() {