diff --git a/src/Views/CommitSubjectPresenter.cs b/src/Views/CommitSubjectPresenter.cs index 694907274..30ad67990 100644 --- a/src/Views/CommitSubjectPresenter.cs +++ b/src/Views/CommitSubjectPresenter.cs @@ -3,17 +3,36 @@ using System.Collections.Specialized; using System.Globalization; using System.Text.RegularExpressions; +using System.Threading.Tasks; using Avalonia; using Avalonia.Collections; using Avalonia.Controls; using Avalonia.Input; +using Avalonia.Interactivity; using Avalonia.Media; +using Avalonia.VisualTree; namespace SourceGit.Views { public partial class CommitSubjectPresenter : Control { + public static readonly StyledProperty FullMessageProperty = + AvaloniaProperty.Register(nameof(FullMessage)); + + public string FullMessage + { + get => GetValue(FullMessageProperty); + set => SetValue(FullMessageProperty, value); + } + + public CommitSubjectPresenter() + { + ToolTip.SetShowDelay(this, 1000); + ToolTip.SetBetweenShowDelay(this, -1); + ToolTip.AddToolTipOpeningHandler(this, OnToolTipOpening); + } + public static readonly StyledProperty FontFamilyProperty = AvaloniaProperty.Register(nameof(FontFamily)); @@ -175,6 +194,11 @@ protected override void OnPropertyChanged(AvaloniaPropertyChangedEventArgs chang _needRebuildInlines = true; GenerateInlineElements(); InvalidateVisual(); + UpdateMessageToolTip(); + } + else if (change.Property == FullMessageProperty) + { + UpdateMessageToolTip(); } else if (change.Property == IssueTrackersProperty) { @@ -239,6 +263,45 @@ protected override void OnPointerExited(PointerEventArgs e) ClearHoveredIssueLink(); } + protected override void OnDataContextChanged(EventArgs e) + { + base.OnDataContextChanged(e); + + ToolTip.SetIsOpen(this, false); + _fullMessageTask = null; + ClearHoveredIssueLink(); + UpdateMessageToolTip(); + } + + protected override void OnDetachedFromVisualTree(VisualTreeAttachmentEventArgs e) + { + ToolTip.SetIsOpen(this, false); + ClearHoveredIssueLink(); + base.OnDetachedFromVisualTree(e); + } + + private async void OnToolTipOpening(object sender, CancelRoutedEventArgs e) + { + if (e.Cancel || _lastHover != null || !string.IsNullOrEmpty(FullMessage)) + return; + + if (DataContext is not Models.Commit commit || + this.FindAncestorOfType()?.DataContext is not ViewModels.Histories histories) + return; + + var task = _fullMessageTask ??= histories.GetCommitFullMessageAsync(commit); + var message = await task; + if (_fullMessageTask == task && !string.IsNullOrEmpty(message)) + _messageToolTip.Text = message; + } + + private void UpdateMessageToolTip() + { + _messageToolTip.Text = string.IsNullOrEmpty(FullMessage) ? Subject : FullMessage; + if (_lastHover == null) + ToolTip.SetTip(this, string.IsNullOrEmpty(Subject) ? null : _messageToolTip); + } + private void OnIssueTrackersChanged(object sender, NotifyCollectionChangedEventArgs e) { _needRebuildInlines = true; @@ -401,10 +464,12 @@ private void ClearHoveredIssueLink() { if (_lastHover != null) { - ToolTip.SetTip(this, null); SetCurrentValue(CursorProperty, Cursor.Parse("Arrow")); _lastHover = null; } + + if (!ReferenceEquals(ToolTip.GetTip(this), _messageToolTip)) + UpdateMessageToolTip(); } [GeneratedRegex(@"`.*?`")] @@ -425,6 +490,8 @@ public Inline(double x, FormattedText text, Models.InlineElement elem) } private string _subject = string.Empty; + private readonly TextBlock _messageToolTip = new() { MaxWidth = 640, TextWrapping = TextWrapping.Wrap }; + private Task _fullMessageTask = null; private AvaloniaList _issueTrackers = null; private Models.InlineElementCollector _elements = new(); private Models.InlineElement _lastHover = null; diff --git a/src/Views/InteractiveRebase.axaml b/src/Views/InteractiveRebase.axaml index af9acc49c..04a556664 100644 --- a/src/Views/InteractiveRebase.axaml +++ b/src/Views/InteractiveRebase.axaml @@ -170,6 +170,7 @@ Foreground="{DynamicResource Brush.FG1}" LinkForeground="{DynamicResource Brush.Link}" Subject="{Binding Subject}" + FullMessage="{Binding FullMessage}" IssueTrackers="{Binding $parent[v:InteractiveRebase].((vm:InteractiveRebase)DataContext).IssueTrackers}" FontWeight="Normal" Opacity="{Binding Action, Mode=OneWay, Converter={x:Static c:InteractiveRebaseActionConverters.ToOpacity}}"