Files
AX-Copilot-Codex/src/AxCopilot/Views/LauncherWindow.xaml

741 lines
44 KiB
XML

<Window x:Class="AxCopilot.Views.LauncherWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
Title="AX Commander"
Width="680"
SizeToContent="Height"
WindowStyle="None"
AllowsTransparency="True"
UseLayoutRounding="True"
SnapsToDevicePixels="True"
Background="Transparent"
Topmost="True"
ShowInTaskbar="False"
ResizeMode="NoResize"
WindowStartupLocation="Manual"
Loaded="Window_Loaded"
Deactivated="Window_Deactivated"
PreviewKeyDown="Window_PreviewKeyDown"
KeyDown="Window_KeyDown">
<Window.Resources>
<!-- ─── 토스트 애니메이션 ─────────────────────────────────────────── -->
<Storyboard x:Key="ToastFadeIn">
<DoubleAnimation Storyboard.TargetName="ToastOverlay"
Storyboard.TargetProperty="Opacity"
From="0" To="1" Duration="0:0:0.18">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<Storyboard x:Key="ToastFadeOut">
<DoubleAnimation Storyboard.TargetName="ToastOverlay"
Storyboard.TargetProperty="Opacity"
From="1" To="0" Duration="0:0:0.28">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
<!-- ─── 결과 항목 스타일 ─────────────────────────────────────────── -->
<Style x:Key="ResultItemStyle" TargetType="ListViewItem">
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Padding" Value="13,8,13,8"/>
<Setter Property="Margin" Value="4,1,4,1"/>
<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ListViewItem">
<Grid>
<!-- 선택 아이템 무지개 글로우 보더 (RainbowGlowBorder와 동일한 방식) -->
<Border x:Name="SelGlow"
CornerRadius="{DynamicResource ItemCornerRadius}"
Margin="-2,0"
IsHitTestVisible="False"
Visibility="Collapsed"
BorderThickness="2"
BorderBrush="{DynamicResource SelectionGlowBrush}">
<Border.Effect>
<BlurEffect Radius="8"/>
</Border.Effect>
</Border>
<!-- 선택 시 좌측 액센트 바 -->
<Border x:Name="AccentBar"
HorizontalAlignment="Left"
Width="3"
CornerRadius="1.5"
Margin="1,4,0,4"
Background="{DynamicResource AccentColor}"
Visibility="Collapsed"/>
<Border x:Name="Bd"
Background="{TemplateBinding Background}"
BorderBrush="Transparent"
BorderThickness="0"
CornerRadius="{DynamicResource ItemCornerRadius}"
Padding="{TemplateBinding Padding}">
<ContentPresenter HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}"/>
</Border>
</Grid>
<ControlTemplate.Triggers>
<Trigger Property="IsSelected" Value="True">
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource ItemSelectedBackground}"/>
<Setter TargetName="AccentBar" Property="Visibility" Value="Visible"/>
<!-- 무지개 글로우 보더: EnableSelectionGlow 설정에 따라 Visible/Collapsed -->
<Setter TargetName="SelGlow" Property="Visibility" Value="{DynamicResource SelectionGlowVisibility}"/>
</Trigger>
<!-- 미선택 아이템 호버 -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsMouseOver" Value="True"/>
<Condition Property="IsSelected" Value="False"/>
</MultiTrigger.Conditions>
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource ItemHoverBackground}"/>
</MultiTrigger>
<!-- 선택 + 호버: 더 밝은 배경 + 강조 글로우 -->
<MultiTrigger>
<MultiTrigger.Conditions>
<Condition Property="IsSelected" Value="True"/>
<Condition Property="IsMouseOver" Value="True"/>
</MultiTrigger.Conditions>
<Setter TargetName="Bd" Property="Background" Value="{DynamicResource ItemSelectedHoverBackground}"/>
<Setter TargetName="Bd" Property="Effect">
<Setter.Value>
<DropShadowEffect ShadowDepth="0" BlurRadius="14" Opacity="0.4"
Color="#4B5EFC"/>
</Setter.Value>
</Setter>
</MultiTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<!-- ─── 스크롤바 스타일 ─────────────────────────────────────────── -->
<Style x:Key="SlimScrollThumb" TargetType="Thumb">
<Setter Property="Background" Value="{DynamicResource ScrollbarThumb}"/>
<Setter Property="Width" Value="3"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="Thumb">
<Border Background="{TemplateBinding Background}" CornerRadius="2"/>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
<Style x:Key="SlimScrollBar" TargetType="ScrollBar">
<Setter Property="Width" Value="5"/>
<Setter Property="Margin" Value="0,4,2,4"/>
<Setter Property="Background" Value="Transparent"/>
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="ScrollBar">
<Grid>
<Track x:Name="PART_Track" IsDirectionReversed="True">
<Track.Thumb>
<Thumb Style="{StaticResource SlimScrollThumb}"/>
</Track.Thumb>
</Track>
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</Window.Resources>
<!-- ─── 메인 컨테이너 ──────────────────────────────────────────────── -->
<Grid Margin="24">
<!-- 그림자 전용 레이어 -->
<Border CornerRadius="{DynamicResource WindowCornerRadius}"
Background="{DynamicResource LauncherBackground}">
<Border.Effect>
<DropShadowEffect Color="{DynamicResource ShadowColor}"
BlurRadius="32" ShadowDepth="8" Opacity="0.32"/>
</Border.Effect>
</Border>
<!-- 무지개 글로우 레이어 (상시 애니메이션) -->
<Border x:Name="RainbowGlowBorder"
CornerRadius="{DynamicResource WindowCornerRadius}"
Margin="-3" Opacity="1.0"
IsHitTestVisible="False">
<Border.BorderBrush>
<LinearGradientBrush x:Name="LauncherRainbowBrush" StartPoint="0,0" EndPoint="1,1">
<GradientStop Color="#FF6B6B" Offset="0.0"/>
<GradientStop Color="#FECA57" Offset="0.17"/>
<GradientStop Color="#48DBFB" Offset="0.33"/>
<GradientStop Color="#FF9FF3" Offset="0.5"/>
<GradientStop Color="#54A0FF" Offset="0.67"/>
<GradientStop Color="#5F27CD" Offset="0.83"/>
<GradientStop Color="#FF6B6B" Offset="1.0"/>
</LinearGradientBrush>
</Border.BorderBrush>
<Border.BorderThickness>
<Thickness>3.5</Thickness>
</Border.BorderThickness>
<Border.Effect>
<BlurEffect Radius="10"/>
</Border.Effect>
</Border>
<!-- 콘텐츠 레이어 -->
<Border x:Name="MainBorder"
CornerRadius="{DynamicResource WindowCornerRadius}"
Background="{DynamicResource LauncherBackground}"
BorderThickness="0"
BorderBrush="Transparent">
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
<RowDefinition Height="Auto"/>
</Grid.RowDefinitions>
<!-- ─── 입력 영역 ─── -->
<Grid Grid.Row="0" Margin="20,16,20,16">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- 검색 아이콘 / Prefix 배지 -->
<Grid Grid.Column="0" Margin="0,0,10,0" VerticalAlignment="Center">
<!-- 기본 아이콘: 다이아몬드 픽셀 (prefix 없을 때) -->
<Canvas x:Name="DiamondIcon" Width="22" Height="22"
VerticalAlignment="Center" Cursor="Hand"
ClipToBounds="False"
MouseLeftButtonDown="DiamondIcon_Click"
Visibility="{Binding HasActivePrefix, Converter={StaticResource InverseBoolToVisibilityConverter}}">
<Canvas.RenderTransformOrigin>0.5,0.5</Canvas.RenderTransformOrigin>
<Canvas.RenderTransform>
<TransformGroup>
<RotateTransform x:Name="IconRotate" Angle="45"/>
<ScaleTransform x:Name="IconScale" ScaleX="1" ScaleY="1"/>
</TransformGroup>
</Canvas.RenderTransform>
<!-- 마우스 오버 시 각 픽셀 색상이 퍼져나가는 글로우 (픽셀보다 먼저 렌더링 = 아래에 배치) -->
<Rectangle x:Name="GlowBlue"
Canvas.Left="-2.5" Canvas.Top="-2.5"
Width="14.5" Height="14.5"
RadiusX="7" RadiusY="7"
Fill="#4488FF" Opacity="0">
<Rectangle.Effect><BlurEffect Radius="9"/></Rectangle.Effect>
</Rectangle>
<Rectangle x:Name="GlowGreen1"
Canvas.Left="9" Canvas.Top="-2.5"
Width="14.5" Height="14.5"
RadiusX="7" RadiusY="7"
Fill="#44DD66" Opacity="0">
<Rectangle.Effect><BlurEffect Radius="9"/></Rectangle.Effect>
</Rectangle>
<Rectangle x:Name="GlowGreen2"
Canvas.Left="-2.5" Canvas.Top="9"
Width="14.5" Height="14.5"
RadiusX="7" RadiusY="7"
Fill="#44DD66" Opacity="0">
<Rectangle.Effect><BlurEffect Radius="9"/></Rectangle.Effect>
</Rectangle>
<Rectangle x:Name="GlowRed"
Canvas.Left="9" Canvas.Top="9"
Width="14.5" Height="14.5"
RadiusX="7" RadiusY="7"
Fill="#FF4466" Opacity="0">
<Rectangle.Effect><BlurEffect Radius="9"/></Rectangle.Effect>
</Rectangle>
<!-- 파란 픽셀 (좌상→상) -->
<Rectangle x:Name="PixelBlue"
Canvas.Left="0.5" Canvas.Top="0.5"
Width="9.5" Height="9.5"
RadiusX="1.5" RadiusY="1.5"
Fill="#4488FF" Opacity="1"/>
<!-- 초록 픽셀 (우상→우) -->
<Rectangle x:Name="PixelGreen1"
Canvas.Left="12" Canvas.Top="0.5"
Width="9.5" Height="9.5"
RadiusX="1.5" RadiusY="1.5"
Fill="#44DD66" Opacity="1"/>
<!-- 초록 픽셀 (좌하→좌) -->
<Rectangle x:Name="PixelGreen2"
Canvas.Left="0.5" Canvas.Top="12"
Width="9.5" Height="9.5"
RadiusX="1.5" RadiusY="1.5"
Fill="#44DD66" Opacity="1"/>
<!-- 빨간 픽셀 (우하→하) -->
<Rectangle x:Name="PixelRed"
Canvas.Left="12" Canvas.Top="12"
Width="9.5" Height="9.5"
RadiusX="1.5" RadiusY="1.5"
Fill="#FF4466" Opacity="1"/>
<!-- 마우스 오버 → 각 픽셀 색 글로우 페이드인/아웃 -->
<Canvas.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="GlowBlue" Storyboard.TargetProperty="Opacity" To="0.9" Duration="0:0:0.15">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseOut"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="GlowGreen1" Storyboard.TargetProperty="Opacity" To="0.9" Duration="0:0:0.15">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseOut"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="GlowGreen2" Storyboard.TargetProperty="Opacity" To="0.9" Duration="0:0:0.15">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseOut"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="GlowRed" Storyboard.TargetProperty="Opacity" To="0.9" Duration="0:0:0.15">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseOut"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetName="GlowBlue" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.22">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseIn"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="GlowGreen1" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.22">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseIn"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="GlowGreen2" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.22">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseIn"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation Storyboard.TargetName="GlowRed" Storyboard.TargetProperty="Opacity" To="0" Duration="0:0:0.22">
<DoubleAnimation.EasingFunction><QuadraticEase EasingMode="EaseIn"/></DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Canvas.Triggers>
<!-- 애니메이션은 코드비하인드에서 5가지 효과 중 랜덤 적용 -->
</Canvas>
<!-- Prefix 배지 (prefix 있을 때) -->
<Border CornerRadius="6"
Padding="7,4,7,4"
Background="{Binding ActivePrefixBrush}"
Visibility="{Binding HasActivePrefix, Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="{Binding ActivePrefixSymbol}"
FontFamily="Segoe MDL2 Assets"
FontSize="11"
Foreground="White"
VerticalAlignment="Center"/>
<TextBlock Text="{Binding ActivePrefixLabel}"
FontSize="11"
FontWeight="SemiBold"
Foreground="White"
Margin="4,0,0,0"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
</Grid>
<!-- 텍스트 입력창 -->
<TextBox x:Name="InputBox"
Grid.Column="1"
FontSize="20"
FontFamily="Segoe UI, Malgun Gothic"
Foreground="{DynamicResource PrimaryText}"
CaretBrush="{DynamicResource AccentColor}"
Background="Transparent"
BorderThickness="0"
VerticalAlignment="Center"
Text="{Binding InputText, UpdateSourceTrigger=PropertyChanged}"
TextChanged="InputBox_TextChanged"
>
<TextBox.Style>
<Style TargetType="TextBox">
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="TextBox">
<Grid>
<TextBlock x:Name="Placeholder"
Text="{Binding PlaceholderText}"
FontSize="17"
Foreground="{DynamicResource PlaceholderText}"
VerticalAlignment="Center"
Margin="4,0,0,0"
IsHitTestVisible="False"
Visibility="Collapsed"/>
<ScrollViewer x:Name="PART_ContentHost" VerticalAlignment="Center"/>
</Grid>
<ControlTemplate.Triggers>
<DataTrigger Binding="{Binding Text, RelativeSource={RelativeSource Self}}" Value="">
<Setter TargetName="Placeholder" Property="Visibility" Value="Visible"/>
</DataTrigger>
</ControlTemplate.Triggers>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</TextBox.Style>
</TextBox>
<!-- 로딩 인디케이터 -->
<ProgressBar Grid.Column="2"
Width="16" Height="16"
IsIndeterminate="True"
Foreground="{DynamicResource AccentColor}"
Background="Transparent"
BorderThickness="0"
Visibility="{Binding IsLoading, Converter={StaticResource BoolToVisibilityConverter}}"/>
<!-- 도움말 힌트 -->
<Border Grid.Column="2"
Background="{DynamicResource HintBackground}"
CornerRadius="6"
Padding="9,4"
Visibility="{Binding IsLoading, Converter={StaticResource InverseBoolToVisibilityConverter}}">
<StackPanel Orientation="Horizontal" VerticalAlignment="Center">
<TextBlock Text="help"
FontSize="11"
FontFamily="Segoe UI Mono, Consolas"
Foreground="{DynamicResource HintText}"
VerticalAlignment="Center"/>
<TextBlock Text="&#x21B5;"
FontSize="12"
FontFamily="Segoe UI"
Foreground="{DynamicResource HintText}"
Margin="3,0,0,0"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
</Grid>
<!-- ─── 파일 액션 모드 breadcrumb 바 ─── -->
<Border Grid.Row="1"
Padding="16,7"
Visibility="{Binding ShowActionModeBar, Converter={StaticResource BoolToVisibilityConverter}}">
<Border.Background>
<SolidColorBrush Color="{Binding Color, Source={StaticResource AccentColor}}" Opacity="0.10"/>
</Border.Background>
<StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE76B;"
FontFamily="Segoe MDL2 Assets"
FontSize="10"
Foreground="{DynamicResource AccentColor}"
VerticalAlignment="Center"
Margin="0,0,7,0"/>
<TextBlock Text="{Binding ActionModeBreadcrumb}"
FontSize="12"
FontWeight="SemiBold"
Foreground="{DynamicResource AccentColor}"
VerticalAlignment="Center"/>
<TextBlock Text=" 에 대한 액션"
FontSize="12"
Foreground="{DynamicResource AccentColor}"
Opacity="0.65"
VerticalAlignment="Center"/>
<TextBlock Text=" · Esc로 돌아가기"
FontSize="11"
Foreground="{DynamicResource AccentColor}"
Opacity="0.45"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
<!-- ─── 구분선 (가장자리 gradient 페이드) ─── -->
<Rectangle Grid.Row="2"
Height="1"
Fill="{DynamicResource SeparatorColor}"
Visibility="{Binding Results.Count, Converter={StaticResource CountToVisibilityConverter}}">
<Rectangle.OpacityMask>
<LinearGradientBrush StartPoint="0,0.5" EndPoint="1,0.5">
<GradientStop Color="Transparent" Offset="0"/>
<GradientStop Color="White" Offset="0.08"/>
<GradientStop Color="White" Offset="0.92"/>
<GradientStop Color="Transparent" Offset="1"/>
</LinearGradientBrush>
</Rectangle.OpacityMask>
</Rectangle>
<!-- ─── 클립보드 병합 힌트 바 ─── -->
<Border Grid.Row="3"
Background="#158764B8"
Padding="16,6"
Visibility="{Binding ShowMergeHint, Converter={StaticResource BoolToVisibilityConverter}}">
<StackPanel Orientation="Horizontal">
<TextBlock Text="&#xE762;"
FontFamily="Segoe MDL2 Assets"
FontSize="10"
Foreground="#8764B8"
VerticalAlignment="Center"
Margin="0,0,7,0"/>
<TextBlock Text="{Binding MergeHintText}"
FontSize="11"
Foreground="#8764B8"
FontFamily="Segoe UI, Malgun Gothic"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
<!-- ─── 결과 리스트 ─── -->
<ListView x:Name="ResultList"
Grid.Row="4"
ItemsSource="{Binding Results}"
SelectedItem="{Binding SelectedItem, Mode=TwoWay}"
Background="Transparent"
BorderThickness="0"
Margin="6,6,6,14"
ScrollViewer.HorizontalScrollBarVisibility="Disabled"
ScrollViewer.VerticalScrollBarVisibility="Auto"
MaxHeight="380"
VirtualizingStackPanel.VirtualizationMode="Recycling"
VirtualizingPanel.ScrollUnit="Item"
ItemContainerStyle="{StaticResource ResultItemStyle}"
PreviewMouseLeftButtonUp="ResultList_PreviewMouseLeftButtonUp"
MouseDoubleClick="ResultList_MouseDoubleClick"
Visibility="{Binding Results.Count, Converter={StaticResource CountToVisibilityConverter}}">
<ListView.Resources>
<Style TargetType="ScrollBar" BasedOn="{StaticResource SlimScrollBar}"/>
</ListView.Resources>
<ListView.ItemTemplate>
<DataTemplate>
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition Width="*"/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<!-- 번호 뱃지 (1~9, Ctrl+N으로 실행 가능) — ShowNumberBadges 설정으로 제어 -->
<TextBlock Grid.Column="0"
Text="{Binding RelativeSource={RelativeSource AncestorType=ListViewItem},
Converter={StaticResource IndexToNumberConverter}}"
FontFamily="Consolas"
FontSize="10"
Foreground="{DynamicResource SecondaryText}"
Opacity="0.55"
VerticalAlignment="Center"
HorizontalAlignment="Center"
Width="16"
Margin="0,0,4,0"
Visibility="{Binding DataContext.ShowNumberBadges,
RelativeSource={RelativeSource AncestorType=Window},
Converter={StaticResource BoolToVisibilityConverter}}"/>
<!-- 아이콘: IconPath가 있으면 이미지, 없으면 심볼 글리프 -->
<Border Grid.Column="1"
Width="34" Height="34"
CornerRadius="8"
Margin="0,0,12,0"
VerticalAlignment="Center"
Background="{Binding Symbol, Converter={StaticResource SymbolToBackgroundConverter}}">
<!-- 외부 글로우: 마우스 오버 시 아이콘 테두리에서 빛이 퍼지는 효과 -->
<Border.Effect>
<DropShadowEffect ShadowDepth="0" BlurRadius="14" Opacity="0" Color="White"/>
</Border.Effect>
<Border.Triggers>
<EventTrigger RoutedEvent="UIElement.MouseEnter">
<BeginStoryboard>
<Storyboard>
<!-- 외부 글로우 페이드인 -->
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Opacity)"
To="0.65" Duration="0:0:0.14">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<!-- 내부 빛 발산 오버레이 페이드인 -->
<DoubleAnimation
Storyboard.TargetName="IconInnerGlow"
Storyboard.TargetProperty="Opacity"
To="1" Duration="0:0:0.14">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseOut"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
<EventTrigger RoutedEvent="UIElement.MouseLeave">
<BeginStoryboard>
<Storyboard>
<DoubleAnimation
Storyboard.TargetProperty="(UIElement.Effect).(DropShadowEffect.Opacity)"
To="0" Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<DoubleAnimation
Storyboard.TargetName="IconInnerGlow"
Storyboard.TargetProperty="Opacity"
To="0" Duration="0:0:0.2">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseIn"/>
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</EventTrigger>
</Border.Triggers>
<Grid>
<TextBlock x:Name="SymbolText"
Text="{Binding Symbol}"
FontFamily="Segoe MDL2 Assets"
FontSize="15"
Foreground="White"
HorizontalAlignment="Center"
VerticalAlignment="Center"/>
<Image Source="{Binding IconPath}"
Width="22" Height="22"
RenderOptions.BitmapScalingMode="HighQuality"
HorizontalAlignment="Center"
VerticalAlignment="Center"
Visibility="{Binding IconPath, Converter={StaticResource NullToCollapsedConverter}}"/>
<!-- 클립보드 이미지 썸네일 -->
<Image Source="{Binding Data, Converter={StaticResource ClipboardThumbnailConverter}}"
Stretch="UniformToFill"
RenderOptions.BitmapScalingMode="HighQuality"
Visibility="{Binding Data, Converter={StaticResource ClipboardHasImageConverter}}"/>
<!-- 내부 빛 발산 오버레이 (RadialGradient: 중심 → 투명 가장자리) -->
<Border x:Name="IconInnerGlow"
CornerRadius="8"
Opacity="0"
IsHitTestVisible="False">
<Border.Background>
<RadialGradientBrush GradientOrigin="0.5,0.35"
Center="0.5,0.35"
RadiusX="0.75" RadiusY="0.75">
<GradientStop Color="#70FFFFFF" Offset="0.0"/>
<GradientStop Color="#20FFFFFF" Offset="0.55"/>
<GradientStop Color="#00FFFFFF" Offset="1.0"/>
</RadialGradientBrush>
</Border.Background>
</Border>
</Grid>
</Border>
<!-- 제목 + 부제목 -->
<StackPanel Grid.Column="2" VerticalAlignment="Center">
<TextBlock Text="{Binding Title}"
FontFamily="Segoe UI, Malgun Gothic"
FontSize="14"
FontWeight="Medium"
TextTrimming="CharacterEllipsis">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource PrimaryText}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter Property="Foreground" Value="White"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<TextBlock Text="{Binding Subtitle}"
FontFamily="Segoe UI, Malgun Gothic"
FontSize="11"
TextTrimming="CharacterEllipsis"
Margin="0,2,0,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Foreground" Value="{DynamicResource SecondaryText}"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter Property="Foreground" Value="#E0E8FF"/>
</DataTrigger>
<DataTrigger Binding="{Binding Subtitle, Converter={StaticResource WarningSubtitleColorConverter}}" Value="{x:Static Visibility.Visible}">
<Setter Property="Foreground" Value="#E53E3E"/>
<Setter Property="FontWeight" Value="SemiBold"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</StackPanel>
<!-- 우측 화살표 (선택 항목에만 표시) -->
<TextBlock Grid.Column="3"
Text="&#xE76C;"
FontFamily="Segoe MDL2 Assets"
FontSize="10"
Foreground="#AABBFF"
VerticalAlignment="Center"
Margin="8,0,2,0">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Setter Property="Visibility" Value="Collapsed"/>
<Style.Triggers>
<DataTrigger Binding="{Binding IsSelected, RelativeSource={RelativeSource AncestorType=ListViewItem}}" Value="True">
<Setter Property="Visibility" Value="Visible"/>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
</Grid>
</DataTemplate>
</ListView.ItemTemplate>
</ListView>
<!-- ─── 인덱싱 상태 바 ─── -->
<TextBlock x:Name="IndexStatusText"
Grid.Row="5"
Visibility="Collapsed"
FontSize="10"
Foreground="{DynamicResource SecondaryText}"
HorizontalAlignment="Center"
Margin="0,0,0,8"
Opacity="0.7"/>
<!-- ─── 토스트 오버레이 ─── -->
<Border x:Name="ToastOverlay"
Grid.Row="4" Grid.RowSpan="2"
HorizontalAlignment="Center"
VerticalAlignment="Bottom"
Margin="0,0,0,12"
CornerRadius="8"
Padding="14,7"
Opacity="0"
Visibility="Collapsed"
IsHitTestVisible="False">
<Border.Background>
<SolidColorBrush Color="#107C10" Opacity="0.92"/>
</Border.Background>
<Border.Triggers>
<EventTrigger RoutedEvent="Border.Loaded">
<!-- 최초 로드 시 아무것도 안 함 -->
</EventTrigger>
</Border.Triggers>
<StackPanel Orientation="Horizontal">
<TextBlock x:Name="ToastIcon"
Text="&#xE73E;"
FontFamily="Segoe MDL2 Assets"
FontSize="12" Foreground="White"
VerticalAlignment="Center"
Margin="0,0,8,0"/>
<TextBlock x:Name="ToastText"
FontSize="11" Foreground="White"
FontWeight="SemiBold"
VerticalAlignment="Center"/>
</StackPanel>
</Border>
</Grid>
</Border>
</Grid>
</Window>