diff options
Diffstat (limited to 'Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture')
3 files changed, 116 insertions, 30 deletions
diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Tango.MachineStudio.DataCapture.csproj b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Tango.MachineStudio.DataCapture.csproj index efa6d2ad7..384a3fc32 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Tango.MachineStudio.DataCapture.csproj +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Tango.MachineStudio.DataCapture.csproj @@ -169,6 +169,10 @@ <Project>{cb0b0aa2-bb24-4bca-a720-45e397684e12}</Project> <Name>Tango.MachineStudio.Common</Name> </ProjectReference> + <ProjectReference Include="..\Tango.MachineStudio.Logging\Tango.MachineStudio.Logging.csproj"> + <Project>{1674f726-0e66-414f-b9fd-c6f20d7f07c7}</Project> + <Name>Tango.MachineStudio.Logging</Name> + </ProjectReference> </ItemGroup> <ItemGroup> <Resource Include="Images\data-capture.jpg" /> @@ -185,5 +189,8 @@ <ItemGroup> <Resource Include="Images\capture-device.png" /> </ItemGroup> + <ItemGroup> + <Folder Include="Messages\" /> + </ItemGroup> <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" /> </Project>
\ No newline at end of file diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs index b3d717263..af65c1430 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/ViewModels/MainViewVM.cs @@ -8,16 +8,21 @@ using System.Text; using System.Threading.Tasks; using System.Windows.Controls; using System.Windows.Media.Imaging; +using Tango.BL.Entities; +using Tango.BL.Enumerations; using Tango.Core.Commands; +using Tango.Core.Helpers; using Tango.Integration.Diagnostics; using Tango.Integration.Operation; using Tango.Integration.Services; using Tango.MachineStudio.Common.Diagnostics; +using Tango.MachineStudio.Common.EventLogging; using Tango.MachineStudio.Common.Notifications; using Tango.MachineStudio.Common.StudioApplication; using Tango.MachineStudio.Common.Video; using Tango.MachineStudio.DataCapture.Recording; using Tango.MachineStudio.DataCapture.Views; +using Tango.MachineStudio.Logging.ViewModels; using Tango.PMR.Diagnostics; using Tango.Settings; using Tango.SharedUI; @@ -34,6 +39,7 @@ namespace Tango.MachineStudio.DataCapture.ViewModels private INotificationProvider _notification; private IStudioApplicationManager _applicationManager; private IDiagnosticsFrameProvider _frameProvider; + private IEventLogger _eventLogger; private String _recordingsFolder; private BarItem _recordingBarItem; private BarItem _playerBarItem; @@ -100,6 +106,16 @@ namespace Tango.MachineStudio.DataCapture.ViewModels set { _captureDevices = value; RaisePropertyChangedAuto(); } } + private TimelineViewVM _timelineViewVM; + /// <summary> + /// Gets or sets the timeline view VM. + /// </summary> + public TimelineViewVM TimelineViewVM + { + get { return _timelineViewVM; } + set { _timelineViewVM = value; RaisePropertyChangedAuto(); } + } + #endregion #region Commands @@ -161,15 +177,20 @@ namespace Tango.MachineStudio.DataCapture.ViewModels /// <summary> /// Initializes a new instance of the <see cref="MainViewVM"/> class. /// </summary> - public MainViewVM(IVideoCaptureProvider videoCaptureProvider, INotificationProvider notification, IStudioApplicationManager applicationManager, IDiagnosticsFrameProvider frameProvider) + public MainViewVM(IVideoCaptureProvider videoCaptureProvider, INotificationProvider notification, IStudioApplicationManager applicationManager, IDiagnosticsFrameProvider frameProvider, IEventLogger eventLogger) { _notification = notification; _applicationManager = applicationManager; _frameProvider = frameProvider; + _eventLogger = eventLogger; + + _eventLogger.NewLog += _eventLogger_NewLog; Recorder = new DiagnosticsFileRecorder(); Player = new DiagnosticsFilePlayer(); + TimelineViewVM = new TimelineViewVM(notification) { EnableTimeMarker = true }; + VideoCaptureProvider = videoCaptureProvider; Recordings = new ObservableCollection<DataRecording>(); @@ -204,6 +225,14 @@ namespace Tango.MachineStudio.DataCapture.ViewModels #region Event Handlers + private void _eventLogger_NewLog(object sender, MachinesEvent ev) + { + if (Recorder.IsRecording) + { + Recorder.Write(ev); + } + } + private void ApplicationManager_ConnectedMachineChanged(object sender, IExternalBridgeClient machine) { MachineOperator = machine; @@ -222,7 +251,10 @@ namespace Tango.MachineStudio.DataCapture.ViewModels { CaptureDevices.First().Invoke(() => { - Recorder.Write(CaptureDevices.Where(x => x.VideoSource != null).Select(x => x.VideoSource.GetAsFrozen() as BitmapSource)); + if (Recorder.IsRecording) + { + Recorder.Write(CaptureDevices.Where(x => x.VideoSource != null).Select(x => x.VideoSource.GetAsFrozen() as BitmapSource)); + } }); }); } @@ -240,6 +272,8 @@ namespace Tango.MachineStudio.DataCapture.ViewModels { Recordings.Add(new DataRecording(file, File.GetCreationTime(file))); } + + Recordings = Recordings.OrderByDescending(x => x.Date).ToObservableCollection(); } /// <summary> @@ -248,7 +282,11 @@ namespace Tango.MachineStudio.DataCapture.ViewModels /// <param name="recording">The recording.</param> private void RemoveRecording(DataRecording recording) { - Recordings.Remove(recording); + if (_notification.ShowQuestion("Are you sure you want to remove the specified recording?")) + { + Recordings.Remove(recording); + PathHelper.TryDeleteFile(recording.FilePath); + } } /// <summary> @@ -275,6 +313,8 @@ namespace Tango.MachineStudio.DataCapture.ViewModels { SelectedRecording.Player = new DiagnosticsFilePlayer(); await SelectedRecording.Player.Load(SelectedRecording.FilePath); + TimelineViewVM.Initialize(SelectedRecording.Player.MachineEvents); + TimelineViewVM.TimelineMaxTime = SelectedRecording.Player.TotalTime; } } @@ -327,6 +367,8 @@ namespace Tango.MachineStudio.DataCapture.ViewModels CaptureDevices[i].VideoSource = frame.VideoFrames[i].ToByteArray().ToBitmapSource(); } }); + + TimelineViewVM.CurrentPosition = (sender as DiagnosticsFilePlayer).CurrentTime; } } @@ -335,7 +377,7 @@ namespace Tango.MachineStudio.DataCapture.ViewModels using (_notification.PushTaskItem("Starting Recording...")) { Recorder.Start(); - + _eventLogger.Log(EventTypes.RecordingStarted, "Recording Started..."); _recordingBarItem.Push(); } @@ -350,6 +392,8 @@ namespace Tango.MachineStudio.DataCapture.ViewModels { await Recorder.Stop(); _recordingBarItem.Pop(); + + _eventLogger.Log(EventTypes.RecordingStopped, "Recording Stopped..."); } String recordingName = _notification.ShowTextInput("Enter recording name", "Recording name"); @@ -370,6 +414,7 @@ namespace Tango.MachineStudio.DataCapture.ViewModels else if (Player.IsPlaying) { await Player.Stop(); + TimelineViewVM.CurrentPosition = TimeSpan.Zero; CaptureDevices.ForEach(x => x.EnableSourceUpdate()); _frameProvider.Disable = false; _playerBarItem.Pop(); diff --git a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Views/MainView.xaml b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Views/MainView.xaml index 445d0d216..37f92dea7 100644 --- a/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Views/MainView.xaml +++ b/Software/Visual_Studio/MachineStudio/Modules/Tango.MachineStudio.DataCapture/Views/MainView.xaml @@ -8,6 +8,7 @@ xmlns:mahapps="http://metro.mahapps.com/winfx/xaml/controls" xmlns:converters="clr-namespace:Tango.SharedUI.Converters;assembly=Tango.SharedUI" xmlns:vm="clr-namespace:Tango.MachineStudio.DataCapture.ViewModels" + xmlns:logging="clr-namespace:Tango.MachineStudio.Logging.Views;assembly=Tango.MachineStudio.Logging" xmlns:video="clr-namespace:Tango.Video.DirectCapture;assembly=Tango.Video" xmlns:global="clr-namespace:Tango.MachineStudio.DataCapture" xmlns:local="clr-namespace:Tango.MachineStudio.DataCapture.Views" @@ -73,7 +74,7 @@ <Grid Grid.Column="1" Margin="10"> <Grid.RowDefinitions> <RowDefinition Height="430"/> - <RowDefinition Height="419*"/> + <RowDefinition Height="1*"/> </Grid.RowDefinitions> <Grid> @@ -179,26 +180,15 @@ </Grid> <Grid Grid.Row="1"> - - <DockPanel HorizontalAlignment="Center" VerticalAlignment="Top" Margin="60" Visibility="{Binding Recorder.IsRecording,Converter={StaticResource BooleanToVisibilityConverter}}" TextElement.FontSize="20"> - <TextBlock DockPanel.Dock="Left"> - <Run FontWeight="SemiBold" FontStyle="Italic">Total Frames:</Run> - <Run FontStyle="Italic" Foreground="#545454" Text="{Binding Recorder.TotalFramesRecorded,StringFormat={}{0:N0},Mode=OneWay,TargetNullValue=0,FallbackValue=0}"></Run> - </TextBlock> - <TextBlock Margin="80 0 0 0" HorizontalAlignment="Right" Width="250"> - <Run FontWeight="SemiBold" FontStyle="Italic">File Size:</Run> - <Run FontStyle="Italic" Foreground="#545454" Text="{Binding Recorder.TotalBytesRecorded,Mode=OneWay,Converter={StaticResource NumberToFileSizeConverter},TargetNullValue=0,FallbackValue=0}"></Run> - </TextBlock> - </DockPanel> - - <StackPanel VerticalAlignment="Bottom" Margin="0 0 0 50"> + <DockPanel> + <StackPanel VerticalAlignment="Bottom" Margin="0 10 0 0" DockPanel.Dock="Bottom"> <Grid Margin="50 0 0 0"> <StackPanel Orientation="Horizontal" HorizontalAlignment="Left" VerticalAlignment="Center"> - <Button Command="{Binding MediaSeekBackwardCommand}" Margin="0 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="150" Height="150" Background="Transparent"> - <materialDesign:PackIcon Width="100" Height="100" Kind="Rewind" Foreground="{StaticResource AccentColorBrush}" /> + <Button Command="{Binding MediaSeekBackwardCommand}" Margin="0 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="60" Height="60" Background="Transparent"> + <materialDesign:PackIcon Width="40" Height="40" Kind="Rewind" Foreground="{StaticResource AccentColorBrush}" /> </Button> - <Button Command="{Binding MediaPlayPauseCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="200" Height="200" Background="Transparent"> - <materialDesign:PackIcon Width="100" Height="100" Foreground="{StaticResource AccentColorBrush}"> + <Button Command="{Binding MediaPlayPauseCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="80" Height="80" Background="Transparent"> + <materialDesign:PackIcon Width="60" Height="60" Foreground="{StaticResource AccentColorBrush}"> <materialDesign:PackIcon.Style> <Style TargetType="materialDesign:PackIcon"> <Setter Property="Kind" Value="Play"></Setter> @@ -215,18 +205,18 @@ </materialDesign:PackIcon.Style> </materialDesign:PackIcon> </Button> - <Button Command="{Binding MediaStopCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="150" Height="150" Background="Transparent"> - <materialDesign:PackIcon Width="100" Height="100" Kind="Stop" Foreground="{StaticResource AccentColorBrush}" /> + <Button Command="{Binding MediaStopCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="60" Height="60" Background="Transparent"> + <materialDesign:PackIcon Width="40" Height="40" Kind="Stop" Foreground="{StaticResource AccentColorBrush}" /> </Button> - <Button Command="{Binding MediaSeekForwardCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="150" Height="150" Background="Transparent"> - <materialDesign:PackIcon Width="100" Height="100" Kind="FastForward" Foreground="{StaticResource AccentColorBrush}" /> + <Button Command="{Binding MediaSeekForwardCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Padding="0" Width="60" Height="60" Background="Transparent"> + <materialDesign:PackIcon Width="40" Height="40" Kind="FastForward" Foreground="{StaticResource AccentColorBrush}" /> </Button> - <Button Command="{Binding MediaRecordingCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Foreground="#FF7A7A" BorderBrush="#FF8585" Padding="0" Width="100" Height="100" Background="Transparent" ToolTip="Start Recording"> - <materialDesign:PackIcon Width="50" Height="50" Kind="Record" /> + <Button Command="{Binding MediaRecordingCommand}" Margin="20 0 0 0" Style="{StaticResource MaterialDesignFloatingActionButton}" Foreground="#FF7A7A" BorderBrush="#FF8585" Padding="0" Width="50" Height="50" Background="Transparent" ToolTip="Start Recording"> + <materialDesign:PackIcon Width="30" Height="30" Kind="Record" /> </Button> </StackPanel> <Grid> - <Label Margin="0 0 50 0" VerticalAlignment="Center" HorizontalAlignment="Right" Foreground="#FF8585" FontSize="60" FontFamily="{StaticResource digital-7}"> + <Label Margin="0 0 15 0" VerticalAlignment="Center" HorizontalAlignment="Right" Foreground="#FF8585" FontSize="40" FontFamily="{StaticResource digital-7}"> <Label.Style> <Style TargetType="Label"> <Setter Property="Opacity" Value="1"></Setter> @@ -273,8 +263,19 @@ </Label.Style> </Label> </Grid> + + <DockPanel HorizontalAlignment="Center" VerticalAlignment="Center" Margin="0" TextElement.FontSize="16" Visibility="{Binding Recorder.IsRecording,Converter={StaticResource BooleanToVisibilityConverter}}"> + <TextBlock DockPanel.Dock="Left"> + <Run FontWeight="SemiBold" FontStyle="Italic">Total Frames:</Run> + <Run FontStyle="Italic" Foreground="#545454" Text="{Binding Recorder.TotalFramesRecorded,StringFormat={}{0:N0},Mode=OneWay,TargetNullValue=0,FallbackValue=0}"></Run> + </TextBlock> + <TextBlock Margin="80 0 0 0" HorizontalAlignment="Right" Width="250"> + <Run FontWeight="SemiBold" FontStyle="Italic">File Size:</Run> + <Run FontStyle="Italic" Foreground="#545454" Text="{Binding Recorder.TotalBytesRecorded,Mode=OneWay,Converter={StaticResource NumberToFileSizeConverter},TargetNullValue=0,FallbackValue=0}"></Run> + </TextBlock> + </DockPanel> </Grid> - <Slider x:Name="slider" Margin="10 40 50 0" Visibility="{Binding Recorder.IsRecording,Converter={StaticResource BooleanToVisibilityInverseConverter}}" Maximum="{Binding Player.TotalFrames}" Value="{Binding Player.CurrentFrame,Mode=OneWay}"> + <Slider x:Name="slider" Margin="0 10 20 0" Visibility="{Binding Recorder.IsRecording,Converter={StaticResource BooleanToVisibilityInverseConverter}}" Maximum="{Binding Player.TotalFrames}" Value="{Binding Player.CurrentFrame,Mode=OneWay}"> <i:Interaction.Triggers> <i:EventTrigger EventName="PreviewMouseDown"> <i:InvokeCommandAction Command="{Binding MediaSeekHoldCommand}"></i:InvokeCommandAction> @@ -285,6 +286,39 @@ </i:Interaction.Triggers> </Slider> </StackPanel> + + <logging:TimelineView RenderTransformOrigin="0.5,0.5" DataContext="{Binding TimelineViewVM}" Margin="0 0 0 10"> + <FrameworkElement.Style> + <Style TargetType="FrameworkElement"> + <Setter Property="RenderTransform"> + <Setter.Value> + <ScaleTransform ScaleX="0" ScaleY="0" /> + </Setter.Value> + </Setter> + <Style.Triggers> + <DataTrigger Binding="{Binding RelativeSource={RelativeSource AncestorType=UserControl},Path=DataContext.Player.IsPlaying}" Value="True"> + <DataTrigger.EnterActions> + <BeginStoryboard> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" To="1" Duration="00:00:0.2" /> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" To="1" Duration="00:00:0.2" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.EnterActions> + <DataTrigger.ExitActions> + <BeginStoryboard> + <Storyboard> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleX" To="0" Duration="00:00:0.2" /> + <DoubleAnimation Storyboard.TargetProperty="RenderTransform.ScaleY" To="0" Duration="00:00:0.2" /> + </Storyboard> + </BeginStoryboard> + </DataTrigger.ExitActions> + </DataTrigger> + </Style.Triggers> + </Style> + </FrameworkElement.Style> + </logging:TimelineView> + </DockPanel> </Grid> </Grid> </Grid> |
