Skip to content

Commit

Permalink
Implement flip / mirror
Browse files Browse the repository at this point in the history
Flip and mirror now handled in the camera control itself. These can be set independently of the camera and do not require permission at the camera level.
  • Loading branch information
victor-david committed Aug 19, 2020
1 parent 714e0f3 commit 35836e3
Show file tree
Hide file tree
Showing 14 changed files with 253 additions and 294 deletions.
176 changes: 127 additions & 49 deletions src/Camera.App/Core/CameraControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,16 +20,19 @@ namespace Restless.App.Camera.Core
/// Represents a composite control to view and move (if supported) a camera
/// </summary>
[TemplatePart(Name = PartImage, Type = typeof(Controls.Image))]
[TemplatePart(Name = PartStatus, Type = typeof(Controls.Border))]
[TemplatePart(Name = PartError, Type = typeof(Controls.Border))]
[TemplatePart(Name = PartController, Type = typeof(Controls.Border))]
public class CameraControl : Controls.Control
{
#region Private
private const string PartImage = "PART_Image";
private const string PartStatus = "PART_Status";
private const string PartError = "PART_Error";
private const string PartController = "PART_Controller";

private Controls.Image imageControl;
private Controls.Border statusControl;
private Controls.Border errorControl;
private Controls.Border controllerControl;

Expand Down Expand Up @@ -416,6 +419,45 @@ public double ImageMinWidth
/// Identifies the <see cref="ImageMinWidth"/> dependency property.
/// </summary>
public static readonly DependencyProperty ImageMinWidthProperty = ImageMinWidthPropertyKey.DependencyProperty;

/// <summary>
/// Gets or sets a boolean value that determines if the video image is flipped vertically.
/// </summary>
public bool IsFlipped
{
get => (bool)GetValue(IsFlippedProperty);
set => SetValue(IsFlippedProperty, value);
}

/// <summary>
/// Identifies the <see cref="IsFlipped"/> dependency property.
/// </summary>
public static readonly DependencyProperty IsFlippedProperty = DependencyProperty.Register
(
nameof(IsFlipped), typeof(bool), typeof(CameraControl), new PropertyMetadata(false, OnIsOrientationChanged)
);

/// <summary>
/// Gets or sets a boolean value that determines if the video image is mirrored horizontally.
/// </summary>
public bool IsMirrored
{
get => (bool)GetValue(IsMirroredProperty);
set => SetValue(IsMirroredProperty, value);
}

/// <summary>
/// Identifies the <see cref="IsMirrored"/> dependency property.
/// </summary>
public static readonly DependencyProperty IsMirroredProperty = DependencyProperty.Register
(
nameof(IsMirrored), typeof(bool), typeof(CameraControl), new PropertyMetadata(false, OnIsOrientationChanged)
);

private static void OnIsOrientationChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
{
(d as CameraControl)?.SetOrientation();
}
#endregion

/************************************************************************/
Expand Down Expand Up @@ -670,9 +712,15 @@ public override void OnApplyTemplate()
}

imageControl = GetTemplateChild(PartImage) as Controls.Image;
statusControl = GetTemplateChild(PartStatus) as Controls.Border;
errorControl = GetTemplateChild(PartError) as Controls.Border;
controllerControl = GetTemplateChild(PartController) as Controls.Border;

if (imageControl == null || statusControl == null || errorControl == null || controllerControl == null)
{
throw new NotImplementedException("CameraControl template not implemented correctly");
}

Storyboard.SetTarget(ShowController, controllerControl);
Storyboard.SetTargetProperty(ShowController, new PropertyPath(HeightProperty));

Expand All @@ -682,16 +730,13 @@ public override void OnApplyTemplate()
Storyboard.SetTarget(HideErrorControl, errorControl);
Storyboard.SetTargetProperty(HideErrorControl, new PropertyPath(OpacityProperty));

if (imageControl != null)
{
imageControl.MouseLeftButtonDown += ImageControlMouseLeftButtonDown;
imageControl.MouseMove += ImageControlMouseMove;
imageControl.MouseLeave += ImageControlMouseLeave;
imageControl.MouseUp += ImageControlMouseUp;
imageControl.MouseWheel += ImageControlMouseWheel;
imageControl.SizeChanged += ImageControlSizeChanged;
InitializeImageTransforms();
}
imageControl.MouseLeftButtonDown += ImageControlMouseLeftButtonDown;
imageControl.MouseMove += ImageControlMouseMove;
imageControl.MouseLeave += ImageControlMouseLeave;
imageControl.MouseUp += ImageControlMouseUp;
imageControl.MouseWheel += ImageControlMouseWheel;
imageControl.SizeChanged += ImageControlSizeChanged;
InitializeImageTransforms();

InitializeIsMouseCameraMotionAvailable();
/*
Expand Down Expand Up @@ -766,6 +811,7 @@ protected override void OnRenderSizeChanged(SizeChangedInfo sizeInfo)
{
base.OnRenderSizeChanged(sizeInfo);
if (sizeInfo.WidthChanged) SetWidths(sizeInfo.NewSize.Width);
//if (sizeInfo.HeightChanged) AdjustStatusBanner();
}
#endregion

Expand All @@ -783,7 +829,7 @@ private void ImageControlMouseMove(object sender, MouseEventArgs e)
if (!isMouseDown) return;
if (isLeftControlKeyDown && !IsMouseCameraMotionAvailable) return;

System.Windows.Point point = e.GetPosition(imageControl);
Point point = e.GetPosition(imageControl);
double deltaX = point.X - mouseDownPoint.X;
double deltaY = point.Y - mouseDownPoint.Y;

Expand Down Expand Up @@ -935,12 +981,15 @@ private void InitializeCamera()
GoPresetCommand = RelayCommand.Create(RunGoPresetCommand);
SetPresetCommand = RelayCommand.Create(RunSetPresetCommand);
ClearPresetCommand = RelayCommand.Create(RunClearPresetCommand);
ControllerWidth += 256;
ControllerWidth += 258;
PresetList = Enumerable.Range(1, Math.Min((int)Camera.MaxPreset, preset.MaxPreset));
}

isControllerEnabled = IsPluginMotion || IsPluginPreset;

IsFlipped = Camera.Flags.HasFlag(CameraFlags.Flip);
IsMirrored = Camera.Flags.HasFlag(CameraFlags.Mirror);

StatusAlignment = GetStatusAlignment();

FullScreenCommand = RelayCommand.Create(RunFullScreenCommand);
Expand Down Expand Up @@ -1087,28 +1136,46 @@ private void ReturnFromFullScreen()
// placeholder
}

private void ZoomImage(int factor)

private double GetImageScaledWidth()
{
if (GetImageScaleTransform() is ScaleTransform scale)
{
double value = scale.ScaleX;
if (factor > 0)
{
value = Math.Round(Math.Min(value + 0.1, 5.0), 1);
}
else if (factor < 0)
{
value = Math.Round(Math.Max(value - 0.1, 0.4), 1);
}
else
{
value = 1.0;
}
return imageControl.ActualWidth * scale.ScaleX;
}
return 0.0;
}

scale.ScaleX = scale.ScaleY = value;
imageScaledWidth = imageControl.ActualWidth * value;
SetWidths(imageControl.ActualWidth * value);
private void SetWidths(double proposedWidth)
{
imageScaledWidth = GetImageScaledWidth();
StatusWidth = Math.Min(Math.Min(Math.Max(proposedWidth, imageScaledWidth), imageScaledWidth), ActualWidth);
/* ErrorWidth default = double.NaN. Do not set to zero or initial failure to connect won't show */
if (StatusWidth > 0) ErrorWidth = StatusWidth;
}
#endregion

/************************************************************************/

#region Private methods (transforms)
private void InitializeImageTransforms()
{
// this method is called from OnApplyTemplate()
TransformGroup group = new TransformGroup();
group.Children.Add(new TranslateTransform());
group.Children.Add(new ScaleTransform(1.0, 1.0));
group.Children.Add(new ScaleTransform(1.0, 1.0));
imageControl.RenderTransform = group;
SetOrientation();
}

private TranslateTransform GetImageTranslateTransform()
{
if (imageControl?.RenderTransform is TransformGroup group && group.Children.Count > 0)
{
return group.Children[0] as TranslateTransform;
}
return null;
}

private ScaleTransform GetImageScaleTransform()
Expand All @@ -1120,39 +1187,46 @@ private ScaleTransform GetImageScaleTransform()
return null;
}

private TranslateTransform GetImageTranslateTransform()
private ScaleTransform GetImageFlipMirrorTransform()
{
if (imageControl?.RenderTransform is TransformGroup group && group.Children.Count > 0)
if (imageControl?.RenderTransform is TransformGroup group && group.Children.Count > 2)
{
return group.Children[0] as TranslateTransform;
return group.Children[2] as ScaleTransform;
}
return null;
}

private double GetImageScaledWidth()
private void ZoomImage(int factor)
{
if (GetImageScaleTransform() is ScaleTransform scale)
{
return imageControl.ActualWidth * scale.ScaleX;
}
return 0.0;
}
double value = scale.ScaleX;
if (factor > 0)
{
value = Math.Round(Math.Min(value + 0.1, 5.0), 1);
}
else if (factor < 0)
{
value = Math.Round(Math.Max(value - 0.1, 0.4), 1);
}
else
{
value = 1.0;
}

private void SetWidths(double proposedWidth)
{
imageScaledWidth = GetImageScaledWidth();
StatusWidth = Math.Min(Math.Min(Math.Max(proposedWidth, imageScaledWidth), imageScaledWidth), ActualWidth);
/* ErrorWidth default = double.NaN. Do not set to zero or initial failure to connect won't show */
if (StatusWidth > 0) ErrorWidth = StatusWidth;
scale.ScaleX = scale.ScaleY = value;
imageScaledWidth = imageControl.ActualWidth * value;
SetWidths(imageControl.ActualWidth * value);
}
}

// method called from OnApplyTemplate() only is imageControl != null
private void InitializeImageTransforms()
private void SetOrientation()
{
TransformGroup group = new TransformGroup();
group.Children.Add(new TranslateTransform());
group.Children.Add(new ScaleTransform(1.0, 1.0));
imageControl.RenderTransform = group;
if (GetImageFlipMirrorTransform() is ScaleTransform transform)
{
transform.ScaleX = IsMirrored ? -1.0 : 1.0;
transform.ScaleY = IsFlipped ? -1.0 : 1.0;
}
}

private void ResetImageTransforms()
Expand All @@ -1170,7 +1244,11 @@ private void ResetImageTransforms()
SetWidths(imageControl.ActualWidth);
}
}
#endregion

/************************************************************************/

#region Private methods (storyboards)
private void InitializeStoryBoards()
{
ShowController = new Storyboard() { FillBehavior = FillBehavior.HoldEnd };
Expand Down
12 changes: 12 additions & 0 deletions src/Camera.App/Core/CameraWallControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -334,6 +334,15 @@ private VerticalAlignment GetStatusAlignment(CameraRow camera)
return VerticalAlignment.Center;
}

private void UpdateOrientation(long id)
{
if (GetCameraHost(id) is CameraHostBorder host)
{
host.CameraControl.IsFlipped = host.CameraControl.Camera.Flags.HasFlag(CameraFlags.Flip);
host.CameraControl.IsMirrored= host.CameraControl.Camera.Flags.HasFlag(CameraFlags.Mirror);
}
}

private void ShowCameraLocation(long id)
{
foreach (var child in Children.OfType<CameraHostBorder>())
Expand All @@ -357,6 +366,9 @@ private void ExecutePushCommand(PushCommand command)
case PushCommandType.UpdateStatusBanner:
UpdateStatusBanner(command.Id);
break;
case PushCommandType.UpdateOrientation:
UpdateOrientation(command.Id);
break;
case PushCommandType.ShowCameraLocation:
ShowCameraLocation(command.Id);
break;
Expand Down
4 changes: 4 additions & 0 deletions src/Camera.App/Core/PushCommandType.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,10 @@ public enum PushCommandType
/// </summary>
UpdateStatusBanner,
/// <summary>
/// Update the camera's orientation (flip, mirror)
/// </summary>
UpdateOrientation,
/// <summary>
/// Show the camera's location on the wall.
/// </summary>
ShowCameraLocation,
Expand Down
2 changes: 1 addition & 1 deletion src/Camera.App/Resources/Dictionary/Box.xaml
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@
<Border x:Name="InnerBorder" Height="8" Width="8" CornerRadius="1"/>

</Border>
<ContentPresenter Grid.Column="1" Margin="6,0"/>
<ContentPresenter Grid.Column="1" Margin="6,0" VerticalAlignment="Center"/>
</StackPanel>

<ControlTemplate.Triggers>
Expand Down
Loading

0 comments on commit 35836e3

Please sign in to comment.