Initial release

This commit is contained in:
civ
2026-08-16 18:24:52 +07:00
commit 876886a39a
13244 changed files with 2353959 additions and 0 deletions
@@ -0,0 +1,134 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "scriptobject.h"
#include "../../lib/vstguifwd.h"
#include "../../uidescription/uidescriptionfwd.h"
#include "../../lib/events.h"
#include "../../lib/crect.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
//------------------------------------------------------------------------
inline ScriptObject makeScriptRect (const CRect& rect)
{
using namespace std::literals;
ScriptObject obj;
obj.addChild ("left"sv, rect.left);
obj.addChild ("top"sv, rect.top);
obj.addChild ("right"sv, rect.right);
obj.addChild ("bottom"sv, rect.bottom);
obj.addFunc ("getWidth"sv, "{ return this.right - this.left; }"sv);
obj.addFunc ("getHeight"sv, "{ return this.bottom - this.top; }"sv);
return obj;
}
//------------------------------------------------------------------------
inline ScriptObject makeScriptPoint (const CPoint& point)
{
using namespace std::literals;
ScriptObject obj;
obj.addChild ("x"sv, point.x);
obj.addChild ("y"sv, point.y);
return obj;
}
//------------------------------------------------------------------------
inline CPoint fromScriptPoint (TJS::CScriptVar& var)
{
using namespace std::literals;
CPoint result {};
if (auto xVar = var.findChild ("x"sv))
result.x = xVar->getVar ()->getDouble ();
else
throw TJS::CScriptException ("Not a point object, missing 'x' member");
if (auto yVar = var.findChild ("y"sv))
result.y = yVar->getVar ()->getDouble ();
else
throw TJS::CScriptException ("Not a point object, missing 'y' member");
return result;
}
//------------------------------------------------------------------------
inline CRect fromScriptRect (TJS::CScriptVar& var)
{
using namespace std::literals;
CRect result {};
auto leftVar = var.findChild ("left"sv);
auto topVar = var.findChild ("top"sv);
auto rightVar = var.findChild ("right"sv);
auto bottomVar = var.findChild ("bottom"sv);
if (!leftVar || !topVar || !rightVar || !bottomVar)
throw TJS::CScriptException ("Expecting a rect object here");
result.left = leftVar->getVar ()->getDouble ();
result.top = topVar->getVar ()->getDouble ();
result.right = rightVar->getVar ()->getDouble ();
result.bottom = bottomVar->getVar ()->getDouble ();
return result;
}
//------------------------------------------------------------------------
inline ScriptObject makeScriptEvent (const Event& event)
{
using namespace std::literals;
ScriptObject obj;
if (auto modifierEvent = asModifierEvent (event))
{
ScriptObject mod;
if (modifierEvent->modifiers.has (ModifierKey::Shift))
mod.addChild ("shift"sv, true);
if (modifierEvent->modifiers.has (ModifierKey::Alt))
mod.addChild ("alt"sv, true);
if (modifierEvent->modifiers.has (ModifierKey::Control))
mod.addChild ("control"sv, true);
if (modifierEvent->modifiers.has (ModifierKey::Super))
mod.addChild ("super"sv, true);
obj.addChild ("modifiers"sv, std::move (mod));
}
if (auto mouseEvent = asMousePositionEvent (event))
{
obj.addChild ("mousePosition"sv, makeScriptPoint (mouseEvent->mousePosition));
}
if (auto mouseEvent = asMouseEvent (event))
{
ScriptObject buttons;
if (mouseEvent->buttonState.has (MouseButton::Left))
buttons.addChild ("left"sv, true);
if (mouseEvent->buttonState.has (MouseButton::Right))
buttons.addChild ("right"sv, true);
if (mouseEvent->buttonState.has (MouseButton::Middle))
buttons.addChild ("middle"sv, true);
obj.addChild ("mouseButtons"sv, std::move (buttons));
}
if (event.type == EventType::MouseWheel)
{
const auto& wheelEvent = castMouseWheelEvent (event);
ScriptObject wheel;
wheel.addChild ("deltaX"sv, wheelEvent.deltaX);
wheel.addChild ("deltaY"sv, wheelEvent.deltaY);
if (wheelEvent.flags & MouseWheelEvent::Flags::DirectionInvertedFromDevice)
wheel.addChild ("directionInvertedFromDevice"sv, true);
if (wheelEvent.flags & MouseWheelEvent::Flags::PreciseDeltas)
wheel.addChild ("preciceDelta"sv, true);
obj.addChild ("mouseWheel"sv, std::move (wheel));
}
if (auto keyEvent = asKeyboardEvent (event))
{
ScriptObject key;
key.addChild ("character"sv, static_cast<int> (keyEvent->character));
key.addChild ("virtual"sv, static_cast<int> (keyEvent->virt));
key.addChild ("isRepeat"sv, keyEvent->isRepeat);
obj.addChild ("key"sv, std::move (key));
}
obj.addChild ("consume"sv, 0);
return obj;
}
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,214 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "drawable.h"
#include "converters.h"
#include "../../lib/cframe.h"
#include "../../lib/cdrawcontext.h"
#include "../../lib/cgraphicspath.h"
#include "../../lib/cgraphicstransform.h"
#include "../../uidescription/detail/uiviewcreatorattributes.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
using namespace std::literals;
using namespace TJS;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void JavaScriptDrawable::onDraw (CDrawContext* context, const CRect& rect, const CRect& viewSize)
{
if (!scriptObject)
{
auto dashLength = std::round ((viewSize.getWidth () * 2 + viewSize.getHeight () * 2) / 40.);
CLineStyle ls (CLineStyle::kLineCapButt, CLineStyle::kLineJoinMiter, 0,
{dashLength, dashLength});
auto lineWidth = 1.;
auto size = viewSize;
size.inset (lineWidth / 2., lineWidth / 2.);
context->setLineStyle (ls);
context->setLineWidth (lineWidth);
context->setFrameColor (kBlackCColor);
context->drawRect (size, kDrawStroked);
ls.setDashPhase (dashLength * lineWidth);
context->setLineStyle (ls);
context->setFrameColor (kWhiteCColor);
context->drawRect (size, kDrawStroked);
return;
}
auto scriptContext = scriptObject->getContext ();
if (!scriptContext)
return;
context->saveGlobalState ();
drawContext.setDrawContext (context, scriptContext->getUIDescription ());
CDrawContext::Transform tm (*context, CGraphicsTransform ().translate (viewSize.getTopLeft ()));
auto rectVar = makeScriptRect (rect);
auto scriptRoot = scriptContext->getRoot ();
ScriptAddChildScoped scs (*scriptRoot, "view"sv, *scriptObject);
ScriptAddChildScoped scs2 (*scriptRoot, "context"sv, drawContext);
ScriptAddChildScoped scs3 (*scriptRoot, "rect"sv, rectVar);
scriptContext->evalScript ("view.draw(context, rect);"sv);
drawContext.setDrawContext (nullptr, nullptr);
context->restoreGlobalState ();
}
//------------------------------------------------------------------------
void JavaScriptDrawable::setup (ViewScriptObject* inObject) { scriptObject = inObject; }
//------------------------------------------------------------------------
bool JavaScriptDrawable::onDrawFocusOnTop ()
{
auto scriptContext = scriptObject->getContext ();
if (!scriptContext)
return false;
if (scriptObject->getVar ()->findChild ("drawFocusOnTop"sv) == nullptr)
return false;
auto scriptRoot = scriptContext->getRoot ();
ScriptAddChildScoped scs (*scriptRoot, "view"sv, *scriptObject);
auto boolResult = scriptContext->evalScript ("view.drawFocusOnTop();"sv);
return boolResult->isNumeric () ? boolResult->getInt () : false;
}
//------------------------------------------------------------------------
bool JavaScriptDrawable::onGetFocusPath (CGraphicsPath& outPath, CCoord focusWidth,
const CRect& viewSize)
{
if (auto scriptContext = scriptObject->getContext ())
{
if (scriptObject->getVar ()->findChild ("getFocusPath"sv) == nullptr)
{
auto r = viewSize;
outPath.addRect (r);
r.extend (focusWidth, focusWidth);
outPath.addRect (r);
return true;
}
auto scriptRoot = scriptContext->getRoot ();
auto path = makeOwned<CGraphicsPath> (outPath);
ScriptObject focusWidthVar;
focusWidthVar->setDouble (focusWidth);
ScriptAddChildScoped scs (*scriptRoot, "view"sv, *scriptObject);
ScriptAddChildScoped scs2 (*scriptRoot, "path"sv, makeGraphicsPathScriptObject (path));
ScriptAddChildScoped scs3 (*scriptRoot, "focusWidth"sv, focusWidthVar);
auto boolResult = scriptContext->evalScript ("view.getFocusPath(path, focusWidth);"sv);
if (boolResult->isNumeric ())
{
if (boolResult->getInt () == 1)
{
CGraphicsTransform tm;
tm.translate (viewSize.left, viewSize.top);
outPath.addPath (*path, &tm);
return true;
}
return false;
}
}
return false;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void JavaScriptDrawableView::drawRect (CDrawContext* context, const CRect& rect)
{
onDraw (context, rect, getViewSize ());
}
//------------------------------------------------------------------------
bool JavaScriptDrawableView::drawFocusOnTop ()
{
if (wantsFocus ())
return onDrawFocusOnTop ();
return false;
}
//------------------------------------------------------------------------
bool JavaScriptDrawableView::getFocusPath (CGraphicsPath& outPath)
{
if (wantsFocus ())
return onGetFocusPath (outPath, getFrame ()->getFocusWidth (), getViewSize ());
return false;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
void JavaScriptDrawableControl::draw (CDrawContext* context) { drawRect (context, getViewSize ()); }
//------------------------------------------------------------------------
void JavaScriptDrawableControl::drawRect (CDrawContext* context, const CRect& rect)
{
onDraw (context, rect, getViewSize ());
}
//------------------------------------------------------------------------
bool JavaScriptDrawableControl::drawFocusOnTop ()
{
if (wantsFocus ())
return onDrawFocusOnTop ();
return false;
}
//------------------------------------------------------------------------
bool JavaScriptDrawableControl::getFocusPath (CGraphicsPath& outPath)
{
if (wantsFocus ())
return onGetFocusPath (outPath, getFrame ()->getFocusWidth (), getViewSize ());
return false;
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
IdStringPtr JavaScriptDrawableViewCreator::getViewName () const { return "JavaScriptDrawableView"; }
//------------------------------------------------------------------------
IdStringPtr JavaScriptDrawableViewCreator::getBaseViewName () const
{
return UIViewCreator::kCView;
}
//------------------------------------------------------------------------
CView* JavaScriptDrawableViewCreator::create (const UIAttributes& attributes,
const IUIDescription* description) const
{
return new JavaScriptDrawableView (CRect ());
}
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
IdStringPtr JavaScriptDrawableControlCreator::getViewName () const
{
return "JavaScriptDrawableControl";
}
//------------------------------------------------------------------------
IdStringPtr JavaScriptDrawableControlCreator::getBaseViewName () const
{
return UIViewCreator::kCControl;
}
//------------------------------------------------------------------------
CView* JavaScriptDrawableControlCreator::create (const UIAttributes& attributes,
const IUIDescription* description) const
{
return new JavaScriptDrawableControl (CRect ());
}
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,77 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "viewscriptobject.h"
#include "drawcontextobject.h"
#include "../../lib/cview.h"
#include "../../lib/controls/ccontrol.h"
#include "../../uidescription/iviewcreator.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
//------------------------------------------------------------------------
struct JavaScriptDrawable
{
void onDraw (CDrawContext* context, const CRect& rect, const CRect& viewSize);
bool onDrawFocusOnTop ();
bool onGetFocusPath (CGraphicsPath& outPath, CCoord focusWidth, const CRect& viewSize);
void setup (ViewScriptObject* object);
private:
ViewScriptObject* scriptObject {nullptr};
DrawContextObject drawContext;
};
//------------------------------------------------------------------------
struct JavaScriptDrawableView : CView,
IFocusDrawing,
JavaScriptDrawable
{
using CView::CView;
void drawRect (CDrawContext* context, const CRect& rect) override;
bool drawFocusOnTop () override;
bool getFocusPath (CGraphicsPath& outPath) override;
};
//------------------------------------------------------------------------
struct JavaScriptDrawableControl : CControl,
JavaScriptDrawable
{
using CControl::CControl;
void draw (CDrawContext* pContext) override;
void drawRect (CDrawContext* context, const CRect& rect) override;
bool drawFocusOnTop () override;
bool getFocusPath (CGraphicsPath& outPath) override;
CLASS_METHODS_NOCOPY (JavaScriptDrawableControl, CControl);
};
//------------------------------------------------------------------------
struct JavaScriptDrawableViewCreator : ViewCreatorAdapter
{
IdStringPtr getViewName () const override;
IdStringPtr getBaseViewName () const override;
CView* create (const UIAttributes& attributes,
const IUIDescription* description) const override;
};
//------------------------------------------------------------------------
struct JavaScriptDrawableControlCreator : ViewCreatorAdapter
{
IdStringPtr getViewName () const override;
IdStringPtr getBaseViewName () const override;
CView* create (const UIAttributes& attributes,
const IUIDescription* description) const override;
};
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,870 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "drawcontextobject.h"
#include "converters.h"
#include "../../lib/cdrawcontext.h"
#include "../../lib/cgraphicspath.h"
#include "../../lib/cgradient.h"
#include "../../uidescription/uidescription.h"
#include "../../uidescription/uiviewcreator.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
using namespace std::literals;
using namespace TJS;
//------------------------------------------------------------------------
template<typename T>
static T getFromVar (CScriptVar* var, const string& exceptionString)
{
auto customData = var->getCustomData ();
if (!customData.has_value ())
throw CScriptException (exceptionString);
try
{
auto result = std::any_cast<T> (customData);
return result;
}
catch (const std::bad_any_cast&)
{
throw CScriptException (exceptionString);
}
return {};
}
//------------------------------------------------------------------------
static SharedPointer<CGraphicsPath> getGraphicsPath (CScriptVar* var, std::string_view varName,
std::string_view signature)
{
auto pathVar = getArgument (var, varName, signature);
return getFromVar<SharedPointer<CGraphicsPath>> (pathVar, "Variable is not a graphics path");
}
//------------------------------------------------------------------------
static SharedPointer<CGradient> getGradient (CScriptVar* var, std::string_view varName,
std::string_view signature)
{
auto gradientVar = getArgument (var, varName, signature);
return getFromVar<SharedPointer<CGradient>> (gradientVar, "Variable is not a gradient");
}
//------------------------------------------------------------------------
static std::shared_ptr<CGraphicsTransform> getTransformMatrix (CScriptVar* var,
std::string_view varName,
std::string_view signature)
{
auto tmVar = getArgument (var, varName, signature);
return getFromVar<std::shared_ptr<CGraphicsTransform>> (tmVar,
"Variable is not a transform matrix");
}
//------------------------------------------------------------------------
static std::shared_ptr<CGraphicsTransform> getOptionalTransformMatrix (CScriptVar* var,
std::string_view varName,
std::string_view signature)
{
if (auto tmVar = getOptionalArgument (var, varName))
return getFromVar<std::shared_ptr<CGraphicsTransform>> (
tmVar, "Variable is not a transform matrix");
return {};
}
//------------------------------------------------------------------------
static CRect getRect (CScriptVar* var, std::string_view varName, std::string_view signature)
{
auto rectVar = getArgument (var, varName, signature);
auto rect = fromScriptRect (*rectVar);
return rect;
}
//------------------------------------------------------------------------
static CPoint getPoint (CScriptVar* var, std::string_view varName, std::string_view signature)
{
auto pointVar = getArgument (var, varName, signature);
auto point = fromScriptPoint (*pointVar);
return point;
}
//------------------------------------------------------------------------
static CPoint getOptionalPoint (CScriptVar* var, std::string_view varName,
std::string_view signature, CPoint defaultPoint = {})
{
if (auto pointVar = getOptionalArgument (var, varName))
return fromScriptPoint (*pointVar);
return defaultPoint;
}
//------------------------------------------------------------------------
static double getDouble (CScriptVar* var, std::string_view varName, std::string_view signature)
{
auto doubleVar = getArgument (var, varName, signature);
if (!doubleVar->isNumeric ())
{
TJS::string s ("'");
s.append (varName);
s.append ("' must be a number");
throw CScriptException (s);
}
return doubleVar->getDouble ();
}
//------------------------------------------------------------------------
static int64_t getInt (CScriptVar* var, std::string_view varName, std::string_view signature)
{
auto intVar = getArgument (var, varName, signature);
if (!intVar->isNumeric ())
{
TJS::string s ("'");
s.append (varName);
s.append ("' must be numeric");
throw CScriptException (s);
}
return intVar->getInt ();
}
//------------------------------------------------------------------------
static int64_t getOptionalInt (CScriptVar* var, std::string_view varName,
std::string_view signature, int64_t defaultInt = {})
{
if (auto intVar = getOptionalArgument (var, varName))
{
if (!intVar->isNumeric ())
{
TJS::string s ("'");
s.append (varName);
s.append ("' must be numeric");
throw CScriptException (s);
}
return intVar->getInt ();
}
return defaultInt;
}
//------------------------------------------------------------------------
static CColor getColor (CScriptVar* var, const IUIDescription* uiDesc, std::string_view varName,
std::string_view signature)
{
auto colorVar = getArgument (var, varName, signature);
auto colorStr = colorVar->getString ();
CColor color {};
if (!UIViewCreator::stringToColor (colorStr, color, uiDesc))
{
string str ("'");
str += colorStr;
str += "' is not a color in a call to ";
str += signature;
throw CScriptException (str);
}
return color;
}
//------------------------------------------------------------------------
struct TransformMatrixScriptObject : ScriptObject
{
using TransformMatrixPtr = std::shared_ptr<CGraphicsTransform>;
TransformMatrixScriptObject (TransformMatrixPtr tm = std::make_shared<CGraphicsTransform> ())
: ScriptObject (new CScriptVar ("", SCRIPTVAR_OBJECT))
{
scriptVar->setCustomData (tm);
addFunc ("concat"sv, [tm] (auto var) { concat (tm, var); }, {"transformMatrix"sv});
addFunc ("inverse"sv, [tm] (auto var) { inverse (tm, var); });
addFunc ("rotate"sv, [tm] (auto var) { rotate (tm, var); }, {"angle"sv, "center?"sv});
addFunc ("scale"sv, [tm] (auto var) { scale (tm, var); }, {"x"sv, "y"sv});
addFunc ("skewX"sv, [tm] (auto var) { skewX (tm, var); }, {"angle"sv});
addFunc ("skewY"sv, [tm] (auto var) { skewY (tm, var); }, {"angle"sv});
addFunc ("translate"sv, [tm] (auto var) { translate (tm, var); }, {"x"sv, "y"sv});
addFunc ("transform"sv, [tm] (auto var) { transform (tm, var); }, {"pointOrRect"sv});
}
static void inverse (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.inverse();"sv;
auto iTm = tm->inverse ();
TransformMatrixScriptObject obj (std::make_shared<CGraphicsTransform> (iTm));
var->setReturnVar (obj.take ());
}
static void concat (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.concat(transformMatrix);"sv;
auto other = getTransformMatrix (var, "transformMatrix"sv, signature);
auto result = *(tm.get ()) * *(other.get ());
*(tm.get ()) = result;
}
static void translate (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.translate(x, y);"sv;
auto x = getDouble (var, "x"sv, signature);
auto y = getDouble (var, "y"sv, signature);
tm->translate (x, y);
}
static void scale (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.scale(x, y);"sv;
auto x = getDouble (var, "x"sv, signature);
auto y = getDouble (var, "y"sv, signature);
tm->scale (x, y);
}
static void rotate (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.rotate(angle, center?);"sv;
auto angle = getDouble (var, "angle"sv, signature);
if (auto centerVar = getOptionalArgument (var, "center?"sv))
{
auto center = fromScriptPoint (*centerVar);
tm->rotate (angle, center);
}
else
{
tm->rotate (angle);
}
}
static void skewX (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.skewX(angle);"sv;
auto angle = getDouble (var, "angle"sv, signature);
tm->skewX (angle);
}
static void skewY (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.skewY(angle);"sv;
auto angle = getDouble (var, "angle"sv, signature);
tm->skewY (angle);
}
static void transform (const TransformMatrixPtr& tm, CScriptVar* var)
{
static constexpr auto signature = "matrix.transform(pointOrRect);"sv;
auto pointOrRect = getArgument (var, "pointOrRect"sv, signature);
auto xVar = getOptionalArgument (pointOrRect, "x"sv);
auto yVar = getOptionalArgument (pointOrRect, "y"sv);
if (xVar && yVar)
{
auto x = xVar->getDouble ();
auto y = yVar->getDouble ();
tm->transform (x, y);
xVar->setDouble (x);
yVar->setDouble (y);
return;
}
auto leftVar = getOptionalArgument (pointOrRect, "left"sv);
auto topVar = getOptionalArgument (pointOrRect, "top"sv);
auto rightVar = getOptionalArgument (pointOrRect, "right"sv);
auto bottomVar = getOptionalArgument (pointOrRect, "bottom"sv);
if (leftVar && topVar && rightVar && bottomVar)
{
CRect r (leftVar->getDouble (), topVar->getDouble (), rightVar->getDouble (),
bottomVar->getDouble ());
tm->transform (r);
leftVar->setDouble (r.left);
topVar->setDouble (r.top);
rightVar->setDouble (r.right);
bottomVar->setDouble (r.bottom);
return;
}
string s ("Argument is not a point or a rect in ");
s.append (signature);
throw CScriptException (std::move (s));
}
};
//------------------------------------------------------------------------
TJS::CScriptVar* makeTransformMatrixObject ()
{
TransformMatrixScriptObject obj;
return obj.take ();
}
//------------------------------------------------------------------------
struct GradientScriptObject : ScriptObject
{
GradientScriptObject (const SharedPointer<CGradient>& g, const IUIDescription* uiDesc)
: ScriptObject (new CScriptVar ("", SCRIPTVAR_OBJECT))
{
scriptVar->setCustomData (g);
addFunc ("addColorStop"sv, [g, uiDesc] (auto var) { addColorStop (g, uiDesc, var); },
{"position"sv, "color"sv});
}
static void addColorStop (const SharedPointer<CGradient>& g, const IUIDescription* uiDesc,
CScriptVar* var)
{
static constexpr auto signature = "gradient.addColorStop(position, color);"sv;
auto position = getDouble (var, "position"sv, signature);
auto color = getColor (var, uiDesc, "color"sv, signature);
g->addColorStop (position, color);
}
};
//------------------------------------------------------------------------
struct GraphicsPathScriptObject : ScriptObject
{
GraphicsPathScriptObject (const SharedPointer<CGraphicsPath>& p)
: ScriptObject (new CScriptVar ("", SCRIPTVAR_OBJECT))
{
scriptVar->setCustomData (p);
addFunc ("addEllipse"sv, [p] (auto var) { addEllipse (p, var); }, {"rect"sv});
addFunc ("addArc"sv, [p] (auto var) { addArc (p, var); },
{"rect"sv, "startAngle"sv, "endAngle"sv, "clockwise"sv});
addFunc ("addBezierCurve"sv, [p] (auto var) { addBezierCurve (p, var); },
{"control1"sv, "control2"sv, "end"sv});
addFunc ("addLine"sv, [p] (auto var) { addLine (p, var); }, {"to"sv});
addFunc ("addPath"sv, [p] (auto var) { addPath (p, var); },
{"path"sv, "transformMatrix?"sv});
addFunc ("addRect"sv, [p] (auto var) { addRect (p, var); }, {"rect"sv});
addFunc ("addRoundRect"sv, [p] (auto var) { addRoundRect (p, var); },
{"rect"sv, "radius"sv});
addFunc ("closeSubpath"sv, [p] (auto var) { closeSubpath (p); });
addFunc ("beginSubpath"sv, [p] (auto var) { beginSubpath (p, var); }, {"start"sv});
}
static void addPath (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.addPath(path, transformMatrix?);"sv;
auto otherPath = getGraphicsPath (var, "path"sv, signature);
auto tm = getOptionalTransformMatrix (var, "transformMatrix?"sv, signature);
path->addPath (*otherPath.get (), tm ? tm.get () : nullptr);
}
static void addArc (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.addArc(rect, startAngle, endAngle, clockwise);"sv;
auto rect = getRect (var, "rect"sv, signature);
auto startAngle = getDouble (var, "startAngle"sv, signature);
auto endAngle = getDouble (var, "endAngle"sv, signature);
auto clockwise = getInt (var, "clockwise"sv, signature);
path->addArc (rect, startAngle, endAngle, clockwise != 0 ? true : false);
}
static void addEllipse (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.addEllipse(rect);"sv;
auto rect = getRect (var, "rect"sv, signature);
path->addEllipse (rect);
}
static void addRect (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.addRect(rect);"sv;
auto rect = getRect (var, "rect"sv, signature);
path->addRect (rect);
}
static void addLine (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.addLine(to);"sv;
auto point = getPoint (var, "to"sv, signature);
path->addLine (point);
}
static void addBezierCurve (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.addBezierCurve(control1, control2, end);"sv;
auto control1 = getPoint (var, "control1"sv, signature);
auto control2 = getPoint (var, "control2"sv, signature);
auto end = getPoint (var, "end"sv, signature);
path->addBezierCurve (control1, control2, end);
}
static void beginSubpath (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.beginSubpath(start);"sv;
auto start = getPoint (var, "start"sv, signature);
path->beginSubpath (start);
}
static void closeSubpath (const SharedPointer<CGraphicsPath>& path)
{
static constexpr auto signature = "path.closeSubpath();"sv;
path->closeSubpath ();
}
static void addRoundRect (const SharedPointer<CGraphicsPath>& path, CScriptVar* var)
{
static constexpr auto signature = "path.addRoundRect(rect, radius);"sv;
auto rect = getRect (var, "rect"sv, signature);
auto radius = getDouble (var, "radius"sv, signature);
path->addRoundRect (rect, radius);
}
};
//------------------------------------------------------------------------
ScriptObject makeGraphicsPathScriptObject (const SharedPointer<CGraphicsPath>& p)
{
return GraphicsPathScriptObject (p);
}
//------------------------------------------------------------------------
struct DrawContextObject::Impl
{
CDrawContext* context {nullptr};
IUIDescription* uiDesc {nullptr};
mutable int32_t globalStatesStored {0};
void setContext (CDrawContext* inContext, IUIDescription* inUIDesc)
{
if (context)
{
while (globalStatesStored > 0)
{
context->restoreGlobalState ();
--globalStatesStored;
}
}
context = inContext;
uiDesc = inUIDesc;
globalStatesStored = 0;
}
void checkContextOrThrow () const
{
if (!context)
throw CScriptException ("Native context is missing!");
}
CDrawStyle getDrawStyle (CScriptVar* styleVar) const
{
CDrawStyle style {};
auto string = styleVar->getString ();
if (string == "stroked"sv)
style = kDrawStroked;
else if (string == "filled"sv)
style = kDrawFilled;
else if (string == "filledAndStroked"sv)
style = kDrawFilledAndStroked;
else
throw CScriptException ("Unknown draw style: " + string);
return style;
}
CDrawContext::PathDrawMode getPathDrawMode (CScriptVar* var) const
{
CDrawContext::PathDrawMode mode {};
auto string = var->getString ();
if (string == "stroked"sv)
mode = CDrawContext::PathDrawMode::kPathStroked;
else if (string == "filled"sv)
mode = CDrawContext::PathDrawMode::kPathFilled;
else if (string == "filledEvenOdd"sv)
mode = CDrawContext::PathDrawMode::kPathFilledEvenOdd;
else
throw CScriptException ("Unknown path draw mode: " + string);
return mode;
}
void createRoundGraphicsPath (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.createRoundGraphicsPath(rect, radius);"sv;
checkContextOrThrow ();
auto rect = getRect (var, "rect"sv, signature);
auto radius = getDouble (var, "radius"sv, signature);
if (auto path = owned (context->createRoundRectGraphicsPath (rect, radius)))
{
GraphicsPathScriptObject obj (path);
var->setReturnVar (obj);
}
}
void createGraphicsPath (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.createGraphicsPath();"sv;
checkContextOrThrow ();
if (auto path = owned (context->createGraphicsPath ()))
{
GraphicsPathScriptObject obj (path);
var->setReturnVar (obj);
}
}
void createGradient (CScriptVar* var) const
{
static constexpr auto signature =
"drawContext.createGradient(startColorPosition, startColor, endColorPosition, endColor);"sv;
auto startColorPosition = getDouble (var, "startColorPosition", signature);
auto endColorPosition = getDouble (var, "endColorPosition", signature);
auto startColor = getColor (var, uiDesc, "startColor"sv, signature);
auto endColor = getColor (var, uiDesc, "endColor"sv, signature);
if (auto gradient = owned (
CGradient::create (startColorPosition, endColorPosition, startColor, endColor)))
{
GradientScriptObject obj (gradient, uiDesc);
var->setReturnVar (obj);
}
}
void drawGraphicsPath (CScriptVar* var) const
{
static constexpr auto signature =
"drawContext.drawGraphicsPath(path, mode?, transform?);"sv;
checkContextOrThrow ();
auto path = getGraphicsPath (var, "path"sv, signature);
auto modeVar = getOptionalArgument (var, "mode?");
auto mode = modeVar ? getPathDrawMode (modeVar) : CDrawContext::PathDrawMode::kPathFilled;
auto tm = getOptionalTransformMatrix (var, "transform?"sv, signature);
context->drawGraphicsPath (path, mode, tm ? tm.get () : nullptr);
}
void fillLinearGradient (CScriptVar* var) const
{
static constexpr auto signature =
"drawContext.fillLinearGradient(path, gradient, startPoint, endPoint, evenOdd?, transform?);"sv;
checkContextOrThrow ();
auto path = getGraphicsPath (var, "path"sv, signature);
auto gradient = getGradient (var, "gradient"sv, signature);
auto startPoint = getPoint (var, "startPoint"sv, signature);
auto endPoint = getPoint (var, "endPoint"sv, signature);
auto tm = getOptionalTransformMatrix (var, "transform?"sv, signature);
auto evenOdd = getOptionalInt (var, "evenOdd?", signature);
context->fillLinearGradient (path, *gradient, startPoint, endPoint, evenOdd > 0, tm.get ());
}
void fillRadialGradient (CScriptVar* var) const
{
static constexpr auto signature =
"drawContext.fillRadialGradient(path, gradient, centerPoint, radius, originOffsetPoint?, evenOdd?, transform?);"sv;
checkContextOrThrow ();
auto path = getGraphicsPath (var, "path"sv, signature);
auto gradient = getGradient (var, "gradient"sv, signature);
auto centerPoint = getPoint (var, "centerPoint"sv, signature);
auto radius = getDouble (var, "radius"sv, signature);
auto originOffsetPoint = getOptionalPoint (var, "originOffsetPoint?"sv, signature);
auto evenOdd = getOptionalInt (var, "evenOdd?", signature);
auto tm = getOptionalTransformMatrix (var, "transform?"sv, signature);
context->fillRadialGradient (path, *gradient, centerPoint, radius, originOffsetPoint,
evenOdd, tm.get ());
}
void drawLine (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.drawLine(from, to);"sv;
checkContextOrThrow ();
auto fromPoint = getArgument (var, "from"sv, signature);
auto toPoint = getArgument (var, "to"sv, signature);
auto from = fromScriptPoint (*fromPoint);
auto to = fromScriptPoint (*toPoint);
context->drawLine (from, to);
}
void drawRect (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.drawRect(rect, style);"sv;
checkContextOrThrow ();
auto rect = getRect (var, "rect"sv, signature);
auto styleVar = getArgument (var, "style"sv, signature);
auto style = getDrawStyle (styleVar);
context->drawRect (rect, style);
}
void drawEllipse (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.drawEllipse(rect, style);"sv;
checkContextOrThrow ();
auto rect = getRect (var, "rect"sv, signature);
auto styleVar = getArgument (var, "style"sv, signature);
auto style = getDrawStyle (styleVar);
context->drawEllipse (rect, style);
}
void drawArc (CScriptVar* var) const
{
static constexpr auto signature =
"drawContext.drawArc(rect, startAngle, endAngle, style);"sv;
checkContextOrThrow ();
auto rect = getRect (var, "rect"sv, signature);
auto startAngle = static_cast<float> (getDouble (var, "startAngle"sv, signature));
auto endAngle = static_cast<float> (getDouble (var, "endAngle"sv, signature));
auto styleVar = getArgument (var, "style"sv, signature);
auto style = getDrawStyle (styleVar);
context->drawArc (rect, startAngle, endAngle, style);
}
void clearRect (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.clearRect(rect);"sv;
checkContextOrThrow ();
auto rect = getRect (var, "rect"sv, signature);
context->clearRect (rect);
}
void drawPolygon (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.drawPolygon(points, style);"sv;
checkContextOrThrow ();
auto pointsVar = getArgument (var, "points"sv, signature);
auto styleVar = getArgument (var, "style"sv, signature);
if (!pointsVar->isArray ())
throw CScriptException ("`points` argument must be an array of points in "
"drawContext.drawPolygon(points, style);");
PointList points;
auto numPoints = pointsVar->getArrayLength ();
for (auto index = 0; index < numPoints; ++index)
{
auto pointVar = pointsVar->getArrayIndex (index);
vstgui_assert (pointVar != nullptr);
points.emplace_back (fromScriptPoint (*pointVar));
}
auto style = getDrawStyle (styleVar);
context->drawPolygon (points, style);
}
void setClipRect (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setClipRect(rect);"sv;
checkContextOrThrow ();
auto rect = getRect (var, "rect"sv, signature);
context->setClipRect (rect);
}
void drawBitmap (CScriptVar* var) const
{
static constexpr auto signature =
"drawContext.drawBitmap(name, destRect, offsetPoint?, alpha?);"sv;
checkContextOrThrow ();
auto nameVar = getArgument (var, "name"sv, signature);
auto destRect = getRect (var, "destRect"sv, signature);
auto offsetPointVar = getOptionalArgument (var, "offsetPoint?"sv);
auto alphaVar = getOptionalArgument (var, "alpha?"sv);
auto bitmap = uiDesc->getBitmap (nameVar->getString ().data ());
if (!bitmap)
throw CScriptException ("bitmap not found in uiDescription");
auto offset = offsetPointVar ? fromScriptPoint (*offsetPointVar) : CPoint (0, 0);
auto alpha = static_cast<float> (alphaVar ? alphaVar->getDouble () : 1.);
context->drawBitmap (bitmap, destRect, offset, alpha);
}
void drawString (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.drawString(string, rect, align?);"sv;
checkContextOrThrow ();
auto stringVar = getArgument (var, "string"sv, signature);
auto rect = getRect (var, "rect"sv, signature);
auto alignVar = getOptionalArgument (var, "align?"sv);
auto string = stringVar->getString ().data ();
CHoriTxtAlign align = kCenterText;
if (!alignVar || alignVar->isUndefined ())
align = kCenterText;
else if (alignVar->getString () == "left"sv)
align = kLeftText;
else if (alignVar->getString () == "center"sv)
align = kCenterText;
else if (alignVar->getString () == "right"sv)
align = kRightText;
else
throw CScriptException (
"wrong `align` argument. Expecting 'left', 'center' or 'right'");
context->drawString (string, rect, align, true);
}
void setFont (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setFont(name);"sv;
checkContextOrThrow ();
auto fontVar = getArgument (var, "name"sv, signature);
if (auto font = uiDesc->getFont (fontVar->getString ().data ()))
context->setFont (font);
}
void setFontColor (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setFontColor(color);"sv;
checkContextOrThrow ();
auto colorVar = getArgument (var, "color"sv, signature);
CColor color {};
UIViewCreator::stringToColor (colorVar->getString (), color, uiDesc);
context->setFontColor (color);
}
void setFillColor (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setFillColor(color);"sv;
checkContextOrThrow ();
auto color = getColor (var, uiDesc, "color"sv, signature);
context->setFillColor (color);
}
void setFrameColor (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setFrameColor(color);"sv;
checkContextOrThrow ();
auto color = getColor (var, uiDesc, "color"sv, signature);
context->setFrameColor (color);
}
void setLineWidth (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setLineWidth(width);"sv;
checkContextOrThrow ();
auto widthVar = getArgument (var, "width"sv, signature);
context->setLineWidth (widthVar->getDouble ());
}
void setLineStyle (CScriptVar* var) const
{
static constexpr auto signature =
"drawContext.setLineStyle(styleOrLineCap, lineJoin?, dashLengths?, dashPhase);"sv;
checkContextOrThrow ();
auto styleOrLineCapVar = getArgument (var, "styleOrLineCap"sv, signature);
auto lineJoinVar = getOptionalArgument (var, "lineJoin?"sv);
auto dashLengthsVar = getOptionalArgument (var, "dashLengths?"sv);
auto dashPhaseVar = getOptionalArgument (var, "dashPhase?"sv);
auto styleOrLineCap = styleOrLineCapVar->getString ();
std::unique_ptr<CLineStyle> lineStyle;
if (styleOrLineCap == "solid"sv)
{
lineStyle = std::make_unique<CLineStyle> (kLineSolid);
}
else if (styleOrLineCap == "dotted"sv)
{
lineStyle = std::make_unique<CLineStyle> (kLineOnOffDash);
}
else
{
if (styleOrLineCap == "butt"sv)
lineStyle = std::make_unique<CLineStyle> (CLineStyle::LineCap::kLineCapButt);
else if (styleOrLineCap == "round"sv)
lineStyle = std::make_unique<CLineStyle> (CLineStyle::LineCap::kLineCapRound);
else if (styleOrLineCap == "square"sv)
lineStyle = std::make_unique<CLineStyle> (CLineStyle::LineCap::kLineCapSquare);
else
throw CScriptException ("unknown `line cap` argument");
if (lineJoinVar)
{
auto lineJoin = lineJoinVar->getString ();
if (lineJoin == "miter"sv)
lineStyle->setLineJoin (CLineStyle::LineJoin::kLineJoinMiter);
else if (lineJoin == "round"sv)
lineStyle->setLineJoin (CLineStyle::LineJoin::kLineJoinRound);
else if (lineJoin == "bevel"sv)
lineStyle->setLineJoin (CLineStyle::LineJoin::kLineJoinBevel);
}
if (dashLengthsVar)
{
if (!dashLengthsVar->isArray ())
throw CScriptException ("`dashLengths` must be an array of numbers");
CLineStyle::CoordVector lengths;
auto numValues = dashLengthsVar->getArrayLength ();
for (auto index = 0; index < numValues; ++index)
{
if (auto lengthVar = dashLengthsVar->getArrayIndex (index))
lengths.push_back (lengthVar->getDouble ());
}
lineStyle->getDashLengths () = lengths;
}
if (dashPhaseVar)
{
lineStyle->setDashPhase (dashPhaseVar->getDouble ());
}
}
if (lineStyle)
context->setLineStyle (*lineStyle.get ());
}
void setGlobalAlpha (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setGlobalAlpha(alpha);"sv;
checkContextOrThrow ();
auto alpha = static_cast<float> (getDouble (var, "alpha"sv, signature));
context->setGlobalAlpha (alpha);
}
void saveGlobalState () const
{
checkContextOrThrow ();
context->saveGlobalState ();
++globalStatesStored;
}
void restoreGlobalState () const
{
checkContextOrThrow ();
context->restoreGlobalState ();
--globalStatesStored;
}
void getStringWidth (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.getStringWidth(string);"sv;
checkContextOrThrow ();
auto stringVar = getArgument (var, "string"sv, signature);
auto width = context->getStringWidth (stringVar->getString ().data ());
var->getReturnVar ()->setDouble (width);
}
void setDrawMode (CScriptVar* var) const
{
static constexpr auto signature = "drawContext.setDrawMode(mode);"sv;
checkContextOrThrow ();
auto modeVar = getArgument (var, "mode"sv, signature);
if (modeVar->getString () == "aliasing"sv)
context->setDrawMode (kAliasing);
else if (modeVar->getString () == "anti-aliasing"sv)
context->setDrawMode (kAntiAliasing);
else
throw CScriptException ("`mode` must be `aliasing` or `anti-aliasing`");
}
};
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
DrawContextObject::DrawContextObject ()
{
impl = std::make_unique<Impl> ();
scriptVar->setLifeTimeObserver (this);
addFunc ("clearRect"sv, [this] (auto var) { impl->clearRect (var); }, {"rect"sv});
addFunc ("createRoundGraphicsPath"sv,
[this] (auto var) { impl->createRoundGraphicsPath (var); }, {"rect"sv, "radius"sv});
addFunc ("createGraphicsPath"sv, [this] (auto var) { impl->createGraphicsPath (var); });
addFunc ("createGradient"sv, [this] (auto var) { impl->createGradient (var); },
{"startColorPosition"sv, "startColor"sv, "endColorPosition"sv, "endColor"sv});
addFunc ("getStringWidth"sv, [this] (auto var) { impl->getStringWidth (var); }, {"string"sv});
addFunc ("drawArc"sv, [this] (auto var) { impl->drawArc (var); },
{"rect"sv, "startAngle"sv, "endAngle"sv, "style"sv});
addFunc ("drawBitmap"sv, [this] (auto var) { impl->drawBitmap (var); },
{"name"sv, "destRect"sv, "offsetPoint?"sv, "alpha?"sv});
addFunc ("drawEllipse"sv, [this] (auto var) { impl->drawEllipse (var); },
{"rect"sv, "style"sv});
addFunc ("drawGraphicsPath"sv, [this] (auto var) { impl->drawGraphicsPath (var); },
{"path"sv, "mode?"sv, "transform?"sv});
addFunc ("drawLine"sv, [this] (auto var) { impl->drawLine (var); }, {"from"sv, "to"sv});
addFunc ("drawPolygon"sv, [this] (auto var) { impl->drawPolygon (var); },
{"points"sv, "style"sv});
addFunc ("drawRect"sv, [this] (auto var) { impl->drawRect (var); }, {"rect"sv, "style"sv});
addFunc ("drawString"sv, [this] (auto var) { impl->drawString (var); },
{"string"sv, "rect"sv, "align?"sv});
addFunc ("fillLinearGradient"sv, [this] (auto var) { impl->fillLinearGradient (var); },
{"path"sv, "gradient"sv, "startPoint"sv, "endPoint"sv, "evenOdd?"sv, "transform?"sv});
addFunc ("fillRadialGradient"sv, [this] (auto var) { impl->fillRadialGradient (var); },
{"path"sv, "gradient"sv, "centerPoint"sv, "radius"sv, "originOffsetPoint?"sv,
"evenOdd?"sv, "transform?"sv});
addFunc ("restoreGlobalState"sv, [this] (auto var) { impl->restoreGlobalState (); });
addFunc ("saveGlobalState"sv, [this] (auto var) { impl->saveGlobalState (); });
addFunc ("setClipRect"sv, [this] (auto var) { impl->setClipRect (var); }, {"rect"sv});
addFunc ("setFont"sv, [this] (auto var) { impl->setFont (var); }, {"name"sv});
addFunc ("setFontColor"sv, [this] (auto var) { impl->setFontColor (var); }, {"color"sv});
addFunc ("setFillColor"sv, [this] (auto var) { impl->setFillColor (var); }, {"color"sv});
addFunc ("setFrameColor"sv, [this] (auto var) { impl->setFrameColor (var); }, {"color"sv});
addFunc ("setGlobalAlpha", [this] (auto var) { impl->setGlobalAlpha (var); }, {"alpha"sv});
addFunc ("setLineWidth"sv, [this] (auto var) { impl->setLineWidth (var); }, {"width"sv});
addFunc ("setLineStyle"sv, [this] (auto var) { impl->setLineStyle (var); },
{"styleOrLineCap"sv, "lineJoin?"sv, "dashLengths?"sv, "dashPhase?"sv});
addFunc ("setDrawMode"sv, [this] (auto var) { impl->setDrawMode (var); }, {"mode"sv});
}
//------------------------------------------------------------------------
DrawContextObject::~DrawContextObject () noexcept
{
if (scriptVar)
scriptVar->setLifeTimeObserver (nullptr);
}
//------------------------------------------------------------------------
void DrawContextObject::setDrawContext (CDrawContext* inContext, IUIDescription* inUIDesc)
{
impl->setContext (inContext, inUIDesc);
}
//------------------------------------------------------------------------
void DrawContextObject::onDestroy (CScriptVar* v)
{
v->setLifeTimeObserver (nullptr);
scriptVar = nullptr;
}
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,103 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "scriptobject.h"
#include "../../lib/vstguifwd.h"
#include "../../uidescription/uidescriptionfwd.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
TJS::CScriptVar* makeTransformMatrixObject ();
ScriptObject makeGraphicsPathScriptObject (const SharedPointer<CGraphicsPath>& p);
//------------------------------------------------------------------------
struct DrawContextObject : ScriptObject,
TJS::IScriptVarLifeTimeObserver
{
DrawContextObject ();
~DrawContextObject () noexcept override;
void setDrawContext (CDrawContext* context, IUIDescription* uiDesc);
void onDestroy (CScriptVar* v) override;
private:
// CanvasRenderingContext2D API
// clang-format off
/*
fillStyle: string | CanvasGradient | CanvasPattern;
filter: string
font: string;
fontKerning: string;
fontStretch: string;
fontVariantCaps: string;
globalAlpha: number;
globalCompositionOperation: string;
lineCap: string;
lineDashOffset: number;
lineJoin: string;
lineWidth: number;
miterLimit: number;
shadowBlur: number;
shadowColor: string;
shadowOffsetX: number;
shadowOffsetY: number;
strokeStyle: string;
textAlign: string;
textBaseline: string;
arc: (x: number, y: number, r: number, sAngle: number, eAngle: number, counterClockwise?: boolean) => void;
arcTo: (x1: number, y1: number, x2: number, y2: number, r: number) => void;
beginPath: () => void;
bezierCurveTo: (cp1x: number, cp1y: number, cp2x: number, cp2y: number, x: number, y: number) => void;
clearRect: (x: number, y: number, width: number, height: number) => void;
clip: () => void;
closePath: () => void;
createImageData: (width: number, height: number, imageData: ImageData) => void;
createLinearGradient: (x0: number, yo: number, x1: number, y1: number) => CanvasGradient;
createPattern: () => CanvasPattern;
createRadialGradient: (x0: number, y0: number, r0: number, x1: number, y1: number, r1: number) => CanvasGradient;
drawFocusIfNeeded: (html: HTMLElement) => void;
drawImage: (image: Image,dx: number,dy: number,sx?: number,sy?: number,sWidth?: number,sHeight?: number,dWidth?: number,dHeight?: number) => void;
ellipse: (x: number, y: number, radiusX: number, radiusY: number, rotation: number, startAngle: number, endAngle: number, anticlockwise?: boolean) => void;
fill: (Path2D?: Path2D, fillRule?: any) => void;
fillRect: (x: number, y: number, width: number, height: number) => void;
fillText: (text: string, x: number, y: number, maxWidth?: number) => void;
getImageData: (sx: number, sy: number, sw: number, sh: number) => Promise<ImageData>;
getLineDash: () => number[];
isPointInPath: (x: number, y: number, fillRule: any, path: Path2D) => boolean;
isPointInStroke: (x: number, y: number, path: Path2D) => boolean;
lineTo: (x: number, y: number) => void;
measureText: (text: string) => any;
moveTo: (x: number, y: number) => void;
putImageData: (imageData: ImageData, dx: number, dy: number, dirtyX?: number, dirtyY?: number, dirtyWidth?: number, dirtyHeight?: number) => void;
quadraticCurveTo: (cpx: number, cpy: number, x: number, y: number) => void;
rect: (x: number, y: number, width: number, height: number) => void;
reset: () => void
resetTransform: () => void
restore: () => void;
rotate: (angle: number) => void;
roundRect: (x: number, y: number, width: number, height: number, radii: number) => void
save: () => void;
scale: (x: number, y: number) => void;
setLineDash: (segments: number[]) => void;
setTransform: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
stroke: (path?: Path2D) => void;
strokeRect: (x: number, y: number, width: number, height: number) => void;
strokeText: (text: string, x: number, y: number, maxWidth?: number) => void;
transform: (a: number, b: number, c: number, d: number, e: number, f: number) => void;
translate: (x: number, y: number) => void;
*/
// clang-format on
struct Impl;
std::unique_ptr<Impl> impl;
};
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,24 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../uiscripting.h"
#include <string>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
static const std::string kAttrScript = "script";
//------------------------------------------------------------------------
struct IScriptContextInternal : public IScriptContext
{
virtual void onViewCreated (CView* view, const std::string& script) = 0;
};
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,133 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "scriptingviewfactory.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
//------------------------------------------------------------------------
JavaScriptViewFactory::JavaScriptViewFactory (IScriptContextInternal* scripting,
IViewFactory* origFactory)
: Super (origFactory), scriptContext (scripting)
{
}
//------------------------------------------------------------------------
JavaScriptViewFactory::~JavaScriptViewFactory () noexcept
{
std::for_each (viewControllerLinks.begin (), viewControllerLinks.end (),
[this] (const auto& el) {
el.first->unregisterViewListener (this);
el.second->scriptContextDestroyed (scriptContext);
});
}
//------------------------------------------------------------------------
CView* JavaScriptViewFactory::createView (const UIAttributes& attributes,
const IUIDescription* description) const
{
if (auto view = Super::createView (attributes, description))
{
if (auto value = attributes.getAttributeValue (kAttrScript))
{
std::optional<std::string> verifiedScript;
if (auto scriptViewController =
dynamic_cast<IScriptControllerExtension*> (description->getController ()))
{
verifiedScript = scriptViewController->verifyScript (view, *value, scriptContext);
view->registerViewListener (const_cast<JavaScriptViewFactory*> (this));
viewControllerLinks.emplace_back (view, scriptViewController);
}
const auto& script = verifiedScript ? *verifiedScript : *value;
auto scriptSize = static_cast<uint32_t> (script.size () + 1);
view->setAttribute (scriptAttrID, scriptSize, script.data ());
if (!disabled)
{
scriptContext->onViewCreated (view, script);
}
}
return view;
}
return {};
}
//------------------------------------------------------------------------
bool JavaScriptViewFactory::getAttributeNamesForView (CView* view, StringList& attributeNames) const
{
if (Super::getAttributeNamesForView (view, attributeNames))
{
attributeNames.emplace_back (kAttrScript);
return true;
}
return false;
}
//------------------------------------------------------------------------
auto JavaScriptViewFactory::getAttributeType (CView* view, const std::string& attributeName) const
-> IViewCreator::AttrType
{
if (attributeName == kAttrScript)
return IViewCreator::kScriptType;
return Super::getAttributeType (view, attributeName);
}
//------------------------------------------------------------------------
bool JavaScriptViewFactory::getAttributeValue (CView* view, const std::string& attributeName,
std::string& stringValue,
const IUIDescription* desc) const
{
if (attributeName == kAttrScript)
{
uint32_t attrSize = 0;
if (view->getAttributeSize (scriptAttrID, attrSize) && attrSize > 0)
{
stringValue.resize (attrSize - 1);
if (!view->getAttribute (scriptAttrID, attrSize, stringValue.data (), attrSize))
stringValue = "";
return true;
}
return false;
}
return Super::getAttributeValue (view, attributeName, stringValue, desc);
}
//------------------------------------------------------------------------
bool JavaScriptViewFactory::applyAttributeValues (CView* view, const UIAttributes& attributes,
const IUIDescription* desc) const
{
if (auto value = attributes.getAttributeValue (kAttrScript))
{
if (value->empty ())
view->removeAttribute (scriptAttrID);
else
view->setAttribute (scriptAttrID, static_cast<uint32_t> (value->size () + 1),
value->data ());
if (!disabled)
scriptContext->onViewCreated (view, *value);
return true;
}
return Super::applyAttributeValues (view, attributes, desc);
}
//------------------------------------------------------------------------
void JavaScriptViewFactory::setScriptingDisabled (bool state) { disabled = state; }
//------------------------------------------------------------------------
void JavaScriptViewFactory::viewWillDelete (CView* view)
{
auto it = std::find_if (viewControllerLinks.begin (), viewControllerLinks.end (),
[view] (const auto& el) { return el.first == view; });
if (it != viewControllerLinks.end ())
{
it->second->scriptContextDestroyed (scriptContext);
viewControllerLinks.erase (it);
}
view->unregisterViewListener (this);
}
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,51 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "iscriptcontextinternal.h"
#include "../../uidescription/uiattributes.h"
#include "../../uidescription/uiviewfactory.h"
#include "../../lib/iviewlistener.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
//------------------------------------------------------------------------
struct JavaScriptViewFactory : ViewFactoryDelegate,
ViewListenerAdapter
{
static constexpr CViewAttributeID scriptAttrID = 'scri';
JavaScriptViewFactory (ScriptingInternal::IScriptContextInternal* scripting,
IViewFactory* origFactory);
~JavaScriptViewFactory () noexcept;
CView* createView (const UIAttributes& attributes,
const IUIDescription* description) const override;
bool getAttributeNamesForView (CView* view, StringList& attributeNames) const override;
IViewCreator::AttrType getAttributeType (CView* view,
const std::string& attributeName) const override;
bool getAttributeValue (CView* view, const std::string& attributeName, std::string& stringValue,
const IUIDescription* desc) const override;
bool applyAttributeValues (CView* view, const UIAttributes& attributes,
const IUIDescription* desc) const override;
void setScriptingDisabled (bool state);
private:
void viewWillDelete (CView* view) override;
using Super = ViewFactoryDelegate;
using ViewControllerLink = std::pair<CView*, IScriptControllerExtension*>;
using ViewControllerLinkVector = std::vector<ViewControllerLink>;
ScriptingInternal::IScriptContextInternal* scriptContext;
mutable ViewControllerLinkVector viewControllerLinks;
bool disabled {false};
};
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,218 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "../tiny-js/TinyJS.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
//------------------------------------------------------------------------
struct ScriptAddChildScoped
{
using CScriptVar = TJS::CScriptVar;
using CScriptVarLink = TJS::CScriptVarLink;
ScriptAddChildScoped (CScriptVar& var, std::string_view name, CScriptVar* obj) : var (var)
{
if ((link = var.findChild (name)))
{
oldVar = TJS::owning (link->getVar ());
link->setVar (obj);
}
else
{
link = var.addChild (name, obj);
}
}
~ScriptAddChildScoped () noexcept
{
if (oldVar && link)
{
link->setVar (oldVar);
oldVar->release ();
}
else if (link)
{
var.removeLink (link);
}
}
private:
CScriptVar& var;
CScriptVarLink* link {nullptr};
CScriptVar* oldVar {nullptr};
};
//------------------------------------------------------------------------
inline TJS::CScriptVar* createJSFunction (TJS::JSCallback&& proc)
{
auto funcVar = new TJS::CScriptVar (TJS::TINYJS_BLANK_DATA,
TJS::SCRIPTVAR_FUNCTION | TJS::SCRIPTVAR_NATIVE);
funcVar->setCallback (std::move (proc));
return funcVar;
}
//------------------------------------------------------------------------
inline TJS::CScriptVar* createJSFunction (TJS::JSCallback&& proc,
const std::initializer_list<std::string_view>& argNames)
{
auto f = createJSFunction (std::move (proc));
for (auto name : argNames)
f->addChildNoDup (name);
return f;
}
//------------------------------------------------------------------------
inline TJS::CScriptVar* getArgument (TJS::CScriptVar* var, std::string_view argName,
std::string_view funcSignature)
{
auto child = var->findChild (argName);
auto result = child ? child->getVar () : nullptr;
if (!result || result->isUndefined ())
{
TJS::string s ("Missing `");
s.append (argName);
s.append ("` argument in ");
s.append (funcSignature);
throw TJS::CScriptException (std::move (s));
}
return result;
}
//------------------------------------------------------------------------
inline TJS::CScriptVar* getOptionalArgument (TJS::CScriptVar* var, std::string_view argName)
{
if (auto child = var->findChild (argName))
return child->getVar ();
return nullptr;
}
//------------------------------------------------------------------------
struct ScriptObject
{
using CScriptVar = TJS::CScriptVar;
ScriptObject () { scriptVar = TJS::owning (new CScriptVar ()); }
ScriptObject (CScriptVar* var) : scriptVar (TJS::owning (var)) {}
ScriptObject (ScriptObject&& o) { *this = std::move (o); }
ScriptObject& operator= (ScriptObject&& o)
{
if (scriptVar)
scriptVar->release ();
scriptVar = nullptr;
std::swap (scriptVar, o.scriptVar);
return *this;
}
virtual ~ScriptObject () noexcept
{
if (scriptVar)
{
scriptVar->release ();
}
}
operator CScriptVar* () const
{
validate ();
return scriptVar;
}
CScriptVar* operator->() const
{
validate ();
return scriptVar;
}
CScriptVar* getVar () const
{
validate ();
return scriptVar;
}
CScriptVar* take ()
{
auto v = scriptVar;
scriptVar = nullptr;
return v;
}
void addChild (std::string_view name, ScriptObject&& obj)
{
validate ();
scriptVar->addChild (name, obj);
}
void addChild (std::string_view name, double d)
{
validate ();
scriptVar->addChild (name, new CScriptVar (d));
}
void addChild (std::string_view name, int64_t i)
{
validate ();
scriptVar->addChild (name, new CScriptVar (i));
}
void addChild (std::string_view name, int32_t i)
{
validate ();
scriptVar->addChild (name, new CScriptVar (static_cast<int64_t> (i)));
}
void addChild (std::string_view name, std::string_view value)
{
validate ();
scriptVar->addChild (name, new CScriptVar (TJS::string {value.data (), value.size ()}));
}
void addFunc (std::string_view name, std::function<void (CScriptVar*)>&& func)
{
validate ();
scriptVar->addChild (name, createJSFunction (std::move (func)));
}
void addFunc (std::string_view name, std::function<void (CScriptVar*)>&& func,
const std::initializer_list<std::string_view>& argNames)
{
validate ();
scriptVar->addChild (name, createJSFunction (std::move (func), argNames));
}
void addFunc (std::string_view name, std::string_view code)
{
validate ();
auto funcVar = new TJS::CScriptVar (TJS::TINYJS_BLANK_DATA, TJS::SCRIPTVAR_FUNCTION);
funcVar->setFunctionScript (code);
scriptVar->addChild (name, funcVar);
}
using OnDestroyFunc = std::function<void (CScriptVar*)>;
void setOnDestroy (OnDestroyFunc&& f)
{
validate ();
scriptVar->setLifeTimeObserver (OnDestroy::make (std::move (f)));
}
protected:
struct OnDestroy : TJS::IScriptVarLifeTimeObserver
{
static OnDestroy* make (OnDestroyFunc f) { return new OnDestroy (std::move (f)); }
private:
OnDestroy (OnDestroyFunc f) : func (std::move (f)) {}
void onDestroy (CScriptVar* var)
{
func (var);
delete this;
}
OnDestroyFunc func;
};
void validate () const
{
if (scriptVar == nullptr)
scriptVar = TJS::owning (new CScriptVar ());
}
mutable CScriptVar* scriptVar {nullptr};
};
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,97 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "scriptobject.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
//------------------------------------------------------------------------
struct UIDescScriptObject : ScriptObject
{
using StringList = std::list<const std::string*>;
using CScriptException = TJS::CScriptException;
UIDescScriptObject () = default;
UIDescScriptObject (IUIDescription* desc, TJS::CTinyJS* scriptContext)
{
using namespace std::literals;
addFunc ("colorNames"sv, [desc] (CScriptVar* var) {
StringList names;
desc->collectColorNames (names);
var->setReturnVar (createArrayFromNames (names));
});
addFunc ("fontNames"sv, [desc] (CScriptVar* var) {
StringList names;
desc->collectFontNames (names);
var->setReturnVar (createArrayFromNames (names));
});
addFunc ("bitmapNames"sv, [desc] (CScriptVar* var) {
StringList names;
desc->collectBitmapNames (names);
var->setReturnVar (createArrayFromNames (names));
});
addFunc ("gradientNames"sv, [desc] (CScriptVar* var) {
StringList names;
desc->collectGradientNames (names);
var->setReturnVar (createArrayFromNames (names));
});
addFunc ("controlTagNames"sv, [desc] (CScriptVar* var) {
StringList names;
desc->collectControlTagNames (names);
var->setReturnVar (createArrayFromNames (names));
});
addFunc ("getTagForName"sv,
[desc] (CScriptVar* var) {
auto param = var->getParameter ("name"sv);
if (!param)
{
throw CScriptException ("Expect 'name' argument for getTagForName ");
}
auto name = param->getString ();
auto tag = desc->getTagForName (name.data ());
var->setReturnVar (new CScriptVar (static_cast<int64_t> (tag)));
},
{"name"});
addFunc ("lookupTagName"sv,
[desc] (CScriptVar* var) {
auto param = var->getParameter ("tag"sv);
if (!param)
{
throw CScriptException ("Expect 'tag' argument for lookupTagName ");
}
if (!param->isInt ())
{
throw CScriptException ("Expect 'tag' argument to be an integer ");
}
if (auto tagName =
desc->lookupControlTagName (static_cast<int32_t> (param->getInt ())))
{
var->setReturnVar (new CScriptVar (std::string (tagName)));
}
},
{"tag"});
}
static CScriptVar* createArrayFromNames (const StringList& names)
{
auto array = new CScriptVar ();
array->setArray ();
int index = 0;
for (auto name : names)
{
array->addChild (std::to_string (index), new CScriptVar (*name));
++index;
}
return array;
}
};
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,209 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#include "viewscriptobject.h"
#include "converters.h"
#include "drawable.h"
#include "../uiscripting.h"
#include "../../uidescription/iviewfactory.h"
#include "../../uidescription/uiattributes.h"
#include "../../lib/cview.h"
#include "../../lib/controls/ccontrol.h"
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
using namespace std::literals;
using namespace TJS;
//------------------------------------------------------------------------
//------------------------------------------------------------------------
//------------------------------------------------------------------------
ViewScriptObject::ViewScriptObject (CView* view, IViewScriptObjectContext* context)
: view (view), context (context)
{
scriptVar->setLifeTimeObserver (this);
auto viewType = IViewFactory::getViewName (view);
scriptVar->addChild ("type"sv, new CScriptVar (std::string (viewType ? viewType : "unknown")));
addFunc ("setAttribute"sv,
[uiDesc = context->getUIDescription (), view] (CScriptVar* var) {
auto key = var->getParameter ("key"sv);
auto value = var->getParameter ("value"sv);
UIAttributes attr;
attr.setAttribute (key->getString ().data (), value->getString ().data ());
auto result = uiDesc->getViewFactory ()->applyAttributeValues (view, attr, uiDesc);
var->getReturnVar ()->setInt (result);
},
{"key", "value"});
addFunc ("getAttribute"sv,
[uiDesc = context->getUIDescription (), view] (CScriptVar* var) {
auto key = var->getParameter ("key"sv);
std::string result;
if (uiDesc->getViewFactory ()->getAttributeValue (view, key->getString ().data (),
result, uiDesc))
{
var->getReturnVar ()->setString (result);
}
else
{
var->getReturnVar ()->setUndefined ();
}
},
{"key"});
addFunc ("isTypeOf"sv,
[uiDesc = context->getUIDescription (), view] (CScriptVar* var) {
auto typeName = var->getParameter ("typeName"sv);
auto result =
uiDesc->getViewFactory ()->viewIsTypeOf (view, typeName->getString ().data ());
var->getReturnVar ()->setInt (result);
},
{"typeName"});
addFunc ("invalid"sv, [view] (CScriptVar* var) { view->invalid (); });
addFunc ("invalidRect"sv,
[view] (CScriptVar* var) {
auto rectVar = var->getParameter ("rect"sv);
if (!rectVar)
throw CScriptException ("Missing 'rect' argument in view.invalidRect(rect) ");
auto rect = fromScriptRect (*rectVar);
view->invalidRect (rect);
},
{"rect"});
addFunc ("getBounds"sv, [view] (CScriptVar* var) {
auto bounds = view->getViewSize ();
bounds.originize ();
var->setReturnVar (makeScriptRect (bounds));
});
addFunc ("getParent"sv, [view, context] (CScriptVar* var) {
auto parentView = view->getParentView ();
if (!parentView)
{
var->getReturnVar ()->setUndefined ();
return;
}
auto obj = context->addView (parentView);
vstgui_assert (obj);
var->setReturnVar (obj->getVar ());
obj->getVar ()->release ();
});
addFunc ("getControllerProperty"sv,
[view] (CScriptVar* var) {
auto viewController = getViewController (view, true);
auto controller = dynamic_cast<IScriptControllerExtension*> (viewController);
auto name = var->getParameter ("name"sv);
if (!controller || !name)
{
var->getReturnVar ()->setUndefined ();
return;
}
IScriptControllerExtension::PropertyValue value;
if (!controller->getProperty (view, name->getString (), value))
{
var->getReturnVar ()->setUndefined ();
return;
}
std::visit (
[&] (auto&& value) {
using T = std::decay_t<decltype (value)>;
if constexpr (std::is_same_v<T, int64_t>)
var->getReturnVar ()->setInt (value);
else if constexpr (std::is_same_v<T, double>)
var->getReturnVar ()->setDouble (value);
else if constexpr (std::is_same_v<T, std::string>)
var->getReturnVar ()->setString (value);
else if constexpr (std::is_same_v<T, std::nullptr_t>)
var->getReturnVar ()->setUndefined ();
},
value);
},
{"name"});
addFunc ("setControllerProperty"sv,
[view] (CScriptVar* var) {
auto viewController = getViewController (view, true);
auto controller = dynamic_cast<IScriptControllerExtension*> (viewController);
auto name = var->getParameter ("name"sv);
auto value = var->getParameter ("value"sv);
if (!controller || !name || !value || !(value->isNumeric () || value->isString ()))
{
var->getReturnVar ()->setUndefined ();
return;
}
IScriptControllerExtension::PropertyValue propValue;
if (value->isInt ())
propValue = value->getInt ();
else if (value->isDouble ())
propValue = value->getDouble ();
else if (value->isString ())
propValue = value->getString ().data ();
auto result = controller->setProperty (view, name->getString (), propValue);
var->getReturnVar ()->setInt (result);
},
{"name", "value"});
if (auto control = dynamic_cast<CControl*> (view))
{
addFunc ("setValue"sv,
[control] (CScriptVar* var) {
auto value = var->getParameter ("value"sv);
if (value->isNumeric ())
{
auto oldValue = control->getValue ();
control->setValue (static_cast<float> (value->getDouble ()));
if (oldValue != control->getValue ())
control->valueChanged ();
}
},
{"value"});
addFunc ("getValue"sv, [control] (CScriptVar* var) {
var->getReturnVar ()->setDouble (control->getValue ());
});
addFunc ("setValueNormalized"sv,
[control] (CScriptVar* var) {
auto value = var->getParameter ("value"sv);
if (value->isNumeric ())
{
auto oldValue = control->getValue ();
control->setValueNormalized (static_cast<float> (value->getDouble ()));
if (oldValue != control->getValue ())
control->valueChanged ();
}
},
{"value"});
addFunc ("getValueNormalized"sv, [control] (CScriptVar* var) {
var->getReturnVar ()->setDouble (control->getValueNormalized ());
});
addFunc ("beginEdit"sv, [control] (CScriptVar* var) { control->beginEdit (); });
addFunc ("endEdit"sv, [control] (CScriptVar* var) { control->endEdit (); });
addFunc ("getMinValue"sv, [control] (CScriptVar* var) {
var->getReturnVar ()->setDouble (control->getMin ());
});
addFunc ("getMaxValue"sv, [control] (CScriptVar* var) {
var->getReturnVar ()->setDouble (control->getMax ());
});
addFunc ("getTag"sv, [control] (CScriptVar* var) {
var->getReturnVar ()->setInt (control->getTag ());
});
}
if (auto drawable = dynamic_cast<JavaScriptDrawable*> (view))
drawable->setup (this);
}
//------------------------------------------------------------------------
ViewScriptObject::~ViewScriptObject () noexcept
{
if (scriptVar)
scriptVar->setLifeTimeObserver (nullptr);
}
//------------------------------------------------------------------------
void ViewScriptObject::onDestroy (CScriptVar* v)
{
v->setLifeTimeObserver (nullptr);
scriptVar = nullptr;
if (context)
context->removeView (view);
}
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI
@@ -0,0 +1,51 @@
// This file is part of VSTGUI. It is subject to the license terms
// in the LICENSE file found in the top-level directory of this
// distribution and at http://github.com/steinbergmedia/vstgui/LICENSE
#pragma once
#include "scriptobject.h"
#include "../../lib/vstguifwd.h"
#include "../../uidescription/iuidescription.h"
#include <unordered_map>
//------------------------------------------------------------------------
namespace VSTGUI {
namespace ScriptingInternal {
struct IViewScriptObjectContext;
//------------------------------------------------------------------------
struct ViewScriptObject : ScriptObject,
TJS::IScriptVarLifeTimeObserver
{
ViewScriptObject (CView* view, IViewScriptObjectContext* context);
~ViewScriptObject () noexcept;
IViewScriptObjectContext* getContext () const { return context; }
void onDestroy (CScriptVar* v) override;
private:
CView* view {nullptr};
IViewScriptObjectContext* context {nullptr};
};
using ViewScriptMap = std::unordered_map<CView*, std::unique_ptr<ViewScriptObject>>;
//------------------------------------------------------------------------
struct IViewScriptObjectContext
{
virtual ~IViewScriptObjectContext () = default;
virtual IUIDescription* getUIDescription () const = 0;
virtual ViewScriptObject* addView (CView* view) = 0;
virtual ViewScriptMap::iterator removeView (CView* view) = 0;
virtual ScriptObject evalScript (std::string_view script) noexcept = 0;
virtual TJS::CScriptVar* getRoot () const = 0;
};
//------------------------------------------------------------------------
} // ScriptingInternal
} // VSTGUI