Skip to content

Commit

Permalink
🎨 Transmit the selected image region to the backend.
Browse files Browse the repository at this point in the history
  • Loading branch information
hexawyz committed Feb 2, 2025
1 parent df81794 commit 08b1ee5
Show file tree
Hide file tree
Showing 2 changed files with 59 additions and 17 deletions.
2 changes: 1 addition & 1 deletion src/Exo/Service/Exo.Service.Core/EmbeddedMonitorService.cs
Original file line number Diff line number Diff line change
Expand Up @@ -263,7 +263,7 @@ public async ValueTask<bool> SetBuiltInGraphicsAsync(Guid graphicsId, Cancellati

public async ValueTask<bool> SetImageAsync(UInt128 imageId, Rectangle region, CancellationToken cancellationToken)
{
if (imageId != _currentImageId && (region.Left != _currentRegionLeft || region.Top != _currentRegionTop || region.Width != _currentRegionWidth || region.Height != _currentRegionHeight))
if (imageId != _currentImageId || region.Left != _currentRegionLeft || region.Top != _currentRegionTop || region.Width != _currentRegionWidth || region.Height != _currentRegionHeight)
{
if (_monitor is not null)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
using Exo.Contracts.Ui.Settings;
using Exo.Settings.Ui.Services;
using Exo.Ui;
using Microsoft.UI.Xaml.Controls.Primitives;

namespace Exo.Settings.Ui.ViewModels;

Expand Down Expand Up @@ -208,14 +209,7 @@ private EmbeddedMonitorCapabilities Capabilities
public EmbeddedMonitorGraphicsViewModel? CurrentGraphics
{
get => _currentGraphics;
set
{
bool wasChanged = IsChanged;
if (SetValue(ref _currentGraphics, value, ChangedProperty.CurrentGraphics))
{
OnChangeStateChange(wasChanged);
}
}
set => SetChangeableValue(ref _currentGraphics, value, ChangedProperty.CurrentGraphics);
}

internal void UpdateInformation(EmbeddedMonitorInformation information)
Expand Down Expand Up @@ -308,7 +302,7 @@ internal override async ValueTask ApplyAsync(CancellationToken cancellationToken
{
DeviceId = Monitor.Owner.DeviceId,
MonitorId = Monitor.MonitorId,
GraphicsId = Id
GraphicsId = Id
},
cancellationToken
).ConfigureAwait(false);
Expand Down Expand Up @@ -347,17 +341,34 @@ private void OnMonitorPropertyChanged(object? sender, PropertyChangedEventArgs e
}

public override bool IsChanged => (_image?.Id).GetValueOrDefault() != _initialImageId;
public override bool IsValid => _image is not null && _cropRectangle.Width > 0 && _cropRectangle.Height > 0 && (double)_cropRectangle.Width / _cropRectangle.Height == AspectRatio;

public override bool IsValid => _image is not null && IsRegionValid(_cropRectangle);

private bool IsRegionValid(Rectangle rectangle)
=> rectangle.Width > 0 && rectangle.Height > 0 && (_image is null || rectangle.Width <= _image.Width && rectangle.Height <= _image.Height) && rectangle.Width * AspectRatio == rectangle.Height;

public ImageViewModel? Image
{
get => _image;
set
{
bool wasChanged = IsChanged;
if (SetValue(ref _image, value, ChangedProperty.Image))
if (SetChangeableValue(ref _image, value, ChangedProperty.Image))
{
OnChangeStateChange(wasChanged);
// TODO: Improve this to initialize the crop rectangle to a better value automatically.
if (value is not null && !IsRegionValid(_cropRectangle))
{
var imageSize = Monitor.ImageSize;
if (imageSize.Width == imageSize.Height)
{
var s = Math.Min(value.Width, value.Height);
CropRectangle = new() { Left = (value.Width - s) >>> 1, Top = (value.Height - s) >>> 1, Width = s, Height = s };
}
}
else
{
// Not ideal but good enough for now.
IApplicable.NotifyCanExecuteChanged();
}
}
}
}
Expand All @@ -374,16 +385,47 @@ public Rectangle CropRectangle
get => _cropRectangle;
set
{
SetValue(ref _cropRectangle, value, ChangedProperty.CropRectangle);
var oldRectangle = _cropRectangle;
if (value != oldRectangle)
{
bool wasChanged = IsChanged;
_cropRectangle = value;
NotifyPropertyChanged(ChangedProperty.CropRectangle);
bool isChanged = IsChanged;
OnChangeStateChange(wasChanged, isChanged);

// Propagate the applicable status change. Trying to make this as efficient as possible by minimizing the computations.
// Probably introducing a persisted IsValid flag would be better. (Also maybe just refactor the IApplicable stuff)
if (isChanged == wasChanged && _image is not null)
{
if (IsRegionValid(oldRectangle) != IsRegionValid(value))
{
IApplicable.NotifyCanExecuteChanged();
}
}
}
}
}

public double AspectRatio => Monitor.AspectRatio;

public ReadOnlyObservableCollection<ImageViewModel> AvailableImages => Monitor.Owner.AvailableImages;

internal override ValueTask ApplyAsync(CancellationToken cancellationToken)
internal override async ValueTask ApplyAsync(CancellationToken cancellationToken)
{
throw new NotImplementedException();
if (_image is not { } image) throw new InvalidOperationException();
var rectangle = _cropRectangle;

await Monitor.Owner.EmbeddedMonitorService.SetImageAsync
(
new()
{
DeviceId = Monitor.Owner.DeviceId,
MonitorId = Monitor.MonitorId,
ImageId = image.Id,
CropRegion = new() { Left = rectangle.Left, Top = rectangle.Top, Width = rectangle.Width, Height = rectangle.Height },
},
cancellationToken
);
}
}

0 comments on commit 08b1ee5

Please sign in to comment.