using System; using System.Collections.Generic; using Avalonia; using Avalonia.Controls; using Avalonia.Media; namespace MinecraftClient.Tui { public sealed class TuiTooltipLine { public string Text { get; init; } = ""; public IBrush Foreground { get; init; } = Brushes.White; } /// /// Global tooltip that floats above all TUI content. /// Owned by MainTuiView, used by minimap / chat / other components. /// public sealed class TuiTooltipService { private readonly Panel _rootPanel; private readonly Canvas _canvas; private readonly Border _border; private readonly StackPanel _content; internal TuiTooltipService(Panel rootPanel) { _content = new StackPanel { Orientation = Avalonia.Layout.Orientation.Vertical }; _border = new Border { Background = new SolidColorBrush(Color.FromArgb(230, 20, 20, 20)), BorderBrush = new SolidColorBrush(Color.FromRgb(120, 120, 120)), BorderThickness = new Thickness(1), Padding = new Thickness(1), Child = _content, IsVisible = false, }; _canvas = new Canvas { IsHitTestVisible = false, Children = { _border }, }; _rootPanel = rootPanel; rootPanel.Children.Add(_canvas); } /// Global X of the mouse cursor. /// Global Y of the mouse cursor. /// /// If true, try placing tooltip to the right of mouseX; /// if false, try placing to the left. /// The service auto-flips when the tooltip would overflow the screen. /// public void Show(double mouseX, double mouseY, IReadOnlyList lines, bool preferRight = true) { _content.Children.Clear(); if (lines.Count == 0) { _border.IsVisible = false; return; } int maxChars = 0; foreach (var line in lines) { _content.Children.Add(new TextBlock { Text = line.Text, Foreground = line.Foreground, TextWrapping = TextWrapping.Wrap, Padding = new Thickness(0), Margin = new Thickness(0), FontSize = 1, }); if (line.Text.Length > maxChars) maxChars = line.Text.Length; } double tipW = maxChars + 4; double screenW = _rootPanel.Bounds.Width; const double gap = 1; double gx; if (preferRight) { gx = mouseX + gap; if (gx + tipW > screenW) gx = mouseX - tipW - gap; } else { gx = mouseX - tipW - gap; if (gx < 0) gx = mouseX + gap; } Canvas.SetLeft(_border, Math.Max(0, gx)); Canvas.SetTop(_border, Math.Max(0, mouseY)); _border.IsVisible = true; } public void Hide() { _border.IsVisible = false; _content.Children.Clear(); } public bool IsVisible => _border.IsVisible; } }