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:
parent
72d606f40d
commit
2045b230c2
@ -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
|
// 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
|
// to it's start
|
||||||
var timelineDeltaTime = UpdateTimeline(deltaTime);
|
UpdateTimeline(deltaTime);
|
||||||
|
|
||||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
{
|
{
|
||||||
baseLayerEffect.BaseProperties?.Update();
|
baseLayerEffect.BaseProperties?.Update();
|
||||||
baseLayerEffect.Update(timelineDeltaTime);
|
baseLayerEffect.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate the children in reverse because that's how they must be rendered too
|
// Iterate the children in reverse because that's how they must be rendered too
|
||||||
|
|||||||
@ -70,7 +70,6 @@ namespace Artemis.Core.Models.Profile
|
|||||||
|
|
||||||
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
|
General.PropertyGroupInitialized += GeneralOnPropertyGroupInitialized;
|
||||||
ApplyRenderElementEntity();
|
ApplyRenderElementEntity();
|
||||||
ApplyRenderElementDefaults();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LayerEntity LayerEntity { get; set; }
|
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
|
// 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
|
// to it's start
|
||||||
var timelineDeltaTime = UpdateTimeline(deltaTime);
|
UpdateTimeline(deltaTime);
|
||||||
|
|
||||||
General.Update();
|
General.Update();
|
||||||
Transform.Update();
|
Transform.Update();
|
||||||
LayerBrush.BaseProperties?.Update();
|
LayerBrush.BaseProperties?.Update();
|
||||||
LayerBrush.Update(timelineDeltaTime);
|
LayerBrush.Update(deltaTime);
|
||||||
|
|
||||||
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
foreach (var baseLayerEffect in LayerEffects.Where(e => e.Enabled))
|
||||||
{
|
{
|
||||||
baseLayerEffect.BaseProperties?.Update();
|
baseLayerEffect.BaseProperties?.Update();
|
||||||
baseLayerEffect.Update(timelineDeltaTime);
|
baseLayerEffect.Update(deltaTime);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -256,7 +255,10 @@ namespace Artemis.Core.Models.Profile
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
var progress = timeOverride.TotalMilliseconds % MainSegmentLength.TotalMilliseconds;
|
var progress = timeOverride.TotalMilliseconds % MainSegmentLength.TotalMilliseconds;
|
||||||
TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
|
if (progress > 0)
|
||||||
|
TimelinePosition = TimeSpan.FromMilliseconds(progress) + StartSegmentLength;
|
||||||
|
else
|
||||||
|
TimelinePosition = StartSegmentLength;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -437,6 +439,39 @@ namespace Artemis.Core.Models.Profile
|
|||||||
return position;
|
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
|
#endregion
|
||||||
|
|
||||||
#region LED management
|
#region LED management
|
||||||
|
|||||||
@ -17,8 +17,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
{
|
{
|
||||||
protected void ApplyRenderElementDefaults()
|
protected void ApplyRenderElementDefaults()
|
||||||
{
|
{
|
||||||
if (MainSegmentLength <= TimeSpan.Zero)
|
MainSegmentLength = TimeSpan.FromSeconds(5);
|
||||||
MainSegmentLength = TimeSpan.FromSeconds(5);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
protected void ApplyRenderElementEntity()
|
protected void ApplyRenderElementEntity()
|
||||||
|
|||||||
@ -172,130 +172,62 @@
|
|||||||
|
|
||||||
<!-- Timeline headers -->
|
<!-- Timeline headers -->
|
||||||
<ScrollViewer Grid.Row="0" x:Name="TimelineHeaderScrollViewer" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" ScrollChanged="TimelineScrollChanged">
|
<ScrollViewer Grid.Row="0" x:Name="TimelineHeaderScrollViewer" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden" ScrollChanged="TimelineScrollChanged">
|
||||||
<Grid Background="{DynamicResource MaterialDesignCardBackground}">
|
<Canvas Background="{DynamicResource MaterialDesignCardBackground}" Width="{Binding ActualWidth, ElementName=PropertyTimeLine}">
|
||||||
<!-- Caret -->
|
<!-- Timeline segments -->
|
||||||
<Grid.ColumnDefinitions>
|
<ContentControl Canvas.Left="{Binding EndTimelineSegmentViewModel.SegmentStartPosition}" s:View.Model="{Binding EndTimelineSegmentViewModel}" />
|
||||||
<ColumnDefinition Width="{Binding TimelineViewModel.StartSegmentWidth}" />
|
<ContentControl Canvas.Left="{Binding MainTimelineSegmentViewModel.SegmentStartPosition}" s:View.Model="{Binding MainTimelineSegmentViewModel}" />
|
||||||
<ColumnDefinition Width="{Binding TimelineViewModel.MainSegmentWidth}" />
|
<ContentControl Canvas.Left="{Binding StartTimelineSegmentViewModel.SegmentStartPosition}" s:View.Model="{Binding StartTimelineSegmentViewModel}" />
|
||||||
<ColumnDefinition Width="{Binding TimelineViewModel.EndSegmentWidth}" />
|
|
||||||
</Grid.ColumnDefinitions>
|
|
||||||
|
|
||||||
<Canvas Grid.ColumnSpan="3"
|
<!-- Timeline caret -->
|
||||||
Panel.ZIndex="2"
|
<Polygon Canvas.Left="{Binding TimeCaretPosition}"
|
||||||
Margin="{Binding TimeCaretPosition}"
|
Cursor="SizeWE"
|
||||||
Cursor="SizeWE"
|
MouseDown="{s:Action TimelineMouseDown}"
|
||||||
MouseDown="{s:Action TimelineMouseDown}"
|
MouseUp="{s:Action TimelineMouseUp}"
|
||||||
MouseUp="{s:Action TimelineMouseUp}"
|
MouseMove="{s:Action TimelineMouseMove}"
|
||||||
MouseMove="{s:Action TimelineMouseMove}">
|
Points="-8,0 -8,8 0,20, 8,8 8,0"
|
||||||
<Polygon Points="-8,0 -8,8 0,20, 8,8 8,0" Fill="{StaticResource SecondaryAccentBrush}" />
|
Fill="{StaticResource SecondaryAccentBrush}" />
|
||||||
<Line X1="0" X2="0" Y1="0" Y2="{Binding ActualHeight, ElementName=ContainerGrid}" StrokeThickness="2" Stroke="{StaticResource SecondaryAccentBrush}" />
|
<Line Canvas.Left="{Binding TimeCaretPosition}"
|
||||||
</Canvas>
|
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"
|
<!-- Timeline header body -->
|
||||||
Margin="0 25 0 0"
|
<timeline:PropertyTimelineHeader Margin="0 25 0 0"
|
||||||
Fill="{DynamicResource MaterialDesignBody}"
|
Fill="{DynamicResource MaterialDesignBody}"
|
||||||
PixelsPerSecond="{Binding ProfileEditorService.PixelsPerSecond}"
|
PixelsPerSecond="{Binding ProfileEditorService.PixelsPerSecond}"
|
||||||
HorizontalOffset="{Binding ContentHorizontalOffset, ElementName=TimelineHeaderScrollViewer}"
|
HorizontalOffset="{Binding ContentHorizontalOffset, ElementName=TimelineHeaderScrollViewer}"
|
||||||
VisibleWidth="{Binding ActualWidth, ElementName=TimelineHeaderScrollViewer}"
|
VisibleWidth="{Binding ActualWidth, ElementName=TimelineHeaderScrollViewer}"
|
||||||
OffsetFirstValue="True"
|
OffsetFirstValue="True"
|
||||||
Width="{Binding ActualWidth, ElementName=PropertyTimeLine}" />
|
Width="{Binding ActualWidth, ElementName=PropertyTimeLine}" />
|
||||||
|
</Canvas>
|
||||||
<!-- 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>
|
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
|
|
||||||
<!-- Timeline rails -->
|
<!-- Timeline rails -->
|
||||||
<ScrollViewer x:Name="TimelineRailsScrollViewer"
|
<ScrollViewer x:Name="TimelineRailsScrollViewer" Grid.Row="1" Style="{StaticResource SvStyle}" HorizontalScrollBarVisibility="Auto" VerticalScrollBarVisibility="Auto" ScrollChanged="TimelineScrollChanged">
|
||||||
Grid.Row="1"
|
|
||||||
Style="{StaticResource SvStyle}"
|
|
||||||
HorizontalScrollBarVisibility="Auto"
|
|
||||||
VerticalScrollBarVisibility="Auto"
|
|
||||||
ScrollChanged="TimelineScrollChanged">
|
|
||||||
<Grid Background="{DynamicResource MaterialDesignToolBarBackground}">
|
<Grid Background="{DynamicResource MaterialDesignToolBarBackground}">
|
||||||
<Canvas Grid.Column="0"
|
<Canvas Grid.Column="0" Panel.ZIndex="1">
|
||||||
Panel.ZIndex="1"
|
<Line Canvas.Left="{Binding TimeCaretPosition}"
|
||||||
Margin="{Binding TimeCaretPosition}"
|
Cursor="SizeWE"
|
||||||
Cursor="SizeWE"
|
MouseDown="{s:Action TimelineMouseDown}"
|
||||||
MouseDown="{s:Action TimelineMouseDown}"
|
MouseUp="{s:Action TimelineMouseUp}"
|
||||||
MouseUp="{s:Action TimelineMouseUp}"
|
MouseMove="{s:Action TimelineMouseMove}"
|
||||||
MouseMove="{s:Action TimelineMouseMove}">
|
X1="0"
|
||||||
<Line X1="0" X2="0" Y1="0" Y2="{Binding ActualHeight, ElementName=ContainerGrid}" StrokeThickness="2" Stroke="{StaticResource SecondaryAccentBrush}" />
|
X2="0"
|
||||||
|
Y1="0"
|
||||||
|
Y2="{Binding ActualHeight, ElementName=ContainerGrid}"
|
||||||
|
StrokeThickness="2"
|
||||||
|
Stroke="{StaticResource SecondaryAccentBrush}" />
|
||||||
</Canvas>
|
</Canvas>
|
||||||
|
|
||||||
<ContentControl Grid.Column="0" s:View.Model="{Binding TimelineViewModel}" />
|
<ContentControl Grid.Column="0" s:View.Model="{Binding TimelineViewModel}" x:Name="PropertyTimeLine" />
|
||||||
</Grid>
|
</Grid>
|
||||||
</ScrollViewer>
|
</ScrollViewer>
|
||||||
</Grid>
|
</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 -->
|
<!-- 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 Grid.Row="1"
|
||||||
Grid.Column="0"
|
Grid.Column="0"
|
||||||
HorizontalAlignment="Stretch"
|
|
||||||
Panel.ZIndex="2"
|
Panel.ZIndex="2"
|
||||||
|
HorizontalAlignment="Stretch"
|
||||||
Background="{DynamicResource MaterialDesignCardBackground}">
|
Background="{DynamicResource MaterialDesignCardBackground}">
|
||||||
<!-- Selected layer controls -->
|
<!-- Selected layer controls -->
|
||||||
<Grid.ColumnDefinitions>
|
<Grid.ColumnDefinitions>
|
||||||
@ -409,15 +341,15 @@
|
|||||||
<MenuItem Header="Start"
|
<MenuItem Header="Start"
|
||||||
Command="{s:Action EnableSegment}"
|
Command="{s:Action EnableSegment}"
|
||||||
CommandParameter="Start"
|
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"
|
<MenuItem Header="Main"
|
||||||
Command="{s:Action EnableSegment}"
|
Command="{s:Action EnableSegment}"
|
||||||
CommandParameter="Main"
|
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"
|
<MenuItem Header="End"
|
||||||
Command="{s:Action EnableSegment}"
|
Command="{s:Action EnableSegment}"
|
||||||
CommandParameter="End"
|
CommandParameter="End"
|
||||||
IsEnabled="{Binding Data.EndSegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
|
IsEnabled="{Binding Data.EndTimelineSegmentViewModel.SegmentEnabled, Converter={StaticResource InverseBooleanConverter}, Source={StaticResource DataContextProxy}}" />
|
||||||
</ContextMenu>
|
</ContextMenu>
|
||||||
</Button.ContextMenu>
|
</Button.ContextMenu>
|
||||||
<TextBlock FontSize="11">
|
<TextBlock FontSize="11">
|
||||||
|
|||||||
@ -35,6 +35,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
private RenderProfileElement _selectedProfileElement;
|
private RenderProfileElement _selectedProfileElement;
|
||||||
private TimelineViewModel _timelineViewModel;
|
private TimelineViewModel _timelineViewModel;
|
||||||
private TreeViewModel _treeViewModel;
|
private TreeViewModel _treeViewModel;
|
||||||
|
private TimelineSegmentViewModel _startTimelineSegmentViewModel;
|
||||||
|
private TimelineSegmentViewModel _mainTimelineSegmentViewModel;
|
||||||
|
private TimelineSegmentViewModel _endTimelineSegmentViewModel;
|
||||||
|
|
||||||
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService,
|
public LayerPropertiesViewModel(IProfileEditorService profileEditorService, ICoreService coreService, ISettingsService settingsService,
|
||||||
ILayerPropertyVmFactory layerPropertyVmFactory)
|
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 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);
|
get => ProfileEditorService.CurrentTime.TotalSeconds * ProfileEditorService.PixelsPerSecond;
|
||||||
set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value.Left / ProfileEditorService.PixelsPerSecond);
|
set => ProfileEditorService.CurrentTime = TimeSpan.FromSeconds(value / ProfileEditorService.PixelsPerSecond);
|
||||||
}
|
}
|
||||||
|
|
||||||
public int PropertyTreeIndex
|
public int PropertyTreeIndex
|
||||||
@ -94,8 +97,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
if (!SetAndNotify(ref _selectedProfileElement, value)) return;
|
if (!SetAndNotify(ref _selectedProfileElement, value)) return;
|
||||||
NotifyOfPropertyChange(nameof(SelectedLayer));
|
NotifyOfPropertyChange(nameof(SelectedLayer));
|
||||||
NotifyOfPropertyChange(nameof(SelectedFolder));
|
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);
|
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()
|
protected override void OnInitialActivate()
|
||||||
{
|
{
|
||||||
PopulateProperties(ProfileEditorService.SelectedProfileElement);
|
PopulateProperties(ProfileEditorService.SelectedProfileElement);
|
||||||
@ -227,11 +246,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
|
|
||||||
TimelineViewModel?.Dispose();
|
TimelineViewModel?.Dispose();
|
||||||
TimelineViewModel = _layerPropertyVmFactory.TimelineViewModel(this, LayerPropertyGroups);
|
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();
|
ApplyLayerBrush();
|
||||||
ApplyEffects();
|
ApplyEffects();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
private void SelectedLayerOnLayerBrushUpdated(object sender, EventArgs e)
|
private void SelectedLayerOnLayerBrushUpdated(object sender, EventArgs e)
|
||||||
{
|
{
|
||||||
ApplyLayerBrush();
|
ApplyLayerBrush();
|
||||||
@ -564,163 +591,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
|||||||
#endregion
|
#endregion
|
||||||
|
|
||||||
#region Segments
|
#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)
|
public void EnableSegment(string segment)
|
||||||
{
|
{
|
||||||
if (segment == "Start")
|
if (segment == "Start")
|
||||||
StartSegmentEnabled = true;
|
StartTimelineSegmentViewModel.EnableSegment();
|
||||||
else if (segment == "Main")
|
else if (segment == "Main")
|
||||||
MainSegmentEnabled = true;
|
MainTimelineSegmentViewModel.EnableSegment();
|
||||||
else if (segment == "End")
|
else if (segment == "End")
|
||||||
EndSegmentEnabled = true;
|
EndTimelineSegmentViewModel.EnableSegment();
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -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>
|
||||||
@ -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
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -73,6 +73,19 @@ namespace Artemis.Plugins.LayerBrushes.Noise
|
|||||||
var height = (int) Math.Floor(path.Bounds.Height * _renderScale);
|
var height = (int) Math.Floor(path.Bounds.Height * _renderScale);
|
||||||
|
|
||||||
CreateBitmap(width, height);
|
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 y = 0; y < height; y++)
|
||||||
{
|
{
|
||||||
for (var x = 0; x < width; x++)
|
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))
|
if (double.IsInfinity(evalX) || double.IsNaN(evalX) || double.IsNaN(evalY) || double.IsInfinity(evalY))
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
|
var pixel = _bitmap.GetPixel(x, y);
|
||||||
|
if (pixel.Alpha != 255)
|
||||||
|
continue;
|
||||||
|
|
||||||
var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
|
var v = (float) _noise.Evaluate(evalX, evalY, _z) * hardness;
|
||||||
var amount = Math.Max(0f, Math.Min(1f, v));
|
var amount = Math.Max(0f, Math.Min(1f, v));
|
||||||
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
if (Properties.ColorType.BaseValue == ColorMappingType.Simple)
|
||||||
|
|||||||
@ -1,62 +1,9 @@
|
|||||||
using System.Collections.Generic;
|
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
||||||
using System.Diagnostics;
|
|
||||||
using Artemis.Core.Plugins.Abstract.DataModels.Attributes;
|
|
||||||
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Artemis.Plugins.Modules.General.DataModel
|
namespace Artemis.Plugins.Modules.General.DataModel
|
||||||
{
|
{
|
||||||
public class GeneralDataModel : Core.Plugins.Abstract.DataModels.DataModel
|
public class GeneralDataModel : Core.Plugins.Abstract.DataModels.DataModel
|
||||||
{
|
{
|
||||||
public TestDataModel TestDataModel { get; set; }
|
public WindowDataModel ActiveWindow { 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; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -16,7 +16,7 @@ namespace Artemis.Plugins.Modules.General.DataModel.Windows
|
|||||||
ProcessName = process.ProcessName;
|
ProcessName = process.ProcessName;
|
||||||
|
|
||||||
// Accessing MainModule requires admin privileges, this way does not
|
// Accessing MainModule requires admin privileges, this way does not
|
||||||
ProgramLocation = WindowMonitor.GetProcessFilename(process);
|
ProgramLocation = WindowUtilities.GetProcessFilename(process);
|
||||||
}
|
}
|
||||||
|
|
||||||
public string WindowTitle { get; set; }
|
public string WindowTitle { get; set; }
|
||||||
|
|||||||
@ -6,7 +6,6 @@ namespace Artemis.Plugins.Modules.General.DataModel.Windows
|
|||||||
{
|
{
|
||||||
public class WindowsDataModel
|
public class WindowsDataModel
|
||||||
{
|
{
|
||||||
public WindowDataModel ActiveWindow { get; set; }
|
|
||||||
public List<WindowDataModel> OpenWindows { get; set; }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,33 +1,16 @@
|
|||||||
using System;
|
using System.Collections.Generic;
|
||||||
using System.Collections.Generic;
|
|
||||||
using System.Diagnostics;
|
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;
|
||||||
using Artemis.Core.Plugins.Abstract.ViewModels;
|
using Artemis.Core.Plugins.Abstract.ViewModels;
|
||||||
using Artemis.Core.Plugins.Models;
|
|
||||||
using Artemis.Plugins.Modules.General.DataModel;
|
using Artemis.Plugins.Modules.General.DataModel;
|
||||||
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
using Artemis.Plugins.Modules.General.DataModel.Windows;
|
||||||
using Artemis.Plugins.Modules.General.Utilities;
|
using Artemis.Plugins.Modules.General.Utilities;
|
||||||
using Artemis.Plugins.Modules.General.ViewModels;
|
using Artemis.Plugins.Modules.General.ViewModels;
|
||||||
using SkiaSharp;
|
|
||||||
|
|
||||||
namespace Artemis.Plugins.Modules.General
|
namespace Artemis.Plugins.Modules.General
|
||||||
{
|
{
|
||||||
public class GeneralModule : ProfileModule<GeneralDataModel>
|
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()
|
public override IEnumerable<ModuleViewModel> GetViewModels()
|
||||||
{
|
{
|
||||||
return new List<ModuleViewModel> {new GeneralViewModel(this)};
|
return new List<ModuleViewModel> {new GeneralViewModel(this)};
|
||||||
@ -35,19 +18,7 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
|
|
||||||
public override void Update(double deltaTime)
|
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();
|
UpdateCurrentWindow();
|
||||||
UpdateBackgroundWindows();
|
|
||||||
|
|
||||||
base.Update(deltaTime);
|
base.Update(deltaTime);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -56,11 +27,6 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
DisplayName = "General";
|
DisplayName = "General";
|
||||||
DisplayIcon = "AllInclusive";
|
DisplayIcon = "AllInclusive";
|
||||||
ExpandsDataModel = true;
|
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()
|
public override void DisablePlugin()
|
||||||
@ -69,31 +35,11 @@ namespace Artemis.Plugins.Modules.General
|
|||||||
|
|
||||||
#region Open windows
|
#region Open windows
|
||||||
|
|
||||||
private DateTime _lastBackgroundWindowsUpdate;
|
|
||||||
|
|
||||||
public void UpdateCurrentWindow()
|
public void UpdateCurrentWindow()
|
||||||
{
|
{
|
||||||
var processId = WindowMonitor.GetActiveProcessId();
|
var processId = WindowUtilities.GetActiveProcessId();
|
||||||
if (DataModel.Windows.ActiveWindow == null || DataModel.Windows.ActiveWindow.Process.Id != processId)
|
if (DataModel.ActiveWindow == null || DataModel.ActiveWindow.Process.Id != processId)
|
||||||
DataModel.Windows.ActiveWindow = new WindowDataModel(Process.GetProcessById(processId));
|
DataModel.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();
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endregion
|
#endregion
|
||||||
|
|||||||
@ -5,7 +5,7 @@ using System.Text;
|
|||||||
|
|
||||||
namespace Artemis.Plugins.Modules.General.Utilities
|
namespace Artemis.Plugins.Modules.General.Utilities
|
||||||
{
|
{
|
||||||
public static class WindowMonitor
|
public static class WindowUtilities
|
||||||
{
|
{
|
||||||
public static int GetActiveProcessId()
|
public static int GetActiveProcessId()
|
||||||
{
|
{
|
||||||
Loading…
x
Reference in New Issue
Block a user