Added shape properties

This commit is contained in:
Robert committed 2020-02-05 23:48:36 +01:00
1 parent 2c60a42315
commit 12d5fd39a0
31 files changed
+373 -114

No files matched your search

@@ -19,6 +19,43 @@
</UserControl.InputBindings>
<UserControl.Resources>
<s:BoolToVisibilityConverter x:Key="BoolToVisibilityConverter" />
<Style x:Key="SVStyle" TargetType="{x:Type ScrollViewer}">
<Setter Property="OverridesDefaultStyle" Value="True" />
<Setter Property="Template">
<Setter.Value>
<ControlTemplate TargetType="{x:Type ScrollViewer}">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="*" />
<ColumnDefinition Width="Auto" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<ScrollContentPresenter Grid.ColumnSpan="2" Grid.RowSpan="2" />
<ScrollBar Name="PART_VerticalScrollBar"
HorizontalAlignment="Right"
Opacity="0.5"
Grid.Column="1"
Value="{TemplateBinding VerticalOffset}"
Maximum="{TemplateBinding ScrollableHeight}"
ViewportSize="{TemplateBinding ViewportHeight}"
Visibility="{TemplateBinding ComputedVerticalScrollBarVisibility}" />
<ScrollBar Name="PART_HorizontalScrollBar"
VerticalAlignment="Bottom"
Orientation="Horizontal"
Opacity="0.5"
Grid.Row="1"
Value="{TemplateBinding HorizontalOffset}"
Maximum="{TemplateBinding ScrollableWidth}"
ViewportSize="{TemplateBinding ViewportWidth}"
Visibility="{TemplateBinding ComputedHorizontalScrollBarVisibility}" />
</Grid>
</ControlTemplate>
</Setter.Value>
</Setter>
</Style>
</UserControl.Resources>
<Grid x:Name="ContainerGrid">
<Grid.RowDefinitions>
@@ -74,7 +111,11 @@
</DockPanel>
<!-- Properties tree -->
<ScrollViewer Grid.Row="1" x:Name="PropertyTreeScrollViewer" HorizontalScrollBarVisibility="Hidden" VerticalScrollBarVisibility="Hidden">
<ScrollViewer x:Name="PropertyTreeScrollViewer"
Grid.Row="1"
HorizontalScrollBarVisibility="Hidden"
VerticalScrollBarVisibility="Hidden"
ScrollChanged="TimelineScrollChanged">
<Border BorderThickness="0,0,1,0" BorderBrush="{DynamicResource MaterialDesignDivider}">
<ContentControl s:View.Model="{Binding PropertyTree}" />
</Border>
@@ -113,7 +154,12 @@
</ScrollViewer>
<!-- Timeline rails -->
<ScrollViewer Grid.Row="1" x:Name="TimelineRailsScrollViewer" HorizontalScrollBarVisibility="Visible" VerticalScrollBarVisibility="Hidden" ScrollChanged="TimelineScrollChanged">
<ScrollViewer x:Name="TimelineRailsScrollViewer"
Grid.Row="1"
Style="{StaticResource SVStyle}"
HorizontalScrollBarVisibility="Auto"
VerticalScrollBarVisibility="Auto"
ScrollChanged="TimelineScrollChanged">
<Grid>
<Canvas ZIndex="1"
Margin="{Binding TimeCaretPosition}"
@@ -125,7 +171,6 @@
</Canvas>
<ContentControl x:Name="PropertyTimeLine" s:View.Model="{Binding PropertyTimeline}" />
</Grid>
</ScrollViewer>
</Grid>
@@ -17,8 +17,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
{
if (sender == TimelineHeaderScrollViewer)
TimelineRailsScrollViewer.ScrollToHorizontalOffset(e.HorizontalOffset);
else if (sender == PropertyTreeScrollViewer)
TimelineRailsScrollViewer.ScrollToVerticalOffset(e.VerticalOffset);
else if (sender == TimelineRailsScrollViewer)
{
TimelineHeaderScrollViewer.ScrollToHorizontalOffset(e.HorizontalOffset);
PropertyTreeScrollViewer.ScrollToVerticalOffset(e.VerticalOffset);
}
}
}
}
@@ -1,4 +1,5 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.Core.Models.Profile.LayerProperties;
using Artemis.UI.Ninject.Factories;
@@ -58,14 +59,19 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties
// Force the keyframe engine to update, the new keyframe is the current keyframe
LayerProperty.IsUsingKeyframes = _keyframesEnabled;
LayerProperty.KeyframeEngine.Update(0);
LayerProperty.KeyframeEngine?.Update(0);
_profileEditorService.UpdateSelectedProfileElement();
}
public PropertyInputViewModel GetPropertyInputViewModel()
{
var match = _kernel.Get<List<PropertyInputViewModel>>().FirstOrDefault(p => p.CompatibleTypes.Contains(LayerProperty.Type));
// If the type is an enum type, search for Enum instead.
var type = LayerProperty.Type;
if (type.IsEnum)
type = typeof(Enum);
var match = _kernel.Get<List<PropertyInputViewModel>>().FirstOrDefault(p => p.CompatibleTypes.Contains(type));
if (match == null)
return null;
@@ -0,0 +1,34 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput.EnumPropertyInputView"
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.PropertyTree.PropertyInput"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
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}" />
<ComboBox Width="132"
Margin="0 2"
Padding="0 -1"
Height="15"
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
ItemsSource="{Binding Path=EnumValues}"
SelectedValuePath="Value"
DisplayMemberPath="Description"
SelectedValue="{Binding Path=EnumInputValue}"
RequestBringIntoView="{s:Action OnRequestBringIntoView}"
materialDesign:ComboBoxAssist.ClassicMode="True">
<ComboBox.ItemContainerStyle>
<Style TargetType="ComboBoxItem" BasedOn="{StaticResource MaterialDesignComboBoxItemStyle}">
<EventSetter Event="RequestBringIntoView" Handler="OnRequestBringIntoView"/>
</Style>
</ComboBox.ItemContainerStyle>
</ComboBox>
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
</StackPanel>
</UserControl>
@@ -0,0 +1,33 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput
{
/// <summary>
/// Interaction logic for EnumPropertyInputView.xaml
/// </summary>
public partial class EnumPropertyInputView : UserControl
{
public EnumPropertyInputView()
{
InitializeComponent();
}
private void OnRequestBringIntoView(object sender, RequestBringIntoViewEventArgs e)
{
e.Handled = true;
}
}
}
@@ -0,0 +1,35 @@
using System;
using System.Collections.Generic;
using System.Linq;
using Artemis.UI.Services.Interfaces;
using Artemis.UI.Shared.Utilities;
namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput
{
public class EnumPropertyInputViewModel : PropertyInputViewModel
{
public EnumPropertyInputViewModel(IProfileEditorService profileEditorService) : base(profileEditorService)
{
}
public IEnumerable<ValueDescription> EnumValues { get; private set; }
public sealed override List<Type> CompatibleTypes { get; } = new List<Type> {typeof(Enum)};
public object EnumInputValue
{
get => InputValue ?? Enum.GetValues(LayerPropertyViewModel.LayerProperty.Type).Cast<object>().First();
set => InputValue = value;
}
protected override void OnInitialized()
{
EnumValues = EnumUtilities.GetAllValuesAndDescriptions(LayerPropertyViewModel.LayerProperty.Type);
}
public override void Update()
{
NotifyOfPropertyChange(() => EnumInputValue);
}
}
}
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:FloatPropertyInputViewModel}">
@@ -15,7 +16,8 @@
Padding="0 -1"
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
Text="{Binding FloatInputValue}" />
Text="{Binding FloatInputValue}"
RequestBringIntoView="{s:Action OnRequestBringIntoView}"/>
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
</StackPanel>
</UserControl>
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:IntPropertyInputViewModel}">
@@ -15,7 +16,8 @@
Padding="0 -1"
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
Text="{Binding IntInputValue}" />
Text="{Binding IntInputValue}"
RequestBringIntoView="{s:Action OnRequestBringIntoView}"/>
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
</StackPanel>
</UserControl>
@@ -1,5 +1,6 @@
using System;
using System.Collections.Generic;
using System.Windows;
using Artemis.UI.Exceptions;
using Artemis.UI.Services.Interfaces;
using Stylet;
@@ -28,16 +29,31 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
public void Initialize(LayerPropertyViewModel layerPropertyViewModel)
{
var type = layerPropertyViewModel.LayerProperty.Type;
if (type.IsEnum)
type = typeof(Enum);
if (Initialized)
throw new ArtemisUIException("Cannot initialize the same property input VM twice");
if (!CompatibleTypes.Contains(layerPropertyViewModel.LayerProperty.Type))
throw new ArtemisUIException($"This input VM does not support the provided type {layerPropertyViewModel.LayerProperty.Type.Name}");
if (!CompatibleTypes.Contains(type))
throw new ArtemisUIException($"This input VM does not support the provided type {type.Name}");
LayerPropertyViewModel = layerPropertyViewModel;
layerPropertyViewModel.LayerProperty.ValueChanged += (sender, args) => Update();
Update();
Initialized = true;
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;
}
private void UpdateInputValue(object value)
@@ -49,6 +65,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.P
ProfileEditorService.UpdateSelectedProfileElement();
}
protected virtual void OnInitialized()
{
}
public abstract void Update();
}
}
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="25" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:SKPointPropertyInputViewModel}">
@@ -16,7 +17,8 @@
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
ToolTip="X-coordinate (horizontal)"
Text="{Binding X}" />
Text="{Binding X}"
RequestBringIntoView="{s:Action OnRequestBringIntoView}"/>
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
<TextBox Width="60"
Margin="0 2"
@@ -24,7 +26,8 @@
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
ToolTip="Y-coordinate (vertical)"
Text="{Binding Y}" />
Text="{Binding Y}"
RequestBringIntoView="{s:Action OnRequestBringIntoView}"/>
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
</StackPanel>
</UserControl>
@@ -5,6 +5,7 @@
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree.PropertyInput"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800"
d:DataContext="{d:DesignInstance local:SKSizePropertyInputViewModel}">
@@ -16,7 +17,8 @@
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
ToolTip="Height"
Text="{Binding Height}" />
Text="{Binding Height}"
RequestBringIntoView="{s:Action OnRequestBringIntoView}"/>
<TextBlock Margin="5 0" VerticalAlignment="Bottom">,</TextBlock>
<TextBox Width="60"
Margin="0 2"
@@ -24,7 +26,8 @@
materialDesign:ValidationAssist.UsePopup="True"
HorizontalAlignment="Left"
ToolTip="Width"
Text="{Binding Width}" />
Text="{Binding Width}"
RequestBringIntoView="{s:Action OnRequestBringIntoView}"/>
<TextBlock Margin="5 0 0 0" Width="10" VerticalAlignment="Bottom" Text="{Binding LayerPropertyViewModel.LayerProperty.InputAffix}" />
</StackPanel>
</UserControl>
@@ -23,6 +23,7 @@
Width="18"
Height="18"
IsChecked="{Binding LayerPropertyViewModel.KeyframesEnabled}"
IsEnabled="{Binding LayerPropertyViewModel.LayerProperty.CanUseKeyframes}"
VerticalAlignment="Center" Padding="-25">
<materialDesign:PackIcon Kind="Stopwatch" Height="13" Width="13" />
</ToggleButton>
@@ -82,6 +82,7 @@
<TreeView ItemsSource="{Binding PropertyTreeItemViewModels}"
HorizontalContentAlignment="Stretch"
Background="{DynamicResource MaterialDesignToolBarBackground}"
PreviewMouseWheel="{s:Action PropertyTreePreviewMouseWheel}"
Margin="0 -1">
<TreeView.ItemContainerStyle>
<Style TargetType="TreeViewItem" BasedOn="{StaticResource PropertyTreeStyle}">
@@ -1,5 +1,8 @@
using System.Collections.Generic;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using Artemis.UI.Services.Interfaces;
using Stylet;
@@ -49,5 +52,20 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.LayerProperties.PropertyTree
foreach (var viewModel in PropertyTreeItemViewModels)
viewModel.Update(forceUpdate);
}
public void PropertyTreePreviewMouseWheel(object sender, MouseWheelEventArgs e)
{
if (e.Handled || !(sender is TreeView))
return;
e.Handled = true;
var eventArg = new MouseWheelEventArgs(e.MouseDevice, e.Timestamp, e.Delta)
{
RoutedEvent = UIElement.MouseWheelEvent,
Source = sender
};
var parent = ((Control) sender).Parent as UIElement;
parent?.RaiseEvent(eventArg);
}
}
}
@@ -120,7 +120,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
// The path starts at 0,0 so there's no simple way to get the position relative to the top-left of the path
_dragStart = GetRelativePosition(sender, e.MouseEventArgs).ToSKPoint();
_dragStartScale = layer.SizeProperty.CurrentValue;
_dragStartScale = layer.ScaleProperty.CurrentValue;
// Store the original position and do a test to figure out the mouse offset
var originalPosition = layer.PositionProperty.CurrentValue;
@@ -169,25 +169,25 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
break;
case ShapeControlPoint.TopCenter:
height = VerticalResize(layer, position, ResizeOrigin.Top);
width = layer.SizeProperty.CurrentValue.Width;
width = layer.ScaleProperty.CurrentValue.Width;
break;
case ShapeControlPoint.RightCenter:
width = HorizontalResize(layer, position, ResizeOrigin.Right);
height = layer.SizeProperty.CurrentValue.Height;
height = layer.ScaleProperty.CurrentValue.Height;
break;
case ShapeControlPoint.BottomCenter:
width = layer.SizeProperty.CurrentValue.Width;
width = layer.ScaleProperty.CurrentValue.Width;
height = VerticalResize(layer, position, ResizeOrigin.Bottom);
break;
case ShapeControlPoint.LeftCenter:
width = HorizontalResize(layer, position, ResizeOrigin.Left);
height = layer.SizeProperty.CurrentValue.Height;
height = layer.ScaleProperty.CurrentValue.Height;
break;
default:
throw new ArgumentOutOfRangeException();
}
layer.SizeProperty.SetCurrentValue(new SKSize(width, height), ProfileEditorService.CurrentTime);
layer.ScaleProperty.SetCurrentValue(new SKSize(width, height), ProfileEditorService.CurrentTime);
ProfileEditorService.UpdateProfilePreview();
}
@@ -206,9 +206,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
var anchorOffset = anchorDistance / shapePath.Bounds.Width;
var pixelsToAdd = (position - dragStart).X / anchorOffset;
var scaleToAdd = scalePerPixel * pixelsToAdd;
var scaleToAdd = scalePerPixel * pixelsToAdd * 100f;
return Math.Max(0.001f, _dragStartScale.Width + scaleToAdd);
return (float) Math.Round(Math.Max(0, _dragStartScale.Width + scaleToAdd), 2, MidpointRounding.AwayFromZero);
}
private float VerticalResize(Layer layer, SKPoint position, ResizeOrigin origin)
@@ -226,9 +226,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
var anchorOffset = anchorDistance / shapePath.Bounds.Height;
var pixelsToAdd = (position - dragStart).Y / anchorOffset;
var scaleToAdd = scalePerPixel * pixelsToAdd;
var scaleToAdd = scalePerPixel * pixelsToAdd * 100f;
return Math.Max(0.001f, _dragStartScale.Height + scaleToAdd);
return (float) Math.Round(Math.Max(0, _dragStartScale.Height + scaleToAdd), 2, MidpointRounding.AwayFromZero);
}
#endregion
@@ -250,7 +250,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
// The path starts at 0,0 so there's no simple way to get the position relative to the top-left of the path
_dragStart = GetRelativePosition(sender, e.MouseEventArgs).ToSKPoint();
_dragStartScale = layer.SizeProperty.CurrentValue;
_dragStartScale = layer.ScaleProperty.CurrentValue;
// Store the original position and do a test to figure out the mouse offset
var originalPosition = layer.PositionProperty.CurrentValue;
@@ -378,7 +378,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
counterRotatePath.AddPoly(skPoints, false);
counterRotatePath.Transform(SKMatrix.MakeRotationDegrees(layer.RotationProperty.CurrentValue * -1, pivot.X, pivot.Y));
if (includeScale)
counterRotatePath.Transform(SKMatrix.MakeScale(1f / layer.SizeProperty.CurrentValue.Width, 1f / layer.SizeProperty.CurrentValue.Height));
counterRotatePath.Transform(SKMatrix.MakeScale(1f / (layer.ScaleProperty.CurrentValue.Width / 100f), 1f / (layer.ScaleProperty.CurrentValue.Height / 100f)));
return counterRotatePath.Points;
}