컨텍스트 사용량 링 정렬 회귀 수정
원인: 하단 컨텍스트 사용량 트랙은 22x22 원형인데 arc는 center=15, radius=11 하드코딩으로 더 크게 그려져 오른쪽으로 밀려 보였습니다. 수정: TokenUsageTrack과 TokenUsageArc를 같은 크기와 가운데 정렬로 맞추고, 실제 트랙 지름과 스트로크 두께를 기준으로 중심점·반지름을 계산하는 helper를 추가했습니다. 크기 변경 시에도 arc가 다시 그려지도록 캐시 조건도 보강했습니다. 검증: dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\verify_token_ring_alignment\ -p:IntermediateOutputPath=obj\verify_token_ring_alignment\ (경고 0 / 오류 0), dotnet test src/AxCopilot.Tests/AxCopilot.Tests.csproj -c Release -v minimal --filter ChatWindowSlashPolicyTests -p:OutputPath=bin\verify_token_ring_alignment_tests\ -p:IntermediateOutputPath=obj\verify_token_ring_alignment_tests\ (통과 53)
This commit is contained in:
@@ -198,4 +198,21 @@ public class ChatWindowSlashPolicyTests
|
||||
var result = method!.Invoke(null, new object?[] { runTab });
|
||||
result.Should().Be(expected);
|
||||
}
|
||||
|
||||
[Theory]
|
||||
[InlineData(22, 2, 11, 10)]
|
||||
[InlineData(28, 2, 14, 13)]
|
||||
[InlineData(22, 0, 11, 11)]
|
||||
[InlineData(0, 2, 0, 0)]
|
||||
public void CalculateCircularRingMetrics_ShouldAlignCenterlineToTrack(
|
||||
double diameter,
|
||||
double strokeThickness,
|
||||
double expectedCenter,
|
||||
double expectedRadius)
|
||||
{
|
||||
var (center, radius) = ChatWindow.CalculateCircularRingMetrics(diameter, strokeThickness);
|
||||
|
||||
center.Should().Be(expectedCenter);
|
||||
radius.Should().Be(expectedRadius);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -138,7 +138,24 @@ public partial class ChatWindow
|
||||
|
||||
TokenUsageCard.ToolTip = null;
|
||||
|
||||
UpdateCircularUsageArc(TokenUsageArc, usageRatio, 15, 15, 11);
|
||||
var ringDiameter = ResolveTokenUsageRingDiameter();
|
||||
TokenUsageArc.Width = ringDiameter;
|
||||
TokenUsageArc.Height = ringDiameter;
|
||||
var (center, radius) = CalculateCircularRingMetrics(ringDiameter, TokenUsageArc.StrokeThickness);
|
||||
UpdateCircularUsageArc(TokenUsageArc, usageRatio, center, center, radius);
|
||||
}
|
||||
|
||||
private double ResolveTokenUsageRingDiameter()
|
||||
{
|
||||
var actual = TokenUsageTrack?.ActualWidth ?? 0;
|
||||
if (actual > 0)
|
||||
return actual;
|
||||
|
||||
var declared = TokenUsageTrack?.Width ?? 0;
|
||||
if (declared > 0)
|
||||
return declared;
|
||||
|
||||
return TokenUsageArc?.Width > 0 ? TokenUsageArc.Width : 22;
|
||||
}
|
||||
|
||||
private void TokenUsageCard_MouseEnter(object sender, MouseEventArgs e)
|
||||
|
||||
@@ -2673,7 +2673,8 @@
|
||||
MouseLeave="TokenUsageCard_MouseLeave">
|
||||
<Grid Width="28" Height="28">
|
||||
<!-- Ring track (subtle background ring) -->
|
||||
<Ellipse Width="22" Height="22"
|
||||
<Ellipse x:Name="TokenUsageTrack"
|
||||
Width="22" Height="22"
|
||||
Stroke="{DynamicResource BorderColor}"
|
||||
StrokeThickness="2"
|
||||
Opacity="0.45"
|
||||
@@ -2681,10 +2682,16 @@
|
||||
VerticalAlignment="Center"/>
|
||||
<!-- Usage arc (progress) -->
|
||||
<Path x:Name="TokenUsageArc"
|
||||
Width="22"
|
||||
Height="22"
|
||||
Stroke="{DynamicResource AccentColor}"
|
||||
StrokeThickness="2"
|
||||
StrokeStartLineCap="Round"
|
||||
StrokeEndLineCap="Round"/>
|
||||
StrokeEndLineCap="Round"
|
||||
Stretch="None"
|
||||
SnapsToDevicePixels="True"
|
||||
HorizontalAlignment="Center"
|
||||
VerticalAlignment="Center"/>
|
||||
<!-- Hidden data elements (referenced in code) -->
|
||||
<StackPanel Visibility="Collapsed">
|
||||
<TextBlock x:Name="TokenUsagePercentText"
|
||||
|
||||
@@ -7347,16 +7347,32 @@ public partial class ChatWindow : Window
|
||||
return value.ToString("N0");
|
||||
}
|
||||
|
||||
internal static (double Center, double Radius) CalculateCircularRingMetrics(double diameter, double strokeThickness)
|
||||
{
|
||||
var safeDiameter = Math.Max(0, diameter);
|
||||
var safeStrokeThickness = Math.Max(0, strokeThickness);
|
||||
var center = safeDiameter / 2;
|
||||
var radius = Math.Max(0, center - (safeStrokeThickness / 2));
|
||||
return (center, radius);
|
||||
}
|
||||
|
||||
private double _lastArcRatio = -1;
|
||||
private double _lastArcDiameter = -1;
|
||||
private double _lastArcStrokeThickness = -1;
|
||||
|
||||
private void UpdateCircularUsageArc(System.Windows.Shapes.Path path, double ratio, double centerX, double centerY, double radius)
|
||||
{
|
||||
ratio = Math.Clamp(ratio, 0, 0.9999);
|
||||
var effectiveDiameter = Math.Max(0, radius * 2 + path.StrokeThickness);
|
||||
|
||||
// 비율 변화가 1% 미만이면 렌더링 생략 (250ms마다 호출되므로 불필요한 재생성 방지)
|
||||
if (Math.Abs(ratio - _lastArcRatio) < 0.01)
|
||||
// 비율 변화가 1% 미만이어도 크기나 두께가 바뀌면 다시 그립니다.
|
||||
if (Math.Abs(ratio - _lastArcRatio) < 0.01
|
||||
&& Math.Abs(effectiveDiameter - _lastArcDiameter) < 0.01
|
||||
&& Math.Abs(path.StrokeThickness - _lastArcStrokeThickness) < 0.01)
|
||||
return;
|
||||
_lastArcRatio = ratio;
|
||||
_lastArcDiameter = effectiveDiameter;
|
||||
_lastArcStrokeThickness = path.StrokeThickness;
|
||||
|
||||
if (ratio <= 0)
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user