Forge
csharpdeeb25a2
1using System.Globalization;
2using Avalonia;
3using Avalonia.Media;
4using static CascadeIDE.Cockpit.PrimitivesKit.CockpitPrimitivesPalette.Annunciator;
5
6namespace CascadeIDE.Cockpit.PrimitivesKit;
7
8/// <summary>
9/// Task cockpit: блокировка сплиттеров (мелодия/бренд TOL; на линзе GND = «на земле» можно двигать границы, IN AIR = зафиксировано) в том же визуальном языке, что <see cref="CommandArmedStripLampFace"/>.
10/// </summary>
11public readonly record struct WorkspaceSplittersTolLampFace(bool SplittersLocked)
12{
13 /// <summary>true = IN AIR (заблокировано), false = ON GND (сплиттеры можно двигать).</summary>
14 public void Draw(DrawingContext context, Rect outerRect)
15 {
16 AnnunciatorLampChrome.DrawCellHousing(context, outerRect);
17
18 var face = AnnunciatorLampChrome.ComputeFaceSquare(outerRect);
19
20 var faceBase = new LinearGradientBrush
21 {
22 StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
23 EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
24 GradientStops =
25 {
26 new GradientStop(OffLensTop, 0),
27 new GradientStop(OffLensBottom, 1),
28 },
29 };
30 context.DrawRectangle(faceBase, new Pen(new SolidColorBrush(OffLensBorder), 0.75), face);
31
32 // Полоса чуть ниже, чем у CMD, чтобы над ней осталась вертикаль на две строки (7pt в две линии не влезали → текст не рисовался).
33 var barH = Math.Max(5.0, face.Height * 0.22);
34 var padX = Math.Max(2.0, face.Width * 0.08);
35 var barY = face.Bottom - barH - 2;
36 var barRect = new Rect(face.X + padX, barY, face.Width - 2 * padX, barH);
37 var textBandBottomY = barRect.Y - 2;
38
39 if (SplittersLocked)
40 {
41 var g = CommandArmedStripGreen;
42 var gTop = AnnunciatorLampChrome.Lighten(g, 0.18);
43 var gBot = AnnunciatorLampChrome.Darken(g, 0.22);
44 var barBrush = 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(gTop, 0),
51 new GradientStop(g, 0.5),
52 new GradientStop(gBot, 1),
53 },
54 };
55 context.DrawRectangle(barBrush, new Pen(Brushes.Black, 0.5), barRect);
56 DrawTolTwoLineLabelInFace(
57 context,
58 face,
59 textBandBottomY,
60 "IN",
61 "AIR",
62 Brushes.White,
63 new SolidColorBrush(OutlinedTextStrokeLit));
64 }
65 else
66 {
67 var r = Color.Parse("#C62828");
68 var rTop = AnnunciatorLampChrome.Lighten(r, 0.12);
69 var rBot = AnnunciatorLampChrome.Darken(r, 0.2);
70 var barBrush = new LinearGradientBrush
71 {
72 StartPoint = new RelativePoint(0, 0, RelativeUnit.Relative),
73 EndPoint = new RelativePoint(0, 1, RelativeUnit.Relative),
74 GradientStops =
75 {
76 new GradientStop(rTop, 0),
77 new GradientStop(r, 0.5),
78 new GradientStop(rBot, 1),
79 },
80 };
81 context.DrawRectangle(barBrush, new Pen(Brushes.Black, 0.5), barRect);
82 var amber = new SolidColorBrush(CommandArmedLabelAmber);
83 var stroke = new SolidColorBrush(OutlinedTextStrokeLit);
84 DrawTolTwoLineLabelInFace(
85 context,
86 face,
87 textBandBottomY,
88 "ON",
89 "GND",
90 amber,
91 stroke);
92 }
93 }
94
95 /// <summary>Кегль подбирается по вертикали, чтобы в узкой зоне над полосой текст не исчезал целиком.</summary>
96 private static void DrawTolTwoLineLabelInFace(
97 DrawingContext context,
98 Rect face,
99 double labelBottomY,
100 string line1,
101 string line2,
102 IBrush fillBrush,
103 IBrush strokeBrush)
104 {
105 if (labelBottomY <= face.Y + 2)
106 return;
107
108 const double lineGap = 0.4;
109 var bandTop = face.Y + 2;
110 var available = labelBottomY - bandTop;
111 if (available <= 0)
112 return;
113
114 ReadOnlySpan<double> trySizes = [5.5, 5.0, 4.5, 4.0, 3.5];
115 foreach (var fontSize in trySizes)
116 {
117 var (ft1Fill, ft1Stroke, ft2Fill, ft2Stroke) = BuildTolLineFormatted(
118 line1, line2, fontSize, fillBrush, strokeBrush);
119 var totalH = ft1Fill.Height + lineGap + ft2Fill.Height;
120 if (totalH > available)
121 continue;
122
123 var y = bandTop + (available - totalH) / 2;
124 var x1 = face.X + (face.Width - ft1Fill.Width) / 2;
125 AnnunciatorLampChrome.DrawOutlinedText(context, ft1Stroke, ft1Fill, new Point(x1, y));
126 y += ft1Fill.Height + lineGap;
127 var x2 = face.X + (face.Width - ft2Fill.Width) / 2;
128 AnnunciatorLampChrome.DrawOutlinedText(context, ft2Stroke, ft2Fill, new Point(x2, y));
129 return;
130 }
131 }
132
133 private static (FormattedText Ft1Fill, FormattedText Ft1Stroke, FormattedText Ft2Fill, FormattedText Ft2Stroke) BuildTolLineFormatted(
134 string line1,
135 string line2,
136 double fontSize,
137 IBrush fillBrush,
138 IBrush strokeBrush)
139 {
140 var ft1Fill = new FormattedText(
141 line1,
142 CultureInfo.InvariantCulture,
143 FlowDirection.LeftToRight,
144 AnnunciatorLampChrome.LabelTypeface,
145 fontSize,
146 fillBrush);
147 var ft1Stroke = new FormattedText(
148 line1,
149 CultureInfo.InvariantCulture,
150 FlowDirection.LeftToRight,
151 AnnunciatorLampChrome.LabelTypeface,
152 fontSize,
153 strokeBrush);
154 var ft2Fill = new FormattedText(
155 line2,
156 CultureInfo.InvariantCulture,
157 FlowDirection.LeftToRight,
158 AnnunciatorLampChrome.LabelTypeface,
159 fontSize,
160 fillBrush);
161 var ft2Stroke = new FormattedText(
162 line2,
163 CultureInfo.InvariantCulture,
164 FlowDirection.LeftToRight,
165 AnnunciatorLampChrome.LabelTypeface,
166 fontSize,
167 strokeBrush);
168 return (ft1Fill, ft1Stroke, ft2Fill, ft2Stroke);
169 }
170}
171
View only · write via MCP/CIDE