mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
33756a228d
@ -99,7 +99,7 @@ namespace Artemis.Core.Services
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!ModuleUpdatingDisabled)
|
||||
if (!ModuleUpdatingDisabled && _modules != null)
|
||||
{
|
||||
lock (_modules)
|
||||
{
|
||||
|
||||
@ -97,7 +97,7 @@ namespace Artemis.UI.Behaviors
|
||||
// Update state of all items starting with given, with optional recursion
|
||||
private void UpdateTreeViewItem(TreeViewItem item, bool recurse)
|
||||
{
|
||||
if (SelectedItem == null) return;
|
||||
// if (SelectedItem == null) return;
|
||||
var model = item.DataContext;
|
||||
|
||||
// If the selected item is this model and is not yet selected - select and return
|
||||
|
||||
@ -44,7 +44,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
|
||||
PopulateProperties(_profileEditorService.SelectedProfileElement, null);
|
||||
_profileEditorService.SelectedProfileElementChanged += (sender, args) => PopulateProperties(args.ProfileElement, args.PreviousProfileElement);
|
||||
_profileEditorService.SelectedProfileChanged += (sender, args) => PopulateProperties(_profileEditorService.SelectedProfileElement, null);
|
||||
_profileEditorService.CurrentTimeChanged += ProfileEditorServiceOnCurrentTimeChanged;
|
||||
}
|
||||
|
||||
@ -112,6 +111,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
|
||||
layer.LayerPropertyRegistered += LayerOnPropertyRegistered;
|
||||
layer.LayerPropertyRemoved += LayerOnPropertyRemoved;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var layerPropertyViewModel in _layerPropertyViewModels.ToList())
|
||||
RemovePropertyViewModel(layerPropertyViewModel);
|
||||
}
|
||||
}
|
||||
|
||||
private void LayerOnPropertyRegistered(object sender, LayerPropertyEventArgs e)
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450" d:DesignWidth="800">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0 0 5 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<ComboBox Width="132"
|
||||
Margin="0 2"
|
||||
Padding="0 -1"
|
||||
@ -20,8 +20,7 @@
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description"
|
||||
SelectedValue="{Binding Path=BrushInputValue}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}"
|
||||
materialDesign:ComboBoxAssist.ClassicMode="True" />
|
||||
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
<TextBlock Margin="5 0 0 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -59,6 +59,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
NotifyOfPropertyChange(() => BrushInputValue);
|
||||
}
|
||||
|
||||
public override void ApplyInputDrag(object startValue, double dragDistance)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
UpdateEnumValues();
|
||||
|
||||
@ -10,7 +10,7 @@
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:EnumPropertyInputViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0 0 5 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<ComboBox Width="132"
|
||||
Margin="0 2"
|
||||
Padding="0 -1"
|
||||
@ -21,8 +21,7 @@
|
||||
SelectedValuePath="Value"
|
||||
DisplayMemberPath="Description"
|
||||
SelectedValue="{Binding Path=EnumInputValue}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}"
|
||||
materialDesign:ComboBoxAssist.ClassicMode="True" />
|
||||
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
<TextBlock Margin="5 0 0 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -27,6 +27,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
NotifyOfPropertyChange(() => EnumInputValue);
|
||||
}
|
||||
|
||||
public override void ApplyInputDrag(object startValue, double dragDistance)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
|
||||
protected override void OnInitialized()
|
||||
{
|
||||
EnumValues = EnumUtilities.GetAllValuesAndDescriptions(LayerPropertyViewModel.LayerProperty.Type);
|
||||
|
||||
@ -10,14 +10,41 @@
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:FloatPropertyInputViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0 0 5 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<!-- Drag handle -->
|
||||
<Border BorderThickness="0,0,0,1" Margin="0 2">
|
||||
<Border.BorderBrush>
|
||||
<VisualBrush>
|
||||
<VisualBrush.Visual>
|
||||
<Rectangle StrokeDashArray="2 2" Stroke="{DynamicResource SecondaryAccentBrush}" StrokeThickness="1"
|
||||
Width="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualWidth}"
|
||||
Height="{Binding RelativeSource={RelativeSource AncestorType={x:Type Border}}, Path=ActualHeight}"/>
|
||||
</VisualBrush.Visual>
|
||||
</VisualBrush>
|
||||
</Border.BorderBrush>
|
||||
<TextBlock Width="60"
|
||||
Padding="2 0"
|
||||
Margin="0 2 0 0"
|
||||
Text="{Binding FloatInputValue}"
|
||||
Cursor="/Resources/aero_drag_ew.cur"
|
||||
Foreground="{DynamicResource SecondaryAccentBrush}"
|
||||
Visibility="{Binding InputFieldEnabled, Converter={x:Static s:BoolToVisibilityConverter.InverseInstance}, Mode=OneWay}"
|
||||
MouseDown="{s:Action InputMouseDown}"
|
||||
MouseUp="{s:Action InputMouseUp}"
|
||||
MouseMove="{s:Action InputMouseMove}" />
|
||||
</Border>
|
||||
|
||||
<!-- Input -->
|
||||
<TextBox Width="60"
|
||||
Margin="0 2"
|
||||
Padding="0 -1"
|
||||
materialDesign:ValidationAssist.UsePopup="True"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding FloatInputValue}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}" />
|
||||
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
Visibility="{Binding InputFieldEnabled, Converter={StaticResource BoolToVisibilityConverter}, Mode=OneWay}"
|
||||
LostFocus="{s:Action InputLostFocus}"
|
||||
KeyDown="{s:Action InputKeyDown}"
|
||||
IsVisibleChanged="{s:Action InputIsVisibleChanged}" />
|
||||
<TextBlock Margin="5 0 0 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -12,6 +12,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
|
||||
public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(float)};
|
||||
|
||||
|
||||
public float FloatInputValue
|
||||
{
|
||||
get => (float?) InputValue ?? 0f;
|
||||
@ -22,5 +23,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
{
|
||||
NotifyOfPropertyChange(() => FloatInputValue);
|
||||
}
|
||||
|
||||
public override void ApplyInputDrag(object startValue, double dragDistance)
|
||||
{
|
||||
var floatStartValue = (float) startValue;
|
||||
FloatInputValue = (float) (floatStartValue + dragDistance);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,14 +10,13 @@
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:IntPropertyInputViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0 0 5 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBox Width="60"
|
||||
Margin="0 2"
|
||||
Padding="0 -1"
|
||||
materialDesign:ValidationAssist.UsePopup="True"
|
||||
HorizontalAlignment="Left"
|
||||
Text="{Binding IntInputValue}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}" />
|
||||
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
Text="{Binding IntInputValue}" />
|
||||
<TextBlock Margin="5 0 0 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -22,5 +22,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
{
|
||||
NotifyOfPropertyChange(() => IntInputValue);
|
||||
}
|
||||
|
||||
public override void ApplyInputDrag(object startValue, double dragDistance)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1,6 +1,8 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using Artemis.UI.Exceptions;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Stylet;
|
||||
@ -15,11 +17,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
}
|
||||
|
||||
protected IProfileEditorService ProfileEditorService { get; set; }
|
||||
public abstract List<Type> CompatibleTypes { get; }
|
||||
|
||||
public bool Initialized { get; private set; }
|
||||
|
||||
public abstract List<Type> CompatibleTypes { get; }
|
||||
public LayerPropertyViewModel LayerPropertyViewModel { get; private set; }
|
||||
public bool InputFieldEnabled { get; set; }
|
||||
|
||||
protected object InputValue
|
||||
{
|
||||
@ -46,18 +48,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
OnInitialized();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Called by the view, prevents scrolling into view when scrubbing through the timeline
|
||||
/// </summary>
|
||||
/// <param name="sender"></param>
|
||||
/// <param name="e"></param>
|
||||
public void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
public abstract void Update();
|
||||
|
||||
public abstract void ApplyInputDrag(object startValue, double dragDistance);
|
||||
|
||||
protected virtual void OnInitialized()
|
||||
{
|
||||
}
|
||||
@ -70,5 +64,70 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
|
||||
ProfileEditorService.UpdateSelectedProfileElement();
|
||||
}
|
||||
|
||||
#region Mouse-based mutations
|
||||
|
||||
private Point _mouseDragStartPoint;
|
||||
private object _startValue;
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void InputMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
_startValue = InputValue;
|
||||
((IInputElement) sender).CaptureMouse();
|
||||
_mouseDragStartPoint = e.GetPosition((IInputElement) sender);
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void InputMouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
var position = e.GetPosition((IInputElement) sender);
|
||||
if (position == _mouseDragStartPoint)
|
||||
InputFieldEnabled = true;
|
||||
|
||||
((IInputElement) sender).ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void InputMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
var position = e.GetPosition((IInputElement) sender);
|
||||
ApplyInputDrag(_startValue, position.X - _mouseDragStartPoint.X);
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void InputIsVisibleChanged(object sender, DependencyPropertyChangedEventArgs e)
|
||||
{
|
||||
if (InputFieldEnabled)
|
||||
{
|
||||
((UIElement) sender).Focus();
|
||||
if (sender is TextBox textBox)
|
||||
textBox.SelectAll();
|
||||
}
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void InputLostFocus(object sender, RoutedEventArgs e)
|
||||
{
|
||||
InputFieldEnabled = false;
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void InputKeyDown(object sender, KeyEventArgs e)
|
||||
{
|
||||
if (e.Key == Key.Enter)
|
||||
InputFieldEnabled = false;
|
||||
else if (e.Key == Key.Escape)
|
||||
{
|
||||
if (sender is TextBox textBox)
|
||||
textBox.Text = _startValue.ToString();
|
||||
InputFieldEnabled = false;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
@ -15,11 +15,11 @@
|
||||
<converters:SKColorToColorConverter x:Key="SKColorToColorConverter" />
|
||||
</UserControl.Resources>
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0 0 5 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<artemis:ColorPicker Width="132"
|
||||
Margin="0 2"
|
||||
Padding="0 -1"
|
||||
Color="{Binding SKColorInputValue, Converter={StaticResource SKColorToColorConverter}}" />
|
||||
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
<TextBlock Margin="5 0 0 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -23,5 +23,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
{
|
||||
NotifyOfPropertyChange(() => SKColorInputValue);
|
||||
}
|
||||
|
||||
public override void ApplyInputDrag(object startValue, double dragDistance)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,15 +10,14 @@
|
||||
d:DesignHeight="25" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:SKPointPropertyInputViewModel}">
|
||||
<StackPanel Orientation="Horizontal" KeyboardNavigation.IsTabStop="True">
|
||||
<TextBlock Margin="0 0 5 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBox Width="60"
|
||||
Margin="0 2"
|
||||
Padding="0 -1"
|
||||
materialDesign:ValidationAssist.UsePopup="True"
|
||||
HorizontalAlignment="Left"
|
||||
ToolTip="X-coordinate (horizontal)"
|
||||
Text="{Binding X}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}" />
|
||||
Text="{Binding X}" />
|
||||
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
|
||||
<TextBox Width="60"
|
||||
Margin="0 2"
|
||||
@ -26,8 +25,7 @@
|
||||
materialDesign:ValidationAssist.UsePopup="True"
|
||||
HorizontalAlignment="Left"
|
||||
ToolTip="Y-coordinate (vertical)"
|
||||
Text="{Binding Y}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}" />
|
||||
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
Text="{Binding Y}" />
|
||||
<TextBlock Margin="5 0 0 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -34,5 +34,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
NotifyOfPropertyChange(() => X);
|
||||
NotifyOfPropertyChange(() => Y);
|
||||
}
|
||||
|
||||
public override void ApplyInputDrag(object startValue, double dragDistance)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -10,15 +10,14 @@
|
||||
d:DesignHeight="450" d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:SKSizePropertyInputViewModel}">
|
||||
<StackPanel Orientation="Horizontal">
|
||||
<TextBlock Margin="0 0 5 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBlock Margin="0 0 5 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputPrefix}" />
|
||||
<TextBox Width="60"
|
||||
Margin="0 2"
|
||||
Padding="0 -1"
|
||||
materialDesign:ValidationAssist.UsePopup="True"
|
||||
HorizontalAlignment="Left"
|
||||
ToolTip="Height"
|
||||
Text="{Binding Height}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}" />
|
||||
Text="{Binding Height}" />
|
||||
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
|
||||
<TextBox Width="60"
|
||||
Margin="0 2"
|
||||
@ -26,8 +25,7 @@
|
||||
materialDesign:ValidationAssist.UsePopup="True"
|
||||
HorizontalAlignment="Left"
|
||||
ToolTip="Width"
|
||||
Text="{Binding Width}"
|
||||
RequestBringIntoView="{s:Action OnRequestBringIntoView}" />
|
||||
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
Text="{Binding Width}" />
|
||||
<TextBlock Margin="5 0 0 4" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
|
||||
</StackPanel>
|
||||
</UserControl>
|
||||
@ -34,5 +34,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
|
||||
NotifyOfPropertyChange(() => Width);
|
||||
NotifyOfPropertyChange(() => Height);
|
||||
}
|
||||
|
||||
public override void ApplyInputDrag(object startValue, double dragDistance)
|
||||
{
|
||||
throw new NotImplementedException();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -9,15 +9,47 @@
|
||||
d:DesignHeight="25"
|
||||
d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance local:PropertyTimelineViewModel}">
|
||||
<ItemsControl ItemsSource="{Binding PropertyTrackViewModels}"
|
||||
Width="{Binding Width}"
|
||||
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}"
|
||||
Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||
HorizontalAlignment="Left">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
<Canvas Background="{DynamicResource MaterialDesignToolBarBackground}"
|
||||
MouseDown="{s:Action TimelineCanvasMouseDown}"
|
||||
MouseUp="{s:Action TimelineCanvasMouseUp}"
|
||||
MouseMove="{s:Action TimelineCanvasMouseMove}">
|
||||
<Canvas.Triggers>
|
||||
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonDown">
|
||||
<BeginStoryboard>
|
||||
<Storyboard Storyboard.TargetName="MultiSelectionPath" Storyboard.TargetProperty="Opacity">
|
||||
<DoubleAnimation From="0" To="1" Duration="0:0:0.1" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
<EventTrigger RoutedEvent="UIElement.MouseLeftButtonUp">
|
||||
<BeginStoryboard>
|
||||
<Storyboard Storyboard.TargetName="MultiSelectionPath" Storyboard.TargetProperty="Opacity">
|
||||
<DoubleAnimation From="1" To="0" Duration="0:0:0.2" />
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</EventTrigger>
|
||||
</Canvas.Triggers>
|
||||
|
||||
<ItemsControl ItemsSource="{Binding PropertyTrackViewModels}"
|
||||
Width="{Binding Width}"
|
||||
MinWidth="{Binding ActualWidth, RelativeSource={RelativeSource Mode=FindAncestor, AncestorType=ScrollViewer}}"
|
||||
HorizontalAlignment="Left">
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<ContentControl s:View.Model="{Binding}" VerticalContentAlignment="Stretch" HorizontalContentAlignment="Stretch" />
|
||||
</DataTemplate>
|
||||
</ItemsControl.ItemTemplate>
|
||||
</ItemsControl>
|
||||
|
||||
<!-- Multi-selection rectangle -->
|
||||
<Path Data="{Binding SelectionRectangle}" Opacity="0"
|
||||
Stroke="{DynamicResource PrimaryHueLightBrush}"
|
||||
StrokeThickness="1"
|
||||
x:Name="MultiSelectionPath"
|
||||
IsHitTestVisible="False">
|
||||
<Path.Fill>
|
||||
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
|
||||
</Path.Fill>
|
||||
</Path>
|
||||
</Canvas>
|
||||
</UserControl>
|
||||
@ -1,7 +1,15 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Shapes;
|
||||
using Artemis.Core.Models.Surface;
|
||||
using Artemis.UI.Ninject.Factories;
|
||||
using Artemis.UI.Screens.SurfaceEditor;
|
||||
using Artemis.UI.Screens.SurfaceEditor.Visualization;
|
||||
using Artemis.UI.Services.Interfaces;
|
||||
using Stylet;
|
||||
|
||||
@ -24,12 +32,15 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
_profileEditorService.SelectedProfileElementUpdated += (sender, args) => Update();
|
||||
LayerPropertiesViewModel.PixelsPerSecondChanged += (sender, args) => UpdateKeyframePositions();
|
||||
|
||||
Execute.PostToUIThread(() => SelectionRectangle = new RectangleGeometry());
|
||||
}
|
||||
|
||||
public LayerPropertiesViewModel LayerPropertiesViewModel { get; }
|
||||
|
||||
public double Width { get; set; }
|
||||
public BindableCollection<PropertyTrackViewModel> PropertyTrackViewModels { get; set; }
|
||||
public RectangleGeometry SelectionRectangle { get; set; }
|
||||
|
||||
public void UpdateEndTime()
|
||||
{
|
||||
@ -88,6 +99,119 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
||||
UpdateEndTime();
|
||||
}
|
||||
|
||||
#region Keyframe selection
|
||||
|
||||
private Point _mouseDragStartPoint;
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void TimelineCanvasMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
((IInputElement) sender).CaptureMouse();
|
||||
|
||||
SelectionRectangle.Rect = new Rect();
|
||||
_mouseDragStartPoint = e.GetPosition((IInputElement) sender);
|
||||
}
|
||||
|
||||
// ReSharper disable once UnusedMember.Global - Called from view
|
||||
public void TimelineCanvasMouseUp(object sender, MouseEventArgs e)
|
||||
{
|
||||
var position = e.GetPosition((IInputElement)sender);
|
||||
var selectedRect = new Rect(_mouseDragStartPoint, position);
|
||||
SelectionRectangle.Rect = selectedRect;
|
||||
|
||||
// Find all keyframes in the rectangle
|
||||
var selectedKeyframes = new List<PropertyTrackKeyframeViewModel>();
|
||||
var hitTestParams = new GeometryHitTestParameters(SelectionRectangle);
|
||||
var resultCallback = new HitTestResultCallback(result => HitTestResultBehavior.Continue);
|
||||
var filterCallback = new HitTestFilterCallback(element =>
|
||||
{
|
||||
if (element is Ellipse ellipse)
|
||||
selectedKeyframes.Add((PropertyTrackKeyframeViewModel) ellipse.DataContext);
|
||||
return HitTestFilterBehavior.Continue;
|
||||
});
|
||||
VisualTreeHelper.HitTest((Visual) sender, filterCallback, resultCallback, hitTestParams);
|
||||
|
||||
var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList();
|
||||
foreach (var keyframeViewModel in keyframeViewModels)
|
||||
keyframeViewModel.IsSelected = selectedKeyframes.Contains(keyframeViewModel);
|
||||
|
||||
((IInputElement) sender).ReleaseMouseCapture();
|
||||
}
|
||||
|
||||
public void TimelineCanvasMouseMove(object sender, MouseEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Pressed)
|
||||
{
|
||||
var position = e.GetPosition((IInputElement) sender);
|
||||
var selectedRect = new Rect(_mouseDragStartPoint, position);
|
||||
SelectionRectangle.Rect = selectedRect;
|
||||
}
|
||||
}
|
||||
|
||||
public void SelectKeyframe(PropertyTrackKeyframeViewModel clicked, bool selectBetween, bool toggle)
|
||||
{
|
||||
var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList();
|
||||
if (selectBetween)
|
||||
{
|
||||
var selectedIndex = keyframeViewModels.FindIndex(k => k.IsSelected);
|
||||
// If nothing is selected, select only the clicked
|
||||
if (selectedIndex == -1)
|
||||
{
|
||||
clicked.IsSelected = true;
|
||||
return;
|
||||
}
|
||||
|
||||
foreach (var keyframeViewModel in keyframeViewModels)
|
||||
keyframeViewModel.IsSelected = false;
|
||||
|
||||
var clickedIndex = keyframeViewModels.IndexOf(clicked);
|
||||
if (clickedIndex < selectedIndex)
|
||||
{
|
||||
foreach (var keyframeViewModel in keyframeViewModels.Skip(clickedIndex).Take(selectedIndex - clickedIndex + 1))
|
||||
keyframeViewModel.IsSelected = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach (var keyframeViewModel in keyframeViewModels.Skip(selectedIndex).Take(clickedIndex - selectedIndex + 1))
|
||||
keyframeViewModel.IsSelected = true;
|
||||
}
|
||||
}
|
||||
else if (toggle)
|
||||
{
|
||||
// Toggle only the clicked keyframe, leave others alone
|
||||
clicked.IsSelected = !clicked.IsSelected;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Only select the clicked keyframe
|
||||
foreach (var keyframeViewModel in keyframeViewModels)
|
||||
keyframeViewModel.IsSelected = false;
|
||||
clicked.IsSelected = true;
|
||||
}
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Keyframe movement
|
||||
|
||||
public void MoveSelectedKeyframes(TimeSpan offset)
|
||||
{
|
||||
var keyframeViewModels = PropertyTrackViewModels.SelectMany(t => t.KeyframeViewModels.OrderBy(k => k.Keyframe.Position)).ToList();
|
||||
foreach (var keyframeViewModel in keyframeViewModels.Where(k => k.IsSelected))
|
||||
{
|
||||
// TODO: Not ideal as this stacks them all if they get to 0, oh well
|
||||
if (keyframeViewModel.Keyframe.Position + offset > TimeSpan.Zero)
|
||||
{
|
||||
keyframeViewModel.Keyframe.Position += offset;
|
||||
keyframeViewModel.Update(LayerPropertiesViewModel.PixelsPerSecond);
|
||||
}
|
||||
}
|
||||
|
||||
_profileEditorService.UpdateProfilePreview();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private void CreateViewModels(LayerPropertyViewModel property)
|
||||
{
|
||||
PropertyTrackViewModels.Add(_propertyTrackVmFactory.Create(this, property));
|
||||
|
||||
@ -46,13 +46,26 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
||||
|
||||
public void KeyframeMouseDown(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Released)
|
||||
return;
|
||||
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift) && !IsSelected)
|
||||
PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, true, false);
|
||||
else if (Keyboard.IsKeyDown(Key.LeftCtrl) || Keyboard.IsKeyDown(Key.RightCtrl))
|
||||
PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, false, true);
|
||||
else if (!IsSelected)
|
||||
PropertyTrackViewModel.PropertyTimelineViewModel.SelectKeyframe(this, false, false);
|
||||
|
||||
((IInputElement) sender).CaptureMouse();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
public void KeyframeMouseUp(object sender, MouseButtonEventArgs e)
|
||||
{
|
||||
if (e.LeftButton == MouseButtonState.Released)
|
||||
return;
|
||||
((IInputElement) sender).ReleaseMouseCapture();
|
||||
_profileEditorService.UpdateSelectedProfileElement();
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
public void KeyframeMouseMove(object sender, MouseEventArgs e)
|
||||
@ -71,26 +84,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.Timeline
|
||||
else
|
||||
newTime = TimeSpan.FromMilliseconds(Math.Round(newTime.TotalMilliseconds));
|
||||
|
||||
if (!Keyboard.IsKeyDown(Key.LeftShift) && !Keyboard.IsKeyDown(Key.RightShift))
|
||||
{
|
||||
Keyframe.Position = newTime;
|
||||
|
||||
Update(_pixelsPerSecond);
|
||||
_profileEditorService.UpdateProfilePreview();
|
||||
return;
|
||||
}
|
||||
|
||||
// If shift is held, snap to the current time
|
||||
// Take a tolerance of 5 pixels (half a keyframe width)
|
||||
var tolerance = 1000f / _pixelsPerSecond * 5;
|
||||
if (Math.Abs(_profileEditorService.CurrentTime.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance)
|
||||
Keyframe.Position = _profileEditorService.CurrentTime;
|
||||
else
|
||||
Keyframe.Position = newTime;
|
||||
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
|
||||
{
|
||||
var tolerance = 1000f / _pixelsPerSecond * 5;
|
||||
if (Math.Abs(_profileEditorService.CurrentTime.TotalMilliseconds - newTime.TotalMilliseconds) < tolerance)
|
||||
newTime = _profileEditorService.CurrentTime;
|
||||
}
|
||||
|
||||
Update(_pixelsPerSecond);
|
||||
_profileEditorService.UpdateProfilePreview();
|
||||
PropertyTrackViewModel.PropertyTimelineViewModel.MoveSelectedKeyframes(newTime - Keyframe.Position);
|
||||
}
|
||||
e.Handled = true;
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@ -29,6 +29,8 @@
|
||||
<ItemsControl.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<Ellipse Fill="{StaticResource PrimaryHueMidBrush}"
|
||||
Stroke="White"
|
||||
StrokeThickness="0"
|
||||
Width="10"
|
||||
Height="10"
|
||||
Margin="-5,6,0,0"
|
||||
@ -37,6 +39,28 @@
|
||||
MouseDown="{s:Action KeyframeMouseDown}"
|
||||
MouseUp="{s:Action KeyframeMouseUp}"
|
||||
MouseMove="{s:Action KeyframeMouseMove}">
|
||||
<Ellipse.Style>
|
||||
<Style TargetType="{x:Type Ellipse}">
|
||||
<Style.Triggers>
|
||||
<DataTrigger Binding="{Binding IsSelected}" Value="True">
|
||||
<DataTrigger.EnterActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="StrokeThickness" To="1" Duration="0:0:0.25"></DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.EnterActions>
|
||||
<DataTrigger.ExitActions>
|
||||
<BeginStoryboard>
|
||||
<Storyboard>
|
||||
<DoubleAnimation Storyboard.TargetProperty="StrokeThickness" To="0" Duration="0:0:0.25"></DoubleAnimation>
|
||||
</Storyboard>
|
||||
</BeginStoryboard>
|
||||
</DataTrigger.ExitActions>
|
||||
</DataTrigger>
|
||||
</Style.Triggers>
|
||||
</Style>
|
||||
</Ellipse.Style>
|
||||
<Ellipse.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Copy" Command="{s:Action Copy}">
|
||||
|
||||
@ -136,9 +136,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
|
||||
private void ChangeSelectedProfile(Profile profile)
|
||||
{
|
||||
if (profile == Module.ActiveProfile)
|
||||
return;
|
||||
|
||||
var oldProfile = Module.ActiveProfile;
|
||||
_profileService.ActivateProfile(Module, profile);
|
||||
|
||||
@ -147,7 +144,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
if (profile != null)
|
||||
_profileService.UpdateProfile(profile, false);
|
||||
|
||||
_profileEditorService.ChangeSelectedProfile(profile);
|
||||
if (_profileEditorService.SelectedProfile != profile)
|
||||
_profileEditorService.ChangeSelectedProfile(profile);
|
||||
}
|
||||
|
||||
private void ModuleOnActiveProfileChanged(object sender, EventArgs e)
|
||||
@ -188,11 +186,18 @@ namespace Artemis.UI.Screens.Module.ProfileEditor
|
||||
// Populate the UI collection
|
||||
Execute.PostToUIThread(() =>
|
||||
{
|
||||
Profiles.Clear();
|
||||
Profiles.AddRange(profiles.OrderBy(p => p.Name));
|
||||
SelectedProfile = activeProfile;
|
||||
Profiles.AddRange(profiles.Except(Profiles).ToList());
|
||||
Profiles.RemoveRange(Profiles.Except(profiles).ToList());
|
||||
var index = 0;
|
||||
foreach (var profile in Profiles.OrderBy(p => p.Name).ToList())
|
||||
{
|
||||
Profiles.Move(Profiles.IndexOf(profile), index);
|
||||
index++;
|
||||
}
|
||||
|
||||
_profileEditorService.ChangeSelectedProfile(SelectedProfile);
|
||||
SelectedProfile = activeProfile;
|
||||
if (_profileEditorService.SelectedProfile != activeProfile)
|
||||
_profileEditorService.ChangeSelectedProfile(activeProfile);
|
||||
if (!activeProfile.IsActivated)
|
||||
_profileService.ActivateProfile(Module, activeProfile);
|
||||
});
|
||||
|
||||
@ -16,10 +16,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.ProfileTree
|
||||
private TreeItemViewModel _selectedTreeItem;
|
||||
private bool _updatingTree;
|
||||
|
||||
|
||||
public ProfileTreeViewModel(IProfileEditorService profileEditorService,
|
||||
IFolderVmFactory folderVmFactory,
|
||||
ILayerVmFactory layerVmFactory)
|
||||
public ProfileTreeViewModel(IProfileEditorService profileEditorService, IFolderVmFactory folderVmFactory)
|
||||
{
|
||||
_profileEditorService = profileEditorService;
|
||||
_folderVmFactory = folderVmFactory;
|
||||
|
||||
@ -40,6 +40,8 @@ namespace Artemis.UI.Services
|
||||
|
||||
public void ChangeSelectedProfile(Profile profile)
|
||||
{
|
||||
ChangeSelectedProfileElement(null);
|
||||
|
||||
var profileElementEvent = new ProfileElementEventArgs(profile, SelectedProfile);
|
||||
SelectedProfile = profile;
|
||||
UpdateProfilePreview();
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user