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("",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("",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, '^', 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, '^', 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 @@ - +