Initial commit to new repository

This commit is contained in:
2026-04-03 18:22:19 +09:00
commit 4458bb0f52
7672 changed files with 452440 additions and 0 deletions

View File

@@ -0,0 +1,192 @@
using System.Drawing;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.IO;
namespace AxCopilot.Views;
/// <summary>
/// 전체 화면 위에 반투명 오버레이를 표시하고 마우스 드래그로 캡처 영역을 선택합니다.
/// ShowDialog() 후 SelectedRect로 결과를 얻습니다.
/// </summary>
public partial class RegionSelectWindow : Window
{
public System.Drawing.Rectangle? SelectedRect { get; private set; }
private readonly System.Drawing.Rectangle _screenBounds;
private System.Windows.Point _startPoint;
private System.Windows.Point _endPoint;
private bool _isDragging;
public RegionSelectWindow(Bitmap fullScreenshot, System.Drawing.Rectangle screenBounds)
{
InitializeComponent();
_screenBounds = screenBounds;
// 창을 모든 모니터 전체에 걸쳐 표시
Left = screenBounds.X;
Top = screenBounds.Y;
Width = screenBounds.Width;
Height = screenBounds.Height;
// 전체 화면 스크린샷을 배경으로 렌더링
RootCanvas.Background = CreateFrozenBrush(fullScreenshot);
// 오버레이 초기 크기 설정
OverlayTop.Width = screenBounds.Width;
OverlayTop.Height = screenBounds.Height;
OverlayBottom.Width = screenBounds.Width;
OverlayLeft.Width = 0;
OverlayRight.Width = 0;
// 가이드 텍스트 중앙 배치 (Loaded 이후)
Loaded += (_, _) =>
{
Canvas.SetLeft(GuideText, (Width - GuideText.ActualWidth) / 2);
Canvas.SetTop(GuideText, (Height - GuideText.ActualHeight) / 2);
};
}
private static ImageBrush CreateFrozenBrush(Bitmap bmp)
{
using var ms = new MemoryStream();
bmp.Save(ms, System.Drawing.Imaging.ImageFormat.Bmp);
ms.Position = 0;
var img = new BitmapImage();
img.BeginInit();
img.StreamSource = ms;
img.CacheOption = BitmapCacheOption.OnLoad;
img.EndInit();
img.Freeze();
var brush = new ImageBrush(img) { Stretch = Stretch.None, AlignmentX = AlignmentX.Left, AlignmentY = AlignmentY.Top };
brush.Freeze();
return brush;
}
private void Window_MouseDown(object sender, MouseButtonEventArgs e)
{
if (e.ChangedButton != MouseButton.Left) return;
_startPoint = e.GetPosition(RootCanvas);
_isDragging = true;
GuideText.Visibility = Visibility.Collapsed;
SelectionBorder.Visibility = Visibility.Visible;
SizeLabel.Visibility = Visibility.Visible;
CaptureMouse();
}
private void Window_MouseMove(object sender, MouseEventArgs e)
{
if (!_isDragging) return;
var cur = e.GetPosition(RootCanvas);
UpdateSelection(_startPoint, cur);
}
private void Window_MouseUp(object sender, MouseButtonEventArgs e)
{
if (!_isDragging || e.ChangedButton != MouseButton.Left) return;
_isDragging = false;
ReleaseMouseCapture();
var cur = e.GetPosition(RootCanvas);
_endPoint = cur;
var rect = MakeRect(_startPoint, cur);
if (rect.Width < 4 || rect.Height < 4)
{
// 너무 작으면 무시, 다시 드래그 가능
return;
}
// 선택 완료 — 화살표 키로 미세 조정 후 Enter/더블클릭으로 확정, Esc로 취소
// SizeLabel 하단에 힌트 표시
SizeLabelText.Text += " · ↑↓←→ 미세조정 · Enter 확정";
}
private void Window_KeyDown(object sender, KeyEventArgs e)
{
if (e.Key == Key.Escape)
{
SelectedRect = null;
Close();
return;
}
// 드래그 완료 후 화살표 키로 선택 영역 미세 조정
if (!_isDragging && SelectionBorder.Visibility == Visibility.Visible)
{
double dx = 0, dy = 0;
bool shift = Keyboard.Modifiers.HasFlag(ModifierKeys.Shift);
double step = shift ? 10 : 1; // Shift 누르면 10px 단위
switch (e.Key)
{
case Key.Left: dx = -step; break;
case Key.Right: dx = step; break;
case Key.Up: dy = -step; break;
case Key.Down: dy = step; break;
case Key.Enter:
// Enter 키로 현재 선택 확정
var r = MakeRect(_startPoint, _endPoint);
if (r.Width >= 4 && r.Height >= 4)
{
var dpi = VisualTreeHelper.GetDpi(this);
SelectedRect = new System.Drawing.Rectangle(
(int)(r.X * dpi.DpiScaleX) + _screenBounds.X,
(int)(r.Y * dpi.DpiScaleY) + _screenBounds.Y,
(int)(r.Width * dpi.DpiScaleX),
(int)(r.Height * dpi.DpiScaleY));
}
Close();
return;
default: return;
}
_endPoint = new System.Windows.Point(_endPoint.X + dx, _endPoint.Y + dy);
UpdateSelection(_startPoint, _endPoint);
e.Handled = true;
}
}
private void UpdateSelection(System.Windows.Point a, System.Windows.Point b)
{
var rect = MakeRect(a, b);
Canvas.SetLeft(SelectionBorder, rect.X);
Canvas.SetTop(SelectionBorder, rect.Y);
SelectionBorder.Width = rect.Width;
SelectionBorder.Height = rect.Height;
// 바깥 마스크 업데이트
OverlayTop.Width = Width;
OverlayTop.Height = rect.Y;
OverlayBottom.Width = Width;
OverlayBottom.Height = Height - rect.Y - rect.Height;
Canvas.SetTop(OverlayBottom, rect.Y + rect.Height);
OverlayLeft.Width = rect.X;
OverlayLeft.Height = rect.Height;
Canvas.SetTop(OverlayLeft, rect.Y);
OverlayRight.Width = Width - rect.X - rect.Width;
OverlayRight.Height = rect.Height;
Canvas.SetLeft(OverlayRight, rect.X + rect.Width);
Canvas.SetTop(OverlayRight, rect.Y);
// 크기 레이블
var dpiScale = VisualTreeHelper.GetDpi(this);
var pw = (int)(rect.Width * dpiScale.DpiScaleX);
var ph = (int)(rect.Height * dpiScale.DpiScaleY);
SizeLabelText.Text = $"{pw} × {ph}";
Canvas.SetLeft(SizeLabel, rect.X + rect.Width + 8);
Canvas.SetTop(SizeLabel, rect.Y + rect.Height + 4);
}
private static Rect MakeRect(System.Windows.Point a, System.Windows.Point b) =>
new(Math.Min(a.X, b.X), Math.Min(a.Y, b.Y),
Math.Abs(b.X - a.X), Math.Abs(b.Y - a.Y));
}