diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..b0b80e9 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,8 @@ +README.md merge=ours + +.gitattributes export-ignore +.gitignore export-ignore +LICENSE.md export-ignore +README.md export-ignore +/.github export-ignore +/docs export-ignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..626af09 --- /dev/null +++ b/.gitignore @@ -0,0 +1,65 @@ +# GENERAL # +########### + +# Ignore everything in root +/* + +# Allow specified directories and their subdirectories +!/.github/ +!/Menu/ +!/Tool/ +!/ScriptResources/ +!/Utility/ +!/Modules/ + +# Ignore everything within allowed directories +/.github/* +/Menu/* +/Menu/- Lost Scripts/* +/Tool/* +/ScriptResources/* +/Utility/* +/Modules/* + +# Unignore specific files after unignoring their directories +!.gitattributes +!.gitignore +!LICENSE.md +!README.md +#!/.github/docs/ +#!/.github/README.md +!/docs +!/Menu/ls_separator.lua +!/Menu/- Lost Scripts/ +!/Menu/- Lost Scripts/ls_webpage.lua +!/ScriptResources/ls/ +!/Tool/_tool_list_ls.txt +!/Utility/ls_utilities.lua +!/Modules/ls_modules.lua + + +# Ignore folders starting with... +#/ls_*/ +# Ignore files starting with... +#ls_* +# Ignore all starting with... +#ls_ + +# PATHS # +######### + + + +# FOLDERS # +########### + +#Modules/ + +# FILE TYPES # +############## + + + +# FILES # +######### + diff --git a/LICENSE.md b/LICENSE.md new file mode 100644 index 0000000..734760e --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,24 @@ +Copyright © 2022-2024, Rai López . All Rights Reserved. + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this Lost Scripts™ project and its associated documentation files (the +"Software") to use it for personal and commercial purposes, including the +rights to copy and modify the Software, provided that: + +* The above copyright notice and this permission notice shall be included in +all copies or substantial portions of the Software. + +* The distribution, publication, sublicensing, and/or sale of the Software, +are strictly prohibited without express permission from the copyright holder. + +* Derivative works may be distributed or sold under licensee's own terms, +provided that such works do not contain the original Software in its entirety +and they will not overwrite any part of the Software upon coexisting public +installations (e.g., for using "LS" instead of licensee's own identifier). + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION, USE OR OTHER DEALINGS IN THE SOFTWARE. \ No newline at end of file diff --git a/Menu/- Lost Scripts/ls_webpage.lua b/Menu/- Lost Scripts/ls_webpage.lua new file mode 100644 index 0000000..7624368 --- /dev/null +++ b/Menu/- Lost Scripts/ls_webpage.lua @@ -0,0 +1,54 @@ +-- ************************************************** +-- Provide Moho with the name of this script object +-- ************************************************** + +ScriptName = "LS_Webpage" + +-- ************************************************** +-- General information about this script +-- ************************************************** + +LS_Webpage = {} + +--LS_Webpage.BASE_STR = 2480 + +function LS_Webpage:Name(n) --name, ID + return ({"Lost Scripts Webpage", "LS_Webpage"})[n or 1] +end + +function LS_Webpage:Version() + return "0.0.1" +end + +function LS_Webpage:Description() + return "Lost Scripts Webpage Direct Link" +end + +function LS_Webpage:Creator() + return "Rai López" +end + +function LS_Webpage:UILabel() + return "Lost Scripts Webpage..." --"- Tag Scripts Webpage..." -- - Tags Webpage... --🌐  +end + +-- ************************************************** +-- The guts of this Script +-- ************************************************** + +function LS_Webpage:IsEnabled(moho) + return true +end + +function LS_Webpage:Run(moho) + local url = "https://lost-scripts.github.io/" -- "https://github.com/lost-scripts/" --"https://lostastools.blogspot.com/" + --[[ + if LS_Utilities:OS() == "unix" then + os.execute('open "" "' .. url .. '"') + else + os.execute('start "" "' .. url .. '"') + end + --]] + os.execute('start "" "' .. url .. '"') +end + diff --git a/Menu/ls_separator.lua b/Menu/ls_separator.lua new file mode 100644 index 0000000..aa77434 --- /dev/null +++ b/Menu/ls_separator.lua @@ -0,0 +1,45 @@ +-- ************************************************** +-- Provide Moho with the name of this script object +-- ************************************************** + +ScriptName = "LS_Separator" + +-- ************************************************** +-- General information about this script +-- ************************************************** + +LS_Separator = {} + +--LS_Separator.BASE_STR = 2480 + +function LS_Separator:Name(n) --name, ID + return ({"Menu Separator", "LS_Separator"})[n or 1] +end + +function LS_Separator:Version() + return "0.0.1" +end + +function LS_Separator:Description() + return "Menu Separator" +end + +function LS_Separator:Creator() + return "Rai López" +end + +function LS_Separator:UILabel() + return "-------------------------------" --"------------- MENU ------------" --"[ 📄 ]" +end + +-- ************************************************** +-- The guts of this Script +-- ************************************************** + +function LS_Separator:IsEnabled(moho) + return false +end + +function LS_Separator:Run(moho) +end + diff --git a/Modules/ls_modules.lua b/Modules/ls_modules.lua new file mode 100644 index 0000000..efac340 --- /dev/null +++ b/Modules/ls_modules.lua @@ -0,0 +1,791 @@ +-- ************************************************** +-- Provide Moho with the name of this script object +-- ************************************************** + +ScriptName = "LS" +ScriptBirth = "20220918-0248" +ScriptBuild = "20240717-0348" + +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- +--LS = LS or {} -- Module LS (MohoDoc, MohoLayer, SS, SSI, SSS, ColorOps, OS, String) +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- + +-- ************************************************** +-- General information about this script +-- ************************************************** + +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- +LS = LS or {["ScriptName"] = ScriptName, ["ScriptBirth"] = ScriptBirth, ["ScriptBuild"] = ScriptBuild} -- Module LS (MohoDoc, MohoLayer, SS, SSI, SSS, ColorOps, OS, String) +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- + +function LS:Name(i) + return ({"Lost Modules", ScriptName = self.ScriptName, Short = "LSM", UUID = "1b310067-35f4-425e-8796-624e70a1492b"})[i or 1] +end + +function LS:Version(i) + return ({"0.0.1", Build = self.ScriptBuild, App = "14.2"})[i or 1] +end + +function LS:Description(i) + return ({MOHO.Localize("/LS/Description=Lost modules container. Contains all the necessary modules for the well operation of Lost Scripts™."), Type = "ModuleScript", LayerType = {[0] = MOHO.LT_UNKNOWN}})[i or 1] +end + +function LS:Creator(i) + return ({"Rai López", Company = "Lost Scripts™", Team = "", Ack = {"Lost Marble team", "Supportive folks at Moho (Scripting) forum"}})[i or 1] +end + +function LS:UILabel(i) + return ({MOHO.Localize("/LS/Modules=Lost Modules"), Labels = "Modules, Development, Programming, Scripting, API, Lua, Interfaces"})[i or 1] --"Lost Scripts Modules" --DON'T LOCALIZE! +end + +function LS:ColorizeIcon(i, j) + return ({true, Icon = "Ⓜ", Color = ({[0] = "#838383", "#DC4040", "#F0A000", "#F0F000", "#40DC40", "#4040DC", "#C060F0", "#D2B48C", "#FFC0CB", "#40E0D0", "#5F9EA0", "#FF7F50"})[j or 0]})[i or 1] +end --print(LS:ColorizeIcon("Color", 2)) + +function LS:Source(i) + return ({"github.com/lost-scripts/ls", Web = "lost-scripts.github.io", Host = "github", User = "lost-scripts"})[i or 1] +end + +function LS:Location(f, l, s) --fullPath: 1, 3 --ScriptLocation()? + return table.concat({debug.getinfo(1).source:sub(2, -#debug.getinfo(1, "S").source:match("[^/\\]*.lua$") - 1), debug.getinfo(1, "S").source:sub(2):match("[^/\\]*.lua$"):sub(0, -5), ".lua"}, s or "", f or 1, (l and l > f) and l or f or 1) +end + +-- LS Module's Properties (deprecate favor of functions system above?) & Constants: + +LS.Name = "LS Modules" +LS.Icon = "Ⓜ" +LS.ScriptName = ScriptName +LS.Type = "ModuleScript" +LS.Creator = "Rai López" +LS.Company = "Lost Scripts™" +LS.Description = "Contains all the necessary modules for the operation of Lost Scripts (The Lost Scripts modules container)." +LS.Version = "0.0.1" +LS.Host = "github" +LS.HostUser = "lost-scripts" +LS.Url = LS.Host .. ".com/" .. LS.HostUser .. "/" .. LS.ScriptName +LS.Web = LS.HostUser .. "." .. LS.Host .. ".io" +LS.Location = debug.getinfo(1).source:sub(2, -#debug.getinfo(1, "S").source:match("[^/\\]*.lua$") - 1) + +-- Layer Types +--MOHO.LT_CHILD = -2 +--MOHO.LT_ROOT = -1 + +LS.LT_UNKNOWN = 2 -- 0 +LS.LT_VECTOR = 4 -- 1 +LS.LT_IMAGE = 8 -- 2 +LS.LT_GROUP = 16 -- 3 +LS.LT_BONE = 32 -- 4 +LS.LT_SWITCH = 64 -- 5 +LS.LT_PARTICLE = 128 -- 6 +LS.LT_NOTE = 256 -- 7 +LS.LT_3D = 512 -- 8 +LS.LT_AUDIO = 1024 -- 9 +LS.LT_PATCH = 2048 -- 10 +LS.LT_TEXT = 4096 -- 11 +LS.LT_ROOT = 2097152 -- 20 +LS.LT_CHILD = 4194304 -- 21 + +LS.LT_FLAGS = {} +LS.LT_FLAGS[MOHO.LT_UNKNOWN] = 2; LS.LT_FLAGS["UNKNOWN"] = 2 -- 0 +LS.LT_FLAGS[MOHO.LT_VECTOR] = 4; LS.LT_FLAGS["VECTOR"] = 4; LS.LT_FLAGS[-MOHO.LT_VECTOR] = "VECTOR" -- 1 +LS.LT_FLAGS[MOHO.LT_IMAGE] = 8; LS.LT_FLAGS["IMAGE"] = 8; LS.LT_FLAGS[-MOHO.LT_IMAGE] = "IMAGE" -- 2 +LS.LT_FLAGS[MOHO.LT_GROUP] = 16; LS.LT_FLAGS["GROUP"] = 16; LS.LT_FLAGS[-MOHO.LT_GROUP] = "GROUP" -- 3 +LS.LT_FLAGS[MOHO.LT_BONE] = 32; LS.LT_FLAGS["BONE"] = 32; LS.LT_FLAGS[-MOHO.LT_BONE] = "BONE" -- 4 +LS.LT_FLAGS[MOHO.LT_SWITCH] = 64; LS.LT_FLAGS["SWITCH"] = 64; LS.LT_FLAGS[-MOHO.LT_SWITCH] = "SWITCH" -- 5 +LS.LT_FLAGS[MOHO.LT_PARTICLE] = 128; LS.LT_FLAGS["PARTICLE"] = 128; LS.LT_FLAGS[-MOHO.LT_PARTICLE] = "PARTICLE" -- 6 +LS.LT_FLAGS[MOHO.LT_NOTE] = 256; LS.LT_FLAGS["NOTE"] = 256; LS.LT_FLAGS[-MOHO.LT_NOTE] = "NOTE" -- 7 +LS.LT_FLAGS[MOHO.LT_3D] = 512; LS.LT_FLAGS["3D"] = 512; LS.LT_FLAGS[-MOHO.LT_3D] = "3D" -- 8 +LS.LT_FLAGS[MOHO.LT_AUDIO] = 1024; LS.LT_FLAGS["AUDIO"] = 1024; LS.LT_FLAGS[-MOHO.LT_AUDIO] = "AUDIO" -- 9 +LS.LT_FLAGS[MOHO.LT_PATCH] = 2048; LS.LT_FLAGS["PATCH"] = 2048; LS.LT_FLAGS[-MOHO.LT_PATCH] = "PATCH" -- 10 +LS.LT_FLAGS[MOHO.LT_TEXT] = 4096; LS.LT_FLAGS["TEXT"] = 4096; LS.LT_FLAGS[-MOHO.LT_TEXT] = "TEXT" -- 11 +LS.LT_FLAGS[20] = 2097152; LS.LT_FLAGS["ROOT"] = 2097152; LS.LT_FLAGS[-20] = "ROOT" -- 20 + +-- Layer Categories +LS.LC_DOC = LS.LT_ROOT + LS.LT_UNKNOWN -- For scripts applicant to any root layer type +LS.LC_ANY = LS.LT_UNKNOWN -- For scripts applicant to any/every layer type +LS.LC_MEDIA = MOHO.LT_IMAGE + MOHO.LT_AUDIO -- For scripts applicant to media kind of layers +LS.LC_GROUP = LS.LT_GROUP + LS.LT_BONE + LS.LT_SWITCH + LS.LT_PARTICLE -- For scripts applicant to group kind of layers +LS.LC_SKEL = MOHO.LT_BONE + MOHO.LT_SWITCH -- For scripts applicant to bone/skel kind of layers +LS.LC_TEXT = LS.LT_NOTE + LS.LT_TEXT -- For scripts applicant to text kind of layers + +-- Layer Placement/Placing? +LS.LP_UNKNOWN = 0 -- free (creates above current) +LS.LP_ROOT = 1 -- root only +LS.LP_ROOT_TOP = 2 -- root only at top +LS.LP_ROOT_BOTTOM = 3 -- root only at bottom +LS.LP_GROUP = 3 -- inside group only +LS.LP_GROUP_TOP = 4 -- inside group only at top +LS.LP_GROUP_BOTTOM = 5 -- inside group only at bottom + +-- Layer Flags +LS.LF_ROOT = 2 +LS.LF_CHILD = 4 + +-- Script Types +LS.ST_UNKNOWN = 0 +LS.ST_TOOL = 1 +LS.ST_MENU = 2 +LS.ST_EMBED = 3 +--LS.ST_S = 4 +LS.ST_MODULE = 5 +LS.ST_UTILITY = 6 + +-- Script Inventory Types +LS.SIT_UNKNOWN = 0 +LS.SIT_LAYER = 1 +LS.SIT_DOCUMENT = 2 + +-- Script Source Types +LS.SST_UNKNOWN = 0 +LS.SST_INSTALLED = 1 +LS.SST_LOCAL = 2 +LS.SST_REMOTE = 3 + +-- Label Colors +LS.LC_GRAY = "#838383" +LS.LC_RED = "#DC4040" +LS.LC_ORANGE = "#F0A000" +LS.LC_YELLOW = "#F0F000" +LS.LC_GREEN = "#40DC40" +LS.LC_BLUE = "#4040DC" +LS.LC_PURPLE = "#C060F0" +LS.LC_TAN = "#D2B48C" +LS.LC_PINK = "#FFC0CB" +LS.LC_TURQUOISE = "#40E0D0" +LS.LC_CADETBLUE = "#5F9EA0" +LS.LC_CORAL = "#FF7F50" +LS.LC = {[0] = LS.LC_GRAY, LS.LC_RED, LS.LC_ORANGE, LS.LC_YELLOW, LS.LC_GREEN, LS.LC_BLUE, LS.LC_PURPLE, LS.LC_TAN, LS.LC_PINK, LS.LC_TURQUOISE, LS.LC_CADETBLUE, LS.LC_CORAL} + +---------------------------------------------------------------------------------------------------------- +LS.Globals = LS.Globals or {fName = "LS_Globals"} -- Globals Submodule +---------------------------------------------------------------------------------------------------------- + +LS.Globals.Moho = nil +LS.Globals.UserModulesDir = LS.Globals.UserModulesDir or debug.getinfo(1).source:sub(2, -#debug.getinfo(1, "S").source:match("[^/\\]*.lua$") - 1) or "\\Scripts\\Modules" + +-- LS Module's Methods: + +function LS.AddMethods(target, source, prefix) --(tbl, tbl, str) + prefix = prefix or "" + if type(target) == "table" and type(source) == "table" then + if source then + for k, v in pairs(source) do + if type(v) == "function" and not target[k] and not k:match("^__") then --20230811-1346: Avoid metamethod overwriting! + target[prefix .. k] = v --print(k, v) -- MODE 1 (preferred): add it to target table + --rawset(target, prefix .. k, v) --print(k, v) -- MODE 2: add it to target table with rawset? + end + end + local metatable = getmetatable(source) + LS.AddMethods(target, metatable) -- recursion... + end + end +end + +function LS.BeepBeep(msec) --(int) + msec = msec or 333 + LM.Beep() LM.Snooze(msec) LM.Beep() +end + +function LS.BuildLayerTypeList() --() tbl + local layerTypeList = {} + for k, v in pairs(MOHO) do + local lt = "" + if k:sub(1, 3) == "LT_" and type(v) == "number" then + layerTypeList[v] = #k:gsub("LT_", "") > 2 and k:gsub("LT_", ""):lower():gsub("^%l", string.upper) or k:gsub("LT_", "") -- text after LT_ is lowered and 1st char uppered, unless it's shorten than 3 chars + end + end + return layerTypeList +end + +function LS.ClickClick(msec) --(int) + msec = msec or 125 + MOHO.ScriptInterface:Click() LM.Snooze(msec) MOHO.ScriptInterface:Click() +end + +function LS.DoubleClick(prevState, curState, prevClock, speed, speedFactor) --(any, any, num, num) bool + speed, speedFactor = speed or 300, speedFactor or 1 + if prevState ~= nil and prevState ~= curState then + if prevClock and (os.clock() - prevClock) * 1000 < speed * (speedFactor or 1) then + --print("Double Click!!!") + return true + end + --self.prevClock = os.clock() + end + return false +end + +function LS.RunningAs(f) --(int) int, str + f = f or 2 + local kind = 0 + local runner = debug.getinfo(f, "n").name --print(tostring(runAsLayerScript)) --print(tostring(caller)) + if runner == "Run" then + kind = LS.ST_EMBED --3 + else + kind = LS.ST_MENU --2 + end + return kind, runner +end + +function LS.Localize(s, n) --(str, int) + local lang = ({["New"]="EN", ["Neu"]="DE", ["Nuevo"]="ES", ["Nouveau"]="FR", ["新規"]="JA", ["Новый"]="RU", ["新建项目"]="ZH_CN", ["新建"]="ZH_HK"})[MOHO.Localize("/Menus/File/New=New")] --EN = English, DE = Deutsch, ES = Español, FR = Français, JA = Japanese, RU = Russian, ZH_CN = Chinese (PRC), ZH_HK = Chinese (Hong Kong) + if (lang == nil) then + return s + end + + local path = self:Location(1, 2) .. "_" .. lang .. ".txt" + if (path == nil) or (path == "") then + return s + end + + local f = io.open(path, "r") + if (f == nil) then + return s + end + + local escapes = {a = '\a', b = '\b', f = '\b', n = '\n', r = '\r', t = '\t', v = '\v', ['\\'] = '\\', ["'"] = "'", ['"'] = '"'} + local c, n = 1, n or 1 + local k, v = "", "" + local cmd = f:read() + s = s:gsub('"', '\\"') --WIP! + + --print(lang, ", ", type(self.strings), ", ", self.strings[s]) + if self.strings ~= nil and self.strings[s] ~= nil and cmd:sub(1,3) ~= "WIP" then + return assert(load(('return "%s"'):format(self.strings[s])))() --.. "(In Table)" + end + while (cmd ~= nil) do + if cmd ~= "" then + k, v = cmd, f:read() --print(k, " || ", v) + --if s:find("Ignore") then print(s, " || ", k, " || ", v) end + while v ~= nil and v ~= "" do + if s == k and c == n then --print(k, " || ", v) + self.strings[k] = tostring(v) + s = assert(load(('return "%s"'):format(v)))() --s = tostring(v) + break + --return tostring(v) + end + v = f:read() + c = c + 1 + end + end + cmd = f:read() + c = 1 + end + f:close() + + return s +end + +--[[ +function LS.Localize(s) + local lang = "EN" --0 = EN, 1 = ES, 2 = DE + local tools = MOHO.Localize("/Windows/Tools/Title=Tools") --determine current language + if tools == "Herramientas" then + lang = "ES" + elseif tools == "Werkzeuge" then + lang = "DE" + end + --print(lang, type(self[lang]), self[lang][s]) + if self[lang] ~= nil and self[lang][s] ~= nil then + s = self[lang][s] + end + return s +end +--]] + +function LS.P1(frame, sep, ...) --(int, str, ...) + local s = "" + local sep = sep or ", " + local arg = {...} + if (self.frame ~= nil and frame ~= nil) and self.frame ~= frame then + for i, v in ipairs(arg) do + s = s .. tostring(v) .. (i ~= #arg and sep or "") --"\t" + end + print(s) + end + --self.frame = moho.frame +end + +---------------------------------------------------------------------------------------------------------- +LS.MohoDoc = LS.MohoDoc or {} -- MohoDoc Submodule +---------------------------------------------------------------------------------------------------------- + +-- MohoDoc Submodule attributes: +LS.MohoDoc.curLayer = 0 + +function LS.MohoDoc:GetCurLayer() --MohoLayer + local curLayer = nil + local selLayers = {} + local selCount = self:CountSelectedLayers() + + if selCount > 1 then + for i = 0, selCount - 1 do --storing current multi-selection + local layer = self:GetSelectedLayer(i) + table.insert(selLayers, layer) + end + + self:ClearSecondarySelection() --clearing current multi-selection + self:CountSelectedLayers() --THIS DUMMY LINE SEEMS TO MAKE IT WORK FOR WHATEVER REASON... + curLayer = self:GetSelectedLayer(0) --getting the working layer now that it's the only one selected + + for i = 1, #selLayers do --restoring the previous multi-selection + local layer = selLayers[i] + layer:SetSecondarySelection(true) + end + elseif selCount == 1 then + curLayer = self:GetSelectedLayer(0) + else + --self:Refresh() + if self.curLayer ~= nil then + curLayer = self.curLayer + else + return + end + end + + return curLayer +end + +function LS.MohoDoc:CountAllLayers(doc) --(MohoDoc) int + self = doc or self + if self ~= nil then + local count = 0 + repeat + local layer = self:LayerByAbsoluteID(count) + if layer then + count = count + 1 + end + until not layer + return count + end +end + +function LS.MohoDoc:ListLayers() --tbl + if self ~= nil then + local t = {} + local count = 0 + repeat + local layer = self:LayerByAbsoluteID(count) + if layer then + table.insert(t, layer:Name()) --t[count] = layer:Name() + count = count + 1 + end + until not layer + return t + end +end + +function LS.MohoDoc:Main2Action(prevAction, invert) --(str) bool + self = doc or self if self == nil then return end + prevAction = prevAction or "" + invert = invert or false --invert == nil and false or invert (NOT necessary here!) + local docAction = self:CurrentDocAction() + + if (invert and docAction == "") or (not invert and docAction ~= "") then --2023053-0005(ORIG): if docAction ~= "" then + if prevAction and (prevAction == "" and docAction ~= "") or prevAction ~= docAction then --print(prevAction, ", ", docAction .. "!!!") + return true + end + end + return false +end + +function LS.MohoDoc:ScanDoc(reverse, indent) --(int, int) tbl + reverse = reverse or 1 + indent = indent or 0 + t = {} + + for r = reverse == 1 and 0 or self:CountLayers() - 1, reverse == 1 and self:CountLayers() - 1 or 0, reverse == 1 and 1 or -1 do + local layer, group = self:Layer(r) + table.insert(t, {["layer"] = layer, ["AID"] = self:LayerAbsoluteID(layer), ["name"] = layer:Name(), ["indent"] = 0}) + if layer:IsGroupType() then + group = MOHO.ScriptInterface:LayerAsGroup(layer) + t[#t].isExpanded = group:IsExpanded() + LS.MohoLayer:ScanGroup(layer, t, reverse, indent) + end + end + return t +end + +---------------------------------------------------------------------------------------------------------- +LS.ColorOps = LS.ColorOps or {} -- Color Operations Submodule +---------------------------------------------------------------------------------------------------------- + +function LS.ColorOps:SetRgb(curRgb, newRgb) --(tbl, tbl) + curRgb.r = curRgb.r and newRgb.r or 0 + curRgb.g = curRgb.g and newRgb.g or 0 + curRgb.b = curRgb.b and newRgb.b or 0 + curRgb.a = curRgb.a and newRgb.a or 0 + return curRgb +end + +function LS.ColorOps:Hex2Model(hex, model) --(str, str) + hex = (hex and type(hex) == "string") and hex:gsub("#","") or "000000" + model = (model and type(model) == "string") and model:lower() or "rgb" + + local color = #hex == 6 and {r = tonumber("0x" .. hex:sub(1, 2)), g = tonumber("0x" .. hex:sub(3, 4)), b = tonumber("0x" .. hex:sub(5, 6))} or {r = tonumber("0x" .. hex:sub(1, 1)) * 17, g = tonumber("0x" .. hex:sub(2, 2)) * 17, b = tonumber("0x" .. hex:sub(3, 3)) * 17} + if model == "rgb" then + color = LM.ColorOps:RgbColor(color.r, color.g, color.b) + elseif model == "hsv" then + color = LM.ColorOps:HsvColor(color.r, color.g, color.b) + elseif model == "v" or model == "vec" or model == "vector" then + local cv = LM.ColorVector:new_local() cv:Set(color.r / 255, color.g / 255, color.b / 255) + color = cv + end + return color +end --print(LS.ColorOps:Hex2Model("#FF00FF", "hsv").h, ", ", LS.ColorOps:Hex2Model("#FF00FF", "hsv").s, ", ", LS.ColorOps:Hex2Model("#FF00FF", "hsv").v) + +---------------------------------------------------------------------------------------------------------- +LS.OS = LS.OS or {} -- OS/Sys Submodule +---------------------------------------------------------------------------------------------------------- + +function LS.OS:FileExists(path) --(str) bool NOTE: win only?? + local f = io.open(path, "r") + return f ~= nil and io.close(f) +end + +function LS.OS:GetOS() --str + return package.config:sub(1, 1) == "\\" and "win" or "unix" +end + +function LS.OS:Open(location) --(str) void + if LS.OS:GetOS() == "unix" then + os.execute('open "" "' .. location .. '"') + else + os.execute('start "" "' .. location .. '"') + end +end + +function LS.OS:ResourceExists(folder, keyword, kind) --(str, str, str ext) bool, str + folder = folder or "" + local resDir = MOHO.MohoGlobals.UserResourcesDir and MOHO.MohoGlobals.UserResourcesDir .. "\\" .. folder or "" + if lfs and lfs.chdir(resDir) then + for filename in lfs.dir(resDir) do + if kind then + if filename:lower():match("%." .. kind:lower() .. "$") then + local st, en, fileMatch = filename:find("^(" .. keyword .. ")") + if fileMatch then + return true, filename + end + end + else + local st, en, fileMatch = filename:find("^(" .. keyword .. ")") + if fileMatch then + return true, filename + end + end + end + end + return false +end --print(tostring(LS.OS:ResourceExists(_G.LS_PointLinker:Location(2), "icon", "lua"))) + +function LS.OS:ResourceListing(folder) --(tbl) tbl + folder = folder or "" + local resDir = MOHO.MohoGlobals.UserResourcesDir and MOHO.MohoGlobals.UserResourcesDir .. "\\" .. folder or "" + local resDirList = {} + if lfs and resDir and lfs.chdir(resDir) then + for filename in lfs.dir(resDir) do + if filename ~= "." and filename ~= ".." then + table.insert(resDirList, filename) + end + end + end + return #resDirList > 0 and resDirList or nil +end + +function LS.OS:ScriptDir(part) --(int) str | https://stackoverflow.com/a/74661335/2805176 + part = (part and (type(part)) == "number") and part or 1 + local dir = debug.getinfo(2, "S").source:sub(2) + return dir:match("(.*[/\\])") .. (part > 1 and debug.getinfo(2, "S").source:sub(2):match("[^/\\]*.lua$"):sub(0, -5) or "") .. (part > 2 and ".lua" or "") or "./" +end + +function LS.OS:SuitPath(path) --(str) str + return package.config:sub(1, 1) == "\\" and path:gsub("/", "\\") or path:gsub("\\", "/") +end + +---------------------------------------------------------------------------------------------------------- +LS.Data = LS.Data or {} -- Data Submodule +---------------------------------------------------------------------------------------------------------- + +function LS.Data:TableClone(t) + return {table.unpack(t)} +end + +function LS.Data:TableComparison(t1, t2) + if #t1 ~= #t2 then + return false + end + for i = 1, #t1 do + if t1[i] ~= t2[i] then + return false + end + end + return true +end + +function LS.Data:TableConcat(t, fSep, kSep) --(tbl, str, str) + local cTab, n, fSep, kSep = {}, 1, fSep or "", kSep or ": " + for k, v in pairs(t) do + if not ({["function"] = 0, table = 0, thread = 0, userdata = 0})[type(v)] then + cTab[n] = k .. kSep .. tostring(v) + n = n + 1 + end + end + return table.concat(cTab, fSep) +end --print(LS.Data:TableConcat({"ONE", "TWO", "THREE", ["One"] = "1", ["Two"] = "2", ["Three"] = "3"}, " | ")) + +function LS.Data:CountKeys(t, kind, s) + local count = 0 + for k in pairs(t) do + if kind ~= nil and type(k) == kind then --count only specified type of keys + if s ~= nil and k == "string" then + count = k:match(s) and count + 1 or count + else + count = count + 1 + end + elseif not type(k) == "number" and (k > 0 and math.floor(k) == k) then --count all but positive integers + count = count + 1 + end + end + return count +end + +function LS.Data:UUID(short) --(bool) str --20221209-1700: https://gist.github.com/jrus/3197011 + short = short == nil and false or short + local template = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx" + math.randomseed(os.time() + math.floor(10000*math.random())) + local uuid = (string.gsub(template, "[xy]", function (c) + local v = (c == "x") and math.random(0, 0xf) or math.random(8, 0xb) + return string.format("%x", v) + end)) + + return short and uuid:sub(1, 8) or uuid +end + +function LS.Data:UUIDAlt() + local tempLayer = MOHO.MohoLayer:new_local() + return tempLayer:UUID() +end + +---------------------------------------------------------------------------------------------------------- +LS.String = LS.String or {} -- String Submodule +---------------------------------------------------------------------------------------------------------- + +function LS.String:Centring(s, d, widgetWidth, margin, shift, char) --(str, dlog, int, int, int, str) str + widgetWidth, margin, shift, char = widgetWidth or 256, margin or 24, shift or 0, char or " " + local sWidth = 0 + if (s ~= nil and d ~= nil) then + d.dummyText = LM.GUI.DynamicText(s, 0) + sWidth = d.dummyText:Width() + else + return s + end + s = shift < 0 and s .. (char):rep(shift) or (char):rep(shift) .. s + while sWidth < widgetWidth - margin do + s = char .. s .. char + d.dummyText = LM.GUI.DynamicText(s, 0) --d.dummyText:SetValue(s) + sWidth = d.dummyText:Width() --print(sWidth) + end + return s +end + +function LS.String:Compact(s, lenght, from, mark) --(str, int, real, str) str + if s and length or #s > lenght then + from, mark = from or 0.5, mark or "…" -- "…" "..." " […] " "~" " | " "||" + if from <= 0 then -- 0: "...from left." + s = s:sub(-lenght) + s = (s:sub(1, 1) == " " and mark .. s:sub(2, #s) or mark .. s) -- remove possible space + elseif from >= 1 then -- 1: "From right..." + s = s:sub(1, lenght) + s = (s:sub(-1) == " " and s:sub(1, -2) .. mark or s .. mark) -- remove possible space + else -- 0.5/nil: "From...center", or >0.0/<1.0 to shift (Warning: emojis may affect extreme shititng results!) + s = s:sub(1, math.ceil(lenght * from)) .. mark .. s:sub(math.floor(-lenght * (1 - from))) -- remove possible space PENDING! + end + end + return s +end + +function LS.String:Decentring(s, d, shift, off, char) --(str, dlog, int, int, str) str + s, off, char = s or "", off or 0, char or " " + local sTail, sTailWidth = "", 0 + while sTailWidth < math.abs(shift) + off do --the offset is for compensating e. g. the space taken by menu widgets' right arrow + sTail = shift < 0 and sTail .. char or char .. sTail + d.dummyText = LM.GUI.DynamicText(sTail, 0) --d.dummyText:SetValue(s) + sTailWidth = d.dummyText:Width() - off + end --print(sTailWidth) + return shift < 0 and s .. sTail or sTail .. s --(s .. sTail):gsub('()',{[math.ceil(#(s .. sTail)/2)]="◧"}) --middle char test +end + +function LS.String:MultiLiner(s, width, sep, remove) --(dlog, str, int, bool) tbl --20221009-1330: http://www.wellho.net/resources/ex.php?item=u108/patplode + sep = sep or "%S+" + remove = remove == nil and true or remove + local w = LM.GUI.StaticText + local t = {words = {}, lines = {}} + local lineCount = 1 + local charCount = 0 + for i in string.gmatch(s, sep) do + table.insert(t.words, i) --t.words[wordCount] = i + charCount = #table.concat(t.lines, " ") + #table.concat(t.words, " ") + 1 --print(#s, ", ", charCount) + local lineWidth = LM.GUI.DynamicText(table.concat(t.words, " "), 0):Width() --print("Width: " .. d.lineWidth:Width()) + if lineWidth > width or charCount >= #s then + t.lines[lineCount] = table.concat(t.words, " ") + t.words = {} + lineCount = lineCount + 1 + end + end + return t.lines +end + +function LS.String:MultiText(d, s, sep, width, remove) --(dlog, str, int, bool) tbl --20221009-1330: http://www.wellho.net/resources/ex.php?item=u108/patplode + sep = sep or "%S+" + remove = remove == nil and true or remove + local t = {words = {}, lines = {}} + local lineCount = 1 + local charCount = 0 + for i in string.gmatch(s, sep) do + table.insert(t.words, i) --t.words[wordCount] = i + charCount = #table.concat(t.lines, " ") + #table.concat(t.words, " ") + 1 --print(#s, ", ", charCount) + d.lineWidth = LM.GUI.DynamicText(table.concat(t.words, " "), 0) --print("Width: " .. d.lineWidth:Width()) + if d.lineWidth:Width() > width or charCount >= #s then + t.lines[lineCount] = table.concat(t.words, " ") + t.words = {} + lineCount = lineCount + 1 + end + end + return t.lines +end + +function LS.String:Replace(substring, replacement, n) -- Plain replacement (all characters are non-magic) [https://stackoverflow.com/a/76013512/2805176] + return (self:gsub(substring:gsub("%p", "%%%0"), replacement:gsub("%%", "%%%%"), n)) +end + +function LS.String:SplitPath(path, n, alt) -- 1 .. 2 .. 3 == fullPath (alt == true -> 1: no last \/, 2: name + extension,3: no dot) + return (string.gsub(path, alt and "^(.-)[\\/]([^\\/]-%.([^\\/%.]-))%.?$" or "^(.-)([^\\/]-)(%.[^\\/%.]-)%.?$", "%" .. (n or 1))) -- "^(.-)([^\\/]-%.([^\\/%.]-))%.?$" (filename with extension) -- "^(.-)([^\\/]-)%.([^\\/%.]-)%.?$", "%" (exclude dot) -- string.match(path, "^(.-)([^\\/]-)(%.[^\\/%.]-)%.?$") (return 3 values version) +end + +function LS.String:String2KeyValue(s, sep) --(str, str) tbl + sep = sep or ":" --"%s" + local t = {} + for line in s:gmatch("(.-)\r?\n") do --for line in str:gmatch"[^\n]+" do + local k, v = line:match("%s*([^" .. sep .. "]+)%s*" .. sep .. "%s*(.-)%s*$") --local k, v = line:match("^(.-)" .. sep .. "(.-)$") --print(k, ", ", v) + if not k then -- line is not k:v pair, so add to array + table.insert(t, line) + else --line is k:v pair, so add to dict + t[k] = v + end + end + return t +end + +function LS.String:StringToKeyValue(s, sep) --(str, str) tbl + sep = sep or ":" --"%s" + local t = {} + for line in (s.."\n"):gmatch"(.-)\r?\n" do + for k, v in line:gmatch("([^:]+)" .. sep .. "([^:\n\r]+)") do --print(k, ", ", v) + if not k then -- line is not k:v pair, so add to array + table.insert(t, line) + else --line is k:v pair, so add to dict + t[k] = v + end + end + end + return t +end + +function LS.String:UnCamel(s) --(str) str + s = s or self + if type(s) == "string" then + local result = string.gsub(s, "%u", " %1"):gsub("(%d+)", " %1") + return (result:gsub("^%s*(.-)%s*$", "%1")) + else + return tostring(s) + end +end + +function LS.String:Acronymize(s, ignore) --(str, tbl) str | https://stackoverflow.com/a/47053374/2805176 + s = s or self + local ignored = {['a'] = true, ['an'] = true, ['and'] = true, ['in'] = true, ['for'] = true, ['of'] = true, ['the'] = true, ['to'] = true, ['or'] = true} -- default list of words to ignore + if ignore and type(ignore) == "table" then + for word in pairs(ignore) do + ignored[word] = ignore[word] + end + elseif ignore == false then + ignored = {} + end + + local words, ans = LS.String:UnCamel(s), {} + for w in words:gmatch "[%w\']+" do + if not ignored[w:lower()] or ignored[w:lower()] == false then + ans[#ans + 1] = w:sub(1, 1):upper() + end + end + return table.concat(ans) +end + +----------------------------------------------------- +-- The Script class constructor +----------------------------------------------------- +--[[20230510-0430: First method... +setmetatable(string, { + __index = function(t, k) + if k == "UnCamel" then + return LS.String.UnCamel + else + return rawget(t, k) + end + end +}) +--]] +--[[20230510-0620: Second method... +for k,v in pairs(LS.String) do -- add methods to the string library as is + rawset(string, k, v) +end +--]] +for k, v in pairs(LS.String) do -- add methods to the string library with a prefix + local newName = "LS_" .. k + LS.String[newName] = v + rawset(string, newName, v) +end + +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- +LS.GUI = LS.GUI or {} -- Module LS.GUI +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- + +LS.GUI.MSG = MOHO.MSG_BASE + +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- +LS.M = LS.M or {} -- Module (M = Moho/Module/Main) +---------------------------------------------------------------------------------------------------------- +---------------------------------------------------------------------------------------------------------- + +--[[ +-- Script Types +LS.M.ST_UNKNOWN = 0 +LS.M.ST_TOOL = 1 +LS.M.ST_MENU = 2 +LS.M.ST_EMBED = 3 +LS.M.ST_S = 4 + +-- Script Inventory Types +LS.M.SIT_UNKNOWN = 0 +LS.M.SIT_LAYER = 1 +LS.M.SIT_DOCUMENT = 2 + +-- Script Source Types +LS.M.SST_UNKNOWN = 0 +LS.M.SST_INSTALLED = 3 +LS.M.SST_LOCAL = 4 +LS.M.SST_REMOTE = 5 + +-- Other Properties +LS.M.UserAppDir = LS.M.UserAppDir or debug.getinfo(1, "S").source:sub(2):match("(.*)[/\\]"):match("(.*)[/\\]"):match("(.*)[/\\]") or "\\Scripts\\ScriptResources" --print(LS.M.UserAppDir or "NIL") +LS.M.UserScriptRes = LS.M.UserAppDir ~= nil and LS.M.UserAppDir .. "\\Scripts\\ScriptResources" or "\\ScriptResources" --print(LS.M.UserScriptRes or "NIL") +LS.M.UserScriptMod = MOHO.ScriptInterface ~= nil and MOHO.ScriptInterface:UserAppDir() .. "\\Scripts\\Modules" or "\\Modules" --print(LS.M.UserScriptMod or "NIL") +--]] + +return LS \ No newline at end of file diff --git a/README.md b/README.md new file mode 120000 index 0000000..558f146 --- /dev/null +++ b/README.md @@ -0,0 +1 @@ +ScriptResources/ls/docs/index.htm \ No newline at end of file diff --git a/ScriptResources/ls/docs/index.css b/ScriptResources/ls/docs/index.css new file mode 100644 index 0000000..dc3b7c5 --- /dev/null +++ b/ScriptResources/ls/docs/index.css @@ -0,0 +1,446 @@ +/* +ScriptName = "index.css" +ScriptBirth = "20240506-0030" +ScriptBuild = "20240525-0054" +*/ + +html, body { + height: 100%; + margin: 0; + padding: 0; + color: #CCC; + font-family: 'Segoe UI','Noto Sans',Helvetica,Arial,sans-serif,'Segoe UI Emoji'; + background-color: #272822; + accent-color: yellow; + scrollbar-color: SlateGrey DarkSlateGrey; + scrollbar-width: thin; +} + +* { + box-sizing: border-box; /* Includes padding and borders in width and height */ +} + +*:disabled { + opacity: 0.67; + pointer-events: none; + cursor: not-allowed; +} + +a:link { + text-decoration: none; + color: #7dcbff; +} + +a:visited { + color: #c680ff; + text-decoration: none +} + +a:hover { + text-decoration: underline; + color: #FFFF00; +} + +a:active { + text-decoration: none; + color: #ff8000; +} + +blockquote { + border-left: 6px solid yellow; + font-size: 16px; + margin: 0.25em 0px; + padding: 0.25em 1em; + background-color: #363D45; +} + +blockquote blockquote { + border-left: 2px solid dimgrey; + margin-left: 0.25em; /* Ajusta este valor según sea necesario */ + padding-left: 1em; /* Ajusta este valor según sea necesario */ +} + +blockquote code { + display: block; +} + +button { + color: inherit; + background-color: #333; + border: 1px solid #111; + border-radius: 4px; + margin: 0px 2px; + padding: 4px 8px; + text-align: center; + text-decoration: none; + display: inline-block; + white-space: nowrap; + font-size: small; +} + +button:hover { + background-color: #555; +} + +button:active { + color: inherit; + background-color: rgb(80, 80, 0); + border-color: yellow; + transform: translateX(1px) translateY(1px); +} + +details ul { + margin: 0; + padding: 0.25em 0 0.5em 1.25em; + list-style-type: none; +} + +h1 { + text-align: center; + color: yellow; + font-family: 'Josefin Sans', sans-serif; +} + +h2 { + text-align: center; + color: yellow; + font-family: 'Josefin Sans', sans-serif; +} + +hr { + height: 2px; + background-color: #444; + color: #333; + border: none; +} + +img.colorize { + image-rendering: crisp-edges; + filter: invert(1) sepia(1) hue-rotate(160deg) invert(1) hue-rotate(60deg) brightness(10000%) saturate(100%) drop-shadow(4px 2px 6px black); +} + +span { + margin: 0; + padding: 0; +} + +ul { + margin: 0; + padding: 0; + list-style-type: none; +} + +.center { + display: block; + margin: 0 auto; + text-align: center; +} + +.hs, .hs1, .hs2, .hs3 { /* Horizontal Separator*/ + display: block; + height: 2px; + width: 2px; + background-color: transparent; + border-bottom: 1px solid #ddd; +} +.hs1 {height: 4px;} +.hs2 {height: 8px;} +.hs3 {height: 16px;} + +/* Style the tab */ +.tab { + display: flex; + /* gap: 4px; */ + background-color: #333; + flex-shrink: 0; +} + +.tab-group { + margin: 0; + padding: 0; + width: 100%; + height: 100%; + border: 1px #333; /* And bellow: Best way to apply two-side-only border? */ + border-style: solid none; + box-shadow: inset 2px 4px 4px rgba(0,0,0,0.5); +} + +/* Style the buttons that are used to open the tab content */ +.tab button { + display: flex; + flex: 1; + color: inherit; + background-color: inherit; + border: none; + border-radius: 0; + outline: none; + margin: 0; + padding: 8px 4px; + align-items: center; + justify-content: center; + white-space: nowrap; /* Prevent text from wrapping */ + overflow: hidden; + text-overflow: ellipsis; + box-shadow: 2px 4px 4px rgba(0,0,0,0.5); + cursor: pointer; + transition: 0.3s; +} + +.tab button:nth-child(1) { + flex: 2; /* El primer botón ocupará 3 partes */ +} + +.tab button:nth-child(2) { + flex: 2; /* El segundo botón ocupará 2 partes */ +} + +/* Change background color of buttons on hover */ +.tab button:hover { + background-color: #666; +} + +.tab button:nth-child(1).active { + box-shadow: inset 0px 4px 4px rgba(0,0,0,0.5); +} + +/* Create an active/current tablink class */ +.tab button.active { + /* background: linear-gradient(to bottom, rgba(0,0,0,0.5) 0px, rgba(0,0,0,0) 10px); */ + background-color: #1E1F1C; /*#ccc*/ + box-shadow: inset 2px 4px 4px rgba(0,0,0,0.5); +} + +/* Style the tab content */ +.tabContent { + flex-grow: 1; + display: none; /* Keep this display:none initially */ + padding: 12px 8px 4px 8px; + /* border: 1px solid #ccc; */ + border-top: none; + overflow-y: auto; + scrollbar-width: thin; + animation: fadeEffect 0.3s; /* Fading effect takes 1 second */ +} + +/* Ensure the first visible tab has the correct display */ +.tabContent:first-of-type { + display: block; +} + +.tab .tab-text { + margin-left: 2px; + font-size: x-small; + font-weight: bold; + overflow: hidden; + text-overflow: ellipsis; +} + +.slider { + width: 100%; + height: 6px; + margin: 12px auto; + outline: none; +} + +.widget-group { + gap: 10px; + font-size: small; + margin-bottom: 8px; + padding: 12px 8px; + border-radius: 4px; + border: 1px solid #444; +} + +.widget-group2 { + display: grid; /* Enable CSS Grid Layout */ + grid-template-columns: auto 1fr; /* Define column widths */ + justify-content: end; +} + +#layout { + display: flex; + height: 100%; + overflow-y: hidden; +} + +#menu { + display: flex; + flex-direction: column; + height: 100%; + width: 15%; /* Initial width, 224px */ + min-width: 144px; + max-width: 288px; + margin: 0; + padding: 0; + overflow: hidden; + text-overflow: ellipsis; + resize: horizontal; + background-color: #1E1F1C; + box-shadow: 4px 0px 8px rgba(0,0,0,0.5); + z-index: 1; +} + +/* +#menu::after { + position: absolute; + left: 0px; + bottom: 0px; + right: 0px; + width: 90%; + max-width: fit-content; + height: fit-content; + display: flex; + vertical-align: bottom; + text-align: center; + justify-content: center; + align-items: flex-end; + margin: auto; + padding: 8px 4px; + font-size: 9px; + color: #CCC; + content: 'Copyright © 2024 · Rai López · All Rights Reserved'; + background: linear-gradient(to top, rgba(30,31,28,1) 25%, rgba(30,31,28,0) 100%); + pointer-events: none; +} +*/ + +#menu-header { + top: 0; /* Remain at the top of the container */ + margin: 0; + padding: 0; + width: 100%; + border-bottom: 1px solid #333; + /* background: linear-gradient(to bottom, rgba(0,0,0,0.5) 0px, rgba(0,0,0,0) 10px); */ + box-shadow: inset 2px 4px 4px rgba(0,0,0,0.5); +} + +#menu-logo { + width: 33%; + min-width: 32px; + max-width: 128px; + margin: 0px auto -2px auto; + padding: 0; + font-size: 24px; +} + +#menu-search { + width: 90%; /* Full-width */ + font-size: 12px; /* Increase font-size */ + padding: 3px 5px 3px 10px; /* Add some padding */ + border: 1px solid #ddd; /* Add a grey border */ + margin: 0 auto 8px auto; +} + +#menu-search::placeholder { + text-align: right; + opacity: 0.67; +} + +#menu-content { + flex-grow: 1; + display: flex; + flex-direction: column; + margin: 0; + padding: 0; + width: 100%; + height: auto; /* Remove fixed height */ + overflow-y: auto; + scrollbar-width: thin; +} + +#menu-content1 { + display: flex; + flex-direction: column; + flex-grow: 1; + overflow-y: hidden; +} + +#menu-footer { + width: 100%; + height: fit-content; + text-align: center; + justify-content: center; + /* align-items: flex-end; */ + margin: 0 auto; + padding: 8px 6px; + color: inherit; + border-top: 1px solid #333; + box-shadow: inset 2px 4px 4px rgba(0,0,0,0.5); + container-type: inline-size; /* Defines the element as a container */ + /* background: linear-gradient(to bottom, rgba(0,0,0,0.5) 0px, rgba(0,0,0,0) 10px); */ + /*pointer-events: none;*/ /* no react to pointer events */ +} + +#menu-footer span { + font-size: 8px; /* Fallback for unsupported browsers */ + font-size: clamp(8px, 4.5cqw, 12px); /* Minimum 8px, based on 4.5cqw, Maximum 12px */ +} + +#menu-list { + padding: 0px 8px; + /* border: 1px solid red; */ +} + +.menu-item { + display: list-item; + overflow-x: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 14px; + font-weight: bold; + padding: 0px 4px; + cursor: pointer; +} + +.menu-details summary { + margin: 4px 0 0 0; + padding: 2px 4px; + cursor: pointer; + border-radius: 4px; +} + +.menu-details[open] summary { + background-color: #333; +} + +.menu-summary { + display: list-item; + overflow-x: hidden; + white-space: nowrap; + text-overflow: ellipsis; + font-size: 14px; + font-weight: bold; +} + +#iContainer { + flex-grow: 1; /* Occupy the remaining space */ + margin: 0; + padding: 0; + overflow-y: hidden; +} + +#iFrame { + margin: 0; + padding: 0; + overflow-y: auto; + scrollbar-color: orange yellow; + scrollbar-width: thin; + /*border: 1px solid yellow;*/ +} + +#content { + /* box-sizing: border-box; */ + width: 80%; + max-width: 1080px; + min-width: 360px; + margin: 0 auto 0 auto; + padding: 10px 5%; + overflow: hidden; + /*border: 1px solid yellow;*/ +} + +/* Go from zero to full opacity */ +@keyframes fadeEffect { + from {opacity: 0;} + to {opacity: 1;} +} \ No newline at end of file diff --git a/ScriptResources/ls/docs/index.htm b/ScriptResources/ls/docs/index.htm new file mode 100644 index 0000000..9340737 --- /dev/null +++ b/ScriptResources/ls/docs/index.htm @@ -0,0 +1,368 @@ + + + + + + + + + + + + + + + + + + + + + + + + + +

Lost Scripts Project

+ + + + + + + + + + + + + +
+ Lost Scripts + + Moho version + GitHub version + GitHub downloads +
+ Script icon + +
+ The Lost Scripts Project is responsible for providing all the necessary shared/common files and helpers that Moho® needs for the well functioning of Lost Scripts™. Click to expand details... +
+

Overview/Contents:

+
+
+
+
📂 ls
+
📁 Menu
+
📁 - Lost Scripts
+ 📄 ls_webpage.lua +
+ 📄 ls_separator.lua +
+
📁 Modules
+
+					 📄 ls_gui.lua
+					 📄 ls_modules.lua
+					
+
+
📁 ScriptResources
+
📁 ls
+ 🖼 logo.png +
+
+
📁 Tool
+ 📄 _tool_list_ls.txt +
+
📁 Utility
+ 📄 ls_utilities.lua +
+
+
+
+
+ For (even) more info, visit project's webpage... +
+
+ + +

📦 Contents

+ + + + +
+
+
📂 ls +
+
📁 Menu +
+
📁 - Lost Scripts +
+ 📄 ls_webpage.lua +
+
+ 📄 ls_separator.lua +
+
+
📁 Modules +
+
+							 📄 ls_gui.lua
+							 📄 ls_modules.lua
+							
+
+
+
📁 ScriptResources +
+
📁 ls +
+ 🖼 logo.png +
+
+
+
+
📁 Tool +
+ 📄 _tool_list_ls.txt +
+
+
📁 Utility +
+ 📄 ls_utilities.lua +
+
+
+
+
+
+ +

✨ Featured Scripts

+ + + + + + + + + + + + + +
+ Shapes Window + + Moho version + GitHub version + GitHub downloads +
+ Script icon + +
+ A persistent shape palette plus many other helpers for better management of Moho® vectors in general and Liquid Shapes in particular. Click to expand details... +
+

Main Features:

+
+
+
    +
  • Visualize layers' shape relationships at a glance.
  • +
  • Take the most of Liquid Shapes thanks to improved management.
  • +
  • Rename, reorder, hide/show, etc. one or several shapes with ease.
  • +
  • New ways of shape creation independently of selected tool.
  • +
  • Shape selection helpers: Select all, Inverse, Similar, Identical...
  • +
  • Improved style management, picking and modification.
  • +
  • Many interactive "live" Swatches (and you can easily make your own).
  • +
  • Recoloring features plus other helpers.
  • +
  • Several window display modes to better suit your needs.
  • +
+
+
+ For (even) more info, visit script's webpage... +
+
+ + + + + + + + + + + + + + +
+ Script Placeholder + + Moho version + GitHub version + GitHub downloads +
+ Script icon + +
+ Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum. Click to expand details... +
+

Main Features:

+
+
+
    +
  • Awesome feature 1.
  • +
  • Awesome feature 2.
  • +
  • Awesome feature 3
  • +
  • ...
  • +
+
+
+ For (even) more info, visit script's webpage... +
+
+ +

🔗 Links of Interest

+ + + + + + + + +
+ 👉 Go to the Lost Scripts™ website... + + 👉 Go to the Lost Marble Forum topic... +
+ +

⚙ Installation (Two Ways)

+ + + + + + + + + + + + + + + + +
MANUALAUTOMATIC
+
    +
  1. Unzip the downloaded file.
  2. +
  3. You'll get one or more of the following folders: Menu | ScriptResources | Tool | Utility
  4. +
  5. Drag & Drop (or Copy & Paste) all of them into the Scripts folder of your Custom Content Folder (overwrite if prompted).
  6. +
  7. Restart Moho® or press "Alt + Shift + Ctrl + L" to Reload Tools And Brushes and that should be all.
  8. +
    +
+
+
    +
  1. Unzip the downloaded file.
  2. +
  3. From Moho's main menus, go to "Scripts -> Install Script..." and a window with some info will appear.
  4. +
  5. Press "Select A Script Folder" button, browse to the just uzipped folder (e.g. ls_shapes_window) and select it.
  6. +
  7. That should be all. You can read chapter 23.17 Install Script... of Moho® user's manual for further details.
  8. +
    +
+
+
WARNING: Please, make sure you have uninstalled every Lost Script on your system before removing any of these shared resources or they may start throwing errors or stop working. For uninstalling a script, just remove any file and folder matching its name and restart Moho® or Reload Tools And Brushes if necessary.
+ +
+ +

🤝 Collab & Support

+

Suggestions and bugs can be reported in the Issues section (or in the corresponding topic, if any, in Scripting section of the Lost Marble Forum).

+ + +
+

Copyright © 2024 · Rai López · All Rights Reserved

+
+ + + + \ No newline at end of file diff --git a/ScriptResources/ls/docs/index.html b/ScriptResources/ls/docs/index.html new file mode 100644 index 0000000..9ab87b6 --- /dev/null +++ b/ScriptResources/ls/docs/index.html @@ -0,0 +1,237 @@ + + + + Lost Scripts + + + + + + + + + + + + +
+ +
+ +
+
+ + + + diff --git a/ScriptResources/ls/docs/index.js b/ScriptResources/ls/docs/index.js new file mode 100644 index 0000000..9239b7c --- /dev/null +++ b/ScriptResources/ls/docs/index.js @@ -0,0 +1,249 @@ +/* +ScriptName = "index.js" +ScriptBirth = "20240506-0030" +ScriptBuild = "20240707-1450" +*/ + +if (!window.scriptLoaded) { //If scriptLoaded is not true (or not defined), run this block and set scriptLoaded to true. + window.scriptLoaded = true; + var currentScriptPath = document.currentScript.src; + var isExpanded = false; // Initial state, all contracted + + document.addEventListener('DOMContentLoaded', function() { + if (window.self === window.top) { // if not in an iframe... + var scriptPath = currentScriptPath; + + if (scriptPath) { //(scriptPath && window.self === window.top) + var dirPath = scriptPath.slice(0, scriptPath.lastIndexOf('/') + 1); // Use substring instead of slice? + var indexPath = dirPath + "index.html"; + var pagePath = window.location.href; // Use window.location.pathname instead? + var pagePathRel = getRelativePath(dirPath, pagePath); // Output e.g.: "../../ls_script/docs/index.html" + var newPath = indexPath + "#" + pagePathRel; // Construct the new URL with the relative path after hash + + window.location.href = newPath; // Redirect to index.html with the final path + } else { + console.error('No se pudo encontrar el tag de script para index.js'); + } + } else { + var basicStyles = document.getElementById('basic-styles'); + if (basicStyles) { // It doesn't seem to be necessary if they are declared before loading index.css, but remove basic styles if you are in an iFrame, just in case? + basicStyles.parentNode.removeChild(basicStyles); + console.log('Estilos básicos eliminados en el iFrame.'); + } + } + + //handleResourceErrors(); // Initialize resource error handling (Using inline solution due to ramdom fails) + //handleImageErrors(); // Initialize image error handling (Using inline solution due to ramdom fails) + + /* + var pages = [ + { name: 'Home', url: 'index.htm' }, + { name: 'Installation', url: 'index_installation.html' }, + { name: 'Other', url: 'index_other.html' }, + { + name: 'Category 1', + content: [ + { name: 'Subpage 1.1', url: 'index_subpage1.html' }, + { name: 'Subpage 1.2', url: 'index_subpage2.html' } + ] + }, + { + name: 'Category 2', + content: [ + { name: 'Subpage 2.1', url: 'index_subpage1.html' }, + { name: 'Subpage 2.2', url: 'index_subpage2.html' } + ] + }, + // ... more pages and categories ... + ]; + + function createTreeView(container, items) { + items.forEach(function(item) { + if (item.content) { // If it has content, it is a category + var details = document.createElement('details'); + details.id = 'menu-details'; + var summary = document.createElement('summary'); + summary.textContent = item.name; + summary.id = 'menu-summary'; + //summary.style['font-weight'] = 'bold'; + details.appendChild(summary); + + var nestedList = document.createElement('ul'); + createTreeView(nestedList, item.content); // Recursive call for subpages + details.appendChild(nestedList); + container.appendChild(details); + } else { // Otherwise, it is a normal page + var listItem = document.createElement('li'); + listItem.textContent = item.name; + listItem.id = 'menu-item'; + //listItem.style['font-weight'] = 'bold'; + listItem.setAttribute('data-url', item.url); + listItem.onclick = function() { + loadContent(item.url); + }; + container.appendChild(listItem); + } + }); + } + + function loadContent(url) { + var iframe = document.getElementById('iframe') || document.createElement('iframe'); + iframe.style.width = '100%'; + iframe.style.height = '100%'; + iframe.style.margin = '0'; + iframe.style.padding = '0'; + iframe.style['overflow-y'] = 'auto'; + iframe.style['scrollbar-color'] = 'orange yellow'; + iframe.style['scrollbar-width'] = 'thin'; + // iframe.scrolling= 'yes'; + iframe.frameborder = '0'; + iframe.marginwidth = '0'; + iframe.marginheight = '0'; + iframe.id = 'iframe'; + iframe.src = url; + + var contentDiv = document.getElementById('icontainer'); + contentDiv.innerHTML = ''; + contentDiv.appendChild(iframe); + } + + var menu = document.getElementById('menu'); + var list = document.createElement('ul'); + list.id = 'menu-list'; + createTreeView(list, pages); // Start construction of the navigation menu + menu.appendChild(list); + */ + }); + + function handleResourceErrors() { // Ensure valid resource paths for index.html + const resources = document.querySelectorAll('img, script, link[rel="stylesheet"]'); + + resources.forEach(resource => { + resource.onerror = function() { + this.onerror = null; + const fileName = this.getAttribute('src') || this.getAttribute('href'); + if (fileName) { + const newFileName = fileName.split('/').pop(); + if (this.tagName.toLowerCase() === 'img') { + this.src = newFileName; + } else if (this.tagName.toLowerCase() === 'script' || this.tagName.toLowerCase() === 'link') { + if (this.tagName.toLowerCase() === 'script') { + this.src = newFileName; + } else { + this.href = newFileName; + } + } + } + }; + }); + } + + function handleImageErrors() { // Ensure valid image paths for index.html (using handleResourceErrors instead) + const images = document.querySelectorAll('img'); + + images.forEach(img => { + img.onerror = function() { + this.onerror = null; + const fileName = this.getAttribute('src').split('/').pop(); + this.src = fileName; + }; + }); + } + + function getRelativePath(source, target) { + // Split the paths into arrays of directories + const fromParts = source.split('/'); + const toParts = target.split('/'); + + // Remove the file name from source + fromParts.pop(); + + // Find the index at which the paths diverge + let i = 0; + while (i < fromParts.length && i < toParts.length && fromParts[i] === toParts[i]) { + i++; + } + + // Calculate the number of directories to go up from the source + const numUpDirs = fromParts.length - i; + + // Construct the relative path + let relativePath = ''; + for (let j = 0; j < numUpDirs; j++) { + relativePath += '../'; + } + for (let k = i; k < toParts.length; k++) { + relativePath += toParts[k]; + if (k < toParts.length - 1) { + relativePath += '/'; + } + } + + return relativePath; + } + + function getRelativePathAlt(source, target) { + var sep = (source.indexOf("/") !== -1) ? "/" : "\\", + targetArr = target.split(sep), + sourceArr = source.split(sep), + relativePath = ""; + + // Remove protocol and host to work only with the file path + sourceArr = sourceArr.slice(3); + targetArr = targetArr.slice(3); + + // Find the index where paths diverge + var i = 0; + while (sourceArr[i] && sourceArr[i] === targetArr[i]) { + i++; + } + + // Add ".."" for each remaining directory in the source + for (var j = i; j < sourceArr.length - 1; j++) { // -1 para no contar el directorio actual + relativePath += ".." + sep; + } + + // Add the remaining directories of the target + for (var k = i; k < targetArr.length; k++) { + relativePath += targetArr[k] + sep; + } + + // Remove final separator if necessary + if (!target.endsWith(sep)) { + relativePath = relativePath.slice(0, -1); + } + + return relativePath; + } + + /* + function toggleExpansion() { + const detailsElements = document.querySelectorAll("details"); + const toggleButton = document.getElementById('toggleButton'); + + detailsElements.forEach(item => { + if (!isExpanded) { + item.setAttribute("open", ""); + } else { + item.removeAttribute("open"); + } + }); + + // Change button state and text + isExpanded = !isExpanded; + toggleButton.textContent = isExpanded ? "Contract All" : "Expand All"; + } + */ + + function set_theme(name){ + document.cookie = 'sel_theme='+name+';'; + } // so, run set_theme('whatevername'); when it is set by the user (SOURCE: https://stackoverflow.com/a/1616973/2805176) + + window.onload=function(){ + var cookie_pos = document.cookie.indexOf('sel_theme='); // locate value in cookie + if(cookie_pos != -1){ // if string was found + var cookie_flavor = substr(cookie_pos + 10, document.cookie.indexOf(';', cookie_pos)); // extract the value of the cookie + // then run your already existing change theme function using the extracted name (SOURCE: https://stackoverflow.com/a/1616973/2805176) + } + } +} \ No newline at end of file diff --git a/ScriptResources/ls/docs/index_favicon.svg b/ScriptResources/ls/docs/index_favicon.svg new file mode 100644 index 0000000..6291dfd --- /dev/null +++ b/ScriptResources/ls/docs/index_favicon.svg @@ -0,0 +1,17 @@ + + + + + + + + diff --git a/ScriptResources/ls/docs/index_icon_shapes_window.png b/ScriptResources/ls/docs/index_icon_shapes_window.png new file mode 100644 index 0000000..7cb4637 Binary files /dev/null and b/ScriptResources/ls/docs/index_icon_shapes_window.png differ diff --git a/ScriptResources/ls/docs/index_icon_unknown.png b/ScriptResources/ls/docs/index_icon_unknown.png new file mode 100644 index 0000000..765fe22 Binary files /dev/null and b/ScriptResources/ls/docs/index_icon_unknown.png differ diff --git a/ScriptResources/ls/docs/index_installation.htm b/ScriptResources/ls/docs/index_installation.htm new file mode 100644 index 0000000..01652ca --- /dev/null +++ b/ScriptResources/ls/docs/index_installation.htm @@ -0,0 +1,71 @@ + + + + + INSTALACIÓN + + + + + + + + + + + + + + +
+

INSTALLATION

+

There are actually two ways for installing custom scripts in Moho® and they apply the same to this kind of shareed resources container, so (as usually) you can choose the one that better suit your needs...

+ + + + + + + + + +

Manual Installation

Automatic Installation

+
    +
  1. Unzip the downloaded file.
  2. +
  3. You'll get one or more of the following folders: Menu | ScriptResources | Tool | Utility
  4. +
  5. Drag & Drop (or Copy & Paste) all of them into the Scripts folder of your Custom Content Folder (overwrite if prompted).
  6. +
  7. Restart Moho® or press "Alt + Shift + Ctrl + L" to Reload Tools And Brushes and that should be all.
  8. +
+
+
    +
  1. Unzip the downloaded file.
  2. +
  3. From Moho's main menus, go to "Scripts -> Install Script..." and a window with some info will appear.
  4. +
  5. Press "Select A Script Folder" button, browse to the just uzipped folder (e.g. ls_shapes_window) and select it.
  6. +
  7. That should be all. You can read chapter 23.17 Install Script... of Moho® user's manual for further details.
  8. +
+
+
WARNING: Please, make sure you have uninstalled every Lost Script on your system before removing any of these shared resources or they may start throwing errors or stop working. For uninstalling a script, just remove any file and folder matching its name and restart Moho® or Reload Tools And Brushes if necessary.
+ +
+
+ + \ No newline at end of file diff --git a/ScriptResources/ls/docs/index_logo.png b/ScriptResources/ls/docs/index_logo.png new file mode 100644 index 0000000..8ff1fe0 Binary files /dev/null and b/ScriptResources/ls/docs/index_logo.png differ diff --git a/ScriptResources/ls/docs/index_logo_2.png b/ScriptResources/ls/docs/index_logo_2.png new file mode 100644 index 0000000..761e8a7 Binary files /dev/null and b/ScriptResources/ls/docs/index_logo_2.png differ diff --git a/ScriptResources/ls/docs/index_logo_d.png b/ScriptResources/ls/docs/index_logo_d.png new file mode 100644 index 0000000..9abc685 Binary files /dev/null and b/ScriptResources/ls/docs/index_logo_d.png differ diff --git a/ScriptResources/ls/docs/index_other.htm b/ScriptResources/ls/docs/index_other.htm new file mode 100644 index 0000000..b425ac3 --- /dev/null +++ b/ScriptResources/ls/docs/index_other.htm @@ -0,0 +1,22 @@ + + + + + OTHER... + + + + + + + + + + + +
+

Other

+

Cuerpo...

+
+ + \ No newline at end of file diff --git a/ScriptResources/ls/logo.png b/ScriptResources/ls/logo.png new file mode 100644 index 0000000..c7f7957 Binary files /dev/null and b/ScriptResources/ls/logo.png differ diff --git a/Tool/_tool_list_ls.txt b/Tool/_tool_list_ls.txt new file mode 100644 index 0000000..6b573cf --- /dev/null +++ b/Tool/_tool_list_ls.txt @@ -0,0 +1,6 @@ +/* anime_version 11200001 */ +/* keyboard shortcuts are now set in the application */ +/* for format compatibility placeholders are retained below */ + +group Lost Scripts™ +button ls_shapes_window ... diff --git a/Utility/ls_utilities.lua b/Utility/ls_utilities.lua new file mode 100644 index 0000000..3d44eb3 --- /dev/null +++ b/Utility/ls_utilities.lua @@ -0,0 +1,127 @@ +-- ************************************************** +-- Provide Moho with the name of this script object +-- ************************************************** + +ScriptName = "LS_Utilities" +ScriptBirth = "20220918-0248" +ScriptBuild = "20240717-0348" + +-- ************************************************** +-- General information about this script +-- ************************************************** + +LS_Utilities = LS_Utilities or {["ScriptName"] = ScriptName, ["ScriptBirth"] = ScriptBirth, ["ScriptBuild"] = ScriptBuild} + +function LS_Utilities:Name(i) + return ({"Lost Utilities", ScriptName = self.ScriptName, Short = "LSU", UUID = "0c48445e-2774-4701-8712-9be38418c85f"})[i or 1] +end + +function LS_Utilities:Version(i) + return ({"0.0.1", Build = self.ScriptBuild, App = "14.2"})[i or 1] +end + +function LS_Utilities:Description(i) + return ({MOHO.Localize("/LS_Utilities/Description=Lost utilities container. It provides a number of useful utilities, loads modules and is also an alternative way to extend them."), Type = "UtilityScript", LayerType = {[0] = MOHO.LT_UNKNOWN}})[i or 1] +end + +function LS_Utilities:Creator(i) + return ({"Rai López", Company = "Lost Scripts™", Team = "", Ack = {"Lost Marble team", "Supportive folks at Moho (Scripting) forum"}})[i or 1] +end + +function LS_Utilities:UILabel(i) + return ({MOHO.Localize("/LS_Utilities/Utilities=Lost Utilities"), Labels = "Utilities, Utility, Utils, Helpers, Help"})[i or 1] --"Lost Scripts Modules" --DON'T LOCALIZE! +end + +function LS_Utilities:ColorizeIcon(i, j) + return ({true, Icon = "🛠", Color = ({[0] = "#838383", "#DC4040", "#F0A000", "#F0F000", "#40DC40", "#4040DC", "#C060F0", "#D2B48C", "#FFC0CB", "#40E0D0", "#5F9EA0", "#FF7F50"})[j or 0]})[i or 1] +end --print(LS_Utilities:ColorizeIcon("Color", 2)) + +function LS_Utilities:Source(i, j) + return ({"github.com/lost-scripts/ls", "bitbucket.org/lostscripts/ls", Web = ({"lost-scripts.github.io", "lostscripts.bitbucket.io"})[j or 1], Host = ({"github", "bitbucket"})[j or 1], User = ({"lost-scripts", "lostscripts"})[j or 1]})[i or 1] +end --print(LS_Utilities:Source("Web", 2)) + +function LS_Utilities:Location(f, l, s) --fullPath: 1, 3 --ScriptLocation()? + return table.concat({debug.getinfo(1).source:sub(2, -#debug.getinfo(1, "S").source:match("[^/\\]*.lua$") - 1), debug.getinfo(1, "S").source:sub(2):match("[^/\\]*.lua$"):sub(0, -5), ".lua"}, s or "", f or 1, (l and l > f) and l or f or 1) +end + +-- ************************************************** +-- Recurring values +-- ************************************************** + +math.randomseed(os.time()) +math.random() +math.random() +math.random() + +-- ************************************************** +-- Other MOHO utility functions... +-- ************************************************** + +--local cpath = "C:\Program Files\MB\?.dll;C:\Program Files\MB\..\lib\lua\5.4\?.dll;C:\Program Files\MB\loadall.dll;.\?.dll;C:\Program Files\MB\Resources\Support\Scripts\Modules\?.dll;D:\Ramon0\Projects\Moho Pro\Scripts\Modules\?.dll" +function MOHO.GetDir(paths, ext) --(str, str) str + for path in string.gmatch(paths, "([^;]+)") do + if string.find(path, "Moho Pro\\Scripts\\Modules") then + return (ext and path:gsub("%?%.([^.]+)", "?." .. ext) or path) --return (ext and path:gsub("%?%.%a+$", "?." .. ext) or path) -- OPTION 2 + end + end +end + +function MOHO.GetAbsDir(path) --(str) str + path = path or "" + local absDir + if lfs ~= nil then + local oldDir = lfs.currentdir() + lfs.chdir(path) + absDir = lfs.currentdir() + lfs.chdir(oldDir) + else --just in case? + local cmd = io.popen("cd /D " .. path .. " && cd") + absDir = cmd:read("*a"):gsub("\n", "") + cmd:close() + end + return absDir or path +end + +function MOHO.GetLocation(rel) --(str) str + rel = rel or "" + local path = debug.getinfo(1).source:sub(2, -#debug.getinfo(1, "S").source:match("[^/\\]*.lua$") - 1) --"D:\\Ramon0\\Projects\\Moho Pro\\Scripts\\Modules\\?.lua" + return path .. rel +end + +-- LS Utilities' Properties/Constants: +MOHO.MohoGlobals.UserUtilityDir = debug.getinfo(1).source:sub(2, -#debug.getinfo(1, "S").source:match("[^/\\]*.lua$") - 1) --local script_path = (debug.getinfo(1).source:match("@?(.*)[\\/][^\\/]+$") or ".") .. package.config:sub(1,1) +MOHO.MohoGlobals.UserModulesDir = MOHO.GetAbsDir(MOHO.MohoGlobals.UserUtilityDir .. "..\\Modules\\") +MOHO.MohoGlobals.UserResourcesDir = MOHO.GetAbsDir(MOHO.MohoGlobals.UserUtilityDir and MOHO.MohoGlobals.UserUtilityDir .. "..\\ScriptResources" or "\\ScriptResources") +MOHO.MohoGlobals.UserScriptsDir = MOHO.GetAbsDir(MOHO.MohoGlobals.UserUtilityDir .. "..\\") +MOHO.MohoGlobals.UserAppDir = MOHO.GetAbsDir(MOHO.MohoGlobals.UserUtilityDir .. "..\\..\\") + +-- ************************************************** +-- Load/Preload LS Module & Submodules +-- ************************************************** + +local path = MOHO.GetDir(package.cpath, "lua") --local path2 = MOHO.ScriptInterface:UserAppDir() .. "\\Scripts\\Modules\\?.lua" --(20230716-1706) +if not string.find(package.path, MOHO.MohoGlobals.UserUtilityDir, 1, true) and not string.find(package.path, path, 1, true) then -- busca la ruta como una cadena literal en toda package.path + package.path = package.path .. ";" .. MOHO.MohoGlobals.UserUtilityDir .. "..\\Modules\\?.lua" .. ";" .. path --print(package.path) +end + +-- Modules loading... +package.loaded["ls_modules"] = nil --Ensures the module is loaded upon reloading tools and brushes! +LS = require("ls_modules") + +-- ************************************************** +-- LS utility functions... +-- ************************************************** + +function LS_Utilities.RandomInt(min, max) + local f = math.random() + return LM.Round(LM.Lerp(f, min, max)) +end + +-- ************************************************** +-- Other LS module utility functions... +-- ************************************************** + +function LS.RandomInt(min, max) + local f = math.random() + return LM.Round(LM.Lerp(f, min, max)) +end \ No newline at end of file diff --git a/docs b/docs new file mode 120000 index 0000000..ea101e3 --- /dev/null +++ b/docs @@ -0,0 +1 @@ +ScriptResources/ls/docs \ No newline at end of file