| 1 | using System.Reflection; |
| 2 | using System.Text.Json; |
| 3 | using System.Text.Json.Serialization; |
| 4 | using Avalonia; |
| 5 | using Avalonia.Controls; |
| 6 | using Avalonia.Media; |
| 7 | |
| 8 | namespace CascadeIDE.Services; |
| 9 | |
| 10 | /// <summary> |
| 11 | /// Цвета элемента под курсором (хит-тест по последней позиции указателя). Вызывать из UI-потока. |
| 12 | /// Для ide_get_colors_under_cursor — мгновенный фон и текст под мышью. |
| 13 | /// Учитываются все открытые окна IDE (главное, настройки, превью и т.д.). |
| 14 | /// </summary> |
| 15 | public static class UiColorsUnderCursor |
| 16 | { |
| 17 | private static readonly JsonSerializerOptions Options = new() |
| 18 | { |
| 19 | WriteIndented = true, |
| 20 | DefaultIgnoreCondition = JsonIgnoreCondition.WhenWritingNull |
| 21 | }; |
| 22 | |
| 23 | /// <summary>Собрать JSON: тип, имя, background_hex, foreground_hex элемента под курсором. |
| 24 | /// Перебирает все открытые окна приложения и возвращает элемент из того окна, под курсором которого есть Control.</summary> |
| 25 | public static string GetJson(TopLevel topLevel) |
| 26 | { |
| 27 | var control = FindControlUnderCursor(topLevel); |
| 28 | if (control is null) |
| 29 | return JsonSerializer.Serialize(new { hint = "Нет элемента под курсором или не Control." }, Options); |
| 30 | |
| 31 | var name = (control as StyledElement)?.Name ?? ""; |
| 32 | var bgHex = BrushToHex(GetBrush(control, "Background")); |
| 33 | var fgHex = BrushToHex(GetBrush(control, "Foreground")); |
| 34 | var (effectiveBg, effectiveFg) = UiControlAppearance.GetEffectiveColors(control); |
| 35 | |
| 36 | var obj = new Dictionary<string, object?> |
| 37 | { |
| 38 | ["type"] = control.GetType().Name, |
| 39 | ["name"] = name, |
| 40 | ["background"] = bgHex, |
| 41 | ["foreground"] = fgHex, |
| 42 | ["effective_background"] = effectiveBg, |
| 43 | ["effective_foreground"] = effectiveFg |
| 44 | }; |
| 45 | return JsonSerializer.Serialize(obj, Options); |
| 46 | } |
| 47 | |
| 48 | private static Control? FindControlUnderCursor(TopLevel fallbackTopLevel) => |
| 49 | UiPointerClientPosition.TryGetPointerOverControlAnywhere() |
| 50 | ?? UiPointerClientPosition.TryGetControlUnderPointer(fallbackTopLevel); |
| 51 | |
| 52 | private static IBrush? GetBrush(Control control, string propertyName) |
| 53 | { |
| 54 | var prop = control.GetType().GetProperty(propertyName); |
| 55 | return prop?.GetValue(control) as IBrush; |
| 56 | } |
| 57 | |
| 58 | private static string? BrushToHex(IBrush? brush) |
| 59 | { |
| 60 | if (brush is not SolidColorBrush scb) |
| 61 | return null; |
| 62 | var c = scb.Color; |
| 63 | return $"#{c.A:X2}{c.R:X2}{c.G:X2}{c.B:X2}"; |
| 64 | } |
| 65 | } |
| 66 | |