AX Agent 공통 팝업과 시각 상호작용 렌더를 분리해 메인 창 구조를 정리한다
Some checks failed
Release Gate / gate (push) Has been cancelled
Some checks failed
Release Gate / gate (push) Has been cancelled
- ChatWindow.VisualInteractionHelpers.cs를 추가해 메시지 액션 버튼, 선택 스타일, hover 애니메이션, 공통 체크 아이콘 생성을 메인 창 코드 밖으로 이동했다. - ChatWindow.PopupPresentation.cs를 추가해 공통 테마 팝업 컨테이너, 메뉴 아이템, 구분선, 최근 폴더 컨텍스트 메뉴 구성을 한 곳으로 모았다. - README와 DEVELOPMENT 문서에 2026-04-06 09:03 (KST) 기준 구조 분리 이력을 반영했다. - dotnet build src/AxCopilot/AxCopilot.csproj -c Release -v minimal -p:OutputPath=bin\\verify\\ -p:IntermediateOutputPath=obj\\verify\\ 검증 결과 경고 0 / 오류 0을 확인했다.
This commit is contained in:
159
src/AxCopilot/Views/ChatWindow.PopupPresentation.cs
Normal file
159
src/AxCopilot/Views/ChatWindow.PopupPresentation.cs
Normal file
@@ -0,0 +1,159 @@
|
||||
using System;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Controls.Primitives;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Threading;
|
||||
|
||||
namespace AxCopilot.Views;
|
||||
|
||||
public partial class ChatWindow
|
||||
{
|
||||
private Popup? _sharedContextPopup;
|
||||
|
||||
private (Popup Popup, StackPanel Panel) CreateThemedPopupMenu(
|
||||
UIElement? placementTarget = null,
|
||||
PlacementMode placement = PlacementMode.MousePoint,
|
||||
double minWidth = 200)
|
||||
{
|
||||
_sharedContextPopup?.SetCurrentValue(Popup.IsOpenProperty, false);
|
||||
|
||||
var bg = TryFindResource("LauncherBackground") as Brush ?? Brushes.White;
|
||||
var border = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
var panel = new StackPanel { Margin = new Thickness(2) };
|
||||
var container = new Border
|
||||
{
|
||||
Background = bg,
|
||||
BorderBrush = border,
|
||||
BorderThickness = new Thickness(1),
|
||||
CornerRadius = new CornerRadius(10),
|
||||
Padding = new Thickness(6),
|
||||
MinWidth = minWidth,
|
||||
Child = panel,
|
||||
Effect = new System.Windows.Media.Effects.DropShadowEffect
|
||||
{
|
||||
BlurRadius = 16,
|
||||
ShadowDepth = 3,
|
||||
Opacity = 0.18,
|
||||
Color = Colors.Black,
|
||||
Direction = 270,
|
||||
},
|
||||
};
|
||||
|
||||
var popup = new Popup
|
||||
{
|
||||
Child = container,
|
||||
StaysOpen = false,
|
||||
AllowsTransparency = true,
|
||||
PopupAnimation = PopupAnimation.Fade,
|
||||
Placement = placement,
|
||||
PlacementTarget = placementTarget,
|
||||
};
|
||||
|
||||
_sharedContextPopup = popup;
|
||||
return (popup, panel);
|
||||
}
|
||||
|
||||
private Border CreatePopupMenuItem(
|
||||
Popup popup,
|
||||
string icon,
|
||||
string label,
|
||||
Brush iconBrush,
|
||||
Brush labelBrush,
|
||||
Brush hoverBrush,
|
||||
Action action)
|
||||
{
|
||||
var sp = new StackPanel { Orientation = Orientation.Horizontal };
|
||||
sp.Children.Add(new TextBlock
|
||||
{
|
||||
Text = icon,
|
||||
FontFamily = new FontFamily("Segoe MDL2 Assets"),
|
||||
FontSize = 12.5,
|
||||
Foreground = iconBrush,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
Margin = new Thickness(0, 0, 9, 0),
|
||||
});
|
||||
sp.Children.Add(new TextBlock
|
||||
{
|
||||
Text = label,
|
||||
FontSize = 12.5,
|
||||
Foreground = labelBrush,
|
||||
VerticalAlignment = VerticalAlignment.Center,
|
||||
});
|
||||
|
||||
var item = new Border
|
||||
{
|
||||
Child = sp,
|
||||
Background = Brushes.Transparent,
|
||||
CornerRadius = new CornerRadius(8),
|
||||
Cursor = Cursors.Hand,
|
||||
Padding = new Thickness(10, 7, 12, 7),
|
||||
Margin = new Thickness(0, 1, 0, 1),
|
||||
};
|
||||
item.MouseEnter += (s, _) => { if (s is Border b) b.Background = hoverBrush; };
|
||||
item.MouseLeave += (s, _) => { if (s is Border b) b.Background = Brushes.Transparent; };
|
||||
item.MouseLeftButtonUp += (_, _) =>
|
||||
{
|
||||
popup.SetCurrentValue(Popup.IsOpenProperty, false);
|
||||
action();
|
||||
};
|
||||
|
||||
return item;
|
||||
}
|
||||
|
||||
private static void AddPopupMenuSeparator(Panel panel, Brush brush)
|
||||
{
|
||||
panel.Children.Add(new Border
|
||||
{
|
||||
Height = 1,
|
||||
Margin = new Thickness(10, 4, 10, 4),
|
||||
Background = brush,
|
||||
Opacity = 0.35,
|
||||
});
|
||||
}
|
||||
|
||||
/// <summary>최근 폴더 항목 우클릭 컨텍스트 메뉴를 표시합니다.</summary>
|
||||
private void ShowRecentFolderContextMenu(string folderPath)
|
||||
{
|
||||
var primaryText = TryFindResource("PrimaryText") as Brush ?? Brushes.White;
|
||||
var secondaryText = TryFindResource("SecondaryText") as Brush ?? Brushes.Gray;
|
||||
var borderBrush = TryFindResource("BorderColor") as Brush ?? Brushes.Gray;
|
||||
var hoverBg = TryFindResource("ItemHoverBackground") as Brush ?? Brushes.Transparent;
|
||||
var warningBrush = new SolidColorBrush(Color.FromRgb(0xEF, 0x44, 0x44));
|
||||
var (popup, panel) = CreateThemedPopupMenu();
|
||||
|
||||
panel.Children.Add(CreatePopupMenuItem(popup, "\uED25", "폴더 열기", secondaryText, primaryText, hoverBg, () =>
|
||||
{
|
||||
try
|
||||
{
|
||||
System.Diagnostics.Process.Start(new System.Diagnostics.ProcessStartInfo
|
||||
{
|
||||
FileName = folderPath,
|
||||
UseShellExecute = true,
|
||||
});
|
||||
}
|
||||
catch
|
||||
{
|
||||
}
|
||||
}));
|
||||
|
||||
panel.Children.Add(CreatePopupMenuItem(popup, "\uE8C8", "경로 복사", secondaryText, primaryText, hoverBg, () =>
|
||||
{
|
||||
try { Clipboard.SetText(folderPath); } catch { }
|
||||
}));
|
||||
|
||||
AddPopupMenuSeparator(panel, borderBrush);
|
||||
|
||||
panel.Children.Add(CreatePopupMenuItem(popup, "\uE74D", "목록에서 삭제", warningBrush, warningBrush, hoverBg, () =>
|
||||
{
|
||||
_settings.Settings.Llm.RecentWorkFolders.RemoveAll(
|
||||
p => p.Equals(folderPath, StringComparison.OrdinalIgnoreCase));
|
||||
_settings.Save();
|
||||
if (FolderMenuPopup.IsOpen)
|
||||
ShowFolderMenu();
|
||||
}));
|
||||
|
||||
Dispatcher.BeginInvoke(() => { popup.IsOpen = true; }, DispatcherPriority.Input);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user