| 1 | #nullable enable |
| 2 | using CascadeIDE.Features.Chat; |
| 3 | using CascadeIDE.Views.SkiaKit; |
| 4 | using SkiaSharp; |
| 5 | |
| 6 | namespace CascadeIDE.Views.Chat.Skia; |
| 7 | |
| 8 | /// <summary>Интерактивный список/дерево тем после <c>/topic list|tree</c>.</summary> |
| 9 | internal sealed class SkiaChatTopicPickerEntity( |
| 10 | TopicPickerPresentation mode, |
| 11 | IReadOnlyList<ChatThreadNode> threads, |
| 12 | IReadOnlyDictionary<Guid, int> messageCounts) : ISkiaChatEntity |
| 13 | { |
| 14 | private const float Padding = 10f; |
| 15 | private const float RowHeight = 34f; |
| 16 | private const float RowGap = 4f; |
| 17 | private const float IndentPerDepth = 14f; |
| 18 | |
| 19 | private readonly IReadOnlyList<ChatThreadPresentation.PickerRow> _rows = |
| 20 | ChatThreadPresentation.BuildPickerRows(mode, threads, messageCounts); |
| 21 | |
| 22 | public SkiaChatMeasuredLayout Measure(SkiaChatMeasureContext context) |
| 23 | { |
| 24 | if (_rows.Count == 0) |
| 25 | return new SkiaChatMeasuredLayout(40f, 8f); |
| 26 | |
| 27 | var height = Padding + 20f + _rows.Count * RowHeight + (_rows.Count - 1) * RowGap + Padding; |
| 28 | return new SkiaChatMeasuredLayout(height, 10f); |
| 29 | } |
| 30 | |
| 31 | public void Draw(SkiaChatDrawContext context, float top, in SkiaChatMeasuredLayout layout) |
| 32 | { |
| 33 | var rect = new SKRect(context.ContentLeft, top, context.ContentLeft + context.ContentWidth, top + layout.Height); |
| 34 | using var panelFill = new SKPaint |
| 35 | { |
| 36 | Color = SkiaKitColor.Blend(context.Theme.Surface, context.Theme.Border, 0.12f), |
| 37 | IsAntialias = true, |
| 38 | }; |
| 39 | context.Canvas.DrawRoundRect(rect, 8, 8, panelFill); |
| 40 | |
| 41 | using var headerFont = new SKFont(SKTypeface.FromFamilyName("Segoe UI", SKFontStyle.Bold), 12f); |
| 42 | using var headerPaint = new SKPaint { IsAntialias = true, Color = context.Theme.MutedContent }; |
| 43 | var header = mode == TopicPickerPresentation.Tree |
| 44 | ? "Дерево тем — клик для открытия" |
| 45 | : "Список тем — клик для открытия"; |
| 46 | context.Canvas.DrawText(header, rect.Left + Padding, rect.Top + Padding + 12f, SKTextAlign.Left, headerFont, headerPaint); |
| 47 | |
| 48 | var y = rect.Top + Padding + 20f; |
| 49 | foreach (var row in _rows) |
| 50 | { |
| 51 | var rowRect = new SKRect(rect.Left + Padding, y, rect.Right - Padding, y + RowHeight); |
| 52 | using var rowFill = new SKPaint |
| 53 | { |
| 54 | Color = SkiaKitColor.Blend(context.Theme.Surface, context.Theme.Border, 0.2f), |
| 55 | IsAntialias = true, |
| 56 | }; |
| 57 | context.Canvas.DrawRoundRect(rowRect, 6, 6, rowFill); |
| 58 | |
| 59 | using var titleFont = new SKFont(SKTypeface.FromFamilyName("Segoe UI", SKFontStyle.Normal), 12.5f); |
| 60 | using var titlePaint = new SKPaint { IsAntialias = true, Color = context.Theme.Content }; |
| 61 | var titleX = rowRect.Left + 8f + row.Depth * IndentPerDepth; |
| 62 | context.Canvas.DrawText(row.Title, titleX, rowRect.MidY + 4f, SKTextAlign.Left, titleFont, titlePaint); |
| 63 | |
| 64 | using var metaFont = new SKFont(SKTypeface.FromFamilyName("Segoe UI", SKFontStyle.Normal), 10.5f); |
| 65 | using var metaPaint = new SKPaint { IsAntialias = true, Color = context.Theme.MutedContent }; |
| 66 | context.Canvas.DrawText(row.Meta, rowRect.Right - 8f, rowRect.MidY + 4f, SKTextAlign.Right, metaFont, metaPaint); |
| 67 | |
| 68 | context.RegisterHit(rowRect, new SkiaChatHit(null, row.ThreadId, ResetDetailMode: false)); |
| 69 | y += RowHeight + RowGap; |
| 70 | } |
| 71 | } |
| 72 | |
| 73 | public SkiaChatHit? CreateHit(in SkiaChatMeasuredLayout layout) => null; |
| 74 | } |
| 75 | |