Implemented normal text element.

Added `require` to load external script.
This commit is contained in:
Creeper Lv
2026-01-12 02:37:22 +11:00
parent 1bcaff76b2
commit 641a4581d2
15 changed files with 248 additions and 14 deletions

View File

@@ -19,13 +19,13 @@
<PackageVersion Include="Devolutions.AvaloniaTheme.MacOS" Version="2025.12.4" />--> <PackageVersion Include="Devolutions.AvaloniaTheme.MacOS" Version="2025.12.4" />-->
<PackageVersion Include="AvaloniaEdit.TextMate" Version="11.3.0" /> <PackageVersion Include="AvaloniaEdit.TextMate" Version="11.3.0" />
<PackageVersion Include="Deadpikle.AvaloniaProgressRing" Version="0.10.11-preview20251127001" /> <PackageVersion Include="Deadpikle.AvaloniaProgressRing" Version="0.10.11-preview20251127001" />
<PackageVersion Include="DialogHost.Avalonia" Version="0.10.3" /> <PackageVersion Include="DialogHost.Avalonia" Version="0.10.4" />
<PackageVersion Include="Jint" Version="4.4.2" /> <PackageVersion Include="Jint" Version="4.4.2" />
<PackageVersion Include="Microsoft.Maui.Graphics" Version="10.0.11" /> <PackageVersion Include="Microsoft.Maui.Graphics" Version="10.0.11" />
<PackageVersion Include="Microsoft.Maui.Graphics.Skia" Version="10.0.11" /> <PackageVersion Include="Microsoft.Maui.Graphics.Skia" Version="10.0.11" />
<PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" /> <PackageVersion Include="Microsoft.VisualStudio.Azure.Containers.Tools.Targets" Version="1.23.0" />
<PackageVersion Include="Newtonsoft.Json" Version="13.0.4" /> <PackageVersion Include="Newtonsoft.Json" Version="13.0.4" />
<PackageVersion Include="PanAndZoom" Version="11.3.6" /> <PackageVersion Include="PanAndZoom" Version="11.3.9" />
<PackageVersion Include="SkiaSharp" Version="3.116.1" /> <PackageVersion Include="SkiaSharp" Version="3.116.1" />
<PackageVersion Include="SkiaSharp.NativeAssets.WebAssembly" Version="3.116.1" /> <PackageVersion Include="SkiaSharp.NativeAssets.WebAssembly" Version="3.116.1" />
<PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.15" /> <PackageVersion Include="Xamarin.AndroidX.Core.SplashScreen" Version="1.0.1.15" />

View File

@@ -5,7 +5,7 @@ using SkiaSharp;
namespace Progrart.Core.Graphics namespace Progrart.Core.Graphics
{ {
public class Circle : BaseElement public class Circle : BaseElement
{ {
float StrokeWidth; float StrokeWidth;

View File

@@ -0,0 +1,105 @@
using Jint;
using Jint.Native;
using Progrart.Core.JSExecution;
using SkiaSharp;
namespace Progrart.Core.Graphics
{
public class Text : BaseElement
{
float StrokeWidth;
SKPoint Position;
float Size;
SKColorF Color;
string str = "";
bool IsStroke;
SKShader? shader = null;
string? fontFamily = null;
public override void SetupProperties(Engine engine)
{
base.SetupProperties(engine);
if (__object != null)
{
{
JsObject point = new JsObject(engine);
point.Set("x", 0);
point.Set("y", 0);
__object.Set("Position", point);
}
__object.Set("StrokeWidth", 1);
__object.Set("Size", 1);
__object.Set("Text", "");
__object.Set("IsStroke", true);
__object.Set("Color", ProgrartFunctions.color(engine, 1, 1, 1, 1));
}
}
public override void LoadProperties()
{
if (__object is not null)
{
StrokeWidth = (float)__object.Get("StrokeWidth").AsNumber();
str = __object.Get("Text").AsString();
Size = (float)__object.Get("Size").AsNumber();
IsStroke = (bool)__object.Get("IsStroke").AsBoolean();
{
if (__object.Get("Position") is JsObject Start)
{
this.Position = ProgrartConversion.ObtainSKPointFromJsObject(Start);
}
}
{
if (__object.Get("Color") is JsObject Color)
{
this.Color = ProgrartConversion.ObtainSKColorFFromJsObject(Color);
}
}
if (__object.Get("Shader") is JsObject shaderObj)
shader = ProgrartConversion.ObtainFromJsObject(shaderObj);
if (__object.Get("Font") is JsString fontObj)
fontFamily = fontObj.AsString();
}
}
public override void Render(RenderContext context)
{
base.Render(context);
LoadProperties();
SKPoint pos = context.TranslatePoint(Position);
float Size = context.TranslateSize(this.Size);
if (fontFamily is not null)
{
var face = context.GetFont(fontFamily);
if (face != null)
{
context.canvas.DrawText(str,
pos.X, pos.Y, SKTextAlign.Center, new SKFont(face, Size) { },
new SKPaint()
{
ColorF = Color,
StrokeWidth = context.TranslateSize(StrokeWidth),
Shader = shader,
IsStroke = IsStroke,
IsAntialias = true
}
);
return;
}
}
context.canvas.DrawText(str,
pos.X, pos.Y, SKTextAlign.Center, new SKFont(SKTypeface.Default, Size) { },
new SKPaint()
{
ColorF = Color,
StrokeWidth = context.TranslateSize(StrokeWidth),
Shader = shader,
IsStroke = IsStroke,
IsAntialias = true
}
);
}
}
}

View File

@@ -25,7 +25,7 @@ namespace Progrart.Core.Graphics
float rotate; float rotate;
void Transform(RenderContext context) void Transform(RenderContext context)
{ {
Trace.WriteLine($"Visual Root: Rotation:{rotate}"); //Trace.WriteLine($"Visual Root: Rotation:{rotate}");
context.canvas.Translate(tx, ty); context.canvas.Translate(tx, ty);
context.canvas.RotateDegrees(rotate, context.DrawingCore.Width / 2, context.DrawingCore.Height / 2); context.canvas.RotateDegrees(rotate, context.DrawingCore.Width / 2, context.DrawingCore.Height / 2);
if (scale != 1) if (scale != 1)

View File

@@ -1,5 +1,6 @@
using Jint; using Jint;
using Jint.Native; using Jint.Native;
using Jint.Runtime.Modules;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@@ -43,6 +44,7 @@ namespace Progrart.Core.JSExecution
JsObject _obj = new JsObject(Engine); JsObject _obj = new JsObject(Engine);
Engine.SetValue("math", _obj); Engine.SetValue("math", _obj);
Random r = new Random(); Random r = new Random();
_obj.Set("random", JsObject.FromObject(Engine, new Func<double>(() => _obj.Set("random", JsObject.FromObject(Engine, new Func<double>(() =>
{ {
return r.NextDouble(); return r.NextDouble();

View File

@@ -29,6 +29,26 @@ namespace Progrart.Core.JSExecution
else else
Trace.WriteLine(v); Trace.WriteLine(v);
})); }));
engine.Engine.SetValue("require", (string str) =>
{
require(str, () =>
{
if (str.IndexOf(".") < 0)
{
require(str + ".progrart", () =>
{
require(str + ".js", () =>
{
throw new Exception("Module not found: " + str);
});
});
}
else
{
throw new Exception("Module not found: " + str);
}
});
});
engine.Engine.SetValue("visual_root", visual_root); engine.Engine.SetValue("visual_root", visual_root);
engine.Engine.SetValue("line", line); engine.Engine.SetValue("line", line);
engine.Engine.SetValue("rectangle", rectangle); engine.Engine.SetValue("rectangle", rectangle);
@@ -40,10 +60,26 @@ namespace Progrart.Core.JSExecution
engine.Engine.SetValue("circle", circle); engine.Engine.SetValue("circle", circle);
engine.Engine.SetValue("color4", color4); engine.Engine.SetValue("color4", color4);
engine.Engine.SetValue("color3", color3); engine.Engine.SetValue("color3", color3);
engine.Engine.SetValue("text", text);
engine.Engine.SetValue("color_hex", color_hex); engine.Engine.SetValue("color_hex", color_hex);
engine.Engine.SetValue("linear_gradient", linear_gradient); engine.Engine.SetValue("linear_gradient", linear_gradient);
engine.Engine.SetValue("radial_gradient", radial_gradient); engine.Engine.SetValue("radial_gradient", radial_gradient);
} }
private void require(string str, Action onNoFound)
{
var task = StorageProvider.TryOpenRead(str);
task.Wait();
var stream = task.GetAwaiter().GetResult();
if (stream is null)
{
onNoFound();
return;
}
using var sr = new StreamReader(stream);
engine.Engine.Execute(sr.ReadToEnd());
}
public JsObject color4(JsNumber r, JsNumber g, JsNumber b, JsNumber a) public JsObject color4(JsNumber r, JsNumber g, JsNumber b, JsNumber a)
{ {
return ProgrartFunctions.color(engine.Engine return ProgrartFunctions.color(engine.Engine
@@ -93,6 +129,7 @@ namespace Progrart.Core.JSExecution
public JsObject circle() => ProgrartFunctions.CreateElement<Circle>(this); public JsObject circle() => ProgrartFunctions.CreateElement<Circle>(this);
public JsObject oval() => ProgrartFunctions.CreateElement<Oval>(this); public JsObject oval() => ProgrartFunctions.CreateElement<Oval>(this);
public JsObject triangle() => ProgrartFunctions.CreateElement<Triangle>(this); public JsObject triangle() => ProgrartFunctions.CreateElement<Triangle>(this);
public JsObject text() => ProgrartFunctions.CreateElement<Text>(this);
public RenderContext RenderImage(int Scale, string script, ExecuteArguments arguments) public RenderContext RenderImage(int Scale, string script, ExecuteArguments arguments)
{ {

View File

@@ -4,7 +4,7 @@ using System.Diagnostics;
namespace Progrart.Core namespace Progrart.Core
{ {
public class PrimitiveDrawingCore : IDisposable public class PrimitiveDrawingCore : IDisposable
{ {
internal bool isDisposed = false; internal bool isDisposed = false;
SKSurface surface; SKSurface surface;
@@ -13,6 +13,26 @@ namespace Progrart.Core
public readonly int Height; public readonly int Height;
public SKCanvas canvas { get; } public SKCanvas canvas { get; }
internal IStorageProvider StorageProvider; internal IStorageProvider StorageProvider;
Dictionary<string, SKTypeface> Fonts = new Dictionary<string, SKTypeface>();
public SKTypeface? GetFont(string fontName)
{
if (Fonts.ContainsKey(fontName))
return Fonts[fontName];
else
{
var task=StorageProvider.TryOpenRead(fontName);
task.Wait();
var stream=task.Result;
if(stream != null)
{
SKTypeface typeface = SKTypeface.FromStream(stream);
Fonts[fontName] = typeface;
return typeface;
}
}
return null;
}
public PrimitiveDrawingCore(int W, int H, IStorageProvider storageProvider) public PrimitiveDrawingCore(int W, int H, IStorageProvider storageProvider)
{ {
Width = W; Width = W;

View File

@@ -14,6 +14,10 @@ namespace Progrart.Core
{ {
this.DrawingCore = core; this.DrawingCore = core;
} }
public SKTypeface? GetFont(string fontName)
{
return DrawingCore.GetFont(fontName);
}
public SKPoint TranslatePoint(float x, float y) public SKPoint TranslatePoint(float x, float y)
{ {
return new SKPoint(x * DrawingCore.Width, y * DrawingCore.Height); return new SKPoint(x * DrawingCore.Width, y * DrawingCore.Height);

16
Progrart.slnx Normal file
View File

@@ -0,0 +1,16 @@
<Solution>
<Folder Name="/Solution Items/">
<File Path="Directory.Packages.props" />
</Folder>
<Project Path="Progrart.Android/Progrart.Android.csproj">
<Deploy Solution="Debug|*" />
</Project>
<Project Path="Progrart.Browser/Progrart.Browser.csproj" />
<Project Path="Progrart.Cmd/Progrart.Cmd.csproj" />
<Project Path="Progrart.Core/Progrart.Core.csproj" />
<Project Path="Progrart.Desktop/Progrart.Desktop.csproj" />
<Project Path="Progrart.iOS/Progrart.iOS.csproj">
<Deploy Solution="Debug|*" />
</Project>
<Project Path="Progrart/Progrart.csproj" />
</Solution>

View File

@@ -4,8 +4,7 @@
xmlns:local="using:Progrart.Controls" xmlns:local="using:Progrart.Controls"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Progrart.Controls.ConfigEditor"> x:Class="Progrart.Controls.ConfigEditor" Margin="5">
<StackPanel> <StackPanel>
<TextBlock Name="NameBlock" FontSize="18" Text="{Binding #NameBox.Text}"/> <TextBlock Name="NameBlock" FontSize="18" Text="{Binding #NameBox.Text}"/>
<Grid> <Grid>
@@ -31,7 +30,7 @@
<TextBlock FontSize="13" VerticalAlignment="Center">Targets</TextBlock> <TextBlock FontSize="13" VerticalAlignment="Center">Targets</TextBlock>
<Button Name="AddButton" Grid.Column="1" Padding="16,2" VerticalAlignment="Center">+</Button> <Button Name="AddButton" Grid.Column="1" Padding="16,2" VerticalAlignment="Center">+</Button>
</Grid> </Grid>
<StackPanel Name="ConfigurationHolder"> <StackPanel Name="TargetHolder" Margin="5,0">
</StackPanel> </StackPanel>
</StackPanel> </StackPanel>
</UserControl> </UserControl>

View File

@@ -1,11 +1,16 @@
using Avalonia.Controls; using Avalonia.Controls;
using AvaloniaEdit.Editing;
namespace Progrart.Controls; namespace Progrart.Controls;
public partial class ConfigEditor : UserControl public partial class ConfigEditor : UserControl
{ {
public ConfigEditor() public ConfigEditor()
{ {
InitializeComponent(); InitializeComponent();
} AddButton.Click += (_, _) =>
{
TargetHolder.Children.Add(new TargetEditor());
};
}
} }

View File

@@ -5,7 +5,8 @@
xmlns:paz="using:Avalonia.Controls.PanAndZoom" xmlns:paz="using:Avalonia.Controls.PanAndZoom"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Progrart.Controls.ImageViewer"> x:Class="Progrart.Controls.ImageViewer">
<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto"> <!--<ScrollViewer VerticalScrollBarVisibility="Auto" HorizontalScrollBarVisibility="Auto">
</ScrollViewer>-->
<paz:ZoomBorder Name="ZoomBorder" Stretch="Uniform" ZoomSpeed="1.2" <paz:ZoomBorder Name="ZoomBorder" Stretch="Uniform" ZoomSpeed="1.2"
Background="Transparent" ClipToBounds="True" Focusable="True" Background="Transparent" ClipToBounds="True" Focusable="True"
EnableGestures="True" EnablePan="True" EnableZoom="True" EnableGestures="True" EnablePan="True" EnableZoom="True"
@@ -14,5 +15,4 @@
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"> VerticalAlignment="Stretch" HorizontalAlignment="Stretch">
<Image Name="ImagePresenter"></Image> <Image Name="ImagePresenter"></Image>
</paz:ZoomBorder> </paz:ZoomBorder>
</ScrollViewer>
</UserControl> </UserControl>

View File

@@ -0,0 +1,27 @@
<UserControl xmlns="https://github.com/avaloniaui"
xmlns:controls="using:Progrart.Controls"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
x:Class="Progrart.TargetEditor">
<Grid>
<Grid.ColumnDefinitions>
<ColumnDefinition/>
<ColumnDefinition Width="Auto"/>
</Grid.ColumnDefinitions>
<StackPanel>
<Grid>
<Grid.RowDefinitions>
<RowDefinition/>
<RowDefinition/>
</Grid.RowDefinitions>
<Grid.ColumnDefinitions>
<ColumnDefinition Width="Auto"/>
<ColumnDefinition/>
</Grid.ColumnDefinitions>
</Grid>
<controls:ExecuteArgumentsEditor/>
</StackPanel>
</Grid>
</UserControl>

View File

@@ -0,0 +1,13 @@
using Avalonia;
using Avalonia.Controls;
using Avalonia.Markup.Xaml;
namespace Progrart;
public partial class TargetEditor : UserControl
{
public TargetEditor()
{
InitializeComponent();
}
}

View File

@@ -36,4 +36,10 @@
<ItemGroup> <ItemGroup>
<ProjectReference Include="..\Progrart.Core\Progrart.Core.csproj" /> <ProjectReference Include="..\Progrart.Core\Progrart.Core.csproj" />
</ItemGroup> </ItemGroup>
<ItemGroup>
<Compile Update="Controls\TargetEditor.axaml.cs">
<DependentUpon>TargetEditor.axaml</DependentUpon>
</Compile>
</ItemGroup>
</Project> </Project>