Skip to content

Commit 07ef3b0

Browse files
committed
feat(Avalonia): allow region selector to be called programatically
1 parent 9f11c3a commit 07ef3b0

1 file changed

Lines changed: 66 additions & 27 deletions

File tree

SnapX.Avalonia/Views/RegionSelectorWindow.axaml.cs

Lines changed: 66 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -32,9 +32,16 @@ public partial class RegionSelectorWindow : Window
3232
private Stream? _imageStream;
3333
private Rect _imageBounds;
3434
private List<Window> windowsHiddenByUs = [];
35-
public RegionSelectorWindow(RegionSelectorViewModel vm)
35+
private TaskCompletionSource<Image?> _resultImg = new();
36+
private TaskCompletionSource<SixLabors.ImageSharp.Rectangle?> _resultRect = new();
37+
private bool IsSilentMode { get; set; } = false;
38+
39+
private bool TakeScreenshot { get; set; } = true;
40+
public RegionSelectorWindow(RegionSelectorViewModel vm, bool IsSilent = false, bool takeScreenshot = true)
3641
{
3742
DataContext = vm;
43+
IsSilentMode = IsSilent;
44+
TakeScreenshot = takeScreenshot;
3845
InitializeComponent();
3946

4047
_selectionRect = this.FindControl<Rectangle>("SelectionRect");
@@ -53,9 +60,21 @@ protected override async void OnOpened(EventArgs e)
5360

5461
Opacity = 1;
5562
}
63+
public static async Task<Image?> SelectRegionAsync()
64+
{
65+
var selector = new RegionSelectorWindow(true);
66+
selector.Show();
67+
return await selector._resultImg.Task;
68+
}
69+
public static async Task<SixLabors.ImageSharp.Rectangle?> SelectRegionRectAsync()
70+
{
71+
var selector = new RegionSelectorWindow(true, false);
72+
selector.Show();
73+
return await selector._resultRect.Task;
74+
}
5675
private async Task SetupWindowBoundsAsync()
5776
{
58-
var bounds = await Task.Run(async() =>
77+
var bounds = await Task.Run(async () =>
5978
{
6079
var (x, y, width, height) = await Methods.GetActiveScreen();
6180
DebugHelper.WriteLine($"VirtualScreen details: X is {x} Y is {y} Width is {width} Height is {height}");
@@ -82,6 +101,7 @@ private async Task SetupWindowBoundsAsync()
82101
});
83102
}
84103
public RegionSelectorWindow() : this(new RegionSelectorViewModel()) { }
104+
public RegionSelectorWindow(bool IsSilent, bool takeScreenShot = true) : this(new RegionSelectorViewModel(), IsSilent, takeScreenShot) { }
85105
private void OnPointerPressed(object? Sender, PointerPressedEventArgs E)
86106
{
87107
_startPoint = E.GetPosition(this);
@@ -175,7 +195,11 @@ private async void OnPointerReleased(object? Sender, PointerReleasedEventArgs E)
175195
_selectionRect.IsVisible = false;
176196
_infoBox.IsVisible = false;
177197
var selectedRegion = _imageBounds.Intersect(new Rect(_selectionRect.Bounds.X, _selectionRect.Bounds.Y, _selectionRect.Bounds.Width, _selectionRect.Bounds.Height));
198+
var sixLaborsRect = new SixLabors.ImageSharp.Rectangle((int)selectedRegion.X,
199+
(int)selectedRegion.Y, (int)selectedRegion.Width, (int)selectedRegion.Height);
200+
_resultRect.TrySetResult(sixLaborsRect);
178201
DebugHelper.WriteLine($"RegionSelectorWindow.OnPointerReleased: Region: {selectedRegion}");
202+
if (!TakeScreenshot) return;
179203
try
180204
{
181205
await Task.Run(() =>
@@ -191,14 +215,16 @@ await Task.Run(() =>
191215
DebugHelper.WriteLine("RegionSelectorWindow.OnPointerReleased: _image is null");
192216
return;
193217
}
194-
_image.Mutate(Context => Context.Crop(new SixLabors.ImageSharp.Rectangle((int)selectedRegion.X,
195-
(int)selectedRegion.Y, (int)selectedRegion.Width, (int)selectedRegion.Height)));
218+
_image.Mutate(Context => Context.Crop(sixLaborsRect));
219+
_resultImg.TrySetResult(_image);
220+
if (IsSilentMode) return;
196221
DebugHelper.WriteLine("Running image task");
197222
UploadManager.RunImageTask(_image, TaskSettings.GetDefaultTaskSettings());
198223
});
199224
}
200225
catch (Exception ex)
201226
{
227+
_resultImg.TrySetException(ex);
202228
ShowErrorDialog(ex);
203229
}
204230
App.MyMainWindow?.Show();
@@ -238,24 +264,30 @@ private void OnKeyDown(object? sender, KeyEventArgs e)
238264

239265
private async void OnInit(object? Sender, EventArgs EventArgs)
240266
{
241-
foreach (var win in App.MyMainWindow?.OwnedWindows.Where(w => w != this && w.IsVisible) ?? [])
267+
if (!IsSilentMode)
242268
{
243-
_ownershipMap[win] = win.Owner; // Save original owner
244-
win.Hide();
245-
windowsHiddenByUs.Add(win);
246-
}
247-
if (App.MyMainWindow != null && App.MyMainWindow.IsVisible)
248-
{
249-
_ownershipMap[App.MyMainWindow] = App.MyMainWindow.Owner;
250-
App.MyMainWindow.Hide(); // Hide makes it lose relationship with child windows.
251-
windowsHiddenByUs.Add(App.MyMainWindow);
269+
foreach (var win in App.MyMainWindow?.OwnedWindows.Where(w => w != this && w.IsVisible) ?? [])
270+
{
271+
_ownershipMap[win] = win.Owner; // Save original owner
272+
win.Hide();
273+
windowsHiddenByUs.Add(win);
274+
}
275+
276+
if (App.MyMainWindow != null && App.MyMainWindow.IsVisible)
277+
{
278+
_ownershipMap[App.MyMainWindow] = App.MyMainWindow.Owner;
279+
App.MyMainWindow.Hide(); // Hide makes it lose relationship with child windows.
280+
windowsHiddenByUs.Add(App.MyMainWindow);
281+
}
252282
}
253283

284+
if (!TakeScreenshot) return;
254285
// Screenshotting can sometimes take time and block the UI thread.
255286
// It can also fail, so we have to handle it gracefully.
256287
try
257288
{
258-
var captureTask = Task.Factory.StartNew(async () => await TaskHelpers.GetScreenshot().CaptureActiveMonitor(),
289+
var captureTask = Task.Factory.StartNew(
290+
async () => await TaskHelpers.GetScreenshot().CaptureActiveMonitor(),
259291
TaskCreationOptions.LongRunning).Unwrap();
260292

261293

@@ -282,7 +314,8 @@ private async void OnInit(object? Sender, EventArgs EventArgs)
282314
await _image.SaveAsPngAsync(_imageStream);
283315
_imageStream.Position = 0;
284316
_imageBounds = new Rect(_image.Bounds.X, _image.Bounds.Y, _image.Bounds.Width, _image.Bounds.Height);
285-
DebugHelper.WriteLine($"_imageStream {_imageStream.Length} (Readable? {_imageStream.CanRead}) bytes raw image bounds {_image.Bounds}");
317+
DebugHelper.WriteLine(
318+
$"_imageStream {_imageStream.Length} (Readable? {_imageStream.CanRead}) bytes raw image bounds {_image.Bounds}");
286319
try
287320
{
288321
Background = new ImageBrush
@@ -323,23 +356,29 @@ void Visit(Window w)
323356
}
324357
private void OnClosed(object? Sender, EventArgs E)
325358
{
359+
_resultRect.TrySetResult(null);
360+
_resultImg.TrySetResult(null);
326361
_imageStream?.Dispose();
327362
_imageStream = null;
328-
var sortedWindows = TopoSortWindows(windowsHiddenByUs);
329-
330-
foreach (var win in sortedWindows)
363+
if (!IsSilentMode)
331364
{
332-
if (_ownershipMap.TryGetValue(win, out var owner) && owner?.IsVisible == true)
333-
{
334-
win.Show(owner as Window);
335-
}
336-
else
365+
var sortedWindows = TopoSortWindows(windowsHiddenByUs);
366+
367+
foreach (var win in sortedWindows)
337368
{
338-
win.Show();
369+
if (_ownershipMap.TryGetValue(win, out var owner) && owner?.IsVisible == true)
370+
{
371+
win.Show(owner as Window);
372+
}
373+
else
374+
{
375+
win.Show();
376+
}
339377
}
378+
379+
_ownershipMap.Clear();
380+
windowsHiddenByUs.Clear();
340381
}
341-
_ownershipMap.Clear();
342-
windowsHiddenByUs.Clear();
343382
}
344383
private void OnLostFocus(object? Sender, RoutedEventArgs E)
345384
{

0 commit comments

Comments
 (0)