Initial commit to new repository
This commit is contained in:
192
src/AxCopilot/Views/RegionSelectWindow.xaml.cs
Normal file
192
src/AxCopilot/Views/RegionSelectWindow.xaml.cs
Normal 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));
|
||||
}
|
||||
Reference in New Issue
Block a user