Forge
csharpdeeb25a2
1#nullable enable
2using CascadeIDE.Views.SkiaKit;
3using SkiaSharp;
4
5namespace CascadeIDE.Views.Chat;
6
7/// <summary>
8/// Command Deck: composer + CCL + slash popup в одном нижнем блоке (ADR 0138).
9/// Подсказки не рисуются над лентой — только внутри deck, лента отступает на <see cref="Layout.TotalHeight"/>.
10/// </summary>
11internal static class SkiaIntercomCommandDeckLayout
12{
13 public const float SectionGap = 2f;
14 public const float PopupHorizontalInset = 8f;
15 public const float PopupInnerPadding = 4f;
16
17 public readonly record struct Layout(
18 float TotalHeight,
19 SKRect DeckBounds,
20 SKRect ComposerBounds,
21 SKRect CommandLineBounds,
22 SKRect SlashPopupBounds)
23 {
24 public bool HasDeck => DeckBounds.Width > 0 && DeckBounds.Height > 0;
25 }
26
27 public static Layout Compute(
28 float surfaceWidth,
29 float surfaceBottom,
30 bool showComposer,
31 bool showCommandLine,
32 string? commandLinePreview,
33 string composerText,
34 bool showSlashPopup,
35 int slashRowCount,
36 string? composerPreeditText = null,
37 bool showSlashHierarchyHeader = false,
38 float composerFontSize = 12f,
39 float composerLineHeight = 17f,
40 string? composerSlashPreview = null,
41 float composerSlashPreviewFontSize = 10f,
42 float commandLineFontSize = 12f,
43 float commandLinePreviewFontSize = 10f)
44 {
45 if (!showComposer || surfaceWidth <= 0f)
46 return default;
47
48 var contentWidth = Math.Max(
49 40f,
50 surfaceWidth - SkiaComposerStrip.HorizontalPadding * 2 - SkiaComposerStrip.SendButtonWidth - 24f);
51 var composerHeight = SkiaComposerStrip.MeasureHeight(
52 composerText,
53 composerPreeditText,
54 contentWidth,
55 composerFontSize,
56 composerLineHeight,
57 composerSlashPreview,
58 composerSlashPreviewFontSize);
59 var commandLineHeight = showCommandLine
60 ? SkiaCommandLineStrip.MeasureHeight(commandLinePreview, commandLineFontSize, commandLinePreviewFontSize)
61 : 0f;
62 var popupHeight = showSlashPopup && slashRowCount > 0
63 ? SkiaPopupList.MeasureHeight(slashRowCount, showSlashHierarchyHeader) + PopupInnerPadding
64 : 0f;
65
66 var cursor = surfaceBottom;
67 var composerTop = cursor - composerHeight;
68 var composerBounds = new SKRect(0f, composerTop, surfaceWidth, cursor);
69 cursor = composerTop - SectionGap;
70
71 var commandLineBounds = default(SKRect);
72 if (commandLineHeight > 0f)
73 {
74 var cclBottom = cursor;
75 var cclTop = cclBottom - commandLineHeight;
76 commandLineBounds = new SKRect(0f, cclTop, surfaceWidth, cclBottom);
77 cursor = cclTop - SectionGap;
78 }
79
80 var slashPopupBounds = default(SKRect);
81 float deckTop;
82 if (popupHeight > 0f)
83 {
84 var popupBottom = cursor;
85 var popupTop = popupBottom - popupHeight;
86 slashPopupBounds = new SKRect(
87 PopupHorizontalInset,
88 popupTop,
89 surfaceWidth - PopupHorizontalInset,
90 popupBottom);
91 deckTop = popupTop;
92 }
93 else
94 deckTop = commandLineHeight > 0f ? commandLineBounds.Top : composerBounds.Top;
95
96 var bottom = surfaceBottom;
97 var deckBounds = new SKRect(0f, deckTop, surfaceWidth, bottom);
98 var totalHeight = bottom - deckTop;
99 return new Layout(totalHeight, deckBounds, composerBounds, commandLineBounds, slashPopupBounds);
100 }
101
102 public static float MeasureTotalHeight(
103 float surfaceWidth,
104 bool showComposer,
105 bool showCommandLine,
106 string? commandLinePreview,
107 string composerText,
108 bool showSlashPopup,
109 int slashRowCount,
110 string? composerPreeditText = null,
111 bool showSlashHierarchyHeader = false,
112 float composerFontSize = 12f,
113 float composerLineHeight = 17f,
114 string? composerSlashPreview = null,
115 float composerSlashPreviewFontSize = 10f,
116 float commandLineFontSize = 12f,
117 float commandLinePreviewFontSize = 10f) =>
118 Compute(
119 surfaceWidth,
120 surfaceBottom: 0f,
121 showComposer,
122 showCommandLine,
123 commandLinePreview,
124 composerText,
125 showSlashPopup,
126 slashRowCount,
127 composerPreeditText,
128 showSlashHierarchyHeader,
129 composerFontSize,
130 composerLineHeight,
131 composerSlashPreview,
132 composerSlashPreviewFontSize,
133 commandLineFontSize,
134 commandLinePreviewFontSize)
135 .TotalHeight;
136
137 public static void DrawDeckChrome(SKCanvas canvas, SKRect deckBounds, ISkiaKitPaintTheme theme)
138 {
139 if (deckBounds.Width <= 0f || deckBounds.Height <= 0f)
140 return;
141
142 using var fill = new SKPaint
143 {
144 Color = SkiaKitColor.Blend(theme.Surface, new SKColor(40, 48, 58), 0.06f),
145 IsAntialias = true,
146 };
147 canvas.DrawRect(deckBounds, fill);
148
149 using var topEdge = new SKPaint
150 {
151 Color = theme.Border,
152 IsAntialias = true,
153 StrokeWidth = 1f,
154 };
155 canvas.DrawLine(deckBounds.Left, deckBounds.Top + 0.5f, deckBounds.Right, deckBounds.Top + 0.5f, topEdge);
156 }
157}
158
View only · write via MCP/CIDE