mirror of
https://github.com/Artemis-RGB/Artemis
synced 2025-12-13 05:48:35 +00:00
Implemented ellipse shape application
This commit is contained in:
parent
94df1544c5
commit
8dc15f6894
@ -39,6 +39,8 @@ namespace Artemis.Core.Models.Profile
|
|||||||
Name = layerEntity.Name;
|
Name = layerEntity.Name;
|
||||||
Order = layerEntity.Order;
|
Order = layerEntity.Order;
|
||||||
|
|
||||||
|
_leds = new List<ArtemisLed>();
|
||||||
|
|
||||||
switch (layerEntity.ShapeEntity?.Type)
|
switch (layerEntity.ShapeEntity?.Type)
|
||||||
{
|
{
|
||||||
case ShapeEntityType.Ellipse:
|
case ShapeEntityType.Ellipse:
|
||||||
@ -59,8 +61,6 @@ namespace Artemis.Core.Models.Profile
|
|||||||
default:
|
default:
|
||||||
throw new ArgumentOutOfRangeException();
|
throw new ArgumentOutOfRangeException();
|
||||||
}
|
}
|
||||||
|
|
||||||
_leds = new List<ArtemisLed>();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal LayerEntity LayerEntity { get; set; }
|
internal LayerEntity LayerEntity { get; set; }
|
||||||
@ -243,7 +243,7 @@ namespace Artemis.Core.Models.Profile
|
|||||||
path.AddRect(artemisLed.AbsoluteRenderRectangle);
|
path.AddRect(artemisLed.AbsoluteRenderRectangle);
|
||||||
|
|
||||||
Path = path;
|
Path = path;
|
||||||
LayerShape.CalculateRenderProperties();
|
LayerShape?.CalculateRenderProperties();
|
||||||
OnRenderPropertiesUpdated();
|
OnRenderPropertiesUpdated();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
using System;
|
using System;
|
||||||
|
using System.Linq;
|
||||||
using Artemis.Storage.Entities.Profile;
|
using Artemis.Storage.Entities.Profile;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
|
||||||
@ -6,6 +7,9 @@ namespace Artemis.Core.Models.Profile.LayerShapes
|
|||||||
{
|
{
|
||||||
public abstract class LayerShape
|
public abstract class LayerShape
|
||||||
{
|
{
|
||||||
|
private SKPoint _position;
|
||||||
|
private SKSize _size;
|
||||||
|
|
||||||
protected LayerShape(Layer layer)
|
protected LayerShape(Layer layer)
|
||||||
{
|
{
|
||||||
Layer = layer;
|
Layer = layer;
|
||||||
@ -33,12 +37,28 @@ namespace Artemis.Core.Models.Profile.LayerShapes
|
|||||||
/// <summary>
|
/// <summary>
|
||||||
/// The position of the shape
|
/// The position of the shape
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKPoint Position { get; set; }
|
public SKPoint Position
|
||||||
|
{
|
||||||
|
get => _position;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_position = value;
|
||||||
|
Layer.CalculateRenderProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// The size of the shape
|
/// The size of the shape
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public SKSize Size { get; set; }
|
public SKSize Size
|
||||||
|
{
|
||||||
|
get => _size;
|
||||||
|
set
|
||||||
|
{
|
||||||
|
_size = value;
|
||||||
|
Layer.CalculateRenderProperties();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// A render rectangle relative to the layer
|
/// A render rectangle relative to the layer
|
||||||
@ -56,11 +76,48 @@ namespace Artemis.Core.Models.Profile.LayerShapes
|
|||||||
{
|
{
|
||||||
Layer.LayerEntity.ShapeEntity = new ShapeEntity
|
Layer.LayerEntity.ShapeEntity = new ShapeEntity
|
||||||
{
|
{
|
||||||
Anchor = new ShapePointEntity { X = Anchor.X, Y = Anchor.Y },
|
Anchor = new ShapePointEntity {X = Anchor.X, Y = Anchor.Y},
|
||||||
Position = new ShapePointEntity { X = Position.X, Y = Position.Y },
|
Position = new ShapePointEntity {X = Position.X, Y = Position.Y},
|
||||||
Width = Size.Width,
|
Width = Size.Width,
|
||||||
Height = Size.Height
|
Height = Size.Height
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// <summary>
|
||||||
|
/// 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())
|
||||||
|
{
|
||||||
|
Position = SKPoint.Empty;
|
||||||
|
Size = SKSize.Empty;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var x = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.X);
|
||||||
|
var y = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.Y);
|
||||||
|
var width = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.X + l.RgbLed.AbsoluteLedRectangle.Size.Width) - x;
|
||||||
|
var height = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y;
|
||||||
|
|
||||||
|
Position = new SKPoint((float) (100f / width * (rect.Left - x)) / 100f, (float) (100f / height * (rect.Top - y)) / 100f);
|
||||||
|
Size = new SKSize((float) (100f / width * rect.Width) / 100f, (float) (100f / height * rect.Height) / 100f);
|
||||||
|
}
|
||||||
|
|
||||||
|
public SKRect GetUnscaledRectangle()
|
||||||
|
{
|
||||||
|
var x = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.X);
|
||||||
|
var y = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.Y);
|
||||||
|
var width = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.X + l.RgbLed.AbsoluteLedRectangle.Size.Width) - x;
|
||||||
|
var height = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y;
|
||||||
|
|
||||||
|
return SKRect.Create(
|
||||||
|
(float) (x + width * Position.X),
|
||||||
|
(float) (y + height * Position.Y),
|
||||||
|
(float) (width * Size.Width),
|
||||||
|
(float) (height * Size.Height)
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -61,9 +61,14 @@
|
|||||||
<Name>Artemis.Core</Name>
|
<Name>Artemis.Core</Name>
|
||||||
</ProjectReference>
|
</ProjectReference>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
|
<ItemGroup />
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<Folder Include="x64\" />
|
<Content Include="x64\wooting-rgb-sdk64.dll">
|
||||||
<Folder Include="x86\" />
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
|
<Content Include="x86\wooting-rgb-sdk.dll">
|
||||||
|
<CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
|
||||||
|
</Content>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
|
||||||
<PropertyGroup>
|
<PropertyGroup>
|
||||||
|
|||||||
@ -19,11 +19,10 @@ namespace Artemis.Plugins.Devices.Wooting
|
|||||||
|
|
||||||
public override void EnablePlugin()
|
public override void EnablePlugin()
|
||||||
{
|
{
|
||||||
// Disabled for now because the DLLs aren't on the repo
|
PathHelper.ResolvingAbsolutePath += (sender, args) => ResolveAbsolutePath(typeof(WootingRGBDevice<>), sender, args);
|
||||||
// PathHelper.ResolvingAbsolutePath += (sender, args) => ResolveAbsolutePath(typeof(WootingRGBDevice<>), sender, args);
|
RGB.NET.Devices.Wooting.WootingDeviceProvider.PossibleX64NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x64", "wooting-rgb-sdk64.dll"));
|
||||||
// RGB.NET.Devices.Wooting.WootingDeviceProvider.PossibleX64NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x64", "wooting-rgb-sdk64.dll"));
|
RGB.NET.Devices.Wooting.WootingDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "wooting-rgb-sdk.dll"));
|
||||||
// RGB.NET.Devices.Wooting.WootingDeviceProvider.PossibleX86NativePaths.Add(Path.Combine(PluginInfo.Directory.FullName, "x86", "wooting-rgb-sdk.dll"));
|
_rgbService.AddDeviceProvider(RgbDeviceProvider);
|
||||||
// _rgbService.AddDeviceProvider(RgbDeviceProvider);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override void DisablePlugin()
|
public override void DisablePlugin()
|
||||||
|
|||||||
BIN
src/Artemis.Plugins.Devices.Wooting/x64/wooting-rgb-sdk64.dll
Normal file
BIN
src/Artemis.Plugins.Devices.Wooting/x64/wooting-rgb-sdk64.dll
Normal file
Binary file not shown.
BIN
src/Artemis.Plugins.Devices.Wooting/x86/wooting-rgb-sdk.dll
Normal file
BIN
src/Artemis.Plugins.Devices.Wooting/x86/wooting-rgb-sdk.dll
Normal file
Binary file not shown.
@ -10,23 +10,23 @@
|
|||||||
<!-- The part of the layer's shape that falls outside 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.25" />
|
<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>
|
</Path>
|
||||||
|
|
||||||
<!-- The part of the layer's shape that is inside the layer -->
|
<!-- The part of the layer's shape that is inside the layer -->
|
||||||
<Path Data="{Binding ShapeGeometry, Mode=OneWay}" >
|
<Path Data="{Binding ShapeGeometry, Mode=OneWay}" >
|
||||||
<Path.Fill>
|
<Path.Fill>
|
||||||
<SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.25" />
|
<SolidColorBrush Color="{StaticResource Accent700}" Opacity="0.35" />
|
||||||
</Path.Fill>
|
</Path.Fill>
|
||||||
<Path.Stroke>
|
<Path.Stroke>
|
||||||
<SolidColorBrush Color="{StaticResource Accent700}" />
|
<SolidColorBrush Color="{StaticResource Accent700}" />
|
||||||
</Path.Stroke>
|
</Path.Stroke>
|
||||||
<Path.OpacityMask>
|
<Path.OpacityMask>
|
||||||
<VisualBrush >
|
<VisualBrush Viewport="{Binding ViewportRectangle}" ViewportUnits="Absolute">
|
||||||
<VisualBrush.Visual>
|
<VisualBrush.Visual>
|
||||||
<Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" Fill="Black" />
|
<Path Data="{Binding LayerGeometry, Mode=OneWay}" ClipToBounds="False" Fill="Black" />
|
||||||
</VisualBrush.Visual>
|
</VisualBrush.Visual>
|
||||||
|
|||||||
@ -7,6 +7,7 @@ using Artemis.Core.Models.Profile.LayerShapes;
|
|||||||
using Artemis.Core.Models.Surface;
|
using Artemis.Core.Models.Surface;
|
||||||
using Artemis.UI.Extensions;
|
using Artemis.UI.Extensions;
|
||||||
using RGB.NET.Core;
|
using RGB.NET.Core;
|
||||||
|
using SkiaSharp.Views.WPF;
|
||||||
using Rectangle = Artemis.Core.Models.Profile.LayerShapes.Rectangle;
|
using Rectangle = Artemis.Core.Models.Profile.LayerShapes.Rectangle;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
||||||
@ -85,17 +86,8 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
var x = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.X);
|
var skRect = Layer.LayerShape.GetUnscaledRectangle();
|
||||||
var y = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.Y);
|
var rect = new Rect(skRect.Left, skRect.Top, skRect.Width, skRect.Height);
|
||||||
var width = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.X + l.RgbLed.AbsoluteLedRectangle.Size.Width) - x;
|
|
||||||
var height = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y;
|
|
||||||
|
|
||||||
var rect = new Rect(
|
|
||||||
x + width * Layer.LayerShape.Position.X,
|
|
||||||
y + height * Layer.LayerShape.Position.Y,
|
|
||||||
width * Layer.LayerShape.Size.Width,
|
|
||||||
height * Layer.LayerShape.Size.Height
|
|
||||||
);
|
|
||||||
var shapeGeometry = Geometry.Empty;
|
var shapeGeometry = Geometry.Empty;
|
||||||
switch (Layer.LayerShape)
|
switch (Layer.LayerShape)
|
||||||
{
|
{
|
||||||
@ -121,17 +113,20 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
|
|
||||||
private void CreateViewportRectangle()
|
private void CreateViewportRectangle()
|
||||||
{
|
{
|
||||||
if (!Layer.Leds.Any())
|
if (!Layer.Leds.Any() || Layer.LayerShape == null)
|
||||||
{
|
{
|
||||||
ViewportRectangle = Rect.Empty;
|
ViewportRectangle = Rect.Empty;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
var x = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.X);
|
var x = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.X);
|
||||||
var y = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.Y);
|
var y = Layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.Y);
|
||||||
var width = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.X + l.RgbLed.AbsoluteLedRectangle.Size.Width) - x;
|
var width = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.X + l.RgbLed.AbsoluteLedRectangle.Size.Width) - x;
|
||||||
var height = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y;
|
var height = Layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y;
|
||||||
ViewportRectangle = new Rect(x - x * Layer.LayerShape.Position.X, y - y * Layer.LayerShape.Position.Y, width, height);
|
|
||||||
|
var rect = new Rect(x, y, width, height);
|
||||||
|
ViewportRectangle = rect;
|
||||||
}
|
}
|
||||||
|
|
||||||
private Geometry CreateRectangleGeometry(ArtemisLed led)
|
private Geometry CreateRectangleGeometry(ArtemisLed led)
|
||||||
|
|||||||
@ -183,7 +183,10 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization
|
|||||||
lock (CanvasViewModels)
|
lock (CanvasViewModels)
|
||||||
{
|
{
|
||||||
foreach (var device in Devices.OrderBy(d => d.ZIndex).ToList())
|
foreach (var device in Devices.OrderBy(d => d.ZIndex).ToList())
|
||||||
CanvasViewModels.Move(CanvasViewModels.IndexOf(device), device.ZIndex - 1);
|
{
|
||||||
|
var newIndex = Math.Max(device.ZIndex - 1, CanvasViewModels.Count - 1);
|
||||||
|
CanvasViewModels.Move(CanvasViewModels.IndexOf(device), newIndex);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@ -7,6 +7,7 @@ using Artemis.Core.Models.Profile.LayerShapes;
|
|||||||
using Artemis.UI.Properties;
|
using Artemis.UI.Properties;
|
||||||
using Artemis.UI.Services.Interfaces;
|
using Artemis.UI.Services.Interfaces;
|
||||||
using SkiaSharp;
|
using SkiaSharp;
|
||||||
|
using SkiaSharp.Views.WPF;
|
||||||
|
|
||||||
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
||||||
{
|
{
|
||||||
@ -44,8 +45,9 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
|||||||
|
|
||||||
if (ProfileEditorService.SelectedProfileElement is Layer layer)
|
if (ProfileEditorService.SelectedProfileElement is Layer layer)
|
||||||
{
|
{
|
||||||
GetShapePosition(out var point, out var size);
|
if (!(layer.LayerShape is Ellipse))
|
||||||
layer.LayerShape = new Ellipse(layer) {Size = size, Position = point};
|
layer.LayerShape = new Ellipse(layer);
|
||||||
|
layer.LayerShape.SetFromUnscaledRectangle(DragRectangle.ToSKRect());
|
||||||
ProfileEditorService.UpdateSelectedProfileElement();
|
ProfileEditorService.UpdateSelectedProfileElement();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -65,25 +67,5 @@ namespace Artemis.UI.Screens.Module.ProfileEditor.Visualization.Tools
|
|||||||
if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
|
if (e.Key == Key.LeftShift || e.Key == Key.RightShift)
|
||||||
_shiftDown = true;
|
_shiftDown = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private void GetShapePosition(out SKPoint point, out SKSize size)
|
|
||||||
{
|
|
||||||
var layer = (Layer) ProfileEditorService.SelectedProfileElement;
|
|
||||||
var x = layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.X);
|
|
||||||
var y = layer.Leds.Min(l => l.RgbLed.AbsoluteLedRectangle.Location.Y);
|
|
||||||
var width = layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.X + l.RgbLed.AbsoluteLedRectangle.Size.Width) - x;
|
|
||||||
var height = layer.Leds.Max(l => l.RgbLed.AbsoluteLedRectangle.Location.Y + l.RgbLed.AbsoluteLedRectangle.Size.Height) - y;
|
|
||||||
|
|
||||||
var widthScale = width / 100f;
|
|
||||||
var heightScale = height / 100f;
|
|
||||||
var rect = new Rect(
|
|
||||||
x - width / DragRectangle.X,
|
|
||||||
y - height / DragRectangle.Y,
|
|
||||||
width / DragRectangle.Width,
|
|
||||||
height / DragRectangle.Height
|
|
||||||
);
|
|
||||||
point = new SKPoint(0.5f,0.5f);
|
|
||||||
size = new SKSize((float) (DragRectangle.Width * widthScale), (float) (DragRectangle.Height * heightScale));
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -7,6 +7,7 @@ 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
|
||||||
{
|
{
|
||||||
@ -46,8 +47,16 @@ 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();
|
||||||
layer.ClearLeds();
|
layer.ClearLeds();
|
||||||
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
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user