From 89e9886b9742c20186ad803a3e5a87441939cd3a Mon Sep 17 00:00:00 2001 From: "Adam D. Ruppe" Date: Mon, 12 Mar 2018 17:38:01 -0400 Subject: [PATCH] scripting nvg --- color.d | 5 +++++ jsvar.d | 52 ++++++++++++++++++++++++++++++++++++++++++------- minigui.d | 2 +- nanovega.d | 26 +++++++++++++++++++++++++ simpledisplay.d | 4 ++++ 5 files changed, 81 insertions(+), 8 deletions(-) diff --git a/color.d b/color.d index a607d6a..d74c752 100644 --- a/color.d +++ b/color.d @@ -119,6 +119,11 @@ private { /// Represents an RGBA color struct Color { + + @system static Color fromJsVar(T)(T v) { // it is a template so i don't have to actually import arsd.jsvar... + return Color.fromString(v.get!string); + } + @safe: /++ The color components are available as a static array, individual bytes, and a uint inside this union. diff --git a/jsvar.d b/jsvar.d index 5dcaf05..8a7a044 100644 --- a/jsvar.d +++ b/jsvar.d @@ -802,6 +802,8 @@ struct var { public T get(T)() if(!is(T == void)) { static if(is(T == var)) { return this; + } else static if(__traits(compiles, T.fromJsVar(var.init))) { + return T.fromJsVar(this); } else static if(__traits(compiles, T(this))) { return T(this); } else static if(__traits(compiles, new T(this))) { @@ -1660,13 +1662,15 @@ class WrappedNativeObject : PrototypeObject { template helper(alias T) { alias helper = T; } -/// Wraps a class. If you are manually managing the memory, remember the jsvar may keep a reference to the object; don't free it! -/// -/// To use this: var a = wrapNativeObject(your_d_object); OR var a = your_d_object; -/// -/// By default, it will wrap all methods and members with a public or greater protection level. The second template parameter can filter things differently. FIXME implement this -/// -/// That may be done automatically with opAssign in the future. +/++ + Wraps a class. If you are manually managing the memory, remember the jsvar may keep a reference to the object; don't free it! + + To use this: `var a = wrapNativeObject(your_d_object);` OR `var a = your_d_object`; + + By default, it will wrap all methods and members with a public or greater protection level. The second template parameter can filter things differently. FIXME implement this + + That may be done automatically with `opAssign` in the future. ++/ WrappedNativeObject wrapNativeObject(Class)(Class obj) if(is(Class == class)) { import std.meta; return new class WrappedNativeObject { @@ -1693,6 +1697,8 @@ WrappedNativeObject wrapNativeObject(Class)(Class obj) if(is(Class == class)) { _properties[memberName] = new PropertyPrototype( () => var(__traits(getMember, obj, memberName)), (var v) { + // read-only property hack + static if(__traits(compiles, __traits(getMember, obj, memberName) = v.get!(type))) __traits(getMember, obj, memberName) = v.get!(type); }); } @@ -1701,6 +1707,38 @@ WrappedNativeObject wrapNativeObject(Class)(Class obj) if(is(Class == class)) { }; } +/** + Wraps an opaque struct pointer in a module with ufcs functions +*/ +WrappedNativeObject wrapUfcs(alias Module, Type)(Type obj) { + import std.meta; + return new class WrappedNativeObject { + override Object getObject() { + return null; // not actually an object! but close to + } + + this() { + wrappedType = typeid(Type); + // wrap the other methods + // and wrap members as scriptable properties + + foreach(memberName; __traits(allMembers, Module)) static if(is(typeof(__traits(getMember, Module, memberName)) type)) { + static if(is(type == function)) { + foreach(idx, overload; AliasSeq!(__traits(getOverloads, Module, memberName))) static if(.isScriptable!(__traits(getAttributes, overload))()) { + auto helper = &__traits(getOverloads, Module, memberName)[idx]; + static if(Parameters!helper.length >= 1 && is(Parameters!helper[0] == Type)) { + // this staticMap is a bit of a hack so it can handle `in float`... liable to break with others, i'm sure + _properties[memberName] = (staticMap!(Unqual, Parameters!helper[1 .. $]) args) { + return __traits(getOverloads, Module, memberName)[idx](obj, args); + }; + } + } + } + } + } + }; +} + bool isScriptable(attributes...)() { foreach(attribute; attributes) { static if(is(typeof(attribute) == string)) { diff --git a/minigui.d b/minigui.d index 2729f44..0b04335 100644 --- a/minigui.d +++ b/minigui.d @@ -112,7 +112,7 @@ version(Windows) // this is a hack to call the original window procedure on native win32 widgets if our event listener thing prevents default. private bool lastDefaultPrevented; -/// Methods marked with this are available from scripts +/// Methods marked with this are available from scripts if added to the [arsd.script] engine. alias scriptable = arsd_jsvar_compatible; version(Windows) { diff --git a/nanovega.d b/nanovega.d index 23fb500..0526077 100644 --- a/nanovega.d +++ b/nanovega.d @@ -558,6 +558,11 @@ version(nanovg_disable_fontconfig) { //version = nanovg_bench_flatten; +/++ + Annotation to indicate it is compatible with [arsd.script] ++/ +package(arsd) enum scriptable = "arsd_jsvar_compatible"; + public: alias NVG_PI = PI; @@ -2975,6 +2980,7 @@ public void shapeAntiAlias (NVGContext ctx, bool enabled) { /// Sets the stroke width of the stroke style. /// Group: render_styles +@scriptable public void strokeWidth (NVGContext ctx, float width) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); state.strokeWidth = width; @@ -3036,9 +3042,14 @@ public void strokePaint() (NVGContext ctx, in auto ref NVGPaint paint) nothrow @ state.stroke.xform.mul(state.xform); } +// this is a hack to work around https://issues.dlang.org/show_bug.cgi?id=16206 +// for scriptable reflection. it just needs to be declared first among the overloads +private void fillColor (NVGContext ctx) nothrow @trusted @nogc { } + static if (NanoVegaHasArsdColor) { /// Sets current fill style to a solid color. /// Group: render_styles +@scriptable public void fillColor (NVGContext ctx, Color color) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); nvg__setPaintColor(state.fill, NVGColor(color)); @@ -3093,6 +3104,7 @@ public void currTransform() (NVGContext ctx, in auto ref NVGMatrix m) nothrow @t /// Resets current transform to an identity matrix. /// Group: render_transformations +@scriptable public void resetTransform (NVGContext ctx) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); state.xform.identity; @@ -3108,6 +3120,7 @@ public void transform() (NVGContext ctx, in auto ref NVGMatrix mt) nothrow @trus /// Translates current coordinate system. /// Group: render_transformations +@scriptable public void translate (NVGContext ctx, in float x, in float y) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); //NVGMatrix t = void; @@ -3118,6 +3131,7 @@ public void translate (NVGContext ctx, in float x, in float y) nothrow @trusted /// Rotates current coordinate system. Angle is specified in radians. /// Group: render_transformations +@scriptable public void rotate (NVGContext ctx, in float angle) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); //NVGMatrix t = void; @@ -3128,6 +3142,7 @@ public void rotate (NVGContext ctx, in float angle) nothrow @trusted @nogc { /// Skews the current coordinate system along X axis. Angle is specified in radians. /// Group: render_transformations +@scriptable public void skewX (NVGContext ctx, in float angle) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); //NVGMatrix t = void; @@ -3138,6 +3153,7 @@ public void skewX (NVGContext ctx, in float angle) nothrow @trusted @nogc { /// Skews the current coordinate system along Y axis. Angle is specified in radians. /// Group: render_transformations +@scriptable public void skewY (NVGContext ctx, in float angle) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); //NVGMatrix t = void; @@ -3148,6 +3164,7 @@ public void skewY (NVGContext ctx, in float angle) nothrow @trusted @nogc { /// Scales the current coordinate system. /// Group: render_transformations +@scriptable public void scale (NVGContext ctx, in float x, in float y) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); //NVGMatrix t = void; @@ -4967,6 +4984,7 @@ void nvg__expandFill (NVGContext ctx, float w, int lineJoin, float miterLimit) n /// Clears the current path and sub-paths. /// Group: paths +@scriptable public void beginPath (NVGContext ctx) nothrow @trusted @nogc { ctx.ncommands = 0; ctx.pathPickRegistered &= NVGPickKind.All; // reset "registered" flags @@ -4977,6 +4995,7 @@ public alias newPath = beginPath; /// Ditto. /// Starts new sub-path with specified point as first point. /// Group: paths +@scriptable public void moveTo (NVGContext ctx, in float x, in float y) nothrow @trusted @nogc { nvg__appendCommands(ctx, Command.MoveTo, x, y); } @@ -4993,6 +5012,7 @@ public void moveTo (NVGContext ctx, in float[] args) nothrow @trusted @nogc { /// Adds line segment from the last point in the path to the specified point. /// Group: paths +@scriptable public void lineTo (NVGContext ctx, in float x, in float y) nothrow @trusted @nogc { nvg__appendCommands(ctx, Command.LineTo, x, y); } @@ -5144,6 +5164,7 @@ public void arcTo (NVGContext ctx, in float[] args) nothrow @trusted @nogc { /// Closes current sub-path with a line segment. /// Group: paths +@scriptable public void closePath (NVGContext ctx) nothrow @trusted @nogc { nvg__appendCommands(ctx, Command.Close); } @@ -5277,6 +5298,7 @@ public void arc(string mode="original") (NVGContext ctx, NVGWinding dir, in floa /// Creates new rectangle shaped sub-path. /// Group: paths +@scriptable public void rect (NVGContext ctx, in float x, in float y, in float w, in float h) nothrow @trusted @nogc { nvg__appendCommands!false(ctx, Command.MoveTo, // ignore command Command.MoveTo, x, y, @@ -5312,6 +5334,7 @@ public void rect (NVGContext ctx, in float[] args) nothrow @trusted @nogc { /// Creates new rounded rectangle shaped sub-path. /// Group: paths +@scriptable public void roundedRect (NVGContext ctx, in float x, in float y, in float w, in float h, in float radius) nothrow @trusted @nogc { ctx.roundedRectVarying(x, y, w, h, radius, radius, radius, radius); } @@ -5336,6 +5359,7 @@ public void roundedRect (NVGContext ctx, in float[] args) nothrow @trusted @nogc /// Creates new rounded rectangle shaped sub-path. Specify ellipse width and height to round corners according to it. /// Group: paths +@scriptable public void roundedRectEllipse (NVGContext ctx, in float x, in float y, in float w, in float h, in float rw, in float rh) nothrow @trusted @nogc { if (rw < 0.1f || rh < 0.1f) { rect(ctx, x, y, w, h); @@ -5591,6 +5615,7 @@ void nvg__prepareStroke (NVGContext ctx) nothrow @trusted @nogc { /// Fills the current path with current fill style. /// Group: paths +@scriptable public void fill (NVGContext ctx) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); @@ -5624,6 +5649,7 @@ public void fill (NVGContext ctx) nothrow @trusted @nogc { /// Fills the current path with current stroke style. /// Group: paths +@scriptable public void stroke (NVGContext ctx) nothrow @trusted @nogc { NVGstate* state = nvg__getState(ctx); diff --git a/simpledisplay.d b/simpledisplay.d index ffc4992..4095e9e 100644 --- a/simpledisplay.d +++ b/simpledisplay.d @@ -1666,9 +1666,11 @@ class SimpleWindow : CapableOfHandlingNativeEvent, CapableOfBeingDrawnUpon { public __gshared SimpleWindow[NativeWindowHandle] nativeMapping; /// Width of the window's drawable client area, in pixels. + @scriptable final @property int width() { return _width; } /// Height of the window's drawable client area, in pixels. + @scriptable final @property int height() { return _height; } private int _width; @@ -13824,3 +13826,5 @@ class NotYetImplementedException : Exception { super("Not yet implemented", file, line); } } + +private alias scriptable = arsd_jsvar_compatible;