diff --git a/src/MaaWpfGui/Constants/UILogColor.cs b/src/MaaWpfGui/Constants/UILogColor.cs index 9a5b22f853..f47489f9ca 100644 --- a/src/MaaWpfGui/Constants/UILogColor.cs +++ b/src/MaaWpfGui/Constants/UILogColor.cs @@ -56,6 +56,36 @@ namespace MaaWpfGui.Constants [UsedImplicitly] public const string RobotOperator = "RobotOperatorLogBrush"; + /// + /// The recommended color for 1-star operators (also used for robot operators). + /// + public const string Star1Operator = "Star1OperatorLogBrush"; + + /// + /// The recommended color for 2-star operators. + /// + public const string Star2Operator = "Star2OperatorLogBrush"; + + /// + /// The recommended color for 3-star operators. + /// + public const string Star3Operator = "Star3OperatorLogBrush"; + + /// + /// The recommended color for 4-star operators. + /// + public const string Star4Operator = "Star4OperatorLogBrush"; + + /// + /// The recommended color for 5-star operators. + /// + public const string Star5Operator = "Star5OperatorLogBrush"; + + /// + /// The recommended color for 6-star operators. + /// + public const string Star6Operator = "Star6OperatorLogBrush"; + /// /// The recommended color for file downloading or downloaded or download failed. /// diff --git a/src/MaaWpfGui/Helper/ToolTipHelper.cs b/src/MaaWpfGui/Helper/ToolTipHelper.cs index 816e216c4c..2b8370f313 100644 --- a/src/MaaWpfGui/Helper/ToolTipHelper.cs +++ b/src/MaaWpfGui/Helper/ToolTipHelper.cs @@ -76,6 +76,38 @@ namespace MaaWpfGui.Helper return tb.CreateTooltip(placementMode); } + public static ToolTip CreateTooltip(this IEnumerable inlines, PlacementMode? placementMode = null, int maxWidth = 750) + { + var tb = new TextBlock + { + TextWrapping = TextWrapping.Wrap, + Margin = new(4), + MaxWidth = maxWidth, + }; + + foreach (var inline in inlines) + { + tb.Inlines.Add(CloneInline(inline)); + } + + return tb.CreateTooltip(placementMode); + + Inline CloneInline(Inline inline) + { + return inline switch + { + Run run => new Run(run.Text) + { + Foreground = run.Foreground, + FontWeight = run.FontWeight, + FontStyle = run.FontStyle, + }, + LineBreak => new LineBreak(), + _ => new Run(), + }; + } + } + #region 创建日志 Tooltip 的辅助方法 /// diff --git a/src/MaaWpfGui/Main/AsstProxy.cs b/src/MaaWpfGui/Main/AsstProxy.cs index 6a392670ba..534dbd0c4a 100644 --- a/src/MaaWpfGui/Main/AsstProxy.cs +++ b/src/MaaWpfGui/Main/AsstProxy.cs @@ -1593,7 +1593,7 @@ namespace MaaWpfGui.Main case "RecruitResult": { int level = (int)subTaskDetails!["level"]!; - var tooltip = $"{Instances.RecognizerViewModel.RecruitInfo}\n\n{Instances.RecognizerViewModel.RecruitResult}".CreateTooltip(PlacementMode.Center); + var tooltip = Instances.RecognizerViewModel.RecruitResultInlines.CreateTooltip(PlacementMode.Center); if (level >= 5) { using (var toast = new ToastNotification(string.Format(LocalizationHelper.GetString("RecruitmentOfStar"), level))) diff --git a/src/MaaWpfGui/Res/Themes/Dark.xaml b/src/MaaWpfGui/Res/Themes/Dark.xaml index 97f8ddbd1b..274fdf7351 100644 --- a/src/MaaWpfGui/Res/Themes/Dark.xaml +++ b/src/MaaWpfGui/Res/Themes/Dark.xaml @@ -85,6 +85,12 @@ + + + + + + diff --git a/src/MaaWpfGui/Res/Themes/Light.xaml b/src/MaaWpfGui/Res/Themes/Light.xaml index fea509183f..42a7d4afbf 100644 --- a/src/MaaWpfGui/Res/Themes/Light.xaml +++ b/src/MaaWpfGui/Res/Themes/Light.xaml @@ -65,6 +65,12 @@ + + + + + + diff --git a/src/MaaWpfGui/Styles/Controls/TextBlock.cs b/src/MaaWpfGui/Styles/Controls/TextBlock.cs index f751cf0f3b..64c0abb066 100644 --- a/src/MaaWpfGui/Styles/Controls/TextBlock.cs +++ b/src/MaaWpfGui/Styles/Controls/TextBlock.cs @@ -11,7 +11,9 @@ // but WITHOUT ANY WARRANTY // +using System.Collections.Generic; using System.Windows; +using System.Windows.Documents; using System.Windows.Media; using MaaWpfGui.Helper; @@ -69,5 +71,37 @@ namespace MaaWpfGui.Styles.Controls SetValue(ForegroundProperty, brush); } } + + public static readonly DependencyProperty BindableInlinesProperty = + DependencyProperty.RegisterAttached( + "BindableInlines", + typeof(IEnumerable), + typeof(TextBlock), + new PropertyMetadata(null, OnBindableInlinesChanged)); + + public static void SetBindableInlines(DependencyObject element, IEnumerable value) + => element.SetValue(BindableInlinesProperty, value); + + public static IEnumerable GetBindableInlines(DependencyObject element) + => (IEnumerable)element.GetValue(BindableInlinesProperty); + + private static void OnBindableInlinesChanged(DependencyObject d, DependencyPropertyChangedEventArgs e) + { + if (d is not TextBlock tb) + { + return; + } + + tb.Inlines.Clear(); + if (e.NewValue is not IEnumerable inlines) + { + return; + } + + foreach (var inline in inlines) + { + tb.Inlines.Add(inline); + } + } } } diff --git a/src/MaaWpfGui/ViewModels/UI/RecognizerViewModel.cs b/src/MaaWpfGui/ViewModels/UI/RecognizerViewModel.cs index db600974f0..c5dcea81df 100644 --- a/src/MaaWpfGui/ViewModels/UI/RecognizerViewModel.cs +++ b/src/MaaWpfGui/ViewModels/UI/RecognizerViewModel.cs @@ -20,6 +20,8 @@ using System.Linq; using System.Threading; using System.Threading.Tasks; using System.Windows; +using System.Windows.Documents; +using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Threading; using HandyControl.Controls; @@ -99,15 +101,100 @@ namespace MaaWpfGui.ViewModels.UI set => SetAndNotify(ref _recruitInfo, value); } - private string _recruitResult = string.Empty; + private ObservableCollection _recruitResultInlines = []; - /// - /// Gets or sets the recruit result. - /// - public string RecruitResult + public ObservableCollection RecruitResultInlines { - get => _recruitResult; - set => SetAndNotify(ref _recruitResult, value); + get => _recruitResultInlines; + set => SetAndNotify(ref _recruitResultInlines, value); + } + + public void UpdateRecruitResult(JArray? resultArray) + { + ObservableCollection recruitResultInlines = []; + + foreach (var combs in resultArray ?? []) + { + int tagLevel = (int)(combs["level"] ?? -1); + recruitResultInlines.Add(new Run($"{tagLevel}★ Tags: ")); + + foreach (var tag in (JArray?)combs["tags"] ?? []) + { + recruitResultInlines.Add(new Run($"{tag} ")); + } + + recruitResultInlines.Add(new LineBreak()); + + foreach (var oper in (JArray?)combs["opers"] ?? []) + { + int operLevel = (int)(oper["level"] ?? -1); + var operId = oper["id"]?.ToString(); + var operName = DataHelper.GetLocalizedCharacterName(oper["name"]?.ToString()); + + bool isMaxPot = false; + string potentialText = string.Empty; + + if (RecruitmentShowPotential && OperBoxPotential != null && operId != null && (tagLevel >= 4 || operLevel == 1)) + { + if (OperBoxPotential.TryGetValue(operId, out var pot)) + { + potentialText = $" ( {pot} )"; + if (pot == 6) + { + isMaxPot = true; + potentialText = " ( MAX )"; + } + } + else + { + potentialText = " ( !!! NEW !!! )"; + } + } + + var run = new Run($"{operName}{potentialText} "); + var foreground = GetColorByStarWithOpacity(operLevel, isMaxPot ? 0.4 : 1.0); + if (foreground != null) + { + run.Foreground = foreground; + } + + recruitResultInlines.Add(run); + } + + recruitResultInlines.Add(new LineBreak()); + recruitResultInlines.Add(new LineBreak()); + } + + RecruitResultInlines = recruitResultInlines; + return; + + SolidColorBrush GetBrushWithOpacity(Color baseColor, double opacity) + { + byte alpha = (byte)(opacity * 255); + return new(Color.FromArgb(alpha, baseColor.R, baseColor.G, baseColor.B)); + } + + Brush? GetColorByStarWithOpacity(int level, double opacity = 1.0) + { + var brushKey = level switch + { + >= 6 => UiLogColor.Star6Operator, + 5 => UiLogColor.Star5Operator, + 4 => UiLogColor.Star4Operator, + 3 => UiLogColor.Star3Operator, + 2 => UiLogColor.Star2Operator, + _ => UiLogColor.Star1Operator, + }; + + var brush = Application.Current.TryFindResource(brushKey) as SolidColorBrush; + if (brush == null) + { + return null; + } + + var baseColor = brush.Color; + return GetBrushWithOpacity(baseColor, opacity); + } } private bool _chooseLevel3 = Convert.ToBoolean(ConfigurationHelper.GetValue(ConfigurationKeys.ChooseLevel3, bool.FalseString)); @@ -205,7 +292,6 @@ namespace MaaWpfGui.ViewModels.UI } RecruitInfo = LocalizationHelper.GetString("Identifying"); - RecruitResult = string.Empty; var levelList = new List(); @@ -277,44 +363,8 @@ namespace MaaWpfGui.ViewModels.UI case "RecruitResult": { - string resultContent = string.Empty; JArray? resultArray = (JArray?)subTaskDetails?["result"]; - /* int level = (int)subTaskDetails["level"]; */ - foreach (var combs in resultArray ?? []) - { - int tagLevel = (int)(combs["level"] ?? -1); - resultContent += tagLevel + "★ Tags: "; - resultContent = (((JArray?)combs["tags"]) ?? []).Aggregate(resultContent, (current, tag) => current + (tag + " ")); - - resultContent += "\n\t"; - foreach (var oper in (JArray?)combs["opers"] ?? []) - { - int operLevel = (int)(oper["level"] ?? -1); - var operId = oper["id"]?.ToString(); - var operName = DataHelper.GetLocalizedCharacterName(oper["name"]?.ToString()); - - string potential = string.Empty; - - if (RecruitmentShowPotential && OperBoxPotential != null && operId != null - && (tagLevel >= 4 || operLevel == 1)) - { - if (OperBoxPotential.ContainsKey(operId)) - { - potential = " ( " + OperBoxPotential[operId] + " )"; - } - else - { - potential = " ( !!! NEW !!! )"; - } - } - - resultContent += operLevel + "★ " + operName + potential + " "; - } - - resultContent += "\n\n"; - } - - RecruitResult = resultContent; + UpdateRecruitResult(resultArray); } break; diff --git a/src/MaaWpfGui/Views/UI/RecognizerView.xaml b/src/MaaWpfGui/Views/UI/RecognizerView.xaml index fbf8c2af86..dc947192fe 100644 --- a/src/MaaWpfGui/Views/UI/RecognizerView.xaml +++ b/src/MaaWpfGui/Views/UI/RecognizerView.xaml @@ -41,15 +41,21 @@ VerticalAlignment="Top" Focusable="True" FontSize="14" + ForceCursor="False" Style="{StaticResource TextBlockDefaultBold}" Text="{Binding RecruitInfo}" TextWrapping="Wrap" /> - + + +