diff --git a/vstgui/uidescription-scripting/detail/drawable.cpp b/vstgui/uidescription-scripting/detail/drawable.cpp index a65aad626..5d35d8abe 100644 --- a/vstgui/uidescription-scripting/detail/drawable.cpp +++ b/vstgui/uidescription-scripting/detail/drawable.cpp @@ -49,9 +49,9 @@ void JavaScriptDrawable::onDraw (CDrawContext* context, const CRect& rect, const auto rectVar = makeScriptRect (rect); auto scriptRoot = scriptContext->getRoot (); - ScriptAddChildScoped scs (*scriptRoot, "view", scriptObject->getVar ()); - ScriptAddChildScoped scs2 (*scriptRoot, "context", drawContext.getVar ()); - ScriptAddChildScoped scs3 (*scriptRoot, "rect", rectVar.getVar ()); + ScriptAddChildScoped scs (*scriptRoot, "view", *scriptObject); + ScriptAddChildScoped scs2 (*scriptRoot, "context", drawContext); + ScriptAddChildScoped scs3 (*scriptRoot, "rect", rectVar); scriptContext->evalScript ("view.draw(context, rect);"sv); drawContext.setDrawContext (nullptr, nullptr); diff --git a/vstgui/uidescription-scripting/detail/drawcontextobject.cpp b/vstgui/uidescription-scripting/detail/drawcontextobject.cpp index b8251792c..1a976eaa1 100644 --- a/vstgui/uidescription-scripting/detail/drawcontextobject.cpp +++ b/vstgui/uidescription-scripting/detail/drawcontextobject.cpp @@ -468,7 +468,7 @@ struct DrawContextObject::Impl if (auto path = owned (context->createRoundRectGraphicsPath (rect, radius))) { GraphicsPathScriptObject obj (path); - var->setReturnVar (obj.getVar ()); + var->setReturnVar (obj); } } @@ -479,7 +479,7 @@ struct DrawContextObject::Impl if (auto path = owned (context->createGraphicsPath ())) { GraphicsPathScriptObject obj (path); - var->setReturnVar (obj.getVar ()); + var->setReturnVar (obj); } } @@ -495,7 +495,7 @@ struct DrawContextObject::Impl CGradient::create (startColorPosition, endColorPosition, startColor, endColor))) { GradientScriptObject obj (gradient, uiDesc); - var->setReturnVar (obj.getVar ()); + var->setReturnVar (obj); } } diff --git a/vstgui/uidescription-scripting/detail/scriptobject.h b/vstgui/uidescription-scripting/detail/scriptobject.h index 86e4f333f..cbab0e5ff 100644 --- a/vstgui/uidescription-scripting/detail/scriptobject.h +++ b/vstgui/uidescription-scripting/detail/scriptobject.h @@ -115,53 +115,102 @@ struct ScriptObject } } - CScriptVar* getVar () const { return scriptVar; } + 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) { - scriptVar->addChild (name, obj.getVar ()); + 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 (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&& func) { + validate (); scriptVar->addChild (name, createJSFunction (std::move (func))); } void addFunc (std::string_view name, std::function&& func, const std::initializer_list& 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 setOnDestroy (OnDestroyFunc&& f) + { + validate (); + scriptVar->setLifeTimeObserver (OnDestroy::make (std::move (f))); + } + protected: - CScriptVar* scriptVar {nullptr}; + 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}; }; //------------------------------------------------------------------------ diff --git a/vstgui/uidescription-scripting/detail/viewscriptobject.cpp b/vstgui/uidescription-scripting/detail/viewscriptobject.cpp index a7d32d2d6..a3c3c4a29 100644 --- a/vstgui/uidescription-scripting/detail/viewscriptobject.cpp +++ b/vstgui/uidescription-scripting/detail/viewscriptobject.cpp @@ -73,7 +73,7 @@ ViewScriptObject::ViewScriptObject (CView* view, IViewScriptObjectContext* conte addFunc ("getBounds"sv, [view] (CScriptVar* var) { auto bounds = view->getViewSize (); bounds.originize (); - var->setReturnVar (makeScriptRect (bounds).getVar ()); + var->setReturnVar (makeScriptRect (bounds)); }); addFunc ("getParent"sv, [view, context] (CScriptVar* var) { auto parentView = view->getParentView (); diff --git a/vstgui/uidescription-scripting/uiscripting.cpp b/vstgui/uidescription-scripting/uiscripting.cpp index 7e8016c09..c2f257504 100644 --- a/vstgui/uidescription-scripting/uiscripting.cpp +++ b/vstgui/uidescription-scripting/uiscripting.cpp @@ -57,37 +57,27 @@ class ScriptContext : public IScriptContextInternal }; //------------------------------------------------------------------------ -struct TimerScriptObject : CScriptVar +struct TimerScriptObject : ScriptObject { template TimerScriptObject (uint64_t fireTime, CScriptVar* _callback, Proc timerProc) - : CScriptVar (TINYJS_BLANK_DATA, SCRIPTVAR_OBJECT), callback (owning (_callback)) { - timer = makeOwned ( - [timerProc, this] (auto) { - if (!timerProc (callback)) + auto cb = owning (_callback); + auto t = makeOwned ( + [timerProc, cb] (auto timer) { + if (!timerProc (cb)) timer->stop (); }, static_cast (fireTime), false); - addChild ("invalid"sv, createJSFunction ([this] (auto) { timer = nullptr; })); - addChild ("start"sv, createJSFunction ([this] (auto) { - if (timer) - timer->start (); - })); - addChild ("stop"sv, createJSFunction ([this] (auto) { - if (timer) - timer->stop (); - })); - } - ~TimerScriptObject () noexcept - { - timer = nullptr; - callback->release (); + scriptVar->setCustomData (t); + addFunc ("invalid"sv, [t] (auto v) mutable { + t = nullptr; + v->setCustomData (nullptr); + }); + addFunc ("start"sv, [t] (auto) { t->start (); }); + addFunc ("stop"sv, [t] (auto) { t->stop (); }); + setOnDestroy ([cb] (auto) { cb->release (); }); } - -private: - SharedPointer timer; - CScriptVar* callback; }; //------------------------------------------------------------------------ @@ -128,7 +118,7 @@ struct ScriptContext::Impl : ViewListenerAdapter, registerFunctions (jsContext.get ()); registerMathFunctions (jsContext.get ()); - jsContext->getRoot ()->addChild ("uiDesc"sv, uiDescObject.getVar ()); + jsContext->getRoot ()->addChild ("uiDesc"sv, uiDescObject); jsContext->addNative ( "function createTimer(context, fireTime, callback)"sv, [this] (CScriptVar* var) { @@ -144,15 +134,14 @@ struct ScriptContext::Impl : ViewListenerAdapter, throw CScriptException ( "Expect function as second parameter on timer creation"); } - auto timerObj = new TimerScriptObject ( + auto timerObj = TimerScriptObject ( fireTime->getInt (), callback->deepCopy (), [this, context] (auto callback) { using namespace ScriptingInternal; ScriptAddChildScoped scs (*jsContext->getRoot (), "timerContext", context); return evalScript (callback, "timerCallback (timerContext); ", "timerCallback"); }); - var->setReturnVar (owning (timerObj)); - timerObj->release (); + var->setReturnVar (timerObj); }); jsContext->addNative ( "function iterateSubViews(view, context, callback)"sv, [this] (CScriptVar* var) { @@ -320,7 +309,7 @@ struct ScriptContext::Impl : ViewListenerAdapter, callWhenScriptHasFunction (view, "onSizeChanged"sv, [&] (auto This, auto& obj) { auto newSize = view->getViewSize (); ScriptObject newSizeObject = ScriptingInternal::makeScriptRect (newSize); - ScriptAddChildScoped scs (*jsContext->getRoot (), "newSize", newSizeObject.getVar ()); + ScriptAddChildScoped scs (*jsContext->getRoot (), "newSize", newSizeObject); static constexpr auto script = R"(view.onSizeChanged(view, newSize);)"sv; This->evalScript (obj->getVar (), script); }); @@ -385,7 +374,7 @@ struct ScriptContext::Impl : ViewListenerAdapter, void checkEventConsumed (ScriptObject& obj, Event& event) { - if (auto consume = obj.getVar ()->findChild ("consumed")) + if (auto consume = obj->findChild ("consumed")) { if (consume->getVar ()->isInt () && consume->getVar ()->getInt ()) event.consumed = true; @@ -395,7 +384,7 @@ struct ScriptContext::Impl : ViewListenerAdapter, void callEventFunction (CScriptVar* var, Event& event, std::string_view script) noexcept { auto scriptEvent = ScriptingInternal::makeScriptEvent (event); - ScriptAddChildScoped scs (*jsContext->getRoot (), "event", scriptEvent.getVar ()); + ScriptAddChildScoped scs (*jsContext->getRoot (), "event", scriptEvent); evalScript (var, script); checkEventConsumed (scriptEvent, event); } @@ -477,8 +466,8 @@ struct ScriptContext::Impl : ViewListenerAdapter, { callWhenScriptHasFunction (control, "onValueChanged"sv, [&] (auto This, auto& obj) { ScriptObject controlValue; - controlValue.getVar ()->setDouble (control->getValue ()); - ScriptAddChildScoped scs (*jsContext->getRoot (), "value", controlValue.getVar ()); + controlValue->setDouble (control->getValue ()); + ScriptAddChildScoped scs (*jsContext->getRoot (), "value", controlValue); static constexpr auto script = R"(view.onValueChanged(view, value);)"sv; This->evalScript (obj->getVar (), script); });