Forge
csharpcf25d736
1#nullable enable
2using Avalonia;
3using CascadeIDE.ViewModels;
4
5namespace CascadeIDE.Services.CodeNavigation;
6
7/// <summary>Стабильные id внутренних блоков прибора карты намерений (ADR 0088 §2.4) — не путать с <c>cell_id</c> deck региона.</summary>
8public static class CodeNavigationMapInstrumentBlockIds
9{
10 public const string Graph = "code_navigation.pfd_instrument.block.graph";
11 public const string Legend = "code_navigation.pfd_instrument.block.legend";
12}
13
14/// <summary>Вид внутреннего блока кабинного прибора (граф control flow / легенда — домен CodeNavigation).</summary>
15public enum CodeNavigationMapInstrumentBlockKind
16{
17 /// <summary>Подграф (узлы, рёбра) в зарезервированной области графа.</summary>
18 Graph = 0,
19
20 /// <summary>Легенда (индексы шагов, ключи фигур, стили рёбер).</summary>
21 Legend = 1
22}
23
24/// <summary>Размещение одного внутреннего блока в системе координат мини-карты (0,0 — левый верх вьюпорта).</summary>
25public sealed record CodeNavigationMapInstrumentBlockDescriptor(
26 string Id,
27 CodeNavigationMapInstrumentBlockKind Kind,
28 Rect Bounds)
29{
30 public bool IsEmpty => Bounds.Width <= 0 || Bounds.Height <= 0;
31}
32
33/// <summary>
34/// Композитор <b>внутренних</b> блоков прибора: по уже уложенной <see cref="CodeNavigationMapGraphSceneVm"/> и размеру вьюпорта
35/// вычисляет прямоугольники «граф / легенда» (тот же смысл, что разнесение в отрисовке сцены).
36/// </summary>
37public static class CodeNavigationMapInstrumentBlockCompositor
38{
39 public static IReadOnlyList<CodeNavigationMapInstrumentBlockDescriptor> Compose(
40 CodeNavigationMapGraphSceneVm scene,
41 double viewportWidth,
42 double viewportHeight)
43 {
44 if (scene.IsEmpty
45 || !double.IsFinite(viewportWidth)
46 || !double.IsFinite(viewportHeight)
47 || viewportWidth <= 0
48 || viewportHeight <= 0)
49 return Array.Empty<CodeNavigationMapInstrumentBlockDescriptor>();
50
51 if (!scene.UseLegendColumn)
52 {
53 return
54 [
55 new CodeNavigationMapInstrumentBlockDescriptor(
56 CodeNavigationMapInstrumentBlockIds.Graph,
57 CodeNavigationMapInstrumentBlockKind.Graph,
58 new Rect(0, 0, viewportWidth, viewportHeight))
59 ];
60 }
61
62 if (scene.LegendPlacement == CodeNavigationMapLegendBlockPlacement.BelowGraph
63 && scene.LegendBlockTopY > 0
64 && scene.LegendBlockTopY < viewportHeight)
65 {
66 var graphH = Math.Min(scene.LegendBlockTopY, viewportHeight);
67 return
68 [
69 new CodeNavigationMapInstrumentBlockDescriptor(
70 CodeNavigationMapInstrumentBlockIds.Graph,
71 CodeNavigationMapInstrumentBlockKind.Graph,
72 new Rect(0, 0, viewportWidth, graphH)),
73 new CodeNavigationMapInstrumentBlockDescriptor(
74 CodeNavigationMapInstrumentBlockIds.Legend,
75 CodeNavigationMapInstrumentBlockKind.Legend,
76 new Rect(0, scene.LegendBlockTopY, viewportWidth, viewportHeight - scene.LegendBlockTopY))
77 ];
78 }
79
80 // Соседняя колонка: легенда справа от <see cref="CodeNavigationMapGraphSceneVm.LegendColumnLeft"/>
81 var legendX = Math.Min(scene.LegendColumnLeft, viewportWidth);
82 if (legendX >= viewportWidth - 1)
83 {
84 return
85 [
86 new CodeNavigationMapInstrumentBlockDescriptor(
87 CodeNavigationMapInstrumentBlockIds.Graph,
88 CodeNavigationMapInstrumentBlockKind.Graph,
89 new Rect(0, 0, viewportWidth, viewportHeight))
90 ];
91 }
92
93 var graphW = Math.Max(0, legendX);
94 return
95 [
96 new CodeNavigationMapInstrumentBlockDescriptor(
97 CodeNavigationMapInstrumentBlockIds.Graph,
98 CodeNavigationMapInstrumentBlockKind.Graph,
99 new Rect(0, 0, graphW, viewportHeight)),
100 new CodeNavigationMapInstrumentBlockDescriptor(
101 CodeNavigationMapInstrumentBlockIds.Legend,
102 CodeNavigationMapInstrumentBlockKind.Legend,
103 new Rect(legendX, 0, viewportWidth - legendX, viewportHeight))
104 ];
105 }
106}
107
View only · write via MCP/CIDE