| 1 | using System.Globalization; |
| 2 | using System.Text.Json; |
| 3 | using Avalonia; |
| 4 | using Avalonia.Controls; |
| 5 | using Avalonia.Controls.ApplicationLifetimes; |
| 6 | using CascadeIDE.Cockpit.Surface; |
| 7 | using CascadeIDE.Services; |
| 8 | |
| 9 | namespace CascadeIDE.Views; |
| 10 | |
| 11 | public partial class MainWindow |
| 12 | { |
| 13 | private Task<string> CaptureWindowForMcpCoreAsync(string? workspacePath, string? outputRelativePath, string? scope) |
| 14 | { |
| 15 | if (string.Equals(scope?.Trim(), "all", StringComparison.OrdinalIgnoreCase)) |
| 16 | return Task.FromResult(CaptureAllIdeWindowsJson(workspacePath, outputRelativePath)); |
| 17 | |
| 18 | var (bytes, w, h) = IdeWindowScreenshot.CaptureWindowPng(this); |
| 19 | string? saved = null; |
| 20 | if (!string.IsNullOrWhiteSpace(workspacePath) && !string.IsNullOrWhiteSpace(outputRelativePath)) |
| 21 | saved = IdeWindowScreenshot.TrySaveUnderWorkspace(workspacePath, outputRelativePath, bytes); |
| 22 | var json = IdeWindowScreenshot.BuildCaptureJson(bytes, w, h, saved); |
| 23 | return Task.FromResult(json); |
| 24 | } |
| 25 | |
| 26 | private string CaptureAllIdeWindowsJson(string? workspacePath, string? outputRelativePath) |
| 27 | { |
| 28 | var options = new JsonSerializerOptions { WriteIndented = true }; |
| 29 | |
| 30 | if (Application.Current?.ApplicationLifetime is not IClassicDesktopStyleApplicationLifetime desktop) |
| 31 | { |
| 32 | var (b, w, h) = IdeWindowScreenshot.CaptureWindowPng(this); |
| 33 | string? s = null; |
| 34 | if (!string.IsNullOrWhiteSpace(workspacePath) && !string.IsNullOrWhiteSpace(outputRelativePath)) |
| 35 | s = IdeWindowScreenshot.TrySaveUnderWorkspace(workspacePath, outputRelativePath, b); |
| 36 | var one = new[] |
| 37 | { |
| 38 | new |
| 39 | { |
| 40 | role = "main", |
| 41 | window_type = GetType().Name, |
| 42 | title = Title ?? "", |
| 43 | format = "png_base64", |
| 44 | width = w, |
| 45 | height = h, |
| 46 | data = Convert.ToBase64String(b), |
| 47 | saved_path = s |
| 48 | } |
| 49 | }; |
| 50 | return JsonSerializer.Serialize(new { format = "png_multi_window", windows = one }, options); |
| 51 | } |
| 52 | |
| 53 | var list = new List<object>(); |
| 54 | var idx = 0; |
| 55 | foreach (var w in desktop.Windows) |
| 56 | { |
| 57 | if (w is not Window win) |
| 58 | continue; |
| 59 | var (bytes, pw, ph) = IdeWindowScreenshot.CaptureWindowPng(win); |
| 60 | var saved = TrySaveIndexedCapture(workspacePath, outputRelativePath, idx, bytes); |
| 61 | var role = UiLayoutSnapshot.GetWindowRole(win, this); |
| 62 | list.Add(new |
| 63 | { |
| 64 | role, |
| 65 | window_type = win.GetType().Name, |
| 66 | title = win.Title ?? "", |
| 67 | format = "png_base64", |
| 68 | width = pw, |
| 69 | height = ph, |
| 70 | data = Convert.ToBase64String(bytes), |
| 71 | saved_path = saved |
| 72 | }); |
| 73 | idx++; |
| 74 | } |
| 75 | |
| 76 | return JsonSerializer.Serialize(new { format = "png_multi_window", windows = list }, options); |
| 77 | } |
| 78 | |
| 79 | private static string? TrySaveIndexedCapture(string? workspacePath, string? outputRelativePath, int index, byte[] pngBytes) |
| 80 | { |
| 81 | if (string.IsNullOrWhiteSpace(workspacePath) || string.IsNullOrWhiteSpace(outputRelativePath)) |
| 82 | return null; |
| 83 | var rel = outputRelativePath.Trim(); |
| 84 | if (rel.Contains("{n}", StringComparison.Ordinal)) |
| 85 | { |
| 86 | rel = rel.Replace("{n}", index.ToString(CultureInfo.InvariantCulture), StringComparison.Ordinal); |
| 87 | return IdeWindowScreenshot.TrySaveUnderWorkspace(workspacePath, rel, pngBytes); |
| 88 | } |
| 89 | |
| 90 | var sep = rel.Replace('/', Path.DirectorySeparatorChar); |
| 91 | var dir = Path.GetDirectoryName(sep); |
| 92 | var fileName = Path.GetFileName(sep); |
| 93 | var stem = Path.GetFileNameWithoutExtension(fileName); |
| 94 | if (string.IsNullOrEmpty(stem)) |
| 95 | stem = "ide-window"; |
| 96 | var ext = Path.GetExtension(fileName); |
| 97 | if (string.IsNullOrEmpty(ext)) |
| 98 | ext = ".png"; |
| 99 | var folder = string.IsNullOrEmpty(dir) ? "" : dir.TrimEnd(Path.DirectorySeparatorChar, Path.AltDirectorySeparatorChar) + Path.DirectorySeparatorChar; |
| 100 | var combined = $"{folder}{stem}-{index}{ext}"; |
| 101 | return IdeWindowScreenshot.TrySaveUnderWorkspace(workspacePath, combined, pngBytes); |
| 102 | } |
| 103 | } |
| 104 | |