diff --git a/Plugins/Sheets/Coyote and Crow/FillablePDF/1.lfm b/Plugins/Sheets/Coyote and Crow/FillablePDF/1.lfm
new file mode 100644
index 00000000..38e055f5
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/FillablePDF/1.lfm
@@ -0,0 +1,505 @@
+
+
diff --git a/Plugins/Sheets/Coyote and Crow/FillablePDF/2.lfm b/Plugins/Sheets/Coyote and Crow/FillablePDF/2.lfm
new file mode 100644
index 00000000..7ceb72e2
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/FillablePDF/2.lfm
@@ -0,0 +1,45 @@
+
+
diff --git a/Plugins/Sheets/Coyote and Crow/FillablePDF/CoyoteAndCrow.lfm b/Plugins/Sheets/Coyote and Crow/FillablePDF/CoyoteAndCrow.lfm
new file mode 100644
index 00000000..fd7e45ed
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/FillablePDF/CoyoteAndCrow.lfm
@@ -0,0 +1,18 @@
+
+
diff --git a/Plugins/Sheets/Coyote and Crow/FillablePDF/images/1.png b/Plugins/Sheets/Coyote and Crow/FillablePDF/images/1.png
new file mode 100644
index 00000000..07b33b29
Binary files /dev/null and b/Plugins/Sheets/Coyote and Crow/FillablePDF/images/1.png differ
diff --git a/Plugins/Sheets/Coyote and Crow/FillablePDF/images/2.png b/Plugins/Sheets/Coyote and Crow/FillablePDF/images/2.png
new file mode 100644
index 00000000..7104922c
Binary files /dev/null and b/Plugins/Sheets/Coyote and Crow/FillablePDF/images/2.png differ
diff --git a/Plugins/Sheets/Coyote and Crow/module.xml b/Plugins/Sheets/Coyote and Crow/module.xml
new file mode 100644
index 00000000..c1b9b319
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/module.xml
@@ -0,0 +1,20 @@
+
+
+
+ app.firecast.plugins.coyoteandcrow
+
+ 1.0
+
+
+
+ Coyote & Crow
+ Modelo de ficha para Coyote & Crow
+ AlyssonRPG
+ https://firecast.app
+ alyssonrpg@gmail.com
+
+
+
+ Character sheet for Coyote & Crow
+
+
diff --git a/Plugins/Sheets/Coyote and Crow/output/Coyote and Crow.rpk b/Plugins/Sheets/Coyote and Crow/output/Coyote and Crow.rpk
new file mode 100644
index 00000000..675f6efb
Binary files /dev/null and b/Plugins/Sheets/Coyote and Crow/output/Coyote and Crow.rpk differ
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/README.md b/Plugins/Sheets/Coyote and Crow/sdk/README.md
new file mode 100644
index 00000000..dc558bad
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/README.md
@@ -0,0 +1,10 @@
+# API do SDK 3 (Software Development Kit)
+
+O motor de funcionamento do SDK3 é dividido entre duas entidades:
+
+- Código binário em pascal, embutido no rrpg.exe ou FirecastMobile
+- Código lua que faz a ponte entre seu código .lua e o código binário.
+
+Esta pasta contém o código lua que faz a ponte entre os dois mundos!
+
+Observação: Quando você realiza o comando "rdk p", o conteúdo desta pasta é copiado para a subpasta /sdk do seu projeto.
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/async.lua b/Plugins/Sheets/Coyote and Crow/sdk/async.lua
new file mode 100644
index 00000000..a7b78d8a
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/async.lua
@@ -0,0 +1,486 @@
+local Log = require("log.lua");
+
+local _ASYNC_EXEC_AWAIT_CO_RET = "_co:await";
+local _ASYNC_EXEC_IDLE_COROUTINE_RET = "_co:idle";
+
+Async = {};
+Async.Promise = {};
+
+Promise = Async.Promise;
+
+Async._ASYNC_EXEC_AWAIT_CO_RET = _ASYNC_EXEC_AWAIT_CO_RET;
+
+local _asyncExecution = {idleCoroutines = {},
+ idleCoroutinesCount = 0,
+ maxIdleCoroutines = 8};
+
+function Async.haveNativeBackendSupport()
+ return true;
+end;
+
+--- Base Promise MetaTable
+
+local BasePromiseMetatable = {}
+BasePromiseMetatable.__index = BasePromiseMetatable;
+
+function BasePromiseMetatable:thenFinally(callback)
+ local wrappedContinuationCallback =
+ function(ignoredParameter)
+ if callback ~= nil then
+ return callback();
+ end;
+ end;
+
+ return self:thenDo(wrappedContinuationCallback, wrappedContinuationCallback);
+end;
+
+function BasePromiseMetatable:onSuccess(callback)
+ return self:thenDo(callback, nil);
+end;
+
+function BasePromiseMetatable:onError(callback)
+ return self:thenDo(nil, callback);
+end;
+
+function BasePromiseMetatable:thenResolve(promiseResolution)
+ return self:thenDo(
+ function(...)
+ return promiseResolution:setSuccess(...);
+ end,
+
+ function(errorMsg)
+ return promiseResolution:setFailure(errorMsg);
+ end);
+end;
+
+function BasePromiseMetatable:unwrap()
+ local ret = table.pack(self:peek());
+
+ if ret[1] then
+ if ret[2] then
+ return table.unpack(ret, 3);
+ else
+ reraise(ret[3]);
+ end;
+ else
+ return self;
+ end;
+end;
+
+function BasePromiseMetatable:await()
+ return Async.await(self);
+end;
+
+function BasePromiseMetatable:pawait()
+ return Async.pawait(self);
+end;
+
+--- Concrete Promise MetaTable
+
+local PromiseMetatable = {};
+setmetatable(PromiseMetatable, BasePromiseMetatable);
+PromiseMetatable.__index = PromiseMetatable;
+
+function PromiseMetatable:peek()
+ if _async_promise_peek ~= nil then
+ return _async_promise_peek(self.handle);
+ else
+ return false;
+ end;
+end;
+
+function PromiseMetatable:thenDo(successCallback, errorCallback)
+ local thenDoHandle = _async_promise_thenDo(self.handle, successCallback, errorCallback);
+ return Promise.wrap(thenDoHandle);
+end;
+
+-- PromiseResolution Metatable
+
+local PromiseResolutionMetatable = {};
+PromiseResolutionMetatable.__index = PromiseResolutionMetatable;
+
+function PromiseResolutionMetatable:setSuccess(...)
+ return _async_promiseResolution_setSuccess(self.handle, ...);
+end;
+
+function PromiseResolutionMetatable:setFailure(...)
+ return _async_promiseResolution_setFailure(self.handle, ...);
+end;
+
+function PromiseResolutionMetatable:setUserAborted()
+ return _async_promiseResolution_setUserAborted(self.handle);
+end;
+
+-- Promises Creation
+
+function Promise.__newBaseStubPromise()
+ local p = {}
+ setmetatable(p, BasePromiseMetatable);
+ return p;
+end;
+
+function Promise.__newStubSuccessPromise(data)
+ local p = Promise.__newBaseStubPromise();
+ local previousThenDo = p.thenDo;
+
+ function p:peek()
+ return true, true, data;
+ end;
+
+ function p:thenDo(successCallback, errorCallback)
+ if type(successCallback) == "function" then
+ successCallback(data);
+ end;
+
+ return previousThenDo(p, successCallback, errorCallback)
+ end;
+
+ return p;
+end;
+
+function Promise.__newStubFailedPromise(errorMsg)
+ local p = Promise.__newBaseStubPromise();
+ local previousThenDo = p.thenDo;
+
+ function p:peek()
+ return true, false, errorMsg;
+ end;
+
+ function p:thenDo(successCallback, errorCallback)
+ if type(errorCallback) == "function" then
+ errorCallback(errorMsg);
+ end;
+
+ return previousThenDo(p, successCallback, errorCallback)
+ end;
+
+ return p;
+end;
+
+function Promise.__newStubPendingPromise()
+ local p = Promise.__newBaseStubPromise();
+
+ p.__resolved = false;
+
+ -- Promise interface
+
+ function p:peek()
+ if self.__resolved then
+ return true, p.__success, table.unpack(p.__data);
+ else
+ return false;
+ end;
+ end;
+
+ function p:thenDo(successCallback, errorCallback)
+ if self.__resolved then
+ if self.__success and type(successCallback) == "function" then
+ successCallback(table.unpack(self.__data));
+ elseif not self.__success and type(errorCallback) == "function" then
+ errorCallback(table.unpack(self.__data));
+ end;
+ else
+ if type(errorCallback) == "function" then
+ errorCallback("No API Support");
+ end;
+ end;
+
+ return Async.Promise.failed("No API Support");
+ end;
+
+ -- PromiseResolution interface
+
+ function p:setSuccess(...)
+ if not self.__resolved then
+ self.__resolved = true;
+ self.__success = true;
+ self.__data = table.pack(...);
+ else
+ return false;
+ end;
+ end;
+
+ function p:setFailure(errorMsg)
+ if not self.__resolved then
+ self.__resolved = true;
+ self.__success = false;
+ self.__data = {errorMsg};
+ else
+ return false;
+ end;
+ end;
+
+ function p:setUserAborted()
+ return self:setFailure("UserAbortedException");
+ end;
+
+ return p;
+end;
+
+function Promise.wrap(handle)
+ local p = {}
+ setmetatable(p, PromiseMetatable);
+ p.handle = handle;
+ return p;
+end;
+
+function Promise.wrapPromiseResolution(handle)
+ local r = {};
+ setmetatable(r, PromiseResolutionMetatable);
+ r.handle = handle;
+
+ return r;
+end;
+
+function _asyncExecution.__asyncExecAwaitPromise(co, promise)
+ promise:thenDo(
+ function (...)
+ _asyncExecution.resume(co, true, ...);
+ end,
+
+ function (errorMsg)
+ _asyncExecution.resume(co, false, errorMsg);
+ end);
+end;
+
+function _asyncExecution.resume(co, ...)
+ local retData = table.pack(coroutine.resume(co, ...));
+
+ if not retData[1] then
+ Log.e("Async.execute", "coroutine execution failure: " .. tostring(retData[2]));
+ else
+ if retData[2] == _ASYNC_EXEC_IDLE_COROUTINE_RET then
+ _asyncExecution.releaseIdleCoroutine(co);
+ elseif retData[2] == _ASYNC_EXEC_AWAIT_CO_RET then
+ local r, errorMessage = pcall(_asyncExecution.__asyncExecAwaitPromise, co, retData[3]);
+
+ if not r then
+ _asyncExecution.resume(co, false, errorMessage);
+ end;
+ elseif coroutine.status(co) == "dead" then
+ Log.e("Async.execute", "Coroutine died before expected");
+ else
+ Log.e("Async.execute", "Unhandled coroutine.yield case: " .. tostring(retData[2]));
+ end;
+ end;
+end;
+
+function _asyncExecution.entrypoint(mustExecute, fn, arguments, promiseResolution)
+ while mustExecute do
+ local ret = table.pack(pcall(fn, table.unpack(arguments)));
+
+ if ret[1] then
+ promiseResolution:setSuccess(table.unpack(ret, 2));
+ else
+ promiseResolution:setFailure(ret[2]);
+ Log.w("Async.execute", tostring(ret[2]));
+ require("dialogs.lua").showErrorMessage(ret[2]);
+ end;
+
+ fn, arguments, promiseResolution, ret = nil, nil, nil, nil;
+
+ -- fn, arguments, promiseResolution and ret are used below as parameter just to avoid rdk command line linter warning
+ mustExecute, fn, arguments, promiseResolution = coroutine.yield(_ASYNC_EXEC_IDLE_COROUTINE_RET, fn and arguments and promiseResolution and ret);
+ end;
+end;
+
+function _asyncExecution.createIdleCoroutine()
+ return coroutine.create(_asyncExecution.entrypoint);
+end;
+
+function _asyncExecution.acquireIdleCoroutine()
+ if _asyncExecution.idleCoroutinesCount > 0 then
+ local co = _asyncExecution.idleCoroutines[_asyncExecution.idleCoroutinesCount];
+ _asyncExecution.idleCoroutinesCount = _asyncExecution.idleCoroutinesCount - 1;
+ return co;
+ else
+ return _asyncExecution.createIdleCoroutine();
+ end;
+end;
+
+function _asyncExecution.releaseIdleCoroutine(co)
+ if _asyncExecution.idleCoroutinesCount < _asyncExecution.maxIdleCoroutines then
+ _asyncExecution.idleCoroutinesCount = _asyncExecution.idleCoroutinesCount + 1;
+ _asyncExecution.idleCoroutines[_asyncExecution.idleCoroutinesCount] = co;
+ else
+ coroutine.resume(co, false, nil, nil, nil);
+ end;
+end;
+
+-- Exported API to the Firecast Executable
+
+function __async_start_execution(fn, ...)
+ return Async.execute(fn, ...);
+end;
+
+-- Async.Promise public API
+
+function Promise.resolved(...)
+ if Async.haveNativeBackendSupport() then
+ return Promise.wrap(_async_promise_newResolved(...));
+ else
+ return Promise.__newStubSuccessPromise(...);
+ end;
+end;
+
+function Promise.withError(errorMsg)
+ if Async.haveNativeBackendSupport() then
+ return Promise.wrap(_async_promise_newWithException(errorMsg));
+ else
+ return Promise.__newStubFailedPromise(errorMsg);
+ end;
+end;
+
+function Promise.toResolve()
+ local promiseHandle, promiseResolutionHandle = _async_promise_newToResolve();
+
+ local promise = Promise.wrap(promiseHandle);
+ local promiseResolution = Promise.wrapPromiseResolution(promiseResolutionHandle);
+
+ return promise, promiseResolution;
+end;
+
+function Promise.toHandle(promise, successCallback, failureCallback)
+ assert(promise ~= nil);
+
+ local outerPromise, outerResolution = Promise.toResolve();
+
+ promise:thenDo(
+ function (...)
+ if successCallback ~= nil then
+ local ret = table.pack(pcall(successCallback, ...));
+
+ if ret[1] then
+ outerResolution:setSuccess(table.unpack(ret, 2));
+ else
+ outerResolution:setFailure(ret[2]);
+ end;
+ else
+ outerResolution:setSuccess(...);
+ end;
+ end,
+
+ function (originalErrorMsg)
+ if failureCallback ~= nil then
+ local ret = table.pack(pcall(failureCallback, originalErrorMsg));
+
+ if ret[1] then
+ outerResolution:setSuccess(table.unpack(ret, 2));
+ else
+ outerResolution:setFailure(ret[2]);
+ end;
+ else
+ outerResolution:setFailure(originalErrorMsg);
+ end;
+ end);
+
+ return outerPromise;
+end;
+
+function Promise.isPromise(value)
+ return (type(value) == "table") and
+ (value.thenDo ~= nil) and
+ (value.onError ~= nil) and
+ (value.await ~= nil);
+end;
+
+function Promise.all(...)
+ local normalized = {};
+ local argsTable = table.pack(...);
+
+ for i = 1, #argsTable, 1 do
+ local item = argsTable[i];
+
+ if Promise.isPromise(item) then
+ normalized[#normalized + 1] = item.handle;
+ else
+ for j = 1, #item, 1 do
+ local subItem = item[j];
+
+ if Promise.isPromise(subItem) then
+ normalized[#normalized + 1] = subItem.handle;
+ end;
+ end;
+ end;
+ end;
+
+ return Promise.wrap(_async_promise_newAll(normalized));
+end;
+
+-- Async library public API
+
+function Async.await(promise)
+ if (coroutine.isyieldable ~= nil) and not coroutine.isyieldable() then
+ error("Is not possible to await outside a coroutine. Please consider using the Async.execute function");
+ end;
+
+ if not Promise.isPromise(promise) then
+ return promise;
+ end;
+
+ local ret = table.pack(promise:peek());
+
+ if ret[1] then
+ if ret[2] then
+ if #ret >= 3 then
+ return table.unpack(ret, 3);
+ else
+ return nil;
+ end;
+ else
+ local traceMessage = ret[3] .. "\n" .. debug.traceback(coroutine.running(), nil, 2);
+ reraise(traceMessage);
+ end;
+ end;
+
+ ret = table.pack(coroutine.yield(_ASYNC_EXEC_AWAIT_CO_RET, promise));
+
+ if ret[1] then
+ if #ret >= 2 then
+ return table.unpack(ret, 2);
+ else
+ return nil;
+ end;
+ else
+ local traceMessage = ret[2] .. "\n" .. debug.traceback(coroutine.running(), nil, 2);
+ reraise(traceMessage);
+ end;
+end;
+
+function Async.pawait(promise)
+ if (coroutine.isyieldable ~= nil) and not coroutine.isyieldable() then
+ error("Is not possible to pawait outside a coroutine. Please consider using the Async.execute function");
+ end;
+
+ if not Promise.isPromise(promise) then
+ return true, promise;
+ end;
+
+ local ret = table.pack(promise:peek());
+
+ if ret[1] then
+ return table.unpack(ret, 2);
+ else
+ return coroutine.yield(_ASYNC_EXEC_AWAIT_CO_RET, promise);
+ end;
+end;
+
+function Async.execute(fn, ...)
+ local co = _asyncExecution.acquireIdleCoroutine();
+ local promise, resolution = Async.Promise.pending();
+
+ _asyncExecution.resume(co, true, fn, table.pack(...), resolution);
+
+ return promise;
+end;
+
+Promise.withException = Promise.withError;
+Promise.failed = Promise.withError;
+Promise.pending = Promise.toResolve;
+Promise.succeeded = Promise.resolved;
+Promise.resolve = Promise.resolved;
+Promise.reject = Promise.withError;
+await = Async.await;
+pawait = Async.pawait;
+
+return Async
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/audio.lua b/Plugins/Sheets/Coyote and Crow/sdk/audio.lua
new file mode 100644
index 00000000..7f84d685
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/audio.lua
@@ -0,0 +1,2 @@
+Audio = require("delayedLoad.dlua").new("audioCore.dlua");
+return Audio;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/audioCore.dlua b/Plugins/Sheets/Coyote and Crow/sdk/audioCore.dlua
new file mode 100644
index 00000000..e42afa46
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/audioCore.dlua
@@ -0,0 +1,194 @@
+local Async = require("async.lua");
+local Objs = require("rrpgObjs.lua");
+
+local audioLib = Objs.objectFromHandle(_obj_newObject("TRRPGAudioLibWrapper"));
+assert(audioLib ~= nil);
+
+if audioLib.props == nil then
+ audioLib.props = {};
+end;
+
+-- AudioStream Class wrapper
+
+function audioLib._newAudioStreamWrapperFromStreamReader(streamReader)
+ local objHandle = _obj_invokeEx(audioLib.handle, 'CreateAudioStream', streamReader);
+ return audioLib._newAudioStreamWrapperFromObjectHandle(objHandle);
+end;
+
+function audioLib._newAudioStreamWrapperFromObjectHandle(objHandle)
+ local stream = Objs.objectFromHandle(objHandle);
+ stream.props = stream.props or {};
+ stream.eves = stream.eves or {};
+
+ function stream:getLength()
+ return _obj_invokeEx(self.handle, "GetLengthInSecs");
+ end;
+
+ function stream:getPosition()
+ return _obj_invokeEx(self.handle, "GetPositionInSecs");
+ end;
+
+ function stream:setPosition(newPosition)
+ return _obj_invokeEx(self.handle, "SetPositionInSecs", newPosition);
+ end;
+
+ function stream:waitEOF()
+ return Async.Promise.wrap(_obj_invokeEx(self.handle, 'WaitEOF'));
+ end;
+
+ stream.props["enabled"] = {readProp="Enabled", writeProp="Enabled", tipo="bool"};
+ stream.props["eof"] = {readProp="IsEOF", tipo="bool"};
+ stream.props["length"] = {getter="getLength", tipo="float"};
+ stream.props["position"] = {getter="getPosition", setter="setPosition", tipo="float"};
+ stream.props["volume"] = {readProp="Volume", writeProp="Volume", tipo="float"};
+
+ stream.eves["onEOF"] = "";
+ return stream;
+end;
+
+-- AudioTrack Class wrapper
+
+function audioLib._audioTrackWrapperFromHandle(audioStream, objHandle)
+ local track = Objs.objectFromHandle(objHandle);
+ track.props = track.props or {};
+ track.eves = track.eves or {};
+
+ rawset(track, "_attachedStream", audioStream);
+
+ function track:getAudioStream()
+ return rawget(self, "_attachedStream");
+ end;
+
+ function track:remove()
+ return Async.Promise.wrap(_obj_invokeEx(self.handle, 'AsyncRemoveTrack'));
+ end;
+
+ function track:waitRemoval()
+ return Async.Promise.wrap(_obj_invokeEx(self.handle, 'WaitRemoval'));
+ end;
+
+ track.props["audioStream"] = {getter = "getAudioStream", tipo="table"};
+ track.props["removed"] = {readProp = "Removed", tipo="bool"};
+
+ track.eves["onRemoved"] = "";
+ return track;
+end;
+
+function audioLib._newNullAudioTrackWrapper(audioStream)
+ local track = Objs.newPureLuaObject();
+ track.props = {};
+
+ rawset(track, "audioStream", audioStream);
+ rawset(track, "removed", true);
+
+ function track:remove()
+ return Async.Promise.resolved();
+ end;
+
+ function track:waitRemoval()
+ return Async.Promise.resolved();
+ end;
+
+ return track;
+end;
+
+-- AudioPlayer Class internal utility
+
+local function __keepStrongReferenceToTrackUntilRemoved(track)
+ track:waitRemoval():thenFinally(
+ function()
+ track = nil;
+ end)
+end;
+
+local function __keepStrongReferenceToTrackPromiseUntilRemoved(trackPromise)
+ trackPromise:thenDo(
+ function (track)
+ __keepStrongReferenceToTrackUntilRemoved(track);
+ end);
+end;
+
+-- AudioPlayer Class wrapper
+
+function audioLib._audioPlayerWrapperFromHandle(objHandle)
+ local sa = Objs.objectFromHandle(objHandle);
+
+ function sa:asyncAddTrack(audioStream, params)
+ local trackHandlePromise = Async.Promise.wrap(_obj_invokeEx(self.handle, 'AsyncCreateAudioTrack', audioStream.handle, params));
+
+ return trackHandlePromise:thenDo(
+ function(trackHandle)
+ return audioLib._audioTrackWrapperFromHandle(audioStream, trackHandle);
+ end);
+ end;
+
+ function sa:play(source, volume)
+ local streamPromise = audioLib.asyncLoadAudioStream(source);
+
+ local trackPromise = streamPromise:thenDo(
+ function(audioStream)
+ if type(volume) == "number" then
+ audioStream.volume = volume;
+ end;
+
+ local trackPromise = self:asyncAddTrack(audioStream, {autoRemoveOnEOF=true});
+ __keepStrongReferenceToTrackPromiseUntilRemoved(trackPromise);
+ return trackPromise;
+ end);
+
+ return trackPromise;
+ end;
+
+ return sa;
+end;
+
+function audioLib._newNullAudioPlayerWrapper(errorMessage)
+ local sa = Objs.newPureLuaObject();
+
+ if errorMessage == nil then
+ errorMessage = "No API Support";
+ end;
+
+ function sa:asyncAddTrack(audioStream, params)
+ return Async.Promise.failed(errorMessage);
+ end;
+
+ function sa:play(source, volume)
+ return Async.Promise.failed(errorMessage);
+ end;
+
+ return sa;
+end;
+
+-- AudioLib public API
+
+function audioLib.asyncLoadAudioStream(source)
+ local loadPromise = Async.Promise.wrap(_obj_invokeEx(audioLib.handle, 'AsyncLoadStreamReader', source));
+
+ return loadPromise:thenDo(
+ function(streamReader)
+ return audioLib._newAudioStreamWrapperFromStreamReader(streamReader);
+ end);
+end;
+
+function audioLib:getDefaultPlayer()
+ local cachedPlayer = rawget(audioLib, "__cachedDefaultAudioPlayer");
+
+ if cachedPlayer == nil then
+ local handle = _obj_invokeEx(self.handle, 'CreateGlobalAudioPlayer');
+ cachedPlayer = audioLib._audioPlayerWrapperFromHandle(handle);
+
+ assert(cachedPlayer ~= nil);
+ rawset(audioLib, "__cachedDefaultAudioPlayer", cachedPlayer);
+ end;
+
+ return cachedPlayer;
+end;
+
+function audioLib.play(source, volume)
+ return audioLib.defaultPlayer:play(source, volume);
+end;
+
+audioLib.props["defaultPlayer"] = {getter="getDefaultPlayer", tipo="table"};
+
+return audioLib;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/btree.dlua b/Plugins/Sheets/Coyote and Crow/sdk/btree.dlua
new file mode 100644
index 00000000..14b21fcf
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/btree.dlua
@@ -0,0 +1,141 @@
+local BTreeInner = require("btree_private.dlua");
+local BTree = {};
+
+local function DEFAULT_BTREE_COMPARER(left, right)
+ if left < right then
+ return -1;
+ elseif left > right then
+ return 1;
+ else
+ return 0;
+ end;
+end;
+
+function BTree.new(theComparer)
+ local bt = {};
+
+ -- Atributos privados
+ bt.comparer = theComparer or DEFAULT_BTREE_COMPARER;
+ bt.raiz = nil;
+ bt.count = 0;
+
+ local comparer = bt.comparer;
+
+ -- métodos privados
+
+ for k, v in pairs(BTreeInner) do
+ bt[k] = v;
+ end;
+
+ -- Funções Públicas
+
+ function bt:inserir(chave, valor)
+ if self.raiz == nil then
+ self.raiz = self:alocarPagina();
+ end;
+
+ local inserirEm, indiceInserir = self:innerLocalizarForInsert(self.raiz, chave);
+
+ if inserirEm == nil then
+ error("InnerLocalizarForInsert retornou nil");
+ end;
+
+ if (indiceInserir <= inserirEm.countChaves) and (comparer(inserirEm.chaves[indiceInserir].valorChave, chave) == 0) then
+ error("Esta chave já existe");
+ end;
+
+ self:innerInsertCollated(inserirEm, indiceInserir, chave, valor);
+ end;
+
+ function bt:alterar(chave, valor)
+ local pEncontrado, indice = self:innerLocateCollated(self.raiz, chave);
+
+ if pEncontrado ~= nil then
+ pEncontrado.chaves[indice].valor = valor;
+ else
+ error("Esta chave não existe para que seu valor seja alterado");
+ end;
+ end;
+
+ function bt:inserirOuAlterar(chave, valor)
+
+ if self.raiz == nil then
+ self.raiz = self:alocarPagina();
+ end;
+
+ local inserirEm, indiceInserir = self:innerLocalizarForInsert(self.raiz, chave);
+
+ if inserirEm == nil then
+ error("InnerLocalizarForInsert retornou nil");
+ end;
+
+ if (indiceInserir <= inserirEm.countChaves) and (comparer(inserirEm.chaves[indiceInserir].valorChave, chave) == 0) then
+ inserirEm.chaves[indiceInserir].valor = valor;
+ else
+ self:innerInsertCollated(inserirEm, indiceInserir, chave, valor);
+ end;
+ end;
+
+ function bt:remover(chave)
+ local pEncontrado, indice = self:innerLocateCollated(self.raiz, chave);
+
+ if pEncontrado ~= nil then
+ pEncontrado.chaves[indice].valorChave = nil;
+ pEncontrado.chaves[indice].valor = nil;
+ self:innerDelete(pEncontrado, indice);
+ self.count = self.count - 1;
+ end;
+ end;
+
+ function bt:limpar()
+ self.raiz = nil;
+ self.count = 0;
+ end;
+
+ function bt:existe(chave)
+ local pEncontrado = self:innerLocateCollated(self.raiz, chave);
+ return (pEncontrado ~= nil);
+ end;
+
+ function bt:tryGet(chave)
+ local pEncontrado, indice = self:innerLocateCollated(self.raiz, chave);
+
+ if pEncontrado ~= nil then
+ return true, pEncontrado.chaves[indice].valor;
+ else
+ return false, nil;
+ end;
+ end;
+
+ function bt:menorChave()
+ if self.root == nil then
+ return nil;
+ end;
+
+ local pEncontrada, indice = self:innerFindLowest(self.raiz);
+
+ if pEncontrada ~= nil then
+ return pEncontrada.chaves[indice].valorChave, pEncontrada.chaves[indice].valor;
+ end;
+ end;
+
+ function bt:maiorChave()
+ if self.root == nil then
+ return nil;
+ end;
+
+ local pEncontrada, indice = self:innerFindHighest(self.raiz);
+
+ if pEncontrada ~= nil then
+ return pEncontrada.chaves[indice].valorChave, pEncontrada.chaves[indice].valor;
+ end;
+ end;
+
+ function bt:navigator()
+ return self:createNavigator();
+ end;
+
+ return bt;
+end;
+
+return BTree;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/btree_private.dlua b/Plugins/Sheets/Coyote and Crow/sdk/btree_private.dlua
new file mode 100644
index 00000000..c91c3cbb
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/btree_private.dlua
@@ -0,0 +1,849 @@
+local BTreeIN = {};
+
+local ARV_GRAU = 4;
+local MAX_CHAVES = (ARV_GRAU * 2) - 1;
+local MAX_FILHOS = (ARV_GRAU * 2);
+
+local MIN_CHAVES = ARV_GRAU - 1;
+
+
+-- Funções privadas
+
+local function pagina_setCountChaves(pagina, count)
+ if count < pagina.countChaves then
+ for i = count + 1, pagina.countChaves, 1 do
+ pagina.chaves[i].valorChave = nil;
+ pagina.chaves[i].valor = nil;
+ end;
+ end;
+
+ pagina.countChaves = count;
+end;
+
+function BTreeIN:alocarPagina()
+ local pagina = {countChaves=0, filhos={}, pai=nil, indiceNoPai=1};
+ local chaves = {};
+
+ for i = 1, MAX_CHAVES, 1 do
+ chaves[i] = {valorChave = nil, valor = nil};
+ end;
+
+ pagina.chaves = chaves;
+ return pagina;
+end;
+
+
+function BTreeIN:innerLocalizarForInsert(paginaOrigem, chaveALocalizar)
+ local comp, pOrg, min, max, meio;
+
+ pOrg = paginaOrigem;
+
+ while pOrg ~= nil do
+ min = 1;
+ max = pOrg.countChaves;
+
+ while min <= max do
+ meio = math.ceil((min + max) / 2);
+ comp = self.comparer(chaveALocalizar, pOrg.chaves[meio].valorChave);
+
+ if comp == 0 then
+ return pOrg, meio;
+ elseif comp < 0 then
+ max = meio - 1;
+ else
+ min = meio + 1;
+ end;
+ end;
+
+ if pOrg.filhos[min] ~= nil then
+ pOrg = pOrg.filhos[min];
+ else
+ return pOrg, min;
+ end;
+ end;
+
+ return nil, -1;
+end;
+
+function BTreeIN:innerAlocarEspaco(pagina, indiceEspaco)
+ local mediana, indiceNoPai, countToLeft, countToRight, countSemMediana, qtRetirado;
+ local novoIrmaoEsq, oPai;
+
+ if pagina.countChaves >= MAX_CHAVES then
+ -- Vamos precisar dividir a página em 2 páginas.
+ mediana = math.ceil(pagina.countChaves / 2);
+ oPai = pagina.pai;
+
+ if oPai == nil then
+ -- Estamos na raiz;
+ oPai = self:alocarPagina();
+ self.raiz = oPai;
+ end;
+
+ indiceNoPai = pagina.indiceNoPai;
+
+ -- Subir Mediana
+ oPai, indiceNoPai = self:innerAlocarEspaco(oPai, indiceNoPai);
+ oPai.chaves[indiceNoPai].valorChave = pagina.chaves[mediana].valorChave;
+ oPai.chaves[indiceNoPai].valor = pagina.chaves[mediana].valor;
+
+ novoIrmaoEsq = self:alocarPagina();
+
+ -- Copiar as chaves que estão antes da mediana para o novo irmão da esquerda
+
+ countSemMediana = pagina.countChaves - 1;
+ countToLeft = math.ceil(countSemMediana / 2);
+ countToRight = countSemMediana - countToLeft;
+ qtRetirado = pagina.countChaves - countToRight;
+
+ for i = 1, countToLeft, 1 do
+ novoIrmaoEsq.chaves[i].valorChave = pagina.chaves[i].valorChave;
+ novoIrmaoEsq.chaves[i].valor = pagina.chaves[i].valor;
+ end;
+
+ for i = 1, countToLeft + 1, 1 do
+ novoIrmaoEsq.filhos[i] = pagina.filhos[i];
+
+ if novoIrmaoEsq.filhos[i] ~= nil then
+ novoIrmaoEsq.filhos[i].pai = novoIrmaoEsq;
+ end;
+ end;
+
+ -- Reduzir o tamanho da Direita
+
+ for i = 1, countToRight, 1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i + qtRetirado].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i + qtRetirado].valor;
+ end;
+
+ for i = 1, countToRight + 1, 1 do
+ pagina.filhos[i] = pagina.filhos[i + qtRetirado];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ for i = countToRight + 2, MAX_FILHOS, 1 do
+ pagina.filhos[i] = nil;
+ end;
+
+ pagina_setCountChaves(novoIrmaoEsq, countToLeft);
+ pagina_setCountChaves(pagina, countToRight);
+
+ -- Ligar os pontos no OPai
+ oPai.filhos[indiceNoPai] = novoIrmaoEsq;
+ oPai.filhos[indiceNoPai + 1] = pagina;
+
+ novoIrmaoEsq.pai = oPai;
+ novoIrmaoEsq.indiceNoPai = indiceNoPai;
+
+ pagina.pai = oPai;
+ pagina.indiceNoPai = indiceNoPai + 1;
+
+ if indiceEspaco > mediana then
+ indiceEspaco = indiceEspaco - qtRetirado;
+ else
+ pagina = novoIrmaoEsq;
+ end;
+ end;
+
+ for i = pagina.countChaves + 1, indiceEspaco + 1, -1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i - 1].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i - 1].valor;
+ end;
+
+ for i = pagina.countChaves + 2, indiceEspaco + 2, -1 do
+ pagina.filhos[i] = pagina.filhos[i - 1];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ pagina.filhos[indiceEspaco + 1] = nil;
+ pagina_setCountChaves(pagina, pagina.countChaves + 1);
+ return pagina, indiceEspaco;
+end;
+
+function BTreeIN:innerInsertCollated(inserirEm, indice, chave, valor)
+ inserirEm, indice = self:innerAlocarEspaco(inserirEm, indice);
+ inserirEm.chaves[indice].valorChave = chave;
+ inserirEm.chaves[indice].valor = valor;
+ self.count = self.count + 1;
+end;
+
+function BTreeIN:innerLocateCollated(paginaOrigem, chaveALocalizar)
+ local comp, min, max, meio, pOrg;
+
+ pOrg = paginaOrigem;
+
+ while pOrg ~= nil do
+ min = 1;
+ max = pOrg.countChaves;
+
+ while min <= max do
+ meio = math.ceil((min + max) / 2);
+ comp = self.comparer(chaveALocalizar, pOrg.chaves[meio].valorChave);
+
+ if comp == 0 then
+ return pOrg, meio;
+ elseif comp < 0 then
+ max = meio - 1;
+ else
+ min = meio + 1;
+ end;
+ end;
+
+ pOrg = pOrg.filhos[min];
+ end;
+
+ return nil, nil;
+end;
+
+function BTreeIN:innerFindLowest(pagina)
+ local pOrg = pagina;
+
+ while (pOrg ~= nil) and (pOrg.countChaves > 0) do
+ if pOrg.filhos[1] ~= nil then
+ pOrg = pOrg.filhos[1];
+ else
+ return pOrg, 1;
+ end;
+ end;
+end;
+
+function BTreeIN:innerFindHighest(pagina)
+ local pOrg = pagina;
+
+ while (pOrg ~= nil) and (pOrg.countChaves > 0) do
+ local ind = pOrg.countChaves;
+
+ if pOrg.filhos[ind + 1] ~= nil then
+ pOrg = pOrg.filhos[ind + 1];
+ else
+ return pOrg, ind;
+ end;
+ end;
+end;
+
+function BTreeIN:destruirPagina(_)
+ -- faz nada
+end;
+
+function BTreeIN:innerDeletePucharDeCima(pagina, indice)
+ local retIndice;
+ local oPai, irmaoEsq, irmaoDir, paginaAux;
+ local indiceTemp, qtACopiar, tempChave, tempValor;
+
+ oPai = pagina.pai;
+ retIndice = indice;
+
+ if oPai == nil then
+ -- Estamos na raiz, não temos irmao nem pai. nao temos de onde puxar
+ -- Remover a chave
+
+ for i = indice, pagina.countChaves - 1, 1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i + 1].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i + 1].valor;
+ end;
+
+ -- Mover os filhos
+
+ for i = indice + 1, pagina.countChaves do
+ pagina.filhos[i] = pagina.filhos[i + 1];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ pagina_setCountChaves(pagina, pagina.countChaves - 1);
+ return pagina, indice, retIndice;
+ end;
+
+ if pagina.indiceNoPai > 1 then
+ irmaoEsq = oPai.filhos[pagina.indiceNoPai - 1];
+ else
+ irmaoEsq = nil;
+ end;
+
+ if pagina.indiceNoPai < oPai.countChaves + 1 then
+ irmaoDir = oPai.filhos[pagina.indiceNoPai + 1];
+ else
+ irmaoDir = nil;
+ end;
+
+
+ if (irmaoDir ~= nil) and (irmaoDir.countChaves > MIN_CHAVES) then
+ -- Vamos pegar uma chave do irmão da direita
+ -- Remover a chave do indice
+
+ for i = indice, pagina.countChaves - 1, 1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i + 1].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i + 1].valor;
+ end;
+
+ for i = indice + 1, pagina.countChaves, 1 do
+ pagina.filhos[i] = pagina.filhos[i + 1];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ -- Copiar a chave do pai;
+ pagina.chaves[pagina.countChaves].valorChave = oPai.chaves[pagina.indiceNoPai].valorChave;
+ pagina.chaves[pagina.countChaves].valor = oPai.chaves[pagina.indiceNoPai].valor;
+
+ -- Pegar os primeiros filhos do irmão da direita
+ paginaAux = irmaoDir.filhos[1];
+ pagina.filhos[pagina.countChaves + 1] = paginaAux;
+
+ if paginaAux ~= nil then
+ paginaAux.pai = pagina;
+ paginaAux.indiceNoPai = pagina.countChaves + 1;
+ end;
+
+ -- Mover a chave do irmao direita para o pai
+
+ oPai.chaves[pagina.indiceNoPai].valorChave = irmaoDir.chaves[1].valorChave;
+ oPai.chaves[pagina.indiceNoPai].valor = irmaoDir.chaves[1].valor;
+
+ -- excluir a chave do irmao da direita
+
+ for i = 1, irmaoDir.countChaves - 1, 1 do
+ irmaoDir.chaves[i].valorChave = irmaoDir.chaves[i + 1].valorChave;
+ irmaoDir.chaves[i].valor = irmaoDir.chaves[i + 1].valor;
+ end;
+
+ for i = 1, irmaoDir.countChaves, 1 do
+ irmaoDir.filhos[i] = irmaoDir.filhos[i + 1];
+
+ if irmaoDir.filhos[i] ~= nil then
+ irmaoDir.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ pagina_setCountChaves(irmaoDir, irmaoDir.countChaves - 1);
+ return pagina, indice, retIndice;
+ end;
+
+ if (irmaoEsq ~= nil) and (irmaoEsq.countChaves > MIN_CHAVES) then
+ -- Não conseguimos negociar com o irmão da direita. Vamos tentar no da esquerda
+ -- Remover a chave do Indice abrindo espaço no inicio para caber a Chave do Pai
+ qtACopiar = 1;
+
+ -- Copiar os que estão do lado esquerdo da chave que vai ser apagada
+ for i = indice + qtACopiar, qtACopiar + 2, -1 do
+ pagina.chaves[i - 1].valorChave = pagina.chaves[i - qtACopiar - 1].valorChave;
+ pagina.chaves[i - 1].valor = pagina.chaves[i - qtACopiar - 1].valor;
+ end;
+
+ for i = indice + qtACopiar, qtACopiar + 1, -1 do
+ pagina.filhos[i] = pagina.filhos[i - qtACopiar];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ -- Copiar a chave do pai
+ pagina.chaves[1].valorChave = oPai.chaves[pagina.indiceNoPai - 1].valorChave;
+ pagina.chaves[1].valor = oPai.chaves[pagina.indiceNoPai - 1].valor;
+
+ -- Pegar os ultimos filhos do irmao da esquerda
+ paginaAux = irmaoEsq.filhos[irmaoEsq.countChaves + 1];
+ pagina.filhos[1] = paginaAux;
+
+ if paginaAux ~= nil then
+ paginaAux.pai = pagina;
+ paginaAux.indiceNoPai = 1;
+ end;
+
+ oPai.chaves[pagina.indiceNoPai - 1].valorChave = irmaoEsq.chaves[irmaoEsq.countChaves].valorChave;
+ oPai.chaves[pagina.indiceNoPai - 1].valor = irmaoEsq.chaves[irmaoEsq.countChaves].valor;
+ pagina_setCountChaves(irmaoEsq, irmaoEsq.countChaves - 1);
+ return pagina, indice, retIndice;
+ end;
+
+ -- Se chegou aqui, os irmãos não podem doar uma chave. Devemos mesclar
+
+ if irmaoDir ~= nil then
+ -- Mesclar com o irmão da direita
+
+ -- Obtendo a chave que vai vir de cima
+ tempChave = oPai.chaves[pagina.indiceNoPai].valorChave;
+ tempValor = oPai.chaves[pagina.indiceNoPai].valor;
+
+ -- Remover a chave do indice
+ for i = indice, pagina.countChaves - 1, 1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i + 1].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i + 1].valor;
+ end;
+
+ for i = indice + 1, pagina.countChaves, 1 do
+ pagina.filhos[i] = pagina.filhos[i + 1];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ -- Copiar uma chave do pai
+ pagina.chaves[pagina.countChaves].valorChave = tempChave;
+ pagina.chaves[pagina.countChaves].valor = tempValor;
+
+ -- Copiar as chaves e filhos do irmão
+ qtACopiar = irmaoDir.countChaves;
+
+ for i = pagina.countChaves + 1, pagina.countChaves + qtACopiar, 1 do
+ pagina.chaves[i].valorChave = irmaoDir.chaves[i - pagina.countChaves].valorChave;
+ pagina.chaves[i].valor = irmaoDir.chaves[i - pagina.countChaves].valor;
+ end;
+
+ for i = pagina.countChaves + 1, pagina.countChaves + qtACopiar + 1, 1 do
+ pagina.filhos[i] = irmaoDir.filhos[i - pagina.countChaves];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].pai = pagina;
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ pagina_setCountChaves(pagina, pagina.countChaves + irmaoDir.countChaves);
+
+ if oPai.countChaves > MIN_CHAVES then
+ -- Remover a chave
+
+ for i = pagina.indiceNoPai, oPai.countChaves - 1, 1 do
+ oPai.chaves[i].valorChave = oPai.chaves[i + 1].valorChave;
+ oPai.chaves[i].valor = oPai.chaves[i + 1].valor;
+ end;
+
+ -- Mover os filhos
+
+ for i = pagina.indiceNoPai + 1, oPai.countChaves, 1 do
+ oPai.filhos[i] = oPai.filhos[i + 1];
+
+ if oPai.filhos[i] ~= nil then
+ oPai.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ pagina_setCountChaves(oPai, oPai.countChaves - 1);
+ else
+ --local novoIndiceNoPai;
+ --oPai, novoIndiceNoPai = self:innerDeletePucharDeCima(oPai, pagina.indiceNoPai);
+ --pagina.indiceNoPai = novoIndiceNoPai;
+ self:innerDeletePucharDeCima(oPai, pagina.indiceNoPai);
+
+ if oPai.countChaves == 0 then
+ self.raiz = pagina;
+ pagina.pai = nil;
+ pagina.indiceNoPai = 1;
+ self:destruirPagina(oPai);
+ --oPai = nil;
+ end;
+ end;
+
+ self:destruirPagina(irmaoDir);
+ return pagina, indice, retIndice;
+ end;
+
+ if irmaoEsq ~= nil then
+ --self.deveValidar = true;
+
+ -- Mesclar com o irmão da esquerda
+ tempChave = oPai.chaves[pagina.indiceNoPai - 1].valorChave;
+ tempValor = oPai.chaves[pagina.indiceNoPai - 1].valor;
+
+ -- Remover a chave do indice abrinco espaco no inicio para caber a chave do pai + chaves do irmao da esquerda
+ qtACopiar = irmaoEsq.countChaves;
+
+ -- Copiar os que estão do lado direito da chave que vai ser apagada
+
+ for i = pagina.countChaves + qtACopiar, indice + qtACopiar + 1, -1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i - qtACopiar].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i - qtACopiar].valor;
+ end;
+
+ for i = pagina.countChaves + qtACopiar + 1, indice + qtACopiar + 1, -1 do
+ pagina.filhos[i] = pagina.filhos[i - qtACopiar];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ -- Copiar os que estão do lado esquerdo da chave que vai ser apagada
+ for i = indice + qtACopiar, qtACopiar + 2, -1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i - qtACopiar - 1].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i - qtACopiar - 1].valor;
+ end;
+
+ for i = indice + qtACopiar, qtACopiar + 1, -1 do
+ pagina.filhos[i + 1] = pagina.filhos[i - qtACopiar];
+
+ if pagina.filhos[i + 1] ~= nil then
+ pagina.filhos[i + 1].indiceNoPai = i + 1;
+ end;
+ end;
+
+ -- Copiar a chave do pai
+ pagina.chaves[irmaoEsq.countChaves + 1].valorChave = tempChave;
+ pagina.chaves[irmaoEsq.countChaves + 1].valor = tempValor;
+
+ -- copiar as chaves e filhos do irmão da esquerda
+
+ for i = 1, irmaoEsq.countChaves, 1 do
+ pagina.chaves[i].valorChave = irmaoEsq.chaves[i].valorChave;
+ pagina.chaves[i].valor = irmaoEsq.chaves[i].valor;
+ end;
+
+ for i = 1, irmaoEsq.countChaves + 1, 1 do
+ pagina.filhos[i] = irmaoEsq.filhos[i];
+
+ if pagina.filhos[i] ~= nil then
+ pagina.filhos[i].pai = pagina;
+ pagina.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ pagina_setCountChaves(pagina, pagina.countChaves + irmaoEsq.countChaves);
+
+ if oPai.countChaves > MIN_CHAVES then
+ -- Remover a chave
+
+ for i = pagina.indiceNoPai, oPai.countChaves - 1, 1 do
+ oPai.chaves[i].valorChave = oPai.chaves[i + 1].valorChave;
+ oPai.chaves[i].valor = oPai.chaves[i + 1].valor;
+ end;
+
+ -- Mover os filhos
+
+ for i = pagina.indiceNoPai - 1, oPai.countChaves, 1 do
+ oPai.filhos[i] = oPai.filhos[i + 1];
+
+ if oPai.filhos[i] ~= nil then
+ oPai.filhos[i].indiceNoPai = i;
+ end;
+ end;
+
+ pagina_setCountChaves(oPai, oPai.countChaves - 1);
+ else
+ indiceTemp = pagina.indiceNoPai - 1;
+ --oPai, indiceTemp = self:innerDeletePucharDeCima(oPai, indiceTemp);
+ oPai = self:innerDeletePucharDeCima(oPai, indiceTemp);
+
+ if oPai.countChaves == 0 then
+ self.raiz = pagina;
+ pagina.pai = nil;
+ pagina.indiceNoPai = 1;
+ self:destruirPagina(oPai);
+ oPai = nil;
+ end;
+ end;
+
+ if oPai ~= nil then
+ oPai.filhos[irmaoEsq.indiceNoPai] = pagina;
+ end;
+
+ pagina.indiceNoPai = irmaoEsq.indiceNoPai;
+ self:destruirPagina(irmaoEsq);
+ return pagina, indice, retIndice;
+ end;
+
+ error("Ops, não deveria ter chegado até aqui");
+end;
+
+function BTreeIN:innerDelete(pagina, indiceEspaco)
+ local oPai, filhoEsq, filhoDir;
+ local pagToDelete;
+ local indiceToDelete;
+
+ oPai = pagina.pai;
+
+ if (pagina.filhos[indiceEspaco] == nil) and (pagina.filhos[indiceEspaco + 1] == nil) then
+ -- É uma página folha
+
+ if (oPai ~= nil) and (pagina.countChaves <= MIN_CHAVES) then
+ -- Não é root e vai atingir limite minimo
+ indiceToDelete = indiceEspaco;
+ --pagina, indiceToDelete = self:innerDeletePucharDeCima(pagina, indiceToDelete)
+ self:innerDeletePucharDeCima(pagina, indiceToDelete)
+ else
+ for i = indiceEspaco, pagina.countChaves - 1, 1 do
+ pagina.chaves[i].valorChave = pagina.chaves[i + 1].valorChave;
+ pagina.chaves[i].valor = pagina.chaves[i + 1].valor;
+ end;
+
+ pagina_setCountChaves(pagina, pagina.countChaves - 1);
+ end;
+ else
+ -- Página nó
+ filhoEsq = pagina.filhos[indiceEspaco];
+ filhoDir = pagina.filhos[indiceEspaco + 1];
+
+ if filhoDir ~= nil then
+ pagToDelete, indiceToDelete = self:innerFindLowest(filhoDir);
+
+ if pagToDelete ~= nil then
+ pagina.chaves[indiceEspaco].valorChave = pagToDelete.chaves[indiceToDelete].valorChave;
+ pagina.chaves[indiceEspaco].valor = pagToDelete.chaves[indiceToDelete].valor;
+ self:innerDelete(pagToDelete, indiceToDelete);
+ return;
+ else
+ error("Ops");
+ end;
+ end;
+
+ if filhoEsq ~= nil then
+ pagToDelete, indiceToDelete = self:innerFindHighest(filhoEsq);
+
+ if pagToDelete ~= nil then
+ pagina.chaves[indiceEspaco].valorChave = pagToDelete.chaves[indiceToDelete].valorChave;
+ pagina.chaves[indiceEspaco].valor = pagToDelete.chaves[indiceToDelete].valor;
+ self:innerDelete(pagToDelete, indiceToDelete);
+ return;
+ else
+ error("Ops");
+ end;
+ end;
+
+ error("Ops. Não era para ter chegado ate aqui");
+ end;
+end;
+
+function BTreeIN:checarPagina(p, min, max)
+ local vMin , vMax;
+ local last = nil;
+
+ for i = 1, p.countChaves, 1 do
+ if (min ~= nil) and (self.comparer(p.chaves[i].valorChave, min) < 0) then
+ error("Ops. Existe uma falha na ordem das paginas, min");
+ end;
+
+ if (max ~= nil) and (self.comparer(p.chaves[i].valorChave, max) > 0) then
+ error("Ops. Existe uma falha na ordem das paginas, max");
+ end;
+
+ if i > 1 then
+ if self.comparer(p.chaves[i].valorChave, last) <= 0 then
+ error("Ops. os numeros de uma página não estão ordenados de forma crescente");
+ end;
+ end;
+
+ last = p.chaves[i].valorChave;
+ end;
+
+ -- Checar Filhos
+
+ for i = 1, p.countChaves + 1, 1 do
+ if p.filhos[i] ~= nil then
+ if i == 1 then
+ vMax = p.chaves[i].valorChave;
+ self:checarPagina(p.filhos[i], min, vMax);
+ elseif i == p.countChaves + 1 then
+ vMin = p.chaves[i - 1].valorChave;
+ self:checarPagina(p.filhos[i], vMin, max);
+ else
+ vMin = p.chaves[i - 1].valorChave;
+ vMax = p.chaves[i].valorChave;
+ self:checarPagina(p.filhos[i], vMin, vMax);
+ end;
+ end;
+ end;
+
+ if p.pai ~= nil then
+ if p.pai.filhos[p.indiceNoPai] ~= p then
+ error("Indice no pai de uma pagina esta errada");
+ end;
+ end;
+end;
+
+function BTreeIN:validate(errPrefix)
+ local ok, err = pcall(self.checarPagina, self, self.raiz, nil, nil);
+
+ if not ok then
+ --error(err .. "\n\n: " .. tableToStr(self.raiz, true));
+ error((errPrefix or "") .. err);
+ end;
+end;
+
+
+function BTreeIN.createNavigator(bt)
+ local nav = {};
+
+ local fPaginaAtual = nil;
+ local fIndiceAtual = -1;
+ local fEof = true;
+ local fBof = true;
+
+ function nav:first()
+ local pagina, indice;
+ local raiz = bt.raiz;
+
+ if raiz ~= nil then
+ pagina, indice = bt:innerFindLowest(raiz);
+ end;
+
+ if pagina ~= nil then
+ fPaginaAtual = pagina;
+ fIndiceAtual = indice;
+ fEof = false;
+ fBof = true;
+ else
+ fPaginaAtual = nil;
+ fIndiceAtual = -1;
+ fEof = true;
+ fBof = true;
+ end;
+ end;
+
+ function nav:last()
+ local pagina, indice;
+ local raiz = bt.raiz;
+
+ if raiz ~= nil then
+ pagina, indice = bt:innerFindHighest(raiz);
+ end;
+
+ if pagina ~= nil then
+ fPaginaAtual = pagina;
+ fIndiceAtual = indice;
+ fEof = true;
+ fBof = false;
+ else
+ fPaginaAtual = nil;
+ fIndiceAtual = -1;
+ fEof = true;
+ fBof = true;
+ end;
+ end;
+
+ function nav:next()
+ local pagAtual, pagEncontrada, oPai;
+ local indAtual, indEncontrado, indPai;
+
+ pagAtual = fPaginaAtual;
+ indAtual = fIndiceAtual;
+
+ if (pagAtual == nil) or (indAtual == -1) then
+ fEof = true;
+ return;
+ end;
+
+ if pagAtual.filhos[indAtual + 1] ~= nil then
+ pagEncontrada, indEncontrado = bt:innerFindLowest(pagAtual.filhos[indAtual + 1]);
+
+ fEof = false;
+ fBof = false;
+ fPaginaAtual = pagEncontrada;
+ fIndiceAtual = indEncontrado;
+ else
+ if indAtual < pagAtual.countChaves then
+ fIndiceAtual = fIndiceAtual + 1;
+ else
+ -- Já estamos apontando para o último desta página. vamos procurar recursivamente nos pais
+ oPai = pagAtual.pai;
+ indPai = pagAtual.indiceNoPai;
+
+ local deveProcurar = true;
+
+ while deveProcurar do
+ if oPai == nil then
+ fEof = true;
+ deveProcurar = false;
+ else
+ if indPai <= oPai.countChaves then
+ fPaginaAtual = oPai;
+ fIndiceAtual = indPai;
+ deveProcurar = false;
+ else
+ indPai = oPai.indiceNoPai;
+ oPai = oPai.pai;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ function nav:previous()
+ local pagAtual, pagEncontrada, oPai;
+ local indAtual, indEncontrado, indPai;
+
+ pagAtual = fPaginaAtual;
+ indAtual = fIndiceAtual;
+
+ if (pagAtual == nil) or (indAtual == -1) then
+ fBof = true;
+ return;
+ end;
+
+ if pagAtual.filhos[indAtual] ~= nil then
+ pagEncontrada, indEncontrado = bt:innerFindHighest(pagAtual.filhos[indAtual]);
+
+ fEof = false;
+ fBof = false;
+ fPaginaAtual = pagEncontrada;
+ fIndiceAtual = indEncontrado;
+ else
+ if indAtual > 1 then
+ fIndiceAtual = fIndiceAtual - 1;
+ else
+ -- Já estamos apontando para o último desta página. vamos procurar recursivamente nos pais
+ oPai = pagAtual.pai;
+ indPai = pagAtual.indiceNoPai;
+
+ local deveProcurar = true;
+
+ while deveProcurar do
+ if oPai == nil then
+ fBof = true;
+ deveProcurar = false;
+ else
+ if indPai > 1 then
+ fPaginaAtual = oPai;
+ fIndiceAtual = indPai - 1;
+ deveProcurar = false;
+ else
+ indPai = oPai.indiceNoPai;
+ oPai = oPai.pai;
+ end;
+ end;
+ end;
+ end;
+ end;
+ end;
+
+ function nav:key()
+ if fPaginaAtual ~= nil then
+ return fPaginaAtual.chaves[fIndiceAtual].valorChave;
+ else
+ return nil;
+ end;
+ end;
+
+ function nav:value()
+ if fPaginaAtual ~= nil then
+ return fPaginaAtual.chaves[fIndiceAtual].valor;
+ else
+ return nil;
+ end;
+ end;
+
+ function nav:eof()
+ return fEof;
+ end;
+
+ function nav:bof()
+ return fBof;
+ end;
+
+ nav:first();
+ return nav;
+end;
+
+return BTreeIN;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/delayedLoad.dlua b/Plugins/Sheets/Coyote and Crow/sdk/delayedLoad.dlua
new file mode 100644
index 00000000..fbd8902d
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/delayedLoad.dlua
@@ -0,0 +1,42 @@
+local dLoadHelper = {};
+
+function dLoadHelper.new(moduleName)
+ local interface = {};
+ local moduleObject = nil;
+
+ local metaTable = {
+ __index = function(table, key)
+ if moduleObject == nil then
+ moduleObject = require(moduleName);
+ end;
+
+ if moduleObject ~= nil then
+ local r = moduleObject[key];
+
+ if type(r) == "function" then
+ rawset(table, key, r);
+ end;
+
+ return r;
+ else
+ return nil;
+ end;
+ end,
+
+ __newindex = function(table, key, value)
+ if moduleObject == nil then
+ moduleObject = require(moduleName);
+ end;
+
+ rawset(table, key, value);
+ end;
+ };
+
+ rawset(interface, "__isDelayedLoad", true);
+ rawset(interface, "__delayedLoadModuleName", moduleName);
+
+ setmetatable(interface, metaTable);
+ return interface;
+end;
+
+return dLoadHelper;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/dialogs.lua b/Plugins/Sheets/Coyote and Crow/sdk/dialogs.lua
new file mode 100644
index 00000000..2acdf45d
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/dialogs.lua
@@ -0,0 +1 @@
+return require("rrpgDialogs.lua");
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/fireDrive.lua b/Plugins/Sheets/Coyote and Crow/sdk/fireDrive.lua
new file mode 100644
index 00000000..77c93b17
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/fireDrive.lua
@@ -0,0 +1,3 @@
+fireDrive = require("delayedLoad.dlua").new("fireDriveCore.dlua");
+FireDrive = fireDrive;
+return fireDrive;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/fireDriveCore.dlua b/Plugins/Sheets/Coyote and Crow/sdk/fireDriveCore.dlua
new file mode 100644
index 00000000..b63ac244
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/fireDriveCore.dlua
@@ -0,0 +1,261 @@
+require("rrpg.lua");
+local plugins = require("plugins.lua");
+local fdmodule = "RRPG.FIRECAST.FMXModule";
+
+plugins.requirePlugin(fdmodule);
+
+local fireDrive = {};
+
+local _uploads = {};
+local _uploadsIdGenerator = 0;
+
+local function unsetupUpload(uploadId)
+ local upload =_uploads[uploadId];
+
+ if upload ~= nil then
+ plugins.unlistenPM(upload.pmListenerId);
+ upload.pmListenerId = nil;
+ _uploads[uploadId] = nil;
+ end;
+end;
+
+local function fdManageItem(destName, metadata, onSuccess, onProgress, onFailure)
+ _uploadsIdGenerator = _uploadsIdGenerator + 1;
+ local esteId = _uploadsIdGenerator;
+ local esteUpload = {};
+ local msg = {};
+
+ _uploads[esteId] = esteUpload;
+ esteUpload.destName = destName;
+ esteUpload.metadata = metadata;
+ esteUpload.onSuccess = onSuccess;
+ esteUpload.onProgress = onProgress;
+ esteUpload.onFailure = onFailure;
+ esteUpload.pmListener = "L" .. _rrpg_generateUniqueStrID();
+ esteUpload.pmListenerId = plugins.listenPM(esteUpload.pmListener,
+ function (receivedMsg)
+ plugins.replyPM(receivedMsg, nil);
+
+ if receivedMsg.kind == "progress" then
+ if onProgress ~= nil then
+ onProgress(receivedMsg.currentBytes, receivedMsg.maxBytes);
+ end;
+ elseif receivedMsg.kind == "error" then
+ unsetupUpload(esteId);
+
+ if onFailure ~= nil then
+ onFailure(receivedMsg.errorMsg);
+ end;
+ elseif receivedMsg.kind == "end" then
+ unsetupUpload(esteId);
+
+ if onSuccess ~= nil then
+ onSuccess(receivedMsg.successData);
+ end;
+ elseif receivedMsg.kind == "uploadId" then
+ esteUpload.remoteUploadId = receivedMsg.uploadId;
+ end;
+ end);
+
+ msg.destName = destName;
+ msg.metadata = metadata;
+ msg.uploadId = esteId;
+ msg.pmListener = esteUpload.pmListener;
+
+ plugins.sendPM(fdmodule, "fireDrive:manageItem", msg,
+ function (_)
+
+ end,
+
+ function (r)
+ if onFailure ~= nil then
+ unsetupUpload(esteId);
+ onFailure(r);
+ end;
+ end);
+
+ return esteId;
+end;
+
+local function tryGetMimeFromFileName(fileName)
+ local ext = string.match(fileName, "%.[^%.\\/]+$");
+
+ if ext ~= nil then
+ local r, mime = _util_tryGetMimeFromExtension(ext);
+
+ if r then
+ return mime;
+ else
+ return 'application/octet-stream';
+ end;
+ else
+ return 'application/octet-stream';
+ end;
+end;
+
+local function fdExecuteUpload(params)
+ if type(params) ~= "table" then
+ error("fdExecuteUpload - params was not informed");
+ end;
+
+ if type(params.stream) ~= "table" then
+ error("fireDrive upload - stream was not informed");
+ end;
+
+ local metadata = {};
+ params.stream.position = 0;
+
+ if params.stream.size > 128 * 1024 * 1024 then
+ if params.onFailure then
+ params.onFailure("FILE TOO BIG");
+ end;
+
+ return nil;
+ end;
+
+ metadata.headers = {};
+
+ if params.isQuickUpload then
+ params.destName = params.suggestedFileName;
+ metadata.headers.operation = "quickUpload";
+ else
+ metadata.headers.operation = "create";
+ metadata.headers.kind = "file";
+ end;
+
+ metadata.blobs = {};
+ metadata.blobs[1] = {name="content", streamSharedId = params.stream:share(), mimeType = params.mimeType or tryGetMimeFromFileName(params.destName)};
+
+ if params.isQuickUpload and not _util_isValidMimeType(metadata.blobs[1].mimeType) then
+ error("INVALID MIME TYPE: " .. tostring(metadata.blobs[1].mimeType));
+ end;
+
+ local ret = fdManageItem(params.destName, metadata, params.onSuccess, params.onProgress, params.onFailure);
+ metadata.blobs[1].data = nil;
+ return ret;
+end;
+
+function fireDrive.uploadFile(destName, stream, onSuccess, onProgress, onFailure, mimeType)
+ local params = {};
+ params.destName = destName;
+ params.stream = stream;
+ params.onSuccess = onSuccess;
+ params.onProgress = onProgress;
+ params.onFailure = onFailure;
+ params.mimeType = mimeType;
+
+ return fdExecuteUpload(params);
+end;
+
+function fireDrive.upload(...)
+ return fireDrive.uploadFile(...);
+end;
+
+function fireDrive.quickUpload(suggestedFileName, mimeType, stream, onSuccess, onProgress, onFailure)
+ local params = {};
+ params.stream = stream;
+ params.onSuccess = onSuccess;
+ params.onProgress = onProgress;
+ params.onFailure = onFailure;
+ params.mimeType = mimeType;
+ params.isQuickUpload = true;
+ params.suggestedFileName = suggestedFileName;
+
+ return fdExecuteUpload(params);
+end;
+
+function fireDrive.abortOperation(operationId)
+ local upload = _uploads[operationId];
+
+ if upload ~= nil then
+ plugins.sendPM(fdmodule, "fireDrive:abortOperation", {uploadId = upload.remoteUploadId});
+ end;
+
+ unsetupUpload(operationId);
+end;
+
+function fireDrive.createDirectory(directoryName, onSuccess, onFailure)
+ local metadata = {};
+ metadata.headers = {};
+ metadata.headers.operation = "create";
+ metadata.headers.kind = "directory";
+
+ return fdManageItem(directoryName, metadata, onSuccess, nil, onFailure);
+end;
+
+function fireDrive.delete(destName, onSuccess, onFailure)
+ local metadata = {};
+ metadata.headers = {};
+ metadata.headers.operation = "delete";
+ return fdManageItem(destName, metadata, onSuccess, nil, onFailure);
+end;
+
+function fireDrive.rename(existingFileName, newFileName, onSuccess, onFailure)
+ local metadata = {};
+ metadata.headers = {};
+ metadata.headers.operation = "rename";
+ metadata.headers.newFileName = newFileName;
+ return fdManageItem(existingFileName, metadata, onSuccess, nil, onFailure);
+end;
+
+function fireDrive.getFiles(directory, callback, failureCallback)
+ plugins.sendPM(fdmodule, "fireDrive:enumerateFiles", {dir=directory},
+ function(r)
+ if callback ~= nil then
+ callback(r);
+ end;
+ end,
+
+ function(r)
+ if failureCallback ~= nil then
+ failureCallback(r);
+ end;
+ end);
+end;
+
+function fireDrive.refresh(refreshCallback, failureCallback)
+ plugins.sendPM(fdmodule, "fireDrive:refresh", nil,
+ function (r)
+ if refreshCallback ~= nil then
+ refreshCallback(r);
+ end;
+ end,
+
+ function (r)
+ if failureCallback ~= nil then
+ failureCallback(r);
+ end;
+ end);
+end;
+
+function fireDrive.getFileInfo(fileName, callback, failureCallback)
+ plugins.sendPM(fdmodule, "fireDrive:getFileInfo", {fileName=fileName},
+ function (r)
+ if callback ~= nil then
+ callback(r);
+ end;
+ end,
+
+ function (r)
+ if failureCallback ~= nil then
+ failureCallback(r);
+ end;
+ end);
+end;
+
+function fireDrive.getSpaceInfo(callback, failureCallback)
+ plugins.sendPM(fdmodule, "fireDrive:getSpaceInfo", nil,
+ function (r)
+ if callback ~= nil then
+ callback(r);
+ end;
+ end,
+
+ function (r)
+ if failureCallback ~= nil then
+ failureCallback(r);
+ end;
+ end);
+end;
+
+return fireDrive;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/firecast.lua b/Plugins/Sheets/Coyote and Crow/sdk/firecast.lua
new file mode 100644
index 00000000..1a3a8b17
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/firecast.lua
@@ -0,0 +1 @@
+return require('rrpg.lua');
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/gui.lua b/Plugins/Sheets/Coyote and Crow/sdk/gui.lua
new file mode 100644
index 00000000..60ae87f6
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/gui.lua
@@ -0,0 +1 @@
+return require("rrpgGUI.lua");
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/internet.lua b/Plugins/Sheets/Coyote and Crow/sdk/internet.lua
new file mode 100644
index 00000000..05ae4b0f
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/internet.lua
@@ -0,0 +1,3 @@
+internet = require("delayedLoad.dlua").new("internetCore.dlua");
+Internet = internet;
+return internet;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/internetCore.dlua b/Plugins/Sheets/Coyote and Crow/sdk/internetCore.dlua
new file mode 100644
index 00000000..0a3811d8
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/internetCore.dlua
@@ -0,0 +1,188 @@
+local objs = require("rrpgObjs.lua");
+local utils = require("rrpgUtil.lua");
+local Async = require("async.lua");
+
+local lInternet = {};
+local _downloadIdGenerator = 1;
+local _downloads = {};
+local internet = lInternet;
+
+function internet.asyncDownload(url, cacheMode, progressCallback)
+ local promise, resolution = Async.Promise.pending();
+ assert((promise ~= nil) and (resolution ~= nil));
+
+ internet.download(url,
+ function (stream, contentType)
+ assert(resolution ~= nil);
+ assert(stream ~= nil);
+
+ resolution:setSuccess(stream, contentType);
+ end,
+ function (errorMessage)
+ assert(resolution ~= nil);
+ resolution:setFailure(errorMessage);
+ end,
+ progressCallback,
+ cacheMode);
+
+ return promise;
+end;
+
+function internet.download(url, finishCallback, errorCallback, progressCallback, cacheMode)
+ local urlGetter = objs.objectFromHandle(_obj_newObject("TLuaURLGetter"));
+
+ _downloadIdGenerator = _downloadIdGenerator + 1;
+ local idDownload = _downloadIdGenerator;
+
+ objs.registerHandle(urlGetter.handle, urlGetter);
+
+ urlGetter:addEventListener("OnDados",
+ function(streamObjectHandle, contentType)
+ _downloads[idDownload] = nil;
+ local stream = utils.streamFromHandle(streamObjectHandle);
+
+ if finishCallback ~= nil then
+ finishCallback(stream, contentType);
+ end;
+ end);
+
+ urlGetter:addEventListener("OnError",
+ function(errorMsg)
+ _downloads[idDownload] = nil;
+
+ if errorCallback ~= nil then
+ errorCallback(errorMsg);
+ end;
+ end);
+
+ urlGetter:addEventListener("OnProgress",
+ function(downloadedBytes, totalBytes)
+
+ if progressCallback ~= nil then
+ local ret = progressCallback(downloadedBytes, totalBytes);
+
+ if ret == false then
+ internet.stopDownload(idDownload);
+ end;
+ end;
+ end);
+
+ if type(cacheMode) == "string" then
+ _obj_setProp(urlGetter.handle, "CacheMode", cacheMode);
+ end;
+
+ _downloads[idDownload] = urlGetter;
+ _obj_invoke(urlGetter.handle, "StartDownload", url);
+ return idDownload;
+end;
+
+function internet.stopDownload(downloadId)
+ local urlGetter = _downloads[downloadId];
+
+ if urlGetter ~= nil then
+ _obj_invoke(urlGetter.handle, "StopDownload");
+ end;
+end;
+
+local __requestsStrongReference = {};
+
+function internet.newHTTPRequest(method, url)
+ local r = objs.objectFromHandle(_obj_newObject("TLuaHTTPRequest"));
+ objs.registerHandle(r.handle, r);
+
+ if r.props == nil then
+ r.props = {};
+ end;
+
+ if r.eves == nil then
+ r.eves = {};
+ end;
+
+ if type(method) ~= "string" then
+ method = "GET";
+ end;
+
+ function r:getUrl() return _obj_getProp(self.handle, "URL"); end;
+ function r:setUrl(v) _obj_setProp(self.handle, "URL", v); end;
+
+ function r:getMethod() return _obj_getProp(self.handle, "HTTPMethod"); end;
+ function r:setMethod(v) _obj_setProp(self.handle, "HTTPMethod", v); end;
+
+ function r:setRequestHeader(header, value) _obj_invoke(self.handle, "SetRequestHeader", header, tostring(value or "")); end;
+ function r:getRequestHeader(header) return _obj_invoke(self.handle, "GetRequestHeader", header); end;
+
+ function r:getResponseHeader(header) return _obj_invoke(self.handle, "GetResponseHeader", header); end;
+ function r:getAllResponseHeaders() return _obj_invoke(self.handle, "GetAllResponseHeaders"); end;
+ function r:getResponseText() return _obj_getProp(self.handle, "ResponseText"); end;
+ function r:getResponseStream() return utils.streamFromHandle(_obj_invokeEx(self.handle, "GetResponseStreamHandle")); end;
+ function r:getStatus() return _obj_getProp(self.handle, "Status"); end;
+ function r:getStatusText() return _obj_getProp(self.handle, "StatusText"); end;
+
+ function r:open(openMethod, openURL)
+ self.method = openMethod;
+ self.url = openURL;
+ end;
+
+ function r:send(body)
+ __requestsStrongReference[self] = true; -- manter uma referência forte ate o fim da requisicao
+ local tBody = type(body);
+
+ if tBody == "table" then
+ if body.handle == nil then
+ body = tableToStr(body);
+ end;
+ elseif body ~= nil then
+ body = tostring(body);
+ end;
+
+ if self.__refResponseEventId == nil then
+ self.__refResponseEventId = self:addEventListener("onResponse",
+ function()
+ __requestsStrongReference[self] = nil; -- Remover referencia forte
+ end);
+ end;
+
+ if self.__refOnErrorEventId == nil then
+ self.__refOnErrorEventId = self:addEventListener("onError",
+ function()
+ __requestsStrongReference[self] = nil; -- Remover referencia forte
+ end);
+ end;
+
+ _obj_invokeEx(self.handle, "Send", body);
+ end;
+
+ function r:abort() _obj_invoke(self.handle, "Abort"); end;
+
+ r.props["url"] = {setter = "setUrl", getter = "getUrl", tipo = "string"};
+ r.props["method"] = {setter = "setMethod", getter = "getMethod", tipo = "string"};
+
+ r.props["responseText"] = {getter = "getResponseText", tipo = "string"};
+ r.props["responseStream"] = {getter = "getResponseStream", tipo = "table"};
+ r.props["status"] = {getter = "getStatus", tipo = "int"};
+ r.props["statusText"] = {getter = "getStatusText", tipo = "string"};
+ r.props["allResponseHeaders"] = {getter = "getAllResponseHeaders", tipo = "string"};
+
+ r.eves["onError"] = "errorMsg";
+ r.eves["onResponse"] = "";
+ r.eves["onSendProgress"] = "currentBytes, maxBytes";
+ r.eves["onReceiveProgress"] = "currentBytes, maxBytes";
+
+ r.method = method;
+
+ if url ~= nil then
+ r.url = url;
+ end;
+
+ return r;
+end;
+
+function internet.httpEncode(str)
+ return _internet_HTTPEncode(str);
+end;
+
+function internet.httpDecode(str)
+ return _internet_HTTPDecode(str);
+end;
+
+return lInternet;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/locale.lua b/Plugins/Sheets/Coyote and Crow/sdk/locale.lua
new file mode 100644
index 00000000..d4afe9ae
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/locale.lua
@@ -0,0 +1,19 @@
+Locale = require("delayedLoad.dlua").new("localeCore.dlua");
+
+function LANG(idTxt)
+ return Locale.lang(idTxt);
+end
+
+function lang(idTxt)
+ return Locale.lang(idTxt);
+end
+
+function tryLang(idTxt)
+ return Locale.tryLang(idTxt);
+end
+
+function tryLANG(idTxt)
+ return Locale.tryLang(idTxt);
+end
+
+return Locale;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/localeCore.dlua b/Plugins/Sheets/Coyote and Crow/sdk/localeCore.dlua
new file mode 100644
index 00000000..cbba73cc
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/localeCore.dlua
@@ -0,0 +1,99 @@
+local Objs = require("rrpgObjs.lua");
+local Locale = {};
+
+function Locale.lang(txtId)
+ return _system_locale_lang(txtId);
+end;
+
+function Locale.tryLang(txtId)
+ return _system_locale_tryLang(txtId);
+end;
+
+function Locale.loadLangTexts(langTexts)
+ return _system_locale_loadLangTexts(langTexts);
+end;
+
+function Locale.withDesiredAutoEval(callback, desiredEnabled, ...)
+ assert(type(callback) == 'function', "callback parameter is not a function");
+
+ local wasAutoEvalEnabled = Locale.getIsAutoStringEvalEnabled();
+ Locale.setIsAutoStringEvalEnabled(desiredEnabled);
+
+ local r = table.pack(pcall(callback, ...));
+
+ Locale.setIsAutoStringEvalEnabled(wasAutoEvalEnabled);
+
+ if not r[1] then
+ reraise(r[2]);
+ else
+ return table.unpack(r, 2);
+ end;
+end
+
+function Locale.withEval(callback, ...)
+ return Locale.withDesiredAutoEval(callback, true, ...);
+end;
+
+function Locale.withNoEval(callback, ...)
+ return Locale.withDesiredAutoEval(callback, false, ...);
+end;
+
+function Locale.getIsAutoStringEvalEnabled()
+ return _system_locale_getCurrentThreadAutomaticLocalizedStringEvaluation();
+end;
+
+function Locale.setIsAutoStringEvalEnabled(enabled)
+ return _system_locale_setCurrentThreadAutomaticLocalizedStringEvaluation(not not enabled);
+end;
+
+function Locale.eval(...)
+ return _system_locale_eval(...);
+end;
+
+function Locale.autoEval(...)
+ return _system_locale_autoEval(...);
+end;
+
+function Locale.__createNullLocalizedTexts()
+ local nullTxts = {};
+
+ function nullTxts:lang(textId)
+ error("No API Support");
+ end;
+
+ function nullTxts:tryLang(textId)
+ return nil;
+ end;
+
+ function nullTxts:loadTexts(langTexts)
+ end;
+
+ function nullTxts:addText(localeId, textId, text)
+ end;
+
+ return nullTxts;
+end;
+
+function Locale.newLocalizedTexts()
+ local txts = Objs.objectFromHandle(_obj_newObject("TLuaLocalizedTexts"));
+
+ function txts:addText(localeId, textId, text)
+ return _obj_invokeEx(self.handle, "AddText", localeId, textId, text);
+ end;
+
+ function txts:lang(textId)
+ return _obj_invokeEx(self.handle, "Lang", textId);
+ end;
+
+ function txts:loadTexts(langTexts)
+ return _obj_invokeEx(self.handle, "LoadTexts", langTexts);
+ end;
+
+ function txts:tryLang(textId)
+ return _obj_invokeEx(self.handle, "TryLang", textId);
+ end;
+
+ return txts;
+end;
+
+return Locale;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/log.lua b/Plugins/Sheets/Coyote and Crow/sdk/log.lua
new file mode 100644
index 00000000..35d31848
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/log.lua
@@ -0,0 +1,39 @@
+require("system.lua");
+
+Log = {}
+
+function Log.haveNativeBackendSupport()
+ return System.checkAPIVersion(87, 3)
+end;
+
+function Log.v(tag, msg)
+ if Log.haveNativeBackendSupport() then
+ return _system_log_v(tag, msg);
+ end;
+end;
+
+function Log.d(tag, msg)
+ if Log.haveNativeBackendSupport() then
+ return _system_log_d(tag, msg);
+ end;
+end;
+
+function Log.i(tag, msg)
+ if Log.haveNativeBackendSupport() then
+ return _system_log_i(tag, msg);
+ end;
+end;
+
+function Log.w(tag, msg)
+ if Log.haveNativeBackendSupport() then
+ return _system_log_w(tag, msg);
+ end;
+end;
+
+function Log.e(tag, msg)
+ if Log.haveNativeBackendSupport() then
+ return _system_log_e(tag, msg);
+ end;
+end;
+
+return Log
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/ndb.lua b/Plugins/Sheets/Coyote and Crow/sdk/ndb.lua
new file mode 100644
index 00000000..b3a55a6f
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/ndb.lua
@@ -0,0 +1,947 @@
+local objs = require("rrpgObjs.lua");
+local vhd = require("vhd");
+require("utils.lua");
+ndb = {}
+NDB = ndb;
+
+local localNDB = {};
+
+local _localOpenNDBs = {}
+setmetatable(_localOpenNDBs, objs.weakMetatable);
+
+function localNDB.ndbFromHandle(handle)
+ local ctrl;
+
+ if handle ~= nil then
+ ctrl = objs.tryFindFromHandle(handle);
+
+ if ctrl ~= nil then
+ return ctrl;
+ end;
+ else
+ return nil;
+ end;
+
+ ctrl = objs.objectFromHandle(handle);
+ ctrl.__dbFlag = true;
+
+ objs.registerHandle(handle, ctrl);
+ return ctrl;
+end;
+
+-- [[ Node class ]] --
+
+localNDB.Node = objs.newClass();
+
+function localNDB.Node:initialize()
+ rawset(self, "__nodeFlag", true);
+end;
+
+function localNDB.Node:findChild(nodeName)
+ local nh = _ndb_findChild(self.handle, nodeName);
+ return localNDB.openNode(nh);
+end;
+
+function localNDB.Node:getFacade()
+ local nodeFacade = rawget(self, "__nodeFacade");
+
+ if nodeFacade == nil then
+ nodeFacade = localNDB.newNodeFacadeFor(self);
+ rawset(self, "__nodeFacade", nodeFacade);
+ end;
+
+ return nodeFacade;
+end;
+
+function localNDB.Node:getAttribute(name)
+ return _ndb_getAttribute(self.handle, name);
+end;
+
+function localNDB.Node:setAttribute(name, value)
+ return _ndb_setAttribute(self.handle, name, value);
+end;
+
+function localNDB.Node:clearNode()
+ return _obj_invoke(self.handle, "ClearNode");
+end;
+
+function localNDB.Node:getAttributesNames()
+ return _ndb_getAttributesNames(self.handle);
+end;
+
+function localNDB.Node:getAllAttributes()
+ return _ndb_getAllAttributes(self.handle);
+end;
+
+function localNDB.Node:getChildCount()
+ return _ndb_getChildCount(self.handle);
+end;
+
+function localNDB.Node:getChild(indice)
+ return localNDB.openNode(_ndb_getChild(self.handle, indice));
+end;
+
+function localNDB.Node:getAllChilds()
+ local ret = {};
+ local count = self:getChildCount();
+
+ for i = 0, count - 1, 1 do
+ ret[i + 1] = self:getChild(i);
+ end;
+
+ return ret;
+end;
+
+function localNDB.Node:addChild(nodeName)
+ return localNDB.openNode(_ndb_addChild(self.handle, nodeName));
+end;
+
+function localNDB.Node:delete()
+ _obj_invoke(self.handle, "Delete");
+end;
+
+function localNDB.Node:getName()
+ return _ndb_getNodeName(self.handle);
+end;
+
+function localNDB.Node:getPersistedAttributeValue(attributeName)
+ return _ndb_getPersistedAttributeValue(self.handle, attributeName);
+end;
+
+function localNDB.Node:exportXML()
+ return _obj_invoke(self.handle, "ExportToXMLString");
+end;
+
+function localNDB.Node:importXML(xmlString)
+ return _obj_invoke(self.handle, "ImportXMLString", (tostring(xmlString)) or "");
+end;
+
+function localNDB.Node:getLocalID()
+ return _obj_getProp(self.handle, "LocalID");
+end;
+
+function localNDB.Node:beginUpdate()
+ _obj_invoke(self.handle, "BeginUpdate");
+end;
+
+function localNDB.Node:endUpdate()
+ _obj_invoke(self.handle, "EndUpdate");
+end;
+
+function localNDB.Node:getState()
+ return _obj_getProp(self.handle, "ProviderState");
+end;
+
+function localNDB.Node:setPermission(selKind, selId, permission, allowance)
+ return _obj_invokeEx(self.handle, "SetPermission", selKind, selId, permission, allowance);
+end;
+
+function localNDB.Node:getPermission(selKind, selId, permission)
+ return _obj_invokeEx(self.handle, "GetPermission", selKind, selId, permission);
+end;
+
+function localNDB.Node:testPermission(permission)
+ return _obj_invokeEx(self.handle, "TestPermission", permission);
+end;
+
+function localNDB.Node:enumPermissions()
+ return _obj_invokeEx(self.handle, "EnumPermissions");
+end;
+
+function localNDB.nodeFromHandle(nodeHandle)
+ local node;
+
+ if nodeHandle == nil then
+ return nil;
+ end;
+
+ node = objs.tryFindFromHandle(nodeHandle);
+
+ if node ~= nil then
+ return node;
+ end;
+
+ node = localNDB.Node.fromHandle(nodeHandle);
+ node.__nodeDatabase = localNDB.ndbFromHandle(_ndb_getNDBHandleOfNode(nodeHandle));
+
+ objs.registerHandle(nodeHandle, node);
+ return node;
+end;
+
+function localNDB.copyNodeToAnother(nodeDest, nodeSrc, ctxCtrl)
+ if (nodeDest == nil) or (nodeSrc == nil) or (nodeDest.handle == nodeSrc.handle) then
+ return;
+ end;
+
+ if ctxCtrl == nil then
+ ctxCtrl = {}; -- avoid circular reference
+ end;
+
+ if ctxCtrl[nodeSrc.handle] then
+ return;
+ else
+ ctxCtrl[nodeSrc.handle] = true;
+ end;
+
+ nodeDest:beginUpdate();
+
+ tryFinally(
+ function()
+ nodeDest:clearNode();
+
+ local allAtts = nodeSrc:getAllAttributes();
+
+ for k, v in pairs(allAtts) do
+ localNDB.assignPropValueToNode(nodeDest, k, v);
+ end;
+
+ local allChilds = nodeSrc:getAllChilds();
+ local newChild, srcChild;
+
+ for _, v in pairs(allChilds) do
+ srcChild = v;
+
+ if not ctxCtrl[srcChild.handle] then
+ newChild = nodeDest:addChild(srcChild:getName());
+
+ if newChild ~= nil then
+ localNDB.copyNodeToAnother(newChild, srcChild, ctxCtrl);
+ end;
+ end;
+ end;
+ end,
+
+ function()
+ nodeDest:endUpdate();
+ end);
+end;
+
+function localNDB.copyTableToNode(nodeDest, tableValue)
+ if (nodeDest == nil) then
+ return;
+ end;
+
+ nodeDest:clearNode();
+
+ for k, v in pairs(tableValue) do
+ localNDB.assignPropValueToNode(nodeDest, k, v);
+ end;
+end;
+
+function localNDB.assignPropValueToNode(node, prop, value)
+ prop = tostring(prop);
+
+ -- Limpando propriedade
+ if value == nil then
+ _obj_invoke(node.handle, "RemoveAtributeAndChildNodes", prop);
+ return;
+ end;
+
+ if type(value) == "function" then
+ -- Tipo inválido para setar
+ require("locale.lua");
+ error(string.format(lang("sdk3.err.ndb.functionAssign"), tostring(prop)));
+ return;
+ end;
+
+ if type(value) == "table" then
+ -- Setando um Table/Child Node
+ _obj_invoke(node.handle, "BeginUpdate");
+
+ tryFinally(
+ function()
+ node:setAttribute(prop, nil); -- remover atributo de mesmo nome se existir
+ local childNode = node:findChild(prop);
+
+ if childNode == nil then
+ childNode = node:addChild(prop); -- Nodo não existe, vamos criar um
+ end;
+
+ if childNode ~= nil then
+ if rawget(value, "__nodeFlag") then
+ -- é um node
+ localNDB.copyNodeToAnother(childNode, value);
+ elseif rawget(value, "__nodeFacadeFlag") then
+ -- é um node facade
+ localNDB.copyNodeToAnother(childNode, value.__node);
+ else
+ -- Aparentemente é um table comum
+ localNDB.copyTableToNode(childNode, value);
+ end;
+ end;
+ end,
+
+ function()
+ _obj_invoke(node.handle, "EndUpdate");
+ end);
+ else
+ -- Setando um Atributo
+ _obj_invoke(node.handle, "RemoveChildNodes", prop); -- remover todos os child nodes de mesmo nome
+ node:setAttribute(prop, value);
+ end;
+end;
+
+local NodeFacadeMetatable = {
+ --[[ getter padrão de propriedades dos objetos. Chamado quando tentou gettar uma propriedade que não existe ]]--
+ __index = function(table, key)
+ local v = rawget(table, key);
+
+ if (v ~= nil) then
+ return v;
+ end;
+
+ local node = rawget(table, "__node");
+
+ if node ~= nil then
+ local childNode = node:findChild(key);
+
+ if childNode ~= nil then
+ -- Achamos um child node com este nome.
+ return childNode:getFacade();
+ end;
+
+ return node:getAttribute(key);
+ end;
+
+ return nil;
+ end,
+
+ --[[ setter padrão de propriedades dos objetos. Chamado quando tentou settar uma propriedade que não existe ]]--
+ __newindex = function(table, key, value)
+ local node = rawget(table, "__node");
+
+ if node ~= nil then
+ localNDB.assignPropValueToNode(node, key, value);
+ end;
+ end,
+};
+
+function localNDB.newNodeFacadeFor(nodeObj)
+ local nodeFacade = {__node = nodeObj, __nodeFacadeFlag = true};
+ setmetatable(nodeFacade, NodeFacadeMetatable);
+ return nodeFacade;
+end;
+
+function localNDB.openNode(nodeHandle)
+ local nodeObj;
+
+ if nodeHandle == nil then
+ return nil;
+ end;
+
+ nodeObj = objs.tryFindFromHandle(nodeHandle);
+
+ if nodeObj == nil then
+ nodeObj = localNDB.nodeFromHandle(nodeHandle);
+ end;
+
+ return nodeObj;
+end;
+
+function localNDB.openNodeFacade(nodeHandle)
+ local nodeObj = localNDB.openNode(nodeHandle);
+
+ if nodeObj ~= nil then
+ return nodeObj:getFacade();
+ else
+ return nil;
+ end;
+end;
+
+function localNDB.getNodeObjectFromFacade(nodeFacade)
+ return rawget(nodeFacade, "__node");
+end;
+
+function _export_ndb_openNodeFacade(nodeHandle)
+ return localNDB.openNodeFacade(nodeHandle);
+end;
+
+-- Funções exportadas
+
+function ndb.openNodeDatabaseFromHandle(nodeDatabaseHandle)
+ return localNDB.ndbFromHandle(nodeDatabaseHandle);
+end;
+
+function ndb.load(fileName, userName)
+ local expandedName = vhd.expandFileName(fileName);
+
+ if #expandedName > 0 then
+ if string.sub(expandedName, 1, 1) ~= "/" then
+ expandedName = "/" .. expandedName;
+ end;
+ end;
+
+ if type(userName) ~= "string" then
+ userName = "";
+ end;
+
+ local openDB = _localOpenNDBs[expandedName];
+
+ if openDB ~= nil then
+ return ndb.getRoot(openDB);
+ end;
+
+ openDB = ndb.openNodeDatabaseFromHandle(_obj_newObject("TLocalLuaNodeDatabase"));
+ _obj_invoke(openDB.handle, "SetupLocalFile", expandedName, userName);
+ _localOpenNDBs[expandedName] = openDB;
+ return ndb.getRoot(openDB);
+end;
+
+function ndb.newMemNodeDatabase(initialContent)
+ local openDB = ndb.openNodeDatabaseFromHandle(_obj_newObject("TLuaMemoryNodeDatabase", initialContent));
+ return ndb.getRoot(openDB);
+end;
+
+function ndb.getRoot(node)
+ if type(node) ~= "table" then
+ return nil;
+ end;
+
+ if node.__nodeFlag then
+ return localNDB.openNodeFacade(_ndb_getTheRoot(node.handle));
+ elseif node.__nodeFacadeFlag then
+ return ndb.getRoot(rawget(node, "__node"));
+ elseif node.__dbFlag then
+ return localNDB.openNodeFacade(_ndb_getRoot(node.handle));
+ else
+ return nil;
+ end;
+end;
+
+function ndb.getParent(node)
+ if type(node) ~= "table" then
+ return nil;
+ end;
+
+ if node.__nodeFlag then
+ return localNDB.openNodeFacade(_ndb_getParent(node.handle));
+ elseif node.__nodeFacadeFlag then
+ return ndb.getParent(rawget(node, "__node"));
+ else
+ return nil;
+ end;
+end;
+
+function ndb.openNodeFacade(nodeHandle)
+ return localNDB.openNodeFacade(nodeHandle);
+end;
+
+function ndb.getChildNodes(nodeObj)
+ if (nodeObj == nil) then
+ return {};
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ local nodesCtrls = node:getAllChilds();
+ local ret = {};
+
+ for i = 1, #nodesCtrls, 1 do
+ ret[i] = nodesCtrls[i]:getFacade();
+ end;
+
+ return ret;
+ else
+ return {};
+ end;
+end;
+
+function ndb.getAttributes(nodeObj)
+ if (nodeObj == nil) then
+ return {};
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ return node:getAllAttributes();
+ else
+ return {};
+ end;
+end;
+
+function ndb.isNodeObject(value)
+ if type(value) ~= "table" then
+ return false;
+ end;
+
+ return rawget(value, "__nodeFacadeFlag");
+end;
+
+function ndb.getNodeHandle(nodeObject)
+ if ndb.isNodeObject(nodeObject) then
+ return nodeObject.__node.handle;
+ else
+ return nil;
+ end;
+end;
+
+function ndb.createChildNode(nodeObj, childName)
+ if (nodeObj == nil) then
+ return nil;
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ local childNode = node:addChild(childName);
+
+ if childNode ~= nil then
+ return childNode:getFacade();
+ else
+ return nil;
+ end;
+ else
+ return nil;
+ end;
+end;
+
+function ndb.deleteNode(nodeObj)
+ if (nodeObj == nil) then
+ return;
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ node:delete();
+ end;
+end;
+
+function ndb.clearNode(nodeObj)
+ if (nodeObj == nil) then
+ return;
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ node:clearNode();
+ end;
+end;
+
+function ndb.getNodeName(nodeObj)
+ if (nodeObj == nil) then
+ return nil;
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ return node:getName();
+ else
+ return nil;
+ end;
+end;
+
+function ndb.getPersistedAttributeValue(nodeObj, attributeName)
+ if (nodeObj == nil) then
+ return nil;
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ return node:getPersistedAttributeValue(attributeName);
+ else
+ return nil;
+ end;
+end;
+
+function ndb.exportXML(nodeObj)
+ if (nodeObj == nil) then
+ local aLocale = require("locale.lua");
+ error(aLocale.lang("sdk3.err.ndb.func.exportToXML.invalidPar"));
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ return node:exportXML();
+ else
+ local aLocale = require("locale.lua");
+ error(aLocale.lang("sdk3.err.ndb.func.exportToXML.invalidPar"));
+ end;
+end;
+
+function ndb.importXML(nodeObj, xmlString)
+ if (nodeObj == nil) then
+ local aLocale = require("locale.lua");
+ error(aLocale.lang("sdk3.err.ndb.func.importXML.invalidPar"));
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ return node:importXML(xmlString);
+ else
+ local aLocale = require("locale.lua");
+ error(aLocale.lang("sdk3.err.ndb.func.importXML.invalidPar"));
+ end;
+end;
+
+function ndb.copy(destNodeObj, srcNodeObj)
+ if (destNodeObj == nil) then
+ local aLocale = require("locale.lua");
+ error(aLocale.lang("sdk3.err.ndb.func.copy.invalidPar2"));
+ end;
+
+ local srcNode;
+ local dstNode = localNDB.getNodeObjectFromFacade(destNodeObj);
+
+ if srcNodeObj ~= nil then
+ srcNode = localNDB.getNodeObjectFromFacade(srcNodeObj);
+ else
+ srcNode = nil;
+ end;
+
+ if dstNode ~= nil then
+ if srcNode ~= nil then
+ local xmlString = srcNode:exportXML();
+ dstNode:importXML(xmlString);
+ else
+ dstNode:clearNode();
+ end;
+ else
+ local aLocale = require("locale.lua");
+ error(aLocale.lang("sdk3.err.ndb.func.copy.invalidPar2"));
+ end;
+end;
+
+function ndb.beginUpdate(nodeObj)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ node:beginUpdate();
+ end;
+ end;
+end;
+
+function ndb.endUpdate(nodeObj)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ node:endUpdate();
+ end;
+ end;
+end;
+
+function ndb.getState(nodeObj)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ return node:getState();
+ end;
+ end;
+
+ return "closed";
+end;
+
+local _observerBib = nil;
+
+function ndb.newObserver(nodeObj)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ if _observerBib == nil then
+ _observerBib = require("ndb_observer.dlua");
+ end;
+
+ return _observerBib.newObserver(node.handle, nodeObj);
+ end;
+ end;
+
+ return nil;
+end;
+
+function ndb.setPermission(node, selKind, selId, permission, allowance)
+ if node ~= nil then
+ local nodeObj = localNDB.getNodeObjectFromFacade(node);
+
+ if nodeObj ~= nil then
+ return nodeObj:setPermission(tostring(selKind), tostring(selId), tostring(permission), allowance);
+ end;
+ end;
+end;
+
+function ndb.getPermission(node, selKind, selId, permission)
+ if node ~= nil then
+ local nodeObj = localNDB.getNodeObjectFromFacade(node);
+
+ if nodeObj ~= nil then
+ return nodeObj:getPermission(tostring(selKind), tostring(selId), tostring(permission));
+ end;
+ end;
+
+ return nil;
+end;
+
+function ndb.testPermission(node, permission)
+ if node ~= nil then
+ local nodeObj = localNDB.getNodeObjectFromFacade(node);
+
+ if nodeObj ~= nil then
+ return nodeObj:testPermission(tostring(permission));
+ end;
+ end;
+
+ return false;
+end;
+
+function ndb.enumPermissions(node)
+ if node ~= nil then
+ local nodeObj = localNDB.getNodeObjectFromFacade(node);
+
+ if nodeObj ~= nil then
+ return nodeObj:enumPermissions();
+ end;
+ end;
+
+ return {};
+end;
+
+function ndb.resetPermissions(node)
+ if node ~= nil then
+ local nodeObj = localNDB.getNodeObjectFromFacade(node);
+
+ if nodeObj ~= nil then
+ _obj_invoke(nodeObj.handle, "ResetPermissions");
+ end;
+ end;
+
+ return {};
+end;
+
+local _transactionBib = nil;
+
+function ndb.newTransaction(nodeObj)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ if _transactionBib == nil then
+ _transactionBib = require("ndb_transaction.dlua");
+ end;
+
+ return _transactionBib.newTransaction(node.handle, nodeObj);
+ end;
+ end;
+
+ return nil;
+end;
+
+function ndb.pushTransaction(nodeObj, transaction)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ local trHandle;
+
+ if transaction ~= nil then
+ trHandle = transaction.handle or 0;
+ else
+ trHandle = 0;
+ end;
+
+ _obj_invoke(node.handle, "PushTransaction", trHandle);
+ end;
+ end;
+end;
+
+function ndb.popTransaction(nodeObj)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ _obj_invoke(node.handle, "PopTransaction");
+ end;
+ end;
+end;
+
+function ndb.getServerUTCTime(nodeObj)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ return _obj_getProp(node.handle, "ServerUTCTime");
+ end;
+ end;
+end;
+
+function ndb.editPermissions(nodeObj)
+ if nodeObj == nil then
+ return;
+ end;
+
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ local plugins = require("plugins.lua");
+ local ndbmodule = "RRPG.FIRECAST.FMXModule";
+ plugins.sendPM(ndbmodule, "ndbHost:editPermissions", {localNodeID=node:getLocalID()}, nil, nil);
+ end;
+end;
+
+function ndb.loadNodeFromLocalID(localNodeID)
+ return _ndb_tryLoadNodeFromLocalID(localNodeID);
+end;
+
+local _Serializer = nil;
+
+function ndb.broadcastMessage(nodeObj, messageId, message, loopBack)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ if _Serializer == nil then
+ _Serializer = require("utils.serializer.dlua");
+ end;
+
+ if loopBack == nil then
+ loopBack = false;
+ end;
+
+ _obj_invokeEx(node.handle, "LUABroadcastMessage", messageId, _Serializer.serialize(message), loopBack);
+ end;
+ end;
+end;
+
+function ndb.newBroadcastListener(nodeObj, messageId, callback)
+ if nodeObj ~= nil then
+ local node = localNDB.getNodeObjectFromFacade(nodeObj);
+
+ if node ~= nil then
+ local obj = objs.objectFromHandle(_obj_newObject("TLuaNDBBroadcastReceiver"));
+ obj.eves = obj.eves or {};
+ obj.eves["onReceiveBroadcast"] = "sender, messageId, messageText";
+
+ _obj_invoke(obj.handle, "SetupReceiver", node.handle, messageId or "");
+
+ obj.onReceiveBroadcast = function(sender, returnedMessageId, messageText)
+ if callback ~= nil then
+ if _Serializer == nil then
+ _Serializer = require("utils.serializer.dlua");
+ end;
+
+ local success, message = pcall(_Serializer.deserialize, messageText);
+
+ if not success then
+ message = messageText;
+ end;
+
+ callback(sender, returnedMessageId, message);
+ end;
+ end;
+ return obj;
+ end;
+ end;
+end;
+
+function ndb.onReady(nodeObj, callback, failCallback)
+ local function scheduleFailReturn()
+ if failCallback ~= nil then
+ setTimeout(failCallback, 1, nil);
+ end;
+ end;
+
+ if nodeObj == nil then
+ scheduleFailReturn();
+ return;
+ end;
+
+ local state = ndb.getState(nodeObj);
+
+ if state == "open" then
+ -- Already loaded
+
+ if callback ~= nil then
+ setTimeout(callback, 1, nodeObj);
+ end;
+
+ return;
+ end;
+
+ -- Not loaded yet, letz monitor
+ local nodeInternObj = localNDB.getNodeObjectFromFacade(nodeObj);
+ local ndbObj = localNDB.ndbFromHandle(_ndb_getNDBHandleOfNode(nodeInternObj.handle));
+ local jaNotificou = false;
+ local listenerProvider = nil;
+ local listenerLoaded = nil;
+
+ local function checkState()
+ if not jaNotificou then
+ state = ndb.getState(nodeObj);
+
+ if state == "open" then
+ jaNotificou = true;
+
+ if callback ~= nil then
+ setTimeout(callback, 1, nodeObj);
+ end;
+ elseif state == "closed" then
+ jaNotificou = true;
+ scheduleFailReturn();
+ end;
+
+ if jaNotificou then
+ ndbObj:removeEventListener(listenerProvider);
+ ndbObj:removeEventListener(listenerLoaded);
+ end;
+ end;
+ end;
+
+ listenerProvider = ndbObj:addEventListener("OnProviderStateChange", checkState);
+ listenerLoaded = ndbObj:addEventListener("OnLoaded", checkState);
+
+ checkState();
+end;
+
+-- OVERRIDE de funções nativas para funcionar com o NDB
+
+local oldPairsFunc = pairs;
+local oldIPairsFunc = ipairs;
+
+local function _prepareNodeFacadePairsState(nodeFacade)
+ local node = nodeFacade.__node;
+ local state = node:getAllAttributes();
+
+ local childs = node:getAllChilds();
+
+ for _, v in oldPairsFunc(childs) do
+ local name = v:getName();
+ local nodeForName = node:findChild(name);
+
+ if nodeForName ~= nil then
+ state[name] = nodeForName;
+ end;
+ end;
+
+ return state;
+end;
+
+function pairs(obj)
+ if (obj ~= nil) and rawget(obj, "__nodeFacadeFlag") then
+ -- Node Façade
+ local state = _prepareNodeFacadePairsState(obj);
+ return oldPairsFunc(state);
+ else
+ return oldPairsFunc(obj);
+ end;
+end;
+
+function ipairs(obj)
+ if (obj ~= nil) and rawget(obj, "__nodeFacadeFlag") then
+ -- Node Façade
+ local state = _prepareNodeFacadePairsState(obj);
+ return oldIPairsFunc(state);
+ else
+ return oldIPairsFunc(obj);
+ end;
+end;
+
+return ndb;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/ndb_observer.dlua b/Plugins/Sheets/Coyote and Crow/sdk/ndb_observer.dlua
new file mode 100644
index 00000000..e7a80b54
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/ndb_observer.dlua
@@ -0,0 +1,51 @@
+local objs = require("rrpgObjs.lua");
+local nO = {};
+
+local _observerProps = {};
+local _observerEves = {};
+
+_observerProps["enabled"] = {setter = "setEnabled", getter = "getEnabled", tipo="bool"};
+
+_observerEves["onChildAdded"] = "node";
+_observerEves["onChildRemoved"] = "node";
+_observerEves["onDeepChildAdded"] = "node";
+_observerEves["onDeepChildRemoved"] = "node";
+_observerEves["onDeleted"] = "node";
+_observerEves["onChanged"] = "node, attribute, oldValue";
+_observerEves["onDeepChanged"] = "node, attribute, oldValue";
+_observerEves["onUserChanged"] = "node, attribute, oldValue";
+_observerEves["onDeepUserChanged"] = "node, attribute, oldValue";
+_observerEves["onPersistedChanged"] = "node, attribute, oldValue";
+_observerEves["onDeepPersistedChanged"] = "node, attribute, oldValue";
+_observerEves["onPermissionListChanged"] = "node";
+_observerEves["onDeepPermissionListChanged"] = "node";
+_observerEves["onFinalPermissionsCouldBeChanged"] = "node";
+_observerEves["onStateChanged"] = "node";
+
+local function _observerFromHandle(handle)
+ local obj = objs.tryFindFromHandle(handle);
+
+ if obj ~= nil then
+ return obj;
+ end;
+
+ obj = objs.objectFromHandle(handle);
+ objs.registerHandle(handle, obj);
+
+ function obj:getEnabled() return _obj_getProp(self.handle, "Enabled"); end;
+ function obj:setEnabled(v) _obj_setProp(self.handle, "Enabled", v); end;
+
+
+ obj.props = _observerProps;
+ obj.eves = _observerEves;
+ return obj;
+end;
+
+function nO.newObserver(nodeHandle, nodeObj)
+ local observer = _observerFromHandle(_obj_newObject("TLuaNodeObserver"));
+ _obj_invokeEx(observer.handle, "SetNodeHandle", nodeHandle);
+ rawset(observer, "node", nodeObj);
+ return observer;
+end;
+
+return nO;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/ndb_transaction.dlua b/Plugins/Sheets/Coyote and Crow/sdk/ndb_transaction.dlua
new file mode 100644
index 00000000..6ea1b512
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/ndb_transaction.dlua
@@ -0,0 +1,53 @@
+local objs = require("rrpgObjs.lua");
+local nO = {};
+
+local _transactionProps = {};
+local _transactionEves = {};
+local _transactionMethods = {};
+
+function _transactionMethods.commit(tr)
+ _obj_invoke(tr.handle, "Commit");
+end;
+
+function _transactionMethods.rollback(tr)
+ _obj_invoke(tr.handle, "Rollback");
+end;
+
+function _transactionMethods.createUndoData(tr)
+ local handle = _obj_invoke(tr.handle, "CreateUndoData");
+ local obj = objs.objectFromHandle(handle);
+ objs.registerHandle(handle, obj);
+ return obj;
+end;
+
+function _transactionMethods.applyUndoData(tr, undoData)
+ _obj_invoke(tr.handle, "ApplyUndoData", undoData.handle);
+end;
+
+local function _transactionFromHandle(handle)
+ local obj = objs.tryFindFromHandle(handle);
+
+ if obj ~= nil then
+ return obj;
+ end;
+
+ obj = objs.objectFromHandle(handle);
+ objs.registerHandle(handle, obj);
+
+ for k, v in pairs(_transactionMethods) do
+ rawset(obj, k, v);
+ end;
+
+ obj.props = _transactionProps;
+ obj.eves = _transactionEves;
+ return obj;
+end;
+
+function nO.newTransaction(nodeHandle, nodeObj)
+ local transaction = _transactionFromHandle(_obj_newObject("TLuaNodeTransaction"));
+ _obj_invokeEx(transaction.handle, "InitializeFromNodeHandle", nodeHandle);
+ rawset(transaction, "node", nodeObj);
+ return transaction;
+end;
+
+return nO;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/plugins.lua b/Plugins/Sheets/Coyote and Crow/sdk/plugins.lua
new file mode 100644
index 00000000..6c014411
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/plugins.lua
@@ -0,0 +1,6 @@
+local rrpg = require("rrpg.lua");
+local plugins = require("delayedLoad.dlua").new("pluginsCore.dlua");
+
+rrpg.plugins = plugins;
+rrpg.Plugins = plugins;
+return plugins;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/pluginsCore.dlua b/Plugins/Sheets/Coyote and Crow/sdk/pluginsCore.dlua
new file mode 100644
index 00000000..520efd1e
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/pluginsCore.dlua
@@ -0,0 +1,243 @@
+require("rrpgObjs.lua");
+require("utils.lua");
+require("rrpg.lua");
+local plugins = {};
+local serializer = nil;
+
+function plugins.getInstalledDataTypes()
+ local retorno = _rrpg_plugins_getInstalledDataTypes();
+
+ if type(retorno) == "table" then
+ return retorno;
+ else
+ return {};
+ end;
+end;
+
+function plugins.getInstalledPlugins()
+ local retorno = _rrpg_plugins_getInstalledPlugins();
+
+ if type(retorno) == "table" then
+ return retorno;
+ else
+ return {};
+ end;
+end;
+
+function plugins.getRPKDetails(stream)
+ if type(stream) == "table" then
+ return _rrpg_plugins_getPackageInfos(stream.handle);
+ else
+ return nil;
+ end;
+end;
+
+function plugins.installPlugin(stream, ignoreIfOlder)
+ if type(stream) ~= "table" then
+ return false, "Invalid stream parameter";
+ end;
+
+ ignoreIfOlder = not (not ignoreIfOlder);
+ return _rrpg_plugins_installPluginPackage(stream.handle, ignoreIfOlder);
+end;
+
+function plugins.uninstallPlugin(moduleId)
+ return _rrpg_plugins_uninstallPluginPackage(moduleId);
+end;
+
+local pmListenersByName = {};
+local pmGeneratorId = 0;
+local pmPrefixID = _rrpg_generateUniqueStrID() .. "_";
+local pmSent = {};
+
+local function __convertIncomingPMData(data)
+ if serializer == nil then
+ serializer = require("utils.serializer.dlua");
+ end;
+
+ return serializer.deserialize(data);
+end;
+
+local function __convertOutgoingPMData(data)
+ if serializer == nil then
+ serializer = require("utils.serializer.dlua");
+ end;
+
+ return serializer.serialize(data);
+end;
+
+function plugins.sendPM(moduleId, pmName, data, returnCallback, failureCallback)
+ pmGeneratorId = pmGeneratorId + 1;
+ local esteId = pmPrefixID .. tostring(pmGeneratorId);
+ local pmObject = {};
+ pmObject.returnCallback = returnCallback;
+ pmObject.failureCallback = failureCallback;
+
+ --[[if type(data) ~= "table" then
+ data = {data=data};
+ end;]]
+
+ data = __convertOutgoingPMData(data);
+ pmSent[esteId] = pmObject;
+
+ local ret, msg = _rrpg_plugins_sendPM(esteId, moduleId, pmName, data);
+
+ if not ret then
+ pmSent[esteId] = nil;
+
+ if failureCallback ~= nil then
+ failureCallback(msg);
+ end;
+ end;
+end;
+
+function plugins.replyPM(message, data)
+ if not message.__replied then
+ message.__replied = true;
+ _rrpg_plugins_sendPMReply(message.__msgId, message.moduleId, true, __convertOutgoingPMData(data));
+ end;
+end;
+
+function plugins.replyPMFailure(message, failureData)
+ if not message.__replied then
+ message.__replied = true;
+ _rrpg_plugins_sendPMReply(message.__msgId, message.moduleId, false, __convertOutgoingPMData(failureData));
+ end;
+end;
+
+function plugins.setLatePMReply(message)
+ message.__isLateReply = true;
+end;
+
+function plugins.listenPM(pmName, callback)
+ local listener = pmListenersByName[pmName];
+
+ if listener ~= nil then
+ listener.callback = callback;
+ return pmName;
+ end;
+
+ listener = {};
+ listener.callback = callback;
+ listener.pmName = pmName;
+ pmListenersByName[pmName] = listener;
+ return pmName;
+end;
+
+function plugins.unlistenPM(listenerId)
+ local listener = pmListenersByName[listenerId]; -- listenerId é o pmName
+
+ if listener ~= nil then
+ pmListenersByName[listenerId] = nil;
+ listener.callback = nil;
+ end;
+end;
+
+function plugins.requirePlugin(moduleId)
+ return _rrpg_plugins_requirePlugin(moduleId);
+end;
+
+function __export_plugins_handlePMResponse(msgId, success, data)
+ local pmObject = pmSent[msgId];
+
+ if pmObject ~= nil then
+ pmSent[msgId] = nil;
+ data = __convertIncomingPMData(data);
+
+ if success then
+ if pmObject.returnCallback ~= nil then
+ pmObject.returnCallback(data);
+ end;
+ else
+ if pmObject.failureCallback ~= nil then
+ pmObject.failureCallback(data);
+ end;
+ end;
+ end;
+end;
+
+function __export_plugins_handlePMResponse(msgId, success, data)
+ local pmObject = pmSent[msgId];
+
+ if pmObject ~= nil then
+ pmSent[msgId] = nil;
+ data = __convertIncomingPMData(data);
+
+ if success then
+ if pmObject.returnCallback ~= nil then
+ pmObject.returnCallback(data);
+ end;
+ else
+ if pmObject.failureCallback ~= nil then
+ pmObject.failureCallback(data);
+ end;
+ end;
+
+ return true;
+ else
+ return false;
+ end;
+end
+
+function __export_plugins_handleIncomingPM(fromModuleId, msgId, pmName, data)
+ local listener = pmListenersByName[pmName];
+
+ if listener ~= nil and listener.callback ~= nil then
+ local message = {};
+ data = __convertIncomingPMData(data);
+
+ if type(data) ~= "table" then
+ data = {data=data};
+ end;
+
+ for k, v in pairs(data) do
+ message[k] = v;
+ end;
+
+ message.moduleId = fromModuleId;
+ message.__msgId = msgId;
+
+ setTimeout(
+ function()
+ local r, ret = pcall(listener.callback, message);
+
+ if r then
+ if not message.__isLateReply and not message.__replied then
+ plugins.replyPM(message, ret);
+ end;
+ else
+ plugins.replyPMFailure(message, ret);
+ end;
+ end, 0);
+
+ return true;
+ else
+ return false;
+ end;
+end
+
+function plugins.getInstalledTablesDock()
+ return _rrpg_plugins_getInstalledTablesDock();
+end;
+
+function plugins.activateTablesDock(mesa, moduleId, name, storedInfo)
+ return _rrpg_plugins_activateTablesDock(mesa.objectID, moduleId, name, storedInfo or "");
+end;
+
+function plugins.deactivateTablesDock(mesa, moduleId, name)
+ return _rrpg_plugins_deactivateTablesDock(mesa.objectID, moduleId, name);
+end;
+
+function plugins.getIsTablesDockActive(mesa, moduleId, name)
+ return _rrpg_plugins_getIsTablesDockActive(mesa.objectID, moduleId, name);
+end;
+
+function plugins.getActiveTablesDockStoredInfo(mesa, moduleId, name)
+ return _rrpg_plugins_getActiveTablesDockStoredInfo(mesa.objectID, moduleId, name);
+end;
+
+function plugins.getListOfActiveTablesDockOnMesa(mesa)
+ return _rrpg_plugins_getListOfActiveTablesDockOnMesa(mesa.objectID);
+end;
+
+return plugins;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpg.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpg.lua
new file mode 100644
index 00000000..0e7300c4
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpg.lua
@@ -0,0 +1,442 @@
+require("rrpgEvents.lua");
+local ndb = require("ndb.lua");
+local objs = require("rrpgObjs.lua");
+local rrpgWrappers = require("rrpgWrappers.lua");
+local Async = require("async.lua")
+
+--[[ API do RRPG ]]--
+
+rrpg = objs.objectFromHandle(_obj_newObject("TRRPGMainWrapper"));
+RRPG = rrpg;
+Firecast = rrpg;
+
+local localRRPG = rrpg;
+objs.registerHandle(rrpg.handle);
+
+rawset(rrpg, "listeners", {generator = 0});
+rawset(rrpg, "dataTypes", {});
+rawset(rrpg, "forms", {});
+rawset(rrpg, "props", {});
+
+function rrpg:getMesas()
+ local hs = _rrpg_GetMesasIDs();
+ local mesas = {};
+ local idx = 1;
+
+ for i = 1, #hs, 1 do
+ local mesaObj = localRRPG.contextObjectFromID(hs[i]);
+
+ if (mesaObj ~= nil) then
+ mesas[idx] = mesaObj;
+ idx = idx + 1;
+ end;
+ end
+
+ return mesas;
+end;
+
+local propsRolagem = {
+ possuiAlgumDado = {getter="getPossuiAlgumDado", tipo="bool"},
+ isRolado = {getter="getIsRolado", tipo="bool"},
+ resultado = {getter="getResultado", tipo="int"},
+ asString = {getter="getAsString", tipo="string"},
+ tipo = {getter="getTipo", tipo="enum",
+ values={"direta", "storyteller"}}
+};
+
+local function newRolagemObject()
+ local rolObj = objs.objectFromHandle(_obj_newObject("TRRPGLuaRolagem"));
+
+ function rolObj:getTipo() return _obj_getProp(self.handle, "TipoRolagem"); end;
+
+ function rolObj:_readOps()
+ local nOps = {};
+ local idxAtual = 1;
+ local rolado = _obj_getProp(self.handle, "IsRolado");
+
+ _obj_invoke(self.handle, "NavigatorBegin");
+
+ while (not _obj_getProp(self.handle, "IsNavigatorEOF")) do
+ local sOp = {};
+ sOp.tipo = string.lower(_obj_getProp(self.handle, "NavigatorTipoOperacao"));
+
+ if sOp.tipo == "dado" then
+ sOp.quantidade = _obj_getProp(self.handle, "NavigatorDadosQuantidade");
+ local faceStr = _obj_getProp(self.handle, "NavigatorDadosFace");
+ local faceAsNumber = tonumber(faceStr);
+
+ if faceAsNumber ~= nil then
+ sOp.face = faceAsNumber;
+ else
+ sOp.face = faceStr;
+ end;
+
+ if rolado then
+ sOp.resultados = _obj_getProp(self.handle, "NavigatorGetResultadoDados");
+ else
+ sOp.resultados = {};
+ end;
+ elseif sOp.tipo == "comparacao" then
+ sOp.comparacao = _obj_getProp(self.handle, "NavigatorComparacao");
+ elseif sOp.tipo == "imediato" then
+ sOp.valor = _obj_getProp(self.handle, "NavigatorGetImediatoValue");
+ end;
+
+ nOps[idxAtual] = sOp;
+ idxAtual = idxAtual + 1;
+
+ _obj_invoke(self.handle, "NavigatorNext");
+ end
+
+ rawset(self, "ops", nOps);
+ end;
+
+ function rolObj:interpretarString(str) local ret = _obj_invoke(self.handle, "InterpretarString", str or ""); self:_readOps(); return ret; end;
+
+ function rolObj:getPossuiAlgumDado()
+ local lOps = rawget(self, "ops");
+
+ if lOps ~= nil then
+ for i, k in pairs(lOps) do
+ if k.tipo == "dado" then
+ return true;
+ end;
+ end;
+ end;
+
+ return false;
+ end;
+
+ function rolObj:getIsRolado() return _obj_getProp(self.handle, "IsRolado"); end;
+ function rolObj:getResultado() return _obj_getProp(self.handle, "Resultado"); end;
+ function rolObj:getAsString() return _obj_getProp(self.handle, "RolagemAsStr"); end;
+
+ function rolObj:concatenar(rolDir)
+ local rolDirObj;
+
+ if type(rolDir) == "string" then
+ rolDirObj = localRRPG.interpretarRolagem(rolDir);
+ elseif type(rolDir) == "table" then
+ rolDirObj = rolDir;
+ elseif type(rolDir) == "number" then
+ rolDirObj = localRRPG.interpretarRolagem(tostring(rolDir));
+ else
+ error("Cant concatenate rolls with the type " .. type(rolDir));
+ end;
+
+ local ret = _obj_invoke(self.handle, "Concatenar", rolDirObj.handle);
+
+ if ret then
+ self:_readOps();
+ end;
+
+ return self;
+ end;
+
+ function rolObj:rolarLocalmente() _obj_invoke(self.handle, "RolarLocalmente"); self:_readOps(); end;
+ function rolObj:loadFromBase64EncodedString(str) _obj_invoke(self.handle, "LoadFromBase64EncodedString", str); self:_readOps(); end;
+
+ rolObj.props = propsRolagem;
+ objs.registerHandle(rolObj.handle, rolObj);
+ return rolObj;
+end;
+
+function rrpg.interpretarRolagem(stringDaRolagem)
+ local rolObj = newRolagemObject();
+ rolObj:interpretarString(stringDaRolagem);
+ return rolObj;
+end;
+
+function rrpg.loadRolagemFromBase64EncodedString(encodedString)
+ local rolObj = newRolagemObject();
+ rolObj:loadFromBase64EncodedString(encodedString);
+ return rolObj;
+end
+
+function rrpg.contextObjectFromID(objectID)
+ return rrpgWrappers.contextObjectFromID(objectID);
+end;
+
+function rrpg.objectFromID(objectID)
+ return localRRPG.contextObjectFromID(objectID);
+end;
+
+function rrpg.getMesaFromNodeDataBase()
+end;
+
+function rrpg.getMesaFromSheet(sheet)
+ return rrpg.getMesaFromNodeDataBase(sheet);
+end;
+
+function rrpg.findMesa(codigoInterno)
+ local mesas = rrpg.getMesas();
+
+ for i = 1, #mesas, 1 do
+ local mesa = mesas[i];
+
+ if mesa.codigoInterno == codigoInterno then
+ return mesa;
+ end;
+ end;
+
+ return nil;
+end;
+
+function rrpg.getMesaDe(object)
+ if type(object) == "number" then
+ return rrpg.findMesa(object);
+ end;
+
+ if (type(object) ~= "table") then
+ return nil;
+ end;
+
+ local handle = rawget(object, "handle");
+ local mesaObjectID;
+
+ if handle == nil then
+ if ndb.isNodeObject(object) then
+ handle = ndb.getNodeHandle(object);
+ end;
+ end;
+
+ if handle ~= nil then
+ mesaObjectID = _rrpg_tryGetMesaObjectIDRelatedToHandle(handle);
+
+ if (mesaObjectID ~= nil) then
+ mesaObjectID = tonumber(mesaObjectID);
+ end;
+
+ if mesaObjectID ~= nil then
+ return rrpg.objectFromID(mesaObjectID);
+ end;
+ end;
+
+ return nil;
+end;
+
+function rrpg.getBibliotecaItemDe(object)
+ if (type(object) ~= "table") then
+ return nil;
+ end;
+
+ local handle = rawget(object, "handle");
+ local bibObjectID;
+
+ if handle == nil then
+ if ndb.isNodeObject(object) then
+ handle = ndb.getNodeHandle(object);
+ end;
+ end;
+
+ if handle ~= nil then
+ bibObjectID = _rrpg_tryGetBibItemObjectIDRelatedToHandle(handle);
+
+ if (bibObjectID ~= nil) then
+ bibObjectID = tonumber(bibObjectID);
+ end;
+
+ if bibObjectID ~= nil then
+ return rrpg.objectFromID(bibObjectID);
+ end;
+ end;
+
+ return nil;
+end;
+
+function rrpg.getPersonagemDe(object)
+ local ctxObj = localRRPG.getBibliotecaItemDe(object);
+
+ if (ctxObj ~= nil) and (ctxObj:isType("personagem")) then
+ return ctxObj;
+ else
+ return nil;
+ end;
+end;
+
+function rrpg.getCurrentUser()
+ return _rrpg_getCurrentUser();
+end;
+
+function rrpg.ouvir(eventos)
+ if (eventos == nil) then
+ return;
+ end
+
+ for k, v in pairs(eventos) do
+ if (type(v == "function")) then
+ local t = localRRPG.listeners[k];
+
+ if (t == nil) then
+ t = {};
+ localRRPG.listeners[k] = t;
+ end;
+
+ localRRPG.listeners.generator = localRRPG.listeners.generator + 1;
+ t[localRRPG.listeners.generator] = v;
+
+ _rrpg_KnownEvent(k);
+ end
+ end;
+end
+
+function rrpg.on(eventName, callbackFunction)
+ local tabela = {};
+ tabela[eventName] = callbackFunction;
+ rrpg.ouvir(tabela);
+end;
+
+function on(eventName, callbackFunction)
+ rrpg.on(eventName, callbackFunction);
+end;
+
+function rrpg.dispatch(eventName, ...)
+ local t = localRRPG.listeners[eventName];
+
+ if (t == nil) then
+ return;
+ end;
+
+ for k,v in pairs(t) do
+ v(...);
+ end;
+end
+
+function rrpg.registrarDataType(dt)
+ if type(dt) == 'table' then
+ if ((dt.dataType ~= nil) and (dt.dataType ~= "")) then
+ localRRPG.dataTypes[dt.dataType] = dt;
+ _rrpg_DataTypes_Registrar(dt);
+ end;
+ end;
+end;
+
+function rrpg.registrarForm(frm)
+ if type(frm) == 'table' then
+ if (frm.name ~= nil) then
+ localRRPG.forms[frm.name] = frm;
+ _rrpg_Forms_RegisterForm(frm);
+ end;
+ end;
+end;
+
+function rrpg.registrarSpecialForm(frm)
+ if (type(frm) == 'table') and (frm.name ~= nil) then
+ _rrpg_Forms_RegistrarSpecial(frm);
+ end;
+end;
+
+local __registeredToolButtons = nil;
+
+function rrpg.registerChatToolButton(params)
+ if type(params) ~= "table" then
+ error("registerChatToolButton: params must be a table");
+ end;
+
+ local regClass = objs.objectFromHandle(_obj_newObject("TRRPGLuaRegisteredChatToolButton"));
+ objs.registerHandle(regClass.handle);
+
+ regClass.eves = {};
+ regClass.eves["onCallback"] = "";
+
+
+ if params.hint ~= nil then
+ _obj_setProp(regClass.handle, "Hint", params.hint);
+ end;
+
+ _obj_setProp(regClass.handle, "IconURL", params.icon);
+
+ local p = tonumber(params.priority);
+
+ if p ~= nil then
+ _obj_setProp(regClass.handle, "Priority", math.floor(p));
+ end;
+
+ local group = tostring(params.group) or "";
+
+ if group ~= "" then
+ _obj_setProp(regClass.handle, "Group", tostring(params.group) or "");
+
+ p = tonumber(params.groupPriority);
+
+ if p ~= nil then
+ _obj_setProp(regClass.handle, "GroupPriority", math.floor(p));
+ end;
+ end;
+
+
+ if params.callback ~= nil then
+ regClass.onCallback = params.callback;
+ end;
+
+ _obj_invoke(regClass.handle, "Activate");
+
+ if __registeredToolButtons == nil then
+ __registeredToolButtons = {};
+ end;
+
+ __registeredToolButtons[regClass.handle] = regClass; -- strong reference
+ return regClass.handle;
+end;
+
+function rrpg.unregisterChatToolButton(toolButtonId)
+ if __registeredToolButtons ~= nil then
+ local regClass = __registeredToolButtons[toolButtonId];
+
+ if regClass ~= nil then
+ __registeredToolButtons[toolButtonId] = nil;
+ _obj_invoke(regClass.handle, "Deactivate");
+ end;
+ end;
+end;
+
+function rrpg.asyncOpenUserNDB(name, options)
+ if not Async.haveNativeBackendSupport() or not System.checkAPIVersion(87, 3) then
+ return Async.Promise.withError("No API Support");
+ end;
+
+ return rrpgWrappers.__serverRequestQueue:addAsyncJob(
+ function ()
+ return Async.Promise.wrap(_rrpg_Session_asyncOpenUserNDB(name, options));
+ end);
+end;
+
+function rrpg.parseTalemark(text, talemarkOptions)
+ if System.checkAPIVersion(87, 4) then
+ return _obj_invokeEx(localRRPG.handle, 'ParseTalemark', text, talemarkOptions);
+ else
+ return {type="root"};
+ end;
+end;
+
+rrpg.messaging = require("rrpgEventMessages.lua");
+
+rrpg.props["mesas"] = {getter="getMesas", tipo="table"};
+
+-- Alias functions
+rrpg.listen = rrpg.messaging.listen;
+rrpg.listenOnce = rrpg.messaging.listenOnce;
+rrpg.unlisten = rrpg.messaging.unlisten;
+rrpg.groupOnceListeners = rrpg.messaging.groupOnceListeners;
+rrpg.Messaging = rrpg.messaging;
+rrpg.parseRoll = rrpg.interpretarRolagem;
+rrpg.findRoom = rrpg.findMesa;
+rrpg.getRoomOf = rrpg.getMesaDe;
+rrpg.getRooms = rrpg.getMesas;
+rrpg.getLibraryItemOf = rrpg.getBibliotecaItemDe;
+rrpg.getCharacterOf = rrpg.getPersonagemDe;
+
+-- Alias properties
+rrpg.props["rooms"] = rrpg.props["mesas"];
+
+RRPG = rrpg;
+
+
+-- Exported API to the Firecast Executable
+
+function __rrpg_loadRolagemFromBase64EncodedString(encodedString)
+ return rrpg.loadRolagemFromBase64EncodedString(encodedString);
+end;
+
+require("rrpgEventMessagesAdapters.lua");
+return rrpg;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgDialogs.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgDialogs.lua
new file mode 100644
index 00000000..9ea447c5
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgDialogs.lua
@@ -0,0 +1,519 @@
+local objs = require("rrpgObjs.lua");
+local Async = require("async.lua");
+
+local lDialogs = objs.objectFromHandle(_obj_newObject("TLuaDialogsServices"));
+
+local function newDialogObject(className)
+ return objs.objectFromHandle(_obj_newObject(className));
+end;
+
+lDialogs.DT_INFORMATION = "information";
+lDialogs.DT_ERROR = "error";
+lDialogs.DT_WARNING = "warning";
+lDialogs.DT_CONFIRMATION = "confirmation";
+
+lDialogs.DB_YES = "yes";
+lDialogs.DB_NO = "no";
+lDialogs.DB_OK = "ok";
+lDialogs.DB_CANCEL = "cancel";
+lDialogs.DB_ABORT = "abort";
+lDialogs.DB_ALL = "all";
+lDialogs.DB_RETRY = "retry";
+lDialogs.DB_IGNORE = "ignore";
+lDialogs.DB_CLOSE = "close";
+
+function lDialogs.newMessageDialog()
+ local dlg = newDialogObject('messageDialog');
+
+ function dlg:show(message, dialogType, dialogButtons, funcCallback)
+ _obj_setProp(dlg.handle, "DialogType", dialogType);
+ _obj_setProp(dlg.handle, "DialogButtons", dialogButtons);
+
+ if funcCallback ~= nil then
+ dlg:addEventListener('OnResult', funcCallback);
+ end;
+
+ _obj_invoke(dlg.handle, 'Executar', tostring(message));
+ end;
+
+ return dlg;
+end;
+
+local runningMessageDialogs = {};
+
+function lDialogs.showMessageDlg(message, dialogType, dialogButtons, funcCallback)
+ local dlg = lDialogs.newMessageDialog();
+ runningMessageDialogs[dlg] = true; -- apenas manter uma referência forte ate o fim do dialogo
+
+ dlg:show(message, dialogType, dialogButtons,
+ function (...)
+ runningMessageDialogs[dlg] = nil;
+ dlg = nil
+
+ if type(funcCallback) == "function" then
+ funcCallback(...);
+ end;
+ end);
+end;
+
+function lDialogs.confirmYesNo(question, callback)
+ lDialogs.showMessageDlg(question, lDialogs.DT_CONFIRMATION, {lDialogs.DB_YES, lDialogs.DB_NO},
+ function(modalResult)
+ if type(callback) == "function" then
+ if modalResult == lDialogs.DB_YES then
+ callback(true);
+ else
+ callback(false);
+ end;
+ end;
+ end);
+end;
+
+function lDialogs.confirmOkCancel(question, callback)
+ lDialogs.showMessageDlg(question, lDialogs.DT_CONFIRMATION, {lDialogs.DB_OK, lDialogs.DB_CANCEL},
+ function(modalResult)
+ if type(callback) == "function" then
+ if modalResult == lDialogs.DB_OK then
+ callback(true);
+ else
+ callback(false);
+ end;
+ end;
+ end);
+end;
+
+function lDialogs.showMessage(msg, callback)
+ lDialogs.showMessageDlg(msg, lDialogs.DT_INFORMATION, {lDialogs.DB_OK},
+ function(modalResult)
+ if type(callback) == "function" then
+ callback();
+ end;
+ end);
+end;
+
+function lDialogs.showErrorMessage(msg, callback)
+ lDialogs.showMessageDlg(msg, lDialogs.DT_ERROR, {lDialogs.DB_OK},
+ function(modalResult)
+ if type(callback) == "function" then
+ callback();
+ end;
+ end);
+end;
+
+function lDialogs.alert(msg, callback)
+ lDialogs.showMessageDlg(msg, lDialogs.DT_WARNING, {lDialogs.DB_OK},
+ function(modalResult)
+ if type(callback) == "function" then
+ callback();
+ end;
+ end);
+end;
+
+function lDialogs.newInputQueryDialog()
+ local dlg = objs.objectFromHandle(_obj_newObject("TLuaInputQueryDialog"));
+
+ function dlg:show(caption, prompt, initialValue, confirmCallback, cancelCallback, allowEmptyString)
+ if (confirmCallback ~= nil) then
+ dlg:addEventListener("OnConfirm", confirmCallback);
+ end;
+
+ if (cancelCallback ~= nil) then
+ dlg:addEventListener("OnCancel", cancelCallback);
+ end;
+
+ _obj_invoke(dlg.handle, "Executar", caption or "", prompt or "", initialValue or "", allowEmptyString == true);
+ end;
+
+ objs.registerHandle(dlg.handle, dlg);
+ return dlg;
+end;
+
+local runningQueryDialogs = {};
+
+function lDialogs.inputQuery(caption, prompt, initialValue, confirmCallback, cancelCallback, allowEmptyString)
+ local dlg = lDialogs.newInputQueryDialog();
+ runningQueryDialogs[dlg] = true; -- apenas manter uma referência forte até o fim do input query
+
+ dlg:show(caption, prompt, initialValue,
+ function(...)
+ runningQueryDialogs[dlg] = nil;
+ dlg = nil;
+
+ if confirmCallback ~= nil then
+ confirmCallback(...);
+ end;
+ end,
+
+ function (...)
+ runningQueryDialogs[dlg] = nil;
+ dlg = nil;
+
+ if cancelCallback ~= nil then
+ cancelCallback(...);
+ end;
+ end, allowEmptyString);
+end;
+
+function alert(msg, callback)
+ lDialogs.alert(msg, callback);
+end;
+
+function showMessage(msg, callback)
+ lDialogs.showMessage(msg, callback);
+end;
+
+local runningFileQuerys = {};
+
+function _newFileQueryObject()
+ local obj = objs.objectFromHandle(_obj_newObject('TLuaFileQueryDialog'));
+
+ if obj.eves == nil then
+ obj.eves = {};
+ end;
+
+ obj.eves["onResult"] = "data";
+ obj.eves["onCancel"] = "";
+
+ objs.registerHandle(obj.handle, obj);
+ return obj;
+end;
+
+function lDialogs.openFile(prompt, accept, multiple, callback, cancelCallback)
+ local query = _newFileQueryObject();
+
+ query.onResult = function(files)
+ runningFileQuerys[query] = nil;
+ local utils = require("utils.lua");
+
+ for i = 1, #files, 1 do
+ files[i].stream = utils.streamFromHandle(files[i].streamHandle);
+ files[i].stream.position = 0;
+ files[i].streamHandle = nil;
+ end;
+
+ if callback ~= nil then
+ callback(files or {});
+ end;
+ end;
+
+ query.onCancel = function()
+ runningFileQuerys[query] = nil;
+
+ if cancelCallback ~= nil then
+ cancelCallback();
+ end;
+ end;
+
+ _obj_setProp(query.handle, "Accept", tostring(accept or "") or "");
+ _obj_setProp(query.handle, "Multiple", not (not multiple));
+ _obj_setProp(query.handle, "Prompt", tostring(prompt or "") or "");
+
+ runningFileQuerys[query] = true;
+ _obj_invoke(query.handle, "Execute");
+end;
+
+function lDialogs.asyncOpenFile(prompt, accept, multiple)
+ local promise, resolution = Async.Promise.pending();
+
+ lDialogs.openFile(prompt, accept, multiple,
+ function(data)
+ resolution:setSuccess(data);
+ end,
+
+ function()
+ resolution:setUserAborted();
+ end);
+
+ return promise;
+end;
+
+local function _newFileSaveObject()
+ local obj = objs.objectFromHandle(_obj_newObject('TLuaFileSaveDialog'));
+
+ if obj.eves == nil then
+ obj.eves = {};
+ end;
+
+ obj.eves["OnCallback"] = "";
+ obj.eves["OnCancelCallback"] = "";
+
+ objs.registerHandle(obj.handle, obj);
+ return obj;
+end;
+
+local runningFileSaveDialogs = {};
+
+function lDialogs.saveFile(prompt, stream, suggestedFileName, mimeType, callback, cancelCallback)
+ if (type(stream) ~= "table") or (stream.handle == nil) then
+ error("Dialogs.saveFile - 'stream' parameter is not a valid object");
+ end;
+
+ local query = _newFileSaveObject();
+ rawset(query, "__tempStream", stream); -- keep reference while running the save dialog
+
+ query.OnCallback = function()
+ runningFileSaveDialogs[query] = nil;
+
+ if callback ~= nil then
+ callback();
+ end;
+ end;
+
+ query.OnCancelCallback = function()
+ runningFileSaveDialogs[query] = nil;
+
+ if cancelCallback ~= nil then
+ cancelCallback();
+ end;
+ end;
+
+ _obj_setProp(query.handle, "Prompt", tostring(prompt or "") or "");
+ _obj_setProp(query.handle, "SuggestedFileName", tostring(suggestedFileName or "") or "");
+ _obj_setProp(query.handle, "MimeType", tostring(mimeType or "") or "");
+
+ _obj_invokeEx(query.handle, "SetStream", stream.handle);
+
+ runningFileSaveDialogs[query] = true;
+ _obj_invoke(query.handle, "Execute");
+end
+
+function lDialogs.o(prompt, multiple, callback, cancelCallback)
+ return lDialogs.openFile(prompt, "image/*", multiple, callback, cancelCallback);
+end;
+
+local function _newSelectImageURLObject()
+ local obj = objs.objectFromHandle(_obj_newObject('TLuaSelectImageURLQuery'));
+
+ if obj.eves == nil then
+ obj.eves = {};
+ end;
+
+ obj.eves["OnCallback"] = "";
+ obj.eves["OnCancelCallback"] = "";
+
+ objs.registerHandle(obj.handle, obj);
+ return obj;
+end;
+
+local runningSelectImageURLDialogs = {};
+
+function lDialogs.selectImageURL(defaultURL, callback, cancelCallback)
+ local query = _newSelectImageURLObject();
+
+ query.OnCallback = function()
+ runningSelectImageURLDialogs[query] = nil;
+
+ if callback ~= nil then
+ callback(_obj_getProp(query.handle, "SelectedURL"));
+ end;
+ end;
+
+ query.OnCancelCallback = function()
+ runningSelectImageURLDialogs[query] = nil;
+
+ if cancelCallback ~= nil then
+ cancelCallback();
+ end;
+ end;
+
+ _obj_setProp(query.handle, "DefaultURL", tostring(defaultURL or "") or "");
+
+ runningSelectImageURLDialogs[query] = true;
+ _obj_invoke(query.handle, "Execute");
+end
+
+local function _newChoiceDialogPopup(className)
+ local GUI = require("gui.lua");
+ local obj = GUI.controlFromHandle(_obj_newObject(className or 'TLuaChoiceDialogPopup'));
+
+ if obj.eves == nil then
+ obj.eves = {};
+ end;
+
+ function obj:addSelectionOption(option)
+ _obj_invoke(obj.handle, "AddSelectionOption", tostring(option) or "");
+ end;
+
+ function obj:setDefaultIndex(defaultIndex)
+ _obj_setProp(obj.handle, "DefaultIndex", defaultIndex);
+ end;
+
+ function obj:setTitle(title)
+ _obj_setProp(obj.handle, "DialogTitle", tostring(title) or "");
+ end;
+
+ function obj:buildPanel()
+ _obj_invoke(obj.handle, "BuildPanel");
+ end;
+
+ function obj:executeAsync()
+ _obj_invoke(obj.handle, "ExecuteAsync");
+ end;
+
+ function obj:acquireFocus()
+ _obj_invoke(obj.handle, "AcquireFocus");
+ end;
+
+ function obj:getSelectedIndex()
+ return _obj_getProp(obj.handle, "LuaSelectedIndex");
+ end;
+
+ obj.eves["onChoiceSelected"] = "";
+ obj.eves["onChoiceCanceled"] = "";
+
+ objs.registerHandle(obj.handle, obj);
+ return obj;
+end;
+
+local function _newMultipleChoiceDialogPopup()
+ local obj = _newChoiceDialogPopup("TLuaMultipleChoiceDialogPopup");
+
+ function obj:getSelectedIndexes()
+ return _obj_invokeEx(obj.handle, "ReturnLuaArrayOfSelected");
+ end;
+
+ return obj;
+end;
+
+local function _executeChoicePanel(panel, callback)
+ local GUI = require("gui.lua");
+ require("utils.lua");
+
+ local frm = GUI.newPopupForm();
+ frm.drawContainer = true;
+ frm.cancelable = false;
+ frm.resizable = true;
+ local haveNotified = false;
+
+ local cancelProc = function()
+ frm:close();
+
+ if not haveNotified then
+ haveNotified = true;
+
+ setTimeout(
+ function()
+ callback(false);
+ end, 1);
+ end;
+ end;
+
+ frm.onCancelRequest = cancelProc;
+ panel.onChoiceCanceled = cancelProc;
+ frm.onHide = cancelProc;
+
+ panel.onChoiceSelected =
+ function()
+ local mustNotify = not haveNotified;
+ haveNotified = true;
+
+ frm:close();
+
+ if mustNotify then
+ setTimeout(function()
+ callback(true);
+ end, 1);
+ end;
+ end;
+
+ panel.parent = frm;
+ panel.align = "client";
+ panel.visible = true;
+ frm.width = 300;
+ frm.height = 300;
+ frm.theme = "dark";
+ panel:executeAsync();
+ frm:show();
+ panel:acquireFocus();
+end;
+
+function lDialogs.choose(prompt, options, callback, defaultIndex, shortCircuit)
+ if (type(options) ~= "table") or (#options < 1) then
+ if callback ~= nil then
+ callback(false);
+ end;
+
+ return;
+ end;
+
+ require("gui.lua");
+ local choosePanel = _newChoiceDialogPopup();
+
+ if type(options) == "table" then
+ for i = 1, #options, 1 do
+ choosePanel:addSelectionOption(options[i]);
+ end;
+
+ if shortCircuit and (#options == 1) then
+ setTimeout(
+ function()
+ if callback ~= nil then
+ callback(true, 1, options[1]);
+ end;
+ end, 1);
+
+ return;
+ end;
+ end;
+
+ if defaultIndex ~= nil then
+ choosePanel:setDefaultIndex(defaultIndex - 1);
+ end;
+
+ choosePanel:setTitle(prompt or "");
+ choosePanel:buildPanel();
+
+ _executeChoicePanel(choosePanel,
+ function (confirmed)
+ if callback ~= nil then
+ if confirmed then
+ local idx = choosePanel:getSelectedIndex() + 1;
+ callback(true, idx, options[idx]);
+ else
+ callback(false);
+ end;
+ end;
+ end);
+end;
+
+function lDialogs.chooseMultiple(prompt, options, callback)
+ require("gui.lua");
+ local choosePanel = _newMultipleChoiceDialogPopup();
+
+ if type(options) == "table" then
+ for i = 1, #options, 1 do
+ choosePanel:addSelectionOption(options[i]);
+ end;
+ end;
+
+ choosePanel:setTitle(prompt or "");
+ choosePanel:buildPanel();
+
+ _executeChoicePanel(choosePanel,
+ function (confirmed)
+ if callback ~= nil then
+ if confirmed then
+ local indexes = choosePanel:getSelectedIndexes();
+ local values = {};
+
+ for i = 1, #indexes, 1 do
+ indexes[i] = indexes[i] + 1;
+ values[i] = options[indexes[i]];
+ end;
+
+ callback(true, indexes, values);
+ else
+ callback(false);
+ end;
+ end;
+ end);
+end;
+
+function lDialogs.asyncSelectTalemarkColor(initialColor)
+ local promiseHandle = _obj_invokeEx(lDialogs.handle, "AsyncSelectTalemarkColor", initialColor);
+ return Async.Promise.wrap(promiseHandle);
+end;
+
+dialogs = lDialogs;
+Dialogs = dialogs;
+return dialogs;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgEventMessages.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgEventMessages.lua
new file mode 100644
index 00000000..d32bb018
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgEventMessages.lua
@@ -0,0 +1,236 @@
+local rrpgObjs = require("rrpgObjs.lua");
+local messaging = {};
+
+local CANCEL_RECEIVER = false;
+messaging.CANCEL = CANCEL_RECEIVER;
+
+local _messageAdapters = {};
+
+function messaging.createReceiver(messageName, callback, filters)
+ if (type(callback) ~= "function") or (type(messageName) ~= "string") or (messageName == "") then
+ return nil;
+ end;
+
+ if type(filters) ~= "table" then
+ filters = nil;
+ end;
+
+ local obj = rrpgObjs.objectFromHandle(_obj_newObject("TRRPGEventMessageReceiver"));
+ rrpgObjs.registerHandle(obj.handle, obj);
+
+ local msgAdapter = _messageAdapters[string.upper(messageName)];
+
+ if (msgAdapter ~= nil) and (msgAdapter.prepareFilters ~= nil) and (filters ~= nil) then
+ msgAdapter.prepareFilters(filters);
+ end;
+
+ if filters ~= nil then
+ for k, v in pairs(filters) do
+ _obj_invokeEx(obj.handle, "AddFilter", k, v);
+ end;
+ end;
+
+ _obj_setProp(obj.handle, "EventName", messageName);
+
+ obj.__callbackEventListenerId = obj:addEventListener("OnMessage",
+ function (message)
+ if callback ~= nil then
+ if (msgAdapter ~= nil) and (msgAdapter.prepareMessage ~= nil) then
+ msgAdapter.prepareMessage(message);
+ end;
+
+ local retorno = callback(message);
+
+ if retorno == CANCEL_RECEIVER then
+ messaging.disableReceiver(obj);
+ end;
+
+ local response = message.response;
+
+ if (response ~= nil) and (type(response) == "table") then
+ if (msgAdapter ~= nil) and (msgAdapter.prepareResponse ~= nil) then
+ msgAdapter.prepareResponse(response);
+ end;
+
+ _obj_invokeEx(obj.handle, "AddResponse", response);
+ end;
+ end;
+ end);
+
+ function obj:disable()
+ callback = nil;
+ local evtId = obj.__callbackEventListenerId;
+
+ if evtId ~= nil then
+ _obj_setProp(obj.handle, "EventName", "");
+ obj:removeEventListener(evtId);
+ obj.__callbackEventListenerId = nil;
+ end;
+ end;
+
+ return obj;
+end;
+
+messaging.newReceiver = messaging.createReceiver;
+
+function messaging.disableReceiver(receiverObj)
+ if (type(receiverObj) == "table") and (receiverObj.disable ~= nil) then
+ receiverObj:disable();
+ end;
+end;
+
+local __settedListeners = {};
+local __listenersGeneratorId = 1;
+local __listenersByName = {};
+
+function messaging.listen(messageName, callback, filters)
+ if (type(callback) ~= "function") or (type(messageName) ~= "string") or (messageName == "") then
+ return nil;
+ end;
+
+ __listenersGeneratorId = __listenersGeneratorId + 1;
+ local esteListenerId = __listenersGeneratorId;
+
+ local obj = messaging.createReceiver(messageName,
+ function(message)
+ local retorno;
+
+ if callback ~= nil then
+ retorno = callback(message);
+ else
+ retorno = nil;
+ end;
+
+ if retorno == CANCEL_RECEIVER then
+ messaging.unlisten(esteListenerId);
+ callback = nil;
+ end;
+
+ return retorno;
+ end, filters);
+
+ if obj == nil then
+ return nil;
+ end;
+
+ __settedListeners[esteListenerId] = obj;
+
+ local preparedMessageName = _util_genCollateWinPtBrString(messageName);
+ local lbn = __listenersByName[preparedMessageName];
+
+ if lbn == nil then
+ lbn = {};
+ __listenersByName[preparedMessageName] = lbn;
+ end;
+
+ obj.preparedMessageName = preparedMessageName;
+ lbn[esteListenerId] = obj;
+ return esteListenerId;
+end;
+
+function messaging.unlisten(listenerId)
+ if listenerId == nil then
+ return;
+ end;
+
+ local listenerObj = __settedListeners[listenerId];
+
+ if listenerObj ~= nil then
+ __settedListeners[listenerId] = nil;
+
+ local lbn = __listenersByName[listenerObj.preparedMessageName];
+
+ if lbn ~= nil then
+ lbn[listenerId] = nil;
+
+ if next(lbn, nil) == nil then -- Tabela vazia
+ __listenersByName[listenerObj.preparedMessageName] = nil;
+ end;
+ end;
+
+ if listenerObj.disable ~= nil then
+ listenerObj:disable();
+ end;
+ end;
+end;
+
+function messaging.listenOnce(messageName, callback, filters)
+ local listenerId = messaging.listen(messageName,
+ function(message)
+ callback(message);
+ return CANCEL_RECEIVER;
+ end, filters);
+
+ return listenerId;
+end;
+
+function messaging.groupOnceListeners(...)
+ local parametros = table.pack(...);
+ local listenersObjs = {};
+ local listenersId = {};
+
+ for i = 1, #parametros, 1 do
+ local obj = __settedListeners[parametros[i]];
+
+ if (obj ~= nil) then
+ listenersId[#listenersId + 1] = parametros[i];
+ listenersObjs[#listenersObjs + 1] = obj;
+ end;
+ end;
+
+ if #listenersObjs == 0 then
+ return;
+ end;
+
+ local eventListenersId = {};
+
+ for i = 1, #listenersObjs, 1 do
+ local obj = listenersObjs[i];
+ eventListenersId[#eventListenersId + 1] = obj:addEventListener('OnAfterMessage',
+ function()
+ -- um dos listeners disparou, vamos cancelar os outros.
+
+ for j = 1, #listenersObjs, 1 do
+ local otherObj = listenersObjs[j];
+ otherObj:removeEventListener(eventListenersId[j]);
+ messaging.unlisten(listenersId[j]);
+ otherObj:disable();
+ end;
+ end);
+ end;
+end;
+
+function messaging.addMessageAdapter(messageName, adapter)
+ _messageAdapters[string.upper(messageName)] = adapter;
+end;
+
+function messaging.dispatchLocalMessage(messageName, message)
+ local lbn = __listenersByName[_util_genCollateWinPtBrString(messageName)];
+
+ if lbn == nil then
+ return;
+ end;
+
+ if type(message) ~= "table" then
+ local nm = {};
+ nm.data = message;
+ message = nm;
+ end;
+
+ local copyOfLbn = {};
+
+ -- Copiar, pois lbn pode mudar ao longo do processo
+ for k, v in pairs(lbn) do
+ copyOfLbn[k] = v;
+ end;
+
+ for k, v in pairs(copyOfLbn) do
+ _obj_invokeEx(v.handle, "TryDispatchLocalMessage", message);
+ end
+end;
+
+function __export__dispatchLocalMessage(messageName, message)
+ return messaging.dispatchLocalMessage(messageName, message);
+end;
+
+return messaging;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgEventMessagesAdapters.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgEventMessagesAdapters.lua
new file mode 100644
index 00000000..50331dbb
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgEventMessagesAdapters.lua
@@ -0,0 +1,308 @@
+local messaging = require("rrpgEventMessages.lua");
+local rrpgWrappers = require("rrpgWrappers.lua");
+
+-- Não faça require em rrpg.lua
+
+local _basicChatCommandAdapter = {prepareFilters =
+ function(filters)
+
+ if filters.room ~= nil then
+ filters.mesaObjectID = filters.room.objectID;
+ filters.room = nil;
+ filters.mesa = nil;
+ else
+ if filters.mesa ~= nil then
+ filters.mesaObjectID = filters.mesa.objectID;
+ filters.mesa = nil;
+ else
+ filters.mesaObjectID = nil;
+ end;
+ end;
+
+ if filters.chat ~= nil then
+ filters.chatObjectID = filters.chat.objectID;
+ filters.chat = nil;
+ else
+ filters.chatObjectID = nil;
+ end;
+
+ if filters.player ~= nil then
+ filters.jogadorObjectID = filters.player.objectID;
+ filters.player = nil;
+ filters.jogador = nil;
+ else
+ if filters.jogador ~= nil then
+ filters.jogadorObjectID = filters.jogador.objectID;
+ filters.jogador = nil;
+ else
+ filters.jogadorObjectID = nil;
+ end;
+ end;
+ end,
+
+ prepareMessage =
+ function(message)
+ message.mesa = rrpgWrappers.contextObjectFromID(message.mesaObjectID);
+ message.room = message.mesa;
+
+ message.chat = rrpgWrappers.contextObjectFromID(message.chatObjectID);
+
+ message.jogador = rrpgWrappers.contextObjectFromID(message.jogadorObjectID);
+ message.player = message.jogador;
+ end,
+ };
+
+local _basicChatMessageAdapter = {prepareFilters =
+ function(filters)
+ if filters.room ~= nil then
+ filters.mesaObjectID = filters.room.objectID;
+ filters.room = nil;
+ filters.mesa = nil;
+ else
+ if filters.mesa ~= nil then
+ filters.mesaObjectID = filters.mesa.objectID;
+ filters.mesa = nil;
+ else
+ filters.mesaObjectID = nil;
+ end;
+ end;
+
+ if filters.chat ~= nil then
+ filters.chatObjectID = filters.chat.objectID;
+ filters.chat = nil;
+ else
+ filters.chatObjectID = nil;
+ end;
+
+ if filters.player ~= nil then
+ filters.jogadorObjectID = filters.player.objectID;
+ filters.player = nil;
+ filters.jogador = nil;
+ else
+ if filters.jogador ~= nil then
+ filters.jogadorObjectID = filters.jogador.objectID;
+ filters.jogador = nil;
+ else
+ filters.jogadorObjectID = nil;
+ end;
+ end;
+
+ if filters.pvtPlayer ~= nil then
+ filters.jogadorPVTObjectID = filters.pvtPlayer.objectID;
+ filters.pvtPlayer = nil;
+ filters.jogadorPVT = nil;
+ else
+ if filters.jogadorPVT ~= nil then
+ filters.jogadorPVTObjectID = filters.jogadorPVT.objectID;
+ filters.jogadorPVT = nil;
+ else
+ filters.jogadorPVTObjectID = nil;
+ end;
+ end;
+
+ filters.rolagem = nil;
+ filters.roll = nil;
+ end,
+
+ prepareMessage =
+ function(message)
+ message.mesa = rrpgWrappers.contextObjectFromID(message.mesaObjectID);
+ message.room = message.mesa;
+
+ message.chat = rrpgWrappers.contextObjectFromID(message.chatObjectID);
+
+ message.jogador = rrpgWrappers.contextObjectFromID(message.jogadorObjectID);
+ message.player = message.jogador;
+
+ message.jogadorPVT = rrpgWrappers.contextObjectFromID(message.jogadorPVTObjectID);
+ message.pvtPlayer = message.jogadorPVT;
+
+ if message.rolagem64 ~= nil then
+ message.rolagem = rrpg.loadRolagemFromBase64EncodedString(message.rolagem64);
+ message.roll = message.rolagem;
+ message.rolagem64 = nil;
+ end;
+ end,
+ };
+
+local __listChatCommandsAdapter = {
+ prepareFilters = function(filters)
+ _basicChatMessageAdapter.prepareFilters(filters);
+ end,
+
+ prepareMessage =
+ function(message)
+ _basicChatMessageAdapter.prepareMessage(message);
+ end,
+
+ prepareResponse = function(response)
+ local r = {};
+
+ for k, v in pairs(response) do
+ if type(v) == "table" then
+ r[k] = v;
+ end;
+
+ response[k] = nil;
+ end;
+
+ local id = _rrpg_generateUniqueStrID();
+ local qt = 0;
+
+ for k, v in pairs(r) do
+ qt = qt + 1;
+ local str = "";
+ local comando = v.command or v.comando;
+ local tComando = type(comando);
+ local comandoIdx = 1;
+
+ if tComando == "string" then
+ str = str .. "comando" .. comandoIdx .. "=" .. _util_encodeStringToHexUTF8(comando) .. "&";
+ --comandoIdx = comandoIdx + 1;
+ elseif tComando == "table" then
+ for i = 1, #comando, 1 do
+ str = str .. "comando" .. comandoIdx .. "=" .. _util_encodeStringToHexUTF8(comando[i]) .. "&";
+ comandoIdx = comandoIdx + 1;
+ end;
+ end;
+
+ str = str .. "descricao=" .. _util_encodeStringToHexUTF8(v.description or v.descricao);
+ response[id .. qt] = str;
+ end;
+ end;
+};
+
+local _mesaJoinPartAdapter = {prepareFilters =
+ function(filters)
+ if filters.room ~= nil then
+ filters.mesaObjectID = filters.room.objectID;
+ filters.room = nil;
+ filters.mesa = nil;
+ else
+ if filters.mesa ~= nil then
+ filters.mesaObjectID = filters.mesa.objectID;
+ filters.mesa = nil;
+ else
+ filters.mesaObjectID = nil;
+ end;
+ end;
+
+ if filters.player ~= nil then
+ filters.jogadorObjectID = filters.player.objectID;
+ filters.player = nil;
+ filters.jogador = nil;
+ else
+ if filters.jogador ~= nil then
+ filters.jogadorObjectID = filters.jogador.objectID;
+ filters.jogador = nil;
+ else
+ filters.jogadorObjectID = nil;
+ end;
+ end;
+
+ if filters.me ~= nil then
+ filters.eu = filters.me;
+ filters.me = nil;
+ end;
+
+ if filters.isKick ~= nil then
+ filters.ehKick = filters.isKick;
+ filters.isKick = nil;
+ end;
+
+ if filters.text ~= nil then
+ filters.mensagem = filters.text;
+ filters.text = nil;
+ end;
+
+ if filters.responsible ~= nil then
+ filters.responsavelObjectID = filters.responsible.objectID;
+ filters.responsible = nil;
+ filters.responsavel = nil;
+ else
+ if filters.responsavel ~= nil then
+ filters.responsavelObjectID = filters.responsavel.objectID;
+ filters.responsavel = nil;
+ end;
+ end;
+ end,
+
+ prepareMessage =
+ function(message)
+ message.me = message.eu;
+ message.isKick = message.ehKick;
+ message.text = message.mensagem;
+
+ message.mesa = rrpgWrappers.contextObjectFromID(message.mesaObjectID);
+ message.room = message.mesa;
+
+ message.jogador = rrpgWrappers.contextObjectFromID(message.jogadorObjectID);
+ message.player = message.jogador;
+
+ if message.responsavelObjectID ~= nil then
+ message.responsavel = rrpgWrappers.contextObjectFromID(message.responsavelObjectID);
+ message.responsible = message.responsavel;
+ end;
+ end,
+ };
+
+local _mesaMsgAdapter = {prepareFilters =
+ function(filters)
+ if filters.room ~= nil then
+ filters.mesaObjectID = filters.room.objectID;
+ filters.room = nil;
+ filters.mesa = nil;
+ else
+ if filters.mesa ~= nil then
+ filters.mesaObjectID = filters.mesa.objectID;
+ filters.mesa = nil;
+ else
+ filters.mesaObjectID = nil;
+ end;
+ end;
+ end,
+
+ prepareMessage =
+ function(message)
+ message.mesa = rrpgWrappers.contextObjectFromID(message.mesaObjectID);
+ message.room = message.mesa;
+ end,
+ };
+
+messaging.addMessageAdapter("ChatMessage", _basicChatMessageAdapter);
+messaging.addMessageAdapter("HandleChatTextInput", _basicChatMessageAdapter);
+messaging.addMessageAdapter("HandleChatCommand", _basicChatCommandAdapter);
+messaging.addMessageAdapter("ListChatCommands", __listChatCommandsAdapter);
+messaging.addMessageAdapter("MesaJoined", _mesaJoinPartAdapter);
+messaging.addMessageAdapter("MesaParted", _mesaJoinPartAdapter);
+messaging.addMessageAdapter("TablesDockClosedByUser", _mesaMsgAdapter);
+messaging.addMessageAdapter("TablesDockPosChanged", _mesaMsgAdapter);
+
+-- Mensagens do Scene 3
+
+local _SceneWrappers = nil;
+
+local _sceneMsgAdapter = {prepareFilters =
+ function(filters)
+ if filters.scene ~= nil then
+ filters.sceneObjectID = filters.scene.objectID;
+ filters.scene = nil;
+ else
+ filters.sceneObjectID = nil;
+ end;
+ end,
+
+ prepareMessage =
+ function(message)
+ if _SceneWrappers == nil then
+ _SceneWrappers = require("sceneWrappers.dlua");
+ end;
+
+ message.scene = _SceneWrappers.objectFromID(message.sceneObjectID);
+ end,
+ };
+
+
+messaging.addMessageAdapter("SC3SceneLoaded", _sceneMsgAdapter);
+messaging.addMessageAdapter("SC3SceneUnloaded", _sceneMsgAdapter);
+
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgEvents.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgEvents.lua
new file mode 100644
index 00000000..209c0115
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgEvents.lua
@@ -0,0 +1,133 @@
+local ndb = require("ndb.lua");
+local objs = require("rrpgObjs.lua");
+
+
+
+function _eve_MESA_PVT_ReceberMensagem(mesaID, senderID, msg)
+ rrpg.dispatch("MESA_PVT_ReceberMensagem", rrpg.objectFromID(mesaID), rrpg.objectFromID(senderID), msg);
+end
+
+
+--[[ Coisas relacionadas ao Sistema de Forms ]]--
+
+local _LuaForms = {};
+
+--[ Lista de forms que não estao sendo utilizados, e podem ser reusados (antes que o garbage colector faca sua parte) ]--
+local _CachedFreeForms = {};
+
+function _eve_Forms_CriarForm(formName)
+ local dtObj = rrpg.forms[formName];
+
+ if dtObj ~= nil then
+ local frm = dtObj.newEditor();
+ rawset(frm, "__formName", formName);
+
+ _LuaForms[frm.handle] = frm;
+ return frm.handle;
+ else
+ return nil;
+ end;
+end;
+
+function eve_Forms_ExisteFormName(formName)
+ return rrpg.forms[formName] ~= nil;
+end;
+
+function _eve_Forms_DestruirForm(formHandle)
+ local frm = _LuaForms[formHandle];
+
+ if frm ~= nil then
+ _LuaForms[formHandle] = nil;
+ frm:destroy();
+ end;
+end;
+
+function _eve_Forms_AssignNodeDatabase(formHandle, nodeHandle)
+ local nodeDataBase = ndb.openNodeFacade(nodeHandle);
+ local formObj = _LuaForms[formHandle];
+
+ if (formObj ~= nil) then
+ if formObj.setNodeDatabase ~= nil then
+ formObj:setNodeDatabase(nodeDataBase);
+ end;
+ end;
+end;
+
+local _tmrDestroyCachedForms = objs.newTimer(45000);
+_tmrDestroyCachedForms:setEnabled(false);
+
+function _eve_Forms_Cached_CriarForm(formName)
+ local cache = _CachedFreeForms[formName];
+
+ if type(cache) == "table" then
+ local objetoEncontrado = nil;
+
+ for k, v in pairs(cache) do
+ if (type(k) == "table") and (v ~= nil) then
+ objetoEncontrado = k;
+ break;
+ end;
+ end;
+
+ if objetoEncontrado ~= nil then
+ _LuaForms[objetoEncontrado.handle] = objetoEncontrado;
+ cache[objetoEncontrado] = nil;
+ return objetoEncontrado.handle;
+ end;
+ end;
+
+ -- se chegou até aqui, é porque nao conseguiu usar algum do cache
+ return _eve_Forms_CriarForm(formName);
+end;
+
+function _eve_Forms_Cached_DestruirForm(formHandle)
+ local formObject = _LuaForms[formHandle];
+
+ if formObject ~= nil then
+ local formName = rawget(formObject, "__formName");
+
+ if formName ~= nil then
+ local cache = _CachedFreeForms[formName];
+
+ if cache == nil then
+ cache = {};
+ _CachedFreeForms[formName] = cache;
+ end;
+
+ cache[formObject] = true; -- adicionar ao cache
+ _LuaForms[formObject.handle] = nil;
+
+ if formObject.setNodeDatabase ~= nil then
+ formObject:setNodeDatabase(nil);
+ end;
+
+ formObject:setParent(nil);
+
+ _tmrDestroyCachedForms:setEnabled(true); -- ativar o timer de coleta de cache
+ return;
+ end;
+ end;
+
+ -- se chegou até aqui, é porque nao conseguiu colocar o form no cache
+ return _eve_Forms_DestruirForm(formHandle);
+end;
+
+function timedCheckAndDestroyCachedForms()
+ _tmrDestroyCachedForms:setEnabled(false);
+
+ local oldCachedFreeForms = _CachedFreeForms;
+ _CachedFreeForms = {};
+
+ for formName, cache in pairs(oldCachedFreeForms) do
+
+ if cache ~= nil then
+ for formObj, v in pairs(cache) do
+ if (formObj ~= nil) and (formObj.destroy ~= nil) then
+ formObj:destroy();
+ end;
+ end;
+ end;
+ end;
+end;
+
+_tmrDestroyCachedForms:addEventListener("onTimer", timedCheckAndDestroyCachedForms);
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgGUI.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgGUI.lua
new file mode 100644
index 00000000..885a60bd
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgGUI.lua
@@ -0,0 +1,2066 @@
+local objs = require("rrpgObjs.lua");
+local ndb = require("ndb.lua");
+local System = require("system.lua");
+local Async = require("async.lua");
+local Utils = require("utils.lua");
+
+local __delayedGridLib = nil;
+
+gui = objs.objectFromHandle(_obj_newObject("TLuaGUIServices"));
+GUI = gui;
+
+gui.DEFAULT_FORM_CACHE_TIMEOUT = 60000;
+
+local guiLoaders = {};
+local guiClasses = {};
+
+gui.guiLoaders = guiLoaders;
+gui.guiClasses = guiClasses;
+
+local function registerTag(class, tagName)
+ assert(guiClasses[tagName] == nil, tagName);
+ assert(rawget(class, "tagName") == nil, tagName);
+
+ guiLoaders[tagName] = class.fromHandle;
+ guiClasses[tagName] = class;
+
+ rawset(class, "tagName", tagName);
+
+ rawset(class, "new",
+ function()
+ return class.fromHandle(_obj_newObject(tagName));
+ end);
+
+ local constructorName = "new" .. tagName:gsub("^%l", string.upper);
+
+ gui[constructorName] =
+ function()
+ return class.new();
+ end;
+end;
+
+--[[ Objeto Control ]]--
+
+gui.Control = objs.HierarchyObject.inherit();
+
+function gui.Control:initialize()
+ if self.props == nil then
+ self.props = {};
+ end;
+
+ if self.eves == nil then
+ self.eves = {};
+ end;
+
+ self:setParent(self:getParent());
+end;
+
+function gui.Control:setFocus() _obj_invoke(self.handle, "SetFocus"); end;
+function gui.Control:beginUpdate() _obj_invoke(self.handle, "BeginUpdate"); end;
+function gui.Control:endUpdate() _obj_invoke(self.handle, "EndUpdate"); end;
+function gui.Control:needRepaint() _obj_invoke(self.handle, "Repaint"); end;
+
+function gui.Control:getVisible() return _obj_getProp(self.handle, "Visible"); end;
+
+function gui.Control:setVisible(visible)
+ _obj_setProp(self.handle, "Visible", visible == true);
+
+ if visible then
+ local grid = self:tryGetGrid();
+
+ if grid ~= nil then
+ grid:invalidate();
+ end;
+ end;
+end;
+
+function gui.Control:getAlign() return _obj_getProp(self.handle, "Align"); end;
+function gui.Control:setAlign(align) _obj_setProp(self.handle, "Align", align); end;
+
+function gui.Control:getEnabled()return _obj_getProp(self.handle, "Enabled"); end;
+function gui.Control:setEnabled(enabled) _obj_setProp(self.handle, "Enabled", enabled == true) end;
+
+function gui.Control:getLeft() return _obj_getProp(self.handle, "Position.X"); end;
+function gui.Control:setLeft(left) _obj_setProp(self.handle, "Position.X", left) end;
+
+function gui.Control:getTop() return _obj_getProp(self.handle, "Position.Y"); end;
+function gui.Control:setTop(top) _obj_setProp(self.handle, "Position.Y", top) end;
+
+function gui.Control:getBottom() return self:getTop() + self:getHeight(); end;
+function gui.Control:setBottom(bottom) self:setTop(bottom - self:getHeight()); end;
+
+function gui.Control:getRight() return self:getLeft() + self:getWidth(); end;
+function gui.Control:setRight(right) self:setLeft(right - self:getWidth()); end;
+
+function gui.Control:getWidth() return _obj_getProp(self.handle, "Width"); end;
+function gui.Control:setWidth(width) _obj_setProp(self.handle, "Width", width) end;
+
+function gui.Control:getHeight() return _gui_getHeight(self.handle); end;
+function gui.Control:setHeight(height) _gui_setHeight(self.handle, height) end;
+
+function gui.Control:getHitTest() return _obj_getProp(self.handle, "HitTest"); end;
+function gui.Control:setHitTest(hittest) _obj_setProp(self.handle, "HitTest", hittest == true) end;
+
+function gui.Control:getTabOrder() return _obj_getProp(self.handle, "TabOrder"); end;
+function gui.Control:setTabOrder(tabOrder) _obj_setProp(self.handle, "TabOrder", tabOrder); end;
+
+function gui.Control:getOpacity() return _obj_getProp(self.handle, "Opacity"); end;
+function gui.Control:setOpacity(opacity) _obj_setProp(self.handle, "Opacity", opacity); end;
+
+function gui.Control:getMargins() return _obj_getProp(self.handle, "Margins"); end;
+function gui.Control:setMargins(margins) _gui_setMargins(self.handle, margins); end;
+
+function gui.Control:getPadding() return _obj_getProp(self.handle, "Padding"); end;
+function gui.Control:setPadding(padding) _gui_setPadding(self.handle, padding); end;
+
+function gui.Control:getAnchors() return _obj_getProp(self.handle, "Anchors"); end;
+function gui.Control:setAnchors(anchors) _obj_setProp(self.handle, "Anchors", anchors); end;
+
+function gui.Control:getCanFocus() return _obj_getProp(self.handle, "CanFocus"); end;
+function gui.Control:setCanFocus(canFocus) _obj_setProp(self.handle, "CanFocus", canFocus); end;
+
+function gui.Control:getRotationAngle() return _obj_getProp(self.handle, "RotationAngle"); end;
+function gui.Control:setRotationAngle(angle) _obj_setProp(self.handle, "RotationAngle", angle); end;
+
+function gui.Control:getRotationCenterX() return _obj_getProp(self.handle, "RotationCenter.X"); end;
+function gui.Control:setRotationCenterX(x) _obj_setProp(self.handle, "RotationCenter.X", x); end;
+
+function gui.Control:getRotationCenterY() return _obj_getProp(self.handle, "RotationCenter.Y"); end;
+function gui.Control:setRotationCenterY(y) _obj_setProp(self.handle, "RotationCenter.Y", y); end;
+
+function gui.Control:getScaleX() return _obj_getProp(self.handle, "Scale.X"); end;
+function gui.Control:setScaleX(sX) _obj_setProp(self.handle, "Scale.X", sX); end;
+
+function gui.Control:getScaleY() return _obj_getProp(self.handle, "Scale.Y"); end;
+function gui.Control:setScaleY(sY) _obj_setProp(self.handle, "Scale.Y", sY); end;
+
+function gui.Control:getScale() return self:getScaleX(); end;
+function gui.Control:setScale(ss) self:beginUpdate(); self:setScaleX(ss); self:setScaleY(ss); self:endUpdate(); end;
+
+function gui.Control:isChildFocused() return _obj_getProp(self.handle, "IsChildFocused"); end;
+function gui.Control:isFocused() return _obj_getProp(self.handle, "IsFocused"); end;
+function gui.Control:isMouseOver() return _obj_getProp(self.handle, "IsMouseOver"); end;
+function gui.Control:isVisible() return self:getVisible(); end;
+
+function gui.Control:getCursor() return _obj_getProp(self.handle, "MouseCursor"); end;
+function gui.Control:setCursor(v) _obj_setProp(self.handle, "MouseCursor", v); end;
+
+function gui.Control:getHint() return _obj_getProp(self.handle, "Hint"); end;
+function gui.Control:setHint(v) _gui_setHint(self.handle, v); end;
+
+function gui.Control:getEffect() return _obj_getProp(self.handle, "CompEffect"); end;
+function gui.Control:setEffect(effect) _obj_setProp(self.handle, "CompEffect", effect); end;
+
+function gui.Control:getEffectTriggers() return _obj_getProp(self.handle, "CompEffectTriggers"); end;
+function gui.Control:setEffectTriggers(triggers) _obj_setProp(self.handle, "CompEffectTriggers", triggers); end;
+
+function gui.Control:getEffectParam() return _obj_getProp(self.handle, "CompEffectParam"); end;
+function gui.Control:setEffectParam(param) _obj_setProp(self.handle, "CompEffectParam", param); end;
+
+function gui.Control:getEffectParam2() return _obj_getProp(self.handle, "CompEffectParam2"); end;
+function gui.Control:setEffectParam2(param) _obj_setProp(self.handle, "CompEffectParam2", param); end;
+
+function gui.Control:getEffectParam3() return _obj_getProp(self.handle, "CompEffectParam3"); end;
+function gui.Control:setEffectParam3(param) _obj_setProp(self.handle, "CompEffectParam3", param); end;
+
+function gui.Control:getEffectParam4() return _obj_getProp(self.handle, "CompEffectParam4"); end;
+function gui.Control:setEffectParam4(param) _obj_setProp(self.handle, "CompEffectParam4", param); end;
+
+function gui.Control:findControlByName(controlName) return gui.findControlByName(controlName, self); end;
+
+function gui.Control:getGrid()
+ local cachedGrid = rawget(self, "__cachedGrid");
+
+ if cachedGrid == nil then
+ if __delayedGridLib == nil then
+ __delayedGridLib = require("rrpgGUI_grid.dlua");
+ assert(__delayedGridLib ~= nil);
+ end;
+
+ cachedGrid = __delayedGridLib.new(self);
+ rawset(self, "__cachedGrid", cachedGrid);
+ end;
+
+ return cachedGrid;
+end;
+
+function gui.Control:tryGetGrid()
+ return rawget(self, "__cachedGrid");
+end;
+
+function gui.Control:__objindex(key)
+ if type(key) == "string" then
+ if key == "g" then
+ return true, self.grid.role;
+ end;
+
+ local gridPropName = string.match(key, "^g%-(.+)$");
+
+ if gridPropName ~= nil then
+ return true, self.grid[gridPropName];
+ end;
+ end;
+
+ return false;
+end;
+
+function gui.Control:__objnewindex(key, value)
+ if type(key) == "string" then
+ if key == "g" then
+ self.grid.role = value;
+ return true;
+ end;
+
+ local gridPropName = string.match(key, "^g%-(.+)$");
+
+ if gridPropName ~= nil then
+ self.grid[gridPropName] = value;
+ return true;
+ end;
+ end;
+
+ return false;
+end;
+
+gui.Control.props["visible"] = {setter = "setVisible", getter = "getVisible", tipo = "bool"};
+gui.Control.props["align"] = {setter = "setAlign", getter = "getAlign", tipo = "enum",
+ values = {"none", "top", "left", "right",
+ "bottom", "client", "contents", "scale"}}
+
+gui.Control.props["enabled"] = {setter = "setEnabled", getter = "getEnabled", tipo = "bool"};
+gui.Control.props["left"] = {setter = "setLeft", getter = "getLeft", tipo = "double"};
+gui.Control.props["top"] = {setter = "setTop", getter = "getTop", tipo = "double"};
+gui.Control.props["right"] = {setter = "setRight", getter = "getRight", tipo = "double"};
+gui.Control.props["bottom"] = {setter = "setBottom", getter = "getBottom", tipo = "double"};
+gui.Control.props["width"] = {setter = "setWidth", getter = "getWidth", tipo = "double"};
+gui.Control.props["height"] = {setter = "setHeight", getter = "getHeight", tipo = "double"};
+gui.Control.props["hitTest"] = {setter = "setHitTest", getter = "getHitTest", tipo = "bool"};
+gui.Control.props["tabOrder"] = {setter = "setTabOrder", getter = "getTabOrder", tipo = "int"};
+gui.Control.props["opacity"] = {setter = "setOpacity", getter = "getOpacity", tipo = "double"};
+gui.Control.props["margins"] = {setter = "setMargins", getter = "getMargins", tipo = "bounds"};
+gui.Control.props["padding"] = {setter = "setPadding", getter = "getPadding", tipo = "bounds"};
+gui.Control.props["anchors"] = {setter = "setAnchors", getter = "getAnchors", tipo = "set",
+ values = {"left", "top", "right", "bottom"}};
+
+gui.Control.props["canFocus"] = {setter = "setCanFocus", getter = "getCanFocus", tipo="bool"};
+gui.Control.props["rotationAngle"] = {setter = "setRotationAngle", getter = "getRotationAngle", tipo="double"};
+gui.Control.props["rotationCenterX"] = {setter = "setRotationCenterX", getter = "getRotationCenterX", tipo="double"};
+gui.Control.props["rotationCenterY"] = {setter = "setRotationCenterY", getter = "getRotationCenterY", tipo="double"};
+gui.Control.props["scaleX"] = {setter = "setScaleX", getter = "getScaleX", tipo="double"};
+gui.Control.props["scaleY"] = {setter = "setScaleY", getter = "getScaleY", tipo="double"};
+gui.Control.props["scale"] = {setter = "setScale", getter = "getScale", tipo="double"};
+gui.Control.props["parent"] = {setter = "setParent", getter = "getParent", tipo="table"};
+
+gui.Control.props["cursor"] = {setter = "setCursor", getter = "getCursor", tipo="enum",
+ values={'default', 'arrow', 'handPoint', 'hourGlass',
+ 'IBeam', 'size', 'sizeNESW', 'sizeNS',
+ 'sizeNWSE', 'sizeWE', 'upArrow',
+ 'drag', 'noDrop', 'hSplit', 'vSplit',
+ 'multiDrag', 'sqlWait', 'no', 'appStart',
+ 'help', 'cross'}};
+
+gui.Control.props["hint"] = {setter = "setHint", getter = "getHint", tipo="string"};
+gui.Control.props["grid"] = {getter = "getGrid", tipo="table"};
+
+gui.Control.props["cacheMode"] = {readProp = "CacheMode", writeProp = "CacheMode", tipo = "enum",
+ values = {"none", "time"}};
+
+gui.Control.eves["onResize"] = "";
+gui.Control.eves["onClick"] = "event";
+gui.Control.eves["onDblClick"] = "event";
+gui.Control.eves["onMouseDown"] = "event";
+gui.Control.eves["onMouseMove"] = "event";
+gui.Control.eves["onMouseUp"] = "event";
+gui.Control.eves["onMouseEnter"] = "";
+gui.Control.eves["onMouseLeave"] = "";
+gui.Control.eves["onEnter"] = "";
+gui.Control.eves["onExit"] = "";
+gui.Control.eves["onKeyDown"] = "event";
+gui.Control.eves["onKeyUp"] = "event";
+gui.Control.eves["onMenu"] = 'x, y, event';
+gui.Control.eves["onStartDrag"] = 'drag, x, y, event';
+gui.Control.eves["onStartDrop"] = 'drop, x, y, drag, event';
+
+local function controlFromHandle(handle)
+ return gui.Control.fromHandle(handle);
+end
+
+gui.controlFromHandle = controlFromHandle;
+
+--[[ Objeto Layout ]]--
+
+gui.Layout = gui.Control.inherit();
+registerTag(gui.Layout, 'layout');
+
+function gui.Layout:getFrameStyle() return _obj_getProp(self.handle, "FrameStyle"); end;
+function gui.Layout:setFrameStyle(frameStyle) _obj_setProp(self.handle, "FrameStyle", frameStyle) end;
+
+function gui.Layout:getFrameRegion() return _obj_getProp(self.handle, "FrameRegion"); end;
+function gui.Layout:setFrameRegion(frameRegion) _obj_setProp(self.handle, "FrameRegion", frameRegion) end;
+
+gui.Layout.props["frameStyle"] = {setter = "setFrameStyle", getter = "getFrameStyle", tipo = "url"};
+gui.Layout.props["frameRegion"] = {setter = "setFrameRegion", getter = "getFrameRegion", tipo = "string"};
+
+
+--[[ Objeto Row ]]--
+
+gui.Row = gui.Layout.inherit();
+registerTag(gui.Row, 'row');
+
+--[[ Objeto Col ]]--
+
+gui.Col = gui.Layout.inherit();
+registerTag(gui.Col, 'col');
+
+--[[ Objeto Container ]]--
+
+gui.Container = gui.Layout.inherit();
+registerTag(gui.Container, 'container');
+
+--[[ Objeto Form Layout ]]--
+
+local function __atualizarLockPopupWithTopStack(lockPopup)
+ local topStack = lockPopup.__topStackStatus;
+
+ if topStack ~= nil then
+ lockPopup.__label.text = topStack.msg;
+ lockPopup.__label.visible = topStack.msg ~= "";
+ end;
+end;
+
+local function __lockFormWithActivity(form, msg)
+ local thePopup = rawget(form, "__lockWithActivityPopup");
+
+ if thePopup == nil then
+ -- criar o popup de lock
+ thePopup = gui.newPopup();
+ thePopup.width = 280;
+ thePopup.height = 50;
+ thePopup.cancelable = false;
+ thePopup.drawContainer = false;
+ thePopup.autoScopeNode = false;
+
+ thePopup.__indicator = gui.newActivityIndicator();
+ thePopup.__indicator.align = "client";
+ thePopup.__indicator.parent = thePopup;
+
+ thePopup.__label = gui.newLabel();
+ thePopup.__label.vertTextAlign = "leading";
+ thePopup.__label.horzTextAlign = "center";
+ thePopup.__label.autoSize = true;
+ thePopup.__label.wordWrap = true;
+ thePopup.__label.align = "bottom";
+ thePopup.__label.parent = thePopup;
+ thePopup.__label.fontSize = 15;
+
+ thePopup.parent = form;
+ rawset(form, "__lockWithActivityPopup", thePopup);
+ end;
+
+ local stackStatus = {};
+ stackStatus.msg = msg or "";
+ stackStatus.anterior = thePopup.__topStackStatus;
+ thePopup.__topStackStatus = stackStatus;
+
+ __atualizarLockPopupWithTopStack(thePopup);
+
+ if not stackStatus.anterior then
+ -- Primeira chamada
+ thePopup.__indicator.enabled = true;
+ thePopup:show("center", form);
+ end;
+end;
+
+local function __reallyCloseLockPopup(form, lockPopup)
+ lockPopup.__indicator.enabled = false;
+ lockPopup:close();
+ rawset(form, "__lockWithActivityPopup", nil); -- Permitir o garbage collector coletar
+
+ setTimeout(function()
+ lockPopup.parent = nil;
+ lockPopup.__label.parent = nil;
+ lockPopup.__indicator.parent = nil;
+ end, 3000);
+end;
+
+local function __unlockFormWithActivity(form)
+ local thePopup = rawget(form, "__lockWithActivityPopup");
+
+ if thePopup == nil then
+ return true;
+ end;
+
+ local topStack = thePopup.__topStackStatus;
+
+ if topStack ~= nil then
+ topStack = topStack.anterior;
+ thePopup.__topStackStatus = topStack;
+ end;
+
+ if topStack ~= nil then
+ __atualizarLockPopupWithTopStack(thePopup);
+ return false;
+ else
+ __reallyCloseLockPopup(form, thePopup);
+ return true;
+ end;
+end;
+
+gui.Form = gui.Layout.inherit();
+registerTag(gui.Form, 'form');
+
+function gui.Form:initialize()
+ rawset(self, "__isFormFlag", true);
+end;
+
+function gui.Form:getWidth() return _obj_getProp(self.handle, "FormWidth"); end;
+function gui.Form:setWidth(v) _obj_setProp(self.handle, "FormWidth", v); end;
+
+function gui.Form:getHeight() return _obj_getProp(self.handle, "FormHeight"); end;
+function gui.Form:setHeight(v) _obj_setProp(self.handle, "FormHeight", v); end;
+
+function gui.Form:getLeft() return _obj_getProp(self.handle, "FormLeft"); end;
+function gui.Form:setLeft(v) _obj_setProp(self.handle, "FormLeft", v); end;
+
+function gui.Form:getTop() return _obj_getProp(self.handle, "FormTop"); end;
+function gui.Form:setTop(v) _obj_setProp(self.handle, "FormTop", v); end;
+
+function gui.Form:getTitle() return _obj_getProp(self.handle, "Title"); end;
+function gui.Form:setTitle(title) _obj_setProp(self.handle, "Title", title) end;
+
+function gui.Form:getDescription() return _obj_getProp(self.handle, "Description"); end;
+function gui.Form:setDescription(desc) _obj_setProp(self.handle, "Description", desc) end;
+
+function gui.Form:getDataType() return _obj_getProp(self.handle, "DataType"); end;
+function gui.Form:setDataType(dataType) _obj_setProp(self.handle, "DataType", dataType) end;
+
+function gui.Form:getFormType() return _obj_getProp(self.handle, "FormType"); end;
+function gui.Form:setFormType(formType) _obj_setProp(self.handle, "FormType", formType) end;
+
+function gui.Form:getTheme() return _obj_getProp(self.handle, "Theme"); end;
+function gui.Form:setTheme(theme) _obj_setProp(self.handle, "Theme", theme) end;
+
+function gui.Form:getLockWhileNodeIsLoading() return _obj_getProp(self.handle, "LockWhileNodeIsLoading"); end;
+function gui.Form:setLockWhileNodeIsLoading(v) _obj_setProp(self.handle, "LockWhileNodeIsLoading", v) end;
+
+function gui.Form:getMinWidth() return _obj_getProp(self.handle, "MinWidth"); end;
+function gui.Form:setMinWidth(v) _obj_setProp(self.handle, "MinWidth", v) end;
+
+function gui.Form:getMaxWidth() return _obj_getProp(self.handle, "MaxWidth"); end;
+function gui.Form:setMaxWidth(v) _obj_setProp(self.handle, "MaxWidth", v) end;
+
+function gui.Form:setNodeObject(nodeObject)
+ rawset(self, "nodeObject", nodeObject);
+ _gui_assignNodeObject(self.handle, ndb.getNodeHandle(nodeObject));
+end;
+
+function gui.Form:getNodeObject() return rawget(self, "nodeObject") end;
+function gui.Form:getNode() return self:getNodeObject(); end;
+function gui.Form:setNode(node) self:setNodeObject(node); end;
+function gui.Form:getScopeNode() return self:getNodeObject(); end;
+function gui.Form:setScopeNode(node) self:setNodeObject(node); end;
+
+function gui.Form:lockWithActivity(msg) return __lockFormWithActivity(self, msg); end;
+function gui.Form:unlockWithActivity() return __unlockFormWithActivity(self); end;
+
+gui.Form.props["title"] = {setter = "setTitle", getter = "getTitle", tipo = "string"};
+gui.Form.props["description"] = {setter = "setDescription", getter = "getDescription", tipo = "string"};
+gui.Form.props["dataType"] = {setter = "setDataType", getter = "getDataType", tipo = "string"};
+gui.Form.props["formType"] = {setter = "setFormType", getter = "getDataType", tipo = "enum",
+ values = {"undefined", "sheetTemplate", "tablesDock"}};
+gui.Form.props["theme"] = {setter = "setTheme", getter = "getTheme", tipo = "enum",
+ values = {"default", "light", "dark", "firecast"}};
+gui.Form.props["lockWhileNodeIsLoading"] = {setter = "setLockWhileNodeIsLoading", getter = "getLockWhileNodeIsLoading", tipo = "bool"};
+gui.Form.props["scopeNode"] = {setter = "setScopeNode", getter = "getScopeNode", tipo = "table"};
+gui.Form.props["minWidth"] = {setter = "setMinWidth", getter = "getMinWidth", tipo = "double"};
+gui.Form.props["maxWidth"] = {setter = "setMaxWidth", getter = "getMaxWidth", tipo = "double"};
+gui.Form.props["isShowing"] = {readProp = "IsShowing", tipo = "bool"};
+
+gui.Form.eves["onScopeNodeChanged"] = "";
+gui.Form.eves["onShow"] = "";
+gui.Form.eves["onHide"] = "";
+gui.Form.eves["onNodeReady"] = "";
+gui.Form.eves["onNodeUnready"] = "";
+gui.Form.eves["onNodeChanged"] = "";
+
+--[[ Objeto Popup Form ]]--
+
+gui.PopupForm = gui.Form.inherit();
+registerTag(gui.PopupForm, 'popupForm');
+
+function gui.PopupForm:getDrawContainer() return _obj_getProp(self.handle, "DrawContainer"); end;
+function gui.PopupForm:setDrawContainer(v) _obj_setProp(self.handle, "DrawContainer", v); end;
+
+function gui.PopupForm:getCancelable() return _obj_getProp(self.handle, "Cancelable"); end;
+function gui.PopupForm:setCancelable(v) _obj_setProp(self.handle, "Cancelable", v); end;
+
+function gui.PopupForm:getPlacement() return _obj_getProp(self.handle, "Placement"); end;
+function gui.PopupForm:setPlacement(v) _obj_setProp(self.handle, "Placement", v); end;
+
+function gui.PopupForm:getResizable() return _obj_getProp(self.handle, "Resizable"); end;
+function gui.PopupForm:setResizable(v) _obj_setProp(self.handle, "Resizable", v); end;
+
+function gui.PopupForm:show() return gui.showPopup(self); end;
+function gui.PopupForm:close() return gui.closePopup(self); end;
+
+gui.PopupForm.props["drawContainer"] = {setter = "setDrawContainer", getter = "getDrawContainer", tipo = "bool"};
+gui.PopupForm.props["cancelable"] = {setter = "setCancelable", getter = "getCancelable", tipo = "bool"};
+gui.PopupForm.props["resizable"] = {setter = "setResizable", getter = "getResizable", tipo = "bool"};
+gui.PopupForm.props["movable"] = {readProp = "Movable", writeProp = "Movable", tipo = "bool"};
+
+gui.PopupForm.props["placement"] = {setter = "setPlacement", getter = "getPlacement", tipo = "enum",
+ values = {"center", "bottom", "top", "left", "right",
+ "topLeft", "topRight", "bottomLeft", "bottomRight", "mouse", "mouseCenter"}};
+
+gui.PopupForm.eves["onCancelRequest"] = "";
+
+--[[ Objeto Flow Part ]]--
+
+gui.FlowPart = gui.Layout.inherit();
+registerTag(gui.FlowPart, 'flowPart');
+
+function gui.FlowPart:getMinWidth() return _obj_getProp(self.handle, "MinWidth"); end;
+function gui.FlowPart:setMinWidth(value) _obj_setProp(self.handle, "MinWidth", value) end;
+
+function gui.FlowPart:getMinScaledWidth() return _obj_getProp(self.handle, "MinScaledWidth"); end;
+function gui.FlowPart:setMinScaledWidth(value) _obj_setProp(self.handle, "MinScaledWidth", value) end;
+
+function gui.FlowPart:getMaxWidth() return _obj_getProp(self.handle, "MaxWidth"); end;
+function gui.FlowPart:setMaxWidth(value) _obj_setProp(self.handle, "MaxWidth", value) end;
+
+function gui.FlowPart:getMaxScaledWidth() return _obj_getProp(self.handle, "MaxScaledWidth"); end;
+function gui.FlowPart:setMaxScaledWidth(value) _obj_setProp(self.handle, "MaxScaledWidth", value) end;
+
+function gui.FlowPart:getAvoidScale() return _obj_getProp(self.handle, "AvoidScale"); end;
+function gui.FlowPart:setAvoidScale(value) _obj_setProp(self.handle, "AvoidScale", value) end;
+
+function gui.FlowPart:getVertAlign() return _obj_getProp(self.handle, "VerticalAlign"); end;
+function gui.FlowPart:setVertAlign(value) _obj_setProp(self.handle, "VerticalAlign", value) end;
+
+function gui.FlowPart:getStepSizes() return _obj_getProp(self.handle, "StepSizes"); end;
+function gui.FlowPart:setStepSizes(value) _obj_setProp(self.handle, "StepSizes", value) end;
+
+function gui.FlowPart:getAdjustHeightToLine() return _obj_getProp(self.handle, "AdjustHeightToLine"); end;
+function gui.FlowPart:setAdjustHeightToLine(value) _obj_setProp(self.handle, "AdjustHeightToLine", value) end;
+
+gui.FlowPart.props["minWidth"] = {setter = "setMinWidth", getter = "getMinWidth", tipo = "double"};
+gui.FlowPart.props["minScaledWidth"] = {setter = "setMinScaledWidth", getter = "getMinScaledWidth", tipo = "double"};
+gui.FlowPart.props["maxWidth"] = {setter = "setMaxWidth", getter = "getMaxWidth", tipo = "double"};
+gui.FlowPart.props["maxScaledWidth"] = {setter = "setMaxScaledWidth", getter = "getMaxScaledWidth", tipo = "double"};
+gui.FlowPart.props["avoidScale"] = {setter = "setAvoidScale", getter = "getAvoidScale", tipo = "bool"};
+
+gui.FlowPart.props["vertAlign"] = {setter = "setVertAlign", getter = "getVertAlign", tipo = "enum",
+ values={"leading", "center", "trailing"}};
+
+gui.FlowPart.props["stepSizes"] = {setter = "setStepSizes", getter = "getStepSizes", tipo = "table"};
+gui.FlowPart.props["adjustHeightToLine"] = {setter = "setAdjustHeightToLine", getter = "getAdjustHeightToLine", tipo = "bool"};
+
+--[[ Objeto Flow Layout ]]--
+
+gui.FlowLayout = gui.FlowPart.inherit();
+registerTag(gui.FlowLayout, 'flowLayout');
+
+function gui.FlowLayout:getAutoHeight() return _obj_getProp(self.handle, "AutoHeight"); end;
+function gui.FlowLayout:setAutoHeight(value) _obj_setProp(self.handle, "AutoHeight", value) end;
+
+function gui.FlowLayout:getHorzAlign() return _obj_getProp(self.handle, "HorzAlign"); end;
+function gui.FlowLayout:setHorzAlign(value) _obj_setProp(self.handle, "HorzAlign", value) end;
+
+function gui.FlowLayout:getMaxControlsPerLine() return _obj_getProp(self.handle, "MaxControlsPerLine"); end;
+function gui.FlowLayout:setMaxControlsPerLine(value) _obj_setProp(self.handle, "MaxControlsPerLine", value) end;
+
+function gui.FlowLayout:getLineSpacing() return _obj_getProp(self.handle, "LineSpacing"); end;
+function gui.FlowLayout:setLineSpacing(value) _obj_setProp(self.handle, "LineSpacing", value) end;
+
+function gui.FlowLayout:getOrientation() return _obj_getProp(self.handle, "Orientation"); end;
+function gui.FlowLayout:setOrientation(value) _obj_setProp(self.handle, "Orientation", value) end;
+
+function gui.FlowLayout:getMaxColumns() return _obj_getProp(self.handle, "MaxColumns"); end;
+function gui.FlowLayout:setMaxColumns(value) _obj_setProp(self.handle, "MaxColumns", value) end;
+
+function gui.FlowLayout:needRealign() _obj_invoke(self.handle, "NeedRealign"); end;
+
+gui.FlowLayout.props["autoHeight"] = {setter = "setAutoHeight", getter = "getAutoHeight", tipo = "bool"};
+gui.FlowLayout.props["horzAlign"] = {setter = "setHorzAlign", getter = "getHorzAlign", tipo = "enum",
+ values={"leading", "center", "trailing", "justify"}};
+
+gui.FlowLayout.props["maxControlsPerLine"] = {setter = "setMaxControlsPerLine", getter = "getMaxControlsPerLine", tipo = "int"};
+gui.FlowLayout.props["lineSpacing"] = {setter = "setLineSpacing", getter = "getLineSpacing", tipo = "double"};
+gui.FlowLayout.props["orientation"] = {setter = "setOrientation", getter = "getOrientation", tipo = "enum",
+ values={"horizontal", "vertical"}};
+gui.FlowLayout.props["maxColumns"] = {setter = "setMaxColumns", getter = "getMaxColumns", tipo = "int"};
+gui.FlowLayout.props["contentWidth"] = {readProp = "ContentWidth", tipo = "double"};
+gui.FlowLayout.props["contentHeight"] = {readProp = "ContentHeight", tipo = "double"};
+
+gui.FlowLayout.eves["onBeforeLayoutCalc"] = "";
+gui.FlowLayout.eves["onAfterLayoutCalc"] = "";
+
+--[[ Objeto Flow Line Break ]]--
+
+gui.FlowLineBreak = gui.Control.inherit();
+registerTag(gui.FlowLineBreak, 'flowLineBreak');
+
+function gui.FlowLineBreak:getHorzAlign() return _obj_getProp(self.handle, "HorzAlign"); end;
+function gui.FlowLineBreak:setHorzAlign(value) _obj_setProp(self.handle, "HorzAlign", value) end;
+
+function gui.FlowLineBreak:getLineSpacing() return _obj_getProp(self.handle, "LineSpacing"); end;
+function gui.FlowLineBreak:setLineSpacing(value) _obj_setProp(self.handle, "LineSpacing", value) end;
+
+gui.FlowLineBreak.props["horzAlign"] = {setter = "setHorzAlign", getter = "getHorzAlign", tipo = "enum",
+ values={"leading", "center", "trailing", "justify"}};
+
+gui.FlowLineBreak.props["lineSpacing"] = {setter = "setLineSpacing", getter = "getLineSpacing", tipo = "double"};
+
+--[[ Text Controls]]--
+
+local function _addFontPropertiesToObject(ctrl)
+ function ctrl:getFontColor() return _obj_getProp(self.handle, "FontColor"); end;
+ function ctrl:setFontColor(color) _gui_prepareForFontColorChange(self.handle); _obj_setProp(self.handle, "FontColor", color); end;
+
+ function ctrl:getFontFamily() return _obj_getProp(self.handle, "Font.Family"); end;
+ function ctrl:setFontFamily(family) _gui_prepareForFontFamilyChange(self.handle); _obj_setProp(self.handle, "Font.Family", family); end;
+
+ function ctrl:getFontSize() return _obj_getProp(self.handle, "Font.Size"); end;
+ function ctrl:setFontSize(fontSize) _gui_prepareForFontSizeChange(self.handle); _obj_setProp(self.handle, "Font.Size", fontSize); end;
+
+ function ctrl:getFontStyle() return _obj_getProp(self.handle, "Font.Style"); end;
+ function ctrl:setFontStyle(fontStyle) _gui_prepareForFontStyleChange(self.handle); _obj_setProp(self.handle, "Font.Style", fontStyle); end;
+
+ function ctrl:getFontHeight() return _gui_getFontHeight(self.handle); end;
+
+ ctrl.props["fontColor"] = {setter = "setFontColor", getter = "getFontColor", tipo = "color"};
+ ctrl.props["fontFamily"] = {setter = "setFontFamily", getter = "getFontFamily", tipo = "string"};
+ ctrl.props["fontSize"] = {setter = "setFontSize", getter = "getFontSize", tipo = "double"};
+ ctrl.props["fontStyle"] = {setter = "setFontStyle", getter = "getFontStyle", tipo = "set",
+ values = {"bold", "italic", "underline", "strikeout"}};
+
+ return ctrl;
+end;
+
+local function _addTextStylePropsToObject(ctrl)
+ function ctrl:getHorzTextAlign() return _obj_getProp(self.handle, "TextAlign"); end;
+ function ctrl:setHorzTextAlign(textAlign) return _obj_setProp(self.handle, "TextAlign", textAlign); end;
+
+ function ctrl:getVertTextAlign() return _obj_getProp(self.handle, "VertTextAlign"); end;
+ function ctrl:setVertTextAlign(textAlign) return _obj_setProp(self.handle, "VertTextAlign", textAlign); end;
+
+ function ctrl:getWordWrap() return _obj_getProp(self.handle, "WordWrap"); end;
+ function ctrl:setWordWrap(wrap) return _obj_setProp(self.handle, "WordWrap", wrap == true); end;
+
+ function ctrl:getTextTrimming() return _obj_getProp(self.handle, "Trimming"); end;
+ function ctrl:setTextTrimming(trimming) return _obj_setProp(self.handle, "Trimming", trimming); end;
+
+ ctrl.props["horzTextAlign"] = {setter = "setHorzTextAlign", getter="getHorzTextAlign", tipo="enum",
+ values = {"center", "leading", "trailing"}};
+
+ ctrl.props["vertTextAlign"] = {setter = "setVertTextAlign", getter="getVertTextAlign", tipo="enum",
+ values = {"center", "leading", "trailing"}};
+
+ ctrl.props["wordWrap"] = {setter = "setWordWrap", getter="getWordWrap", tipo="bool"};
+
+ ctrl.props["textTrimming"] = {setter = "setTextTrimming", getter="getTextTrimming", tipo="enum",
+ values = {"none", "character", "word"}}
+
+ return ctrl;
+end;
+
+local function _addEditablePropsToObject(ctrl)
+ function ctrl:getReadOnly() return _obj_getProp(self.handle, "ReadOnly"); end;
+ function ctrl:setReadOnly(readonly) return _obj_setProp(self.handle, "ReadOnly", readonly); end;
+
+ ctrl.props["readOnly"] = {setter="setReadOnly", getter="getReadOnly", tipo="bool"};
+ ctrl.eves["onChange"] = "";
+
+ return ctrl;
+end
+
+gui.TextControl = gui.Control.inherit();
+_addFontPropertiesToObject(gui.TextControl);
+_addTextStylePropsToObject(gui.TextControl);
+
+function gui.TextControl:getText() return _obj_getProp(self.handle, "Text"); end;
+function gui.TextControl:setText(text) return _obj_setProp(self.handle, "Text", text); end;
+
+function gui.TextControl:getStyledSettings() return _obj_getProp(self.handle, "StyledSettings"); end;
+function gui.TextControl:setStyledSettings(settings) return _obj_setProp(self.handle, "StyledSettings", settings); end;
+
+gui.TextControl.props["text"] = {setter = "setText", getter = "getText", tipo = "string"};
+gui.TextControl.props["styledSettings"] = {setter = "setStyledSettings", getter = "getStyledSettings", tipo="set",
+ values = {"family", "size", "style", "fontcolor", "other"}};
+
+--[[ Objeto Button ]]--
+
+gui.Button = gui.TextControl.inherit();
+registerTag(gui.Button, 'button');
+
+--[[ Objeto Label ]]--
+
+gui.Label = gui.TextControl.inherit();
+registerTag(gui.Label, 'label');
+
+function gui.Label:getAutoSize() return _obj_getProp(self.handle, "AutoSize"); end;
+function gui.Label:setAutoSize(v) _obj_setProp(self.handle, "AutoSize", v); end;
+
+function gui.Label:getField() return _gui_getFieldName(self.handle); end;
+function gui.Label:setField(v) _gui_setFieldName(self.handle, v); end;
+
+function gui.Label:getFrameRegion() return _obj_getProp(self.handle, "FrameRegion"); end;
+function gui.Label:setFrameRegion(v) _obj_setProp(self.handle, "FrameRegion", v); end;
+
+gui.Label.props["autoSize"] = {setter = "setAutoSize", getter = "getAutoSize", tipo = "bool"};
+gui.Label.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+gui.Label.props["frameRegion"] = {setter = "setFrameRegion", getter = "getFrameRegion", tipo = "string"};
+gui.Label.props["format"] = {writeProp = "StringFormat", readProp = "StringFormat", tipo = "string"};
+gui.Label.props["formatFloat"] = {writeProp = "StringFormatFloat", readProp = "StringFormatFloat", tipo = "string"};
+
+--[[ Objeto CheckBox ]]--
+
+gui.CheckBox = gui.TextControl.inherit();
+registerTag(gui.CheckBox, 'checkBox');
+
+function gui.CheckBox:getChecked() return _obj_getProp(self.handle, "IsChecked"); end;
+function gui.CheckBox:setChecked(v) return _obj_setProp(self.handle, "IsChecked", v); end;
+
+function gui.CheckBox:getField() return _obj_getProp(self.handle, "FieldName"); end;
+function gui.CheckBox:setField(v) return _obj_setProp(self.handle, "FieldName", v); end;
+
+gui.CheckBox.props["checked"] = {setter = "setChecked", getter = "getChecked", tipo = "bool"};
+gui.CheckBox.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+
+gui.CheckBox.eves["onChange"] = "";
+
+--[[ Objeto RadioButton ]]--
+
+gui.RadioButton = gui.TextControl.inherit();
+registerTag(gui.RadioButton, 'radioButton');
+
+function gui.RadioButton:getChecked() return _obj_getProp(self.handle, "IsChecked"); end;
+function gui.RadioButton:setChecked(v) return _obj_setProp(self.handle, "IsChecked", v); end;
+
+function gui.RadioButton:getField() return _obj_getProp(self.handle, "FieldName"); end;
+function gui.RadioButton:setField(v) return _obj_setProp(self.handle, "FieldName", v); end;
+
+function gui.RadioButton:getFieldValue() return _obj_getProp(self.handle, "FieldValue"); end;
+function gui.RadioButton:setFieldValue(v) return _obj_setProp(self.handle, "FieldValue", v); end;
+
+function gui.RadioButton:getGroupName() return _obj_getProp(self.handle, "GroupName"); end;
+function gui.RadioButton:setGroupName(v) return _obj_setProp(self.handle, "GroupName", v); end;
+
+gui.RadioButton.props["checked"] = {setter = "setChecked", getter = "getChecked", tipo = "bool"};
+gui.RadioButton.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+gui.RadioButton.props["fieldValue"] = {setter = "setFieldValue", getter = "getFieldValue", tipo = "string"};
+gui.RadioButton.props["groupName"] = {setter = "setGroupName", getter = "getGroupName", tipo = "string"};
+
+gui.RadioButton.eves["onChange"] = "";
+
+--[[ Objeto ImageCheckBox ]]--
+
+gui.ImageCheckBox = gui.Control.inherit();
+registerTag(gui.ImageCheckBox, 'imageCheckBox');
+
+function gui.ImageCheckBox:getChecked() return _obj_getProp(self.handle, "IsChecked"); end;
+function gui.ImageCheckBox:setChecked(v) _obj_setProp(self.handle, "IsChecked", v); end;
+
+function gui.ImageCheckBox:getField() return _obj_getProp(self.handle, "FieldName"); end;
+function gui.ImageCheckBox:setField(v) _obj_setProp(self.handle, "FieldName", v); end;
+
+function gui.ImageCheckBox:getImageChecked() return _obj_getProp(self.handle, "ImageChecked"); end;
+function gui.ImageCheckBox:setImageChecked(v) _obj_setProp(self.handle, "ImageChecked", v); end;
+
+function gui.ImageCheckBox:getImageUnchecked() return _obj_getProp(self.handle, "ImageUnchecked"); end;
+function gui.ImageCheckBox:setImageUnchecked(v) _obj_setProp(self.handle, "ImageUnchecked", v); end;
+
+function gui.ImageCheckBox:getOptimize() return _obj_getProp(self.handle, "Optimize"); end;
+function gui.ImageCheckBox:setOptimize(opt) return _obj_setProp(self.handle, "Optimize", opt); end;
+
+function gui.ImageCheckBox:getAutoChange() return _obj_getProp(self.handle, "AutoChange"); end;
+function gui.ImageCheckBox:setAutoChange(v) return _obj_setProp(self.handle, "AutoChange", v); end;
+
+gui.ImageCheckBox.props["checked"] = {setter = "setChecked", getter = "getChecked", tipo = "bool"};
+gui.ImageCheckBox.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+gui.ImageCheckBox.props["imageChecked"] = {setter = "setImageChecked", getter = "getImageChecked", tipo = "url"};
+gui.ImageCheckBox.props["checkedImage"] = {setter = "setImageChecked", getter = "getImageChecked", tipo = "url"};
+gui.ImageCheckBox.props["imageUnchecked"] = {setter = "setImageUnchecked", getter = "getImageUnchecked", tipo = "url"};
+gui.ImageCheckBox.props["uncheckedImage"] = {setter = "setImageUnchecked", getter = "getImageUnchecked", tipo = "url"};
+gui.ImageCheckBox.props["optimize"] = {setter = "setOptimize", getter = "getOptimize", tipo = "bool"};
+gui.ImageCheckBox.props["autoChange"] = {setter = "setAutoChange", getter = "getAutoChange", tipo = "bool"};
+
+gui.ImageCheckBox.eves["onChange"] = "";
+
+--[[ Objeto Image ]]--
+
+gui.Image = gui.Control.inherit();
+registerTag(gui.Image, 'image');
+
+function gui.Image:getImageURL() return _obj_getProp(self.handle, "URLImagem"); end;
+function gui.Image:setImageURL(url) return _obj_setProp(self.handle, "URLImagem", url); end;
+
+function gui.Image:getURL() return _obj_getProp(self.handle, "URLImagem"); end;
+function gui.Image:setURL(url) return _obj_setProp(self.handle, "URLImagem", url); end;
+
+function gui.Image:getSRC() return _obj_getProp(self.handle, "URLImagem"); end;
+function gui.Image:setSRC(src) return _obj_setProp(self.handle, "URLImagem", src); end;
+
+function gui.Image:getShowStyle() return _obj_getProp(self.handle, "ShowStyle"); end;
+function gui.Image:setShowStyle(showStyle) return _obj_setProp(self.handle, "ShowStyle", showStyle); end;
+
+function gui.Image:getStyle() return _obj_getProp(self.handle, "ShowStyle"); end;
+function gui.Image:setStyle(style) return _obj_setProp(self.handle, "ShowStyle", style); end;
+
+function gui.Image:getCenter() return _obj_getProp(self.handle, "Center"); end;
+function gui.Image:setCenter(center) return _obj_setProp(self.handle, "Center", center); end;
+
+function gui.Image:getOptimizeQuality() return _obj_getProp(self.handle, "OtimizarDesenho"); end;
+function gui.Image:setOptimizeQuality(opt) return _obj_setProp(self.handle, "OtimizarDesenho", opt); end;
+function gui.Image:getOptimize() return _obj_getProp(self.handle, "OtimizarDesenho"); end;
+function gui.Image:setOptimize(opt) return _obj_setProp(self.handle, "OtimizarDesenho", opt); end;
+
+function gui.Image:getShowProgress() return _obj_getProp(self.handle, "ExibirProgresso"); end;
+function gui.Image:setShowProgress(showProgress) return _obj_setProp(self.handle, "ExibirProgresso", showProgress); end;
+
+function gui.Image:getURLWhileLoading() return _obj_getProp(self.handle, "NoImageURL"); end;
+function gui.Image:setURLWhileLoading(url) return _obj_setProp(self.handle, "NoImageURL", url); end;
+
+function gui.Image:getField() return _obj_getProp(self.handle, "FieldName"); end;
+function gui.Image:setField(v) _obj_setProp(self.handle, "FieldName", v); end;
+
+function gui.Image:getEditable() return _obj_getProp(self.handle, "Editable"); end;
+function gui.Image:setEditable(v) _obj_setProp(self.handle, "Editable", v); end;
+
+function gui.Image:getNaturalWidth() return _obj_getProp(self.handle, "NaturalWidth"); end;
+function gui.Image:getNaturalHeight() return _obj_getProp(self.handle, "NaturalHeight"); end;
+
+gui.Image.props["imageURL"] = {setter = "setImageURL", getter="getImageURL", tipo="url"};
+gui.Image.props["url"] = {setter = "setURL", getter="getURL", tipo="url"};
+gui.Image.props["src"] = {setter = "setSRC", getter="getSRC", tipo="url"};
+gui.Image.props["URLWhileLoading"] = {setter = "setURLWhileLoading", getter="getURLWhileLoading", tipo="url"};
+
+gui.Image.props["showStyle"] = {setter = "setShowStyle", getter="getShowStyle", tipo="enum",
+ values = {"proportional", "autoFit", "originalSize", "stretch"}};
+gui.Image.props["style"] = {setter = "setStyle", getter="getStyle", tipo="enum",
+ values = {"proportional", "autoFit", "originalSize", "stretch"}};
+
+gui.Image.props["center"] = {setter = "setCenter", getter="getCenter", tipo="bool"};
+gui.Image.props["optimizeQuality"] = {setter = "setOptimizeQuality", getter="getOptimizeQuality", tipo="bool"};
+gui.Image.props["optimize"] = {setter = "setOptimize", getter="getOptimize", tipo="bool"};
+gui.Image.props["showProgress"] = {setter = "setShowProgress", getter="getShowProgress", tipo="bool"};
+gui.Image.props["field"] = {setter = "setField", getter="getField", tipo="string"};
+gui.Image.props["editable"] = {setter = "setEditable", getter="getEditable", tipo="bool"};
+gui.Image.props["naturalAnimated"] = {readProp="NaturalAnimated", tipo="bool"};
+gui.Image.props["naturalWidth"] = {getter="getNaturalWidth", tipo="double"};
+gui.Image.props["naturalHeight"] = {getter="getNaturalHeight", tipo="double"};
+gui.Image.props["animate"] = {readProp="Animate", writeProp="Animate", tipo="bool"};
+
+gui.Image.eves["onPictureLoadedChange"] = "";
+gui.Image.eves["onLoad"] = "";
+
+--[[ Objeto Edit ]]--
+
+gui.Edit = gui.TextControl.inherit();
+registerTag(gui.Edit, 'edit');
+
+_addEditablePropsToObject(gui.Edit);
+
+function gui.Edit:getTextPrompt() return _obj_getProp(self.handle, "TextPrompt"); end;
+function gui.Edit:setTextPrompt(text) _obj_setProp(self.handle, "TextPrompt", text); end;
+
+function gui.Edit:getTransparent() _obj_getProp(self.handle, "Transparent"); end;
+function gui.Edit:setTransparent(transparent) _obj_setProp(self.handle, "Transparent", transparent); end;
+
+function gui.Edit:getIsPasswordEdit() return _obj_getProp(self.handle, "Password"); end;
+function gui.Edit:setIsPasswordEdit(isPasswordEdit) _obj_setProp(self.handle, "Password", isPasswordEdit); end;
+
+function gui.Edit:getKeyboardType() return _obj_getProp(self.handle, "KeyboardType"); end;
+function gui.Edit:setKeyboardType(kbtype) _obj_setProp(self.handle, "KeyboardType", kbtype); end;
+
+function gui.Edit:getEnterKeyType() return _obj_getProp(self.handle, "ReturnKeyType"); end;
+function gui.Edit:setEnterKeyType(enterType) _obj_setProp(self.handle, "ReturnKeyType", enterType); end;
+
+function gui.Edit:getField() return _gui_getFieldName(self.handle); end;
+function gui.Edit:setField(field) _gui_setFieldName(self.handle, field); end;
+
+function gui.Edit:getFrameRegion() return _obj_getProp(self.handle, "FrameRegion"); end;
+function gui.Edit:setFrameRegion(frameRegion) _obj_setProp(self.handle, "FrameRegion", frameRegion) end;
+
+function gui.Edit:getType() return _obj_getProp(self.handle, "EditType"); end;
+function gui.Edit:setType(v) _obj_setProp(self.handle, "EditType", v) end;
+
+function gui.Edit:getMin() return _obj_getProp(self.handle, "MinValue"); end;
+function gui.Edit:setMin(v) _obj_setProp(self.handle, "MinValue", v) end;
+
+function gui.Edit:getMax() return _obj_getProp(self.handle, "MaxValue"); end;
+function gui.Edit:setMax(v) _obj_setProp(self.handle, "MaxValue", v) end;
+
+function gui.Edit:getDecimalPlaces() return _obj_getProp(self.handle, "DecimalPlaces"); end;
+function gui.Edit:setDecimalPlaces(v) _obj_setProp(self.handle, "DecimalPlaces", v) end;
+
+function gui.Edit:getAsNumber() return _obj_getProp(self.handle, "AsNumber"); end;
+function gui.Edit:setAsNumber(v) _obj_setProp(self.handle, "AsNumber", v) end;
+
+gui.Edit.props["textPrompt"] = {setter="setTextPrompt", getter="getTextPrompt", tipo="string"};
+gui.Edit.props["transparent"] = {setter="setTransparent", getter="getTransparent", tipo="bool"};
+gui.Edit.props["isPasswordEdit"] = {setter="setIsPasswordEdit", getter="getIsPasswordEdit", tipo="bool"};
+
+gui.Edit.props["keyboardType"] = {setter="setKeyboardType", getter="getKeyboardType", tipo="enum",
+ values = {"default", "numbersAndPunctuation", "numberPad",
+ "phonePad", "alphabet", "url", "email"}};
+
+gui.Edit.props["enterKeyType"] = {setter="setEnterKeyType", getter="getEnterKeyType", tipo="enum",
+ values = {"default", "done", "go", "next", "search", "send"}};
+
+gui.Edit.props["field"] = {setter="setField", getter="getField", tipo="string"};
+gui.Edit.props["frameRegion"] = {setter = "setFrameRegion", getter = "getFrameRegion", tipo = "string"};
+gui.Edit.props["type"] = {setter = "setType", getter = "getType", tipo = "enum", values = {"text", "number", "float"}};
+gui.Edit.props["min"] = {setter = "setMin", getter = "getMin", tipo = "double"};
+gui.Edit.props["max"] = {setter = "setMax", getter = "getMax", tipo = "double"};
+gui.Edit.props["decimalPlaces"] = {setter = "setDecimalPlaces", getter = "getDecimalPlaces", tipo = "int"};
+gui.Edit.props["asNumber"] = {setter = "setAsNumber", getter = "getAsNumber", tipo = "double"};
+
+gui.Edit.eves["onUserChange"] = "";
+
+--[[ Objeto ComboBox ]]--
+
+gui.ComboBox = gui.Control.inherit();
+registerTag(gui.ComboBox, 'comboBox');
+
+_addFontPropertiesToObject(gui.ComboBox);
+_addTextStylePropsToObject(gui.ComboBox);
+
+function gui.ComboBox:getTransparent() _obj_getProp(self.handle, "Transparent"); end;
+function gui.ComboBox:setTransparent(transparent) _obj_setProp(self.handle, "Transparent", transparent); end;
+
+function gui.ComboBox:getField() return _gui_getFieldName(self.handle); end;
+function gui.ComboBox:setField(field) _gui_setFieldName(self.handle, field); end;
+
+function gui.ComboBox:getFrameRegion() return _obj_getProp(self.handle, "FrameRegion"); end;
+function gui.ComboBox:setFrameRegion(frameRegion) _obj_setProp(self.handle, "FrameRegion", frameRegion) end;
+
+function gui.ComboBox:getText() return _obj_getProp(self.handle, "Text"); end;
+function gui.ComboBox:setText(v) _obj_setProp(self.handle, "Text", v) end;
+
+function gui.ComboBox:getValue() return _obj_getProp(self.handle, "Value"); end;
+function gui.ComboBox:setValue(v) _obj_setProp(self.handle, "Value", v) end;
+
+function gui.ComboBox:getItems() return _obj_getProp(self.handle, "ItemsI18N"); end;
+function gui.ComboBox:setItems(v) _obj_setProp(self.handle, "ItemsI18N", v) end;
+
+function gui.ComboBox:getValues() return _obj_getProp(self.handle, "Values"); end;
+function gui.ComboBox:setValues(v) _obj_setProp(self.handle, "Values", v) end;
+
+function gui.ComboBox:dropDown() _obj_invoke(self.handle, "InvokeDropDown"); end;
+
+gui.ComboBox.props["transparent"] = {setter="setTransparent", getter="getTransparent", tipo="bool"};
+gui.ComboBox.props["field"] = {setter="setField", getter="getField", tipo="string"};
+gui.ComboBox.props["frameRegion"] = {setter = "setFrameRegion", getter = "getFrameRegion", tipo = "string"};
+gui.ComboBox.props["items"] = {setter = "setItems", getter = "getItems", tipo = "table"};
+gui.ComboBox.props["values"] = {setter = "setValues", getter = "getValues", tipo = "table"};
+gui.ComboBox.props["text"] = {setter = "setText", getter = "getText", tipo = "string"};
+gui.ComboBox.props["value"] = {setter = "setValue", getter = "getValue", tipo = "string"};
+
+gui.ComboBox.eves["onChange"] = "";
+
+--[[ Objeto ColorComboBox ]]--
+
+gui.ColorComboBox = gui.Control.inherit();
+registerTag(gui.ColorComboBox, 'colorComboBox');
+
+function gui.ColorComboBox:getColor() return _obj_getProp(self.handle, "Color"); end;
+function gui.ColorComboBox:setColor(v) _obj_setProp(self.handle, "Color", v); end;
+
+function gui.ColorComboBox:getUseAlpha() return _obj_getProp(self.handle, "UseAlpha"); end;
+function gui.ColorComboBox:setUseAlpha(v) _obj_setProp(self.handle, "UseAlpha", v); end;
+
+function gui.ColorComboBox:getField() return _gui_getFieldName(self.handle); end;
+function gui.ColorComboBox:setField(field) _gui_setFieldName(self.handle, field); end;
+
+function gui.ColorComboBox:getFrameRegion() return _obj_getProp(self.handle, "FrameRegion"); end;
+function gui.ColorComboBox:setFrameRegion(frameRegion) _obj_setProp(self.handle, "FrameRegion", frameRegion) end;
+
+function gui.ColorComboBox:dropDown() _obj_invoke(self.handle, "InvokeDropDown"); end;
+
+gui.ColorComboBox.props["color"] = {setter="setColor", getter="getColor", tipo="color"};
+gui.ColorComboBox.props["useAlpha"] = {setter = "setUseAlpha", getter = "getUseAlpha", tipo = "bool"};
+gui.ColorComboBox.props["field"] = {setter="setField", getter="getField", tipo="string"};
+gui.ColorComboBox.props["frameRegion"] = {setter = "setFrameRegion", getter = "getFrameRegion", tipo = "string"};
+
+gui.ColorComboBox.eves["onChange"] = "";
+gui.ColorComboBox.eves["onUserChange"] = "";
+
+--[[ Objeto TextEditor ]]--
+
+gui.TextEditor = gui.TextControl.inherit();
+registerTag(gui.TextEditor, 'textEditor');
+
+_addEditablePropsToObject(gui.TextEditor);
+
+function gui.TextEditor:getField() return _obj_getProp(self.handle, "FieldName"); end;
+function gui.TextEditor:setField(v) _obj_setProp(self.handle, "FieldName", v); end;
+
+function gui.TextEditor:getTransparent() return _obj_getProp(self.handle, "Transparent"); end;
+function gui.TextEditor:setTransparent(v) _obj_setProp(self.handle, "Transparent", v); end;
+
+gui.TextEditor.props["field"] = {setter="setField", getter="getField", tipo="string"};
+gui.TextEditor.props["transparent"] = {setter="setTransparent", getter="getTransparent", tipo="bool"};
+
+--[[ Objeto TabControl ]]--
+
+gui.TabControl = gui.Control.inherit();
+registerTag(gui.TabControl, 'tabControl');
+
+function gui.TabControl:getTabIndex() return _obj_getProp(self.handle, "TabIndex"); end;
+function gui.TabControl :setTabIndex(idx) _obj_setProp(self.handle, "TabIndex", idx); end;
+
+gui.TabControl .props["tabIndex"] = {setter="setTabIndex", getter="getTabIndex", tipo="int"};
+
+--[[ Objeto Tab / TabItem ]]--
+
+gui.TabItem = gui.Control.inherit();
+registerTag(gui.TabItem, 'tab');
+
+function gui.TabItem:getText() return _obj_getProp(self.handle, "Title"); end;
+function gui.TabItem:setText(text) _obj_setProp(self.handle, "Title", text); end;
+
+function gui.TabItem:getTitle() return _obj_getProp(self.handle, "Title"); end;
+function gui.TabItem:setTitle(title) _obj_setProp(self.handle, "Title", title); end;
+function gui.TabItem:activate() _obj_invoke(self.handle, "Activate"); end;
+
+gui.TabItem.props["text"] = {setter="setText", getter="getText", tipo="string"};
+gui.TabItem.props["title"] = {setter="setTitle", getter="getTitle", tipo="string"};
+
+--[[ Objeto ScrollBox ]]--
+
+gui.ScrollBox = gui.Control.inherit();
+registerTag(gui.ScrollBox, 'scrollBox');
+
+--[[ Objeto Shape ]]--
+
+gui.Shape = gui.Control.inherit();
+
+function gui.Shape:getColor() return _obj_getProp(self.handle, "Fill.Color"); end;
+function gui.Shape:setColor(color) _gui_shapeSetFillColor(self.handle, color); end;
+
+function gui.Shape:getStrokeColor() return _obj_getProp(self.handle, "Stroke.Color"); end;
+function gui.Shape:setStrokeColor(color) _gui_shapeSetStrokeColor(self.handle, color); end;
+
+function gui.Shape:getStrokeSize() return _obj_getProp(self.handle, "Stroke.Thickness"); end;
+function gui.Shape:setStrokeSize(size) _gui_shapeSetStrokeSize(self.handle, size); end;
+
+function gui.Shape:getStrokeCap() return _obj_getProp(self.handle, "Stroke.Cap"); end;
+function gui.Shape:setStrokeCap(v) _gui_shapeSetStrokeCap(self.handle, v); end;
+
+function gui.Shape:getStrokeJoin() return _obj_getProp(self.handle, "Stroke.Join"); end;
+function gui.Shape:setStrokeJoin(v) _gui_shapeSetStrokeCap(self.handle, v); end;
+
+function gui.Shape:getStrokeDash() return _obj_getProp(self.handle, "Stroke.Dash"); end;
+function gui.Shape:setStrokeDash(v) _gui_shapeSetStrokeCap(self.handle, v); end;
+
+gui.Shape.props["color"] = {setter="setColor", getter="getColor", tipo="color"};
+gui.Shape.props["strokeColor"] = {setter="setStrokeColor", getter="getStrokeColor", tipo="color"};
+gui.Shape.props["strokeSize"] = {setter="setStrokeSize", getter="getStrokeSize", tipo="double"};
+
+gui.Shape.props["strokeCap"] = {setter="setStrokeCap", getter="getStrokeCap", tipo="enum",
+ values={"flat", "round"}};
+
+gui.Shape.props["strokeJoin"] = {setter="setStrokeJoin", getter="getStrokeJoin", tipo="enum",
+ values={"miter", "round", "bevel"}};
+
+gui.Shape.props["strokeDash"] = {setter="setStrokeDash", getter="getStrokeDash", tipo="enum",
+ values={"solid", "dash", "dot", "dashDot", "dashDotDot"}};
+
+--[[ Objeto Rectangle ]]--
+
+gui.Rectangle = gui.Shape.inherit();
+registerTag(gui.Rectangle, 'rectangle');
+
+function gui.Rectangle:getCorners() return _obj_getProp(self.handle, "Corners"); end;
+function gui.Rectangle:setCorners(corners) _obj_setProp(self.handle, "Corners", corners); end;
+
+function gui.Rectangle:getCornerType() return _obj_getProp(self.handle, "CornerType"); end;
+function gui.Rectangle:setCornerType(cornerType) _obj_setProp(self.handle, "CornerType", cornerType); end;
+
+function gui.Rectangle:getSides() return _obj_getProp(self.handle, "CornerType"); end;
+function gui.Rectangle:setSides(sides) _obj_setProp(self.handle, "Sides", sides); end;
+
+function gui.Rectangle:getXradius() return _obj_getProp(self.handle, "XRadius"); end;
+function gui.Rectangle:setXradius(xradius) _obj_setProp(self.handle, "XRadius", xradius); end;
+
+function gui.Rectangle:getYradius() return _obj_getProp(self.handle, "YRadius"); end;
+function gui.Rectangle:setYradius(yradius) _obj_setProp(self.handle, "YRadius", yradius); end;
+
+gui.Rectangle.props["corners"] = {setter="setCorners", getter="getCorners", tipo="set",
+ values={"topLeft", "topRight", "bottomLeft", "bottomRight"}};
+
+gui.Rectangle.props["cornerType"] = {setter="setCornerType", getter="getCornerType", tipo="enum",
+ values={"round", "bevel", "innerRound", "innerLine"}};
+
+gui.Rectangle.props["sides"] = {setter="setSides", getter="getSides", tipo="set",
+ values={"top", "left", "bottom", "right"}};
+
+gui.Rectangle.props["xradius"] = {setter="setXradius", getter="getXradius", tipo="double"};
+gui.Rectangle.props["yradius"] = {setter="setYradius", getter="getYradius", tipo="double"};
+
+--[[ Objeto Path ]]--
+
+gui.Path = gui.Shape.inherit();
+registerTag(gui.Path, 'path');
+
+function gui.Path:getPathData() return _obj_getProp(self.handle, "PathData"); end;
+function gui.Path:setPathData(v) _obj_setProp(self.handle, "PathData", v); end;
+
+function gui.Path:getMode() return _obj_getProp(self.handle, "WrapMode"); end;
+function gui.Path:setMode(v) _obj_setProp(self.handle, "WrapMode", v); end;
+
+function gui.Path:getRoundToPixel() return _obj_getProp(self.handle, "RoundToPixels"); end;
+function gui.Path:setRoundToPixel(v) _obj_setProp(self.handle, "RoundToPixels", v); end;
+
+gui.Path.props["data"] = {setter="setPathData", getter="getPathData", tipo="string"};
+gui.Path.props["pathData"] = gui.Path.props["data"]
+
+gui.Path.props["mode"] = {setter="setMode", getter="getMode", tipo="enum",
+ values={"original", "fit", "stretch", "tile"}};
+
+gui.Path.props["wrapMode"] = gui.Path.props["mode"]
+gui.Path.props["roundToPixel"] = {setter="setRoundToPixel", getter="getRoundToPixel", tipo="bool"};
+
+--[[ Objeto HorzLine ]]--
+
+gui.HorzLine = gui.Shape.inherit();
+registerTag(gui.HorzLine, 'horzLine');
+
+--[[ Objeto Frame ]]--
+
+gui.Frame = gui.Layout.inherit();
+registerTag(gui.Frame, 'frame');
+
+function gui.Frame:getURL() return _obj_getProp(self.handle, "FrameURL"); end;
+function gui.Frame:setURL(url) _obj_setProp(self.handle, "FrameURL", url); end;
+
+function gui.Frame:getFrameStyle() return _obj_getProp(self.handle, "FrameURL"); end;
+function gui.Frame:setFrameStyle(frameStyle) _obj_setProp(self.handle, "FrameURL", frameStyle); end;
+
+function gui.Frame:getSrc() return _obj_getProp(self.handle, "FrameURL"); end;
+function gui.Frame:setSrc(url) _obj_setProp(self.handle, "FrameURL", url); end;
+
+gui.Frame.props["url"] = {setter="setURL", getter="getURL", tipo="url"};
+gui.Frame.props["frameStyle"] = {setter="setFrameStyle", getter="getFrameStyle", tipo="url"};
+gui.Frame.props["src"] = {setter="setSrc", getter="getSrc", tipo="url"};
+
+
+--[[ Objeto DataLink ]]--
+
+gui.DataLink = objs.HierarchyObject.inherit();
+registerTag(gui.DataLink, 'dataLink');
+
+function gui.DataLink:getField() return _obj_getProp(self.handle, "FieldName"); end;
+function gui.DataLink:setField(v) return _obj_setProp(self.handle, "FieldName", v); end;
+
+function gui.DataLink:getFields() return _obj_getProp(self.handle, "Fields"); end;
+function gui.DataLink:setFields(v) return _obj_setProp(self.handle, "Fields", v); end;
+
+function gui.DataLink:getDefaultValue() return _obj_getProp(self.handle, "DefaultValue"); end;
+function gui.DataLink:setDefaultValue(v) return _obj_setProp(self.handle, "DefaultValue", v); end;
+
+function gui.DataLink:getDefaultValues() return _obj_getProp(self.handle, "DefaultValues"); end;
+function gui.DataLink:setDefaultValues(v) return _obj_setProp(self.handle, "DefaultValues", v); end;
+
+function gui.DataLink:beginUpdate() end;
+function gui.DataLink:endUpdate() end;
+
+gui.DataLink.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+gui.DataLink.props["fields"] = {setter = "setFields", getter = "getFields", tipo = "table"};
+gui.DataLink.props["defaultValue"] = {setter = "setDefaultValue", getter = "getDefaultValue", tipo = "string"};
+gui.DataLink.props["defaultValues"] = {setter = "setDefaultValues", getter = "getDefaultValues", tipo = "table"};
+
+gui.DataLink.eves["onChange"] = "field, oldValue, newValue";
+gui.DataLink.eves["onPersistedChange"] = "field, oldValue, newValue";
+gui.DataLink.eves["onUserChange"] = "field, oldValue, newValue";
+gui.DataLink.eves["onChildAdded"] = "node";
+gui.DataLink.eves["onChildRemoved"] = "node";
+
+--[[ Objeto Record List ]]--
+
+gui.RecordList = gui.Layout.inherit();
+registerTag(gui.RecordList, 'recordList');
+
+function gui.RecordList:getField() return _obj_getProp(self.handle, "FieldName"); end;
+function gui.RecordList:setField(v) _obj_setProp(self.handle, "FieldName", v) end;
+
+function gui.RecordList:getItemHeight() return _obj_getProp(self.handle, "ItemHeight"); end;
+function gui.RecordList:setItemHeight(v) _obj_setProp(self.handle, "ItemHeight", v) end;
+
+function gui.RecordList:getMinHeight() return _obj_getProp(self.handle, "MinHeight"); end;
+function gui.RecordList:setMinHeight(v) _obj_setProp(self.handle, "MinHeight", v) end;
+
+function gui.RecordList:getMinQt() return _obj_getProp(self.handle, "MinQt"); end;
+function gui.RecordList:setMinQt(v) _obj_setProp(self.handle, "MinQt", v) end;
+
+function gui.RecordList:getAutoHeight() return _obj_getProp(self.handle, "AutoHeight"); end;
+function gui.RecordList:setAutoHeight(v) _obj_setProp(self.handle, "AutoHeight", v) end;
+
+function gui.RecordList:getTemplateForm() return _obj_getProp(self.handle, "TemplateForm"); end;
+function gui.RecordList:setTemplateForm(v) _obj_setProp(self.handle, "TemplateForm", v); end;
+
+function gui.RecordList:getLayout() return _obj_getProp(self.handle, "RecordListLayout"); end;
+function gui.RecordList:setLayout(v) _obj_setProp(self.handle, "RecordListLayout", v); end;
+
+function gui.RecordList:getSelectable() return _obj_getProp(self.handle, "SelectableList"); end;
+function gui.RecordList:setSelectable(v) _obj_setProp(self.handle, "SelectableList", v); end;
+
+function gui.RecordList:append() return ndb.openNodeFacade(_obj_invokeEx(self.handle, "AppendItemEx")); end;
+
+function gui.RecordList:getSelectedNode() return ndb.openNodeFacade(_gui_recordListGetSelectedNodeHandle(self.handle)); end;
+function gui.RecordList:setSelectedNode(node) _gui_recordListSetSelectedNodeHandle(self.handle, ndb.getNodeHandle(node)); end;
+
+function gui.RecordList:getSelectedForm() return objs.tryFindFromHandle(_gui_recordListGetSelectedFormHandle(self.handle)); end;
+
+function gui.RecordList:scrollToNode(node) _gui_recordListScrollToNodeHandle(self.handle, ndb.getNodeHandle(node)); end;
+function gui.RecordList:sort() _obj_invoke(self.handle, "ReorganizarItens"); end;
+
+function gui.RecordList:getChildren()
+ local ret = {};
+ local childCount = _obj_getProp(self.handle, "ChildFormCount");
+ local child;
+ local childHandle;
+ local idxDest = 1;
+
+ for i = 0, childCount - 1, 1 do
+ childHandle = _gui_rcl_getChild(self.handle, i);
+
+ if (childHandle ~= nil) then
+ child = gui.fromHandle(childHandle);
+
+ if (type(child) == "table") then
+ ret[idxDest] = child;
+ idxDest = idxDest + 1;
+ end
+ end;
+ end
+
+ return ret;
+end;
+
+gui.RecordList.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+gui.RecordList.props["templateForm"] = {setter = "setTemplateForm", getter = "getTemplateForm", tipo = "string"};
+gui.RecordList.props["itemHeight"] = {setter = "setItemHeight", getter = "getItemHeight", tipo = "double"};
+gui.RecordList.props["minHeight"] = {setter = "setMinHeight", getter = "getMinHeight", tipo = "double"};
+gui.RecordList.props["autoHeight"] = {setter = "setAutoHeight", getter = "getAutoHeight", tipo = "bool"};
+gui.RecordList.props["minQt"] = {setter = "setMinQt", getter = "getMinQt", tipo = "int"};
+gui.RecordList.props["layout"] = {setter = "setLayout", getter = "getLayout", tipo = "enum",
+ values = {"vertical", "horizontal", "horizontalTiles", "verticalTiles"}};
+gui.RecordList.props["selectable"] = {setter = "setSelectable", getter = "getSelectable", tipo = "bool"};
+
+gui.RecordList.props["selectedNode"] = {getter = "getSelectedNode", setter="setSelectedNode", tipo = "table"};
+gui.RecordList.props["selectedForm"] = {getter = "getSelectedForm", tipo = "table"};
+
+gui.RecordList.eves["onSelect"] = "";
+gui.RecordList.eves["onBeginEnumeration"] = "";
+gui.RecordList.eves["onItemAdded"] = "node, form";
+gui.RecordList.eves["onItemRemoved"] = "node, form";
+gui.RecordList.eves["onEndEnumeration"] = "";
+gui.RecordList.eves["onCompare"] = "nodeA, nodeB";
+
+--[[ Objeto GridRecordList ]]--
+
+gui.GridRecordList = gui.Layout.inherit();
+registerTag(gui.GridRecordList, 'gridRecordList');
+
+function gui.GridRecordList:append() return ndb.openNodeFacade(_obj_invokeEx(self.handle, "AppendItemEx")); end;
+function gui.GridRecordList:reorganize() _obj_invoke(self.handle, "Reorganize"); end;
+function gui.GridRecordList:getChildren() return _gui_getChildrenObj(self.handle); end;
+function gui.GridRecordList:getSelectedNode() return _obj_invokeEx(self.handle, "GetSelectedNodeEx"); end;
+function gui.GridRecordList:setSelectedNode(node) _obj_invokeEx(self.handle, "SetSelectedNodeEx", node); end;
+function gui.GridRecordList:getSelectedForm() return _obj_invokeEx(self.handle, "GetSelectedFormEx"); end;
+function gui.GridRecordList:scrollToNode(node) _obj_invokeEx(self.handle, "ScrollToNodeEx", node); end;
+
+gui.GridRecordList.props["field"] = {writeProp = "DataFieldName", readProp = "DataFieldName", tipo = "string"};
+gui.GridRecordList.props["templateForm"] = {writeProp = "TemplateForm", readProp = "TemplateForm", tipo = "string"};
+gui.GridRecordList.props["minQt"] = {writeProp = "MinQuantity", readProp = "MinQuantity", tipo = "int"};
+gui.GridRecordList.props["selectable"] = {writeProp = "IsSelectableList", readProp = "IsSelectableList", tipo = "bool"};
+gui.GridRecordList.props["selectedNode"] = {getter = "getSelectedNode", setter="setSelectedNode", tipo = "table"};
+gui.GridRecordList.props["paging"] = {writeProp = "IsPagingEnabled", readProp = "IsPagingEnabled", tipo = "bool"};
+gui.GridRecordList.props["pageSize"] = {writeProp = "PageSize", readProp = "PageSize", tipo = "int"};
+gui.GridRecordList.props["pageIndex"] = {writeProp = "PageIndex", readProp = "PageIndex", tipo = "int"};
+gui.GridRecordList.props["filterFields"] = {writeProp = "FilteringFields", readProp = "FilteringFields", tipo = "table"};
+
+gui.GridRecordList.props["selectedForm"] = {getter = "getSelectedForm", tipo = "table"};
+gui.GridRecordList.props["pageCount"] = {readProp = "PageCount", tipo = "int"};
+
+gui.GridRecordList.eves["onSelect"] = "";
+gui.GridRecordList.eves["onItemAdded"] = "node";
+gui.GridRecordList.eves["onItemRemoved"] = "node";
+gui.GridRecordList.eves["onItemFiltered"] = "node";
+gui.GridRecordList.eves["onItemUnfiltered"] = "node";
+gui.GridRecordList.eves["onItemShow"] = "node, form";
+gui.GridRecordList.eves["onItemHide"] = "node, form";
+gui.GridRecordList.eves["onCompare"] = "left, right";
+gui.GridRecordList.eves["onFilter"] = "node";
+gui.GridRecordList.eves["onGroupId"] = "node";
+gui.GridRecordList.eves["onGroupCompare"] = "left, right";
+gui.GridRecordList.eves["onGroupHeader"] = "id";
+gui.GridRecordList.eves["onGroupShow"] = "id, header";
+gui.GridRecordList.eves["onGroupHide"] = "id, header";
+gui.GridRecordList.eves["onEmptyState"] = "";
+gui.GridRecordList.eves["onPagingStateChange"] = "";
+gui.GridRecordList.eves["onBeginOrganization"] = "";
+gui.GridRecordList.eves["onEndOrganization"] = "";
+
+--[[ Objeto GridRecordListPgCtrl ]]--
+
+gui.GridRecordListPgNav = gui.Layout.inherit();
+registerTag(gui.GridRecordListPgNav, 'gridRecordListPgNav');
+
+function gui.GridRecordListPgNav:setTarget(value) _obj_invokeEx(self.handle, 'SetGridRecordList', value); end;
+function gui.GridRecordListPgNav:getTarget() return _obj_invokeEx(self.handle, 'GetGridRecordList'); end;
+
+gui.GridRecordListPgNav.props["target"] = {setter = "setTarget", getter = "getTarget", tipo = "obj", class=gui.GridRecordList};
+
+--[[ Objeto DataScopeBox ]]--
+
+gui.DataScopeBox = gui.Layout.inherit();
+registerTag(gui.DataScopeBox, 'dataScopeBox');
+
+function gui.DataScopeBox:getNodeObject() return rawget(self, "__nodeObject"); end;
+
+function gui.DataScopeBox:setNodeObject(nodeObject)
+ rawset(self, "__nodeObject", nodeObject);
+ _gui_assignNodeObject(self.handle, ndb.getNodeHandle(nodeObject));
+end;
+
+gui.DataScopeBox.props["scopeNode"] = {setter = "setNodeObject", getter = "getNodeObject", tipo = "table"};
+gui.DataScopeBox.props["nodeObject"] = {setter = "setNodeObject", getter = "getNodeObject", tipo = "table"};
+gui.DataScopeBox.props["node"] = {setter = "setNodeObject", getter = "getNodeObject", tipo = "table"};
+
+gui.DataScopeBox.eves["onNodeReady"] = "";
+gui.DataScopeBox.eves["onNodeUnready"] = "";
+gui.DataScopeBox.eves["onNodeChanged"] = "";
+
+--[[ Objeto RichEdit ]]--
+
+gui.RichEdit = gui.Control.inherit();
+registerTag(gui.RichEdit, 'richEdit');
+
+function gui.RichEdit:getField() return _gui_getFieldName(self.handle); end;
+function gui.RichEdit:setField(v) _gui_setFieldName(self.handle, v); end;
+
+function gui.RichEdit:beginEdit() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LBeginEdit") end; end;
+function gui.RichEdit:endEdit() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEndEdit") end; end;
+
+function gui.RichEdit:selectAll() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LSelectAll") end; end;
+function gui.RichEdit:unselect() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LUnselect") end; end;
+function gui.RichEdit:getSelectionPosInChars() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionPosInChars"); else return 0, 0; end; end;
+function gui.RichEdit:getSelectionPosInGlyphs() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionPosInGlyphs"); else return 0, 0; end; end;
+function gui.RichEdit:getIsSelectionForward() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetIsSelectionForward"); else return true; end; end;
+function gui.RichEdit:getSelectionText() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionText"); else return ""; end; end;
+function gui.RichEdit:getSelectionURL() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionURL"); else return ""; end; end;
+function gui.RichEdit:getSelectionFontColor() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionFontColor"); else return "Black"; end; end;
+function gui.RichEdit:getSelectionFontBkgColor() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionFontBkgColor"); else return "White"; end; end;
+function gui.RichEdit:getSelectionFontSize() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionFontSize"); else return 14; end; end;
+function gui.RichEdit:getSelectionFontFamily() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionFontFamily"); else return "Roboto"; end; end;
+function gui.RichEdit:getSelectionFontStyle() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionFontStyle"); else return {}; end; end;
+function gui.RichEdit:getSelectionFloat() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionFloat"); else return "none"; end; end;
+function gui.RichEdit:getSelectionParaAlign() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetSelectionParaAlign"); else return "left"; end; end;
+function gui.RichEdit:getSelectionParaLineSpacing() if System.checkAPIVersion(88, 3) then return _obj_invokeEx(self.handle, "LGetSelectionParaLineSpacing"); else return 1.0; end; end;
+function gui.RichEdit:getSelectionParaTopMargin() if System.checkAPIVersion(88, 3) then return _obj_invokeEx(self.handle, "LGetSelectionParaTopMargin"); else return 0; end; end;
+function gui.RichEdit:getSelectionParaBottomMargin() if System.checkAPIVersion(88, 3) then return _obj_invokeEx(self.handle, "LGetSelectionParaBottomMargin"); else return 0; end; end;
+
+function gui.RichEdit:gotoStart(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoStart", holdSelection); end; end;
+function gui.RichEdit:gotoEnd(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoEnd", holdSelection); end; end;
+function gui.RichEdit:gotoNext(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoNext", holdSelection); end; end;
+function gui.RichEdit:gotoPrevious(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoPrevious", holdSelection); end; end;
+function gui.RichEdit:gotoStartOfLine(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoStartOfLine", holdSelection); end; end;
+function gui.RichEdit:gotoEndOfLine(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoEndOfLine", holdSelection); end; end;
+function gui.RichEdit:gotoNextWord(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoNextWord", holdSelection); end; end;
+function gui.RichEdit:gotoPreviousWord(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoPreviousWord", holdSelection); end; end;
+function gui.RichEdit:gotoLineUp(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoLineUp", holdSelection); end; end;
+function gui.RichEdit:gotoLineDown(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoLineDown", holdSelection); end; end;
+function gui.RichEdit:gotoPageUp(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoPageUp", holdSelection); end; end;
+function gui.RichEdit:gotoPageDown(holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoPageDown", holdSelection); end; end;
+function gui.RichEdit:gotoPositionInGlyphs(pos, holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoPositionInGlyphs", pos, holdSelection); end; end;
+function gui.RichEdit:gotoPositionInChars(pos, holdSelection) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGotoPositionInChars", pos, holdSelection); end; end;
+
+function gui.RichEdit:copySelectionToClipboard() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LCopySelectionToClipboard"); end; end;
+
+function gui.RichEdit:deleteSelection() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_DeleteSelection"); end; end;
+function gui.RichEdit:insertText(text) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_InsertText", text); end; end;
+function gui.RichEdit:insertTalemark(talemarkText, talemarkOptions, talemarkSheetStyle) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_InsertTalemark", talemarkText, talemarkOptions, talemarkSheetStyle); end; end;
+function gui.RichEdit:insertImage(params) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_InsertImage", params); end; end;
+function gui.RichEdit:breakLine() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_BreakLine"); end; end;
+function gui.RichEdit:breakParagraph() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_BreakParagraph"); end; end;
+function gui.RichEdit:indent(qty) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_Indent", qty); end; end;
+function gui.RichEdit:pasteFromClipboard() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_PasteFromClipboard"); end; end;
+function gui.RichEdit:cutSelectionToClipboard() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_CutSelectionToClipboard"); end; end;
+function gui.RichEdit:setSelectionURL(url) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionURL", url); end; end;
+function gui.RichEdit:setSelectionFontColor(color) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionFontColor", color); end; end;
+function gui.RichEdit:setSelectionFontBkgColor(color) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionFontBkgColor", color); end; end;
+function gui.RichEdit:setSelectionFontSize(size) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionFontSize", size); end; end;
+function gui.RichEdit:setSelectionFontFamily(family) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionFontFamily", family); end; end;
+function gui.RichEdit:setSelectionFontStyle(style) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionFontStyle", style); end; end;
+function gui.RichEdit:setSelectionFloat(floatMode) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionFloat", floatMode); end; end;
+function gui.RichEdit:setSelectionParaAlign(paraAlign) if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionParaAlign", paraAlign); end; end;
+function gui.RichEdit:setSelectionParaLineSpacing(value) if System.checkAPIVersion(88, 3) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionParaLineSpacing", value); end; end;
+function gui.RichEdit:setSelectionParaTopMargin(value) if System.checkAPIVersion(88, 3) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionParaTopMargin", value); end; end;
+function gui.RichEdit:setSelectionParaBottomMargin(value) if System.checkAPIVersion(88, 3) then return _obj_invokeEx(self.handle, "LEditOp_SetSelectionParaBottomMargin", value); end; end;
+
+function gui.RichEdit:getLengthInChars() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetLengthInChars"); else return 0; end; end;
+function gui.RichEdit:getLengthInGlyphs() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetLengthInGlyphs"); else return 0; end; end;
+function gui.RichEdit:getText() if System.checkAPIVersion(87, 4) then return _obj_invokeEx(self.handle, "LGetText"); else return ""; end; end;
+
+gui.RichEdit.props["animateImages"] = {readProp = "CanAnimateImages", writeProp = "CanAnimateImages", tipo = "bool"};
+gui.RichEdit.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+gui.RichEdit.props["backgroundColor"] = {readProp = "BackgroundColor", writeProp = "BackgroundColor", tipo = "color"};
+gui.RichEdit.props["defaultFontColor"] = {readProp = "DefaultFontColor", writeProp = "DefaultFontColor", tipo = "color"};
+gui.RichEdit.props["defaultFontSize"] = {readProp = "DefaultFontSize", writeProp = "DefaultFontSize", tipo = "double"};
+gui.RichEdit.props["showToolbar"] = {readProp = "ShowToolbar", writeProp = "ShowToolbar", tipo = "bool"};
+gui.RichEdit.props["readOnly"] = {readProp = "ReadOnly", writeProp = "ReadOnly", tipo = "bool"};
+gui.RichEdit.props["hideSelection"] = {readProp = "HideSelectionNoFocus", writeProp = "HideSelectionNoFocus", tipo = "bool"};
+
+--[[ Objeto Popup ]]--
+
+gui.Popup = gui.Layout.inherit();
+registerTag(gui.Popup, 'popup');
+
+function gui.Popup:getCancelable() return _obj_getProp(self.handle, "Cancelavel"); end;
+function gui.Popup:setCancelable(v) _obj_setProp(self.handle, "Cancelavel", v) end;
+
+function gui.Popup:getBackOpacity() return _obj_getProp(self.handle, "BackOpacity"); end;
+function gui.Popup:setBackOpacity(v) _obj_setProp(self.handle, "BackOpacity", v) end;
+
+function gui.Popup:getDrawContainer() return _obj_getProp(self.handle, "DesenharPopupContainer"); end;
+function gui.Popup:setDrawContainer(v) _obj_setProp(self.handle, "DesenharPopupContainer", v) end;
+
+function gui.Popup:setNodeObject(nodeObject)
+ rawset(self, "nodeObject", nodeObject);
+ _gui_assignNodeObject(self.handle, ndb.getNodeHandle(nodeObject));
+end;
+
+function gui.Popup:getNodeObject() return rawget(self, "nodeObject") end;
+
+function gui.Popup:showPopupEx(placement, control)
+ if type(placement) ~= "string" then
+ placement = "center";
+ end;
+
+ _obj_setProp(self.handle, "Placement", placement);
+
+ if (type(control) == "table") and (control.handle ~= nil) then
+ _obj_setProp(self.handle, "TargetControlHandle", control.handle);
+ else
+ _obj_setProp(self.handle, "TargetControlHandle", 0);
+ end;
+
+ _obj_invoke(self.handle, "ExibirPopup");
+end;
+
+gui.Popup.show = gui.Popup.showPopupEx;
+gui.Popup.showPopup = gui.Popup.showPopupEx;
+
+function gui.Popup:closePopup(cancelar, forcar) _obj_invoke(self.handle, "FecharPopup", cancelar == true, forcar == true); end;
+function gui.Popup:close(cancelar, forcar) _obj_invoke(self.handle, "FecharPopup", cancelar == true, forcar == true); end;
+
+gui.Popup.props["cancelable"] = {setter = "setCancelable", getter = "getCancelable", tipo = "bool"};
+gui.Popup.props["backOpacity"] = {setter = "setBackOpacity", getter = "getBackOpacity", tipo = "double"};
+gui.Popup.props["drawContainer"] = {setter = "setDrawContainer", getter = "getDrawContainer", tipo = "bool"};
+gui.Popup.props["scopeNode"] = {setter = "setNodeObject", getter = "getNodeObject", tipo = "table"};
+gui.Popup.props["nodeObject"] = {setter = "setNodeObject", getter = "getNodeObject", tipo = "table"};
+gui.Popup.props["node"] = gui.Popup.props["nodeObject"];
+gui.Popup.props["scopeNode"] = gui.Popup.props["nodeObject"];
+gui.Popup.props["autoScopeNode"] = {writeProp = "AutoScopeNode", readProp = "AutoScopeNode", tipo = "bool"};
+
+gui.Popup.eves["onClose"] = "canceled";
+gui.Popup.eves["onCanClose"] = "canceled";
+gui.Popup.eves["onCalculateSize"] = "dueToResize, width, height";
+
+gui.Popup.eves["onNodeReady"] = "";
+gui.Popup.eves["onNodeUnready"] = "";
+gui.Popup.eves["onNodeChanged"] = "";
+
+--[[ Objeto Progress Bar ]]--
+
+gui.ProgressBar = gui.Control.inherit();
+registerTag(gui.ProgressBar, 'progressBar');
+
+function gui.ProgressBar:getColor() return _obj_getProp(self.handle, "Color"); end;
+function gui.ProgressBar:setColor(v) _obj_setProp(self.handle, "Color", v) end;
+
+function gui.ProgressBar:getPosition() return _obj_getProp(self.handle, "Value"); end;
+function gui.ProgressBar:setPosition(v) _obj_setProp(self.handle, "Value", v) end;
+
+function gui.ProgressBar:getMin() return _obj_getProp(self.handle, "Min"); end;
+function gui.ProgressBar:setMin(v) _obj_setProp(self.handle, "Min", v) end;
+
+function gui.ProgressBar:getMax() return _obj_getProp(self.handle, "Max"); end;
+function gui.ProgressBar:setMax(v) _obj_setProp(self.handle, "Max", v) end;
+
+function gui.ProgressBar:getField() return _obj_getProp(self.handle, "Field"); end;
+function gui.ProgressBar:setField(v) _obj_setProp(self.handle, "Field", v); end;
+
+function gui.ProgressBar:getFieldMin() return _obj_getProp(self.handle, "FieldMin"); end;
+function gui.ProgressBar:setFieldMin(v) _obj_setProp(self.handle, "FieldMin", v); end;
+
+function gui.ProgressBar:getFieldMax() return _obj_getProp(self.handle, "FieldMax"); end;
+function gui.ProgressBar:setFieldMax(v) _obj_setProp(self.handle, "FieldMax", v); end;
+
+function gui.ProgressBar:getMouseGlow() return _obj_getProp(self.handle, "MouseGlow"); end;
+function gui.ProgressBar:setMouseGlow(v) _obj_setProp(self.handle, "MouseGlow", v); end;
+
+function gui.ProgressBar:getColorMode() return _obj_getProp(self.handle, "ColorMode"); end;
+function gui.ProgressBar:setColorMode(v) _obj_setProp(self.handle, "ColorMode", v); end;
+
+gui.ProgressBar.props["color"] = {setter = "setColor", getter = "getColor", tipo = "color"};
+gui.ProgressBar.props["position"] = {setter = "setPosition", getter = "getPosition", tipo = "double"};
+gui.ProgressBar.props["value"] = {setter = "setPosition", getter = "getPosition", tipo = "double"};
+gui.ProgressBar.props["min"] = {setter = "setMin", getter = "getMin", tipo = "double"};
+gui.ProgressBar.props["max"] = {setter = "setMax", getter = "getMax", tipo = "double"};
+gui.ProgressBar.props["field"] = {setter = "setField", getter = "getField", tipo = "string"};
+gui.ProgressBar.props["fieldMin"] = {setter = "setFieldMin", getter = "getFieldMin", tipo = "string"};
+gui.ProgressBar.props["fieldMax"] = {setter = "setFieldMax", getter = "getFieldMax", tipo = "string"};
+gui.ProgressBar.props["mouseGlow"] = {setter = "setMouseGlow", getter = "getMouseGlow", tipo = "bool"};
+gui.ProgressBar.props["colorMode"] = {setter = "setColorMode", getter = "getColorMode", tipo = "enum", values={"default", "hl"}};
+
+--[[ Objeto Timer ]]--
+
+gui.Timer = objs.Timer;
+registerTag(gui.Timer, 'timer');
+
+
+--[[ Objeto ActivityIndicator ]]--
+
+gui.ActivityIndicator = gui.Control.inherit();
+registerTag(gui.ActivityIndicator, 'activityIndicator');
+
+--[[ Objeto InertialMovement ]]--
+
+gui.InertialMovement = objs.newClass()
+registerTag(gui.InertialMovement, 'TInertialMovement');
+
+gui.newInertialMovement = gui.InertialMovement.new;
+
+function gui.InertialMovement:setPos(x, y) _obj_invoke(self.handle, "SetPosition", x, y); end;
+function gui.InertialMovement:getPos() return _obj_invokeEx(self.handle, "ExGetPosition"); end;
+function gui.InertialMovement:setBounds(minX, minY, maxX, maxY) _obj_invoke(self.handle, "SetBounds", minX, minY, maxX, maxY); end;
+function gui.InertialMovement:pointerDown(x, y) _obj_invoke(self.handle, "PointerDown", x, y); end;
+function gui.InertialMovement:pointerMove(x, y) _obj_invoke(self.handle, "PointerMove", x, y); end;
+function gui.InertialMovement:pointerUp(x, y) _obj_invoke(self.handle, "PointerUp", x, y); end;
+function gui.InertialMovement:pointerLeave() _obj_invoke(self.handle, "PointerLeave"); end;
+function gui.InertialMovement:pointerWheel(deltaX, deltaY) _obj_invoke(self.handle, "PointerWheel", deltaX, deltaY); end;
+
+gui.InertialMovement.props["active"] = {tipo = "boolean", readProp = "Active", writeProp="Active"};
+gui.InertialMovement.props["animated"] = {tipo = "boolean", readProp = "Animated", writeProp="Animated"};
+gui.InertialMovement.props["decelerationRate"] = {tipo = "double", readProp = "DecelerationRate", writeProp="DecelerationRate"};
+
+gui.InertialMovement.eves["onChange"] = "";
+
+--[[ Objeto Drag n Drop ]]--
+
+local Serializer = nil;
+
+local __DragDropDataProps = {dataCount = {tipo = "int", readProp = "DataCount"}};
+
+local __DragDropDataMethods =
+ {
+ addData = function(d, dataType, dataValue)
+ _obj_invokeEx(d.handle, "AddData", dataType, Serializer.packData(dataValue));
+ end,
+
+ getData = function(d, dataType)
+ return Serializer.unpackData(_obj_invokeEx(d.handle, "GetData", dataType));
+ end
+ };
+
+local __DragProps = {actionCount = {tipo = "int", readProp = "ActionCount"}};
+
+local __DragMethods =
+ {
+ addAction = function(d, dataType, callback)
+ if type(callback) == "function" then
+ _gui_addDragAction(d.handle, dataType, callback);
+ end;
+ end
+ };
+
+local __DragEvents = {};
+
+local __DropProps = {actionCount = {tipo = "int", readProp = "ActionCount"}};
+
+local __DropMethods =
+ {
+ addAction = function(d, dataType, callback)
+ if type(callback) == "function" then
+ _gui_addDropAction(d.handle, dataType, callback);
+ end;
+ end
+ };
+
+local __DropEvents = {};
+
+local function dragDropDataObjectFromHandle(handle)
+ if Serializer == nil then
+ Serializer = require("utils.serializer.dlua");
+ end;
+
+ local obj = objs.objectFromHandle(handle);
+
+ if obj.props == nil then
+ obj.props = {};
+ end;
+
+ for k, v in pairs(__DragDropDataProps) do
+ obj.props[k] = v;
+ end;
+
+ for k, v in pairs(__DragDropDataMethods) do
+ rawset(obj, k, v);
+ end;
+
+ return obj;
+end;
+
+local function dragObjectFromHandle(handle)
+ local obj = dragDropDataObjectFromHandle(handle);
+
+ for k, v in pairs(__DragProps) do
+ obj.props[k] = v;
+ end;
+
+ for k, v in pairs(__DragMethods) do
+ rawset(obj, k, v);
+ end;
+
+ obj.eves = __DragEvents;
+ return obj;
+end
+
+function gui.newDrag()
+ return gui.fromHandle(_obj_newObject("TDragObject"));
+end;
+
+guiLoaders["TDragObject"] = dragObjectFromHandle;
+
+local function dropObjectFromHandle(handle)
+ local obj = dragDropDataObjectFromHandle(handle);
+
+ for k, v in pairs(__DropProps) do
+ obj.props[k] = v;
+ end;
+
+ for k, v in pairs(__DropMethods) do
+ rawset(obj, k, v);
+ end;
+
+ obj.eves = __DropEvents;
+ return obj;
+end
+
+function gui.newDrop()
+ return gui.fromHandle(_obj_newObject("TDropObject"));
+end;
+
+guiLoaders["TDropObject"] = dropObjectFromHandle;
+
+function __export__guiInitDropObject(dropUserData)
+ local d = gui.newDrop();
+ _gui_initDragDropDataObject(d.handle, dropUserData);
+ return d;
+end;
+
+function __export__guiInitDragObject(dragUserData)
+ local d = gui.newDrag();
+ _gui_initDragDropDataObject(d.handle, dragUserData);
+ return d;
+end;
+
+--[[ API gui ]]--
+
+function gui.fromHandle(handle)
+ if (handle == nil) then
+ return nil;
+ end
+
+ local ctrl = objs.tryFindFromHandle(handle);
+
+ if (ctrl ~= nil) then
+ return ctrl;
+ end;
+
+ local className = _obj_getClassName(handle);
+
+ if (className == nil) then
+ return nil;
+ end;
+
+ local loader = guiLoaders[className];
+
+ if (loader ~= nil) then
+ ctrl = loader(handle);
+ else
+ ctrl = controlFromHandle(handle);
+ end
+
+ objs.registerHandleIfNeeded(handle, ctrl);
+ return ctrl;
+end;
+
+function gui.findControlByName(controlName, referenceControl)
+ local parentMost;
+ local p;
+
+ if (type(referenceControl) ~= "table") or (referenceControl.handle == nil) then
+ return nil;
+ end;
+
+ local child;
+
+ child = referenceControl:findChildByName(controlName, true);
+
+ if child ~= nil then
+ return child;
+ end;
+
+ -- Else, vamos ir ate a RAIZ procurar a partir dela o objeto sem fazer analise recursiva
+
+ parentMost = nil;
+ p = referenceControl;
+
+ while p ~= nil do
+ if (type(p) == "table") and (p.findChildByName ~= nil) then
+ parentMost = p;
+ child = parentMost:findChildByName(controlName, false, true); -- não fazer analise recursiva neste ponto ainda
+
+ if child ~= nil then
+ return child;
+ end;
+ end;
+
+ p = p:getParent();
+ end;
+
+ if parentMost == nil then
+ return nil;
+ elseif parentMost.name == controlName then
+ return parentMost;
+ end;
+
+ return parentMost:findChildByName(controlName, true);
+end;
+
+findControlByName = gui.findControlByName;
+
+function gui.newForm(formName)
+ if (formName == nil) then
+ return gui.Form.new();
+ end;
+
+ if (type(formName) == "string" and (rrpg ~= nil)) then
+ local formFactory = rrpg.forms[formName];
+
+ if formFactory ~= nil then
+ local frm = formFactory.newEditor();
+ assert(frm ~= nil);
+
+ return frm;
+ else
+ error("Form name not found: '" .. formName .. "'");
+ end;
+ end;
+
+ return nil;
+end;
+
+function gui.newPopupForm(formName)
+ if (formName == nil) then
+ return gui.fromHandle(_obj_newObject("popupForm"));
+ end;
+
+ if (type(formName) == "string" and (rrpg ~= nil)) then
+ local formFactory = rrpg.forms[formName];
+
+ if (formFactory ~= nil) and (formFactory.formComponentName == "popupForm") then
+ local frm = formFactory.newEditor();
+ assert(frm ~= nil);
+
+ return frm;
+ else
+ error("PopupForm name not found: '" .. formName .. "'");
+ end;
+ end;
+
+ return nil;
+end;
+
+local function formParameterToObjectForm(form)
+ local retorno = nil;
+
+ if (type(form) == "string") then
+ retorno = gui.newForm(form);
+ elseif (type(form) == "table") then
+ local handle = rawget(form, "handle");
+
+ if (handle ~= nil) and (rawget(form, "__isFormFlag")) then
+ retorno = form;
+ end;
+ end;
+
+ return retorno;
+end;
+
+local _popupFormShowers = {};
+setmetatable(_popupFormShowers, {__mode="k"}); -- popupFormShowers possui chaves weak-reference
+
+function gui.showPopup(form, options)
+ if (form == nil) then
+ error("invalid parameter - form is nil");
+ return false;
+ end;
+
+ if type(options) ~= "table" then
+ options = {};
+ end;
+
+ options.placement = options.placement or "center";
+ form = formParameterToObjectForm(form);
+
+ if (form == nil) then
+ return false;
+ end;
+
+ local popupShower = _popupFormShowers[form];
+
+ if popupShower == nil then
+ popupShower = rrpgObjs.componentFromHandle(_obj_newObject('TLuaFiremonkeyPopupShower'));
+ rrpgObjs.registerHandleIfNeeded(popupShower.handle, popupShower);
+ _popupFormShowers[form] = popupShower;
+
+ local frmHandle = form.handle;
+ _obj_invoke(popupShower.handle, "SetFormHandle", frmHandle);
+
+ popupShower:addEventListener("OnPopupClose",
+ function()
+ local frmRef = objs.tryFindFromHandle(frmHandle);
+
+ if frmRef ~= nil then
+ _popupFormShowers[frmRef] = nil;
+ end;
+ end);
+ end;
+
+ local closeListenerId = rawget(popupShower, "__closeListenerID");
+
+ if closeListenerId ~= nil then
+ popupShower:removeEventListener(closeListenerId);
+ rawset(popupShower, "__closeListenerID", nil);
+ end;
+
+ if type(options.onClose) == "function" then
+ closeListenerId = popupShower:addEventListener("OnPopupClose", options.onClose);
+ rawset(popupShower, "__closeListenerID", closeListenerId);
+ end;
+
+ _obj_setProp(popupShower.handle, "PopupPlacement", options.placement);
+ return _obj_invoke(popupShower.handle, "Show");
+end;
+
+function gui.closePopup(form)
+ if type(form) == "table" then
+ for k, v in pairs(_popupFormShowers) do
+ if k == form then
+ return _obj_invoke(v.handle, "Close");
+ end;
+ end;
+ elseif type(form) == "string" then
+ local fechouAlgum = false;
+
+ for k, v in pairs(_popupFormShowers) do
+ if (type(k) == "table") and (k.name == form) then
+ fechouAlgum = fechouAlgum or _obj_invoke(v.handle, "Close");
+ end;
+ end;
+
+ return fechouAlgum;
+ else
+ return false;
+ end;
+end;
+
+function gui.openInBrowser(url)
+ if type(url) == "string" then
+ local achado = url:find("https?://");
+
+ if achado ~= 1 then
+ url = "http://" .. url;
+ end;
+
+ return _gui_openInBrowser(url);
+ end;
+end;
+
+function gui.asyncOpenFirecastURI(uri, params)
+ local promiseHandle = _obj_invokeEx(gui.handle, "AsyncOpenFirecastURI", uri, params);
+ return Async.Promise.wrap(promiseHandle);
+end;
+
+function gui.toast(message)
+ return _gui_toast(message);
+end;
+
+function gui.getShiftState()
+ return _gui_getShiftState();
+end;
+
+-- [ Form cache control ]--
+
+local __frmCachedByTime = {cacheName = {}, countByName = {}, genCacheId = 1};
+
+function __frmCachedByTime:tryAcquireByName(name)
+ if (type(name) ~= "string") or (name == "") then
+ return nil;
+ end;
+
+ local formsWithSameName = self.cacheName[name];
+
+ if formsWithSameName ~= nil then
+ local form = nil;
+
+ for k, v in pairs(formsWithSameName) do
+ if (type(k) == "table") and (v ~= nil) then
+ form = k;
+ break;
+ end;
+ end;
+
+ if form ~= nil then
+ formsWithSameName[form] = nil;
+ self.countByName[name] = (self.countByName[name] or 0) - 1;
+
+ if self.countByName[name] <= 0 then
+ self.cacheName[name] = nil;
+ self.countByName[name] = nil;
+ end;
+
+ rawset(form, '__timeCacheId', nil);
+
+ local timeoutId = rawget(form, '__timeCacheTimeoutId');
+
+ if timeoutId ~= nil then
+ Utils.clearTimeout(timeoutId);
+ rawset(form, '__timeCacheTimeoutId', nil);
+ end;
+
+ return form;
+ else
+ return nil;
+ end;
+ else
+ return nil;
+ end;
+end;
+
+function __frmCachedByTime:createTimeoutCallback(name, form, cacheId)
+ return function()
+ local currentCacheId = rawget(form, "__timeCacheId");
+ local formsWithSameName = self.cacheName[name];
+
+ if (formsWithSameName ~= nil) and (currentCacheId == cacheId) then
+ -- Remove from cache to let GC collect the form
+
+ rawset(form, '__timeCacheId', nil);
+ rawset(form, '__timeCacheTimeoutId', nil);
+
+ formsWithSameName[form] = nil;
+ self.countByName[name] = (self.countByName[name] or 0) - 1;
+
+ if self.countByName[name] <= 0 then
+ self.cacheName[name] = nil;
+ self.countByName[name] = nil;
+ end;
+ end;
+ end;
+end;
+
+function __frmCachedByTime:releaseByName(name, form)
+ assert(form ~= nil);
+
+ if (type(name) ~= "string") or (name == "") then
+ return;
+ end;
+
+ if form.setNodeDatabase ~= nil then
+ form:setNodeDatabase(nil);
+ end;
+
+ form:setParent(nil);
+
+ local formsWithSameName = self.cacheName[name];
+
+ if formsWithSameName == nil then
+ formsWithSameName = {};
+ self.cacheName[name] = formsWithSameName;
+ self.countByName[name] = 0;
+ end;
+
+ formsWithSameName[form] = true;
+ self.countByName[name] = (self.countByName[name] or 0) + 1;
+
+ self.genCacheId = self.genCacheId + 1;
+
+ local cacheId = self.genCacheId;
+ rawset(form, '__timeCacheId', cacheId);
+
+ local timeoutId = Utils.setTimeout(self:createTimeoutCallback(name, form, cacheId), gui.DEFAULT_FORM_CACHE_TIMEOUT);
+ rawset(form, '__timeCacheTimeoutId', timeoutId);
+end;
+
+-- [[ Exported functions ]] --
+
+function _export_gui_fromHandle(handle)
+ return gui.fromHandle(handle);
+end;
+
+function _export_gui_acquireForm(formName)
+ if Firecast == nil then
+ require('rrpg.lua');
+ end;
+
+ assert(Firecast ~= nil);
+ local frmClass = Firecast.forms[formName];
+
+ if frmClass ~= nil then
+ local frm = nil;
+
+ if frmClass.cacheMode == "time" then
+ frm = __frmCachedByTime:tryAcquireByName(formName);
+ end;
+
+ if frm ~= nil then
+ return frm;
+ end;
+
+ frm = frmClass.newEditor();
+ assert(frm ~= nil);
+
+ rawset(frm, "__cachedFrmClass", frmClass);
+ return frm;
+ else
+ return nil;
+ end;
+end;
+
+function _export_gui_releaseForm(form)
+ if form == nil then
+ return;
+ end;
+
+ local cachedFrmClass = rawget(form, "__cachedFrmClass");
+ local cacheMode;
+
+ if cachedFrmClass ~= nil then
+ cacheMode = cachedFrmClass.cacheMode;
+ else
+ cacheMode = nil;
+ end;
+
+ if cacheMode == "time" then
+ __frmCachedByTime:releaseByName(cachedFrmClass.name, form);
+ end;
+end;
+
+return gui;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgGUI_grid.dlua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgGUI_grid.dlua
new file mode 100644
index 00000000..42ce9b30
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgGUI_grid.dlua
@@ -0,0 +1,244 @@
+local Objs = require("rrpgObjs.lua");
+
+local SCREEN_SIZES_ARRAY = {"xs", "sm", "md", "lg", "xl"};
+local VALID_SCREEN_SIZE_STR_DICT = {};
+
+for i = 1, #SCREEN_SIZES_ARRAY, 1 do
+ VALID_SCREEN_SIZE_STR_DICT[SCREEN_SIZES_ARRAY[i]] = true;
+end;
+
+-- Class Declaration
+
+local Grid = Objs.newClass();
+
+function Grid.shouldUseScreenSizeStr(value)
+ return (value ~= nil) and (type(value) == "string") and VALID_SCREEN_SIZE_STR_DICT[value];
+end;
+
+function __registerScreenSizePropFor_specificScreenSize(screenSize, details, outerGetter, outerSetter)
+ local wrappedSetter =
+ function(instance, value)
+ return outerSetter(instance, screenSize, value);
+ end;
+
+ local wrappedGetter =
+ function (instance)
+ return outerGetter(instance, screenSize);
+ end;
+
+ local propDetais = {getter=wrappedGetter, setter=wrappedSetter, tipo=details.tipo, values=details.values};
+
+ if screenSize ~= nil then
+ if details.lfmName ~= nil then
+ Grid.props[details.lfmName .. "-" .. screenSize] = propDetais;
+ else
+ Grid.props[details.luaName .. "-" .. screenSize] = propDetais;
+ end;
+ else
+ if details.lfmName ~= nil then
+ Grid.props[details.lfmName] = propDetais;
+ else
+ Grid.props[details.luaName] = propDetais;
+ end;
+ end;
+end;
+
+local function __registerScreenSizeProp(details)
+ local hostSetterMethodName = "Set" .. details.hostName;
+ local hostGetterMethodName = "Get" .. details.hostName;
+ local luaFirstLetterUpperCasePropName = details.luaName:gsub("^%l", string.upper);
+
+ local setter =
+ function (instance, screenSizeOrValue, value)
+ if Grid.shouldUseScreenSizeStr(screenSizeOrValue) then
+ _obj_invokeEx(instance.handle, hostSetterMethodName, screenSizeOrValue, value);
+ elseif (screenSizeOrValue ~= nil) then
+ if value == nil then
+ _obj_invokeEx(instance.handle, hostSetterMethodName, nil, screenSizeOrValue);
+ else
+ error('Invalid ScreenSize: "' .. tostring(screenSizeOrValue) .. '"');
+ end;
+ else
+ _obj_invokeEx(instance.handle, hostSetterMethodName, nil, value);
+ end;
+
+ return instance;
+ end;
+
+ local getter =
+ function (instance, screenSize)
+ if Grid.shouldUseScreenSizeStr(screenSize) then
+ return _obj_invokeEx(instance.handle, hostGetterMethodName, screenSize);
+ else
+ return _obj_invokeEx(instance.handle, hostGetterMethodName, nil);
+ end;
+ end;
+
+ Grid["set" .. luaFirstLetterUpperCasePropName] = setter;
+ Grid["get" .. luaFirstLetterUpperCasePropName] = getter;
+
+ __registerScreenSizePropFor_specificScreenSize(nil, details, getter, setter)
+
+ for i = 1, #SCREEN_SIZES_ARRAY do
+ __registerScreenSizePropFor_specificScreenSize(SCREEN_SIZES_ARRAY[i], details, getter, setter);
+ end;
+end;
+
+local function __registerNonScreenSizeProp(details)
+ local hostPropertyNamme = details.hostName;
+ local luaFirstLetterUpperCasePropName = details.luaName:gsub("^%l", string.upper);
+ local useDefaultValue = details.useDefaultValueOnSet;
+ local defaultValue = details.defaultValueOnSet;
+
+ local setter =
+ function (instance, value)
+ if (value == nil) and useDefaultValue then
+ _obj_setProp(instance.handle, hostPropertyNamme, defaultValue);
+ else
+ _obj_setProp(instance.handle, hostPropertyNamme, value);
+ end;
+
+ return instance;
+ end;
+
+ local getter =
+ function (instance)
+ return _obj_getProp(instance.handle, hostPropertyNamme);
+ end;
+
+ Grid["set" .. luaFirstLetterUpperCasePropName] = setter;
+ Grid["get" .. luaFirstLetterUpperCasePropName] = getter;
+
+ local propDetais = {getter=getter, setter=setter, tipo=details.tipo, values=details.values};
+ Grid.props[details.luaName] = propDetais;
+
+ if details.lfmName ~= nil then
+ Grid.props[details.lfmName] = propDetais;
+ end;
+end;
+
+local function __registerScreenSizeEvent_specificScreenSize(screenSize, details, setterWithScreenSizeArgument)
+ local eve = {arguments = details.arguments};
+
+ eve.setter =
+ function(instance, value)
+ setterWithScreenSizeArgument(instance, screenSize, value);
+ end;
+
+ if screenSize == nil then
+ if details.lfmName ~= nil then
+ Grid.eves[details.lfmName] = eve;
+ else
+ Grid.eves[details.luaName] = eve;
+ end;
+ else
+ if details.lfmName ~= nil then
+ Grid.eves[details.lfmName .. "-" .. screenSize] = eve;
+ else
+ Grid.eves[details.luaName .. "-" .. screenSize] = eve;
+ end;
+ end;
+end;
+
+local function __registerScreenSizeEvent(details)
+ local hostSetterMethodName = "Set" .. details.hostName;
+
+ local setterWithScreenSizeArgument =
+ function(instance, screenSize, value)
+ _obj_invokeEx(instance.handle, hostSetterMethodName, screenSize, value);
+ return instance;
+ end;
+
+ __registerScreenSizeEvent_specificScreenSize(nil, details, setterWithScreenSizeArgument)
+
+ for i = 1, #SCREEN_SIZES_ARRAY do
+ __registerScreenSizeEvent_specificScreenSize(SCREEN_SIZES_ARRAY[i], details, setterWithScreenSizeArgument);
+ end;
+end;
+
+function Grid:invalidate()
+ _obj_invokeEx(self.handle, "Invalidate");
+ return self;
+end;
+
+function Grid:reset()
+ _obj_invokeEx(self.handle, "Reset");
+ return self;
+end;
+
+function Grid:getTxtWidth()
+ return _obj_invokeEx(self.handle, "GetTxtWidth");
+end;
+
+local GRID_VERT_ALIGN_VALUES = {"top", "center", "middle", "bottom"};
+local GRID_HORZ_ALIGN_VALUES = {"start", "center", "end", "around", "between", "left", "right", "middle"};
+local GRID_CONTAINER_HORZ_ALIGN_VALUES = {"start", "center", "end", "left", "right", "middle"};
+
+-- Grid Properties
+
+__registerNonScreenSizeProp({luaName="role", hostName="Role", tipo="enum", values={"none", "row", "col", "block", "container"}});
+__registerNonScreenSizeProp({luaName="root", hostName="Root", tipo="bool", useDefaultValueOnSet=true, defaultValueOnSet=true});
+__registerNonScreenSizeProp({luaName="screenSizeDet", lfmName="screen-size-det", hostName="ScreenSizeDeterminator", tipo="bool", useDefaultValueOnSet=true, defaultValueOnSet=true});
+__registerNonScreenSizeProp({luaName="autoHeight", lfmName="auto-height", hostName="AutoHeight", tipo="bool", useDefaultValueOnSet=true, defaultValueOnSet=true});
+
+__registerScreenSizeProp({luaName="width", hostName="Width", tipo="int"});
+__registerScreenSizeProp({luaName="offset", lfmName="offset", hostName="Offset", tipo="int"});
+__registerScreenSizeProp({luaName="push", lfmName="push", hostName="Push", tipo="int"});
+__registerScreenSizeProp({luaName="pull", lfmName="pull", hostName="Pull", tipo="int"});
+__registerScreenSizeProp({luaName="cntVertAlign", lfmName="cnt-vert-align", hostName="CntVertAlign", tipo="enum", values=GRID_VERT_ALIGN_VALUES});
+__registerScreenSizeProp({luaName="cntHorzAlign", lfmName="cnt-horz-align", hostName="CntHorzAlign", tipo="enum", values=GRID_HORZ_ALIGN_VALUES});
+__registerScreenSizeProp({luaName="cntGutter", lfmName="cnt-gutter", hostName="CntGutter", tipo="double"});
+__registerScreenSizeProp({luaName="cntLineSpacing", lfmName="cnt-line-spacing", hostName="CntLineSpacing", tipo="double"});
+__registerScreenSizeProp({luaName="cntMinGridWidth", lfmName="cnt-min-grid-width", hostName="CntMinGridWidth", tipo="double"});
+__registerScreenSizeProp({luaName="cntMinGridWidthFt", lfmName="cnt-min-grid-width-ft", hostName="CntMinGridWidthFt", tipo="double"});
+__registerScreenSizeProp({luaName="invisibleReserved", lfmName="invisible-reserved", hostName="InvisibleReserved", tipo="bool"});
+__registerScreenSizeProp({luaName="vertAlign", lfmName="vert-align", hostName="SelfVertAlign", tipo="enum", values=GRID_VERT_ALIGN_VALUES});
+__registerScreenSizeProp({luaName="gutter", lfmName="gutter", hostName="SelfGutter", tipo="double"});
+__registerScreenSizeProp({luaName="horzAlign", lfmName="horz-align", hostName="SelfHorzAlign", tipo="enum", values=GRID_CONTAINER_HORZ_ALIGN_VALUES});
+__registerScreenSizeProp({luaName="breakLineBefore", lfmName="break-line-before", hostName="BreakLineBefore", tipo="bool"});
+__registerScreenSizeProp({luaName="breakLineAfter", lfmName="break-line-after", hostName="BreakLineAfter", tipo="bool"});
+__registerScreenSizeProp({luaName="order", lfmName="order", hostName="Order", tipo="int"});
+__registerScreenSizeProp({luaName="group", lfmName="group", hostName="Group", tipo="int"});
+__registerScreenSizeProp({luaName="marginLeft", lfmName="margin-left", hostName="MarginLeft", tipo="double"});
+__registerScreenSizeProp({luaName="marginTop", lfmName="margin-top", hostName="MarginTop", tipo="double"});
+__registerScreenSizeProp({luaName="marginRight", lfmName="margin-right", hostName="MarginRight", tipo="double"});
+__registerScreenSizeProp({luaName="marginBottom", lfmName="margin-bottom", hostName="MarginBottom", tipo="double"});
+__registerScreenSizeProp({luaName="paddingLeft", lfmName="padding-left", hostName="PaddingLeft", tipo="double"});
+__registerScreenSizeProp({luaName="paddingTop", lfmName="padding-top", hostName="PaddingTop", tipo="double"});
+__registerScreenSizeProp({luaName="paddingRight", lfmName="padding-right", hostName="PaddingRight", tipo="double"});
+__registerScreenSizeProp({luaName="paddingBottom", lfmName="padding-bottom", hostName="PaddingBottom", tipo="double"});
+__registerScreenSizeProp({luaName="dynWidthTxt", lfmName="dyn-width-txt", hostName="DynWidthTxt", tipo="bool"});
+__registerScreenSizeProp({luaName="dynHeightTxt", lfmName="dyn-height-txt", hostName="DynHeightTxt", tipo="bool"});
+__registerScreenSizeProp({luaName="postDynWidthTxt", lfmName="post-dyn-width-txt", hostName="PostDynWidthTxt", tipo="bool"});
+__registerScreenSizeProp({luaName="finalOffsetX", lfmName="final-offset-x", hostName="FinalOffsetX", tipo="double"});
+__registerScreenSizeProp({luaName="finalOffsetY", lfmName="final-offset-y", hostName="FinalOffsetY", tipo="double"});
+__registerScreenSizeProp({luaName="vertTile", lfmName="vert-tile", hostName="VertTile", tipo="bool"});
+__registerScreenSizeProp({luaName="vertTileWeight", lfmName="vert-tile-weight", hostName="VertTileWeight", tipo="double"});
+__registerScreenSizeProp({luaName="horzTile", lfmName="horz-tile", hostName="HorzTile", tipo="bool"});
+__registerScreenSizeProp({luaName="minHeight", lfmName="min-height", hostName="MinHeight", tipo="double"});
+__registerScreenSizeProp({luaName="maxHeight", lfmName="max-height", hostName="MaxHeight", tipo="double"});
+__registerScreenSizeProp({luaName="minWidth", lfmName="min-width", hostName="MinWidth", tipo="double"});
+__registerScreenSizeProp({luaName="maxWidth", lfmName="max-width", hostName="MaxWidth", tipo="double"});
+
+__registerScreenSizeProp({luaName="dynWidthSingleLine", lfmName="dyn-width-single-line", hostName="DynWidthSingleLine", tipo="bool"});
+__registerScreenSizeProp({luaName="dynWidthEachLine", lfmName="dyn-width-each-line", hostName="DynWidthEachLine", tipo="bool"});
+__registerScreenSizeProp({luaName="dynWidthMatchHeight", lfmName="dyn-width-match-height", hostName="DynWidthMatchHeight", tipo="bool"});
+
+
+-- Grid Events
+__registerScreenSizeEvent({luaName="onPrepare", lfmName="on-prepare", hostName="OnPrepare", arguments="screenSize"});
+__registerScreenSizeEvent({luaName="onAligned", lfmName="on-aligned", hostName="OnAligned", arguments="screenSize, changedBounds, childChangedBounds"});
+__registerScreenSizeEvent({luaName="onGetWidth", lfmName="on-get-width", hostName="OnGetWidth", arguments="screenSize, width"});
+__registerScreenSizeEvent({luaName="onGetHeight", lfmName="on-get-height", hostName="OnGetHeight", arguments="screenSize, height"});
+__registerScreenSizeEvent({luaName="onGetVertMargins", lfmName="on-get-vert-margins", hostName="OnGetVertMargins", arguments="screenSize, height, top, bottom"});
+
+-- Instance
+
+function Grid.new(ctrl)
+ assert(ctrl ~= nil);
+
+ local g = Grid.fromHandle(_obj_newObject("TLuaGridControl", ctrl.handle));
+ return g;
+end;
+
+return Grid;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgLFM.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgLFM.lua
new file mode 100644
index 00000000..1fc7525b
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgLFM.lua
@@ -0,0 +1,428 @@
+require("rrpgUtil.lua");
+require("rrpgGUI.lua");
+
+local serpent = nil;
+local lfmObjectsStrongRef = {};
+
+function lfm_getObject(ctrlOrHandle)
+ if ctrlOrHandle == nil then
+ return nil;
+ elseif isNumber(ctrlOrHandle) then
+ return lfmObjectsStrongRef[ctrlOrHandle];
+ else
+ return ctrlOrHandle;
+ end;
+end;
+
+function lfm_newObjectHandle(className)
+ local obj = gui.fromHandle(_obj_newObject(className));
+ lfmObjectsStrongRef[obj.handle] = obj;
+ return obj.handle;
+end;
+
+function lfm_destroyObject(ctrlOrHandle)
+ local obj = lfm_getObject(ctrlOrHandle);
+
+ if obj ~= nil then
+ lfmObjectsStrongRef[obj.handle] = nil;
+ obj:destroy();
+ end
+end
+
+function lfm_enumEvents(ctrlOrHandle)
+ local obj = lfm_getObject(ctrlOrHandle);
+
+ local eves = {};
+ local qt = 0;
+ local alreadyListedEves = {};
+
+ local function processEvent(eventName, eventData)
+ if not alreadyListedEves[eventName] then
+ alreadyListedEves[eventName] = true;
+
+ local eveRec = {name = eventName};
+
+ if type(eventData) == "table" then
+ eveRec.parameters = eventData.arguments or "";
+ else
+ eveRec.parameters = eventData or "";
+ end;
+
+ qt = qt + 1;
+ eves[qt] = eveRec;
+ end;
+ end;
+
+ -- Instance Defined Events
+ local definedEves = obj.eves;
+
+ if definedEves ~= nil then
+ for k, v in pairs(obj.eves) do
+ processEvent(k, v);
+ end;
+ end;
+
+ -- Class Defined Events
+ local currentClass = rawget(obj, "class");
+
+ while currentClass ~= nil do
+ definedEves = currentClass.eves;
+
+ if definedEves ~= nil then
+ for k, v in pairs(definedEves) do
+ processEvent(k, v);
+ end;
+ end;
+
+ currentClass = currentClass.super;
+ end;
+
+ return eves;
+end;
+
+local function __copyPropTable(propName, prop)
+ local tbl = {name = propName, tipo = prop.tipo, values = prop.values, getter = prop.getter, setter = prop.setter};
+
+ if (prop.tipo == "obj") and (type(prop.class) == "table") then
+ tbl.refClassTagName = prop.class.tagName;
+ end;
+
+ return tbl;
+end;
+
+function lfm_enumProps(ctrlOrHandle)
+ local obj = lfm_getObject(ctrlOrHandle);
+
+ local props = {};
+ local qt = 0;
+ local alreadyListedProps = {};
+
+ local function processProp(propName, prop)
+ if not alreadyListedProps[propName] then
+ alreadyListedProps[propName] = true;
+ qt = qt + 1;
+ props[qt] = __copyPropTable(propName, prop);
+ end;
+ end;
+
+ -- Instance Defined Props
+ local definedProps = obj.props;
+
+ if definedProps ~= nil then
+ for k, v in pairs(definedProps) do
+ processProp(k, v);
+ end;
+ end;
+
+ -- Class Defined Props
+ local currentClass = rawget(obj, "class");
+
+ while currentClass ~= nil do
+ definedProps = currentClass.props;
+
+ if definedProps ~= nil then
+ for k, v in pairs(definedProps) do
+ processProp(k, v);
+ end;
+ end;
+
+ currentClass = currentClass.super;
+ end;
+
+ return props;
+end;
+
+function lfm_enumGridPropsForCompiler()
+ local gridClass = require("rrpgGUI_grid.dlua");
+
+ local props = {};
+ local qt = 0;
+ local alreadyListedProps = {};
+
+ local function processProp(propName, prop)
+ if not alreadyListedProps[propName] then
+ alreadyListedProps[propName] = true;
+ qt = qt + 1;
+ props[qt] = __copyPropTable(propName, prop);
+ end;
+ end;
+
+ -- Class Defined Props
+ local currentClass = gridClass;
+
+ while currentClass ~= nil do
+ definedProps = currentClass.props;
+
+ if definedProps ~= nil then
+ for k, v in pairs(definedProps) do
+ processProp(k, v);
+ end;
+ end;
+
+ currentClass = currentClass.super;
+ end;
+
+ return props;
+end;
+
+function lfm_enumGridEventsForCompiler()
+ local gridClass = require("rrpgGUI_grid.dlua");
+
+ local eves = {};
+ local qt = 0;
+ local alreadyListedEves = {};
+
+ local function processEvent(eventName, eventData)
+ if not alreadyListedEves[eventName] then
+ alreadyListedEves[eventName] = true;
+
+ local eveRec = {name = eventName};
+
+ if type(eventData) == "table" then
+ eveRec.parameters = eventData.arguments or "";
+ else
+ eveRec.parameters = eventData or "";
+ end;
+
+ qt = qt + 1;
+ eves[qt] = eveRec;
+ end;
+ end;
+
+ -- Class Defined Events
+ local currentClass = gridClass;
+
+ while currentClass ~= nil do
+ definedEves = currentClass.eves;
+
+ if definedEves ~= nil then
+ for k, v in pairs(definedEves) do
+ processEvent(k, v);
+ end;
+ end;
+
+ currentClass = currentClass.super;
+ end;
+
+ return eves;
+end;
+
+local function _getStrOfSetTable(value)
+ local ret = "";
+ local qt = 0;
+
+ for k, v in pairs(value) do
+ if qt == 0 then
+ ret = tostring(v);
+ else
+ ret = ret .. " " .. tostring(v);
+ end;
+
+ qt = qt + 1;
+ end;
+
+ return ret;
+end;
+
+function lfm_valueToStr(value, tipo, valuesOfTipo)
+ tipo = lowercase(tipo);
+
+ if tipo == "bool" then
+ if value then
+ return "true";
+ else
+ return "false";
+ end;
+ elseif (tipo == "int") then
+ return tostring(round(value));
+ elseif tipo == "double" then
+ return tostring(value);
+ elseif tipo == "enum" then
+ return tostring(value);
+ elseif (tipo == "string") or (tipo == "color") or (tipo == 'url') then
+ return value;
+ elseif tipo == "set" then
+ return _getStrOfSetTable(value, valuesOfTipo);
+ elseif (tipo == "bounds") or (tipo == "table") then
+
+ if serpent == nil then
+ serpent = require("serpent.dlua");
+ end;
+
+ return serpent.line(value, {comment = false});
+ else
+ return "";
+ end;
+end;
+
+function lfm_strToValue(value, tipo, valuesOfTipo)
+ tipo = lowercase(tipo);
+
+ if tipo == "bool" then
+ return value == "true";
+ elseif (tipo == "int") or (tipo =="double") then
+ return tonumber(value);
+ elseif (tipo == "string") or (tipo == "color") or (tipo == "url") then
+ return value;
+ elseif tipo == "enum" then
+ if isStrInTable(value, valuesOfTipo) then
+ return value;
+ else
+ return "";
+ end;
+ elseif tipo == "set" then
+
+ local objSet = {};
+
+ if type(value) == "string" then
+ for k, v in pairs(valuesOfTipo) do
+ if string.find(value, v) then
+ objSet[#objSet + 1] = v;
+ end;
+ end;
+ elseif type(value) == "table" then
+ objSet = value;
+ end;
+
+ return objSet;
+ elseif (tipo == "bounds") or (tipo == "table") then
+ f, e = load("return " .. value);
+ if e then error(e) end
+ return f();
+ else
+ return nil;
+ end;
+end;
+
+local function simplificarTable(t)
+ local ret = {};
+
+ for k, v in pairs(t) do
+ if isNumber(k) or (k == v) then
+ ret[#ret + 1] = v;
+ else
+ ret[k]=v;
+ end;
+ end;
+
+ return ret;
+end
+
+function lfm_valueToStrToUser(value, tipo, valuesOfTipo)
+ tipo = lowercase(tipo);
+
+ if tipo == "set" then
+ if serpent == nil then
+ serpent = require("serpent.dlua");
+ end;
+
+ return serpent.line(simplificarTable(value), {comment = false});
+ else
+ return lfm_valueToStr(value, tipo, valuesOfTipo);
+ end;
+end;
+
+function lfm_getPropAsString(ctrlOrHandle, propName)
+ local obj = lfm_getObject(ctrlOrHandle);
+ local props = obj.props;
+
+ if props == nil then
+ return nil;
+ end;
+
+ local prop = props[propName];
+
+ if prop == nil then
+ return nil;
+ end;
+
+ local getter = obj[prop.getter];
+ local v = getter(obj);
+
+ return lfm_valueToStr(v, prop.tipo, prop.values);
+end;
+
+function lfm_setPropAsString(ctrlOrHandle, propName, vAsStr)
+ local obj = lfm_getObject(ctrlOrHandle);
+ local prop;
+
+ if obj.findPropDef ~= nil then
+ prop = obj:findPropDef(propName);
+ end;
+
+ if prop == nil then
+ local props = obj.props;
+
+ if props ~= nil then
+ prop = props[propName];
+ end;
+ end;
+
+ if prop == nil then
+ return nil;
+ end;
+
+ v = lfm_strToValue(vAsStr, prop.tipo, prop.values);
+ obj[propName] = v;
+end;
+
+function lfm_getPropAsStringToUser(ctrlOrHandle, propName)
+ local obj = lfm_getObject(ctrlOrHandle);
+ local props = obj.props;
+
+ if props == nil then
+ return nil;
+ end;
+
+ local prop = props[propName];
+
+ if prop == nil then
+ return nil;
+ end;
+
+ local getter = obj[prop.getter];
+ local v = getter(obj);
+
+ return lfm_valueToStrToUser(v, prop.tipo, prop.values);
+end;
+
+
+function lfm_setParent(ctrlOrHandleFilho, ctrlOrHandlePai)
+ local objFilho = lfm_getObject(ctrlOrHandleFilho);
+ local objPai = lfm_getObject(ctrlOrHandlePai);
+ objFilho:setParent(objPai);
+end;
+
+local function walkHierarchyAndGetTagClassName(class)
+ local currentClass = class;
+
+ while type(currentClass) == "table" do
+ local tagName = rawget(currentClass, "tagName");
+
+ if type(tagName) == "string" then
+ return tagName;
+ end;
+
+ currentClass = currentClass.super;
+ end;
+
+ return nil;
+end;
+
+function lfm_enumerarClasses()
+ local ret = {};
+
+ for k, v in pairs(gui.guiClasses) do
+ local tagName = rawget(v, "tagName");
+
+ assert(k == tagName, string.format('k = %s, tagName = %s', k, tagName));
+ assert(ret[tagName] == nil, tagName);
+
+ local c = {name = tagName,
+ parentClassName = walkHierarchyAndGetTagClassName(v.super)};
+
+ ret[tagName] = c;
+ end;
+
+ return ret;
+end;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgObjs.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgObjs.lua
new file mode 100644
index 00000000..463da9cc
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgObjs.lua
@@ -0,0 +1,775 @@
+local Async = require("async.lua");
+
+objs = {}
+local localObjs = objs;
+
+rrpgObjs = objs;
+
+local weakHandlerMetatable = {
+ __mode = "v"
+}
+
+objs.weakMetatable = weakHandlerMetatable;
+
+local objHandlers = {};
+setmetatable(objHandlers, weakHandlerMetatable);
+
+objs.events = {};
+
+objs.events.eveIdToObject = {};
+setmetatable(objs.events.eveIdToObject, {__mode="v"});
+
+objs.events.eventsOfObjects = {};
+setmetatable(objs.events.eventsOfObjects, {__mode="k"});
+
+objs.events.idGenerator = 1;
+
+function objs.addEventListener(object, eventName, funcCallback)
+ local objectHandle;
+
+ if type(object) == 'table' then
+ objectHandle = object.handle;
+ else
+ objectHandle = nil;
+ end;
+
+ if type(funcCallback) ~= "function" then
+ error("Ops, a function is needed to listen an event");
+ end;
+
+ if (funcCallback == nil) or (objectHandle == nil) then
+ return 0;
+ end;
+
+ local eveItem = {};
+
+ eveItem.funcCallback = function(...)
+ return Async.execute(funcCallback, ...):unwrap();
+ end
+
+ local evesOfObject = localObjs.events.eventsOfObjects[object];
+
+ if evesOfObject == nil then
+ evesOfObject = {};
+ localObjs.events.eventsOfObjects[object] = evesOfObject;
+ end;
+
+ localObjs.events.idGenerator = localObjs.events.idGenerator + 1;
+ local esteEventId = localObjs.events.idGenerator;
+
+ evesOfObject[esteEventId] = eveItem;
+ localObjs.events.eveIdToObject[esteEventId] = object;
+
+ local eveDefFinder = object.findEventDef;
+ local eveDef;
+
+ if eveDefFinder ~= nil then
+ eveDef = eveDefFinder(object, eventName);
+ else
+ eveDef = nil;
+ end;
+
+ if (eveDef ~= nil) and (type(eveDef) == "table") and (type(eveDef.setter) == "function") then
+ eveItem.haveCustomSetter = true;
+ eveItem.setter = eveDef.setter;
+ eveDef.setter(object, eveItem.funcCallback);
+ else
+ _obj_listenEvent(objectHandle, eventName, esteEventId);
+ end;
+
+ return esteEventId;
+end;
+
+function objs.removeEventListenerById(eventId)
+ local obj = localObjs.events.eveIdToObject[eventId];
+
+ if obj == nil then
+ return;
+ end;
+
+ localObjs.events.eveIdToObject[eventId] = nil;
+
+ local evesOfObject = localObjs.events.eventsOfObjects[obj];
+
+ if evesOfObject == nil then
+ return;
+ end;
+
+ local eventItem = evesOfObject[eventId];
+
+ if eventItem == nil then
+ return;
+ end;
+
+ evesOfObject[eventId] = nil;
+
+ if eventItem.haveCustomSetter then
+ eventItem.setter(obj, nil);
+ else
+ _obj_stopListeningEvent(obj.handle, eventId);
+ end;
+end;
+
+--[[ Objeto TObject ]]--
+
+objs.class = {
+ _isClass = true,
+
+ initialize = function(obj)
+ end,
+
+ addEventListener = function (obj, eventName, funcCallback)
+ return localObjs.addEventListener(obj, eventName, funcCallback);
+ end,
+
+ removeEventListener = function (obj, eventListenerId)
+ return localObjs.removeEventListenerById(eventListenerId);
+ end,
+
+ removeAllEventListeners = function(obj)
+ if (obj.handle == nil) then
+ return;
+ end;
+
+ local eventsOfThis = localObjs.events.eventsOfObjects[obj];
+
+ if (eventsOfThis ~= nil) then
+ local eventsIds = {};
+ local idx = 1;
+
+ for k, v in pairs(eventsOfThis) do
+ eventsIds[idx] = k;
+ idx = idx + 1;
+ end;
+
+ for i = 1, idx - 1, 1 do
+ localObjs.removeEventListenerById(eventsIds[i]);
+ end;
+
+ localObjs.events.eventsOfObjects[obj] = nil;
+ end;
+ end,
+
+ destroy = function(obj)
+ if not obj._calledDestroy then
+ obj._calledDestroy = true;
+
+ if obj.handle ~= nil then
+ if (obj.removeAllEventListeners ~= nil) then
+ obj:removeAllEventListeners();
+ end;
+
+ if objHandlers[obj.handle] == obj then
+ objHandlers[obj.handle] = nil;
+ end;
+
+ _obj_destruir(obj.handle);
+ obj.handle = nil;
+ end;
+ end;
+ end,
+
+ getClassName = function(obj)
+ if obj.handle ~= nil then
+ return _obj_getClassName(obj.handle);
+ else
+ return "";
+ end;
+ end,
+
+ findPropDef = function(obj, propName)
+ -- Instance property
+ local props = rawget(obj, "props");
+
+ if props ~= nil then
+ local propKey = props[propName];
+
+ if propKey ~= nil then
+ return propKey;
+ end;
+ end;
+
+ -- Class property
+ local currentClass = rawget(obj, "class");
+
+ while currentClass ~= nil do
+ props = rawget(currentClass, "props");
+
+ if props ~= nil then
+ local propKey = props[propName];
+
+ if propKey ~= nil then
+ return propKey;
+ end;
+ end;
+
+ currentClass = rawget(currentClass, "super");
+ end;
+
+ return nil;
+ end,
+
+ findEventDef = function(obj, eventName)
+ -- Instance event
+ local eves = rawget(obj, "eves");
+
+ if eves ~= nil then
+ local eveKey = eves[eventName];
+
+ if eveKey ~= nil then
+ return eveKey;
+ end;
+ end;
+
+ -- Class event
+ local currentClass = rawget(obj, "class");
+
+ while currentClass ~= nil do
+ eves = rawget(currentClass, "eves");
+
+ if eves ~= nil then
+ local eveKey = eves[eventName];
+
+ if eveKey ~= nil then
+ return eveKey;
+ end;
+ end;
+
+ currentClass = rawget(currentClass, "super");
+ end;
+
+ return nil;
+ end
+};
+
+objs.class.listen = objs.class.addEventListener;
+objs.class.unlisten = objs.class.removeEventListener;
+
+local function __readPropertyValue(instance, propKey)
+ local fgetter;
+
+ if type(propKey.getter) == "function" then
+ fgetter = propKey.getter;
+ else
+ fgetter = instance[propKey.getter];
+ end;
+
+ if fgetter ~= nil then
+ return fgetter(instance);
+ elseif propKey.readProp ~= nil then
+ return _obj_getProp(rawget(instance, 'handle'), propKey.readProp);
+ end;
+end;
+
+local function __tryIndexObjWithDefinition(definition, instance, key)
+ -- Raw Value
+ local v = rawget(definition, key);
+
+ if (v ~= nil) then
+ return true, v;
+ end;
+
+ -- Property
+ local props = rawget(definition, "props");
+
+ if props ~= nil then
+ local propKey = props[key];
+
+ if propKey ~= nil then
+ return true, __readPropertyValue(instance, propKey);
+ end;
+ end;
+
+ -- Event
+ local eves = rawget(definition, "eves");
+
+ if eves ~= nil then
+ local eveKey = eves[key];
+
+ if eveKey ~= nil then
+ -- Existe um evento com este nome.. Vamos retornar o evento principal associado, se existir.
+ local mainEves = rawget(instance, "__mainEves");
+
+ if mainEves ~= nil then
+ return true, mainEves[key];
+ end;
+ end;
+ end;
+
+ -- Custom object __objindex method
+ local objIndexMethod = rawget(definition, "__objindex");
+
+ if (objIndexMethod ~= nil) and (type(objIndexMethod) == "function") then
+ return objIndexMethod(instance, key);
+ else
+ return false;
+ end;
+end;
+
+local function __tryNewIndexObjWithDefinition(definition, instance, key, value)
+ -- Tentar setar uma propriedade
+ local fsetter = nil;
+ local props = rawget(definition, "props");
+
+ if props ~= nil then
+ local propKey = props[key];
+
+ if propKey ~= nil then
+ if type(propKey.setter) == "function" then
+ fsetter = propKey.setter;
+ else
+ fsetter = instance[propKey.setter];
+ end;
+
+ if (fsetter == nil) and (propKey.writeProp ~= nil) then
+ _obj_setProp(rawget(instance, 'handle'), propKey.writeProp, value);
+ return true;
+ end;
+ end;
+ end;
+
+ if fsetter ~= nil then
+ fsetter(instance, value);
+ return true;
+ end;
+
+ -- Tentar setar um evento
+ local eves = rawget(definition, "eves");
+
+ if eves ~= nil then
+ local eveKey = eves[key];
+
+ if eveKey ~= nil then
+ -- Existe um evento com este nome.. Vamos setar o evento principal associado, se existir.
+ local mainEves = rawget(instance, "__mainEves");
+
+ if (mainEves == nil) then
+ mainEves = {};
+ rawset(instance, "__mainEves", mainEves)
+ end;
+
+ local oldListenerId = mainEves["id_" .. key];
+
+ if oldListenerId ~= nil then
+ objs.removeEventListenerById(oldListenerId);
+ mainEves["id_" .. key] = nil;
+ end;
+
+ mainEves[key] = value;
+
+ if value ~= nil then
+ mainEves[key] = value;
+ mainEves["id_" .. key] = objs.addEventListener(instance, key, value);
+ end;
+
+ return true;
+ end;
+ end;
+
+ -- Custom object __objnewindex method
+ local objNewIndexMethod = rawget(definition, "__objnewindex");
+
+ if (objNewIndexMethod ~= nil) and (type(objNewIndexMethod) == "function") then
+ return objNewIndexMethod(instance, key, value);
+ else
+ -- Could not newindex object with supplied definition
+ return false;
+ end;
+end;
+
+local objectMetaTable = {
+ --[[ Comparação padrão entre objetos ]]--
+ __eq = function(op1, op2)
+ if op1.handle ~= nil then
+ if op2.handle ~= nil then
+ return op1.handle == op2.handle;
+ else
+ return false;
+ end;
+ else
+ if op2.handle ~= nil then
+ return false;
+ else
+ return op1 == op2;
+ end;
+ end;
+ end,
+
+ --[[ getter padrão de propriedades dos objetos. Chamado quando tentar gettar uma propriedade que não existe ]]--
+
+ __index = function(table, key)
+ local r, v;
+
+ r, v = __tryIndexObjWithDefinition(table, table, key);
+
+ if r then
+ return v;
+ end;
+
+ -- Verificar classes
+ local currentClass = rawget(table, "class");
+
+ while currentClass ~= nil do
+ r, v = __tryIndexObjWithDefinition(currentClass, table, key);
+
+ if r then
+ return v;
+ end;
+
+ currentClass = rawget(currentClass, "super");
+ end;
+
+ -- Se chegou até aqui, é porque não localizou nenhum valor especial
+ return nil;
+ end,
+
+ --[[ setter padrão de propriedades dos objetos. Chamado quando tentou settar uma propriedade que não existe ]]--
+
+ __newindex = function(table, key, value)
+ local r;
+ r = __tryNewIndexObjWithDefinition(table, table, key, value);
+
+ if r then
+ return;
+ end;
+
+ -- Verificar classes
+ local currentClass = rawget(table, "class");
+
+ while currentClass ~= nil do
+ r = __tryNewIndexObjWithDefinition(currentClass, table, key, value);
+
+ if r then
+ return;
+ end;
+
+ currentClass = rawget(currentClass, "super");
+ end;
+
+ -- Se chegou até aqui, é porque não conseguiu fazer nenhuma atribuição especial.
+ -- Vamos fazer uma atribuição padrão
+ rawset(table, key, value);
+ end,
+
+ __gc = function(obj)
+ if obj.destroy ~= nil then
+ obj:destroy();
+ end;
+
+ if obj.handle ~= nil then
+ _obj_destruir(obj.handle);
+ obj.handle = nil;
+ end;
+ end
+};
+
+local classMetatable = {
+ __index = function(classTable, key)
+ if (key == "eves") or (key == "props") then
+ return rawget(classTable, key);
+ end;
+
+ local currentClass = classTable;
+
+ while currentClass ~= nil do
+ local v = rawget(currentClass, key);
+
+ if v ~= nil then
+ return v;
+ end;
+
+ currentClass = rawget(currentClass, "super");
+ end;
+
+ -- Se chegou até aqui, é porque não localizou nenhum valor especial
+ return nil;
+ end,
+
+ __newindex = function(classTable, key, value)
+ rawset(classTable, key, value);
+ end;
+};
+
+function objs.objectFromHandle(handle)
+ local obj = {handle=handle,
+ class=objs.class};
+
+ setmetatable(obj, objectMetaTable);
+ objs.registerHandleIfNeeded(handle, obj);
+ return obj;
+end
+
+function objs.newPureLuaObject()
+ return objs.objectFromHandle(nil);
+end;
+
+function objs.__recursiveRunInitialize(obj, class)
+ local superClass = class.super;
+
+ if superClass ~= nil then
+ objs.__recursiveRunInitialize(obj, superClass);
+ end;
+
+ local initialize = rawget(class, "initialize");
+
+ if initialize ~= nil then
+ initialize(obj);
+ end;
+end;
+
+function objs.__createSubclass(superClass)
+ assert(superClass ~= nil);
+ local class = {super = superClass, props = {}, eves = {}, _isClass = true};
+
+ class.new = function()
+ local obj = {class=class};
+ setmetatable(obj, objectMetaTable);
+ objs.__recursiveRunInitialize(obj, class);
+ return obj;
+ end;
+
+ class.fromHandle = function(handle)
+ local obj = {handle=handle, class=class};
+ setmetatable(obj, objectMetaTable);
+ objs.registerHandleIfNeeded(handle, obj);
+ objs.__recursiveRunInitialize(obj, class);
+ return obj;
+ end;
+
+ class.inherit = function() return objs.__createSubclass(class); end;
+ setmetatable(class, classMetatable);
+ return class;
+end;
+
+function objs.newClass()
+ return objs.__createSubclass(objs.class);
+end;
+
+objs.inherit = objs.newClass;
+
+-- ## Component Class
+
+objs.Component = objs.newClass();
+
+function objs.Component:initialize()
+ rawset(self, "props", {});
+ rawset(self, "eves", {});
+end;
+
+function objs.Component:getName() return _obj_getProp(self.handle, "Name"); end;
+function objs.Component:setName(name) _obj_setProp(self.handle, "Name", name); end;
+
+objs.Component.props["name"] = {setter = "setName", getter = "getName", tipo = "string"};
+
+function objs.componentFromHandle(handle)
+ local obj = objs.Component.fromHandle(handle);
+ return obj;
+end;
+
+-- ## HierarchyObject Class
+
+objs.HierarchyObject = objs.Component.inherit();
+
+function objs.HierarchyObject:initialize()
+ rawset(self, "_children", {});
+end;
+
+function objs.HierarchyObject.getChildren(instance)
+ local ret = {};
+ local idxDest = 1;
+
+ for k, v in pairs(instance._children) do
+ ret[idxDest] = v;
+ idxDest = idxDest + 1;
+ end;
+
+ return ret;
+end;
+
+function objs.HierarchyObject.findChildByName(instance, childName, recursive, superficialSearch)
+ recursive = recursive or true;
+ local child;
+
+ child = instance[childName];
+
+ if type(child) == "table" and (child.handle ~= nil) and (child.getName ~= nil) and (child:getName() == childName) then
+ return child;
+ end;
+
+ if superficialSearch then
+ return nil;
+ end;
+
+ local childs = instance:getChildren();
+
+ for i = 1, #childs, 1 do
+ child = childs[i];
+
+ if child.getName ~= nil then
+
+ if child:getName() == childName then
+ return child;
+ end;
+ end;
+ end;
+
+ if recursive then
+ local retChild;
+
+ for i = 1, #childs, 1 do
+ child = childs[i];
+ retChild = child:findChildByName(childName, recursive);
+
+ if retChild ~= nil then
+ return retChild;
+ end;
+ end;
+ end;
+
+ return nil;
+end;
+
+function objs.HierarchyObject.getParent(instance)
+ return GUI.fromHandle(_gui_getParent(instance.handle))
+end;
+
+function objs.HierarchyObject.setParent(instance, parent)
+ if (instance._parent == parent) then
+ return;
+ end;
+
+ if (instance._parent ~= nil) then
+ instance._parent._children[instance.handle] = nil;
+ end
+
+ instance._parent = parent;
+
+ if (instance._parent ~= nil) then
+ _gui_setParent(instance.handle, parent.handle);
+ instance._parent._children[instance.handle] = instance;
+ else
+ _gui_setParent(instance.handle, nil);
+ end;
+end;
+
+objs.HierarchyObject.__oldDestroyHierarchyObject = objs.HierarchyObject.destroy;
+
+function objs.HierarchyObject.destroy(instance)
+ instance:removeAllEventListeners();
+
+ if instance._children ~= nil then
+ for k, v in pairs(instance._children) do
+ if v ~= nil then
+ v:setParent(nil);
+ end;
+ end;
+
+ instance._children = {};
+ end;
+
+ if (instance._parent ~= nil) then
+
+ if (instance._parent._children ~= nil) and (instance.handle ~= nil) then
+ instance._parent._children[instance.handle] = nil;
+ end;
+
+ instance._parent = nil;
+ end;
+
+ objs.HierarchyObject.__oldDestroyHierarchyObject(instance);
+end;
+
+function objs.hierarchyObjectFromHandle(handle)
+ local obj = objs.HierarchyObject.fromHandle(handle);
+ return obj;
+end;
+
+-- ## Timer Class
+
+objs.Timer = objs.HierarchyObject.inherit();
+
+function objs.Timer:getInterval() return _obj_getProp(self.handle, "Interval") end;
+function objs.Timer:setInterval(v) _obj_setProp(self.handle, "Interval", v) end;
+function objs.Timer:getEnabled() return _obj_getProp(self.handle, "Enabled") end;
+function objs.Timer:setEnabled(v) _obj_setProp(self.handle, "Enabled", v) end;
+function objs.Timer:beginUpdate() end;
+function objs.Timer:endUpdate() end;
+
+objs.Timer.props["interval"] = {setter = "setInterval", getter = "getInterval", tipo = "int"};
+objs.Timer.props["enabled"] = {setter = "setEnabled", getter = "getEnabled", tipo = "bool"};
+
+objs.Timer.eves["onTimer"] = "";
+
+function objs.__timerFromHandle(handle)
+ local timer = objs.Timer.fromHandle(handle);
+ return timer;
+end;
+
+function objs.newTimer(interval, callback)
+ local timer = objs.__timerFromHandle(_obj_newObject("timer"));
+
+ interval = tonumber(interval);
+
+ if (type(interval) ~= "number") or (interval < 1) then
+ interval = 1;
+ end;
+
+ timer:setInterval(interval);
+
+ if type(callback) == "function" then
+ timer:addEventListener("onTimer", callback);
+ end;
+
+ timer:setEnabled(true);
+ return timer;
+end;
+
+function objs.beginObjectsLoading()
+ _obj_beginObjectsLoading();
+end;
+
+function objs.endObjectsLoading()
+ _obj_endObjectsLoading();
+end;
+
+function objs.tryFindFromHandle(handle)
+ return objHandlers[handle];
+end;
+
+function objs.registerHandle(handle, object)
+ objHandlers[handle] = object;
+end;
+
+function objs.registerHandleIfNeeded(handle, object)
+ if objHandlers[handle] == nil then
+ objHandlers[handle] = object;
+ end;
+end
+
+function _rrpgObjs_events_receiver(eventId, ...)
+ local obj = localObjs.events.eveIdToObject[eventId];
+
+ if obj == nil then
+ return;
+ end;
+
+ local evesOfObject = localObjs.events.eventsOfObjects[obj];
+
+ if evesOfObject == nil then
+ return;
+ end;
+
+ local eventItem = evesOfObject[eventId];
+
+ if eventItem == nil then
+ return;
+ end;
+
+ return eventItem.funcCallback(...);
+end;
+
+function __EXPORT__objs_tryFindFromHandle(handle)
+ return objs.tryFindFromHandle(handle);
+end;
+
+return localObjs;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgRequests.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgRequests.lua
new file mode 100644
index 00000000..d01ba98a
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgRequests.lua
@@ -0,0 +1,83 @@
+local rrpg = require("rrpg.lua");
+local rrpgObjs = require("rrpgObjs.lua");
+require("rrpgUtil");
+local messaging = rrpg.messaging;
+
+local requests = rrpgObjs.objectFromHandle(_obj_newObject("TRRPGLuaRequests"));
+rrpgObjs.registerHandle(requests.handle, requests);
+
+local sessionLostMessage = "A conexão com o servidor foi perdida";
+
+local function execCallback(callbackFunction, ...)
+ if type(callbackFunction) == "function" then
+ setTimeout(
+ function(...)
+ callbackFunction(...);
+ end, 50, ...);
+ end;
+end;
+
+function requests.criarItensNaBiblioteca(mesa, itens, successCallback, failureCallback)
+ local pacote = itens;
+
+ if mesa == nil then
+ error("Parâmetro mesa não informado");
+ end;
+
+ if #itens == 0 then
+ execCallback(failureCallback, "Não foi especificado itens para a criação");
+ return;
+ end;
+
+ for i = 1, #itens, 1 do
+ local it = itens[i];
+
+ if (type(it.itemPai) == "table") then
+ it.itemPai = it.itemPai.codigoInterno;
+ end;
+
+ if type(it.dono) == "table" then
+ it.dono = it.dono.codigoInterno;
+ end;
+ end;
+
+ if type(mesa) == "table" then
+ mesa = mesa.codigoInterno;
+ end;
+
+ local r, r2 = _obj_invokeEx(requests.handle, "ExCriarItensNaBiblioteca", mesa, pacote);
+
+ if r then
+ local l1 = messaging.listenOnce("ServerResponse_CriarItemBiblioteca",
+ function(msg)
+ if msg.r then
+ execCallback(successCallback);
+ else
+ execCallback(failureCallback, msg.msg);
+ end;
+ end, {requestId=r2});
+
+ local l2 = messaging.listenOnce("SessionLost",
+ function()
+ execCallback(failureCallback, sessionLostMessage);
+ end);
+
+ messaging.groupOnceListeners(l1, l2);
+ else
+ execCallback(failureCallback, r2);
+ end;
+end;
+
+function requests.criarPersonagem(itemPai, nome, dataType, visivelATodos, dono, successCallback, failureCallback)
+
+ if itemPai == nil then
+ error("Parâmetro itemPai não informado");
+ end;
+
+ local itens = {{tipoItem="personagem", itemPai=itemPai, nome=nome, sistema=dataType, dono=dono, visivel=visivelATodos}};
+ return requests.criarItensNaBiblioteca(itemPai.mesa, itens, successCallback, failureCallback);
+end;
+
+rrpg.requests = requests;
+rrpg.Requests = requests;
+return requests;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgSharedObjects.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgSharedObjects.lua
new file mode 100644
index 00000000..f6f6b1d0
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgSharedObjects.lua
@@ -0,0 +1,149 @@
+local SharedObjects = {};
+local registeredUnpackers = {};
+
+local __SHAREDOBJ_PREFIX = "##RRPGshObj(";
+local __SHAREDOBJ_SUFIX = ")##";
+local __MATCH_SHARED_OBJ = "##RRPGshObj%((.+)%)##"
+local __MATCH_SHARED_OBJ_NOCAPTURE = "##RRPGshObj%([^%(%)#]+%)##"
+
+local __SHAREDARRAYOBJ_PREFIX = "@@RRPGshObjArray(";
+local __SHAREDARRAYOBJ_SUFIX = ")@@";
+local __SHAREDARRAYOBJ_SEP = ",";
+local __MATCH_SHARED_ARRAYOBJ = "@@RRPGshObjArray%((.+)%)@@"
+
+local function sidToString(sid)
+ if type(sid) == "table" then
+ if sid.extra ~= nil then
+ return _internet_HTTPEncode(sid.objectType) .. "\\" ..
+ _internet_HTTPEncode(sid.objectID) .. "\\" ..
+ _internet_HTTPEncode(sid.extra);
+ else
+ return _internet_HTTPEncode(sid.objectType) .. "\\" ..
+ _internet_HTTPEncode(sid.objectID);
+ end;
+ else
+ return "";
+ end;
+end;
+
+local __strToSidOrder = {"objectType", "objectID", "extra"}
+
+local function stringToSid(str)
+ local sid = {};
+
+ if str ~= nil and type(str) == "string" then
+ local ordem = 1;
+
+ for t in string.gmatch(str, "[^\\]+") do
+ local k = __strToSidOrder[ordem];
+
+ if k ~= nil then
+ sid[k] = _internet_HTTPDecode(t);
+ end;
+
+ ordem = ordem + 1;
+ end;
+ end;
+
+ sid.objectType = sid.objectType or "";
+ sid.objectID = sid.objectID or "";
+ return sid;
+end;
+
+function SharedObjects.tryPack(tabela)
+ if type(tabela) ~= "table" then
+ return false;
+ end;
+
+ local h = rawget(tabela, "handle");
+
+ if h ~= nil then
+ local so = nil;
+ local fnGetShareObjectID = rawget(tabela, "getShareID");
+
+ if (fnGetShareObjectID ~= nil) and (type(fnGetShareObjectID) == "function") then
+ local sid = fnGetShareObjectID(tabela);
+ so = __SHAREDOBJ_PREFIX .. sidToString(sid) .. __SHAREDOBJ_SUFIX;
+ end;
+
+ return true, so;
+ else
+ local qtNaTabela = #tabela;
+
+ if qtNaTabela > 0 then
+ -- Pode ser um array....
+ local bStr = __SHAREDARRAYOBJ_PREFIX;
+ local qtPacked = 0;
+
+ for i = 1, #tabela, 1 do
+ local xR, xStr = SharedObjects.tryPack(tabela[i]);
+
+ if xR then
+ if qtPacked > 0 then
+ bStr = bStr .. __SHAREDARRAYOBJ_SEP;
+ end;
+
+ bStr = bStr .. xStr;
+ qtPacked = qtPacked + 1;
+ end;
+ end;
+
+ if qtPacked > 0 then
+ return true, bStr .. __SHAREDARRAYOBJ_SUFIX;
+ else
+ return false;
+ end
+ else
+ return false;
+ end
+ end;
+end;
+
+function SharedObjects.tryUnpack(str)
+ if str == nil then
+ return false;
+ end;
+
+ local arrayContent = string.match(str, __MATCH_SHARED_ARRAYOBJ);
+
+ if arrayContent ~= nil then
+ -- Um array de objetos
+ local tabela = {};
+
+ for sObj in string.gmatch(arrayContent, __MATCH_SHARED_OBJ_NOCAPTURE) do
+ local xR, xObj = SharedObjects.tryUnpack(sObj);
+
+ if xR then
+ tabela[#tabela + 1] = xObj;
+ end;
+ end;
+
+ if #tabela > 0 then
+ return true, tabela;
+ else
+ return false;
+ end;
+ else
+ local strSid = string.match(str, __MATCH_SHARED_OBJ);
+
+ if strSid ~= nil then
+ local sid = stringToSid(strSid);
+ local unpacker = registeredUnpackers[sid.objectType];
+
+ if unpacker ~= nil then
+ local so = unpacker(sid);
+ return true, so;
+ else
+ return false;
+ end;
+ else
+ return false;
+ end;
+ end;
+end;
+
+function SharedObjects.registerUnpacker(objectType, unpackerCallback)
+ registeredUnpackers[objectType] = unpackerCallback;
+end;
+
+return SharedObjects;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgUtil.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgUtil.lua
new file mode 100644
index 00000000..225c3835
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgUtil.lua
@@ -0,0 +1,485 @@
+local rrpgObjs = require("rrpgObjs.lua");
+utils = {};
+Utils = utils;
+
+function lowercase(s)
+ return string.lower(s);
+end;
+
+function uppercase(s)
+ return string.upper(s);
+end;
+
+function isNumber(v)
+ return type(v) == "number";
+end;
+
+function isnumber(v)
+ return type(v) == "number";
+end;
+
+function floor(v)
+ return math.floor(v);
+end;
+
+function round(v)
+ return floor(v + 0.5);
+end;
+
+function utils.tryFinally(tryCallback, finallyCallback)
+ return _util_tryFinally(tryCallback, finallyCallback);
+end;
+
+tryFinally = utils.tryFinally;
+
+function isStrInTable(s, table)
+ for k, v in ipairs(table) do
+ if (k == s) or (v == s) then
+ return true;
+ end;
+ end;
+
+ return false;
+end;
+
+function removerAcentos(str)
+ return utils.removerAcentos(str);
+end;
+
+
+function strToTable(str)
+ return totable(str);
+end;
+
+function tableToStr(tabela, pretty)
+ local serpent = require("serpent.dlua");
+
+ if pretty then
+ return serpent.block(tabela, {comment=false});
+ else
+ return serpent.line(tabela, {comment=false});
+ end;
+end;
+
+utils.tableToStr = tableToStr;
+utils.strToTable = strToTable;
+
+function utils.removerAcentos(str)
+ return _util_removerAcentos(str);
+end;
+
+function utils.removerFmtChat(str, removerSmileys)
+ if removerSmileys == nil then
+ removerSmileys = false;
+ end;
+
+ return _util_removerTagsDeFormatacaoDeChat(str, not (not removerSmileys));
+end;
+
+function utils.compareStringPtBr(strLeft, strRight)
+ return _util_compareStringsPtBr(strLeft, strRight);
+end;
+
+function utils.sortPtBrArray(array)
+ table.sort(array, function(l, r) return utils.compareStringPtBr(l, r) < 0; end);
+end;
+
+local __settedTimers = {};
+local __timersGeneratorId = 1;
+
+local function __unsetupTemporizador(timerId, temporizador)
+ if temporizador == nil then
+ temporizador = __settedTimers[timerId];
+ end;
+
+ __settedTimers[timerId] = nil;
+
+ if (temporizador ~= nil) and (temporizador.timer ~= nil) then
+ local timer = temporizador.timer;
+ timer.enabled = false;
+ temporizador.callback = nil;
+ temporizador.parametros = nil;
+ temporizador.timer = nil; -- liberar para o garbage collector
+ end;
+end;
+
+local function __setupTemporizador(callback, interval, isInterval, ...)
+ if (type(callback) ~= "function") or (type(interval) ~= "number") then
+ return nil;
+ end;
+
+ if interval < 1 then
+ interval = 1;
+ end;
+
+ __timersGeneratorId = __timersGeneratorId + 1;
+
+ local temporizador = {};
+ local timer = rrpgObjs.newTimer();
+ local timerId = __timersGeneratorId;
+
+
+ temporizador.id = timerId;
+ temporizador.timer = timer;
+ temporizador.interval = interval;
+ temporizador.isInterval = isInterval;
+ temporizador.callback = callback;
+ temporizador.parametros = table.pack(...);
+
+ temporizador.onTimerEventListenerId = timer:addEventListener("onTimer",
+ function ()
+ local callbackFunction = temporizador.callback;
+ local parametros = temporizador.parametros;
+
+ if not temporizador.isInterval then
+ __unsetupTemporizador(timerId, temporizador);
+ end;
+
+ local ret;
+
+ if callbackFunction ~= nil then
+ if parametros ~= nil then
+ ret = callbackFunction(table.unpack(parametros));
+ else
+ ret = callbackFunction();
+ end;
+ else
+ ret = false;
+ end;
+
+ if temporizador.isInterval and (ret == false) then
+ __unsetupTemporizador(timerId, temporizador);
+ end;
+ end);
+
+ __settedTimers[timerId] = temporizador;
+ timer.interval = interval;
+ timer.enabled = true;
+ return timerId;
+end;
+
+function utils.setTimeout(callback, interval, ...)
+ interval = tonumber(interval);
+
+ if (interval == nil) or (interval <= 0) then
+ callback(...);
+ return nil;
+ else
+ return __setupTemporizador(callback, interval, false, ...);
+ end;
+end;
+
+function utils.setInterval(callback, interval, ...)
+ return __setupTemporizador(callback, interval, true, ...);
+end;
+
+function utils.clearInterval(intervalId)
+ return __unsetupTemporizador(intervalId);
+end;
+
+function utils.clearTimeout(timeoutId)
+ return __unsetupTemporizador(timeoutId);
+end;
+
+function setTimeout(callback, interval, ...)
+ return utils.setTimeout(callback, interval, ...);
+end;
+
+function setInterval(callback, interval, ...)
+ return utils.setInterval(callback, interval, ...);
+end;
+
+function clearInterval(intervalId)
+ return utils.clearInterval(intervalId);
+end;
+
+function clearTimeout(timeoutId)
+ return utils.clearTimeout(timeoutId);
+end;
+
+function utils.binaryEncode(destArray, format, value, startIndex)
+ if type(destArray) ~= "table" then
+ return;
+ end;
+
+ if type(startIndex) ~= "number" then
+ startIndex = 1;
+ end;
+
+ return _util_binaryEncode(destArray, format, value, startIndex);
+end;
+
+function utils.binaryDecode(sourceArray, format, startIndex, length)
+ if type(sourceArray) ~= "table" then
+ return nil;
+ end;
+
+ if type(startIndex) ~= "number" then
+ startIndex = 1;
+ end;
+
+ if type(length) ~= "number" then
+ length = #sourceArray - startIndex + 1;
+ end;
+
+ return _util_binaryDecode(sourceArray, format, startIndex, length);
+end;
+
+function utils.getBinarySize(format)
+ return _util_getBinarySize(format);
+end;
+
+local __streamProps = nil;
+
+function utils.streamFromHandle(handle)
+ local stream = rrpgObjs.tryFindFromHandle(handle);
+
+ if stream ~= nil then
+ return stream;
+ end;
+
+ stream = rrpgObjs.objectFromHandle(handle);
+
+ function stream:getSize() return _obj_getProp(self.handle, "Size"); end;
+ function stream:setSize(v) _obj_setProp(self.handle, "Size", v); end;
+
+ function stream:getPosition() return _obj_getProp(self.handle, "Position"); end;
+ function stream:setPosition(v) _obj_setProp(self.handle, "Position", v); end;
+
+ function stream:read(destArray, qtBytes) return _obj_invokeEx(self.handle, "ReadBytes", destArray, qtBytes); end;
+ function stream:write(sourceArray, qtBytes) return _obj_invokeEx(self.handle, "WriteBytes", sourceArray, qtBytes); end;
+
+ function stream:getRemainingBytes()
+ local r = self.size - self.position;
+
+ if r < 0 then
+ return 0;
+ else
+ return r;
+ end;
+ end;
+
+ function stream:close() _obj_invoke(self.handle, "Close"); end;
+
+ function stream:writeBinary(format, ...)
+ local qt = select("#", ...);
+ local qtBytesEscrito = 0;
+ local binario = {};
+
+ for i = 1, qt, 1 do
+ local v = select(i, ...);
+ local qtBytesEste = utils.binaryEncode(binario, format, v);
+ local qtEscritoNeste = self:write(binario, qtBytesEste);
+ qtBytesEscrito = qtBytesEscrito + qtEscritoNeste;
+
+ if qtEscritoNeste < qtBytesEste then
+ return qtBytesEscrito;
+ end;
+ end;
+
+ return qtBytesEscrito;
+ end;
+
+ function stream:readBinary(format, qt)
+ local qtBytesPorItem = utils.getBinarySize(format);
+ local qtBytesALer;
+
+ if type(qt) ~= "number" then
+ qt = 1;
+ end;
+
+ if qt <= 0 then
+ return;
+ end;
+
+ if qtBytesPorItem < 0 then
+ -- tamanho variável.
+ qtBytesALer = self.remainingBytes;
+ else
+ qtBytesALer = qt * qtBytesPorItem;
+ end;
+
+ local bts = {};
+ local bytesLido = self:read(bts, qtBytesALer);
+
+ if (qt == 1) or (qtBytesPorItem <= 0) then
+ return utils.binaryDecode(bts, format, 1, bytesLido);
+ else
+ local retornos = {};
+ local currentIndex = 1;
+
+ for i = 1, qt, 1 do
+ local retValue, bytesUsados = utils.binaryDecode(bts, format, currentIndex, qtBytesPorItem);
+ retornos[i] = retValue;
+ currentIndex = currentIndex + bytesUsados;
+ end;
+
+ return table.unpack(retornos);
+ end;
+ end;
+
+ function stream:readAsBase64(qtBytes)
+ if qtBytes == nil then
+ qtBytes = self.remainingBytes;
+ else
+ qtBytes = tonumber(qtBytes);
+
+ if qtBytes < 0 then
+ qtBytes = 0;
+ elseif qtBytes > self.remainingBytes then
+ qtBytes = self.remainingBytes;
+ end;
+ end;
+
+ return _obj_invoke(self.handle, "ReadAsBase64", qtBytes);
+ end;
+
+ function stream:writeBase64(str)
+ if str == nil or str == "" then
+ return 0;
+ end;
+
+ return _obj_invoke(self.handle, "WriteBase64", tostring(str));
+ end;
+
+ function stream:copyFrom(sourceStream, qtBytes)
+ qtBytes = tonumber(qtBytes);
+
+ if (type(sourceStream) ~= "table") or (sourceStream.handle == nil) or (qtBytes == nil) or (qtBytes <= 0) then
+ return 0;
+ end;
+
+ return _obj_invokeEx(self.handle, "CopyFrom", sourceStream.handle, qtBytes);
+ end;
+
+ function stream:share() return _obj_invoke(self.handle, "ShareStream"); end;
+
+ function stream:getMD5() return _obj_invoke(self.handle, "CalculateMD5"); end;
+ function stream:getSHA1() return _obj_invoke(self.handle, "CalculateSHA1"); end;
+
+ if __streamProps == nil then
+ __streamProps = stream.props or {};
+ __streamProps["size"] = {setter = "setSize", getter = "getSize", tipo = "int"};
+ __streamProps["position"] = {setter = "setPosition", getter = "getPosition", tipo = "int"};
+ __streamProps["remainingBytes"] = {getter = "getRemainingBytes", tipo = "int"};
+ __streamProps["md5"] = {getter = "getMD5", tipo = "string"};
+ __streamProps["sha1"] = {getter = "getSHA1", tipo = "string"};
+ end;
+
+ stream.props = __streamProps;
+
+ rrpgObjs.registerHandle(handle, stream);
+ return stream;
+end;
+
+string.upper = function(str)
+ return _util_upperCase(str);
+end;
+
+string.lower = function(str)
+ return _util_lowerCase(str);
+end;
+
+function utils.zlibCompress(sourceStream, destStream, level, qtBytesInSource)
+ if level ~= "none" and level ~= "fastest" and level ~= "default" and level ~= "max" then
+ level = "default";
+ end;
+
+ if qtBytesInSource == nil then
+ qtBytesInSource = sourceStream.remainingBytes;
+ else
+ qtBytesInSource = tonumber(qtBytesInSource);
+
+ if qtBytesInSource < 0 then
+ qtBytesInSource = 0;
+ elseif qtBytesInSource > sourceStream.remainingBytes then
+ qtBytesInSource = sourceStream.remainingBytes;
+ end;
+ end;
+
+ return _util_zlibCompress(sourceStream.handle, destStream.handle, level, qtBytesInSource);
+end;
+
+function utils.zlibDecompress(sourceStream, destStream)
+ return _util_zlibDecompress(sourceStream.handle, destStream.handle);
+end;
+
+function utils.zlibCompressAsync(sourceStream, destStream, level, qtBytesInSource, onFinish, onError)
+ if level ~= "none" and level ~= "fastest" and level ~= "default" and level ~= "max" then
+ level = "default";
+ end;
+
+ if qtBytesInSource == nil then
+ qtBytesInSource = sourceStream.remainingBytes;
+ else
+ qtBytesInSource = tonumber(qtBytesInSource);
+
+ if qtBytesInSource < 0 then
+ qtBytesInSource = 0;
+ elseif qtBytesInSource > sourceStream.remainingBytes then
+ qtBytesInSource = sourceStream.remainingBytes;
+ end;
+ end;
+
+ local compressObject = require("rrpgUtil_async.dlua").newAsyncZLibObject();
+ compressObject:zlibCompressAsync(sourceStream, destStream, level, qtBytesInSource, onFinish, onError);
+end;
+
+function utils.zlibDecompressAsync(sourceStream, destStream, onFinish, onError)
+ local compressObject = require("rrpgUtil_async.dlua").newAsyncZLibObject();
+ compressObject:zlibDecompressAsync(sourceStream, destStream, onFinish, onError);
+end;
+
+function utils.newMemoryStream()
+ return utils.streamFromHandle(_util_newMemoryStream());
+end;
+
+function utils.newTempFileStream()
+ return utils.streamFromHandle(_util_newTempFileStream());
+end;
+
+function utils.openSharedStream(sharedId)
+ return utils.streamFromHandle(_util_openSharedStream(sharedId));
+end;
+
+function utils.generateUniqueString()
+ return _rrpg_generateUniqueStrID();
+end;
+
+function utils.cloneTable(t, deep)
+ if t == nil then
+ return nil;
+ end;
+
+ local r = {};
+
+ for i = 1, #t do
+ local v = t[i];
+
+ if (deep) and (type(v) == "table") then
+ r[i] = utils.cloneTable(v);
+ else
+ r[i] = v;
+ end;
+ end;
+
+ for k, v in pairs(t) do
+ if r[k] == nil then
+ if (deep) and (type(v) == "table") then
+ r[k] = utils.cloneTable(v);
+ else
+ r[k] = v;
+ end;
+ end;
+ end;
+
+ return r;
+end;
+
+utils.colorToRGBA = _gui_colorToRGBA;
+utils.RGBAToColor = _gui_RGBAToColor;
+
+colorToRGBA = utils.colorToRGBA;
+RGBAToColor = utils.RGBAToColor;
+
+return utils;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgUtil_async.dlua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgUtil_async.dlua
new file mode 100644
index 00000000..cc51a94d
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgUtil_async.dlua
@@ -0,0 +1,78 @@
+local objs = require("rrpgObjs.lua");
+local async = {};
+
+local __asyncsWorking = {};
+
+function async.newAsyncZLibObject()
+ local obj = objs.objectFromHandle(_obj_newObject("asyncZLibObject"));
+
+ if obj.eves == nil then
+ obj.eves = {};
+ end;
+
+ obj.eves["onFinish"] = "";
+ obj.eves["onError"] = "";
+
+ function obj:undoReferenceToStreams()
+ rawset(obj, "__sourceStream", nil);
+ rawset(obj, "__destStream", nil);
+ end;
+
+ function obj:setWorking()
+ __asyncsWorking[obj] = true;
+ end;
+
+ function obj:setNotWorking()
+ obj:undoReferenceToStreams();
+ __asyncsWorking[obj] = nil;
+ end;
+
+ function obj:zlibCompressAsync(sourceStream, destStream, level, qtBytesInSource, onFinish, onError)
+ rawset(obj, "__sourceStream", sourceStream);
+ rawset(obj, "__destStream", destStream);
+
+ obj.onFinish = function (...)
+ if onFinish ~= nil then
+ onFinish(...);
+ obj:setNotWorking();
+ end;
+ end;
+
+ obj.onError = function (...)
+ if onError ~= nil then
+ onError(...);
+ obj:setNotWorking();
+ end;
+ end;
+
+ obj:setWorking();
+ _obj_invokeEx(obj.handle, "ZLibCompressAsync", sourceStream.handle, destStream.handle, level, qtBytesInSource);
+ end;
+
+ function obj:zlibDecompressAsync(sourceStream, destStream, onFinish, onError)
+ rawset(obj, "__sourceStream", sourceStream);
+ rawset(obj, "__destStream", destStream);
+
+ obj.onFinish = function ()
+ if onFinish ~= nil then
+ onFinish();
+ obj:setNotWorking();
+ end;
+ end;
+
+ obj.onError = function (errorMsg)
+ if onError ~= nil then
+ onError(errorMsg);
+ obj:setNotWorking();
+ end;
+ end;
+
+ obj:setWorking();
+ _obj_invokeEx(obj.handle, "ZLibDecompressAsync", sourceStream.handle, destStream.handle);
+ end;
+
+ objs.registerHandle(obj.handle, obj);
+ return obj;
+end;
+
+return async;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/rrpgWrappers.lua b/Plugins/Sheets/Coyote and Crow/sdk/rrpgWrappers.lua
new file mode 100644
index 00000000..b4b39038
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/rrpgWrappers.lua
@@ -0,0 +1,1185 @@
+local objs = require("rrpgObjs.lua");
+local SharedObjects = require("rrpgSharedObjects.lua");
+local rrpgWrappers = {};
+local localStrongRefContextoObjects = {};
+local Locale = require("locale.lua");
+local Async = require("async.lua");
+local Utils = require('utils.lua');
+
+local SHARED_OBJECT_TYPE = "rrpgObject";
+
+--[ Anti Flood System ]--
+
+local function newTimedJobQueue(interval)
+ local o = {};
+ o.interval = interval;
+
+ o.timer = objs.newTimer(interval,
+ function()
+
+ -- Pesquisar novo job
+ local achouJob = false;
+ local jobEncontrado = nil;
+ local idJobEncontrado = nil;
+
+ while (not achouJob) and (o.ultimoJobExecutado < o.gerador) do
+ o.ultimoJobExecutado = o.ultimoJobExecutado + 1;
+ local jobObject = o.jobs[o.ultimoJobExecutado];
+
+ if jobObject ~= nil then
+ achouJob = true;
+ jobEncontrado = jobObject;
+ idJobEncontrado = o.ultimoJobExecutado;
+ end;
+ end;
+
+ if achouJob and (jobEncontrado ~= nil) then
+ o.jobs[idJobEncontrado] = nil;
+
+ if jobEncontrado.parameters ~= nil then
+ jobEncontrado.callback(table.unpack(jobEncontrado.parameters));
+ else
+ jobEncontrado.callback();
+ end;
+ else
+ o.readyForJob = true;
+ o.timer.enabled = false;
+ end;
+
+ end);
+
+ o.timer.enabled = false;
+
+ function o:addJob(callback, ...)
+ if o.readyForJob then
+ o.readyForJob = false;
+ o.timer.enabled = true;
+ callback(...);
+ else
+ o.gerador = o.gerador + 1;
+ local idJob = o.gerador;
+ local jobObject = {};
+ jobObject.callback = callback;
+ jobObject.parameters = table.pack(...);
+ o.jobs[idJob] = jobObject;
+ end;
+ end;
+
+ function o:addAsyncJob(callback, ...)
+ local promise, resolution = Async.Promise.toResolve();
+ assert((promise ~= nil) and (resolution ~= nil));
+
+ o:addJob(
+ function(...)
+ assert(resolution ~= nil);
+
+ local function protectedCallback(...)
+ local ret = table.pack(pcall(callback, ...));
+
+ if ret[1] then
+ return table.unpack(ret, 2);
+ else
+ return Async.Promise.failed(ret[2]);
+ end;
+ end;
+
+ Async.execute(protectedCallback, ...):thenResolve(resolution);
+ end, ...);
+
+ return promise;
+ end;
+
+ function o:clear()
+ o.timer.enabled = false;
+ o.gerador = 0;
+ o.ultimoJobExecutado = 0;
+ o.jobs = {};
+ o.readyForJob = true;
+ end;
+
+ o:clear();
+ return o;
+end;
+
+local __serverRequestQueue = newTimedJobQueue(250);
+rrpgWrappers.__serverRequestQueue = __serverRequestQueue;
+
+local function initWrappedObjectFromHandle(handle)
+ local wObj = objs.objectFromHandle(handle);
+
+ if (wObj.props == nil) then
+ wObj.props = {};
+ end;
+
+ function wObj:getObjectID() return _obj_getProp(self.handle, "ContextoObjectID"); end;
+ function wObj:getObjectType() return _obj_getProp(self.handle, "WrappedObjectType"); end;
+ function wObj:getIsObjectAlive() return _obj_getProp(self.handle, "IsObjectAlive"); end;
+ function wObj:isType(typeName) return _rrpg_IsWrapperOfType(self.handle, typeName); end;
+
+ function wObj:getShareID() return {objectType=SHARED_OBJECT_TYPE, objectID=tostring(self:getObjectID())} end;
+
+ wObj.props["objectType"] = {getter = "getObjectType", tipo = "string"};
+ wObj.props["isObjectAlive"] = {getter = "getIsObjectAlive", tipo = "bool"};
+ wObj.props["objectID"] = {getter = "getObjectID", tipo = "int"};
+ return wObj;
+end;
+
+--[ OBJETO MESA ]--
+
+local function initMesaWrappedObjectFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+ local mesa = wObj;
+
+ function mesa:getActiveChat()
+ local objMesa = rrpgWrappers.objectFromID(_obj_getProp(self.handle, "ActiveChatObjectID"));
+
+ if objMesa == nil then
+ return mesa:getChat();
+ else
+ return objMesa;
+ end;
+ end;
+
+ function mesa:getAudioPlayer()
+ local cachedPlayer = rawget(self, "__cachedAudioPlayer");
+
+ if cachedPlayer == nil then
+ local audioLib = require("audioCore.dlua");
+
+ if self.isObjectAlive then
+ local audioPlayerHandle = _obj_invokeEx(self.handle, 'CreateRoomAudioPlayer');
+
+ if audioPlayerHandle ~= nil then
+ cachedPlayer = audioLib._audioPlayerWrapperFromHandle(audioPlayerHandle);
+ else
+ cachedPlayer = audioLib._newNullAudioPlayerWrapper("Failed to initialize room audio player");
+ end;
+ else
+ cachedPlayer = audioLib._newNullAudioPlayerWrapper("Not in room");
+ end;
+
+ assert(cachedPlayer ~= nil);
+ rawset(self, "__cachedAudioPlayer", cachedPlayer);
+ end;
+
+ return cachedPlayer;
+ end;
+
+ function mesa:getChat()
+ local objMesa = rrpgWrappers.objectFromID(_obj_getProp(self.handle, "ChatObjectID"));
+
+ if objMesa == nil then
+ return rrpgWrappers.NullChatWrapper; -- ao invés de retornar NULL, vamos retorna um objeto que não faz nada.
+ else
+ return objMesa;
+ end;
+ end;
+
+ function mesa:getJogadores()
+ local hs = _obj_getProp(self.handle, "JogadoresObjectIDs");
+ local jogadores = {};
+ local idx = 1;
+
+ for p, v in pairs(hs) do
+ jogadores[idx] = rrpgWrappers.contextObjectFromID(v);
+ idx = idx + 1;
+ end
+
+ return jogadores;
+ end
+
+ function mesa:findBibliotecaItem(codigoInterno) return rrpgWrappers.objectFromID(_obj_invoke(self.handle, "TryFindBibliotecaItem", codigoInterno)); end;
+
+ function mesa:findJogador(loginOuCodigoInterno)
+ if type(loginOuCodigoInterno) == "string" then
+ return rrpgWrappers.objectFromID(_obj_invoke(self.handle, "TryFindJogadorByLogin", loginOuCodigoInterno));
+ elseif type(loginOuCodigoInterno) == "number" then
+ return rrpgWrappers.objectFromID(_obj_invoke(self.handle, "TryFindJogadorById", loginOuCodigoInterno));
+ else
+ return nil;
+ end;
+ end;
+
+ function mesa:getNome() return _obj_getProp(self.handle, "Nome"); end;
+ function mesa:getDescricao() return _obj_getProp(self.handle, "Descricao"); end;
+ function mesa:getMsgStatus() return _obj_getProp(self.handle, "MsgStatus"); end;
+ function mesa:getSite() return _obj_getProp(self.handle, "Site"); end;
+ function mesa:getLogotipo() return _obj_getProp(self.handle, "Logotipo"); end;
+ function mesa:getSistema() return _obj_getProp(self.handle, "Sistema"); end;
+ function mesa:getMsgBoasVindas() return _obj_getProp(self.handle, "MsgBoasVindas"); end;
+ function mesa:getCodigoInterno() return math.tointeger(_obj_getProp(self.handle, "CodigoInterno")); end;
+ function mesa:getIsRestrito18Anos() return _obj_getProp(self.handle, "IsRestrito18Anos"); end;
+ function mesa:getHaVagas() return _obj_getProp(self.handle, "HaVagas"); end;
+ function mesa:getIsModerada() return _obj_getProp(self.handle, "IsModerada"); end;
+ function mesa:getMeuJogador() return rrpgWrappers.contextObjectFromID(_obj_getProp(self.handle, "MeuJogadorObjectID")); end;
+ function mesa:getBiblioteca() return rrpgWrappers.contextObjectFromID(_obj_getProp(self.handle, "BibliotecaObjectID")); end;
+ function mesa:getPodeTablesDock() return _obj_getProp(self.handle, "PodeTablesDock"); end;
+
+ function mesa:requestSetModerada(moderada)
+ moderada = Locale.autoEval(moderada);
+ __serverRequestQueue:addJob(function () _obj_invokeNoEval(self.handle, "RequestSetModerada", not (not moderada)); end);
+ end;
+
+ function mesa:abrirNDBDeMesa(nome, callback, opcoes)
+ local ndbBib = require("ndb.lua");
+
+ if type(opcoes) ~= "table" then
+ opcoes = {};
+ else
+ opcoes = Utils.cloneTable(opcoes, true);
+ end;
+
+ opcoes.criar = not not opcoes.criar;
+
+ local ndbHandle = _obj_invokeEx(self.handle, 'AbrirNDBDeMesa', tostring(nome) or "", opcoes.criar);
+ local ndbObj = nil;
+ local rootNode = nil;
+
+ if ndbHandle ~= nil then
+ ndbObj = ndbBib.openNodeDatabaseFromHandle(ndbHandle);
+ end;
+
+ if ndbObj ~= nil then
+ rootNode = ndbBib.getRoot(ndbObj);
+ end;
+
+ if rootNode ~= nil then
+ local jaNotificou = false;
+ local jaNotificouEmCarregamento = false;
+ local listenerProvider = nil;
+ local listenerLoaded = nil;
+
+ local function checkState()
+ if not jaNotificou then
+ local state = ndbBib.getState(rootNode);
+
+ if state == "open" then
+ jaNotificou = true;
+
+ if callback ~= nil then
+ setTimeout(callback, 1, rootNode);
+ end;
+ elseif state == "closed" then
+ jaNotificou = true;
+
+ if callback ~= nil then
+ setTimeout(callback, 1, nil);
+ end;
+ else
+ if (not jaNotificouEmCarregamento) and (not jaNotificou) then
+ jaNotificouEmCarregamento = true;
+
+ if opcoes.callbackDeCarga ~= nil then
+ opcoes.callbackDeCarga(rootNode);
+ end;
+ end;
+ end;
+
+ if jaNotificou and (ndbObj ~= nil) then
+ ndbObj:removeEventListener(listenerProvider);
+ ndbObj:removeEventListener(listenerLoaded);
+ --ndbObj = nil;
+ end;
+ end;
+ end;
+
+ listenerProvider = ndbObj:addEventListener("OnProviderStateChange", checkState);
+ listenerLoaded = ndbObj:addEventListener("OnLoaded", checkState);
+
+ checkState();
+ elseif callback ~= nil then
+ setTimeout(callback, 1, nil);
+ end;
+ end;
+
+ function mesa:asyncOpenRoomNDB(name, options)
+ options = options or {};
+
+ local promise, resolution = Async.Promise.pending();
+
+ local adaptedOptions = {};
+ adaptedOptions.criar = options.create;
+
+ if options.skipLoad then
+ adaptedOptions.callbackDeCarga =
+ function(loadingNode)
+ resolution:setSuccess(loadingNode);
+ end;
+ end;
+
+ self:abrirNDBDeMesa(name,
+ function(loadedNode)
+ if loadedNode ~= nil then
+ resolution:setSuccess(loadedNode);
+ else
+ resolution:setFailure("Could not load room nodedatabase");
+ end;
+ end,
+ adaptedOptions);
+
+ return promise;
+ end;
+
+ function mesa:asyncOpenUserRoomNDB(name, options)
+ return __serverRequestQueue:addAsyncJob(
+ function ()
+ return Async.Promise.wrap(_obj_invokeEx(self.handle, "AsyncOpenUserRoomNDB", name, options));
+ end);
+ end;
+
+ function mesa:getFirecastURI()
+ return _obj_invokeEx(self.handle, "GetFirecastURI");
+ end;
+
+ function mesa:asyncOpenPVT(login, params)
+ local promiseHandle = _obj_invokeEx(self.handle, "AsyncOpenPVT", login, params);
+ return Async.Promise.wrap(promiseHandle);
+ end;
+
+ function mesa:asyncCreateGroupPVT(logins, params)
+ local clonedLogins = Utils.cloneTable(logins);
+ local clonedParams = Utils.cloneTable(params);
+
+ return __serverRequestQueue:addAsyncJob(
+ function ()
+ local promiseHandle = _obj_invokeEx(self.handle, "AsyncCreateGroupPVT", clonedLogins, clonedParams);
+ return Async.Promise.wrap(promiseHandle);
+ end);
+ end;
+
+ function mesa:getChats()
+ return _obj_invokeEx(self.handle, "GetChats");
+ end;
+
+ wObj.props["activeChat"] = {getter="getActiveChat", tipo="table"};
+ wObj.props["audioPlayer"] = {getter="getAudioPlayer", tipo="table"};
+ wObj.props["nome"] = {getter = "getNome", tipo = "string"};
+ wObj.props["descricao"] = {getter = "getDescricao", tipo = "string"};
+ wObj.props["msgStatus"] = {getter = "getMsgStatus", tipo = "string"};
+ wObj.props["site"] = {getter = "getSite", tipo = "string"};
+ wObj.props["logotipo"] = {getter = "getLogotipo", tipo = "string"};
+ wObj.props["sistema"] = {getter = "getSistema", tipo = "string"};
+ wObj.props["msgBoasVindas"] = {getter = "getMsgBoasVindas", tipo = "string"};
+ wObj.props["codigoInterno"] = {getter = "getCodigoInterno", tipo = "int"};
+ wObj.props["firecastURI"] = {getter = "getFirecastURI", tipo = "string"};
+ wObj.props["isRestrito18Anos"] = {getter = "getIsRestrito18Anos", tipo = "bool"};
+ wObj.props["haVagas"] = {getter = "getHaVagas", tipo = "bool"};
+ wObj.props["isModerada"] = {getter = "getIsModerada", tipo = "bool"};
+ wObj.props["podeTablesDock"] = {getter = "getPodeTablesDock", tipo = "bool"};
+ wObj.props["jogadores"] = {getter = "getJogadores", tipo = "table"};
+ wObj.props["meuJogador"] = {getter = "getMeuJogador", tipo = "table"};
+ wObj.props["biblioteca"] = {getter = "getBiblioteca", tipo = "table"};
+ wObj.props["chat"] = {getter="getChat", tipo="table"};
+
+ wObj.props["library"] = wObj.props["biblioteca"];
+ wObj.props["me"] = wObj.props["meuJogador"];
+
+ return wObj;
+end;
+
+--[ OBJETO JOGADOR ]--
+
+local function initJogadorWrappedObjectFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+ local jogador = wObj;
+
+ function jogador:getMesa() return rrpgWrappers.objectFromID(_obj_getProp(self.handle, "MesaID")); end;
+ function jogador:getNick() return _obj_getProp(self.handle, "Nick"); end;
+ function jogador:getLogin() return _obj_getProp(self.handle, "Login"); end;
+ function jogador:getAvatar() return _obj_getProp(self.handle, "Avatar"); end;
+ function jogador:getCapa() return _obj_getProp(self.handle, "Capa"); end;
+ function jogador:getIsGold() return _obj_getProp(self.handle, "IsGold"); end;
+ function jogador:getIsGoldPlus() return _obj_getProp(self.handle, "IsGoldPlus"); end;
+ function jogador:getIsRuby() return _obj_getProp(self.handle, "IsRuby"); end;
+ function jogador:getIsAusente() return _obj_getProp(self.handle, "IsAusente"); end;
+ function jogador:getIsCnxDormente() return _obj_getProp(self.handle, "IsCnxDormente"); end;
+ function jogador:getIsSessaoMobile() return _obj_getProp(self.handle, "IsSessaoMobile"); end;
+ function jogador:getIsJuggernaut() return _obj_getProp(self.handle, "IsJuggernaut"); end;
+ function jogador:getIsMestre() return _obj_getProp(self.handle, "IsMestre"); end;
+ function jogador:getIsJogador() return _obj_getProp(self.handle, "IsJogador"); end;
+ function jogador:getIsEspectador() return _obj_getProp(self.handle, "IsEspectador"); end;
+ function jogador:getIsMudo() return _obj_getProp(self.handle, "IsMudo"); end;
+ function jogador:getIsCego() return _obj_getProp(self.handle, "IsCego"); end;
+ function jogador:getHaveVoice() return _obj_getProp(self.handle, "HaveVoice"); end;
+ function jogador:getCodigoInterno() return _obj_getProp(self.handle, "CodigoInterno"); end;
+
+ function jogador:__innerRequestSetMode(modo, ativar)
+ modo, ativar = Locale.autoEval(modo, ativar);
+
+ __serverRequestQueue:addJob(function()
+ _obj_invokeNoEval(self.handle, "RequestSetMode", modo, not (not ativar));
+ end);
+ end;
+
+ function jogador:requestSetCego(cego) self:__innerRequestSetMode("cego", cego); end;
+ function jogador:requestSetMudo(mudo) self:__innerRequestSetMode("mudo", mudo); end;
+ function jogador:requestSetVoz(voz) self:__innerRequestSetMode("voz", voz); end;
+ function jogador:requestSetJogador(isJogador) self:__innerRequestSetMode("jogador", isJogador); end;
+ function jogador:requestKick() __serverRequestQueue:addJob(function() _obj_invoke(self.handle, "RequestKick", ""); end); end;
+ function jogador:getBarValue(index) return _obj_invokeEx(self.handle, "LuaGetBarValue", index); end;
+
+ function jogador:requestSetBarValue(index, currentValue, maxValue)
+ index, currentValue, maxValue = Locale.autoEval(index, currentValue, maxValue);
+
+ __serverRequestQueue:addJob(
+ function()
+ _obj_invokeExNoEval(self.handle, "LuaRequestSetBarValue", index, currentValue, maxValue);
+ end);
+ end;
+
+ function jogador:getEditableLine(index) return _obj_invokeEx(self.handle, "LuaGetEditableLine", index); end;
+ function jogador:requestSetEditableLine(index, text) index, text = Locale.autoEval(index, text); __serverRequestQueue:addJob(function() _obj_invokeExNoEval(self.handle, "LuaRequestSetEditableLine", index, text); end); end;
+
+ wObj.props["mesa"] = {getter = "getMesa", tipo = "table"};
+ wObj.props["nick"] = {getter = "getNick", tipo = "string"};
+ wObj.props["login"] = {getter = "getLogin", tipo = "string"};
+ wObj.props["avatar"] = {getter = "getAvatar", tipo = "string"};
+ wObj.props["isGold"] = {getter = "getIsGold", tipo = "bool"};
+ wObj.props["isGoldPlus"] = {getter = "getIsGoldPlus", tipo = "bool"};
+ wObj.props["isRuby"] = {getter = "getIsRuby", tipo = "bool"};
+ wObj.props["isAusente"] = {getter = "getIsAusente", tipo = "bool"};
+ wObj.props["isCnxDormente"] = {getter = "getIsCnxDormente", tipo = "bool"};
+ wObj.props["isSessaoMobile"] = {getter = "getIsSessaoMobile", tipo = "bool"};
+ wObj.props["isJuggernaut"] = {getter = "getIsJuggernaut", tipo = "bool"};
+ wObj.props["isMestre"] = {getter = "getIsMestre", tipo = "bool"};
+ wObj.props["isJogador"] = {getter = "getIsJogador", tipo = "bool"};
+ wObj.props["isEspectador"] = {getter = "getIsEspectador", tipo = "bool"};
+ wObj.props["isMudo"] = {getter = "getIsMudo", tipo = "bool"};
+ wObj.props["isCego"] = {getter = "getIsCego", tipo = "bool"};
+ wObj.props["haveVoice"] = {getter = "getHaveVoice", tipo = "bool"};
+ wObj.props["haveVoz"] = {getter = "getHaveVoice", tipo = "bool"};
+ wObj.props["codigoInterno"] = {getter = "getCodigoInterno", tipo = "int"};
+ wObj.props["personagemPrincipal"] = {readProp="PersonagemPrincipal", tipo = "int"};
+ wObj.props["id"] = {readProp="ID", tipo = "int"};
+
+ return wObj;
+end;
+
+--[ OBJETO BIBLIOTECA ITEM ]--
+
+local function initBibliotecaItemWrappedObjectFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+ local bibItem = wObj;
+
+ function bibItem:getFilhos()
+ local hs = _obj_getProp(self.handle, "FilhosObjectIDs");
+ local filhos = {};
+ local idx = 1;
+
+ for p, v in pairs(hs) do
+ filhos[idx] = rrpgWrappers.objectFromID(v);
+ idx = idx + 1;
+ end
+
+ return filhos;
+ end;
+
+ function bibItem:__asyncCreateBibItem(bibItemType, params)
+ assert(type(params) == "table");
+
+ local innerPromise = __serverRequestQueue:addAsyncJob(
+ function ()
+ return Async.Promise.wrap(_obj_invokeEx(self.handle, "AsyncCreateBibItemObjectID", bibItemType, params));
+ end);
+
+ return Async.Promise.toHandle(innerPromise,
+ function (newObjectID)
+ local newObj = rrpgWrappers.contextObjectFromID(newObjectID);
+
+ if newObj ~= nil then
+ return newObj;
+ else
+ error("Could not find the new created library item");
+ end;
+ end);
+ end;
+
+ function bibItem:asyncCreateChar(charParams)
+ if type(charParams) ~= "table" then
+ error("charParams must be a table");
+ end;
+
+ if charParams.name == nil then
+ error("Required field: charParams.name");
+ end;
+
+ if charParams.name == nil then
+ error("Required field: charParams.dataType");
+ end;
+
+ return bibItem:__asyncCreateBibItem('character', charParams);
+ end;
+
+ function bibItem:asyncCreateDir(dirParams)
+ if type(dirParams) ~= "table" then
+ error("dirParams must be a table");
+ end;
+
+ if dirParams.name == nil then
+ error("Required field: dirParams.name");
+ end;
+
+ return bibItem:__asyncCreateBibItem('directory', dirParams);
+ end;
+
+ function bibItem:asyncCreateScene3(gridParams)
+ if type(gridParams) ~= "table" then
+ error("gridParams must be a table");
+ end;
+
+ if gridParams.name == nil then
+ error("Required field: gridParams.name");
+ end;
+
+ return bibItem:__asyncCreateBibItem('scene3', gridParams);
+ end;
+
+ function bibItem:asyncDelete()
+ return __serverRequestQueue:addAsyncJob(
+ function ()
+ return Async.Promise.wrap(_obj_invokeEx(bibItem.handle, "AsyncDelete"));
+ end);
+ end;
+
+ function bibItem:asyncMoveTo(newParent)
+ if type(newParent) ~= 'table' then
+ error('Parameter "newParent" must be an object');
+ end;
+
+ return __serverRequestQueue:addAsyncJob(
+ function ()
+ return Async.Promise.wrap(_obj_invokeEx(bibItem.handle, "AsyncMoveTo", newParent.objectID));
+ end);
+ end;
+
+ function bibItem:asyncUpdate(changes)
+ if type(changes) ~= 'table' then
+ error('Parameter "changes" must be a table');
+ end;
+
+ return __serverRequestQueue:addAsyncJob(
+ function ()
+ return Async.Promise.wrap(_obj_invokeEx(bibItem.handle, "AsyncUpdate", changes));
+ end);
+ end;
+
+ function bibItem:getFirecastURI()
+ return _obj_invokeEx(self.handle, "GetFirecastURI");
+ end;
+
+ function bibItem:getMesa() return rrpgWrappers.objectFromID(_obj_getProp(self.handle, "MesaObjectID")); end;
+ function bibItem:getNome() return _obj_getProp(self.handle, "Nome"); end;
+ function bibItem:getPai() return rrpgWrappers.objectFromID(_obj_getProp(self.handle, "ItemMaeObjectID")); end;
+ function bibItem:getDono() return rrpgWrappers.objectFromID(_obj_getProp(self.handle, "JogadorOwnerObjectID")); end;
+ function bibItem:getLoginDono() return _obj_getProp(self.handle, "LoginDono"); end;
+ function bibItem:getCriador() return rrpgWrappers.objectFromID(_obj_getProp(self.handle, "JogadorCriadorObjectID")); end;
+ function bibItem:getLoginCriador() return _obj_getProp(self.handle, "LoginCriador"); end;
+ function bibItem:getVisivel() return _obj_getProp(self.handle, "Visivel"); end;
+ function bibItem:getVisivelRecursivamente() return _obj_getProp(self.handle, "VisivelNaHierarquia"); end;
+ function bibItem:getTipo() return _obj_getProp(self.handle, "Tipo"); end;
+ function bibItem:getCodigoInterno() return _obj_getProp(self.handle, "CodigoInterno"); end;
+
+ wObj.props["mesa"] = {getter = "getMesa", tipo = "table"};
+ wObj.props["filhos"] = {getter = "getFilhos", tipo = "table"};
+ wObj.props["pai"] = {getter = "getPai", tipo = "table"};
+ wObj.props["nome"] = {getter = "getNome", tipo = "string"};
+ wObj.props["dono"] = {getter = "getDono", tipo = "table"};
+ wObj.props["loginDono"] = {getter = "getLoginDono", tipo = "string"};
+ wObj.props["criador"] = {getter = "getCriador", tipo = "table"};
+ wObj.props["loginCriador"] = {getter = "getLoginCriador", tipo = "string"};
+ wObj.props["visivel"] = {getter = "getVisivel", tipo = "bool"};
+ wObj.props["visivelRecursivamente"] = {getter = "getVisivelRecursivo", tipo = "bool"};
+ wObj.props["tipo"] = {getter = "getTipo", tipo = "string"};
+ wObj.props["codigoInterno"] = {getter = "getCodigoInterno", tipo = "int"};
+
+ wObj.props["room"] = wObj.props["mesa"];
+ wObj.props["parent"] = wObj.props["pai"];
+ wObj.props["name"] = wObj.props["nome"];
+ wObj.props["children"] = wObj.props["filhos"];
+ wObj.props["firecastURI"] = {getter = "getFirecastURI", tipo = "string"};
+ wObj.props["ownerLogin"] = wObj.props["loginDono"];
+ wObj.props["creatorLogin"] = wObj.props["loginCriador"];
+ wObj.props["creator"] = wObj.props["criador"];
+ wObj.props["owner"] = wObj.props["dono"];
+ wObj.props["visible"] = wObj.props["visivel"];
+ wObj.props["recursiveVisible"] = wObj.props["visivelRecursivamente"];
+ return wObj;
+end;
+
+--[ OBJETO PERSONAGEM ]--
+
+local __PersonagemWrappedObjectProps = {};
+
+for i = 0, 3 do
+ local barIndex = i;
+
+ __PersonagemWrappedObjectProps["bar" .. tostring(i) .. "Val"] = {tipo = "int", getter = function (personagem)
+ return _obj_invokeEx(personagem.handle, "GetBarVal", barIndex)
+ end};
+
+ __PersonagemWrappedObjectProps["bar" .. tostring(i) .. "Max"] = {tipo = "int", getter = function (personagem)
+ return _obj_invokeEx(personagem.handle, "GetBarMax", barIndex)
+ end};
+end;
+
+for i = 0, 1 do
+ local edtLineIndex = i;
+
+ __PersonagemWrappedObjectProps["edtLine" .. tostring(i)] = {tipo = "string", getter = function (personagem)
+ return _obj_invokeEx(personagem.handle, "GetEdtLine", edtLineIndex)
+ end};
+end;
+
+local function initBibPersonagemWrappedObjectFromHandle(handle)
+ local wObj = initBibliotecaItemWrappedObjectFromHandle(handle);
+ local bibItem = wObj;
+
+ function bibItem:getDataType() return _obj_getProp(self.handle, "DataType"); end;
+ function bibItem:getEscritaBloqueada() return _obj_getProp(self.handle, "EscritaBloqueada"); end;
+
+ function bibItem:loadSheetNDB(callback, params)
+ params = params or {};
+
+ local ndbBib = require("ndb.lua");
+ local ndbHandle = _obj_invokeEx(self.handle, 'GetOrCreateSheetNDB');
+
+ local function scheduleFailReturn()
+ if callback ~= nil then
+ setTimeout(callback, 1, nil);
+ end;
+ end;
+
+ if ndbHandle == nil then
+ scheduleFailReturn();
+ return;
+ end;
+
+ local ndbObj = nil;
+ local rootNode = nil;
+
+ if ndbHandle ~= nil then
+ ndbObj = ndbBib.openNodeDatabaseFromHandle(ndbHandle);
+ end;
+
+ if ndbObj ~= nil then
+ rootNode = ndbBib.getRoot(ndbObj);
+ end;
+
+ if rootNode == nil then
+ scheduleFailReturn();
+ return;
+ end;
+
+ local state = ndbBib.getState(rootNode);
+
+ if (state == "open") or
+ ((state == "opening") and (params.skipLoad)) then
+ -- Already loaded
+ if callback ~= nil then
+ callback(rootNode);
+ end;
+
+ return;
+ end;
+
+ -- Not loaded yet, letz monitor
+
+ local jaNotificou = false;
+ local listenerProvider = nil;
+ local listenerLoaded = nil;
+
+ local function checkState()
+ if not jaNotificou then
+ state = ndbBib.getState(rootNode);
+
+ if state == "open" then
+ jaNotificou = true;
+
+ if callback ~= nil then
+ setTimeout(callback, 1, rootNode);
+ end;
+ elseif state == "closed" then
+ jaNotificou = true;
+ scheduleFailReturn();
+ end;
+
+ if jaNotificou then
+ ndbObj:removeEventListener(listenerProvider);
+ ndbObj:removeEventListener(listenerLoaded);
+ end;
+ end;
+ end;
+
+ listenerProvider = ndbObj:addEventListener("OnProviderStateChange", checkState);
+ listenerLoaded = ndbObj:addEventListener("OnLoaded", checkState);
+
+ checkState();
+ end;
+
+ function bibItem:asyncOpenNDB(options)
+ options = options or {};
+ local promise, resolution = Async.Promise.pending();
+
+ self:loadSheetNDB(
+ function (loadedNDB)
+ if loadedNDB ~= nil then
+ resolution:setSuccess(loadedNDB);
+ else
+ resolution:setFailure("Could not load character nodedatabase");
+ end;
+ end, options);
+
+ return promise;
+ end;
+
+ wObj.props["dataType"] = {getter = "getDataType", tipo = "string"};
+ wObj.props["escritaBloqueada"] = {getter = "getEscritaBloqueada", tipo = "bool"};
+ wObj.props["avatar"] = {readProp="Avatar", tipo = "string"};
+
+ for k, v in pairs(__PersonagemWrappedObjectProps) do
+ wObj.props[k] = v;
+ end;
+
+ wObj.props["editionBlocked"] = wObj.props["escritaBloqueada"];
+ return wObj;
+end;
+
+--[ OBJETO SceneUnitClass ]--
+
+local function initBibSceneUnitClassWrappedObjectFromHandle(handle)
+ local wObj = initBibliotecaItemWrappedObjectFromHandle(handle);
+
+ wObj.props["tamanhoX"] = {readProp = "TamanhoX", tipo = "double"};
+ wObj.props["tamanhoY"] = {readProp = "TamanhoY", tipo = "double"};
+ wObj.props["camada"] = {readProp = "Camada", tipo = "enum", values={"tokens", "objects", "background"}};
+ wObj.props["descricao"] = {readProp = "Descricao", tipo = "string"};
+ wObj.props["urlImg"] = {readProp = "URLImg", tipo = "string"};
+ wObj.props["facing"] = {readProp = "Facing", tipo = "enum", values={"rotate", "drawArrow"}};
+ wObj.props["snapToGrid"] = {readProp = "SnapToGrid", tipo = "bool"};
+ wObj.props["direcaoImg"] = {readProp = "DirecaoImg", tipo = "double"};
+ wObj.props["layoutCenterX"] = {readProp = "LayoutCenterX", tipo = "double"};
+ wObj.props["layoutCenterY"] = {readProp = "LayoutCenterY", tipo = "double"};
+ wObj.props["layoutTamX"] = {readProp = "LayoutTamX", tipo = "double"};
+ wObj.props["layoutTamY"] = {readProp = "LayoutTamY", tipo = "double"};
+
+ return wObj;
+end;
+
+
+--[ OBJETO CHAT ]--
+
+local function _setupCallbackTrapForUniqueRoll(idOfRoll, callbackFunction)
+ local trabTable = {};
+
+ trabTable.listenerId = rrpg.messaging.listenOnce("InternalRollCallbackReceive",
+ function(msg)
+ clearTimeout(trabTable.timeoutId);
+ trabTable.timeoutId = nil;
+
+ if type(callbackFunction) == "function" then
+ local rolagemObject = rrpg.loadRolagemFromBase64EncodedString(msg.rollBase64 or "");
+ callbackFunction(rolagemObject);
+ end;
+ end, {id=idOfRoll});
+
+ trabTable.timeoutId = setTimeout(
+ function()
+ rrpg.messaging.unlisten(trabTable.listenerId);
+ trabTable.listenerId = nil;
+ end, 120000);
+end;
+
+local _NULL_FUNCTION = function() end;
+local _NULL_ARRAY_FUNCTION = function() return {}; end;
+local _NULL_PROMISE_FUNCTION = function() Async.Promise.failed("Chat is not alive"); end;
+
+rrpgWrappers.NullChatWrapper = {enviarMensagem = _NULL_FUNCTION,
+ rolarDados = _NULL_FUNCTION,
+ enviarAcao = _NULL_FUNCTION,
+ enviarRisada = _NULL_FUNCTION,
+ enviarMensagemNPC = _NULL_FUNCTION,
+ enviarNarracao = _NULL_FUNCTION,
+ setImpersonation = _NULL_FUNCTION,
+ readLogRecs = _NULL_ARRAY_FUNCTION,
+ asyncQueryLogRecs = _NULL_PROMISE_FUNCTION,
+ asyncSendLaugh = _NULL_PROMISE_FUNCTION,
+ asyncSendAction = _NULL_PROMISE_FUNCTION,
+ asyncSendStd = _NULL_PROMISE_FUNCTION,
+ asyncInvite = _NULL_PROMISE_FUNCTION,
+ participants = {},
+ medium = {kind="undefined"}
+ };
+
+local function initBaseChatWrappedObjectFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+ local wChat = wObj;
+
+ function wChat:_getTimedJobQueue()
+ local queue = rawget(self, "_timedJobQueue");
+
+ if queue == nil then
+ queue = newTimedJobQueue(250);
+ rawset(self, "_timedJobQueue", queue);
+ end;
+
+ return queue;
+ end;
+
+ function wChat:_getLongTimedJobQueue()
+ local queue = rawget(self, "_longTimedJobQueue");
+
+ if queue == nil then
+ queue = newTimedJobQueue(1000);
+ rawset(self, "_longTimedJobQueue", queue);
+ end;
+
+ return queue;
+ end;
+
+ function wChat:escrever(texto, quebrarLinha, permitirSmileys)
+ if quebrarLinha == nil then
+ quebrarLinha = true;
+ end;
+
+ if permitirSmileys == nil then
+ permitirSmileys = true;
+ end;
+
+ if texto ~= nil then
+ return _obj_invokeEx(self.handle, "Escrever", tostring(texto), quebrarLinha, permitirSmileys);
+ end;
+ end;
+
+ function wChat:enviarMensagem(msg, callback)
+ msg = Locale.autoEval(tostring(msg));
+
+ if msg ~= nil then
+ local queue = self:_getTimedJobQueue()
+
+ function queuedSendTheMessage()
+ if self.handle ~= nil then
+ _obj_invokeNoEval(wChat.handle, "EnviarMensagem", msg);
+
+ if type(callback) == 'function' then
+ callback();
+ end;
+ end;
+ end;
+
+ queue:addJob(queuedSendTheMessage);
+ end;
+ end;
+
+ function wChat:enviarMensagemNPC(npc, msg, callback)
+ npc, msg = Locale.autoEval(npc, msg);
+
+ if msg ~= nil and npc ~= nil then
+ local queue = self:_getTimedJobQueue()
+
+ queue:addJob(function()
+ if self.handle ~= nil then
+ _obj_invokeNoEval(wChat.handle, "EnviarMensagemNPC", tostring(npc), tostring(msg));
+
+ if type(callback) == 'function' then
+ callback();
+ end;
+ end;
+ end);
+ end;
+ end;
+
+ function wChat:enviarNarracao(msg, callback)
+ msg = Locale.autoEval(msg);
+
+ if msg ~= nil then
+ local queue = self:_getTimedJobQueue()
+
+ queue:addJob(function()
+ if self.handle ~= nil then
+ _obj_invokeNoEval(wChat.handle, "EnviarNarracao", tostring(msg));
+
+ if type(callback) == 'function' then
+ callback();
+ end;
+ end;
+ end);
+ end;
+ end;
+
+ function wChat:enviarAcao(acao, callback)
+ acao = Locale.autoEval(acao);
+
+ if acao ~= nil then
+ local queue = self:_getTimedJobQueue()
+
+ queue:addJob(function()
+ if self.handle ~= nil then
+ _obj_invokeNoEval(wChat.handle, "EnviarAcao", tostring(acao));
+
+ if type(callback) == 'function' then
+ callback();
+ end;
+ end;
+ end);
+ end;
+ end;
+
+ function wChat:enviarRisada(callback)
+ local queue = self:_getTimedJobQueue()
+
+ queue:addJob(function()
+ if self.handle ~= nil then
+ _obj_invoke(wChat.handle, "EnviarRisada");
+
+ if type(callback) == 'function' then
+ callback();
+ end;
+ end;
+ end);
+ end;
+
+ function wChat:rolarDados(rolagem, msg, callbackFunction)
+ local rolAsStr;
+ msg = Locale.autoEval(msg);
+
+ if type(rolagem) == "string" then
+ rolAsStr = Locale.autoEval(rolagem);
+ elseif (type(rolagem) == "table") and (rolagem.getAsString ~= nil) then
+ rolAsStr = rolagem:getAsString();
+ else
+ rolAsStr = nil;
+ end;
+
+ if rolAsStr ~= nil then
+ local queue = self:_getTimedJobQueue()
+ --local queue = __serverRequestQueue;
+
+ if type(callbackFunction) == "function" then
+ local idUnicaRolagem = _rrpg_generateUniqueMessageIDForMe();
+ _setupCallbackTrapForUniqueRoll(idUnicaRolagem, callbackFunction);
+
+ queue:addJob(
+ function ()
+ if self.handle ~= nil then
+ return _obj_invokeNoEval(self.handle, "EnviarRolagemEx", rolAsStr, msg, idUnicaRolagem);
+ end;
+ end);
+ else
+ queue:addJob(
+ function ()
+ if self.handle ~= nil then
+ return _obj_invokeNoEval(self.handle, "EnviarRolagem", rolAsStr, msg);
+ end;
+ end);
+ end;
+ end;
+ end;
+
+ function wChat:getRoom()
+ local selfHandle = rawget(self, "handle");
+
+ if selfHandle ~= nil then
+ mesaObjectID = _rrpg_tryGetMesaObjectIDRelatedToHandle(selfHandle);
+
+ if (mesaObjectID ~= nil) then
+ mesaObjectID = tonumber(mesaObjectID);
+ end;
+
+ if mesaObjectID ~= nil then
+ return rrpgWrappers.contextObjectFromID(mesaObjectID);
+ end;
+ end;
+ end;
+
+ function wChat:__asyncSendEx(msgDesc, params)
+ local finalMsgDesc = Utils.cloneTable(params) or {};
+
+ for k, v in pairs(msgDesc) do
+ finalMsgDesc[k] = v;
+ end;
+
+ local queue = self:_getTimedJobQueue()
+
+ return queue:addAsyncJob(
+ function()
+ return Async.Promise.wrap(_obj_invokeEx(self.handle, "AsyncSendEx", finalMsgDesc));
+ end);
+ end;
+
+ function wChat:asyncSendStd(content, params)
+ return self:__asyncSendEx({msgType="standard", content=content}, params);
+ end;
+
+ function wChat:asyncSendAction(content, params)
+ return self:__asyncSendEx({msgType="action", content=content}, params);
+ end;
+
+ function wChat:asyncSendLaugh(params)
+ return self:__asyncSendEx({msgType="laugh"}, params);
+ end;
+
+ function wChat:asyncRoll(expression, message, params)
+ local expressionAsStr;
+
+ if type(expression) == "string" then
+ expressionAsStr = Locale.autoEval(expression);
+ elseif (type(expression) == "table") and (expression.getAsString ~= nil) then
+ expressionAsStr = expression:getAsString();
+ else
+ expressionAsStr = nil;
+ end;
+
+ local sendPromise = self:__asyncSendEx({msgType="dice", expression=expressionAsStr, content=message}, params);
+
+ return sendPromise:thenDo(
+ function(logRec)
+ local roll = logRec.msg.roll;
+ assert(roll ~= nil);
+
+ return roll.resultado, roll, logRec;
+ end);
+ end;
+
+ function wChat:readLogRecs()
+ return _obj_invokeEx(self.handle, "ReadValidLogRecs");
+ end;
+
+ function wChat:getImpersonation()
+ return _obj_invokeEx(self.handle, "GetUIImpersonation");
+ end;
+
+ function wChat:setImpersonation(impersonation)
+ return _obj_invokeEx(self.handle, "SetUIImpersonation", impersonation);
+ end;
+
+ function wChat:getTalemarkOptions()
+ return _obj_invokeEx(self.handle, "GetTalemarkOptions");
+ end;
+
+ function wChat:setTalemarkOptions(options)
+ return _obj_invokeEx(self.handle, "SetTalemarkOptions", options);
+ end;
+
+ function wChat:getMedium()
+ return _obj_invokeEx(self.handle, "GetMedium");
+ end;
+
+ function wChat:getParticipants()
+ return _obj_invokeEx(self.handle, "GetParticipants");
+ end;
+
+ function wChat:asyncQueryLogRecs(params)
+ params = Utils.cloneTable(params or {});
+
+ local queue = self:_getLongTimedJobQueue()
+
+ return queue:addAsyncJob(
+ function()
+ return Async.Promise.wrap(_obj_invokeEx(self.handle, "AsyncQueryLogRecsFromServer", params));
+ end);
+ end;
+
+ function wChat:writeEx(text, talemarkOptions)
+ return _obj_invokeEx(self.handle, "WriteEx", text, talemarkOptions);
+ end;
+
+ function wChat:asyncInvite(logins)
+ local clonedLogins = Utils.cloneTable(logins);
+
+ return __serverRequestQueue:addAsyncJob(
+ function ()
+ local promiseHandle = _obj_invokeEx(self.handle, "AsyncInvite", clonedLogins);
+ return Async.Promise.wrap(promiseHandle);
+ end);
+ end;
+
+ wChat.props["room"] = {getter = "getRoom", tipo = "table"};
+ wChat.props["impersonation"] = {getter = "getImpersonation", setter = "setImpersonation", tipo = "table"};
+ wChat.props["talemarkOptions"] = {getter = "getTalemarkOptions", setter="setTalemarkOptions", tipo = "table"};
+ wChat.props["medium"] = {getter = "getMedium", tipo = "table" };
+ wChat.props["participants"] = {getter = "getParticipants", tipo = "table" };
+
+ -- aliases
+ wChat.write = wChat.escrever;
+
+ return wObj;
+end;
+
+function rrpgWrappers.contextObjectFromID(objectID)
+ local ctxObj = localStrongRefContextoObjects[objectID];
+
+ if ctxObj ~= nil then
+ return ctxObj;
+ end;
+
+ local objWrapperHandle;
+ objWrapperHandle = _rrpg_GetOrCreateObjectWrapperForObjectID(objectID);
+
+ if objWrapperHandle == nil then
+ return nil;
+ end;
+
+ ctxObj = objs.tryFindFromHandle(objWrapperHandle);
+
+ if ctxObj ~= nil then
+ if _rrpg_IsObjectIDAlive(objectID) then
+ localStrongRefContextoObjects[objectID] = ctxObj;
+ end;
+
+ return ctxObj;
+ end;
+
+
+ if _rrpg_IsWrapperOfType(objWrapperHandle, "mesa") then
+ ctxObj = initMesaWrappedObjectFromHandle(objWrapperHandle);
+ elseif _rrpg_IsWrapperOfType(objWrapperHandle, "jogador") then
+ ctxObj = initJogadorWrappedObjectFromHandle(objWrapperHandle);
+ elseif _rrpg_IsWrapperOfType(objWrapperHandle, "personagem") then
+ ctxObj = initBibPersonagemWrappedObjectFromHandle(objWrapperHandle);
+ elseif _rrpg_IsWrapperOfType(objWrapperHandle, "sceneUnitClass") then
+ ctxObj = initBibSceneUnitClassWrappedObjectFromHandle(objWrapperHandle);
+ elseif _rrpg_IsWrapperOfType(objWrapperHandle, "bibliotecaItem") then -- Deve ser o ultimo dos IFs dos Wrappers dos tipos de item de biblioteca
+ ctxObj = initBibliotecaItemWrappedObjectFromHandle(objWrapperHandle);
+ elseif _rrpg_IsWrapperOfType(objWrapperHandle, "chatBase") then -- Deve ser o ultimo dos IFs dos Wrappers dos tipos de CHAT
+ ctxObj = initBaseChatWrappedObjectFromHandle(objWrapperHandle);
+ else
+ ctxObj = initWrappedObjectFromHandle(objWrapperHandle);
+ end;
+
+ objs.registerHandle(objWrapperHandle, ctxObj);
+
+ if _rrpg_IsObjectIDAlive(objectID) then
+ localStrongRefContextoObjects[objectID] = ctxObj;
+ end;
+
+ return ctxObj;
+end;
+
+function rrpgWrappers.objectFromID(objectID)
+ return rrpgWrappers.contextObjectFromID(objectID);
+end;
+
+function _INTERNAL_EVE_OnWrappedObjectWasDestroyed(objectID)
+ localStrongRefContextoObjects[objectID] = nil; -- Permitir o Garbage Collector coletar este objeto
+end;
+
+function _INTERNAL_AUX_ContextObjectFromID(objectID)
+ return rrpgWrappers.contextObjectFromID(objectID);
+end;
+
+function _INTERNAL_AUX_NullChatWrapper()
+ return rrpgWrappers.NullChatWrapper;
+end;
+
+SharedObjects.registerUnpacker(SHARED_OBJECT_TYPE,
+ function (sid)
+ local objectIdN = tonumber(sid.objectID);
+
+ if objectIdN ~= nil then
+ return rrpgWrappers.contextObjectFromID(objectIdN);
+ else
+ return nil;
+ end;
+ end);
+
+return rrpgWrappers;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/scene.lua b/Plugins/Sheets/Coyote and Crow/sdk/scene.lua
new file mode 100644
index 00000000..ff21abba
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/scene.lua
@@ -0,0 +1,13 @@
+local _SceneLib = require("delayedLoad.dlua").new("sceneCore.dlua");
+local _SceneWrapperLib = nil;
+
+function _INTERNAL_export_getSceneObjectFromID(objectID)
+ if _SceneWrapperLib == nil then
+ _SceneWrapperLib = require("sceneWrappers.dlua");
+ end;
+
+ return _SceneWrapperLib.objectFromID(objectID);
+end;
+
+SceneLib = _SceneLib;
+return _SceneLib;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/sceneCore.dlua b/Plugins/Sheets/Coyote and Crow/sdk/sceneCore.dlua
new file mode 100644
index 00000000..c0651997
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/sceneCore.dlua
@@ -0,0 +1,146 @@
+local Objs = require("rrpgObjs.lua")
+local SceneWrappers = require("sceneWrappers.dlua");
+require("utils.lua");
+require("rrpg.lua");
+
+local SceneLib = {};
+local LocalSceneLib = {};
+
+
+-- OBJETO SC3PLUGIN
+
+local __runningPlugins = {};
+
+function LocalSceneLib.newPlugin()
+ local handle = _obj_newObject('TSC3LuaPlugin');
+ local o = Objs.objectFromHandle(handle);
+
+
+ Objs.registerHandle(handle, o);
+ return o;
+end;
+
+-- Funções públicas da SceneLib
+
+function SceneLib.registerPlugin(attachCallback)
+ local plug = LocalSceneLib.newPlugin();
+ local pluginAttachments = {};
+
+ __runningPlugins[plug.handle] = plug;
+
+ setTimeout(
+ function()
+ if __runningPlugins[plug.handle] ~= nil then
+ _obj_invoke(plug.handle, "RegisterYourself");
+ end;
+ end, 1);
+
+ local function startAttachToScene(scene)
+ local oID = scene.objectID;
+ local att = pluginAttachments[oID];
+
+ if att ~= nil then
+ return;
+ end;
+
+ att = Objs.objectFromHandle(_obj_invoke(plug.handle, "LuaCreatePluginAttachment", oID));
+
+ if att ~= nil then
+ Objs.registerHandle(att.handle, att);
+
+ local eves = att.eves;
+
+ if eves == nil then
+ att.eves = {};
+ eves = att.eves;
+ end;
+
+ eves["OnDettach"] = "";
+
+ pluginAttachments[oID] = att;
+
+ if attachCallback ~= nil then
+ setTimeout(function()
+ if scene ~= nil and scene.isObjectAlive then
+ attachCallback(scene, att);
+ end;
+ end, 1)
+ end;
+ end;
+ end;
+
+ local function startDettachFromScene(scene)
+ local oID = scene.objectID;
+ local att = pluginAttachments[oID];
+
+ if att ~= nil then
+ pluginAttachments[oID] = nil;
+ end;
+ end;
+
+ -- Anexar aos scenes já rodando...
+ local scenes = SceneLib.getLoadedScenes();
+
+ for i = 1, #scenes, 1 do
+ startAttachToScene(scenes[i]);
+ end;
+
+ -- Instalar listeners para detectar novos scenes rodando
+
+ plug._lstSceneLoaded = RRPG.listen('SC3SceneLoaded',
+ function(msg)
+ if msg.scene ~= nil then
+ startAttachToScene(msg.scene);
+ msg.scene = nil;
+ end;
+ end);
+
+ plug._lstSceneUnloaded = RRPG.listen('SC3SceneUnloaded',
+ function(msg)
+ if msg.scene ~= nil then
+ startDettachFromScene(msg.scene);
+ msg.scene = nil;
+ end;
+ end);
+
+ return plug.handle;
+end;
+
+function SceneLib.unregisterPlugin(pluginHandle)
+ local plug = __runningPlugins[pluginHandle];
+
+ if plug ~= nil then
+ if plug._lstSceneUnloaded ~= nil then
+ RRPG.unlisten(plug._lstSceneUnloaded);
+ plug._lstSceneUnloaded = nil;
+ end;
+
+ if plug._lstSceneLoaded ~= nil then
+ RRPG.unlisten(plug._lstSceneLoaded);
+ plug._lstSceneLoaded = nil;
+ end;
+
+ _obj_invoke(plug.handle, "UnregisterYourself");
+ __runningPlugins[pluginHandle] = nil;
+ _obj_invoke(plug.handle, "DettachAllAttachments");
+ end;
+end;
+
+function SceneLib.getLoadedScenes()
+ local L = _scene3_GetLoadedScenesObjectIDs();
+
+ for i = 1, #L, 1 do
+ L[i] = SceneWrappers.objectFromID(L[i]);
+ end;
+
+ return L;
+end;
+
+
+SceneLib.Math = {};
+
+SceneLib.Math.newRotationMatrix = _scene3_math_newRotationMatrix;
+SceneLib.Math.transformPoint = _scene3_math_transformPoint;
+SceneLib.Math.rotatePoint = _scene3_math_rotatePoint;
+
+return SceneLib;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/sceneWrappers.dlua b/Plugins/Sheets/Coyote and Crow/sdk/sceneWrappers.dlua
new file mode 100644
index 00000000..d93f30c7
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/sceneWrappers.dlua
@@ -0,0 +1,1123 @@
+local Objs = require("rrpgObjs.lua");
+local objs = Objs;
+local NDB = require("ndb.lua");
+local GUI = nil;
+
+local _userDataScopeAttr = '__userDataScope';
+
+local SceneWrappers = {};
+
+local _localStrongRefSceneObjects = {};
+
+--- [[ Wrapper Object BASE ]]
+local function initWrappedObjectFromHandle(handle)
+ local wObj = Objs.objectFromHandle(handle);
+
+ if (wObj.props == nil) then
+ wObj.props = {};
+ end;
+
+ function wObj:getObjectID() return _obj_getProp(self.handle, "ObjectID"); end;
+ function wObj:getObjectType() return _obj_getProp(self.handle, "WrappedObjectType"); end;
+ function wObj:getIsObjectAlive() return _obj_getProp(self.handle, "IsObjectAlive"); end;
+ function wObj:isType(typeName) return _scene3_IsWrapperOfType(self.handle, typeName); end;
+ function wObj:beginUpdate() _obj_invoke(self.handle, "BeginUpdate"); end;
+ function wObj:endUpdate() _obj_invoke(self.handle, "EndUpdate"); end;
+ function wObj:getUserData() return _obj_invokeEx(self.handle, "GetUserData"); end;
+
+ function wObj:newUserDataLink(field)
+ if GUI == nil then
+ GUI = require("gui.lua");
+ end;
+
+ local dataScope = rawget(self, _userDataScopeAttr);
+
+ if dataScope == nil then
+ dataScope = Objs.hierarchyObjectFromHandle(_obj_newObject("nonVisualDataScope"));
+ rawset(self, _userDataScopeAttr, dataScope);
+ _obj_invokeEx(self.handle, "PrepareUserDataScope", dataScope.handle);
+ end
+
+ local dl = GUI.newDataLink();
+
+ if field ~= nil then
+ dl.field = field;
+ end;
+
+ dl:setParent(dataScope);
+ return dl;
+ end;
+
+ wObj.props["objectType"] = {getter = "getObjectType", tipo = "string"};
+ wObj.props["isObjectAlive"] = {getter = "getIsObjectAlive", tipo = "bool"};
+ wObj.props["objectID"] = {getter = "getObjectID", tipo = "int"};
+ wObj.props["userData"] = {getter = "getUserData", tipo = "table"};
+
+ rawset(wObj, "objectID", wObj:getObjectID());
+ return wObj;
+end;
+
+--- [[ Wrapper Object SCENE ]]
+
+local __sceneProps = {worldWidth = {tipo = "double", readProp = "WorldWidth", writeProp = "WorldWidth"},
+ worldHeight = {tipo = "double", readProp = "WorldHeight", writeProp = "WorldHeight"},
+ worldMetricName = {tipo = "string", readProp = "WorldMetricName", writeProp = "WorldMetricName"},
+ bkgColor = {tipo = "color", readProp = "BkgColor", writeProp = "BkgColor"},
+ bkgImageURL = {tipo = "string", readProp="BkgImageURL", writeProp = "BkgImageURL"},
+ workingLayer = {tipo = "enum", readProp = "WorkingLayer", writeProp = "WorkingLayer", values={"background", "objects", "tokens"}},
+ viewport = {tipo = "table", getter=function(obj) return SceneWrappers.objectFromID(_scene3_getViewportObjectIDOfScene(obj.objectID)); end;},
+ grid = {tipo = "table", getter=function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "GridLayerObjectID")); end;},
+ items = {tipo = "table", getter=function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "ItemsObjectID")); end},
+ fogOfWar = {tipo = "table", getter=function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "FogOfWarObjectID")); end},
+ isGM = {tipo="bool", readProp="IsGM"},
+ currentUserID = {tipo="string", readProp="CurrentUserID"},
+ isViewingAsGM = {tipo="bool", readProp="IsViewingAsGM", writeProp = "IsViewingAsGM"},
+ isViewingWalls = {tipo="bool", readProp="IsViewingWalls", writeProp = "IsViewingWalls"},
+ renderAsPlayer = {tipo="bool", readProp="RenderAsPlayer"}};
+
+local __sceneEvents = {onWorkingLayerChange="",
+ onGMStateChange=""};
+
+local __sceneMethods = {
+ newTransaction = function(scene)
+ local tr = Objs.objectFromHandle(_obj_newObject("TLuaScene3Transaction"));
+ Objs.registerHandle(tr.handle, tr);
+ _obj_invoke(tr.handle, "Initialize", scene.objectID);
+
+ tr.commit = function(trObj)
+ _obj_invoke(trObj.handle, "Commit");
+ end;
+
+ tr.rollback = function(trObj)
+ _obj_invoke(trObj.handle, "Rollback");
+ end;
+
+ tr.createUndoData = function (trObj)
+ local handle = _obj_invoke(trObj.handle, "CreateUndoData");
+ local obj = objs.objectFromHandle(handle);
+ objs.registerHandle(handle, obj);
+ return obj;
+ end;
+
+ tr.applyUndoData = function(trObj, undoData)
+ _obj_invoke(trObj.handle, "ApplyUndoData", undoData.handle);
+ end;
+
+ return tr;
+ end,
+
+ pushTransaction = function(scene, transaction)
+ local trHandle;
+
+ if transaction ~= nil then
+ trHandle = transaction.handle or 0;
+ else
+ trHandle = 0;
+ end;
+
+ _obj_invoke(scene.handle, "PushTransaction", trHandle);
+ end,
+
+ popTransaction = function(scene)
+ _obj_invoke(scene.handle, "PopTransaction");
+ end,
+
+ processCommand = function(scene, command)
+ return _obj_invokeEx(scene.handle, "ProcessCommand", command);
+ end,
+
+ broadcastMessage = function(scene, messageId, message, loopBack)
+ local node = _obj_invokeEx(scene.handle, "LuaGetSceneNode");
+
+ if node ~= nil then
+ return NDB.broadcastMessage(node, messageId, message, loopBack);
+ end;
+ end,
+
+ newBroadcastListener = function(scene, messageId, callback)
+ local node = _obj_invokeEx(scene.handle, "LuaGetSceneNode");
+
+ if node ~= nil then
+ return NDB.newBroadcastListener(node, messageId,
+ function(sender, returnedMessageId, message)
+ if scene.isObjectAlive and (callback ~= nil) then
+ callback(sender, returnedMessageId, message);
+ end;
+ end);
+ end;
+ end,
+
+ sendDelayedUpdates = function(scene)
+ return _obj_invoke(scene.handle, "SendDelayedUpdates");
+ end
+
+ };
+
+local function initWrappedSceneFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ for k, v in pairs(__sceneProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__sceneMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __sceneEvents;
+ return wObj;
+end;
+
+--- [[ Wrapper Object VIEWPORT ]]
+
+local __viewportProps = {width = {tipo = "double", readProp = "Width"},
+ height = {tipo = "double", readProp = "Height"},
+ worldX = {tipo = "double", readProp = "WorldX", writeProp = "WorldX"},
+ worldY = {tipo = "double", readProp = "WorldY", writeProp = "WorldY"},
+ scale = {tipo = "double", readProp = "Scale", writeProp = "Scale"},
+ cursor = {tipo = "enum", readProp = "Cursor", writeProp = "Cursor"},
+ scene = {tipo = "table", getter = function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "SceneObjectID")); end;}};
+
+local __viewportMethods = {screenToWorld =
+ function(vp, screenX, screenY)
+ return _obj_invokeEx(vp.handle, "ScreenToWorld", screenX, screenY);
+ end,
+
+ worldToScreen =
+ function (vp, worldX, worldY)
+ return _scene3_ViewPort_WorldToScreen(vp.handle, worldX, worldY);
+ end,
+
+ getScrollBounds = function(vp) return _obj_invokeEx(vp.handle, "GetScrollBounds"); end;
+
+ setupToolCategory =
+ function(vp, name, title, order)
+ _obj_invoke(vp.handle, "SetupToolCategory", tostring(name), tostring(title), tonumber(order));
+ end,
+
+ addToolButton =
+ function (vp, categoryName, title, iconURL, order, options, callback, deactivationCallback)
+ if type(options) ~= "table" then
+ options = {};
+ end;
+
+ local hBtn = _obj_newObject("SC3ToolButton");
+ local o = Objs.objectFromHandle(hBtn);
+ Objs.registerHandle(hBtn, o);
+
+ if callback ~= nil then
+ o:listen("OnCallback", callback);
+ end;
+
+ if deactivationCallback ~= nil then
+ o:listen("OnDeactivationCallback", deactivationCallback);
+ end;
+
+ _obj_invoke(hBtn, "SetViewport", vp.objectID);
+ _obj_invokeEx(hBtn, "SetupButton", categoryName, title, iconURL, order, options);
+
+ local tblTools = rawget(vp, "_TblTools");
+
+ if tblTools == nil then
+ tblTools = {};
+ rawset(vp, "_TblTools", tblTools);
+ end;
+
+ local genID = (tblTools.generator or 0) + 1;
+ tblTools.generator = genID;
+
+ tblTools[genID] = o;
+ return genID;
+ end,
+
+ removeToolButton =
+ function (vp, toolID)
+ local tblTools = rawget(vp, "_TblTools");
+
+ if tblTools ~= nil then
+ local o = tblTools[toolID];
+
+ if o ~= nil then
+ _obj_invoke(o.handle, "RemoveButton");
+ tblTools[toolID] = nil;
+ end;
+ end;
+ end,
+
+ checkToolButton = function(vp, toolID, checked)
+ local tblTools = rawget(vp, "_TblTools");
+
+ if tblTools ~= nil then
+ local o = tblTools[toolID];
+
+ if o ~= nil then
+ if checked == nil then
+ checked = true;
+ end;
+
+ _obj_invoke(o.handle, "CheckToolButton", not not checked);
+ end;
+ end;
+ end,
+
+ isToolButtonChecked = function(vp, toolID)
+ local tblTools = rawget(vp, "_TblTools");
+
+ if tblTools ~= nil then
+ local o = tblTools[toolID];
+
+ if o ~= nil then
+ return _obj_getProp(o.handle, "IsChecked");
+ end;
+ end;
+
+ return false;
+ end,
+
+ selectToolButton = function(vp, toolID)
+ local tblTools = rawget(vp, "_TblTools");
+
+ if tblTools ~= nil then
+ local o = tblTools[toolID];
+
+ if o ~= nil then
+ _obj_invoke(o.handle, "Select");
+ end;
+ end;
+ end,
+
+ selectDefaultToolButton = function(vp)
+ _obj_invoke(vp.handle, "SelectDefaultToolButton");
+ end,
+
+ needRepaint = function (vp)
+ _obj_invoke(vp.handle, "NeedRepaint");
+ end,
+
+ showForm = function(vp, form, options)
+ if (form == nil) then
+ error("invalid parameter - form is nil");
+ return false;
+ end;
+
+ if type(options) ~= "table" then
+ options = {};
+ end;
+
+ local _popupFormShowers = vp._popupFormShowers;
+
+ if _popupFormShowers == nil then
+ _popupFormShowers = {};
+ setmetatable(_popupFormShowers, {__mode="k"}); -- popupFormShowers possui chaves weak-reference
+ vp._popupFormShowers = _popupFormShowers;
+ end;
+
+ local popupShower = _popupFormShowers[form];
+
+ if popupShower == nil then
+ popupShower = Objs.objectFromHandle(_obj_newObject('TSC3ViewportFormShower'));
+ Objs.registerHandle(popupShower.handle, popupShower);
+ _popupFormShowers[form] = popupShower;
+
+ _obj_invoke(popupShower.handle, "SetFormHandle", form.handle);
+ end;
+
+ local closeListenerId = rawget(popupShower, "__closeListenerID");
+
+ if closeListenerId ~= nil then
+ popupShower:removeEventListener(closeListenerId);
+ rawset(popupShower, "__closeListenerID", nil);
+ end;
+
+ if type(options.onClose) == "function" then
+ closeListenerId = popupShower:addEventListener("OnPopupClose", options.onClose);
+ rawset(popupShower, "__closeListenerID", closeListenerId);
+ end;
+
+ _obj_setProp(popupShower.handle, "PopupPlacement", options.placement);
+ return _obj_invoke(popupShower.handle, "Show", vp.handle);
+ end,
+
+ closeForm = function(vp, form)
+ local _popupFormShowers = vp._popupFormShowers;
+
+ if type(form) == "table" and _popupFormShowers ~= nil then
+ local v = _popupFormShowers[form];
+
+ if v ~= nil then
+ _popupFormShowers[form] = nil;
+ return _obj_invoke(v.handle, "Close");
+ end;
+ else
+ return false;
+ end;
+ end
+ };
+
+local __viewportEvents = {onChange = "",
+ onMouseDown = "event",
+ onMouseUp = "event",
+ onMouseMove = "event",
+ onMouseWheel = "event",
+ onMouseDblClick = "event",
+ onFallbackMouseWheel = "event",
+ onGestureBeginZoom = "x, y",
+ onGestureZoom = "x, y, delta",
+ onGestureEndZoom = "x, y",
+ onGestureBeginRotation = "x, y",
+ onGestureRotation = "x, y, angle",
+ onGestureEndRotation = "x, y",
+ onGestureBeginPan = "x, y",
+ onGesturePan = "x, y",
+ onGestureEndPan = "x, y",
+ onGestureLongTap = "x, y";
+ onKeyDown = "event",
+ onKeyUp = "event",
+ onBeforeDrawBkgLayer="",
+ onBeforeDrawGridLayer="",
+ onBeforeDrawObjsLayer="",
+ onBeforeDrawTokensLayer="",
+ onAfterDrawLayers="",
+ onStartDrop="drop, x, y, drag"};
+
+local __viewportRenderMethods = {
+ prepareFill = _scene3_gfx_prepareFill,
+ fillRect = _scene3_gfx_fillRect,
+ fillEllipse = _scene3_gfx_fillEllipse,
+ fillPolygon = _scene3_gfx_fillPolygon,
+ fillACell = function(vp, i, j, opacity) _scene3_gfx_fillACell(vp.handle, i, j, opacity); end,
+ prepareDraw = _scene3_gfx_prepareDraw,
+ drawRect = _scene3_gfx_drawRect,
+ drawEllipse = _scene3_gfx_drawEllipse,
+ drawLine = _scene3_gfx_drawLine,
+ prepareFont = _scene3_gfx_prepareFont,
+ textSize = _scene3_gfx_textSize,
+ fillText = _scene3_gfx_fillText,
+ fillTextFit = _scene3_gfx_fillTextFit,
+ pushRenderState = _scene3_gfx_pushState,
+ popRenderState = _scene3_gfx_popState,
+ pushRotationTransform = _scene3_gfx_pushRotationTransform,
+ pushWorldToScreenTransform = function(vp) _scene3_gfx_pushWorldToScreenTransform(vp.handle) end,
+ popTransform = _scene3_gfx_popTransform
+ };
+
+local function initWrappedViewportFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ for k, v in pairs(__viewportProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__viewportMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ for k, v in pairs(__viewportRenderMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __viewportEvents;
+
+ return wObj;
+end;
+
+
+--- [[ Wrapper Object GRIDLayer ]]
+
+local __gridLayerProps = {gridType = {tipo = "enum", readProp = "GridType", writeProp="GridType", values={"square", "vertHex", "horzHex"}},
+ offsetX = {tipo = "double", readProp = "OffsetX", writeProp = "OffsetX"},
+ offsetY = {tipo = "double", readProp = "OffsetY", writeProp = "OffsetY"},
+ cellSize = {tipo = "double", readProp = "CellSize", writeProp = "CellSize"},
+ gridColor = {tipo = "color", readProp = "GridColor", writeProp = "GridColor"},
+ grickThickness = {tipo = "double", readProp = "GridThickness", writeProp = "GridThickness"},
+ drawGrid = {tipo = "bool", readProp = "DrawGrid", writeProp = "DrawGrid"},
+ rowCount = {tipo = "int", readProp = "RowCount"},
+ colCount = {tipo = "int", readProp = "ColumnCount"},
+ squareDiagonals = {tipo="enum", readProp = "SquareDiagonals", writeProp="SquareDiagonals", values={"simplified", "manhattan", "alternated", "euclidean"}},
+ scene = {tipo = "table", getter = function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "SceneObjectID")); end;}};
+
+local __gridLayerMethods = {cellToWorld =
+ function(grid, i, j)
+ return _obj_invokeEx(grid.handle, "GetCellCenter", i, j);
+ end,
+
+ worldToCell =
+ function (grid, worldX, worldY)
+ return _obj_invokeEx(grid.handle, "GetGridCellAtPos", worldX, worldY);
+ end,
+
+ shortestPath = function (grid, srcI, srcJ, destI, destJ, options)
+ if (options ~= nil) and type(options) ~= "table" then
+ options = nil;
+ end;
+
+ return _obj_invokeEx(grid.handle, "ShortestPath", srcI, srcJ, destI, destJ, options);
+ end};
+
+local __gridLayerEvents = {onChange = ""};
+
+local function initWrappedGridLayerFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ for k, v in pairs(__gridLayerProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__gridLayerMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __gridLayerEvents;
+
+ return wObj;
+end;
+
+--- [[ Wrapper Object GraphicItemList ]]
+
+local __GIL_Selection = "_xx_selection";
+
+local __GILProps = {count = {tipo = "int", readProp = "Count"},
+ selection = {tipo="table", getter="getSelection"}};
+
+local __GILMethods = { get = function(t, idx)
+ local objID = _obj_invoke(t.handle, "GetItemObjectID", idx - 1);
+ local o = SceneWrappers.objectFromID(objID);
+
+ if o == nil then
+ error("Invalid Scene GraphicItem Index");
+ else
+ return o;
+ end;
+ end,
+
+ enumInRect = function(t, rect, layer)
+ local retObjs = _obj_invokeEx(t.handle, "EnumInRect", rect, layer);
+
+ for i = 1, #retObjs, 1 do
+ retObjs[i] = SceneWrappers.objectFromID(retObjs[i]);
+ end;
+
+ return retObjs;
+ end,
+
+ enumAtPoint = function(t, worldX, worldY, layer)
+ local retObjs = _obj_invokeEx(t.handle, "EnumInPoint", worldX, worldY, layer);
+
+ for i = 1, #retObjs, 1 do
+ retObjs[i] = SceneWrappers.objectFromID(retObjs[i]);
+ end;
+
+ return retObjs;
+ end,
+
+ itemAtPoint = function(t, worldX, worldY, layer)
+ local retObjs = t:enumAtPoint(worldX, worldY, layer);
+
+ if #retObjs > 0 then
+ return retObjs[#retObjs];
+ else
+ return nil;
+ end;
+ end,
+
+ getSelection = function(t)
+ local ss;
+
+ ss = rawget(t, __GIL_Selection);
+
+ if ss ~= nil then
+ return ss;
+ end;
+
+ ss = _obj_invokeEx(t.handle, "EnumSelection");
+
+ for i = 1, #ss, 1 do
+ ss[i] = SceneWrappers.objectFromID(ss[i]);
+ end;
+
+ rawset(t, __GIL_Selection, ss);
+ return ss;
+ end,
+
+ clearSelection = function(t)
+ local ss = t.selection;
+
+ for k, v in pairs(ss) do
+ v.selected = false;
+ end;
+ end,
+
+ addToken = function(t, layer)
+ return SceneWrappers.objectFromID(_obj_invokeEx(t.handle, "AddToken", layer));
+ end;
+
+ addUserDrawing = function(t, layer)
+ return SceneWrappers.objectFromID(_obj_invokeEx(t.handle, "AddUserDrawing", layer));
+ end;
+ };
+
+local __GILEvents = {onChange = "",
+ onItemAdded="item",
+ onItemRemoved="item",
+ onItemSelected="item",
+ onItemDeselected="item",
+ onItemLayerChange="item"};
+local __GILMetatable = nil;
+
+local function initialize_GILMetatable(mtbase)
+ __GILMetatable = {};
+ local oldIndexMT = mtbase.__index;
+ local oldNewIndexMT = mtbase.__newindex;
+
+ for k, v in pairs(mtbase) do
+ __GILMetatable[k] = v;
+ end
+
+ __GILMetatable.__len = function(t)
+ return _obj_getProp(t.handle, "Count");
+ end;
+
+ __GILMetatable.__index = function(t, k)
+ if type(k) == "number" then
+ local objID = _obj_invoke(t.handle, "GetItemObjectID", k - 1);
+ local o = SceneWrappers.objectFromID(objID);
+
+ if o == nil then
+ error("Invalid Scene GraphicItem Index");
+ else
+ return o;
+ end;
+ elseif oldIndexMT ~= nil then
+ return oldIndexMT(t, k);
+ else
+ return rawget(t, k);
+ end;
+ end;
+
+ __GILMetatable.__newindex = function(t, k, v)
+ if type(k) == "number" then
+ error("Scene Graphic Item Index: Read-Only property");
+ elseif oldNewIndexMT ~= nil then
+ return oldNewIndexMT(t, k, v);
+ else
+ rawset(t, k, v);
+ end;
+ end;
+end;
+
+local function initWrappedGraphicItemListFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ if __GILMetatable == nil then
+ initialize_GILMetatable(getmetatable(wObj));
+ end;
+
+ setmetatable(wObj, __GILMetatable);
+
+ for k, v in pairs(__GILProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__GILMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __GILEvents;
+
+ -- Resetar o cache do selection
+ wObj:listen("OnItemSelected", function() rawset(wObj, __GIL_Selection, nil); end);
+ wObj:listen("OnItemDeselected", function() rawset(wObj, __GIL_Selection, nil); end);
+ return wObj;
+end;
+
+--- [[ Wrapper Object GraphicItem ]]
+
+local __graphicItemProps = {width = {tipo = "double", readProp = "Width", writeProp="Width"},
+ height = {tipo = "double", readProp = "Height", writeProp = "Height"},
+ x = {tipo = "double", readProp = "X", writeProp = "X"},
+ y = {tipo = "double", readProp = "Y", writeProp = "Y"},
+ z = {tipo = "double", readProp = "Z", writeProp = "Z"},
+ rotation = {tipo = "double", readProp = "Rotation", writeProp = "Rotation"},
+ visible = {tipo = "bool", readProp = "Visible", writeProp = "Visible"},
+ snapToGrid = {tipo = "bool", readProp = "SnapToGrid", writeProp="SnapToGrid"},
+ locked = {tipo = "bool", readProp = "Locked", writeProp = "Locked"},
+ selected = {tipo = "bool", readProp = "Selected", writeProp = "Selected"},
+ isHover = {tipo = "bool", readProp = "IsHover", writeProp = "IsHover"},
+ layer = {tipo = "enum", readProp = "Layer", writeProp = "Layer", values={"background", "objects", "token"}},
+ isMine = {tipo = "bool", readProp = "IsMine"},
+ canBeRendered = {tipo = "bool", readProp = "CanBeRendered"},
+ ownerUserID = {tipo = "string", readProp = "OwnerUserID", writeProp="OwnerUserID"},
+ canvas = {tipo = "table", getter = function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "CanvasObjectID")); end;},
+ scene = {tipo = "table", getter = function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "SceneObjectID")); end;}};
+
+local __graphicItemMethods = {getCenter =
+ function(t, snapToGrid)
+ return _obj_invokeEx(t.handle, "GetCenter", snapToGrid);
+ end,
+
+ setCenter =
+ function (t, worldX, worldY, snapToGrid)
+ return _obj_invokeEx(t.handle, "SetCenter", worldX, worldY, snapToGrid);
+ end,
+
+ getBounds =
+ function(t)
+ return _scene3_GraItem_getBounds(t.objectID);
+ end,
+
+ setBounds = function(t, left, top, right, bottom, rotation)
+ return _scene3_GraItem_setBounds(t.objectID, left, top, right, bottom, rotation);
+ end,
+
+ getCellsOccupied = function (t)
+ return _obj_invokeEx(t.handle, "GetCellsOccupied");
+ end,
+
+ compareZOrder = function(t, otherItem)
+ return _obj_invokeEx(t.handle, "CompareZOrder", otherItem.handle);
+ end,
+
+ delete = function(t) _obj_invoke(t.handle, "Delete"); end,
+
+ doSnapToGrid = function(t) _obj_invoke(t.handle, "DoSnapToGrid"); end;
+ };
+
+local __graphicItemEvents = {onChange = "",
+ onBeforeDraw = "",
+ onAfterDraw = "",
+ onBoundsChange = "item"};
+
+local function initWrappedGraphicItemFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ for k, v in pairs(__graphicItemProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__graphicItemMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __graphicItemEvents;
+
+ return wObj;
+end;
+
+
+--- [[ Wrapper Object Token ]]
+
+local __tokenItemProps = {facingMode = {tipo = "enum", readProp = "FacingMode", writeProp="FacingMode", values={"rotate", "arrow"}},
+ ownerCharacter = {tipo = "int", readProp = "OwnerCharacter", writeProp="OwnerCharacter"},
+ friendOrFoe = {tipo = "enum", readProp = "FriendOrFoe", writeProp="FriendOrFoe", values={"unknown", "friend", "neutral", "foe"}},
+ name = {tipo="string", readProp="Name", writeProp="Name"},
+ visionIntenseLightRange = {tipo = "double", readProp = "VisIntenseLightRange", writeProp="VisIntenseLightRange"},
+ visionWeakLightRange = {tipo = "double", readProp = "VisWeakLightRange", writeProp="VisWeakLightRange"},
+ visionDarknessRange = {tipo = "double", readProp = "VisDarkRange", writeProp="VisDarkRange"},
+ visionAngle = {tipo = "double", readProp = "VisionAngle", writeProp="VisionAngle"},
+ visionHaveVision = {tipo = "bool", readProp = "VisHaveVision", writeProp="VisHaveVision"},
+ lightIntenseRange = {tipo = "double", readProp = "LightIntenseRange", writeProp="LightIntenseRange"},
+ lightWeakRange = {tipo = "double", readProp = "LightWeakRange", writeProp="LightWeakRange"},
+ lightAngle = {tipo = "double", readProp = "LightAngle", writeProp="LightAngle"},
+ image = {tipo = "table", getter = function(obj) return SceneWrappers.objectFromID(_obj_getProp(obj.handle, "ImageOpObjectID")); end;}
+ };
+
+for i = 1, 3, 1 do
+ __tokenItemProps["barValue" .. i] = {tipo="string",
+ getter = function(obj) return _obj_invoke(obj.handle, "GetBarValue", i - 1); end,
+ setter = function(obj, value) _obj_invoke(obj.handle, "SetBarValue", i - 1, value); end};
+
+ __tokenItemProps["barMax" .. i] = {tipo="string",
+ getter = function(obj) return _obj_invoke(obj.handle, "GetBarMax", i - 1); end,
+ setter = function(obj, value) _obj_invoke(obj.handle, "SetBarMax", i - 1, value); end};
+
+ __tokenItemProps["barColor" .. i] = {tipo="color",
+ getter = function(obj) return _obj_invoke(obj.handle, "GetBarColor", i - 1); end,
+ setter = function(obj, value) _obj_invoke(obj.handle, "SetBarColor", i - 1, value); end};
+end;
+
+local __tokenMethods = {clearMemoryAreas = function(t) _obj_invoke(t.handle, "ClearMemoryAreas"); end
+ };
+local __tokenEvents = {};
+
+for k, v in pairs(__graphicItemEvents) do
+ __tokenEvents[k] = v;
+end;
+
+ __tokenEvents.onChange = "";
+
+local function initWrappedTokenFromHandle(handle)
+ local wObj = initWrappedGraphicItemFromHandle(handle);
+
+ for k, v in pairs(__tokenItemProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__tokenMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __tokenEvents;
+
+ return wObj;
+end;
+
+--- [[ Wrapper UserDrawing ]]
+
+local __userDrawingItemProps = {};
+
+local __userDrawingMethods = {
+ markAsMyDrawing =
+ function(t)
+ local scene = t.scene;
+
+ if scene ~= nil then
+ if scene.isGM then
+ t.ownerUserID = '';
+ else
+ t.ownerUserID = scene.currentUserID;
+ end;
+ end;
+ end
+ };
+local __userDrawingEvents = {};
+
+for k, v in pairs(__graphicItemEvents) do
+ __userDrawingEvents[k] = v;
+end;
+
+local function initWrappedUerDrawingFromHandle(handle)
+ local wObj = initWrappedGraphicItemFromHandle(handle);
+
+ for k, v in pairs(__userDrawingItemProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__userDrawingMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __userDrawingEvents;
+ return wObj;
+end;
+
+--- [[ Wrapper Object Persisted Canvas ]]
+
+local __PerCanvasProps = {opCount = {tipo = "int", readProp = "OpCount"}};
+
+
+local __PerCanvasMethods = {getOp = function(t, idx)
+ return SceneWrappers.objectFromID(_obj_invoke(t.handle, "GetOpObjectID", idx));
+ end,
+
+ addBitmap = function(t)
+ return SceneWrappers.objectFromID(_obj_invoke(t.handle, "AddBitmapOpObjectID"));
+ end,
+
+ addPath = function(t)
+ return SceneWrappers.objectFromID(_obj_invoke(t.handle, "AddPathOpObjectID"));
+ end,
+
+ addText = function(t)
+ return SceneWrappers.objectFromID(_obj_invoke(t.handle, "AddTextOpObjectID"));
+ end,
+
+ findByName = function(t, name)
+ return SceneWrappers.objectFromID(_obj_invokeEx(t.handle, "FindByName", tostring(name)));
+ end,
+
+ clear = function(t) _obj_invoke(t.handle, "Clear"); end;
+ };
+
+local __PerCanvasEvents = {onChange = ""};
+
+local function initWrappedPerCanvasFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ for k, v in pairs(__PerCanvasProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__PerCanvasMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __PerCanvasEvents;
+
+ return wObj;
+end;
+
+
+--- [[ Wrapper Object DrawingOp ]]
+
+local __DOPBaseProps = {x = {tipo = "double", readProp = "X", writeProp="X"},
+ y = {tipo = "double", readProp = "Y", writeProp="Y"},
+ z = {tipo = "double", readProp = "Z", writeProp="Z"},
+ width = {tipo = "double", readProp = "Width", writeProp="Width"},
+ height = {tipo = "double", readProp = "Height", writeProp="Height"},
+ rotMode = {tipo = "enum", readProp="RotMode", writeProp = "RotMode", values={"default", "ignoreCanvasRot"}},
+ name = {tipo = "string", readProp = "Name", writeProp="Name"},
+ opacity = {tipo = "double", readProp = "Opacity", writeProp="Opacity"},
+ visibility = {tipo = "enum", readProp = "Visibility", writeProp="Visibility", values={"everyone", "gmOnly"}},
+ rotation = {tipo="double", readProp="Rotation", writeProp="Rotation"},
+ rotCenterX = {tipo="double", readProp="RotCenterX", writeProp="RotCenterX"},
+ rotCenterY = {tipo="double", readProp="RotCenterY", writeProp="RotCenterY"},
+ drawingTrigger = {tipo="set", readProp="DrawingTrigger", writeProp="DrawingTrigger", values={"hover", "selected"}},
+ outOfOrderMode = {tipo="enum", readProp="OutOfOrderMode", writeProp="OutOfOrderMode", values={"noOutOfOrder", "afterFogOfWarLayer", "beforeOwnerLayer", "afterOwnerLayer"}},
+ xMetric = {tipo="enum", readProp="XMetric", writeProp="XMetric", values={"screenMetric", "worldMetric", "canvasMetric", "cellMetric"}},
+ yMetric = {tipo="enum", readProp="YMetric", writeProp="YMetric", values={"screenMetric", "worldMetric", "canvasMetric", "cellMetric"}},
+ widthMetric = {tipo="enum", readProp="WidthMetric", writeProp="WidthMetric", values={"screenMetric", "worldMetric", "canvasMetric", "cellMetric"}},
+ heightMetric = {tipo="enum", readProp="HeightMetric", writeProp="HeightMetric", values={"screenMetric", "worldMetric", "canvasMetric", "cellMetric"}},
+ xOrigin = {tipo = "double", readProp = "XOrigin", writeProp="XOrigin"},
+ yOrigin = {tipo = "double", readProp = "YOrigin", writeProp="YOrigin"}
+ };
+
+local __DOPBaseMethods = {delete = function(t)
+ _obj_invoke(t.handle, "Delete");
+ end
+ };
+
+local __DOPBaseEvents = {onChange = ""};
+
+local function initWrappedDrawingOpBaseFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ for k, v in pairs(__DOPBaseProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__DOPBaseMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __DOPBaseEvents;
+
+ return wObj;
+end;
+
+
+--- [[ Wrapper Object DrawingOpBitmap ]]
+
+local __DOPBitmapProps = {url = {tipo = "string", readProp = "URL", writeProp="URL"},
+ flipHorz = {tipo = "bool", readProp="FlipHorz", writeProp = "FlipHorz"},
+ flipVert = {tipo = "bool", readProp="FlipVert", writeProp = "FlipVert"},
+ grayscale = {tipo = "bool", readProp="Grayscale", writeProp = "Grayscale"},
+ colorBlend = {tipo = "color", readProp="ColorBlend", writeProp = "ColorBlend"},
+ colorMask = {tipo = "color", readProp="ColorMask", writeProp = "ColorMask"},
+ filterEx = {tipo = "enum", readProp="FilterEx", writeProp = "FilterEx",
+ values={"none", "glow", "innerGlow", "blur", "sepia"}},
+ filterExColor = {tipo = "color", readProp="FilterExColor", writeProp = "FilterExColor"},
+ frame = {tipo = "enum", readProp="Frame", writeProp = "Frame",
+ values={"none", "boton"}},
+ sourceRect = {tipo="table", readProp="SourceRect", writeProp="SourceRect"}};
+
+local __DOPBitmapMethods = {};
+local __DOPBitmapEvents = {onChange = ""};
+
+local function initWrappedDrawingOpBitmapFromHandle(handle)
+ local wObj = initWrappedDrawingOpBaseFromHandle(handle);
+
+ for k, v in pairs(__DOPBitmapProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__DOPBitmapMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __DOPBitmapEvents;
+
+ return wObj;
+end;
+
+--- [[ Wrapper Object DrawingOpPath ]]
+
+local __DOPPathProps = {pathData = {tipo = "string", readProp = "PathData", writeProp="PathData"},
+ data = {tipo = "string", readProp = "PathData", writeProp="PathData"},
+ path = {tipo = "string", readProp = "PathData", writeProp="PathData"},
+ color = {tipo="color", readProp="FillColor", writeProp="FillColor"},
+ strokeColor = {tipo="color", readProp="StrokeColor", writeProp="StrokeColor"},
+ strokeSize = {tipo="double", readProp="StrokeThickness", writeProp="StrokeThickness"},
+ strokeSizeMetric = {tipo="enum", values={"screenMetric", "worldMetric", "canvasMetric", "cellMetric"}, readProp="StrokeThicknessMetric", writeProp="StrokeThicknessMetric"},
+ strokeCap = {tipo="enum", readProp="StrokeCap", writeProp="StrokeCap", values={"flat", "round"}},
+ strokeJoin = {tipo="enum", readProp="StrokeJoin", writeProp="StrokeJoin", values={"miter", "round", "bevel"}},
+ strokeDash = {tipo="enum", readProp="StrokeDash", writeProp="StrokeDash", values={"solid", "dash", "dot", "dashDot", "dashDotDot"}}
+ }
+
+local __DOPPathMethods = {};
+local __DOPPathEvents = {onChange = ""};
+
+local function initWrappedDrawingOpPathFromHandle(handle)
+ local wObj = initWrappedDrawingOpBaseFromHandle(handle);
+
+ for k, v in pairs(__DOPPathProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__DOPPathMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __DOPPathEvents;
+
+ return wObj;
+end;
+
+
+
+--- [[ Wrapper Object DrawingOpText ]]
+
+local __DOPTextProps = {text = {tipo = "string", readProp = "Text", writeProp="Text"},
+ color = {tipo = "color", readProp = "Color", writeProp="Color"},
+ aspect = {tipo = "double", readProp = "Aspect"},
+ fontStyle = {tipo="set", readProp="FontStyle", writeProp="FontStyle"},
+ horzTextAlign = {tipo="enum", readProp="TextAlign", writeProp="TextAlign", values={"leading", "center", "trailing"}},
+ vertTextAlign = {tipo="enum", readProp="VertTextAlign", writeProp="VertTextAlign", values={"leading", "center", "trailing"}}
+ }
+
+local __DOPTextMethods = {};
+local __DOPTextEvents = {};
+
+local function initWrappedDrawingOpTextFromHandle(handle)
+ local wObj = initWrappedDrawingOpBaseFromHandle(handle);
+
+ for k, v in pairs(__DOPTextProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__DOPTextMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __DOPTextEvents;
+
+ return wObj;
+end;
+
+--- [[ Wrapper Object FogOfWar FOW ]]
+
+local __fowProps = {enabled = {tipo="bool", readProp="Enabled", writeProp="Enabled"},
+ ambientLight = {tipo="enum", readProp="AmbientLight", writeProp="AmbientLight", values={"intense", "weak", "none"}},
+ sharingMode = {tipo="enum", readProp="SharingMode", writeProp="SharingMode", values={"individual", "group"}}};
+
+
+local __fowMethods = {setArea = function(t, polygon, areaType)
+ _obj_invokeEx(t.handle, "SetArea", polygon, areaType);
+ end,
+
+ resetAreas = function(t) _obj_invoke(t.handle, "ResetAreas"); end,
+
+ addOpaqueArea = function(t, polygon)
+ _obj_invokeEx(t.handle, "AddOpaqueArea", polygon);
+ end,
+
+ removeOpaqueArea = function(t, polygon)
+ _obj_invokeEx(t.handle, "RemoveOpaqueArea", polygon);
+ end,
+
+ resetOpaqueAreas = function(t) _obj_invoke(t.handle, "ResetOpaqueAreas"); end,
+
+ testCircleMovementCollisionVsOpaqueAreas = function(t, centerX, centerY, r, offsetX, offsetY)
+ return _obj_invokeEx(t.handle, "TestCircleMovementCollisionVsOpaqueAreas", centerX, centerY, r, offsetX, offsetY);
+ end
+
+ };
+
+local __fowEvents = {onChange = ""};
+
+local function initWrappedFogOfWarFromHandle(handle)
+ local wObj = initWrappedObjectFromHandle(handle);
+
+ for k, v in pairs(__fowProps) do
+ wObj.props[k] = v;
+ end;
+
+ for k, v in pairs(__fowMethods) do
+ rawset(wObj, k, v);
+ end;
+
+ wObj.eves = __fowEvents;
+
+ return wObj;
+end;
+
+------------------------------------------
+
+
+local __wrappersInitializers = {
+ token = initWrappedTokenFromHandle,
+ userDrawing = initWrappedUerDrawingFromHandle,
+ graphicItem = initWrappedGraphicItemFromHandle,
+ scene = initWrappedSceneFromHandle,
+ pluginAttachment = initWrappedObjectFromHandle,
+ viewport = initWrappedViewportFromHandle,
+ persistedCanvas = initWrappedPerCanvasFromHandle,
+ gridLayer = initWrappedGridLayerFromHandle,
+ graphicItemList = initWrappedGraphicItemListFromHandle,
+ drawingOpBase = initWrappedDrawingOpBaseFromHandle,
+ opBitmap = initWrappedDrawingOpBitmapFromHandle,
+ opPath = initWrappedDrawingOpPathFromHandle,
+ opText = initWrappedDrawingOpTextFromHandle,
+ fogOfWar = initWrappedFogOfWarFromHandle,
+ }
+
+function SceneWrappers.objectFromID(objectID)
+ if (objectID == nil) or (objectID == 0) then
+ return nil;
+ end;
+
+ local scObj = _localStrongRefSceneObjects[objectID];
+
+ if scObj ~= nil then
+ return scObj;
+ end;
+
+ local objWrapperHandle;
+ objWrapperHandle = _scene3_GetOrCreateObjectWrapperForObjectID(objectID);
+
+ if objWrapperHandle == nil then
+ return nil;
+ end;
+
+ scObj = objs.tryFindFromHandle(objWrapperHandle);
+
+ if scObj ~= nil then
+ if _scene3_IsObjectIDAlive(objectID) then
+ _localStrongRefSceneObjects[objectID] = scObj;
+ end;
+
+ return scObj;
+ end;
+
+ local oType = _scene3_GetWrapperType(objWrapperHandle);
+ local initer = __wrappersInitializers[oType];
+
+ if initer == nil then
+ -- Olhar por um wrapper na herança.
+
+ for k, v in pairs(__wrappersInitializers) do
+ if _scene3_IsWrapperOfType(objWrapperHandle, k) then
+ initer = v;
+ break;
+ end;
+ end;
+
+ if initer == nil then
+ initer = initWrappedObjectFromHandle;
+ end;
+ end;
+
+ scObj = initer(objWrapperHandle);
+ objs.registerHandle(objWrapperHandle, scObj);
+
+ if _scene3_IsObjectIDAlive(objectID) then
+ _localStrongRefSceneObjects[objectID] = scObj;
+ end;
+
+ return scObj;
+end;
+
+function _INTERNAL_EVE_OnWrappedSceneObjectWasDestroyed(objectID)
+ _localStrongRefSceneObjects[objectID] = nil; -- Permitir o Garbage Collector coletar este objeto
+end;
+
+return SceneWrappers;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/sdk3.lang b/Plugins/Sheets/Coyote and Crow/sdk/sdk3.lang
new file mode 100644
index 00000000..e3fdc8c5
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/sdk3.lang
@@ -0,0 +1,11 @@
+[pt]
+sdk3.err.ndb.functionAssign=Tentativa de armazenar uma função Lua na propriedade "%s", porém não é possível salvar funções em NodeDatabases
+sdk3.err.ndb.func.exportToXML.invalidPar=Não foi passado um objeto Nodo válido no parâmetro da função NDB.exportXML
+sdk3.err.ndb.func.importXML.invalidPar=Não foi passado um objeto Nodo válido no primeiro parâmetro da função NDB.importXML
+sdk3.err.ndb.func.copy.invalidPar2=Não foi passado um objeto Nodo válido no segundo parâmetro da função NDB.copy
+
+[en]
+sdk3.err.ndb.functionAssign=Attempting to store a Lua function in the property "%s", but it is not possible to store functions in NodeDatabases
+sdk3.err.ndb.func.exportToXML.invalidPar=A valid Node object was not passed in the NDB.exportXML's first parameter
+sdk3.err.ndb.func.importXML.invalidPar=A valid Node object was not passed in the NDB.importXML's first parameter
+sdk3.err.ndb.func.copy.invalidPar2=A valid Node object was not passed in the NDB.copy's second parameter
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/serpent.dlua b/Plugins/Sheets/Coyote and Crow/sdk/serpent.dlua
new file mode 100644
index 00000000..62f268a6
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/serpent.dlua
@@ -0,0 +1,172 @@
+local function firecastQuotedStr(s)
+ local buildingStr = "";
+
+ for p, c in utf8.codes(s) do
+ if c == 22 then
+ buildingStr = buildingStr .. '\"'
+ elseif c == 10 then
+ buildingStr = buildingStr .. "\n"
+ elseif c == 13 then
+ buildingStr = buildingStr .. "\013"
+ else
+ buildingStr = buildingStr .. utf8.char(c);
+ end;
+ end;
+
+ return '"' .. buildingStr .. '"';
+end;
+
+local n, v = "serpent", "0.303" -- (C) 2012-18 Paul Kulchenko; MIT License
+local c, d = "Paul Kulchenko", "Lua serializer and pretty printer"
+local snum = {[tostring(1/0)]='1/0 --[[math.huge]]',[tostring(-1/0)]='-1/0 --[[-math.huge]]',[tostring(0/0)]='0/0'}
+local badtype = {thread = true, userdata = true, cdata = true}
+local getmetatable = debug and debug.getmetatable or getmetatable
+
+-- local pairs = function(t) return next, t end -- avoid using __pairs in Lua 5.2+ -- it should use pairs because of nodeDatabase
+
+local keyword, globals, G = {}, {}, (_G or _ENV)
+for _,k in ipairs({'and', 'break', 'do', 'else', 'elseif', 'end', 'false',
+ 'for', 'function', 'goto', 'if', 'in', 'local', 'nil', 'not', 'or', 'repeat',
+ 'return', 'then', 'true', 'until', 'while'}) do keyword[k] = true end
+for k,v in pairs(G) do globals[v] = k end -- build func to name mapping
+for _,g in ipairs({'coroutine', 'debug', 'io', 'math', 'string', 'table', 'os'}) do
+ for k,v in pairs(type(G[g]) == 'table' and G[g] or {}) do globals[v] = g..'.'..k end end
+
+local function s(t, opts)
+ local name, indent, fatal, maxnum = opts.name, opts.indent, opts.fatal, opts.maxnum
+ local sparse, custom, huge = opts.sparse, opts.custom, not opts.nohuge
+ local space, maxl = (opts.compact and '' or ' '), (opts.maxlevel or math.huge)
+ local maxlen, metatostring = tonumber(opts.maxlength), opts.metatostring
+ local iname, comm = '_'..(name or ''), opts.comment and (tonumber(opts.comment) or math.huge)
+ local numformat = opts.numformat or "%.17g"
+ local seen, sref, syms, symn = {}, {'local '..iname..'={}'}, {}, 0
+ local function gensym(val) return '_'..(tostring(tostring(val)):gsub("[^%w]",""):gsub("(%d%w+)",
+ -- tostring(val) is needed because __tostring may return a non-string value
+ function(s) if not syms[s] then symn = symn+1; syms[s] = symn end return tostring(syms[s]) end)) end
+ local function safestr(s) return type(s) == "number" and (huge and snum[tostring(s)] or numformat:format(s))
+ or type(s) ~= "string" and tostring(s) -- escape NEWLINE/010 and EOF/026
+ or firecastQuotedStr(s):gsub("\010","n"):gsub("\026","\\026") end
+ -- handle radix changes in some locales
+ if opts.fixradix and (".1f"):format(1.2) ~= "1.2" then
+ local origsafestr = safestr
+ safestr = function(s) return type(s) == "number"
+ and (nohuge and snum[tostring(s)] or numformat:format(s):gsub(",",".")) or origsafestr(s)
+ end
+ end
+ local function comment(s,l) return comm and (l or 0) < comm and ' --[['..select(2, pcall(tostring, s))..']]' or '' end
+ local function globerr(s,l) return globals[s] and globals[s]..comment(s,l) or not fatal
+ and safestr(select(2, pcall(tostring, s))) or error("Can't serialize "..tostring(s)) end
+ local function safename(path, name) -- generates foo.bar, foo[3], or foo['b a r']
+ local n = name == nil and '' or name
+ local plain = type(n) == "string" and n:match("^[%l%u_][%w_]*$") and not keyword[n]
+ local safe = plain and n or '['..safestr(n)..']'
+ return (path or '')..(plain and path and '.' or '')..safe, safe end
+ local alphanumsort = type(opts.sortkeys) == 'function' and opts.sortkeys or function(k, o, n) -- k=keys, o=originaltable, n=padding
+ local maxn, to = tonumber(n) or 12, {number = 'a', string = 'b'}
+ local function padnum(d) return ("%0"..tostring(maxn).."d"):format(tonumber(d)) end
+ table.sort(k, function(a,b)
+ -- sort numeric keys first: k[key] is not nil for numerical keys
+ return (k[a] ~= nil and 0 or to[type(a)] or 'z')..(tostring(a):gsub("%d+",padnum))
+ < (k[b] ~= nil and 0 or to[type(b)] or 'z')..(tostring(b):gsub("%d+",padnum)) end) end
+ local function val2str(t, name, indent, insref, path, plainindex, level)
+ local ttype, level, mt = type(t), (level or 0), getmetatable(t)
+ local spath, sname = safename(path, name)
+ local tag = plainindex and
+ ((type(name) == "number") and '' or name..space..'='..space) or
+ (name ~= nil and sname..space..'='..space or '')
+ if seen[t] then -- already seen this element
+ sref[#sref+1] = spath..space..'='..space..seen[t]
+ return tag..'nil'..comment('ref', level)
+ end
+ -- protect from those cases where __tostring may fail
+ if type(mt) == 'table' and metatostring ~= false then
+ local to, tr = pcall(function() return mt.__tostring(t) end)
+ local so, sr = pcall(function() return mt.__serialize(t) end)
+ if (to or so) then -- knows how to serialize itself
+ seen[t] = insref or spath
+ t = so and sr or tr
+ ttype = type(t)
+ end -- new value falls through to be serialized
+ end
+ if ttype == "table" then
+ if level >= maxl then return tag..'{}'..comment('maxlvl', level) end
+ seen[t] = insref or spath
+ if next(t) == nil then return tag..'{}'..comment(t, level) end -- table empty
+ if maxlen and maxlen < 0 then return tag..'{}'..comment('maxlen', level) end
+ local maxn, o, out = math.min(#t, maxnum or #t), {}, {}
+ for key = 1, maxn do o[key] = key end
+ if not maxnum or #o < maxnum then
+ local n = #o -- n = n + 1; o[n] is much faster than o[#o+1] on large tables
+ for key in pairs(t) do
+ if o[key] ~= key then n = n + 1; o[n] = key end
+ end
+ end
+ if maxnum and #o > maxnum then o[maxnum+1] = nil end
+ if opts.sortkeys and #o > maxn then alphanumsort(o, t, opts.sortkeys) end
+ local sparse = sparse and #o > maxn -- disable sparsness if only numeric keys (shorter output)
+ for n, key in ipairs(o) do
+ local value, ktype, plainindex = t[key], type(key), n <= maxn and not sparse
+ if opts.valignore and opts.valignore[value] -- skip ignored values; do nothing
+ or opts.keyallow and not opts.keyallow[key]
+ or opts.keyignore and opts.keyignore[key]
+ or opts.valtypeignore and opts.valtypeignore[type(value)] -- skipping ignored value types
+ or sparse and value == nil then -- skipping nils; do nothing
+ elseif ktype == 'table' or ktype == 'function' or badtype[ktype] then
+ if not seen[key] and not globals[key] then
+ sref[#sref+1] = 'placeholder'
+ local sname = safename(iname, gensym(key)) -- iname is table for local variables
+ sref[#sref] = val2str(key,sname,indent,sname,iname,true)
+ end
+ sref[#sref+1] = 'placeholder'
+ local path = seen[t]..'['..tostring(seen[key] or globals[key] or gensym(key))..']'
+ sref[#sref] = path..space..'='..space..tostring(seen[value] or val2str(value,nil,indent,path))
+ else
+ out[#out+1] = val2str(value,key,indent,nil,seen[t],plainindex,level+1)
+ if maxlen then
+ maxlen = maxlen - #out[#out]
+ if maxlen < 0 then break end
+ end
+ end
+ end
+ local prefix = string.rep(indent or '', level)
+ local head = indent and '{\n'..prefix..indent or '{'
+ local body = table.concat(out, ','..(indent and '\n'..prefix..indent or space))
+ local tail = indent and "\n"..prefix..'}' or '}'
+ return (custom and custom(tag,head,body,tail,level) or tag..head..body..tail)..comment(t, level)
+ elseif badtype[ttype] then
+ seen[t] = insref or spath
+ return tag..globerr(t, level)
+ elseif ttype == 'function' then
+ seen[t] = insref or spath
+ if opts.nocode then return tag.."function() --[[..skipped..]] end"..comment(t, level) end
+ local ok, res = pcall(string.dump, t)
+ local func = ok and "((loadstring or load)("..safestr(res)..",'@serialized'))"..comment(t, level)
+ return tag..(func or globerr(t, level))
+ else return tag..safestr(t) end -- handle all other types
+ end
+ local sepr = indent and "\n" or ";"..space
+ local body = val2str(t, name, indent) -- this call also populates sref
+ local tail = #sref>1 and table.concat(sref, sepr)..sepr or ''
+ local warn = opts.comment and #sref>1 and space.."--[[incomplete output with shared/self-references skipped]]" or ''
+ return not name and body..warn or "do local "..body..sepr..tail.."return "..name..sepr.."end"
+end
+
+local function deserialize(data, opts)
+ local env = (opts and opts.safe == false) and G
+ or setmetatable({}, {
+ __index = function(t,k) return t end,
+ __call = function(t,...) error("cannot call functions") end
+ })
+ local f, res = (loadstring or load)('return '..data, nil, nil, env)
+ if not f then f, res = (loadstring or load)(data, nil, nil, env) end
+ if not f then return f, res end
+ if setfenv then setfenv(f, env) end
+ return pcall(f)
+end
+
+local function merge(a, b) if b then for k,v in pairs(b) do a[k] = v end end; return a; end
+return { _NAME = n, _COPYRIGHT = c, _DESCRIPTION = d, _VERSION = v, serialize = s,
+ load = deserialize,
+ dump = function(a, opts) return s(a, merge({name = '_', compact = true, sparse = true}, opts)) end,
+ line = function(a, opts) return s(a, merge({sortkeys = true, comment = true}, opts)) end,
+ block = function(a, opts) return s(a, merge({indent = ' ', sortkeys = true, comment = true}, opts)) end }
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/slaxdom.dlua b/Plugins/Sheets/Coyote and Crow/sdk/slaxdom.dlua
new file mode 100644
index 00000000..46b5bc87
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/slaxdom.dlua
@@ -0,0 +1,49 @@
+-- Optional parser that creates a flat DOM from parsing
+local SLAXML = require 'slaxml.dlua'
+function SLAXML:dom(xml,opts)
+ if not opts then opts={} end
+ local rich = not opts.simple
+ local push, pop = table.insert, table.remove
+ local stack = {}
+ local doc = { type="document", name="#doc", kids={} }
+ local current = doc
+ local builder = SLAXML:parser{
+ startElement = function(name,nsURI)
+ local el = { type="element", name=name, kids={}, el=rich and {} or nil, attr={}, nsURI=nsURI, parent=rich and current or nil }
+ if current==doc then
+ if doc.root then error(("Encountered element '%s' when the document already has a root '%s' element"):format(name,doc.root.name)) end
+ doc.root = el
+ end
+ push(current.kids,el)
+ if current.el then push(current.el,el) end
+ current = el
+ push(stack,el)
+ end,
+ attribute = function(name,value,nsURI)
+ if not current or current.type~="element" then error(("Encountered an attribute %s=%s but I wasn't inside an element"):format(name,value)) end
+ local attr = {type='attribute',name=name,nsURI=nsURI,value=value,parent=rich and current or nil}
+ if rich then current.attr[name] = value end
+ push(current.attr,attr)
+ end,
+ closeElement = function(name)
+ if current.name~=name or current.type~="element" then error(("Received a close element notification for '%s' but was inside a '%s' %s"):format(name,current.name,current.type)) end
+ pop(stack)
+ current = stack[#stack]
+ end,
+ text = function(value)
+ if current.type~='document' then
+ if current.type~="element" then error(("Received a text notification '%s' but was inside a %s"):format(value,current.type)) end
+ push(current.kids,{type='text',name='#text',value=value,parent=rich and current or nil})
+ end
+ end,
+ comment = function(value)
+ push(current.kids,{type='comment',name='#comment',value=value,parent=rich and current or nil})
+ end,
+ pi = function(name,value)
+ push(current.kids,{type='pi',name=name,value=value,parent=rich and current or nil})
+ end
+ }
+ builder:parse(xml,opts)
+ return doc
+end
+return SLAXML
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/slaxml.dlua b/Plugins/Sheets/Coyote and Crow/sdk/slaxml.dlua
new file mode 100644
index 00000000..5929b785
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/slaxml.dlua
@@ -0,0 +1,257 @@
+--[=====================================================================[
+v0.7 Copyright © 2013-2014 Gavin Kistner ; MIT Licensed
+See http://github.com/Phrogz/SLAXML for details.
+--]=====================================================================]
+local SLAXML = {
+ VERSION = "0.7",
+ _call = {
+ pi = function(target,content)
+ --print(string.format("%s %s?>",target,content))
+ end,
+ comment = function(content)
+ --print(string.format("",content))
+ end,
+ startElement = function(name,nsURI,nsPrefix)
+ --[[ io.write("<")
+ if nsPrefix then io.write(nsPrefix,":") end
+ io.write(name)
+ if nsURI then io.write(" (ns='",nsURI,"')") end
+ print(">")]]--
+ end,
+ attribute = function(name,value,nsURI,nsPrefix)
+ --[[ io.write(' ')
+ if nsPrefix then io.write(nsPrefix,":") end
+ io.write(name,'=',string.format('%q',value))
+ if nsURI then io.write(" (ns='",nsURI,"')") end
+ io.write("\n")]]--
+ end,
+ text = function(text)
+ --print(string.format(" text: %q",text))
+ end,
+ closeElement = function(name,nsURI,nsPrefix)
+ --print(string.format("%s>",name))
+ end,
+ }
+}
+
+function SLAXML:parser(callbacks)
+ return { _call=callbacks or self._call, parse=SLAXML.parse }
+end
+
+function SLAXML:parse(xml,options)
+ if not options then options = { stripWhitespace=false } end
+
+ -- Cache references for maximum speed
+ local find, sub, gsub, char, push, pop, concat = string.find, string.sub, string.gsub, string.char, table.insert, table.remove, table.concat
+ local first, last, match1, match2, pos2, nsURI
+ local unpack = table.unpack
+ local pos = 1
+ local state = "text"
+ local textStart = 1
+ local currentElement={}
+ local currentAttributes={}
+ local currentAttributeCt -- manually track length since the table is re-used
+ local nsStack = {}
+ local anyElement = false
+
+ local utf8markers = { {0x7FF,192}, {0xFFFF,224}, {0x1FFFFF,240} }
+ function utf8(decimal) -- convert unicode code point to utf-8 encoded character string
+ if decimal<128 then return char(decimal) end
+ local charbytes = {}
+ for bytes,vals in ipairs(utf8markers) do
+ if decimal<=vals[1] then
+ for b=bytes+1,2,-1 do
+ local mod = decimal%64
+ decimal = (decimal-mod)/64
+ charbytes[b] = char(128+mod)
+ end
+ charbytes[1] = char(vals[2]+decimal)
+ return concat(charbytes)
+ end
+ end
+ end
+ local entityMap = { ["lt"]="<", ["gt"]=">", ["amp"]="&", ["quot"]='"', ["apos"]="'" }
+ local entitySwap = function(orig,n,s) return entityMap[s] or n=="#" and utf8(tonumber('0'..s)) or orig end
+ local function unescape(str) return gsub( str, '(&(#?)([%d%a]+);)', entitySwap ) end
+
+ local function finishText()
+ if first>textStart and self._call.text then
+ local text = sub(xml,textStart,first-1)
+ if options.stripWhitespace then
+ text = gsub(text,'^%s+','')
+ text = gsub(text,'%s+$','')
+ if #text==0 then text=nil end
+ end
+ if text then self._call.text(unescape(text)) end
+ end
+ end
+
+ local function findPI()
+ first, last, match1, match2 = find( xml, '^<%?([:%a_][:%w_.-]*) ?(.-)%?>', pos )
+ if first then
+ finishText()
+ if self._call.pi then self._call.pi(match1,match2) end
+ pos = last+1
+ textStart = pos
+ return true
+ end
+ end
+
+ local function findComment()
+ first, last, match1 = find( xml, '^', pos )
+ if first then
+ finishText()
+ if self._call.comment then self._call.comment(match1) end
+ pos = last+1
+ textStart = pos
+ return true
+ end
+ end
+
+ local function nsForPrefix(prefix)
+ if prefix=='xml' then return 'http://www.w3.org/XML/1998/namespace' end -- http://www.w3.org/TR/xml-names/#ns-decl
+ for i=#nsStack,1,-1 do if nsStack[i][prefix] then return nsStack[i][prefix] end end
+ error(("Cannot find namespace for prefix %s"):format(prefix))
+ end
+
+ local function startElement()
+ anyElement = true
+ first, last, match1 = find( xml, '^<([%a_][%w_.-]*)', pos )
+ if first then
+ currentElement[2] = nil -- reset the nsURI, since this table is re-used
+ currentElement[3] = nil -- reset the nsPrefix, since this table is re-used
+ finishText()
+ pos = last+1
+ first,last,match2 = find(xml, '^:([%a_][%w_.-]*)', pos )
+ if first then
+ currentElement[1] = match2
+ currentElement[3] = match1 -- Save the prefix for later resolution
+ match1 = match2
+ pos = last+1
+ else
+ currentElement[1] = match1
+ for i=#nsStack,1,-1 do if nsStack[i]['!'] then currentElement[2] = nsStack[i]['!']; break end end
+ end
+ currentAttributeCt = 0
+ push(nsStack,{})
+ return true
+ end
+ end
+
+ local function findAttribute()
+ first, last, match1 = find( xml, '^%s+([:%a_][:%w_.-]*)%s*=%s*', pos )
+ if first then
+ pos2 = last+1
+ first, last, match2 = find( xml, '^"([^<"]*)"', pos2 ) -- FIXME: disallow non-entity ampersands
+ if first then
+ pos = last+1
+ match2 = unescape(match2)
+ else
+ first, last, match2 = find( xml, "^'([^<']*)'", pos2 ) -- FIXME: disallow non-entity ampersands
+ if first then
+ pos = last+1
+ match2 = unescape(match2)
+ end
+ end
+ end
+ if match1 and match2 then
+ local currentAttribute = {match1,match2}
+ local prefix,name = string.match(match1,'^([^:]+):([^:]+)$')
+ if prefix then
+ if prefix=='xmlns' then
+ nsStack[#nsStack][name] = match2
+ else
+ currentAttribute[1] = name
+ currentAttribute[4] = prefix
+ end
+ else
+ if match1=='xmlns' then
+ nsStack[#nsStack]['!'] = match2
+ currentElement[2] = match2
+ end
+ end
+ currentAttributeCt = currentAttributeCt + 1
+ currentAttributes[currentAttributeCt] = currentAttribute
+ return true
+ end
+ end
+
+ local function findCDATA()
+ first, last, match1 = find( xml, '^', pos )
+ if first then
+ finishText()
+ if self._call.text then self._call.text(match1) end
+ pos = last+1
+ textStart = pos
+ return true
+ end
+ end
+
+ local function closeElement()
+ first, last, match1 = find( xml, '^%s*(/?)>', pos )
+ if first then
+ state = "text"
+ pos = last+1
+ textStart = pos
+
+ -- Resolve namespace prefixes AFTER all new/redefined prefixes have been parsed
+ if currentElement[3] then currentElement[2] = nsForPrefix(currentElement[3]) end
+ if self._call.startElement then self._call.startElement(unpack(currentElement)) end
+ if self._call.attribute then
+ for i=1,currentAttributeCt do
+ if currentAttributes[i][4] then currentAttributes[i][3] = nsForPrefix(currentAttributes[i][4]) end
+ self._call.attribute(unpack(currentAttributes[i]))
+ end
+ end
+
+ if match1=="/" then
+ pop(nsStack)
+ if self._call.closeElement then self._call.closeElement(unpack(currentElement)) end
+ end
+ return true
+ end
+ end
+
+ local function findElementClose()
+ first, last, match1, match2 = find( xml, '^([%a_][%w_.-]*)%s*>', pos )
+ if first then
+ nsURI = nil
+ for i=#nsStack,1,-1 do if nsStack[i]['!'] then nsURI = nsStack[i]['!']; break end end
+ else
+ first, last, match2, match1 = find( xml, '^([%a_][%w_.-]*):([%a_][%w_.-]*)%s*>', pos )
+ if first then nsURI = nsForPrefix(match2) end
+ end
+ if first then
+ finishText()
+ if self._call.closeElement then self._call.closeElement(match1,nsURI) end
+ pos = last+1
+ textStart = pos
+ pop(nsStack)
+ return true
+ end
+ end
+
+ while pos<#xml do
+ if state=="text" then
+ if not (findPI() or findComment() or findCDATA() or findElementClose()) then
+ if startElement() then
+ state = "attributes"
+ else
+ first, last = find( xml, '^[^<]+', pos )
+ pos = (first and last or pos) + 1
+ end
+ end
+ elseif state=="attributes" then
+ if not findAttribute() then
+ if not closeElement() then
+ error("Was in an element and couldn't find attributes or the close.")
+ end
+ end
+ end
+ end
+
+ if not anyElement then error("Parsing did not discover any elements") end
+ if #nsStack > 0 then error("Parsing ended with unclosed elements") end
+end
+
+return SLAXML
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/system.lua b/Plugins/Sheets/Coyote and Crow/sdk/system.lua
new file mode 100644
index 00000000..5e7bcf15
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/system.lua
@@ -0,0 +1,3 @@
+system = require("delayedLoad.dlua").new("systemCore.dlua");
+System = system;
+return system;
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/systemCore.dlua b/Plugins/Sheets/Coyote and Crow/sdk/systemCore.dlua
new file mode 100644
index 00000000..622f8288
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/systemCore.dlua
@@ -0,0 +1,51 @@
+local system = {};
+
+function system.setClipboardText(text)
+ return _system_setClipboardText(text);
+end;
+
+function system.getClipboardText()
+ return _system_getClipboardText();
+end;
+
+function system.readClipboardAsDragNDrop(callback, options)
+ if (type(callback) ~= 'function') then
+ return false;
+ end;
+
+ options = options or {};
+ options.x = tonumber(options.x) or 0;
+ options.y = tonumber(options.y) or 0;
+
+ return _gui_readClipboardAsDragNDrop(options.x, options.y, callback);
+end;
+
+function system.getScreenSize()
+ return _system_getScreenSize();
+end;
+
+function system.isMobile()
+ return _system_isMobile();
+end;
+
+function system.getTickCount()
+ return _system_getTickCount();
+end;
+
+function system.checkAPIVersion(major, minor)
+ return system.getAPIVersion() >= system.makeAPIVersionNumber(major, minor);
+end;
+
+function system.getAPIVersion()
+ if _system_getAPIVersion ~= nil then
+ return _system_getAPIVersion();
+ else
+ return system.makeAPIVersionNumber(87, 0);
+ end;
+end;
+
+function system.makeAPIVersionNumber(major, minor)
+ return ((major or 0) << 16) | ((minor or 0) & 0xFFFF);
+end;
+
+return system;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/utils.lua b/Plugins/Sheets/Coyote and Crow/sdk/utils.lua
new file mode 100644
index 00000000..f1fe1671
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/utils.lua
@@ -0,0 +1 @@
+return require("rrpgUtil.lua");
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/utils.serializer.dlua b/Plugins/Sheets/Coyote and Crow/sdk/utils.serializer.dlua
new file mode 100644
index 00000000..2c5de095
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/utils.serializer.dlua
@@ -0,0 +1,339 @@
+local utils = require("utils.lua");
+local SharedObjects = require("rrpgSharedObjects.lua");
+
+local serializer = {};
+
+local TYPE_STRING = 1;
+local TYPE_NUMBER = 2;
+local TYPE_BOOLEAN = 3;
+local TYPE_TABLE = 4;
+local TYPE_NIL = 5;
+local TYPE_NUMBER_AS_INTEGER = 10;
+
+local typeToId = {string=TYPE_STRING, number=TYPE_NUMBER, boolean=TYPE_BOOLEAN, table=TYPE_TABLE};
+typeToId["nil"] = TYPE_NIL;
+
+local typesForKey = {};
+typesForKey[TYPE_STRING] = true;
+typesForKey[TYPE_NUMBER] = true;
+typesForKey[TYPE_BOOLEAN] = true;
+
+local typesForValue = {};
+typesForValue[TYPE_STRING] = true;
+typesForValue[TYPE_NUMBER] = true;
+typesForValue[TYPE_BOOLEAN] = true;
+typesForValue[TYPE_TABLE] = true;
+
+local function binaryWrite(format, value, scope)
+ local buffer = scope._buffer;
+
+ if buffer == nil then
+ buffer = {};
+ scope._buffer = buffer;
+ end;
+
+ local tam = utils.binaryEncode(buffer, format, value);
+ return scope.writer(buffer, tam);
+end;
+
+local function binaryWriteString(value, scope)
+ local buffer2 = scope._buffer2;
+
+ if buffer2 == nil then
+ buffer2 = {};
+ scope._buffer2 = buffer2;
+ end;
+
+ local tam = utils.binaryEncode(buffer2, "utf8", value);
+ local writed1 = binaryWrite("u32", tam, scope);
+ local writed2 = scope.writer(buffer2, tam);
+
+ return writed1 + writed2;
+end;
+
+function serializer.outputValue(value, scope)
+ local idType = typeToId[type(value)];
+
+ if idType == TYPE_TABLE then
+ local conseguiu, so = serializer.tryPackSharedObject(value);
+
+ if conseguiu then
+ value = so;
+ idType = typeToId[type(value)];
+ end;
+ end;
+
+ if idType == nil then
+ error("Tipo não tratado");
+ elseif idType == TYPE_NUMBER then
+ local numberType = math.type(value);
+
+ if numberType == "integer" then
+ idType = TYPE_NUMBER_AS_INTEGER;
+ end;
+ end;
+
+ binaryWrite("u8", idType, scope);
+
+ if idType == TYPE_STRING then
+ binaryWriteString(value, scope);
+ elseif idType == TYPE_NUMBER then
+ binaryWrite("double", value, scope);
+ elseif idType == TYPE_NUMBER_AS_INTEGER then
+ binaryWrite("s64", value, scope);
+ elseif idType == TYPE_BOOLEAN then
+ if value then
+ binaryWrite("u8", 1, scope);
+ else
+ binaryWrite("u8", 0, scope);
+ end;
+ elseif idType == TYPE_TABLE then
+ serializer.outputTable(value, scope);
+ else
+ if idType ~= TYPE_NIL then
+ error("Tipo desconhecido");
+ end;
+ end;
+end;
+
+function serializer.outputTable(tabela, scope)
+ local toWrite = {};
+
+ for k, v in pairs(tabela) do
+ local kType = typeToId[type(k)];
+ local vType = typeToId[type(v)];
+
+ if (kType ~= nil) and (typesForKey[kType]) and (vType ~= nil) and (typesForValue[vType]) then
+ toWrite[#toWrite + 1] = k;
+ end;
+ end;
+
+ binaryWrite("u32", #toWrite, scope);
+
+ for i = 1, #toWrite, 1 do
+ local k = toWrite[i];
+ local v = tabela[k];
+ serializer.outputValue(k, scope);
+ serializer.outputValue(v, scope);
+ end;
+end;
+
+
+local function binaryRead(format, scope)
+ local buffer = scope._buffer;
+
+ if buffer == nil then
+ buffer = {};
+ scope._buffer = buffer;
+ end;
+
+ local bTam = utils.getBinarySize(format);
+
+ if (bTam ~= nil) and (bTam > 0) then
+ local tamLido = scope.reader(buffer, bTam);
+
+ if tamLido ~= bTam then
+ error("End of Stream");
+ end;
+
+ local value = utils.binaryDecode(buffer, format, 1, tamLido);
+ return value, tamLido;
+ else
+ error("Não é possível prever o tamanho do binaryRead");
+ end;
+end;
+
+local function binaryReadString(scope)
+ local buffer2 = scope._buffer2;
+
+ if buffer2 == nil then
+ buffer2 = {};
+ scope._buffer2 = buffer2;
+ end;
+
+ local stringTam = binaryRead("u32", scope);
+ local tamLido = scope.reader(buffer2, stringTam);
+
+ if tamLido ~= stringTam then
+ error("End of stream");
+ end;
+
+ local value = utils.binaryDecode(buffer2, "utf8", 1, tamLido);
+ return value, tamLido;
+end;
+
+function serializer.inputValue(scope)
+ local tipo = binaryRead("u8", scope);
+
+ if tipo == TYPE_STRING then
+ local vstr = binaryReadString(scope);
+ local conseguiu, so = serializer.tryUnpackSharedObject(vstr);
+
+ if conseguiu then
+ return so;
+ else
+ return vstr;
+ end;
+ elseif tipo == TYPE_NIL then
+ return nil;
+ elseif tipo == TYPE_NUMBER then
+ return binaryRead("double", scope);
+ elseif tipo == TYPE_NUMBER_AS_INTEGER then
+ return binaryRead("s64", scope);
+ elseif tipo == TYPE_TABLE then
+ return serializer.inputTable(scope);
+ elseif tipo == TYPE_BOOLEAN then
+ return binaryRead("u8", scope) == 1;
+ else
+ error("Tipo Desconhecido: " .. tostring(tipo));
+ end;
+end;
+
+function serializer.inputTable(scope)
+ local qtProps = binaryRead("u32", scope);
+ local r = {};
+
+ for i = 1, qtProps, 1 do
+ local k = serializer.inputValue(scope);
+ local v = serializer.inputValue(scope);
+ r[k] = v;
+ end;
+
+ return r;
+end;
+
+function serializer.valueToStream(value, stream)
+ local scope = {};
+
+ scope.writer = function(bytes, qtBytes)
+ return stream:write(bytes, qtBytes);
+ end;
+
+ return serializer.outputValue(value, scope);
+end;
+
+function serializer.streamToValue(stream)
+ local scope = {};
+
+ scope.reader = function(bytes, qtBytes)
+ return stream:read(bytes, qtBytes);
+ end;
+
+ return serializer.inputValue(scope);
+end;
+
+function serializer.serialize(value)
+ local stream = utils.newMemoryStream();
+ local stream2 = utils.newMemoryStream();
+ local ret;
+ serializer.valueToStream(value, stream);
+ stream.position = 0;
+
+ if stream.size > 512 then
+ -- compactar
+ stream2.position = 0;
+ local buffer = {1};
+ stream2:write(buffer, 1); -- sinalizar que está compactado
+
+ utils.zlibCompress(stream, stream2);
+ else
+ -- Não compactar
+ stream2.position = 0;
+ local buffer = {0};
+ stream2:write(buffer, 1); -- sinalizar que não está compactado
+
+ stream2:copyFrom(stream, stream.size);
+ end;
+
+ stream.size = 0;
+ stream2.position = 0;
+
+ ret = stream2:readAsBase64();
+ stream2.size = 0;
+
+ return ret;
+end;
+
+function serializer.deserialize(base64str)
+ local stream = utils.newMemoryStream();
+ local buffer = {};
+ local ret;
+
+ stream:writeBase64(base64str);
+ stream.position = 0;
+
+ if stream:read(buffer, 1) ~= 1 then
+ error("End of Stream");
+ end;
+
+ if buffer[1] == 1 then
+ -- compactado
+ local stream2 = utils.newMemoryStream();
+ utils.zlibDecompress(stream, stream2);
+ stream.size = 0;
+ stream2.position = 0;
+
+ ret = serializer.streamToValue(stream2);
+ stream2.size = 0;
+ else
+ -- descompactado
+ ret = serializer.streamToValue(stream);
+ stream.size = 0;
+ end;
+
+ return ret;
+end;
+
+function serializer.tryPackSharedObject(tabela)
+ return SharedObjects.tryPack(tabela);
+end;
+
+function serializer.tryUnpackSharedObject(str)
+ return SharedObjects.tryUnpack(str);
+end;
+
+local _SERIALIZER_PREFIX = "###SERIALIZER_";
+local _SERIALIZER_SUFIX = "_###";
+local _SERIALIZER_MATCH_MASK = _SERIALIZER_PREFIX .. "(.+)" .. _SERIALIZER_SUFIX;
+
+function serializer.packData(data)
+ local typeId = typeToId[type(data)];
+
+ if typeId ~= nil then
+ if typeId == TYPE_TABLE then
+ local conseguiu, so = serializer.tryPackSharedObject(data);
+
+ if conseguiu then
+ return so;
+ else
+ return _SERIALIZER_PREFIX .. serializer.serialize(data) .. _SERIALIZER_SUFIX;
+ end;
+ else
+ return data;
+ end;
+ else
+ return nil;
+ end
+end;
+
+function serializer.unpackData(data)
+ if type(data) == "string" then
+ local conseguiu, so = serializer.tryUnpackSharedObject(data);
+
+ if conseguiu then
+ return so;
+ else
+ local mData = string.match(data, _SERIALIZER_MATCH_MASK);
+
+ if mData ~= nil then
+ return serializer.deserialize(mData);
+ else
+ return data;
+ end;
+ end;
+ else
+ return data;
+ end;
+end;
+
+return serializer;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/vhd.lua b/Plugins/Sheets/Coyote and Crow/sdk/vhd.lua
new file mode 100644
index 00000000..d5875959
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/vhd.lua
@@ -0,0 +1,77 @@
+local localVHD = {};
+
+vhd = localVHD;
+VHD = vhd;
+
+function vhd.expandFileName(shortFileName)
+ return __vhd__expandFileName(shortFileName);
+end;
+
+function vhd.addSearchPath(directory)
+ __vhd_addSearchPath(directory);
+end;
+
+function vhd.removeSearchPath(directory)
+ __vhd_removeSearchPath(directory);
+end;
+
+function vhd.fileExists(fileName)
+ return __vhd_fileExists(fileName);
+end;
+
+local rrpgUtils = nil;
+
+function vhd.openFile(fileName, mode)
+ if rrpgUtils == nil then
+ rrpgUtils = require("rrpgUtil.lua");
+ end;
+
+ if type(mode) ~= "string" then
+ mode = "r";
+ end;
+
+ local expandedFileName = vhd.expandFileName(fileName);
+ local streamHandle, msgError = _vhd_openFile(expandedFileName, mode);
+
+ if streamHandle ~= nil then
+ return rrpgUtils.streamFromHandle(streamHandle);
+ else
+ return nil, msgError;
+ end;
+end;
+
+function VHD.forceDirectory(directoryPath)
+ return __vhd_forceDirectory(directoryPath);
+end;
+
+function VHD.deleteFile(fileName)
+ return __vhd_deleteFile(fileName);
+end
+
+function VHD.deleteDirectory(directoryPath)
+ return __vhd_deleteDirectory(directoryPath);
+end
+
+function VHD.directoryExists(path)
+ return __vhd_directoryExists(path);
+end
+
+function VHD.enumerateContent(directoryPath)
+ return __vhd_enumerateContent(directoryPath);
+end
+
+function VHD.registerAlias(aliases)
+ return __vhd_registerAlias(aliases);
+end;
+
+function VHD.copyFile(srcFileName, dstFileName)
+ local srcFile = VHD.openFile(srcFileName, "r");
+ local dstFile = VHD.openFile(dstFileName, "w+");
+
+ dstFile:copyFrom(srcFile, srcFile.size);
+
+ dstFile:close();
+ srcFile:close();
+end;
+
+return localVHD;
\ No newline at end of file
diff --git a/Plugins/Sheets/Coyote and Crow/sdk/vkCodes.dlua b/Plugins/Sheets/Coyote and Crow/sdk/vkCodes.dlua
new file mode 100644
index 00000000..9c8b7462
--- /dev/null
+++ b/Plugins/Sheets/Coyote and Crow/sdk/vkCodes.dlua
@@ -0,0 +1,190 @@
+local codes = {
+ vkLButton = 0x01,
+ vkRButton = 0x02,
+ vkCancel = 0x03,
+ vkMButton = 0x04,
+ vkXButton1 = 0x05,
+ vkXButton2 = 0x06,
+ vkBack = 0x08,
+ vkTab = 0x09,
+ vkLineFeed = 0x0A,
+ vkClear = 0x0C,
+ vkReturn = 0x0D,
+ vkShift = 0x10,
+ vkControl = 0x11,
+ vkMenu = 0x12,
+ vkPause = 0x13,
+ vkCapital = 0x14,
+ vkKana = 0x15,
+ vkHangul = 0x15,
+ vkJunja = 0x17,
+ vkFinal = 0x18,
+ vkHanja = 0x19,
+ vkKanji = 0x19,
+ vkConvert = 0x1C,
+ vkNonConvert = 0x1D,
+ vkAccept = 0x1E,
+ vkModeChange = 0x1F,
+ vkEscape = 0x1B,
+ vkSpace = 0x20,
+ vkPrior = 0x21,
+ vkNext = 0x22,
+ vkEnd = 0x23,
+ vkHome = 0x24,
+ vkLeft = 0x25,
+ vkUp = 0x26,
+ vkRight = 0x27,
+ vkDown = 0x28,
+ vkSelect = 0x29,
+ vkPrint = 0x2A,
+ vkExecute = 0x2B,
+ vkSnapshot = 0x2C,
+ vkInsert = 0x2D,
+ vkDelete = 0x2E,
+ vkHelp = 0x2F,
+
+ vk0 = 0x30,
+ vk1 = 0x31,
+ vk2 = 0x32,
+ vk3 = 0x33,
+ vk4 = 0x34,
+ vk5 = 0x35,
+ vk6 = 0x36,
+ vk7 = 0x37,
+ vk8 = 0x38,
+ vk9 = 0x39,
+
+ vkA = 0x41,
+ vkB = 0x42,
+ vkC = 0x43,
+ vkD = 0x44,
+ vkE = 0x45,
+ vkF = 0x46,
+ vkG = 0x47,
+ vkH = 0x48,
+ vkI = 0x49,
+ vkJ = 0x4A,
+ vkK = 0x4B,
+ vkL = 0x4C,
+ vkM = 0x4D,
+ vkN = 0x4E,
+ vkO = 0x4F,
+ vkP = 0x50,
+ vkQ = 0x51,
+ vkR = 0x52,
+ vkS = 0x53,
+ vkT = 0x54,
+ vkU = 0x55,
+ vkV = 0x56,
+ vkW = 0x57,
+ vkX = 0x58,
+ vkY = 0x59,
+ vkZ = 0x5A,
+ vkLWin = 0x5B,
+ vkRWin = 0x5C,
+ vkApps = 0x5D,
+ vkSleep = 0x5F,
+ vkNumpad0 = 0x60,
+ vkNumpad1 = 0x61,
+ vkNumpad2 = 0x62,
+ vkNumpad3 = 0x63,
+ vkNumpad4 = 0x64,
+ vkNumpad5 = 0x65,
+ vkNumpad6 = 0x66,
+ vkNumpad7 = 0x67,
+ vkNumpad8 = 0x68,
+ vkNumpad9 = 0x69,
+ vkMultiply = 0x6A,
+ vkAdd = 0x6B,
+ vkSeparator = 0x6C,
+ vkSubtract = 0x6D,
+ vkDecimal = 0x6E,
+ vkDivide = 0x6F,
+ vkF1 = 0x70,
+ vkF2 = 0x71,
+ vkF3 = 0x72,
+ vkF4 = 0x73,
+ vkF5 = 0x74,
+ vkF6 = 0x75,
+ vkF7 = 0x76,
+ vkF8 = 0x77,
+ vkF9 = 0x78,
+ vkF10 = 0x79,
+ vkF11 = 0x7A,
+ vkF12 = 0x7B,
+ vkF13 = 0x7C,
+ vkF14 = 0x7D,
+ vkF15 = 0x7E,
+ vkF16 = 0x7F,
+ vkF17 = 0x80,
+ vkF18 = 0x81,
+ vkF19 = 0x82,
+ vkF20 = 0x83,
+ vkF21 = 0x84,
+ vkF22 = 0x85,
+ vkF23 = 0x86,
+ vkF24 = 0x87,
+
+ vkCamera = 0x88,
+ vkHardwareBack = 0x89,
+
+ vkNumLock = 0x90,
+ vkScroll = 0x91,
+ vkLShift = 0xA0,
+ vkRShift = 0xA1,
+ vkLControl = 0xA2,
+ vkRControl = 0xA3,
+ vkLMenu = 0xA4,
+ vkRMenu = 0xA5,
+
+ vkBrowserBack = 0xA6,
+ vkBrowserForward = 0xA7,
+ vkBrowserRefresh = 0xA8,
+ vkBrowserStop = 0xA9,
+ vkBrowserSearch = 0xAA,
+ vkBrowserFavorites = 0xAB,
+ vkBrowserHome = 0xAC,
+ vkVolumeMute = 0xAD,
+ vkVolumeDown = 0xAE,
+ vkVolumeUp = 0xAF,
+ vkMediaNextTrack = 0xB0,
+ vkMediaPrevTrack = 0xB1,
+ vkMediaStop = 0xB2,
+ vkMediaPlayPause = 0xB3,
+ vkLaunchMail = 0xB4,
+ vkLaunchMediaSelect= 0xB5,
+ vkLaunchApp1 = 0xB6,
+ vkLaunchApp2 = 0xB7,
+
+ vkSemicolon = 0xBA,
+ vkEqual = 0xBB,
+ vkComma = 0xBC,
+ vkMinus = 0xBD,
+ vkPeriod = 0xBE,
+ vkSlash = 0xBF,
+ vkTilde = 0xC0,
+ vkLeftBracket = 0xDB,
+ vkBackslash = 0xDC,
+ vkRightBracket = 0xDD,
+ vkQuote = 0xDE,
+ vkPara = 0xDF,
+
+ vkOem102 = 0xE2,
+ vkIcoHelp = 0xE3,
+ vkIco00 = 0xE4,
+ vkProcessKey = 0xE5,
+ vkIcoClear = 0xE6,
+ vkPacket = 0xE7,
+ vkAttn = 0xF6,
+ vkCrsel = 0xF7,
+ vkExsel = 0xF8,
+ vkErEof = 0xF9,
+ vkPlay = 0xFA,
+ vkZoom = 0xFB,
+ vkNoname = 0xFC,
+ vkPA1 = 0xFD,
+ vkOemClear = 0xFE,
+ vkNone = 0xFF
+};
+
+return codes;
\ No newline at end of file
diff --git a/Plugins/plugins.xml b/Plugins/plugins.xml
index 1ef93725..397e239c 100644
--- a/Plugins/plugins.xml
+++ b/Plugins/plugins.xml
@@ -372,6 +372,15 @@
+
+
+
+
+
+
+
+
+
@@ -439,7 +448,7 @@
-
+