1
0
mirror of https://github.com/Artemis-RGB/Artemis synced 2025-12-13 05:48:35 +00:00

Noise brush - Greatly improved performance on large layouts

Profiles core - Pass real delta time brushes/effects
Profiles core - Allow main segment to be disabled on layers
General module - Removed test data model
General module - Removed expensive open window scan, was fun to try :P
Profile editor - Refactored segments
Profile editor - Updated segment visuals to scale well when really narrow
This commit is contained in:
SpoinkyNL 2020-07-25 23:01:37 +02:00
parent 72d606f40d
commit 2045b230c2
13 changed files with 584 additions and 396 deletions

View File

@ -70,12 +70,12 @@ namespace Artemis.Core.Models.Profile
// Update the layer timeline, this will give us a new delta time which could be negative in case the main segment wrapped back
// to it's start
var timelineDeltaTime = UpdateTimeline(deltaTime);
UpdateTimeline(deltaTime);
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
{
baseLayerEffect.BaseProperties?.Update();
baseLayerEffect.Update(timelineDeltaTime);
baseLayerEffect.Update(deltaTime);
}
// Iterate the children in reverse because that's how they must be rendered too

View File

@ -70,7 +70,6 @@ namespace Artemis.Core.Models.Profile
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
ApplyRenderElementEntity();
ApplyRenderElementDefaults();
}
internal LayerEntity LayerEntity { get; set; }
@ -224,17 +223,17 @@ namespace Artemis.Core.Models.Profile
// Update the layer timeline, this will give us a new delta time which could be negative in case the main segment wrapped back
// to it's start
var timelineDeltaTime = UpdateTimeline(deltaTime);
UpdateTimeline(deltaTime);
General.Update();
Transform.Update();
LayerBrush.BaseProperties?.Update();
LayerBrush.Update(timelineDeltaTime);
LayerBrush.Update(deltaTime);
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
{
baseLayerEffect.BaseProperties?.Update();
baseLayerEffect.Update(timelineDeltaTime);
baseLayerEffect.Update(deltaTime);
}
}
@ -256,7 +255,10 @@ namespace Artemis.Core.Models.Profile
else
{
var progress = timeOverride.TotalMilliseconds % MainSegmentLength.TotalMilliseconds;
TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
if (progress > 0)
TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
else
TimelinePosition = StartSegmentLength;
}
}
else
@ -437,6 +439,39 @@ namespace Artemis.Core.Models.Profile
return position;
}
/// <summary>
/// Excludes the provided path from the translations applied to the layer by applying translations that cancel the
/// layer translations out
/// </summary>
/// <param name="path"></param>
public void ExcludePathFromTranslation(SKPath path)
{
var sizeProperty = Transform.Scale.CurrentValue;
var rotationProperty = Transform.Rotation.CurrentValue;
var anchorPosition = GetLayerAnchorPosition(Path);
var anchorProperty = Transform.AnchorPoint.CurrentValue;
// Translation originates from the unscaled center of the shape and is tied to the anchor
var x = anchorPosition.X - Bounds.MidX - anchorProperty.X * Bounds.Width;
var y = anchorPosition.Y - Bounds.MidY - anchorProperty.Y * Bounds.Height;
var reversedXScale = 1f / (sizeProperty.Width / 100f);
var reversedYScale = 1f / (sizeProperty.Height / 100f);
if (General.FillType == LayerFillType.Stretch)
{
path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y));
path.Transform(SKMatrix.MakeScale(reversedXScale, reversedYScale, anchorPosition.X, anchorPosition.Y));
path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
}
else
{
path.Transform(SKMatrix.MakeRotationDegrees(rotationProperty * -1, anchorPosition.X, anchorPosition.Y));
path.Transform(SKMatrix.MakeTranslation(x * -1, y * -1));
}
}
#endregion
#region LED management

View File

@ -17,8 +17,7 @@ namespace Artemis.Core.Models.Profile
{
protected void ApplyRenderElementDefaults()
{
if (MainSegmentLength <= TimeSpan.Zero)
MainSegmentLength = TimeSpan.FromSeconds(5);
MainSegmentLength = TimeSpan.FromSeconds(5);
}
protected void ApplyRenderElementEntity()

View File

@ -172,130 +172,62 @@
<!-- Timeline headers -->
<ScrollViewer Grid.Row="0" x:Name="TimelineHeaderScrollViewer" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" ScrollChanged="TimelineScrollChanged">
<Grid Background="{DynamicResource MaterialDesignCardBackground}">
<!-- Caret -->
<Grid.ColumnDefinitions>
<ColumnDefinition Width="{Binding TimelineViewModel.StartSegmentWidth}" />
<ColumnDefinition Width="{Binding TimelineViewModel.MainSegmentWidth}" />
<ColumnDefinition Width="{Binding TimelineViewModel.EndSegmentWidth}" />
</Grid.ColumnDefinitions>
<Canvas Background="{DynamicResource MaterialDesignCardBackground}" Width="{Binding ActualWidth, ElementName=PropertyTimeLine}">
<!-- Timeline segments -->
<ContentControl Canvas.Left="{Binding EndTimelineSegmentViewModel.SegmentStartPosition}" s:View.Model="{Binding EndTimelineSegmentViewModel}" />
<ContentControl Canvas.Left="{Binding MainTimelineSegmentViewModel.SegmentStartPosition}" s:View.Model="{Binding MainTimelineSegmentViewModel}" />
<ContentControl Canvas.Left="{Binding StartTimelineSegmentViewModel.SegmentStartPosition}" s:View.Model="{Binding StartTimelineSegmentViewModel}" />
<Canvas Grid.ColumnSpan="3"
Panel.ZIndex="2"
Margin="{Binding TimeCaretPosition}"
Cursor="SizeWE"
MouseDown="{s:Action TimelineMouseDown}"
MouseUp="{s:Action TimelineMouseUp}"
MouseMove="{s:Action TimelineMouseMove}">
<Polygon Points="-8,0 -8,8 0,20, 8,8 8,0" Fill="{StaticResource SecondaryAccentBrush}" />
<Line X1="0" X2="0" Y1="0" Y2="{Binding ActualHeight, ElementName=ContainerGrid}" StrokeThickness="2" Stroke="{StaticResource SecondaryAccentBrush}" />
</Canvas>
<!-- Timeline caret -->
<Polygon Canvas.Left="{Binding TimeCaretPosition}"
Cursor="SizeWE"
MouseDown="{s:Action TimelineMouseDown}"
MouseUp="{s:Action TimelineMouseUp}"
MouseMove="{s:Action TimelineMouseMove}"
Points="-8,0 -8,8 0,20, 8,8 8,0"
Fill="{StaticResource SecondaryAccentBrush}" />
<Line Canvas.Left="{Binding TimeCaretPosition}"
Cursor="SizeWE"
MouseDown="{s:Action TimelineMouseDown}"
MouseUp="{s:Action TimelineMouseUp}"
MouseMove="{s:Action TimelineMouseMove}"
X1="0"
X2="0"
Y1="0"
Y2="{Binding ActualHeight, ElementName=ContainerGrid}"
StrokeThickness="2"
Stroke="{StaticResource SecondaryAccentBrush}" />
<timeline:PropertyTimelineHeader Grid.Column="0"
Grid.ColumnSpan="3"
Margin="0 25 0 0"
<!-- Timeline header body -->
<timeline:PropertyTimelineHeader Margin="0 25 0 0"
Fill="{DynamicResource MaterialDesignBody}"
PixelsPerSecond="{Binding ProfileEditorService.PixelsPerSecond}"
HorizontalOffset="{Binding ContentHorizontalOffset, ElementName=TimelineHeaderScrollViewer}"
VisibleWidth="{Binding ActualWidth, ElementName=TimelineHeaderScrollViewer}"
OffsetFirstValue="True"
Width="{Binding ActualWidth, ElementName=PropertyTimeLine}" />
<!-- Start segment -->
<Grid Grid.Column="0" VerticalAlignment="Top" Background="{StaticResource MaterialDesignPaper}"
Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock TextAlignment="Center" Padding="0 3" FontSize="12" ToolTip="This segment is played when a layer starts displaying because it's conditions are met">
Start
</TextBlock>
<Button Grid.Column="1" Style="{StaticResource MaterialDesignIconButton}" ToolTip="Disable start segment" Width="20" Height="20" Margin="0 0 6 0"
Command="{s:Action DisableSegment}" CommandParameter="Start">
<materialDesign:PackIcon Kind="Close" Height="18" Width="18" />
</Button>
</Grid>
<!-- Main segment -->
<Grid Grid.Column="1" VerticalAlignment="Top" Background="{StaticResource MaterialDesignPaper}"
Visibility="{Binding MainSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock TextAlignment="Center" Padding="0 3" FontSize="12" ToolTip="This segment is played while a condition is met, either once or on a repeating loop">
Main
</TextBlock>
<ToggleButton Grid.Column="1" Style="{StaticResource MaterialDesignFlatToggleButton}" ToolTip="Toggle main segment repeat" Width="16" Height="16"
IsChecked="{Binding RepeatMainSegment}" VerticalAlignment="Center">
<materialDesign:PackIcon Kind="Repeat" Height="12" Width="12" />
</ToggleButton>
<Button Grid.Column="2" Style="{StaticResource MaterialDesignIconButton}" ToolTip="Remove" Width="20" Height="20" Margin="5 0 8 0"
Command="{s:Action DisableSegment}" CommandParameter="Main">
<materialDesign:PackIcon Kind="Close" Height="18" Width="18" />
</Button>
</Grid>
<!-- End segment -->
<Grid Grid.Column="2" VerticalAlignment="Top" Background="{StaticResource MaterialDesignPaper}"
Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock TextAlignment="Center" Padding="0 3" FontSize="12" ToolTip="This segment is played once a condition is no longer met">
End
</TextBlock>
<Button Grid.Column="1" Style="{StaticResource MaterialDesignIconButton}" ToolTip="Disable end segment" Width="20" Height="20" Margin="0 0 6 0"
Command="{s:Action DisableSegment}" CommandParameter="End">
<materialDesign:PackIcon Kind="Close" Height="18" Width="18" />
</Button>
</Grid>
<!-- Segment movement display -->
<Rectangle Grid.Column="0" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -2 -2 0" Width="5" Height="24" VerticalAlignment="Top"
HorizontalAlignment="Right" Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
<Rectangle Grid.Column="1" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -2 -2 0" Width="5" Height="24" VerticalAlignment="Top"
HorizontalAlignment="Right" Visibility="{Binding MainSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
<Rectangle Grid.Column="2" RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="0 -2 -2 0" Width="5" Height="24" VerticalAlignment="Top"
HorizontalAlignment="Right" Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}" />
<!-- Segment movement handles -->
<Rectangle Grid.Column="0" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="25" VerticalAlignment="Top"
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding StartSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
MouseDown="{s:Action StartSegmentMouseDown}" MouseUp="{s:Action StartSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}" />
<Rectangle Grid.Column="1" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="25" VerticalAlignment="Top"
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding MainSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
MouseDown="{s:Action MainSegmentMouseDown}" MouseUp="{s:Action MainSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}" />
<Rectangle Grid.Column="2" RadiusX="2" RadiusY="2" Fill="Transparent" Margin="0 -1 -6 0" Width="16" Height="25" VerticalAlignment="Top"
HorizontalAlignment="Right" Cursor="SizeWE" Visibility="{Binding EndSegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}"
MouseDown="{s:Action EndSegmentMouseDown}" MouseUp="{s:Action EndSegmentMouseUp}" MouseMove="{s:Action SegmentMouseMove}" />
</Grid>
</Canvas>
</ScrollViewer>
<!-- Timeline rails -->
<ScrollViewer x:Name="TimelineRailsScrollViewer"
Grid.Row="1"
Style="{StaticResource SvStyle}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
ScrollChanged="TimelineScrollChanged">
<ScrollViewer x:Name="TimelineRailsScrollViewer" Grid.Row="1" Style="{StaticResource SvStyle}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" ScrollChanged="TimelineScrollChanged">
<Grid Background="{DynamicResource MaterialDesignToolBarBackground}">
<Canvas Grid.Column="0"
Panel.ZIndex="1"
Margin="{Binding TimeCaretPosition}"
Cursor="SizeWE"
MouseDown="{s:Action TimelineMouseDown}"
MouseUp="{s:Action TimelineMouseUp}"
MouseMove="{s:Action TimelineMouseMove}">
<Line X1="0" X2="0" Y1="0" Y2="{Binding ActualHeight, ElementName=ContainerGrid}" StrokeThickness="2" Stroke="{StaticResource SecondaryAccentBrush}" />
<Canvas Grid.Column="0" Panel.ZIndex="1">
<Line Canvas.Left="{Binding TimeCaretPosition}"
Cursor="SizeWE"
MouseDown="{s:Action TimelineMouseDown}"
MouseUp="{s:Action TimelineMouseUp}"
MouseMove="{s:Action TimelineMouseMove}"
X1="0"
X2="0"
Y1="0"
Y2="{Binding ActualHeight, ElementName=ContainerGrid}"
StrokeThickness="2"
Stroke="{StaticResource SecondaryAccentBrush}" />
</Canvas>
<ContentControl Grid.Column="0" s:View.Model="{Binding TimelineViewModel}" />
<ContentControl Grid.Column="0" s:View.Model="{Binding TimelineViewModel}" x:Name="PropertyTimeLine" />
</Grid>
</ScrollViewer>
</Grid>
@ -303,8 +235,8 @@
<!-- Bottom row, a bit hacky but has a ZIndex of 2 to cut off the time caret that overlaps the entire timeline -->
<Grid Grid.Row="1"
Grid.Column="0"
HorizontalAlignment="Stretch"
Panel.ZIndex="2"
HorizontalAlignment="Stretch"
Background="{DynamicResource MaterialDesignCardBackground}">
<!-- Selected layer controls -->
<Grid.ColumnDefinitions>
@ -409,15 +341,15 @@
<MenuItem Header="Start"
Command="{s:Action EnableSegment}"
CommandParameter="Start"
IsEnabled="{Binding Data.StartSegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
IsEnabled="{Binding Data.StartTimelineSegmentViewModel.SegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
<MenuItem Header="Main"
Command="{s:Action EnableSegment}"
CommandParameter="Main"
IsEnabled="{Binding Data.MainSegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
IsEnabled="{Binding Data.MainTimelineSegmentViewModel.SegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
<MenuItem Header="End"
Command="{s:Action EnableSegment}"
CommandParameter="End"
IsEnabled="{Binding Data.EndSegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
IsEnabled="{Binding Data.EndTimelineSegmentViewModel.SegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
</ContextMenu>
</Button.ContextMenu>
<TextBlock FontSize="11">

View File

@ -35,6 +35,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
private RenderProfileElement _selectedProfileElement;
private TimelineViewModel _timelineViewModel;
private TreeViewModel _treeViewModel;
private TimelineSegmentViewModel _startTimelineSegmentViewModel;
private TimelineSegmentViewModel _mainTimelineSegmentViewModel;
private TimelineSegmentViewModel _endTimelineSegmentViewModel;
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService,
ILayerPropertyVmFactory layerPropertyVmFactory)
@ -68,10 +71,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
public string FormattedCurrentTime => $"{Math.Floor(ProfileEditorService.CurrentTime.TotalSeconds):00}.{ProfileEditorService.CurrentTime.Milliseconds:000}";
public Thickness TimeCaretPosition
public double TimeCaretPosition
{
get => new Thickness(ProfileEditorService.CurrentTime.TotalSeconds * ProfileEditorService.PixelsPerSecond, 0, 0, 0);
set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / ProfileEditorService.PixelsPerSecond);
get => ProfileEditorService.CurrentTime.TotalSeconds * ProfileEditorService.PixelsPerSecond;
set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value / ProfileEditorService.PixelsPerSecond);
}
public int PropertyTreeIndex
@ -94,8 +97,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
if (!SetAndNotify(ref _selectedProfileElement, value)) return;
NotifyOfPropertyChange(nameof(SelectedLayer));
NotifyOfPropertyChange(nameof(SelectedFolder));
NotifyOfPropertyChange(nameof(StartSegmentEnabled));
NotifyOfPropertyChange(nameof(EndSegmentEnabled));
}
}
@ -127,6 +128,24 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
set => SetAndNotify(ref _timelineViewModel, value);
}
public TimelineSegmentViewModel StartTimelineSegmentViewModel
{
get => _startTimelineSegmentViewModel;
set => SetAndNotify(ref _startTimelineSegmentViewModel, value);
}
public TimelineSegmentViewModel MainTimelineSegmentViewModel
{
get => _mainTimelineSegmentViewModel;
set => SetAndNotify(ref _mainTimelineSegmentViewModel, value);
}
public TimelineSegmentViewModel EndTimelineSegmentViewModel
{
get => _endTimelineSegmentViewModel;
set => SetAndNotify(ref _endTimelineSegmentViewModel, value);
}
protected override void OnInitialActivate()
{
PopulateProperties(ProfileEditorService.SelectedProfileElement);
@ -227,11 +246,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
TimelineViewModel?.Dispose();
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups);
StartTimelineSegmentViewModel?.Dispose();
StartTimelineSegmentViewModel = new TimelineSegmentViewModel(ProfileEditorService, SegmentViewModelType.Start);
MainTimelineSegmentViewModel?.Dispose();
MainTimelineSegmentViewModel = new TimelineSegmentViewModel(ProfileEditorService, SegmentViewModelType.Main);
EndTimelineSegmentViewModel?.Dispose();
EndTimelineSegmentViewModel = new TimelineSegmentViewModel(ProfileEditorService, SegmentViewModelType.End);
ApplyLayerBrush();
ApplyEffects();
}
private void SelectedLayerOnLayerBrushUpdated(object sender, EventArgs e)
{
ApplyLayerBrush();
@ -564,163 +591,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
#endregion
#region Segments
public bool StartSegmentEnabled
{
get => SelectedProfileElement?.StartSegmentLength != TimeSpan.Zero;
set
{
SelectedProfileElement.StartSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
ProfileEditorService.UpdateSelectedProfileElement();
NotifyOfPropertyChange(nameof(StartSegmentEnabled));
NotifyOfPropertyChange(nameof(CanAddSegment));
}
}
public bool MainSegmentEnabled
{
get => SelectedProfileElement?.MainSegmentLength != TimeSpan.Zero;
set
{
SelectedProfileElement.MainSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
ProfileEditorService.UpdateSelectedProfileElement();
NotifyOfPropertyChange(nameof(MainSegmentEnabled));
NotifyOfPropertyChange(nameof(CanAddSegment));
}
}
public bool EndSegmentEnabled
{
get => SelectedProfileElement?.EndSegmentLength != TimeSpan.Zero;
set
{
SelectedProfileElement.EndSegmentLength = value ? TimeSpan.FromSeconds(1) : TimeSpan.Zero;
ProfileEditorService.UpdateSelectedProfileElement();
NotifyOfPropertyChange(nameof(EndSegmentEnabled));
NotifyOfPropertyChange(nameof(CanAddSegment));
}
}
public bool CanAddSegment => !StartSegmentEnabled || !MainSegmentEnabled || !EndSegmentEnabled;
public bool RepeatMainSegment
{
get => SelectedProfileElement?.RepeatMainSegment ?? false;
set
{
SelectedProfileElement.RepeatMainSegment = value;
ProfileEditorService.UpdateSelectedProfileElement();
NotifyOfPropertyChange(nameof(RepeatMainSegment));
}
}
private bool _draggingStartSegment;
private bool _draggingMainSegment;
private bool _draggingEndSegment;
public void DisableSegment(string segment)
{
if (segment == "Start")
StartSegmentEnabled = false;
else if (segment == "Main")
MainSegmentEnabled = false;
else if (segment == "End")
EndSegmentEnabled = false;
}
public void EnableSegment(string segment)
{
if (segment == "Start")
StartSegmentEnabled = true;
StartTimelineSegmentViewModel.EnableSegment();
else if (segment == "Main")
MainSegmentEnabled = true;
MainTimelineSegmentViewModel.EnableSegment();
else if (segment == "End")
EndSegmentEnabled = true;
}
public void StartSegmentMouseDown(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).CaptureMouse();
_draggingStartSegment = true;
}
public void StartSegmentMouseUp(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).ReleaseMouseCapture();
_draggingStartSegment = false;
}
public void MainSegmentMouseDown(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).CaptureMouse();
_draggingMainSegment = true;
}
public void MainSegmentMouseUp(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).ReleaseMouseCapture();
_draggingMainSegment = false;
}
public void EndSegmentMouseDown(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).CaptureMouse();
_draggingEndSegment = true;
}
public void EndSegmentMouseUp(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).ReleaseMouseCapture();
_draggingEndSegment = false;
}
public void SegmentMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
// Get the parent grid, need that for our position
var parent = (IInputElement) VisualTreeHelper.GetParent((DependencyObject) sender);
var x = Math.Max(0, e.GetPosition(parent).X);
var newTime = TimeSpan.FromSeconds(x / ProfileEditorService.PixelsPerSecond);
// Round the time to something that fits the current zoom level
if (ProfileEditorService.PixelsPerSecond < 200)
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 5.0) * 5.0);
else if (ProfileEditorService.PixelsPerSecond < 500)
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 2.0) * 2.0);
else
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds));
// If holding down shift, snap to the closest element on the timeline
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
{
newTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), false, true, true);
}
// If holding down control, round to the closest 50ms
else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
{
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 50.0) * 50.0);
}
if (_draggingStartSegment)
{
if (newTime < TimeSpan.FromMilliseconds(100))
newTime = TimeSpan.FromMilliseconds(100);
SelectedProfileElement.StartSegmentLength = newTime;
}
else if (_draggingMainSegment)
{
if (newTime < SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100))
newTime = SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100);
SelectedProfileElement.MainSegmentLength = newTime - SelectedProfileElement.StartSegmentLength;
}
else if (_draggingEndSegment)
{
if (newTime < SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100))
newTime = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100);
SelectedProfileElement.EndSegmentLength = newTime - SelectedProfileElement.StartSegmentLength - SelectedProfileElement.MainSegmentLength;
}
}
EndTimelineSegmentViewModel.EnableSegment();
}
#endregion

View File

@ -0,0 +1,159 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline.TimelineSegmentView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:TimelineSegmentViewModel}}">
<UserControl.Resources>
<utilities:BindingProxy x:Key="DataContextProxy" Data="{Binding}" />
</UserControl.Resources>
<StackPanel Orientation="Horizontal" Visibility="{Binding SegmentEnabled, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<StackPanel.ContextMenu>
<ContextMenu>
<MenuItem Header="Repeat main segment"
IsCheckable="True"
IsChecked="{Binding Data.RepeatSegment, Source={StaticResource DataContextProxy}}"
Visibility="{Binding Data.IsMainSegment, Converter={x:Static s:BoolToVisibilityConverter.Instance}, Source={StaticResource DataContextProxy}}"/>
<MenuItem Header="Disable segment" Command="{s:Action DisableSegment}"/>
</ContextMenu>
</StackPanel.ContextMenu>
<!-- Segment content -->
<Grid VerticalAlignment="Top" Background="{StaticResource MaterialDesignPaper}" Width="{Binding SegmentWidth}">
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<TextBlock TextAlignment="Center"
Padding="0 3"
Margin="5 0 0 0"
FontSize="12"
ToolTip="{Binding ToolTip}"
Text="{Binding Segment}"
ClipToBounds="False">
<TextBlock.Style>
<Style TargetType="TextBlock">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowSegmentName}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1.0" To="0.0" Duration="0:0:0.25">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.25" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</TextBlock.Style>
</TextBlock>
<ToggleButton Grid.Column="1"
ToolTip="Toggle main segment repeat"
Width="16"
Height="16"
IsChecked="{Binding RepeatSegment}"
VerticalAlignment="Center"
Visibility="{Binding IsMainSegment, Converter={x:Static s:BoolToVisibilityConverter.Instance}}">
<ToggleButton.Style>
<Style TargetType="ToggleButton" BasedOn="{StaticResource MaterialDesignFlatToggleButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowRepeatButton}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1.0" To="0.0" Duration="0:0:0.25">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)" >
<DiscreteObjectKeyFrame KeyTime="00:00:0.25" Value="{x:Static Visibility.Collapsed}"/>
</ObjectAnimationUsingKeyFrames>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<ObjectAnimationUsingKeyFrames Storyboard.TargetProperty="(UIElement.Visibility)">
<DiscreteObjectKeyFrame KeyTime="00:00:00" Value="{x:Static Visibility.Visible}"/>
</ObjectAnimationUsingKeyFrames>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.25" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</ToggleButton.Style>
<materialDesign:PackIcon Kind="Repeat" Height="12" Width="12" />
</ToggleButton>
<Button Grid.Column="2" ToolTip="Disable segment" Width="20" Height="20" Margin="0 0 5 0" Command="{s:Action DisableSegment}">
<Button.Style>
<Style TargetType="Button" BasedOn="{StaticResource MaterialDesignIconButton}">
<Style.Triggers>
<DataTrigger Binding="{Binding ShowDisableButton}" Value="False">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="1.0" To="0.0" Duration="0:0:0.25">
<DoubleAnimation.EasingFunction>
<QuadraticEase EasingMode="EaseInOut" />
</DoubleAnimation.EasingFunction>
</DoubleAnimation>
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard>
<DoubleAnimation Storyboard.TargetProperty="Opacity" From="0.0" To="1.0" Duration="0:0:0.25" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</Button.Style>
<materialDesign:PackIcon Kind="Close" Height="18" Width="18" />
</Button>
</Grid>
<!-- Segment movement display -->
<Rectangle RadiusX="2" RadiusY="2" Fill="{DynamicResource PrimaryHueDarkBrush}" Margin="-2 -2 0 0" Width="5" Height="24" VerticalAlignment="Top" HorizontalAlignment="Right" />
<!-- Segment movement handles -->
<Rectangle RadiusX="2"
RadiusY="2"
Fill="Transparent"
Margin="-9 -2 0 0"
Width="12"
Height="25"
VerticalAlignment="Top"
HorizontalAlignment="Right"
Cursor="SizeWE"
MouseDown="{s:Action SegmentMouseDown}"
MouseUp="{s:Action SegmentMouseUp}"
MouseMove="{s:Action SegmentMouseMove}" />
</StackPanel>
</UserControl>

View File

@ -0,0 +1,275 @@
using System;
using System.ComponentModel;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media;
using Artemis.Core.Models.Profile;
using Artemis.UI.Shared.Services.Interfaces;
using Artemis.UI.Shared.Utilities;
using Stylet;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
{
public class TimelineSegmentViewModel : PropertyChangedBase, IDisposable
{
private bool _draggingSegment;
private bool _showSegmentName;
private bool _showRepeatButton;
private bool _showDisableButton;
public TimelineSegmentViewModel(IProfileEditorService profileEditorService, SegmentViewModelType segment)
{
ProfileEditorService = profileEditorService;
Segment = segment;
SelectedProfileElement = ProfileEditorService.SelectedProfileElement;
switch (Segment)
{
case SegmentViewModelType.Start:
ToolTip = "This segment is played when a layer starts displaying because it's conditions are met";
break;
case SegmentViewModelType.Main:
ToolTip = "This segment is played while a condition is met, either once or on a repeating loop";
break;
case SegmentViewModelType.End:
ToolTip = "This segment is played once a condition is no longer met";
break;
default:
throw new ArgumentOutOfRangeException(nameof(segment));
}
UpdateDisplay();
ProfileEditorService.PixelsPerSecondChanged += ProfileEditorServiceOnPixelsPerSecondChanged;
SelectedProfileElement.PropertyChanged += SelectedProfileElementOnPropertyChanged;
}
public RenderProfileElement SelectedProfileElement { get; }
public SegmentViewModelType Segment { get; }
public IProfileEditorService ProfileEditorService { get; }
public string ToolTip { get; }
public TimeSpan SegmentLength
{
get
{
return Segment switch
{
SegmentViewModelType.Start => SelectedProfileElement?.StartSegmentLength ?? TimeSpan.Zero,
SegmentViewModelType.Main => SelectedProfileElement?.MainSegmentLength ?? TimeSpan.Zero,
SegmentViewModelType.End => SelectedProfileElement?.EndSegmentLength ?? TimeSpan.Zero,
_ => throw new ArgumentOutOfRangeException()
};
}
}
public double SegmentWidth => ProfileEditorService.PixelsPerSecond * SegmentLength.TotalSeconds;
public bool SegmentEnabled => SegmentLength != TimeSpan.Zero;
public bool IsMainSegment => Segment == SegmentViewModelType.Main;
// Only the main segment supports this, for any other segment the getter always returns false and the setter does nothing
public bool RepeatSegment
{
get
{
if (Segment != SegmentViewModelType.Main)
return false;
return SelectedProfileElement?.RepeatMainSegment ?? false;
}
set
{
if (Segment != SegmentViewModelType.Main)
return;
SelectedProfileElement.RepeatMainSegment = value;
ProfileEditorService.UpdateSelectedProfileElement();
NotifyOfPropertyChange(nameof(RepeatSegment));
}
}
public double SegmentStartPosition
{
get
{
return Segment switch
{
SegmentViewModelType.Start => 0,
SegmentViewModelType.Main => ProfileEditorService.PixelsPerSecond * SelectedProfileElement.StartSegmentLength.TotalSeconds,
SegmentViewModelType.End => ProfileEditorService.PixelsPerSecond * (SelectedProfileElement.StartSegmentLength.TotalSeconds + SelectedProfileElement.MainSegmentLength.TotalSeconds),
_ => throw new ArgumentOutOfRangeException()
};
}
}
public bool ShowSegmentName
{
get => _showSegmentName;
set => SetAndNotify(ref _showSegmentName, value);
}
public bool ShowRepeatButton
{
get => _showRepeatButton;
set => SetAndNotify(ref _showRepeatButton, value);
}
public bool ShowDisableButton
{
get => _showDisableButton;
set => SetAndNotify(ref _showDisableButton, value);
}
public void Dispose()
{
ProfileEditorService.PixelsPerSecondChanged -= ProfileEditorServiceOnPixelsPerSecondChanged;
SelectedProfileElement.PropertyChanged -= SelectedProfileElementOnPropertyChanged;
}
public void DisableSegment()
{
switch (Segment)
{
case SegmentViewModelType.Start:
SelectedProfileElement.StartSegmentLength = TimeSpan.Zero;
break;
case SegmentViewModelType.Main:
SelectedProfileElement.MainSegmentLength = TimeSpan.Zero;
break;
case SegmentViewModelType.End:
SelectedProfileElement.EndSegmentLength = TimeSpan.Zero;
break;
default:
throw new ArgumentOutOfRangeException();
}
NotifyOfPropertyChange(nameof(SegmentEnabled));
ProfileEditorService.UpdateSelectedProfileElement();
}
public void EnableSegment()
{
switch (Segment)
{
case SegmentViewModelType.Start:
SelectedProfileElement.StartSegmentLength = TimeSpan.FromSeconds(1);
break;
case SegmentViewModelType.Main:
SelectedProfileElement.MainSegmentLength = TimeSpan.FromSeconds(1);
break;
case SegmentViewModelType.End:
SelectedProfileElement.EndSegmentLength = TimeSpan.FromSeconds(1);
break;
default:
throw new ArgumentOutOfRangeException();
}
NotifyOfPropertyChange(nameof(SegmentEnabled));
ProfileEditorService.UpdateSelectedProfileElement();
}
public void SegmentMouseDown(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).CaptureMouse();
_draggingSegment = true;
}
public void SegmentMouseUp(object sender, MouseButtonEventArgs e)
{
((IInputElement) sender).ReleaseMouseCapture();
_draggingSegment = false;
}
public void SegmentMouseMove(object sender, MouseEventArgs e)
{
if (e.LeftButton != MouseButtonState.Pressed || !_draggingSegment)
return;
// Get the parent scroll viewer, need that for our position
var parent = VisualTreeUtilities.FindParent<ScrollViewer>((DependencyObject) sender, "TimelineHeaderScrollViewer");
var x = Math.Max(0, e.GetPosition(parent).X);
var newTime = TimeSpan.FromSeconds(x / ProfileEditorService.PixelsPerSecond);
// Round the time to something that fits the current zoom level
if (ProfileEditorService.PixelsPerSecond < 200)
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 5.0) * 5.0);
else if (ProfileEditorService.PixelsPerSecond < 500)
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 2.0) * 2.0);
else
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds));
// If holding down shift, snap to the closest element on the timeline
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
newTime = ProfileEditorService.SnapToTimeline(newTime, TimeSpan.FromMilliseconds(1000f / ProfileEditorService.PixelsPerSecond * 5), false, true, true);
// If holding down control, round to the closest 50ms
else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds / 50.0) * 50.0);
if (Segment == SegmentViewModelType.Start)
{
if (newTime < TimeSpan.FromMilliseconds(100))
newTime = TimeSpan.FromMilliseconds(100);
SelectedProfileElement.StartSegmentLength = newTime;
}
else if (Segment == SegmentViewModelType.Main)
{
if (newTime < SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100))
newTime = SelectedProfileElement.StartSegmentLength + TimeSpan.FromMilliseconds(100);
SelectedProfileElement.MainSegmentLength = newTime - SelectedProfileElement.StartSegmentLength;
}
else if (Segment == SegmentViewModelType.End)
{
if (newTime < SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100))
newTime = SelectedProfileElement.StartSegmentLength + SelectedProfileElement.MainSegmentLength + TimeSpan.FromMilliseconds(100);
SelectedProfileElement.EndSegmentLength = newTime - SelectedProfileElement.StartSegmentLength - SelectedProfileElement.MainSegmentLength;
}
NotifyOfPropertyChange(nameof(SegmentLength));
NotifyOfPropertyChange(nameof(SegmentWidth));
UpdateDisplay();
}
private void SelectedProfileElementOnPropertyChanged(object sender, PropertyChangedEventArgs e)
{
if (e.PropertyName == nameof(RenderProfileElement.StartSegmentLength) ||
e.PropertyName == nameof(RenderProfileElement.MainSegmentLength) ||
e.PropertyName == nameof(RenderProfileElement.EndSegmentLength))
{
NotifyOfPropertyChange(nameof(SegmentStartPosition));
NotifyOfPropertyChange(nameof(SegmentWidth));
}
}
private void ProfileEditorServiceOnPixelsPerSecondChanged(object? sender, EventArgs e)
{
NotifyOfPropertyChange(nameof(SegmentWidth));
NotifyOfPropertyChange(nameof(SegmentStartPosition));
UpdateDisplay();
}
private void UpdateDisplay()
{
if (!IsMainSegment)
ShowSegmentName = SegmentWidth > 60;
else
ShowSegmentName = SegmentWidth > 80;
ShowRepeatButton = SegmentWidth > 45 && IsMainSegment;
ShowDisableButton = SegmentWidth > 25;
}
}
public enum SegmentViewModelType
{
Start,
Main,
End
}
}

View File

@ -73,6 +73,19 @@ namespace Artemis.Plugins.LayerBrushes.Noise
var height = (int) Math.Floor(path.Bounds.Height * _renderScale);
CreateBitmap(width, height);
var clipPath = new SKPath(Layer.Path);
Layer.ExcludePathFromTranslation(clipPath);
clipPath = new SKPath(clipPath);
clipPath.Transform(SKMatrix.MakeTranslation(Layer.Path.Bounds.Left * -1, Layer.Path.Bounds.Top * -1));
// Fill a canvas matching the final area that will be rendered
using var bitmapCanvas = new SKCanvas(_bitmap);
using var clipPaint = new SKPaint {Color = new SKColor(0, 0, 0, 255)};
bitmapCanvas.Clear();
bitmapCanvas.Scale(_renderScale);
bitmapCanvas.DrawPath(clipPath, clipPaint);
for (var y = 0; y < height; y++)
{
for (var x = 0; x < width; x++)
@ -84,6 +97,10 @@ namespace Artemis.Plugins.LayerBrushes.Noise
if (double.IsInfinity(evalX) || double.IsNaN(evalX) || double.IsNaN(evalY) || double.IsInfinity(evalY))
continue;
var pixel = _bitmap.GetPixel(x, y);
if (pixel.Alpha != 255)
continue;
var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
var amount = Math.Max(0f, Math.Min(1f, v));
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)

View File

@ -1,62 +1,9 @@
using System.Collections.Generic;
using System.Diagnostics;
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
using Artemis.Plugins.Modules.General.DataModel.Windows;
using SkiaSharp;
using Artemis.Plugins.Modules.General.DataModel.Windows;
namespace Artemis.Plugins.Modules.General.DataModel
{
public class GeneralDataModel : Core.Plugins.Abstract.DataModels.DataModel
{
public TestDataModel TestDataModel { get; set; }
public WindowsDataModel Windows { get; set; }
public GeneralDataModel()
{
TestDataModel = new TestDataModel();
Windows = new WindowsDataModel();
}
}
public class TestDataModel
{
public TestDataModel()
{
PlayerInfo = new PlayerInfo();
IntsList = new List<int>();
PlayerInfosList = new List<PlayerInfo>();
}
[DataModelProperty(Name = "A test string", Description = "This is a test string that's not of any use outside testing!")]
public string TestString { get; set; }
[DataModelProperty(Name = "A test boolean", Description = "This is a test boolean that's not of any use outside testing!")]
public bool TestBoolean { get; set; }
public SKColor TestColor { get; set; } = new SKColor(221, 21, 152);
[DataModelProperty(Name = "Player info", Description = "[TEST] Contains information about the player")]
public PlayerInfo PlayerInfo { get; set; }
public double UpdatesDividedByFour { get; set; }
public int Updates { get; set; }
public List<int> IntsList { get; set; }
public List<PlayerInfo> PlayerInfosList { get; set; }
}
public class PlayerInfo
{
[DataModelProperty(Name = "A test string", Description = "This is a test string that's not of any use outside testing!")]
public string TestString { get; set; }
[DataModelProperty(Name = "A test boolean", Description = "This is a test boolean that's not of any use outside testing!")]
public bool TestBoolean { get; set; }
[DataModelProperty(Affix = "%", MinValue = 0, MaxValue = 100)]
public int Health { get; set; }
public SKPoint Position { get; set; }
public WindowDataModel ActiveWindow { get; set; }
}
}

View File

@ -16,7 +16,7 @@ namespace Artemis.Plugins.Modules.General.DataModel.Windows
ProcessName = process.ProcessName;
// Accessing MainModule requires admin privileges, this way does not
ProgramLocation = WindowMonitor.GetProcessFilename(process);
ProgramLocation = WindowUtilities.GetProcessFilename(process);
}
public string WindowTitle { get; set; }

View File

@ -6,7 +6,6 @@ namespace Artemis.Plugins.Modules.General.DataModel.Windows
{
public class WindowsDataModel
{
public WindowDataModel ActiveWindow { get; set; }
public List<WindowDataModel> OpenWindows { get; set; }
}
}

View File

@ -1,33 +1,16 @@
using System;
using System.Collections.Generic;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq;
using System.Threading.Tasks;
using System.Windows.Interop;
using Artemis.Core;
using Artemis.Core.Plugins.Abstract;
using Artemis.Core.Plugins.Abstract.ViewModels;
using Artemis.Core.Plugins.Models;
using Artemis.Plugins.Modules.General.DataModel;
using Artemis.Plugins.Modules.General.DataModel.Windows;
using Artemis.Plugins.Modules.General.Utilities;
using Artemis.Plugins.Modules.General.ViewModels;
using SkiaSharp;
namespace Artemis.Plugins.Modules.General
{
public class GeneralModule : ProfileModule<GeneralDataModel>
{
private readonly PluginSettings _settings;
private readonly Random _rand;
public GeneralModule(PluginSettings settings)
{
_settings = settings;
_rand = new Random();
}
public override IEnumerable<ModuleViewModel> GetViewModels()
{
return new List<ModuleViewModel> {new GeneralViewModel(this)};
@ -35,19 +18,7 @@ namespace Artemis.Plugins.Modules.General
public override void Update(double deltaTime)
{
DataModel.TestDataModel.UpdatesDividedByFour += 0.25;
DataModel.TestDataModel.Updates += 1;
DataModel.TestDataModel.PlayerInfo.Position = new SKPoint(_rand.Next(100), _rand.Next(100));
DataModel.TestDataModel.PlayerInfo.Health++;
if (DataModel.TestDataModel.PlayerInfo.Health > 200)
DataModel.TestDataModel.PlayerInfo.Health = 0;
DataModel.TestDataModel.IntsList[0] = _rand.Next();
DataModel.TestDataModel.IntsList[2] = _rand.Next();
UpdateCurrentWindow();
UpdateBackgroundWindows();
base.Update(deltaTime);
}
@ -56,11 +27,6 @@ namespace Artemis.Plugins.Modules.General
DisplayName = "General";
DisplayIcon = "AllInclusive";
ExpandsDataModel = true;
DataModel.TestDataModel.IntsList = new List<int> {_rand.Next(), _rand.Next(), _rand.Next()};
DataModel.TestDataModel.PlayerInfosList = new List<PlayerInfo> {new PlayerInfo()};
var testSetting = _settings.GetSetting("TestSetting", DateTime.Now);
}
public override void DisablePlugin()
@ -69,31 +35,11 @@ namespace Artemis.Plugins.Modules.General
#region Open windows
private DateTime _lastBackgroundWindowsUpdate;
public void UpdateCurrentWindow()
{
var processId = WindowMonitor.GetActiveProcessId();
if (DataModel.Windows.ActiveWindow == null || DataModel.Windows.ActiveWindow.Process.Id != processId)
DataModel.Windows.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId));
}
public void UpdateBackgroundWindows()
{
// This is kinda slow so lets not do it very often and lets do it in a task
if (DateTime.Now - _lastBackgroundWindowsUpdate < TimeSpan.FromSeconds(5))
return;
_lastBackgroundWindowsUpdate = DateTime.Now;
Task.Run(() =>
{
// All processes with a main window handle are considered open windows
DataModel.Windows.OpenWindows = Process.GetProcesses()
.Where(p => p.MainWindowHandle != IntPtr.Zero)
.Select(p => new WindowDataModel(p))
.Where(w => !string.IsNullOrEmpty(w.WindowTitle))
.ToList();
});
var processId = WindowUtilities.GetActiveProcessId();
if (DataModel.ActiveWindow == null || DataModel.ActiveWindow.Process.Id != processId)
DataModel.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId));
}
#endregion

View File

@ -5,7 +5,7 @@ using System.Text;
namespace Artemis.Plugins.Modules.General.Utilities
{
public static class WindowMonitor
public static class WindowUtilities
{
public static int GetActiveProcessId()
{