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

Removed separate shape size

This commit is contained in:
SpoinkyNL 2020-02-04 22:01:02 +01:00
parent 436994129a
commit 2c60a42315
34 changed files with 81 additions and 862 deletions

View File

@ -158,8 +158,6 @@
<Compile Include="Models\Profile\LayerProperties\Keyframe.cs" /> <Compile Include="Models\Profile\LayerProperties\Keyframe.cs" />
<Compile Include="Models\Profile\LayerProperties\BaseLayerProperty.cs" /> <Compile Include="Models\Profile\LayerProperties\BaseLayerProperty.cs" />
<Compile Include="Models\Profile\LayerShapes\Ellipse.cs" /> <Compile Include="Models\Profile\LayerShapes\Ellipse.cs" />
<Compile Include="Models\Profile\LayerShapes\Fill.cs" />
<Compile Include="Models\Profile\LayerShapes\Polygon.cs" />
<Compile Include="Models\Profile\LayerShapes\Rectangle.cs" /> <Compile Include="Models\Profile\LayerShapes\Rectangle.cs" />
<Compile Include="Models\Profile\LayerShapes\LayerShape.cs" /> <Compile Include="Models\Profile\LayerShapes\LayerShape.cs" />
<Compile Include="Models\Surface\ArtemisLed.cs" /> <Compile Include="Models\Surface\ArtemisLed.cs" />

View File

@ -72,7 +72,7 @@ namespace Artemis.Core.Models.Profile
public Layer AddLayer(string name) public Layer AddLayer(string name)
{ {
var layer = new Layer(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1}; var layer = new Layer(Profile, this, name) {Order = Children.LastOrDefault()?.Order ?? 1};
layer.LayerShape = new Fill(layer); layer.LayerShape = new Rectangle(layer);
AddChild(layer); AddChild(layer);
return layer; return layer;
} }

View File

@ -51,22 +51,13 @@ namespace Artemis.Core.Models.Profile
CreateDefaultProperties(); CreateDefaultProperties();
switch (layerEntity.ShapeEntity?.Type) switch (layerEntity.ShapeType)
{ {
case ShapeEntityType.Ellipse: case ShapeEntityType.Ellipse:
LayerShape = new Ellipse(this, layerEntity.ShapeEntity); LayerShape = new Ellipse(this);
break;
case ShapeEntityType.Fill:
LayerShape = new Fill(this, layerEntity.ShapeEntity);
break;
case ShapeEntityType.Polygon:
LayerShape = new Polygon(this, layerEntity.ShapeEntity);
break; break;
case ShapeEntityType.Rectangle: case ShapeEntityType.Rectangle:
LayerShape = new Rectangle(this, layerEntity.ShapeEntity); LayerShape = new Rectangle(this);
break;
case null:
LayerShape = null;
break; break;
default: default:
throw new ArgumentOutOfRangeException(); throw new ArgumentOutOfRangeException();
@ -175,18 +166,18 @@ namespace Artemis.Core.Models.Profile
var sizeProperty = SizeProperty.CurrentValue; var sizeProperty = SizeProperty.CurrentValue;
var rotationProperty = RotationProperty.CurrentValue; var rotationProperty = RotationProperty.CurrentValue;
var anchorPosition = GetLayerAnchorPosition() + Bounds.Location; var anchorPosition = GetLayerAnchorPosition();
var anchorProperty = AnchorPointProperty.CurrentValue; var anchorProperty = AnchorPointProperty.CurrentValue;
// Translation originates from the unscaled center of the shape and is tied to the anchor // Translation originates from the unscaled center of the layer and is tied to the anchor
var x = anchorPosition.X - LayerShape.Bounds.MidX - anchorProperty.X * Bounds.Width; var x = anchorPosition.X - Bounds.MidX - anchorProperty.X * Bounds.Width;
var y = anchorPosition.Y - LayerShape.Bounds.MidY - anchorProperty.Y * Bounds.Height; var y = anchorPosition.Y - Bounds.MidY - anchorProperty.Y * Bounds.Height;
// Apply these before translation because anchorPosition takes translation into account // Rotation is always applied on the canvas
canvas.RotateDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y); canvas.RotateDegrees(rotationProperty, anchorPosition.X, anchorPosition.Y);
canvas.Scale(sizeProperty.Width, sizeProperty.Height, anchorPosition.X, anchorPosition.Y); // canvas.Scale(sizeProperty.Width, sizeProperty.Height, anchorPosition.X, anchorPosition.Y);
// Once the other transformations are done it is save to translate // Once the other transformations are done it is save to translate
canvas.Translate(x, y); // canvas.Translate(x, y);
// Placeholder // Placeholder
if (LayerShape?.Path != null) if (LayerShape?.Path != null)
@ -200,8 +191,12 @@ namespace Artemis.Core.Models.Profile
testColors.Add(SKColor.FromHsv(0, 100, 100)); testColors.Add(SKColor.FromHsv(0, 100, 100));
} }
var shader = SKShader.CreateSweepGradient(new SKPoint(LayerShape.Bounds.MidX, LayerShape.Bounds.MidY), testColors.ToArray()); var path = new SKPath(LayerShape.Path);
canvas.DrawPath(LayerShape.Path, new SKPaint {Shader = shader, Color = new SKColor(0, 0, 0, (byte) (OpacityProperty.CurrentValue * 2.55f))}); path.Transform(SKMatrix.MakeTranslation(x, y));
path.Transform(SKMatrix.MakeScale(sizeProperty.Width, sizeProperty.Height, anchorPosition.X, anchorPosition.Y));
var shader = SKShader.CreateSweepGradient(new SKPoint(path.Bounds.MidX, path.Bounds.MidY), testColors.ToArray());
canvas.DrawPath(path, new SKPaint {Shader = shader, Color = new SKColor(0, 0, 0, (byte) (OpacityProperty.CurrentValue * 2.55f))});
} }
LayerBrush?.Render(canvas); LayerBrush?.Render(canvas);
@ -213,7 +208,7 @@ namespace Artemis.Core.Models.Profile
var positionProperty = PositionProperty.CurrentValue; var positionProperty = PositionProperty.CurrentValue;
// Start at the center of the shape // Start at the center of the shape
var position = new SKPoint(LayerShape.Bounds.MidX, LayerShape.Bounds.MidY); var position = new SKPoint(Bounds.MidX, Bounds.MidY);
// Apply translation // Apply translation
position.X += positionProperty.X * Bounds.Width; position.X += positionProperty.X * Bounds.Width;

View File

@ -9,21 +9,16 @@ namespace Artemis.Core.Models.Profile.LayerShapes
{ {
} }
internal Ellipse(Layer layer, ShapeEntity shapeEntity) : base(layer, shapeEntity)
{
}
public override void CalculateRenderProperties() public override void CalculateRenderProperties()
{ {
var path = new SKPath(); var path = new SKPath();
path.AddOval(GetUnscaledRectangle()); path.AddOval(Layer.Bounds);
Path = path; Path = path;
} }
internal override void ApplyToEntity() public override void ApplyToEntity()
{ {
base.ApplyToEntity(); Layer.LayerEntity.ShapeType = ShapeEntityType.Ellipse;
Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Ellipse;
} }
} }
} }

View File

@ -1,28 +0,0 @@
using Artemis.Storage.Entities.Profile;
using SkiaSharp;
namespace Artemis.Core.Models.Profile.LayerShapes
{
public class Fill : LayerShape
{
public Fill(Layer layer) : base(layer)
{
}
internal Fill(Layer layer, ShapeEntity shapeEntity) : base(layer, shapeEntity)
{
}
public override void CalculateRenderProperties()
{
// Shape originates from the center so compensate the path for that
Path = new SKPath(Layer.Path);
}
internal override void ApplyToEntity()
{
base.ApplyToEntity();
Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Fill;
}
}
}

View File

@ -1,97 +1,26 @@
using System.Linq; using SkiaSharp;
using Artemis.Storage.Entities.Profile;
using SkiaSharp;
namespace Artemis.Core.Models.Profile.LayerShapes namespace Artemis.Core.Models.Profile.LayerShapes
{ {
public abstract class LayerShape public abstract class LayerShape
{ {
private SKPath _path;
protected LayerShape(Layer layer) protected LayerShape(Layer layer)
{ {
Layer = layer; Layer = layer;
} }
protected LayerShape(Layer layer, ShapeEntity shapeEntity)
{
Layer = layer;
ScaledRectangle = SKRect.Create(shapeEntity.X, shapeEntity.Y, shapeEntity.Width, shapeEntity.Height);
}
/// <summary> /// <summary>
/// The layer this shape is attached to /// The layer this shape is attached to
/// </summary> /// </summary>
public Layer Layer { get; set; } public Layer Layer { get; set; }
/// <summary>
/// A relative and scaled rectangle that defines where the shape is located in relation to the layer's size
/// <para>Note: scaled means a range of 0.0 to 1.0. 1.0 being full width/height, 0.5 being half</para>
/// </summary>
public SKRect ScaledRectangle { get; set; }
/// <summary> /// <summary>
/// A path outlining the shape /// A path outlining the shape
/// </summary> /// </summary>
public SKPath Path public SKPath Path { get; protected set; }
{
get => _path;
protected set
{
_path = value;
Bounds = value?.Bounds ?? SKRect.Empty;
}
}
/// <summary>
/// The bounds of this shape
/// </summary>
public SKRect Bounds { get; private set; }
public abstract void CalculateRenderProperties(); public abstract void CalculateRenderProperties();
/// <summary> public abstract void ApplyToEntity();
/// Updates Position and Size using the provided unscaled rectangle
/// </summary>
/// <param name="rect">An unscaled rectangle where 1px = 1mm</param>
public void SetFromUnscaledRectangle(SKRect rect)
{
if (!Layer.Leds.Any())
{
ScaledRectangle = SKRect.Empty;
return;
}
ScaledRectangle = SKRect.Create(
100f / Layer.Bounds.Width * rect.Left / 100f,
100f / Layer.Bounds.Height * rect.Top / 100f,
100f / Layer.Bounds.Width * rect.Width / 100f,
100f / Layer.Bounds.Height * rect.Height / 100f
);
}
public SKRect GetUnscaledRectangle()
{
if (!Layer.Leds.Any())
return SKRect.Empty;
return SKRect.Create(
Layer.Bounds.Width * ScaledRectangle.Left,
Layer.Bounds.Height * ScaledRectangle.Top,
Layer.Bounds.Width * ScaledRectangle.Width,
Layer.Bounds.Height * ScaledRectangle.Height
);
}
internal virtual void ApplyToEntity()
{
Layer.LayerEntity.ShapeEntity = new ShapeEntity
{
X = ScaledRectangle.Left,
Y = ScaledRectangle.Top,
Width = ScaledRectangle.Width,
Height = ScaledRectangle.Height
};
}
} }
} }

View File

@ -1,45 +0,0 @@
using System.Collections.Generic;
using System.Linq;
using Artemis.Storage.Entities.Profile;
using SkiaSharp;
namespace Artemis.Core.Models.Profile.LayerShapes
{
public class Polygon : LayerShape
{
public Polygon(Layer layer) : base(layer)
{
}
internal Polygon(Layer layer, ShapeEntity shapeEntity) : base(layer, shapeEntity)
{
}
/// <summary>
/// The points of this polygon
/// </summary>
public List<SKPoint> Points { get; set; }
/// <summary>
/// The points of this polygon where they need to be rendered inside the layer
/// </summary>
public List<SKPoint> RenderPoints
{
get { return Points.Select(p => new SKPoint(p.X * Layer.Bounds.Width, p.Y * Layer.Bounds.Height)).ToList(); }
}
public override void CalculateRenderProperties()
{
var path = new SKPath();
path.AddPoly(RenderPoints.ToArray());
Path = path;
}
internal override void ApplyToEntity()
{
base.ApplyToEntity();
Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Polygon;
Layer.LayerEntity.ShapeEntity.Points = Points.Select(p => new ShapePointEntity {X = p.X, Y = p.Y}).ToList();
}
}
}

View File

@ -9,21 +9,16 @@ namespace Artemis.Core.Models.Profile.LayerShapes
{ {
} }
internal Rectangle(Layer layer, ShapeEntity shapeEntity) : base(layer, shapeEntity)
{
}
public override void CalculateRenderProperties() public override void CalculateRenderProperties()
{ {
var path = new SKPath(); var path = new SKPath();
path.AddRect(GetUnscaledRectangle()); path.AddRect(Layer.Bounds);
Path = path; Path = path;
} }
internal override void ApplyToEntity() public override void ApplyToEntity()
{ {
base.ApplyToEntity(); Layer.LayerEntity.ShapeType = ShapeEntityType.Rectangle;
Layer.LayerEntity.ShapeEntity.Type = ShapeEntityType.Rectangle;
} }
} }
} }

View File

@ -35,7 +35,7 @@ namespace Artemis.Plugins.LayerBrushes.Color
private void CreateShader() private void CreateShader()
{ {
var center = new SKPoint(Layer.LayerShape.Bounds.MidX, Layer.LayerShape.Bounds.MidY); var center = new SKPoint(Layer.Bounds.MidX, Layer.Bounds.MidY);
SKShader shader; SKShader shader;
switch (Settings.GradientType) switch (Settings.GradientType)
{ {
@ -43,10 +43,10 @@ namespace Artemis.Plugins.LayerBrushes.Color
shader = SKShader.CreateColor(_testColors.First()); shader = SKShader.CreateColor(_testColors.First());
break; break;
case GradientType.LinearGradient: case GradientType.LinearGradient:
shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(Layer.LayerShape.Bounds.Width, 0), _testColors.ToArray(), SKShaderTileMode.Repeat); shader = SKShader.CreateLinearGradient(new SKPoint(0, 0), new SKPoint(Layer.Bounds.Width, 0), _testColors.ToArray(), SKShaderTileMode.Repeat);
break; break;
case GradientType.RadialGradient: case GradientType.RadialGradient:
shader = SKShader.CreateRadialGradient(center, Math.Min(Layer.LayerShape.Bounds.Width, Layer.LayerShape.Bounds.Height), _testColors.ToArray(), SKShaderTileMode.Repeat); shader = SKShader.CreateRadialGradient(center, Math.Min(Layer.Bounds.Width, Layer.Bounds.Height), _testColors.ToArray(), SKShaderTileMode.Repeat);
break; break;
case GradientType.SweepGradient: case GradientType.SweepGradient:
shader = SKShader.CreateSweepGradient(center, _testColors.ToArray(), null, SKShaderTileMode.Clamp, 0, 360); shader = SKShader.CreateSweepGradient(center, _testColors.ToArray(), null, SKShaderTileMode.Clamp, 0, 360);

View File

@ -23,7 +23,7 @@ namespace Artemis.Storage.Entities.Profile
public List<PropertyEntity> PropertyEntities { get; set; } public List<PropertyEntity> PropertyEntities { get; set; }
public List<ProfileConditionEntity> Condition { get; set; } public List<ProfileConditionEntity> Condition { get; set; }
public ShapeEntity ShapeEntity { get; set; } public ShapeEntityType ShapeType { get; set; }
public BrushEntity BrushEntity { get; set; } public BrushEntity BrushEntity { get; set; }
[BsonRef("ProfileEntity")] [BsonRef("ProfileEntity")]
@ -31,4 +31,10 @@ namespace Artemis.Storage.Entities.Profile
public Guid ProfileId { get; set; } public Guid ProfileId { get; set; }
} }
public enum ShapeEntityType
{
Ellipse,
Rectangle
}
} }

View File

@ -1,28 +0,0 @@
using System.Collections.Generic;
namespace Artemis.Storage.Entities.Profile
{
public class ShapeEntity
{
public float X { get; set; }
public float Y { get; set; }
public float Width { get; set; }
public float Height { get; set; }
public ShapeEntityType Type { get; set; }
public List<ShapePointEntity> Points { get; set; }
}
public class ShapePointEntity
{
public float X { get; set; }
public float Y { get; set; }
}
public enum ShapeEntityType
{
Ellipse,
Fill,
Polygon,
Rectangle
}
}

View File

@ -189,22 +189,6 @@
</Compile> </Compile>
<Compile Include="Screens\Module\ProfileEditor\Visualization\ProfileLayerViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\Visualization\ProfileLayerViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\EditToolViewModel.cs" /> <Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\EditToolViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\EllipseToolView.xaml.cs">
<DependentUpon>EllipseToolView.xaml</DependentUpon>
</Compile>
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\EllipseToolViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\FillToolView.xaml.cs">
<DependentUpon>FillToolView.xaml</DependentUpon>
</Compile>
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\FillToolViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\PolygonToolView.xaml.cs">
<DependentUpon>PolygonToolView.xaml</DependentUpon>
</Compile>
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\PolygonToolViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\RectangleToolView.xaml.cs">
<DependentUpon>RectangleToolView.xaml</DependentUpon>
</Compile>
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\RectangleToolViewModel.cs" />
<Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\SelectionRemoveToolView.xaml.cs"> <Compile Include="Screens\Module\ProfileEditor\Visualization\Tools\SelectionRemoveToolView.xaml.cs">
<DependentUpon>SelectionRemoveToolView.xaml</DependentUpon> <DependentUpon>SelectionRemoveToolView.xaml</DependentUpon>
</Compile> </Compile>
@ -374,22 +358,6 @@
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>
</Page> </Page>
<Page Include="Screens\Module\ProfileEditor\Visualization\Tools\EllipseToolView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Screens\Module\ProfileEditor\Visualization\Tools\FillToolView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Screens\Module\ProfileEditor\Visualization\Tools\PolygonToolView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Screens\Module\ProfileEditor\Visualization\Tools\RectangleToolView.xaml">
<SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator>
</Page>
<Page Include="Screens\Module\ProfileEditor\Visualization\Tools\SelectionRemoveToolView.xaml"> <Page Include="Screens\Module\ProfileEditor\Visualization\Tools\SelectionRemoveToolView.xaml">
<SubType>Designer</SubType> <SubType>Designer</SubType>
<Generator>MSBuild:Compile</Generator> <Generator>MSBuild:Compile</Generator>

View File

@ -32,35 +32,33 @@
</Style> </Style>
</UserControl.Resources> </UserControl.Resources>
<Canvas Style="{StaticResource SelectedStyle}"> <Canvas Style="{StaticResource SelectedStyle}">
<!-- The shape is inside the layer's bounds -->
<Canvas Canvas.Left="{Binding LayerBounds.X}" Canvas.Top="{Binding LayerBounds.Y}">
<!-- The part of the layer's shape that falls outside the layer -->
<Path Data="{Binding ShapeGeometry, Mode=OneWay}">
<Path.Fill>
<SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.05" />
</Path.Fill>
<Path.Stroke>
<SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.15" />
</Path.Stroke>
</Path>
<!-- The part of the layer's shape that is inside the layer --> <!-- The part of the layer's shape that falls outside the layer -->
<Path Data="{Binding ShapeGeometry, Mode=OneWay}"> <Path Data="{Binding ShapeGeometry, Mode=OneWay}">
<Path.Fill> <Path.Fill>
<SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.15" /> <SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.05" />
</Path.Fill> </Path.Fill>
<Path.Stroke> <Path.Stroke>
<SolidColorBrush Color="{StaticResource Accent700}" /> <SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.15" />
</Path.Stroke> </Path.Stroke>
<Path.OpacityMask> </Path>
<VisualBrush Viewport="{Binding ViewportRectangle}" ViewportUnits="Absolute">
<VisualBrush.Visual> <!-- The part of the layer's shape that is inside the layer -->
<Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" Fill="Black" /> <Path Data="{Binding ShapeGeometry, Mode=OneWay}">
</VisualBrush.Visual> <Path.Fill>
</VisualBrush> <SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.15" />
</Path.OpacityMask> </Path.Fill>
</Path> <Path.Stroke>
</Canvas> <SolidColorBrush Color="{StaticResource Accent700}" />
</Path.Stroke>
<Path.OpacityMask>
<VisualBrush Viewport="{Binding ViewportRectangle}" ViewportUnits="Absolute">
<VisualBrush.Visual>
<Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" Fill="Black" />
</VisualBrush.Visual>
</VisualBrush>
</Path.OpacityMask>
</Path>
<Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" StrokeThickness="1.5" StrokeLineJoin="Round" x:Name="LayerPath"> <Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" StrokeThickness="1.5" StrokeLineJoin="Round" x:Name="LayerPath">
<Path.Stroke> <Path.Stroke>

View File

@ -30,11 +30,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
_profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated; _profileEditorService.SelectedProfileElementUpdated += OnSelectedProfileElementUpdated;
_profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated; _profileEditorService.ProfilePreviewUpdated += ProfileEditorServiceOnProfilePreviewUpdated;
} }
public Layer Layer { get; } public Layer Layer { get; }
public Rect LayerBounds { get; set; }
public Geometry LayerGeometry { get; set; } public Geometry LayerGeometry { get; set; }
public Geometry OpacityGeometry { get; set; } public Geometry OpacityGeometry { get; set; }
public Geometry ShapeGeometry { get; set; } public Geometry ShapeGeometry { get; set; }
@ -53,7 +51,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
{ {
if (!Layer.Leds.Any()) if (!Layer.Leds.Any())
{ {
LayerBounds = Rect.Empty;
LayerGeometry = Geometry.Empty; LayerGeometry = Geometry.Empty;
OpacityGeometry = Geometry.Empty; OpacityGeometry = Geometry.Empty;
ViewportRectangle = Rect.Empty; ViewportRectangle = Rect.Empty;
@ -89,8 +86,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
var layerGeometry = group.GetOutlinedPathGeometry(); var layerGeometry = group.GetOutlinedPathGeometry();
var opacityGeometry = Geometry.Combine(Geometry.Empty, layerGeometry, GeometryCombineMode.Exclude, new TranslateTransform()); var opacityGeometry = Geometry.Combine(Geometry.Empty, layerGeometry, GeometryCombineMode.Exclude, new TranslateTransform());
LayerBounds = _layerEditorService.GetLayerBounds(Layer);
LayerGeometry = layerGeometry; LayerGeometry = layerGeometry;
OpacityGeometry = opacityGeometry; OpacityGeometry = opacityGeometry;
} }
@ -105,25 +101,13 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
Execute.PostToUIThread(() => Execute.PostToUIThread(() =>
{ {
var bounds = _layerEditorService.GetLayerShapeBounds(Layer.LayerShape); var bounds = _layerEditorService.GetLayerBounds(Layer);
var shapeGeometry = Geometry.Empty; var shapeGeometry = Geometry.Empty;
switch (Layer.LayerShape) switch (Layer.LayerShape)
{ {
case Ellipse _: case Ellipse _:
shapeGeometry = new EllipseGeometry(bounds); shapeGeometry = new EllipseGeometry(bounds);
break; break;
case Fill _:
// Shape originates from the center so compensate the geometry for that, create a copy
shapeGeometry = LayerGeometry.Clone();
// Add a transformation
shapeGeometry.Transform = new TranslateTransform(bounds.Left - shapeGeometry.Bounds.Left, bounds.Top - shapeGeometry.Bounds.Top);
// Apply the transformation so that it won't be overridden
shapeGeometry = shapeGeometry.GetOutlinedPathGeometry();
break;
case Polygon _:
// TODO
shapeGeometry = new RectangleGeometry(bounds);
break;
case Rectangle _: case Rectangle _:
shapeGeometry = new RectangleGeometry(bounds); shapeGeometry = new RectangleGeometry(bounds);
break; break;
@ -142,8 +126,7 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
return; return;
} }
var rect = _layerEditorService.GetLayerBounds(Layer); ViewportRectangle = _layerEditorService.GetLayerBounds(Layer);
ViewportRectangle = new Rect(0, 0, rect.Width, rect.Height);
} }
private Geometry CreateRectangleGeometry(ArtemisLed led) private Geometry CreateRectangleGeometry(ArtemisLed led)

View File

@ -8,7 +8,7 @@
xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.Visualization" xmlns:profileEditor="clr-namespace:Artemis.UI.Screens.Module.ProfileEditor.Visualization"
xmlns:utilities="clr-namespace:Artemis.UI.Utilities" xmlns:utilities="clr-namespace:Artemis.UI.Utilities"
mc:Ignorable="d" mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800" d:DesignHeight="510.9" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type profileEditor:ProfileViewModel}}"> d:DataContext="{d:DesignInstance {x:Type profileEditor:ProfileViewModel}}">
<UserControl.Resources> <UserControl.Resources>
<Style TargetType="Grid" x:Key="InitializingFade"> <Style TargetType="Grid" x:Key="InitializingFade">
@ -65,21 +65,7 @@
<ListBoxItem ToolTip="Remove from layer selection"> <ListBoxItem ToolTip="Remove from layer selection">
<materialDesign:PackIcon Kind="SelectOff" /> <materialDesign:PackIcon Kind="SelectOff" />
</ListBoxItem> </ListBoxItem>
<Separator />
<ListBoxItem ToolTip="Create round shape in layer">
<materialDesign:PackIcon Kind="ShapeCirclePlus" />
</ListBoxItem>
<ListBoxItem ToolTip="Create rectangular shape in layer">
<materialDesign:PackIcon Kind="ShapeRectanglePlus" />
</ListBoxItem>
<ListBoxItem ToolTip="Create polygonal shape in layer">
<materialDesign:PackIcon Kind="ShapePolygonPlus" />
</ListBoxItem>
<ListBoxItem ToolTip="Fill entire layer">
<materialDesign:PackIcon Kind="FormatColourFill" />
</ListBoxItem>
</ListBox> </ListBox>
</ToolBar> </ToolBar>
</ToolBarTray> </ToolBarTray>
<Grid Grid.Column="1" <Grid Grid.Column="1"

View File

@ -259,22 +259,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
ActiveToolViewModel = new EditToolViewModel(this, _profileEditorService, _layerEditorService); ActiveToolViewModel = new EditToolViewModel(this, _profileEditorService, _layerEditorService);
break; break;
case 2: case 2:
ActiveToolViewModel = new SelectionToolViewModel(this, _profileEditorService, _layerEditorService); ActiveToolViewModel = new SelectionToolViewModel(this, _profileEditorService);
break; break;
case 3: case 3:
ActiveToolViewModel = new SelectionRemoveToolViewModel(this, _profileEditorService, _layerEditorService); ActiveToolViewModel = new SelectionRemoveToolViewModel(this, _profileEditorService);
break;
case 5:
ActiveToolViewModel = new EllipseToolViewModel(this, _profileEditorService, _layerEditorService);
break;
case 6:
ActiveToolViewModel = new RectangleToolViewModel(this, _profileEditorService, _layerEditorService);
break;
case 7:
ActiveToolViewModel = new PolygonToolViewModel(this, _profileEditorService);
break;
case 8:
ActiveToolViewModel = new FillToolViewModel(this, _profileEditorService, _layerEditorService);
break; break;
} }

View File

@ -11,9 +11,7 @@
d:DesignWidth="800" d:DesignWidth="800"
d:DataContext="{d:DesignInstance {x:Type local:EditToolViewModel}}"> d:DataContext="{d:DesignInstance {x:Type local:EditToolViewModel}}">
<Canvas UseLayoutRounding="False"> <Canvas UseLayoutRounding="False">
<userControls:LayerShapeControl Canvas.Left="{Binding LayerBounds.Left}" <userControls:LayerShapeControl Zoom="{Binding ProfileViewModel.PanZoomViewModel.Zoom}"
Canvas.Top="{Binding LayerBounds.Top}"
Zoom="{Binding ProfileViewModel.PanZoomViewModel.Zoom}"
ShapePath="{Binding ShapePath}" ShapePath="{Binding ShapePath}"
ShapeAnchor="{Binding ShapeAnchor}" ShapeAnchor="{Binding ShapeAnchor}"
ShapeGeometry="{Binding ShapeGeometry}" ShapeGeometry="{Binding ShapeGeometry}"

View File

@ -32,7 +32,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
profileEditorService.ProfilePreviewUpdated += (sender, args) => Update(); profileEditorService.ProfilePreviewUpdated += (sender, args) => Update();
} }
public Rect LayerBounds { get; set; }
public SKPath ShapePath { get; set; } public SKPath ShapePath { get; set; }
public SKPoint ShapeAnchor { get; set; } public SKPoint ShapeAnchor { get; set; }
public RectangleGeometry ShapeGeometry { get; set; } public RectangleGeometry ShapeGeometry { get; set; }
@ -42,12 +41,11 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
if (!(ProfileEditorService.SelectedProfileElement is Layer layer)) if (!(ProfileEditorService.SelectedProfileElement is Layer layer))
return; return;
LayerBounds = _layerEditorService.GetLayerBounds(layer);
ShapePath = _layerEditorService.GetLayerPath(layer, true, true, true); ShapePath = _layerEditorService.GetLayerPath(layer, true, true, true);
ShapeAnchor = _layerEditorService.GetLayerAnchorPosition(layer).ToSKPoint(); ShapeAnchor = _layerEditorService.GetLayerAnchorPosition(layer).ToSKPoint();
Execute.PostToUIThread(() => Execute.PostToUIThread(() =>
{ {
var shapeGeometry = new RectangleGeometry(_layerEditorService.GetLayerShapeBounds(layer.LayerShape)) var shapeGeometry = new RectangleGeometry(_layerEditorService.GetLayerBounds(layer))
{ {
Transform = _layerEditorService.GetLayerTransformGroup(layer) Transform = _layerEditorService.GetLayerTransformGroup(layer)
}; };

View File

@ -1,62 +0,0 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools.EllipseToolView"
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.Visualization.Tools"
xmlns:s="https://github.com/canton7/Stylet"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Style TargetType="Shape" x:Key="ShowIfMouseDown">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseDown}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetProperty="Opacity">
<DoubleAnimation From="0" To="1" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard TargetProperty="Opacity">
<DoubleAnimation From="1" To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Canvas Background="Transparent" Width="50" Height="50">
<Canvas.ContextMenu>
<ContextMenu>
<MenuItem Header="Ellipse action 1" Command="{s:Action CreateLayer}" CommandParameter="{Binding}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="LayersPlus" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Ellipse action 2" Command="{s:Action ApplyToLayer}" CommandParameter="{Binding}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Selection" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Canvas.ContextMenu>
<Ellipse Style="{StaticResource ShowIfMouseDown}"
Width="{Binding DragRectangle.Width}"
Height="{Binding DragRectangle.Height}"
Canvas.Left="{Binding DragRectangle.X}"
Canvas.Top="{Binding DragRectangle.Y}"
Stroke="{DynamicResource PrimaryHueLightBrush}"
StrokeThickness="1"
Opacity="0">
<Ellipse.Fill>
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
</Ellipse.Fill>
</Ellipse>
</Canvas>
</UserControl>

View File

@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
/// <summary>
/// Interaction logic for EllipseToolView.xaml
/// </summary>
public partial class EllipseToolView : UserControl
{
public EllipseToolView()
{
InitializeComponent();
}
}
}

View File

@ -1,74 +0,0 @@
using System.IO;
using System.Windows;
using System.Windows.Input;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerShapes;
using Artemis.UI.Properties;
using Artemis.UI.Services.Interfaces;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
public class EllipseToolViewModel : VisualizationToolViewModel
{
private readonly ILayerEditorService _layerEditorService;
private bool _shiftDown;
public EllipseToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService)
: base(profileViewModel, profileEditorService)
{
_layerEditorService = layerEditorService;
using (var stream = new MemoryStream(Resources.aero_crosshair))
{
Cursor = new Cursor(stream);
}
}
public Rect DragRectangle { get; set; }
public override void MouseMove(object sender, MouseEventArgs e)
{
base.MouseMove(sender, e);
if (!IsMouseDown)
return;
var position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e);
if (!_shiftDown)
DragRectangle = new Rect(MouseDownStartPosition, position);
else
DragRectangle = GetSquareRectBetweenPoints(MouseDownStartPosition, position);
}
public override void MouseUp(object sender, MouseButtonEventArgs e)
{
base.MouseUp(sender, e);
if (ProfileEditorService.SelectedProfileElement is Layer layer)
{
// Ensure the shape is an ellipse, we're all about ellipses up here
if (!(layer.LayerShape is Ellipse))
layer.LayerShape = new Ellipse(layer);
// Apply the drag rectangle
_layerEditorService.SetShapeBaseFromRectangle(layer.LayerShape, DragRectangle);
ProfileEditorService.UpdateSelectedProfileElement();
}
}
public override void KeyUp(KeyEventArgs e)
{
base.KeyUp(e);
if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
_shiftDown = false;
}
public override void KeyDown(KeyEventArgs e)
{
base.KeyDown(e);
if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
_shiftDown = true;
}
}
}

View File

@ -1,9 +0,0 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools.FillToolView"
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.Visualization.Tools"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
</UserControl>

View File

@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
/// <summary>
/// Interaction logic for FillToolView.xaml
/// </summary>
public partial class FillToolView : UserControl
{
public FillToolView()
{
InitializeComponent();
}
}
}

View File

@ -1,46 +0,0 @@
using System.IO;
using System.Linq;
using System.Windows;
using System.Windows.Input;
using Artemis.Core.Models.Profile.LayerShapes;
using Artemis.UI.Properties;
using Artemis.UI.Services.Interfaces;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
public class FillToolViewModel : VisualizationToolViewModel
{
private readonly ILayerEditorService _layerEditorService;
public FillToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService) : base(profileViewModel, profileEditorService)
{
_layerEditorService = layerEditorService;
using (var stream = new MemoryStream(Resources.aero_fill))
{
Cursor = new Cursor(stream);
}
}
public override void MouseUp(object sender, MouseButtonEventArgs e)
{
base.MouseUp(sender, e);
// Find out if the click is inside a layer and if so, fill it
var position = e.GetPosition((IInputElement) sender);
var panZoomVm = ProfileViewModel.PanZoomViewModel;
var layer = ProfileEditorService.SelectedProfile
.GetAllLayers()
.FirstOrDefault(l => l.Leds.Any(
led => panZoomVm.TransformContainingRect(led.RgbLed.AbsoluteLedRectangle).Contains(position))
);
if (layer == null)
return;
layer.LayerShape = new Fill(layer);
// Apply the full layer rectangle
_layerEditorService.SetShapeBaseFromRectangle(layer.LayerShape, _layerEditorService.GetLayerBounds(layer));
ProfileEditorService.UpdateSelectedProfileElement();
}
}
}

View File

@ -1,10 +0,0 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools.PolygonToolView"
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.Visualization.Tools"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<Grid />
</UserControl>

View File

@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
/// <summary>
/// Interaction logic for PolygonToolView.xaml
/// </summary>
public partial class PolygonToolView : UserControl
{
public PolygonToolView()
{
InitializeComponent();
}
}
}

View File

@ -1,18 +0,0 @@
using System.IO;
using System.Windows.Input;
using Artemis.UI.Properties;
using Artemis.UI.Services.Interfaces;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
public class PolygonToolViewModel : VisualizationToolViewModel
{
public PolygonToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) : base(profileViewModel, profileEditorService)
{
using (var stream = new MemoryStream(Resources.aero_crosshair))
{
Cursor = new Cursor(stream);
}
}
}
}

View File

@ -1,62 +0,0 @@
<UserControl x:Class="Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools.RectangleToolView"
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.Visualization.Tools"
xmlns:materialDesign="http://materialdesigninxaml.net/winfx/xaml/themes"
xmlns:s="https://github.com/canton7/Stylet"
mc:Ignorable="d"
d:DesignHeight="450" d:DesignWidth="800">
<UserControl.Resources>
<Style TargetType="Shape" x:Key="ShowIfMouseDown">
<Style.Triggers>
<DataTrigger Binding="{Binding IsMouseDown}" Value="True">
<DataTrigger.EnterActions>
<BeginStoryboard>
<Storyboard TargetProperty="Opacity">
<DoubleAnimation From="0" To="1" Duration="0:0:0.1" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.EnterActions>
<DataTrigger.ExitActions>
<BeginStoryboard>
<Storyboard TargetProperty="Opacity">
<DoubleAnimation From="1" To="0" Duration="0:0:0.2" />
</Storyboard>
</BeginStoryboard>
</DataTrigger.ExitActions>
</DataTrigger>
</Style.Triggers>
</Style>
</UserControl.Resources>
<Canvas Background="Transparent" Width="50" Height="50">
<Canvas.ContextMenu>
<ContextMenu>
<MenuItem Header="Ellipse action 1" Command="{s:Action CreateLayer}" CommandParameter="{Binding}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="LayersPlus" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Ellipse action 2" Command="{s:Action ApplyToLayer}" CommandParameter="{Binding}">
<MenuItem.Icon>
<materialDesign:PackIcon Kind="Selection" />
</MenuItem.Icon>
</MenuItem>
</ContextMenu>
</Canvas.ContextMenu>
<Rectangle Style="{StaticResource ShowIfMouseDown}"
Width="{Binding DragRectangle.Width}"
Height="{Binding DragRectangle.Height}"
Canvas.Left="{Binding DragRectangle.X}"
Canvas.Top="{Binding DragRectangle.Y}"
Stroke="{DynamicResource PrimaryHueLightBrush}"
StrokeThickness="1"
Opacity="0">
<Rectangle.Fill>
<SolidColorBrush Color="{DynamicResource Primary400}" Opacity="0.25" />
</Rectangle.Fill>
</Rectangle>
</Canvas>
</UserControl>

View File

@ -1,15 +0,0 @@
using System.Windows.Controls;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
/// <summary>
/// Interaction logic for RectangleToolView.xaml
/// </summary>
public partial class RectangleToolView : UserControl
{
public RectangleToolView()
{
InitializeComponent();
}
}
}

View File

@ -1,74 +0,0 @@
using System.IO;
using System.Windows;
using System.Windows.Input;
using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerShapes;
using Artemis.UI.Properties;
using Artemis.UI.Services.Interfaces;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{
public class RectangleToolViewModel : VisualizationToolViewModel
{
private readonly ILayerEditorService _layerEditorService;
private bool _shiftDown;
public RectangleToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService)
: base(profileViewModel, profileEditorService)
{
_layerEditorService = layerEditorService;
using (var stream = new MemoryStream(Resources.aero_crosshair))
{
Cursor = new Cursor(stream);
}
}
public Rect DragRectangle { get; set; }
public override void MouseMove(object sender, MouseEventArgs e)
{
base.MouseMove(sender, e);
if (!IsMouseDown)
return;
var position = ProfileViewModel.PanZoomViewModel.GetRelativeMousePosition(sender, e);
if (!_shiftDown)
DragRectangle = new Rect(MouseDownStartPosition, position);
else
DragRectangle = GetSquareRectBetweenPoints(MouseDownStartPosition, position);
}
public override void MouseUp(object sender, MouseButtonEventArgs e)
{
base.MouseUp(sender, e);
if (ProfileEditorService.SelectedProfileElement is Layer layer)
{
// Ensure the shape is a rectangle
if (!(layer.LayerShape is Rectangle))
layer.LayerShape = new Rectangle(layer);
// Apply the drag rectangle
_layerEditorService.SetShapeBaseFromRectangle(layer.LayerShape, DragRectangle);
ProfileEditorService.UpdateSelectedProfileElement();
}
}
public override void KeyUp(KeyEventArgs e)
{
base.KeyUp(e);
if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
_shiftDown = false;
}
public override void KeyDown(KeyEventArgs e)
{
base.KeyDown(e);
if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
_shiftDown = true;
}
}
}

View File

@ -8,18 +8,13 @@ using Artemis.Core.Models.Surface;
using Artemis.UI.Extensions; using Artemis.UI.Extensions;
using Artemis.UI.Properties; using Artemis.UI.Properties;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using SkiaSharp;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{ {
public class SelectionRemoveToolViewModel : VisualizationToolViewModel public class SelectionRemoveToolViewModel : VisualizationToolViewModel
{ {
private readonly ILayerEditorService _layerEditorService; public SelectionRemoveToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) : base(profileViewModel, profileEditorService)
public SelectionRemoveToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService) : base(profileViewModel,
profileEditorService)
{ {
_layerEditorService = layerEditorService;
using (var stream = new MemoryStream(Resources.aero_pen_min)) using (var stream = new MemoryStream(Resources.aero_pen_min))
{ {
Cursor = new Cursor(stream); Cursor = new Cursor(stream);
@ -51,19 +46,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
// Apply the selection to the selected layer layer // Apply the selection to the selected layer layer
if (ProfileEditorService.SelectedProfileElement is Layer layer) if (ProfileEditorService.SelectedProfileElement is Layer layer)
{ {
// If the layer has a shape, save it's size
var shapeSize = SKRect.Empty;
if (layer.LayerShape != null)
shapeSize = layer.LayerShape.GetUnscaledRectangle();
var remainingLeds = layer.Leds.Except(selectedLeds).ToList(); var remainingLeds = layer.Leds.Except(selectedLeds).ToList();
layer.ClearLeds(); layer.ClearLeds();
layer.AddLeds(remainingLeds); layer.AddLeds(remainingLeds);
// Restore the saved size
if (layer.LayerShape != null)
layer.LayerShape.SetFromUnscaledRectangle(shapeSize);
ProfileEditorService.UpdateSelectedProfileElement(); ProfileEditorService.UpdateSelectedProfileElement();
} }
} }

View File

@ -8,18 +8,13 @@ using Artemis.Core.Models.Surface;
using Artemis.UI.Extensions; using Artemis.UI.Extensions;
using Artemis.UI.Properties; using Artemis.UI.Properties;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using SkiaSharp;
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
{ {
public class SelectionToolViewModel : VisualizationToolViewModel public class SelectionToolViewModel : VisualizationToolViewModel
{ {
private readonly ILayerEditorService _layerEditorService; public SelectionToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService) : base(profileViewModel, profileEditorService)
public SelectionToolViewModel(ProfileViewModel profileViewModel, IProfileEditorService profileEditorService, ILayerEditorService layerEditorService)
: base(profileViewModel, profileEditorService)
{ {
_layerEditorService = layerEditorService;
using (var stream = new MemoryStream(Resources.aero_crosshair)) using (var stream = new MemoryStream(Resources.aero_crosshair))
{ {
Cursor = new Cursor(stream); Cursor = new Cursor(stream);
@ -51,11 +46,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
// Apply the selection to the selected layer layer // Apply the selection to the selected layer layer
if (ProfileEditorService.SelectedProfileElement is Layer layer) if (ProfileEditorService.SelectedProfileElement is Layer layer)
{ {
// If the layer has a shape, save it's size
var shapeSize = SKRect.Empty;
if (layer.LayerShape != null)
shapeSize = layer.LayerShape.GetUnscaledRectangle();
// If shift is held down, add to the selection instead of replacing it // If shift is held down, add to the selection instead of replacing it
if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift)) if (Keyboard.IsKeyDown(Key.LeftShift) || Keyboard.IsKeyDown(Key.RightShift))
layer.AddLeds(selectedLeds.Except(layer.Leds)); layer.AddLeds(selectedLeds.Except(layer.Leds));
@ -65,10 +55,6 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
layer.AddLeds(selectedLeds); layer.AddLeds(selectedLeds);
} }
// Restore the saved size
if (layer.LayerShape != null)
layer.LayerShape.SetFromUnscaledRectangle(shapeSize);
ProfileEditorService.UpdateSelectedProfileElement(); ProfileEditorService.UpdateSelectedProfileElement();
} }
// If no layer selected, apply it to a new layer in the selected folder // If no layer selected, apply it to a new layer in the selected folder

View File

@ -1,7 +1,6 @@
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerShapes;
using SkiaSharp; using SkiaSharp;
namespace Artemis.UI.Services.Interfaces namespace Artemis.UI.Services.Interfaces
@ -22,13 +21,6 @@ namespace Artemis.UI.Services.Interfaces
/// <returns></returns> /// <returns></returns>
Point GetLayerAnchorPosition(Layer layer); Point GetLayerAnchorPosition(Layer layer);
/// <summary>
/// Returns the layer shape's bounds, corrected for the current render scale.
/// </summary>
/// <param name="layerShape"></param>
/// <returns></returns>
Rect GetLayerShapeBounds(LayerShape layerShape);
/// <summary> /// <summary>
/// Creates a WPF transform group that contains all the transformations required to render the provided layer. /// Creates a WPF transform group that contains all the transformations required to render the provided layer.
/// Note: Run on UI thread. /// Note: Run on UI thread.
@ -47,14 +39,6 @@ namespace Artemis.UI.Services.Interfaces
/// <returns></returns> /// <returns></returns>
SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation); SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation);
/// <summary>
/// Sets the base properties of the given shape to match the provided unscaled rectangle. The rectangle is corrected
/// for the current render scale, anchor property and size property.
/// </summary>
/// <param name="layerShape"></param>
/// <param name="rect"></param>
void SetShapeBaseFromRectangle(LayerShape layerShape, Rect rect);
/// <summary> /// <summary>
/// Returns a new point scaled to the layer. /// Returns a new point scaled to the layer.
/// </summary> /// </summary>

View File

@ -1,9 +1,7 @@
using System; using System;
using System.Linq;
using System.Windows; using System.Windows;
using System.Windows.Media; using System.Windows.Media;
using Artemis.Core.Models.Profile; using Artemis.Core.Models.Profile;
using Artemis.Core.Models.Profile.LayerShapes;
using Artemis.Core.Services; using Artemis.Core.Services;
using Artemis.UI.Services.Interfaces; using Artemis.UI.Services.Interfaces;
using SkiaSharp; using SkiaSharp;
@ -33,28 +31,14 @@ namespace Artemis.UI.Services
); );
} }
/// <inheritdoc />
public Rect GetLayerShapeBounds(LayerShape layerShape)
{
// Adjust the render rectangle for the difference in render scale
var renderScale = _settingsService.GetSetting("Core.RenderScale", 1.0).Value;
return new Rect(
layerShape.Bounds.Left / renderScale * 1,
layerShape.Bounds.Top / renderScale * 1,
Math.Max(0, layerShape.Bounds.Width / renderScale * 1),
Math.Max(0, layerShape.Bounds.Height / renderScale * 1)
);
}
/// <inheritdoc /> /// <inheritdoc />
public Point GetLayerAnchorPosition(Layer layer) public Point GetLayerAnchorPosition(Layer layer)
{ {
var layerBounds = GetLayerBounds(layer); var layerBounds = GetLayerBounds(layer).ToSKRect();
var shapeBounds = GetLayerShapeBounds(layer.LayerShape).ToSKRect();
var positionProperty = layer.PositionProperty.CurrentValue; var positionProperty = layer.PositionProperty.CurrentValue;
// Start at the center of the shape // Start at the center of the shape
var position = new Point(shapeBounds.MidX, shapeBounds.MidY); var position = new Point(layerBounds.MidX, layerBounds.MidY);
// Apply translation // Apply translation
position.X += positionProperty.X * layerBounds.Width; position.X += positionProperty.X * layerBounds.Width;
@ -67,7 +51,6 @@ namespace Artemis.UI.Services
public TransformGroup GetLayerTransformGroup(Layer layer) public TransformGroup GetLayerTransformGroup(Layer layer)
{ {
var layerBounds = GetLayerBounds(layer).ToSKRect(); var layerBounds = GetLayerBounds(layer).ToSKRect();
var shapeBounds = GetLayerShapeBounds(layer.LayerShape).ToSKRect();
// Apply transformation like done by the core during layer rendering. // Apply transformation like done by the core during layer rendering.
// The order in which translations are applied are different because the UI renders the shape inside // The order in which translations are applied are different because the UI renders the shape inside
@ -77,8 +60,8 @@ namespace Artemis.UI.Services
var anchorProperty = layer.AnchorPointProperty.CurrentValue; var anchorProperty = layer.AnchorPointProperty.CurrentValue;
// Translation originates from the unscaled center of the shape and is tied to the anchor // Translation originates from the unscaled center of the shape and is tied to the anchor
var x = anchorPosition.X - shapeBounds.MidX - anchorProperty.X * layerBounds.Width; var x = anchorPosition.X - layerBounds.MidX - anchorProperty.X * layerBounds.Width;
var y = anchorPosition.Y - shapeBounds.MidY - anchorProperty.Y * layerBounds.Height; var y = anchorPosition.Y - layerBounds.MidY - anchorProperty.Y * layerBounds.Height;
var transformGroup = new TransformGroup(); var transformGroup = new TransformGroup();
transformGroup.Children.Add(new TranslateTransform(x, y)); transformGroup.Children.Add(new TranslateTransform(x, y));
@ -92,18 +75,17 @@ namespace Artemis.UI.Services
public SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation) public SKPath GetLayerPath(Layer layer, bool includeTranslation, bool includeScale, bool includeRotation)
{ {
var layerBounds = GetLayerBounds(layer).ToSKRect(); var layerBounds = GetLayerBounds(layer).ToSKRect();
var shapeBounds = GetLayerShapeBounds(layer.LayerShape).ToSKRect();
// Apply transformation like done by the core during layer rendering (same differences apply as in GetLayerTransformGroup) // Apply transformation like done by the core during layer rendering (same differences apply as in GetLayerTransformGroup)
var anchorPosition = GetLayerAnchorPosition(layer).ToSKPoint(); var anchorPosition = GetLayerAnchorPosition(layer).ToSKPoint();
var anchorProperty = layer.AnchorPointProperty.CurrentValue; var anchorProperty = layer.AnchorPointProperty.CurrentValue;
// Translation originates from the unscaled center of the shape and is tied to the anchor // Translation originates from the unscaled center of the shape and is tied to the anchor
var x = anchorPosition.X - shapeBounds.MidX - anchorProperty.X * layerBounds.Width; var x = anchorPosition.X - layerBounds.MidX - anchorProperty.X * layerBounds.Width;
var y = anchorPosition.Y - shapeBounds.MidY - anchorProperty.Y * layerBounds.Height; var y = anchorPosition.Y - layerBounds.MidY - anchorProperty.Y * layerBounds.Height;
var path = new SKPath(); var path = new SKPath();
path.AddRect(shapeBounds); path.AddRect(layerBounds);
if (includeTranslation) if (includeTranslation)
path.Transform(SKMatrix.MakeTranslation(x, y)); path.Transform(SKMatrix.MakeTranslation(x, y));
if (includeScale) if (includeScale)
@ -114,46 +96,6 @@ namespace Artemis.UI.Services
return path; return path;
} }
/// <inheritdoc />
public void SetShapeBaseFromRectangle(LayerShape layerShape, Rect rect)
{
if (!layerShape.Layer.Leds.Any())
{
layerShape.ScaledRectangle = SKRect.Empty;
return;
}
var layerBounds = GetLayerBounds(layerShape.Layer).ToSKRect();
var shapeBounds = GetLayerShapeBounds(layerShape).ToSKRect();
var rectangle = SKRect.Create(
(float) rect.Left - layerBounds.Left,
(float) rect.Top - layerBounds.Top,
(float) rect.Width,
(float) rect.Height
);
// Adjust the provided rect for the difference in render scale
var anchorPosition = GetLayerAnchorPosition(layerShape.Layer).ToSKPoint();
var anchorProperty = layerShape.Layer.AnchorPointProperty.CurrentValue;
var sizeProperty = layerShape.Layer.SizeProperty.CurrentValue;
// Translation originates from the unscaled center of the shape and is tied to the anchor
var x = anchorPosition.X - shapeBounds.MidX - anchorProperty.X * layerBounds.Width;
var y = anchorPosition.Y - shapeBounds.MidY - anchorProperty.Y * layerBounds.Height;
rectangle.Offset(x * -1, y * -1);
// TODO: Determine the new position of the anchor and scale the rectangle to the current scale
layerShape.ScaledRectangle = SKRect.Create(
rectangle.Left / layerBounds.Width,
rectangle.Top / layerBounds.Height,
rectangle.Width / layerBounds.Width,
rectangle.Height / layerBounds.Height
);
layerShape.CalculateRenderProperties();
}
/// <inheritdoc /> /// <inheritdoc />
public SKPoint GetScaledPoint(Layer layer, SKPoint point, bool absolute) public SKPoint GetScaledPoint(Layer layer, SKPoint point, bool absolute)
{ {