Forge
csharpdeeb25a2
1using Avalonia;
2using Avalonia.Input;
3using Avalonia.Media;
4using CascadeIDE.Cockpit.Cds;
5using CascadeIDE.ViewModels;
6
7namespace CascadeIDE.Views;
8
9/// <summary>
10/// Slot-aware scene renderer bound to runtime VM/CDS state.
11/// Visual output is intentionally minimal at this stage; the class primarily
12/// wires SkiaHost to real slot topology/state and pointer routing.
13/// </summary>
14public sealed class CockpitSkiaSceneRenderer : ISkiaSceneRenderer
15{
16 private readonly Func<MainWindowViewModel?> _vmProvider;
17 private readonly SkiaHostSurface _surface;
18
19 public CockpitSkiaSceneRenderer(Func<MainWindowViewModel?> vmProvider, SkiaHostSurface surface)
20 {
21 _vmProvider = vmProvider;
22 _surface = surface;
23 }
24
25 public void Render(DrawingContext context, Rect bounds, SkiaHostSlot slot)
26 {
27 var vm = _vmProvider();
28 if (vm is null || bounds.Width <= 0 || bounds.Height <= 0)
29 return;
30
31 var frame = BuildFrame(vm, slot, _surface, bounds);
32 if (!frame.Visible)
33 return;
34
35 // Slot visuals: Avalonia controls inside SkiaHost. SM: тонкий accent, когда related непустой (не рисуем список).
36 if (slot == SkiaHostSlot.Pfd && _surface == SkiaHostSurface.MainWindow
37 && vm.IsPfdRegionExpanded && vm.NavigationMap.WorkspaceNavigationMapHasRelated)
38 DrawCodeNavigationMapActiveAccent(context, bounds);
39
40 static void DrawCodeNavigationMapActiveAccent(DrawingContext ctx, Rect b)
41 {
42 const double w = 3;
43 var strip = new Rect(b.Left, b.Top, Math.Min(w, b.Width), b.Height);
44 var g = new LinearGradientBrush
45 {
46 StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
47 EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
48 GradientStops =
49 {
50 new GradientStop(Color.Parse("#7CC9FF"), 0),
51 new GradientStop(Color.Parse("#B3A5FF"), 0.55),
52 new GradientStop(Color.FromArgb(0, 179, 165, 255), 1)
53 }
54 };
55 ctx.DrawRectangle(g, null, strip);
56 }
57 }
58
59 public void OnPointerPressed(Point position, PointerPressedEventArgs e, SkiaHostSlot slot)
60 {
61 }
62
63 public void OnPointerMoved(Point position, PointerEventArgs e, SkiaHostSlot slot)
64 {
65 }
66
67 public void OnPointerReleased(Point position, PointerReleasedEventArgs e, SkiaHostSlot slot)
68 {
69 }
70
71 private static SkiaHostRenderFrame BuildFrame(
72 MainWindowViewModel vm,
73 SkiaHostSlot slot,
74 SkiaHostSurface surface,
75 Rect bounds)
76 {
77 var cds = vm.BuildCockpitSurfaceSnapshot();
78 var visible = slot switch
79 {
80 SkiaHostSlot.Pfd => surface == SkiaHostSurface.PfdHostWindow
81 ? vm.IsPfdHostWindowShellOpen
82 : cds.Zones.PfdVisible,
83 SkiaHostSlot.Forward => cds.Zones.ForwardVisible,
84 SkiaHostSlot.Mfd => surface == SkiaHostSurface.MfdHostWindow
85 ? vm.IsMfdHostWindowShellOpen
86 : cds.Zones.MfdVisible,
87 _ => true
88 };
89
90 return new SkiaHostRenderFrame(
91 slot,
92 surface,
93 cds.Topology.SurfaceKind,
94 vm.UiMode,
95 vm.SafetyLevel,
96 visible,
97 bounds);
98 }
99}
100
101public enum SkiaHostSurface
102{
103 MainWindow,
104 MfdHostWindow,
105 PfdHostWindow
106}
107
108public readonly record struct SkiaHostRenderFrame(
109 SkiaHostSlot Slot,
110 SkiaHostSurface Surface,
111 string SurfaceKind,
112 string UiMode,
113 string SafetyLevel,
114 bool Visible,
115 Rect Bounds);
116
View only · write via MCP/CIDE