Download CommonLua/X/XTemplate.lua from sirnii/myspace: direct link, hf CLI and curl.
- Browser
- Download file 50.3 kB
-
https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/X/XTemplate.lua
- Command line
-
hf download hf://spaces/sirnii/myspace/CommonLua/X/XTemplate.lua
-
curl -L -o XTemplate.lua https://huggingface.co/spaces/sirnii/myspace/resolve/main/CommonLua/X/XTemplate.lua
50.3 kB
| XWindowPropertyTabs = { | |
| { TabName = "Layout", Categories = { Layout = true, Children = true, } }, | |
| { TabName = "Visual", Categories = { Visual = true, FX = true, } }, | |
| { TabName = "Image", Categories = { Image = true, Animation = true, Icons = true --[[Zulu]], } }, | |
| { TabName = "Behavior", Categories = { General = true, ["Most Recently Used Items"] = true, Interaction = true, Scroll = true, Actions = true, GedApp = true, Progress = true --[[Zulu]], } }, | |
| { TabName = "Rollover", Categories = { Rollover = true, } }, | |
| } | |
| function XTemplateClass(template_id) | |
| local templates = XTemplates | |
| for i = 1, 100 do | |
| local template = templates[template_id] | |
| local t = template and template.__is_kind_of or "" | |
| if t == "" then | |
| return g_Classes[template_id] and template_id | |
| end | |
| template_id = t | |
| end | |
| return "" | |
| end | |
| function XTemplateCombo(class, include_base) | |
| return function(obj, prop_meta, validate_fn) | |
| if validate_fn == "validate_fn" then | |
| -- function for preset validation, checks whether the property value is from "items" | |
| return "validate_fn", function(value, obj, prop_meta) | |
| if value == "" then return true end | |
| class = class or "XWindow" | |
| local template = XTemplates[value] | |
| return template and IsKindOf(g_Classes[template.__is_kind_of], class) or IsKindOf(g_Classes[value], class) and (include_base ~= false or value ~= class) | |
| end | |
| end | |
| -- list all classes | |
| local list = ClassDescendantsCombo(class or "XWindow", include_base ~= false)() | |
| -- list all templates of this class | |
| ForEachPreset("XTemplate", function(template, group, list) | |
| if not class or IsKindOf(g_Classes[XTemplateClass(template.__is_kind_of)], class) then | |
| list[#list + 1] = template.id | |
| end | |
| end, list) | |
| return list | |
| end | |
| end | |
| ----- XTemplate | |
| DefineClass.XTemplate = { | |
| __parents = { "Preset" }, | |
| properties = { | |
| { category = "Template", id = "__is_kind_of", name = "Is kind of", editor = "choice", default = "", items = XTemplateCombo(), }, | |
| { category = "Template", id = "__content", name = "Template content parent", editor = "expression", params = "parent, context"}, | |
| { category = "Template", id = "recreate_after_save", name = "Recreate dialog after save", editor = "bool", default = false, }, | |
| { category = "Template", id = "RequireActionSortKeys", name = "Require sort keys", editor = "bool", default = false, }, | |
| }, | |
| GlobalMap = "XTemplates", | |
| HasSortKey = true, | |
| SingleFile = false, | |
| ContainerClass = "XTemplateElement", | |
| GedEditor = "XTemplateEditor", | |
| EditorShortcut = "Alt-F3", | |
| EditorName = "XTemplate", | |
| EditorMenubarName = "XTemplate Editor", | |
| EditorMenubar = "Editors.UI", | |
| EditorIcon = "CommonAssets/UI/Icons/delete.png", | |
| DocumentationLink = "Docs/LuaUI.md.html", | |
| Documentation = "Adds a new user interface panel.", | |
| } | |
| function XTemplate.__content(parent, context) | |
| return parent | |
| end | |
| function XTemplate:GetTemplateProperties() | |
| local properties | |
| local __is_kind_of = self.__is_kind_of | |
| local template = XTemplates[__is_kind_of] | |
| if template then | |
| properties = template:GetTemplateProperties() | |
| else | |
| local class = g_Classes[__is_kind_of] | |
| properties = class and class:GetProperties() | |
| end | |
| properties = properties or empty_table | |
| local copy | |
| for i = 1, #self do | |
| if self[i].class == "XTemplateProperty" then | |
| copy = copy or table.icopy(properties) | |
| copy[#copy + 1] = self[i] | |
| end | |
| end | |
| return copy or properties | |
| end | |
| function XTemplate:GetTemplateDefaultPropertyValue(prop_id, prop_meta) | |
| prop_meta = prop_meta or self:GetPropertyMetadata(prop_id) | |
| if IsKindOf(prop_meta, "XTemplateProperty") then | |
| return prop_meta.default | |
| end | |
| for i = 1, #self do | |
| if self[i].class == "XTemplateWindow" then | |
| local value = rawget(self[i], prop_id) | |
| if value ~= nil then return value end | |
| local class = g_Classes[self[i].__class] | |
| return class and class:GetDefaultPropertyValue(prop_id, prop_meta) | |
| end | |
| if self[i].class == "XTemplateTemplate" then | |
| local value = rawget(self[i], prop_id) | |
| if value ~= nil then return value end | |
| local template = XTemplates[self[i].__template] | |
| return template and template ~= self and template:GetTemplateDefaultPropertyValue(prop_id, prop_meta) | |
| end | |
| end | |
| return prop_meta and prop_meta.default | |
| end | |
| local procall = procall | |
| local ipairs = ipairs | |
| function XTemplate:Eval(parent, context) | |
| local first_result | |
| for i, element in ipairs(self) do | |
| local ok, result = procall(element.Eval, element, parent, context) | |
| first_result = first_result or result | |
| end | |
| assert(not first_result or not XTemplateClass(self.__is_kind_of) or IsKindOf(first_result, XTemplateClass(self.__is_kind_of))) | |
| for i, element in ipairs(self) do | |
| if element.class == "XTemplateProperty" then | |
| element:Assign(first_result) | |
| end | |
| end | |
| if first_result and Platform.developer then | |
| rawset(first_result, "__dbg_template", self.id) | |
| end | |
| return first_result | |
| end | |
| function XTemplate:GetSaveFolder(save_in) | |
| save_in = save_in or self.save_in | |
| if save_in == "" then return "Lua" end | |
| if save_in == "Common" then return "CommonLua/X" end | |
| if save_in == "Ged" then return "CommonLua/Ged" end | |
| if save_in == "GameGed" then return "Lua/Ged" end | |
| if save_in:starts_with("Libs/") then | |
| return "CommonLua/" .. save_in | |
| end | |
| -- save_in is a DLC name | |
| return string.format("svnProject/Dlc/%s/Presets", save_in) | |
| end | |
| function XTemplate:GetSavePath() | |
| local folder = self:GetSaveFolder() | |
| if not folder then return end | |
| return string.format("%s/XTemplates/%s.lua", folder, self.id) | |
| end | |
| function XTemplate:GetPresetSaveLocations() | |
| local locations = Preset.GetPresetSaveLocations(self) | |
| table.insert(locations, 3, { text = "Ged", value = "Ged" }) | |
| table.insert(locations, 4, { text = "GameGed", value = "GameGed" }) | |
| return locations | |
| end | |
| function XTemplate:OnPostSave(user_requested) | |
| local id = self.id | |
| if self.recreate_after_save and (id or "") ~= "" then | |
| local dlg = GetDialog(id) | |
| if dlg then | |
| local parent = dlg:GetParent() | |
| local context = dlg:GetContext() | |
| CloseDialog(id) | |
| OpenDialog(id, parent, context) | |
| end | |
| end | |
| end | |
| ----- XTemplateElement | |
| DefineClass.XTemplateElement = { | |
| __parents = { "Container" }, | |
| properties = { | |
| { category = "Template", id = "comment", name = "Comment", editor = "text", default = "", }, | |
| }, | |
| TreeView = T(357198499972, "<class> <color 0 128 0><comment>"), | |
| EditorView = Untranslated("<TreeView>"), | |
| EditorName = "Template Element", | |
| ContainerClass = "XTemplateElement", | |
| } | |
| function XTemplateElement:Eval(parent, context) | |
| return self:EvalChildren(parent, context) | |
| end | |
| function XTemplateElement:EvalChildren(parent, context) | |
| local first_result | |
| for i, element in ipairs(self) do | |
| local ok, result = procall(element.Eval, element, parent, context) | |
| first_result = first_result or result | |
| end | |
| if Platform.developer and self.comment ~= "" and first_result then | |
| rawset(first_result, "__dbg_template_comment", self.comment) | |
| end | |
| return first_result | |
| end | |
| function XTemplateElement:__fromluacode(props, arr) | |
| local obj = self:new(arr) | |
| for i = 1, #(props or ""), 2 do | |
| obj[props[i]] = props[i + 1] | |
| end | |
| return obj | |
| end | |
| ----- XTemplateElementGroup | |
| DefineClass.XTemplateElementGroup = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Template", id = "__context_of_kind", name = "Require context of kind", editor = "text", default = "" }, | |
| { category = "Template", id = "__context", name = "Context expression", editor = "expression", params = "parent, context" }, | |
| { category = "Template", id = "__parent", name = "Parent expression", editor = "expression", params = "parent, context" }, | |
| { category = "Template", id = "__condition", name = "Condition", editor = "expression", params = "parent, context", }, | |
| }, | |
| TreeView = T(551379353577, "Group<ConditionText> <color 0 128 0><comment>"), | |
| EditorName = "Group", | |
| } | |
| function XTemplateElementGroup.__parent(parent, context) | |
| return parent | |
| end | |
| function XTemplateElementGroup.__context(parent, context) | |
| return context | |
| end | |
| function XTemplateElementGroup.__condition(parent, context) | |
| return true | |
| end | |
| function XTemplateElementGroup:ConditionText() | |
| if self.__condition == g_Classes[self.class].__condition then | |
| return "" | |
| end | |
| -- get condition as a string | |
| local name, params, body = GetFuncSource(self.__condition) | |
| if type(body) == "table" then | |
| body = table.concat(body, "\n") | |
| end | |
| if body then | |
| body = body:match("^%s*return%s*(.*)") or body | |
| -- Put a space between < and numbers to avoid treating it like a tag | |
| body = string.gsub(body, "([%w%d])<(%d)", "%1< %2") | |
| end | |
| return body and " <color 128 128 220>cond:" .. body or "" | |
| end | |
| function XTemplateElementGroup:Eval(parent, context) | |
| local kind = self.__context_of_kind | |
| if kind == "" | |
| or type(context) == kind | |
| or IsKindOf(context, kind) | |
| or (IsKindOf(context, "Context") and context:IsKindOf(kind)) | |
| then | |
| context = self.__context(parent, context) | |
| parent = self.__parent(parent, context) | |
| if not self.__condition(parent, context) then | |
| return | |
| end | |
| return self:EvalElement(parent, context) | |
| end | |
| end | |
| function XTemplateElementGroup:EvalElement(parent, context) | |
| return self:EvalChildren(parent, context) | |
| end | |
| ----- XTemplateGroup | |
| DefineClass("XTemplateGroup", "XTemplateElementGroup") | |
| ----- XTemplateCode | |
| DefineClass.XTemplateCode = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Template", id = "copy_context", name = "Copy context", editor = "bool", default = false }, | |
| { category = "Template", id = "run", name = "Run", editor = "func", params = "self, parent, context", lines = 2, max_lines = 40 }, | |
| }, | |
| TreeView = T(519549090093, "Code <color 0 128 0><comment>"), | |
| EditorName = "Code", | |
| ContainerClass = "", -- disallow children | |
| } | |
| function XTemplateCode:Eval(parent, context) | |
| local sub_context = self.copy_context and SubContext(context) or context | |
| return self:run(parent, sub_context) | |
| end | |
| function XTemplateCode:run(parent, context) | |
| end | |
| ----- XTemplateFunc | |
| DefineClass.XTemplateFunc = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Template", id = "name", name = "Name", editor = "combo", default = "", items = { | |
| "OnContextUpdate(self, context, ...)", | |
| "OnMouseButtonDown(self, pos, button)", | |
| "OnShortcut(self, shortcut, source, ...)", | |
| "OnPress(self)", | |
| "OnSetRollover(self, rollover)", | |
| "SetEnabled(self, enabled)", | |
| }}, | |
| { category = "Template", id = "parent", name = "Parent", editor = "expression", params = "parent, context", }, | |
| { category = "Template", id = "func", name = "Func", editor = "func", default = false, | |
| params = function(obj) local name, params = ParseFuncDecl(obj.name) return params or "self, ..." end }, | |
| }, | |
| TreeView = T(804254723579, "func <name> <color 0 128 0><comment>"), | |
| EditorName = "Function", | |
| ContainerClass = "", -- disallow children | |
| } | |
| function ParseFuncDecl(decl) | |
| decl = decl or "" | |
| local name, params = decl:match("^%s*([%w:_]+)%s*%(([%w%s,._]-)%)%s*$") | |
| name = name or decl:match("^%s*([%w:_]+)%s*$") | |
| return name, params | |
| end | |
| function XTemplateFunc.parent(parent, context) | |
| return parent | |
| end | |
| function XTemplateFunc:Eval(parent, context) | |
| local name = ParseFuncDecl(self.name) | |
| if name and self.func then | |
| parent = self.parent(parent, context) | |
| if parent then | |
| rawset(parent, name, self.func) | |
| end | |
| end | |
| return self:EvalChildren(parent, context) | |
| end | |
| ----- XTemplateWindow | |
| DefineClass.XTemplateWindowBase = { | |
| __parents = { "XTemplateElementGroup" }, | |
| properties = { | |
| { category = "Template", id = "__class", name = "Class", editor = "choice", default = "XWindow", show_recent_items = 7, | |
| items = function() return ClassDescendantsCombo("XWindow", true) end, }, | |
| }, | |
| TreeView = T(700510148795, "<IdNodeColor><__class><ConditionText><opt(PlacementText,' <color 128 128 128>','')><opt(comment,' <color 0 128 0>')>"), | |
| EditorName = "Window", | |
| PropertyTabs = XWindowPropertyTabs, | |
| } | |
| DefineClass("XTemplateWindow", "XTemplateWindowBase") | |
| function XTemplateWindowBase:IdNodeColor() | |
| local idNode = rawget(self, "IdNode") | |
| if idNode == false or (idNode == nil and not _G[self.__class].IdNode) then | |
| return "" | |
| end | |
| for _,item in ipairs(self) do | |
| if IsKindOf(item, "XTemplateElementGroup") then | |
| return "<color 75 105 198>" | |
| end | |
| end | |
| return "" | |
| end | |
| function XTemplateWindowBase:PlacementText() | |
| local class = g_Classes[self.__class] | |
| if class and class:IsKindOf("XOpenLayer") then | |
| return Untranslated(self:GetProperty("Layer") .. " " .. self:GetProperty("Mode")) | |
| else | |
| local dock = self:GetProperty("Dock") | |
| dock = dock and (" Dock:" .. tostring(dock)) or "" | |
| return Untranslated(self:GetProperty("Id") .. dock) | |
| end | |
| end | |
| local eval = prop_eval | |
| function XTemplateWindowBase:GetProperties() | |
| local properties = table.icopy(self.properties) | |
| local class = g_Classes[self.__class] | |
| for _, prop_meta in ipairs(class and class:GetProperties() or empty_table) do | |
| if not eval(prop_meta.dont_save, self, prop_meta) then | |
| properties[#properties + 1] = prop_meta | |
| end | |
| end | |
| return properties | |
| end | |
| local modified_base_props = {} | |
| function XTemplateWindowBase:SetProperty(id, value) | |
| rawset(self, id, value) | |
| modified_base_props[self] = nil | |
| end | |
| function XTemplateWindowBase:GetProperty(id) | |
| if self:HasMember(id) then | |
| return self[id] | |
| else | |
| local class = g_Classes[self.__class] | |
| return class and class:GetDefaultPropertyValue(id) | |
| end | |
| end | |
| function XTemplateWindowBase:GetDefaultPropertyValue(id, prop_meta) | |
| if XTemplateWindowBase:HasMember(id) then | |
| return XTemplateWindowBase[id] | |
| end | |
| local class = g_Classes[self.__class] | |
| return class and class:GetDefaultPropertyValue(id, prop_meta) or false | |
| end | |
| function GetPropsToCopy(self, props) | |
| local result = {} | |
| for _, prop_meta in ipairs(props) do | |
| local id = prop_meta.id | |
| local value = rawget(self, id) | |
| if value ~= nil then | |
| result[#result + 1] = { id, value } | |
| end | |
| end | |
| return result | |
| end | |
| function XTemplateWindowBase:EvalElement(parent, context) | |
| local class = g_Classes[self.__class] | |
| assert(class, "XTemplateWindow class not found") | |
| if not class then return end | |
| local obj = class:new({}, parent, context, self) | |
| local props = modified_base_props[self] | |
| if not props then | |
| props = GetPropsToCopy(self, obj:GetProperties()) | |
| modified_base_props[self] = props | |
| end | |
| for _, entry in ipairs(props) do | |
| local id, value = entry[1], entry[2] | |
| if type(value) == "table" and not IsT(value) then | |
| value = table.copy(value, "deep") | |
| end | |
| obj:SetProperty(id, value) | |
| end | |
| self:EvalChildren(obj, context) | |
| return obj | |
| end | |
| function XTemplateWindowBase:OnEditorSetProperty(prop_id, old_value) | |
| local class = g_Classes[self.__class] | |
| if class and class:HasMember("OnXTemplateSetProperty") then | |
| class.OnXTemplateSetProperty(self, prop_id, old_value) | |
| end | |
| end | |
| function XTemplateWindowBase:GetError() | |
| local class = g_Classes[self.__class] | |
| if IsKindOf(class, "XContentTemplate") then | |
| if self:GetProperty("RespawnOnContext") and self:GetProperty("ContextUpdateOnOpen") then | |
| return "'RespawnOnContext' and 'ContextUpdateOnOpen' shouldn't be simultaneously true. This will cause children to be 'Opened' twice." | |
| end | |
| end | |
| if IsKindOf(class, "XEditableText") then | |
| if self:GetProperty("Translate") and self:GetProperty("UserText") then | |
| return "'Translated text' and 'User text' properties can't be both set." | |
| end | |
| end | |
| end | |
| ----- XTemplateTemplate | |
| DefineClass.XTemplateTemplate = { | |
| __parents = { "XTemplateElementGroup" }, | |
| properties = { | |
| { category = "Template", id = "UseDialogModeAsTemplate", name = "Use Dialog Mode as Template", editor = "bool", default = false }, | |
| { category = "Template", id = "__template", name = "Template", editor = "preset_id", default = "", preset_class = "XTemplate", | |
| no_validate = function(self) return self.IgnoreMissing end, | |
| no_edit = function (self) return self.UseDialogModeAsTemplate end, }, | |
| { category = "Template", id = "IgnoreMissing", name = "Ignore missing template", editor = "bool", default = false, | |
| no_edit = function (self) return self.UseDialogModeAsTemplate end, }, | |
| }, | |
| TreeView = T(323454137582, "T: <ShowTemplateName><ConditionText> <color 0 128 0><comment>"), | |
| EditorName = "Invoke template", | |
| PropertyTabs = XWindowPropertyTabs, | |
| } | |
| function XTemplateTemplate:ShowTemplateName() | |
| return self.UseDialogModeAsTemplate and Untranslated("Dialog.mode") or self.__template ~= "" and self.__template or Untranslated("???") | |
| end | |
| function XTemplateTemplate:GetProperties() | |
| if self.UseDialogModeAsTemplate then return self.properties end | |
| local properties = table.icopy(self.properties) | |
| local template = XTemplates[self.__template] | |
| for _, prop_meta in ipairs(template and template:GetTemplateProperties() or empty_table) do | |
| properties[#properties + 1] = prop_meta | |
| end | |
| return properties | |
| end | |
| function XTemplateTemplate:GetProperty(id) | |
| if self:HasMember(id) then | |
| return self[id] | |
| end | |
| local template = XTemplates[self.__template] | |
| return template and template:GetTemplateDefaultPropertyValue(id) | |
| end | |
| function XTemplateTemplate:GetDefaultPropertyValue(id, prop_meta) | |
| if XTemplateTemplate:HasMember(id) then | |
| return XTemplateTemplate[id] | |
| end | |
| local template = XTemplates[self.__template] | |
| return template and template:GetTemplateDefaultPropertyValue(id, prop_meta) | |
| end | |
| local modified_template_props = {} | |
| function XTemplateTemplate:SetProperty(id, value) | |
| rawset(self, id, value) | |
| modified_template_props[self] = nil | |
| end | |
| function XTemplateTemplate:EvalElement(parent, context) | |
| local template = XTemplates[self.__template] | |
| if self.UseDialogModeAsTemplate then | |
| local dlg = GetDialog(parent) | |
| template = XTemplates[dlg and dlg.Mode or false] | |
| end | |
| assert(template or self.__template == "" or self.UseDialogModeAsTemplate or self.IgnoreMissing, "XTemplate not found") | |
| if not template then return end | |
| local obj = template:Eval(parent, context) | |
| if obj then | |
| local props = modified_template_props[self] | |
| if not props then | |
| props = GetPropsToCopy(self, obj:GetProperties()) | |
| modified_template_props[self] = props | |
| end | |
| for _, entry in ipairs(props) do | |
| local id, value = entry[1], entry[2] | |
| obj:SetProperty(id, value) | |
| end | |
| if Platform.developer then | |
| rawset(obj, "__dbg_template_template", self.__template) | |
| end | |
| end | |
| local content_parent = template.__content(obj, context) | |
| self:EvalChildren(content_parent, context) | |
| return obj | |
| end | |
| ----- XTemplateProperty | |
| DefineClass.XTemplateProperty = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Property", id = "category", name = "Category", editor = "text", default = false, }, | |
| { category = "Property", id = "id", name = "Id", editor = "text", default = "", validate = ValidateIdentifier }, | |
| { category = "Property", id = "editor", name = "Type", editor = "choice", default = "bool", items = { "bool", "number", "number_list", "text", "point", "choice", "color"}, }, | |
| { category = "Property", id = "default", name = "Default value", editor = function (obj) return obj.editor end, default = false, | |
| scale = function (obj) return obj.scale end, translate = function (obj) return obj.translate end, items = function(obj) return obj.items end}, | |
| { category = "Property", id = "items", name = "Items", editor = "expression", default = false, no_edit = function (obj) return obj.editor ~= "choice" end}, | |
| { category = "Property", id = "preset_class", name = "Preset class", editor = "choice", default = false, items = ClassDescendantsCombo("Preset"), no_edit = function (obj) return obj.editor ~= "preset_id" end}, | |
| { category = "Property", id = "extra_item", name = "Extra item", editor = "text", default = false }, | |
| { category = "Property", id = "scale", name = "Scale", editor = "choice", default = 1, no_edit = function (obj) return obj.editor ~= "number" end, | |
| items = function () return table.keys2(const.Scale, true, 1, 10, 100, 1000) end, }, | |
| { category = "Property", id = "translate", name = "Translate", editor = "bool", default = true, no_edit = function (obj) return obj.editor ~= "text" end}, | |
| { category = "Property", id = "Set", editor = "func", default = false, params = "self, value", }, | |
| { category = "Property", id = "Get", editor = "func", default = false, params = "self", }, | |
| { category = "Property", id = "name", name = "Name", editor = "text", translate = true, default = false}, | |
| { category = "Property", id = "help", name = "Help", editor = "text", translate = true, default = false}, | |
| }, | |
| ContainerClass = "", -- disallow children | |
| TreeView = T(534697746090, "Property <id> <color 0 128 0><comment>"), | |
| EditorName = "Property", | |
| dont_save = false, | |
| no_edit = false, | |
| no_validate = false, | |
| read_only = false, | |
| sort_order = false, | |
| name_on_top = false, | |
| hide_name = false, | |
| lines = false, | |
| max_lines = false, | |
| max_len = false, | |
| buttons = false, | |
| folder = false, | |
| filter = false, | |
| force_extension = false, | |
| validate = false, | |
| context = false, | |
| gender = false, | |
| min = min_int, | |
| max = max_int, | |
| step = 1, | |
| float = false, | |
| slider = false, | |
| wordwrap = false, | |
| text_style = false, | |
| os_path = false, | |
| realtime_update = false, | |
| max_items_in_set = false, | |
| base_class = "PropertyObject", | |
| auto_expand = false, | |
| preset_group = false, | |
| auto_select_all = false, | |
| allowed_chars = false, | |
| format = "<EditorView>", | |
| alpha = true, | |
| item_default = function(obj, prop_meta) | |
| if prop_meta.editor == "number_list" then return 0 end | |
| end, | |
| max_items = max_int, | |
| three_state = false, | |
| inject_in_subobjects = false, | |
| params = "", | |
| } | |
| function XTemplateProperty:Assign(parent, context) | |
| local id = self.id or "" | |
| if id ~= "" then | |
| if self.Set then | |
| rawset(parent, "Set" .. id, self.Set) | |
| end | |
| if self.Get then | |
| rawset(parent, "Get" .. id, self.Get) | |
| end | |
| assert(rawget(parent, id) == nil) | |
| local properties = rawget(parent, "properties") | |
| if not properties then | |
| properties = table.icopy(parent.properties) | |
| parent.properties = properties | |
| end | |
| properties[#properties + 1] = self | |
| rawset(parent, id, self.default) | |
| end | |
| end | |
| function XTemplateProperty:OnEditorSetProperty(prop_id, old_value, ged) | |
| if prop_id == "editor" then | |
| self.default = nil | |
| end | |
| end | |
| ----- XTemplateMode | |
| DefineClass.XTemplateMode = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Template", id = "mode", name = "Mode", editor = "text", default = "", help = "A single mode or a list of modes."}, | |
| }, | |
| TreeView = T(542491254779, "<color 178 16 16>Mode <mode> <color 0 128 0><comment>"), | |
| EditorName = "Mode", | |
| } | |
| function XTemplateMode:Eval(parent, context) | |
| local dialog = GetParentOfKind(parent, "XDialog") | |
| assert(dialog) | |
| if dialog and (dialog.Mode == self.mode or MatchDialogMode(dialog.Mode, self.mode)) then | |
| return self:EvalChildren(parent, context) | |
| end | |
| end | |
| ----- XTemplateLayer | |
| DefineClass.XTemplateLayer = { | |
| __parents = { "XTemplateElementGroup" }, | |
| properties = { | |
| { category = "Layer", id = "layer", name = "Layer", editor = "choice", default = "", items = XTemplateCombo("XLayer", false) }, | |
| { category = "Layer", id = "layer_id", name = "Layer Id", editor = "text", default = "", }, | |
| { category = "Layer", id = "mode", name = "Mode", editor = "text", default = false, }, | |
| }, | |
| TreeView = T(177501851434, "Layer <layer><ConditionText> <color 0 128 0><comment>"), | |
| EditorName = "Layer", | |
| } | |
| function XTemplateLayer:GatherTemplateProperties(properties) | |
| properties = properties or {} | |
| local layer_props = {} | |
| for _, prop_meta in ipairs(XLayer:GetProperties()) do | |
| layer_props[prop_meta.id] = true | |
| end | |
| local class = g_Classes[self.layer] | |
| for _, prop_meta in ipairs(class and class:GetProperties()) do | |
| if not layer_props[prop_meta.id] and not eval(prop_meta.dont_save, self, prop_meta) then | |
| properties[#properties + 1] = prop_meta | |
| end | |
| end | |
| return properties | |
| end | |
| function XTemplateLayer:GetProperties() | |
| return self:GatherTemplateProperties(table.icopy(self.properties)) | |
| end | |
| function XTemplateLayer:SetProperty(id, value) | |
| rawset(self, id, value) | |
| end | |
| function XTemplateLayer:GetProperty(id) | |
| if self:HasMember(id) then | |
| return self[id] | |
| else | |
| local class = g_Classes[self.layer] | |
| return class and class:GetDefaultPropertyValue(id) | |
| end | |
| end | |
| function XTemplateLayer:GetDefaultPropertyValue(id, prop_meta) | |
| if XTemplateLayer:HasMember(id) then | |
| return XTemplateLayer[id] | |
| end | |
| local class = g_Classes[self.layer] | |
| return class and class:GetDefaultPropertyValue(id, prop_meta) or false | |
| end | |
| function XTemplateLayer:EvalElement(parent, context) | |
| if self.layer ~= "" then | |
| parent = XOpenLayer:new({ | |
| xtemplate = self, | |
| Layer = self.layer, | |
| LayerId = self.layer_id, | |
| Mode = self.mode, | |
| }, parent, context) | |
| end | |
| return self:EvalChildren(parent, context) | |
| end | |
| ----- XTemplateAction | |
| DefineClass.XTemplateAction = { | |
| __parents = { "XTemplateElement", "XAction" }, | |
| properties = { | |
| { category = "Template", id = "__condition", name = "Condition", editor = "expression", params = "parent, context", }, | |
| { category = "Template", id = "replace_matching_id", name = "Replace matching Id", editor = "bool", default = false, }, | |
| }, | |
| TreeView = T(187418329984, "Action<ConditionText> <color 128 128 128><ActionId> <color 200 128 128><ActionShortcut> <color 200 200 128><ActionShortcut2> <color 64 164 164><ActionGamepad><color 0 128 0><comment>"), | |
| EditorName = "Action", | |
| } | |
| function XTemplateAction.__condition(parent, context) | |
| return true | |
| end | |
| function XTemplateAction:ConditionText() | |
| if self.__condition == g_Classes[self.class].__condition then | |
| return "" | |
| end | |
| -- get condition as a string | |
| local name, params, body = GetFuncSource(self.__condition) | |
| if type(body) == "table" then | |
| body = table.concat(body, "\n") | |
| end | |
| if body then | |
| body = body:match("^%s*return%s*(.*)") or body | |
| -- Put a space between < and numbers to avoid treating it like a tag | |
| body = string.gsub(body, "([%w%d])<(%d)", "%1< %2") | |
| end | |
| -- concat mode and condition | |
| local ret = self.ActionMode == "" and "" or "mode:" .. self.ActionMode | |
| if body then | |
| ret = (ret == "" and "" or ret .. " ") .. "cond:" .. body | |
| end | |
| return ret == "" and "" or " <color 128 128 220>" .. ret | |
| end | |
| local xaction_props = false | |
| function XTemplateAction:Eval(parent, context) | |
| if not self.__condition(parent, context) then | |
| return | |
| end | |
| if not xaction_props then | |
| xaction_props = {} | |
| for _, prop_meta in ipairs(XAction:GetProperties()) do | |
| xaction_props[prop_meta.id] = true | |
| end | |
| end | |
| local action = {} | |
| for id, value in pairs(self) do | |
| if xaction_props[id] then | |
| action[id] = value | |
| end | |
| end | |
| local parent_action = ResolveValue(context, "__action") | |
| if parent_action then | |
| if not action.ActionMenubar then | |
| action.ActionMenubar = parent_action.ActionId | |
| end | |
| if not action.ActionMode or action.ActionMode == "" then | |
| action.ActionMode = parent_action.ActionMode | |
| self.InheritedActionModes = action.ActionMode | |
| else | |
| self.InheritedActionModes = "" | |
| end | |
| if not action.BindingsMenuCategory then | |
| action.BindingsMenuCategory = parent_action.BindingsMenuCategory | |
| end | |
| end | |
| action = XAction:new(action, parent, context, self.replace_matching_id) | |
| self:EvalChildren(parent, SubContext(context, { __action = action })) | |
| if IsKindOf(parent, "XButton") then | |
| parent:SetOnPressEffect("action") | |
| parent:SetOnPressParam(action.ActionId) | |
| if IsKindOf(parent, "XTextButton") then | |
| if parent.Text == "" then | |
| parent:SetText(action.ActionName) | |
| end | |
| if parent:GetIcon() == "" then | |
| parent:SetIcon(action.ActionIcon) | |
| end | |
| end | |
| end | |
| if parent_action and action.ActionState == XAction.ActionState and parent_action.ActionState ~= XAction.ActionState then | |
| action.ActionState = parent_action.ActionState | |
| end | |
| return action | |
| end | |
| function XTemplateAction:OnEditorSetProperty(prop_id, old_value) | |
| XAction.OnXTemplateSetProperty(self, prop_id, old_value) | |
| end | |
| function XTemplateAction:GetWarning() | |
| local preset = GetParentTableOfKind(self, "XTemplate") | |
| if preset.RequireActionSortKeys and self.ActionId ~= "" and self.ActionSortKey == "" then | |
| return "Sort keys are required for all Actions within this XTemplate." | |
| end | |
| end | |
| function XTemplateAction:OnEditorNew(parent, ged, is_paste) | |
| if is_paste then | |
| self:SetActionSortKey("") -- don't allow duplicated sort keys | |
| end | |
| end | |
| ----- XTemplateForEach | |
| DefineClass.XTemplateForEach = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Template", id = "array", name = "Array", editor = "expression", params = "parent, context", }, | |
| { category = "Template", id = "map", name = "Map array index", editor = "expression", params = "parent, context, array, i", help = "map(parent, context, array, i) - maps index to an item\nBy default returns array and array[i]", }, | |
| { category = "Template", id = "condition", name = "Condition", editor = "expression", params = "parent, context, item, i", help = "condition(parent, context, item, i) - returns whether the item should be processed\nBy default returns true", }, | |
| { category = "Template", id = "unique", name = "Unique items only", editor = "bool", default = false, }, | |
| { category = "Template", id = "item_in_context", name = "Store item in context field", editor = "text", default = "", }, | |
| { category = "Template", id = "__context", name = "Context", editor = "expression", params = "parent, context, item, i, n", }, | |
| { category = "Template", id = "run_before", name = "Run before", editor = "func", params = "parent, context, item, i, n, last", }, | |
| { category = "Template", id = "run_after", name = "Run after", editor = "func", params = "child, context, item, i, n, last", }, | |
| }, | |
| TreeView = T(633743132666, "For each <color 0 128 0><comment>"), | |
| EditorName = "For each", | |
| } | |
| function XTemplateForEach.array(parent, context) | |
| return context | |
| end | |
| function XTemplateForEach.map(parent, context, array, i) | |
| return array and array[i] | |
| end | |
| function XTemplateForEach.condition(parent, context, item, i) | |
| return true | |
| end | |
| function XTemplateForEach.run_before(parent, context, item, i, n, last) | |
| end | |
| function XTemplateForEach.run_after(child, context, item, i, n, last) | |
| end | |
| function XTemplateForEach.__context(child, context, item, i, n) | |
| return context | |
| end | |
| function XTemplateForEach:Eval(parent, context) | |
| local array, first, last, step = self.array(parent, context) | |
| if (not first or not last) and type(array) ~= "table" then return end | |
| local n = 1 | |
| local item_in_context = self.item_in_context | |
| local seen = self.unique and {} | |
| last = last or #array | |
| for i = first or 1, last, step or 1 do | |
| local item = self.map(parent, context, array, i) | |
| if (not seen or not seen[item]) and self.condition(parent, context, item, i) then | |
| if seen then seen[item] = true end | |
| if item_in_context ~= "" then | |
| context = SubContext(context, {[item_in_context] = item}) | |
| end | |
| local sub_context = self.__context(parent, context, item, i, n) | |
| self.run_before(parent, sub_context, item, i, n, last) | |
| local child = self:EvalChildren(parent, sub_context) | |
| self.run_after(child, sub_context, item, i, n, last) | |
| n = n + 1 | |
| end | |
| end | |
| end | |
| ----- XTemplateForEachPreset | |
| DefineClass.XTemplateForEachPreset = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Template", id = "preset", name = "Preset", editor = "choice", default = false, items = ClassDescendantsCombo("Preset"), }, | |
| { category = "Template", id = "condition", name = "Condition", editor = "expression", params = "parent, context, preset, group", help = "condition(parent, context, preset, group) - returns whether the item should be processed\nBy default returns true", }, | |
| { category = "Template", id = "item_in_context", name = "Store preset in context field", editor = "text", default = "", }, | |
| { category = "Template", id = "__context", name = "Context", editor = "expression", params = "parent, context, preset, group", }, | |
| { category = "Template", id = "run_before", name = "Run before", editor = "func", params = "parent, context, preset, group", }, | |
| { category = "Template", id = "run_after", name = "Run after", editor = "func", params = "child, context, preset, group", }, | |
| }, | |
| TreeView = T(713267586754, "For each preset <preset> <color 0 128 0><comment>"), | |
| EditorName = "For each preset", | |
| } | |
| function XTemplateForEachPreset.condition(parent, context, preset, group) | |
| return true | |
| end | |
| function XTemplateForEachPreset.run_before(parent, context, preset, group) | |
| end | |
| function XTemplateForEachPreset.run_after(child, context, preset, group) | |
| end | |
| function XTemplateForEachPreset.__context(child, context, preset, group) | |
| return context | |
| end | |
| function XTemplateForEachPreset:Eval(parent, context) | |
| local preset = g_Classes[self.preset] | |
| if not preset then return end | |
| ForEachPreset(preset.PresetClass or preset.class, function(preset, group, parent, context, item_in_context) | |
| if self.condition(parent, context, preset, group) then | |
| if item_in_context ~= "" then | |
| context = SubContext(context, {[item_in_context] = preset}) | |
| end | |
| local sub_context = self.__context(parent, context, preset, group) | |
| self.run_before(parent, sub_context, preset, group) | |
| local child = self:EvalChildren(parent, sub_context) | |
| self.run_after(child, sub_context, preset, group) | |
| end | |
| end, parent, context, self.item_in_context) | |
| end | |
| ----- XTemplateForEachAction | |
| DefineClass.XTemplateForEachAction = { | |
| __parents = { "XTemplateElement" }, | |
| properties = { | |
| { category = "Template", id = "menubar", name = "Menubar", editor = "text", default = "", }, | |
| { category = "Template", id = "toolbar", name = "Toolbar", editor = "text", default = "", }, | |
| { category = "Template", id = "condition", name = "Condition", editor = "expression", params = "parent, context, action, i", help = "condition(parent, context, action, i) - returns whether the action should be processed\nBy default returns true", }, | |
| { category = "Template", id = "__context", name = "Context", editor = "expression", params = "parent, context, action, n", }, | |
| { category = "Template", id = "run_after", name = "Run after", editor = "func", params = "child, context, action, n", }, | |
| }, | |
| TreeView = T(584735601325, "For each action <toolbar><menubar> <color 0 128 0><comment>"), | |
| EditorName = "For each action", | |
| } | |
| function XTemplateForEachAction.condition(parent, context, action, i) | |
| return true | |
| end | |
| function XTemplateForEachAction.__context(child, context, action, n) | |
| return context | |
| end | |
| function XTemplateForEachAction.run_after(child, context, action, n) | |
| end | |
| function XTemplateForEachAction:Eval(parent, context) | |
| local host = GetActionsHost(parent, true) | |
| local array = host and host:GetActions() | |
| if #(array or "") == 0 then return end | |
| local toolbar = self.toolbar | |
| local menubar = self.menubar | |
| local n = 1 | |
| for i, action in ipairs(array) do | |
| if (toolbar == "" or toolbar == action.ActionToolbar) | |
| and (menubar == "" or menubar == action.ActionMenubar) | |
| and host:FilterAction(action) | |
| and self.condition(parent, context, action, i) | |
| then | |
| local sub_context = self.__context(parent, context, action, n) | |
| local child = self:EvalChildren(parent, sub_context) | |
| self.run_after(child, sub_context, action, n) | |
| n = n + 1 | |
| end | |
| end | |
| end | |
| ----- XTemplateInterpolation / XTemplateIntAlpha / XTemplateIntRect | |
| DefineClass.XTemplateInterpolation = { | |
| __parents = { "XTemplateElement", }, | |
| properties = { | |
| { id = "interpolation_id", name = "Interpolation id", | |
| editor = "text", default = "", max_lines = 1, }, | |
| { id = "inverse", name = "Inverse", | |
| editor = "bool", default = false, }, | |
| { id = "looping", name = "Looping", | |
| editor = "bool", default = false, }, | |
| { id = "ping_pong", name = "Ping-pong", | |
| editor = "bool", default = false, }, | |
| { id = "game_time", name = "Game time", | |
| editor = "bool", default = true, }, | |
| { id = "autoremove", name = "Auto remove", | |
| editor = "bool", default = false, }, | |
| { id = "easing", name = "Easing", | |
| editor = "choice", default = false, items = function (self) return GetEasingCombo() end, }, | |
| { id = "start", name = "Start offset", | |
| editor = "number", default = 0, scale = "sec", step = 1000, }, | |
| { id = "duration", name = "Duration", | |
| editor = "number", default = 1000, scale = "sec", step = 1000, }, | |
| }, | |
| ContainerClass = "", | |
| EditorName = "Interpolation", | |
| } | |
| function XTemplateInterpolation:Eval(parent, context) | |
| local interpolation = { | |
| id = self.interpolation_id ~= "" and self.interpolation_id or nil, | |
| autoremove = self.autoremove or nil, | |
| easing = self.easing ~= "" and self.easing or nil, | |
| flags = (self.inverse and const.intfInverse or 0) | |
| | (self.looping and const.intfLooping or 0) | |
| | (self.ping_pong and const.intfPingPong or 0) | |
| | (self.game_time and const.intfGameTime or 0), | |
| duration = self.duration, | |
| start = (self.game_time and GameTime() or GetPreciseTicks()) + self.start, | |
| } | |
| interpolation = self:GetInterpolation(interpolation, parent, context) | |
| if interpolation then | |
| parent:AddInterpolation(interpolation) | |
| end | |
| end | |
| function XTemplateInterpolation:GetInterpolation(interpolation, parent, context) | |
| return interpolation | |
| end | |
| DefineClass.XTemplateIntAlpha = { | |
| __parents = { "XTemplateInterpolation", }, | |
| properties = { | |
| { id = "alpha_start", name = "Alpha start", | |
| editor = "number", default = 0, }, | |
| { id = "alpha_end", name = "Alpha end", | |
| editor = "number", default = 255, }, | |
| }, | |
| TreeView = Untranslated("Interpolate opacity <alpha_start> -> <alpha_end> for <FormatScale(duration,'sec')> <color 0 128 0><comment>"), | |
| EditorName = "Interpolate opacity", | |
| } | |
| function XTemplateIntAlpha:GetInterpolation(interpolation, parent, context) | |
| interpolation.type = const.intAlpha | |
| interpolation.startValue = self.alpha_start | |
| interpolation.endValue = self.alpha_end | |
| return interpolation | |
| end | |
| DefineClass.XTemplateIntRect = { | |
| __parents = { "XTemplateInterpolation", }, | |
| properties = { | |
| { id = "original", name = "Original box", | |
| editor = "rect", default = box(0, 0, 1000, 1000), }, | |
| { id = "target", name = "Target box", | |
| editor = "rect", default = box(0, 0, 1000, 1000), }, | |
| }, | |
| TreeView = Untranslated("Interpolate box for <FormatScale(duration,'sec')> <color 0 128 0><comment>"), | |
| EditorName = "Interpolate box", | |
| } | |
| function XTemplateIntRect:GetInterpolation(interpolation, parent, context) | |
| interpolation.type = const.intRect | |
| interpolation.originalRect = self.original | |
| interpolation.targetRect = self.target | |
| return interpolation | |
| end | |
| ----- XTemplateThread | |
| DefineClass.XTemplateThread = { | |
| __parents = { "XTemplateElement", }, | |
| properties = { | |
| { id = "thread_name", name = "Thread name", | |
| editor = "text", default = "", max_lines = 1, }, | |
| { id = "InParentDlg", name = "Create in Dialog parent", | |
| editor = "bool", default = true, }, | |
| { id = "CloseOnFinish", name = "Close thread owner at the end", | |
| editor = "bool", default = false, }, | |
| }, | |
| TreeView = Untranslated("<color 75 105 198><if(InParentDlg)>Dialog </if>Thread <thread_name><if(CloseOnFinish)> [Close]</if> <color 0 128 0><comment>"), | |
| EditorName = "Thread", | |
| } | |
| function XTemplateThread:Eval(parent, context) | |
| local thread_name = self.thread_name == "" and self or self.thread_name | |
| local thread_win = self.InParentDlg and GetParentOfKind(parent, "XDialog") or parent | |
| thread_win:CreateThread(thread_name, function(self, parent, context, to_close) | |
| for i, element in ipairs(self) do | |
| local ok, result = sprocall(element.Eval, element, parent, context) | |
| if IsKindOf(result, "XWindow") and result.window_state == "new" then | |
| result:Open() | |
| end | |
| end | |
| if to_close then to_close:Close() end | |
| end, self, parent, context, self.CloseOnFinish and thread_win) | |
| end | |
| DefineClass.XTemplateThreadElement = { | |
| __parents = { "XTemplateElement", }, | |
| ContainerClass = "", | |
| } | |
| DefineClass.XTemplateSleep = { | |
| __parents = { "XTemplateThreadElement", }, | |
| properties = { | |
| { id = "Time", | |
| editor = "number", default = 1000, scale = "sec", }, | |
| }, | |
| TreeView = Untranslated("Sleep <Time> <color 0 128 0><comment>"), | |
| EditorName = "Sleep", | |
| } | |
| function XTemplateSleep:Eval(parent, context) | |
| Sleep(self.Time) | |
| end | |
| ----- XTemplateMoment / XTemplateWaitMoment | |
| DefineClass.XTemplateMoment = { | |
| __parents = { "XTemplateThreadElement", }, | |
| properties = { | |
| { id = "moment", name = "Moment", | |
| editor = "text", default = "", max_lines = 1, }, | |
| }, | |
| TreeView = Untranslated("Moment <color 0 255 255><u(moment)> <color 0 128 0><comment>"), | |
| EditorName = "Moment", | |
| } | |
| function XTemplateMoment:Eval(parent, context) | |
| parent = GetParentOfKind(parent, "XDialog") or parent | |
| if parent then | |
| rawset(parent, "moments", rawget(parent, "moments") or {}) | |
| parent.moments[self.moment] = RealTime() -- mark the moment as passed | |
| end | |
| Msg("Moment:" .. self.moment) | |
| end | |
| DefineClass.XTemplateWaitMoment = { | |
| __parents = { "XTemplateThreadElement", }, | |
| properties = { | |
| { id = "moment", name = "Moment", | |
| editor = "text", default = "", max_lines = 1, }, | |
| { id = "timeout", name = "Timeout", | |
| editor = "number", default = false, }, | |
| }, | |
| TreeView = Untranslated("Wait moment <color 0 255 255><u(moment)> <color 0 128 0><comment>"), | |
| EditorName = "Wait moment", | |
| } | |
| function XTemplateWaitMoment:Eval(parent, context) | |
| parent = GetParentOfKind(parent, "XDialog") or parent | |
| local moments = parent and parent.moments | |
| if moments and moments[self.moment] then return end -- the moment has already passed | |
| WaitMsg("Moment:" .. self.moment, self.timeout) | |
| end | |
| ----- XTemplateSound / XTemplateStopSound | |
| DefineClass.XTemplateSound = { | |
| __parents = { "XTemplateThreadElement", }, | |
| properties = { | |
| { id = "Sample", | |
| editor = "browse", default = false, folder = "Sounds", filter = "Sound file(*.*)|*.*", }, | |
| { id = "Type", | |
| editor = "preset_id", default = "UI", preset_class = "SoundTypePreset", }, | |
| { id = "Volume", | |
| editor = "number", default = 1000, min = 0, max = 1000, }, | |
| { id = "DelayBefore", name = "Delay before", | |
| editor = "number", default = 0, scale = "sec", min = 0, }, | |
| { id = "FadeIn", name = "Fade in", | |
| editor = "number", default = 0, scale = "sec", min = 0, }, | |
| { id = "DelayAfter", name = "Delay after", help = "This can be negative", | |
| editor = "number", default = 0, scale = "sec", }, | |
| }, | |
| TreeView = Untranslated("Sound <u(Sample)> <color 0 128 0><comment>"), | |
| EditorName = "Sound", | |
| } | |
| function XTemplateSound:Eval(parent, context) | |
| Sleep(self.DelayBefore) | |
| parent = GetParentOfKind(parent, "XDialog") or parent | |
| local handle = PlaySound(self.Sample, self.Type, self.Volume, self.FadeIn) | |
| if parent then | |
| rawset(parent, "playing_sounds", rawget(parent, "playing_sounds") or {}) | |
| parent.playing_sounds[self.Sample] = handle | |
| end | |
| Sleep(GetSoundDuration(handle)) | |
| Sleep(self.DelayAfter) | |
| end | |
| DefineClass.XTemplateStopSound = { | |
| __parents = { "XTemplateThreadElement", }, | |
| properties = { | |
| { id = "Sample", | |
| editor = "browse", default = false, folder = "Sounds", filter = "Sound file(*.*)|*.*", }, | |
| { id = "FadeOut", name = "Fade out", help = "This time is not included in the duration of StopSound.", | |
| editor = "number", default = 0, scale = "sec", min = 0, }, | |
| }, | |
| TreeView = Untranslated("Stop sound <u(Sample)> <color 0 128 0><comment>"), | |
| EditorName = "Stop sound", | |
| } | |
| function XTemplateStopSound:Eval(parent, context) | |
| parent = GetParentOfKind(parent, "XDialog") or parent | |
| local playing_sounds = parent and rawget(parent, "playing_sounds") | |
| local handle = playing_sounds and playing_sounds[self.Sample] or -1 | |
| if handle ~= -1 then | |
| SetSoundVolume(handle, -1, self.FadeOut) | |
| end | |
| end | |
| ----- XTemplateConditionList | |
| DefineClass.XTemplateConditionList = { | |
| __parents = { "XTemplateElement", }, | |
| properties = { | |
| { category = "Template", id = "conditions", name = "Conditions", | |
| editor = "nested_list", default = false, base_class = "Condition", }, | |
| }, | |
| TreeView = Untranslated("Condition list <color 0 128 0><comment>"), | |
| EditorName = "Condition list", | |
| } | |
| function XTemplateConditionList:Eval(parent, context) | |
| if EvalConditionList(self.conditions, context) then | |
| for i, element in ipairs(self) do | |
| element:Eval(parent, context) | |
| end | |
| end | |
| end | |
| ----- XTemplateSlide | |
| DefineClass.XTemplateSlide = { | |
| __parents = { "XTemplateElement", }, | |
| properties = { | |
| { id = "slide_id", name = "Slide id", | |
| editor = "text", default = "SLIDE", }, | |
| { id = "transition", name = "Transition", | |
| editor = "choice", default = "", items = function (self) return table.keys2(SlideTransitions, true, "") end, }, | |
| { id = "transition_time", name = "Transition time", | |
| editor = "number", default = 0, no_edit = function(self) return self.__transition == "" end, scale = "sec", min = 0, }, | |
| { id = "transition_easing", name = "Transition easing", | |
| editor = "choice", default = false, items = function (self) return GetEasingCombo() end, }, | |
| }, | |
| TreeView = Untranslated("<slide_id><if(transition)> transition <transition> <FormatScale(transition_time,'sec')></if> <color 0 128 0><comment>"), | |
| EditorName = "Slide", | |
| } | |
| function XTemplateSlide:Eval(parent, context) | |
| local old_slide = parent:ResolveId(self.slide_id) | |
| if old_slide then old_slide:SetId("") end | |
| local slide = self:EvalChildren(parent, context) | |
| if slide then | |
| slide:SetId(self.slide_id) | |
| slide:Open() | |
| local transition = SlideTransitions[self.transition] | |
| if transition then | |
| transition(slide, old_slide, self.transition_time, self.transition_easing or nil) | |
| end | |
| end | |
| if old_slide then old_slide:delete() end | |
| end | |
| local box100 = box(0, 0, 100, 100) | |
| SlideTransitions = { | |
| ["Fade in"] = function (win, old_win, time, easing) | |
| win:AddInterpolation{ | |
| type = const.intAlpha, | |
| startValue = 0, | |
| endValue = 255, | |
| duration = time, | |
| easing = easing, | |
| } | |
| Sleep(time) | |
| end, | |
| ["Fade-to-black"] = function (win, old_win, time, easing) | |
| -- add a black window on top and fade it in and out | |
| local black_win = XWindow:new({ | |
| ZOrder = -10000, | |
| Dock = "box", | |
| DrawOnTop = true, | |
| Background = RGB(0,0,0), | |
| }, win.parent) | |
| black_win:Open() | |
| local int = black_win:AddInterpolation{ | |
| id = "fade-to-black", | |
| type = const.intAlpha, | |
| startValue = 0, | |
| endValue = 255, | |
| duration = time / 2, | |
| easing = easing, | |
| } | |
| win:SetVisible(false) | |
| Sleep(time / 2) | |
| win:SetVisible(true) | |
| int.start = nil | |
| int.flags = const.intfInverse | |
| black_win:AddInterpolation(int) | |
| Sleep(time / 2) | |
| black_win:Close() | |
| end, | |
| ["Push left"] = function (win, old_win, time, easing) | |
| local rect = old_win and old_win.box or win.parent.box | |
| local offset = rect and rect:sizex() or 1000 | |
| if old_win then | |
| old_win:AddInterpolation{ | |
| type = const.intRect, | |
| originalRect = box100, | |
| targetRect = box(-offset, 0, -offset + 100, 100), | |
| duration = time, | |
| easing = easing, | |
| } | |
| end | |
| win:AddInterpolation{ | |
| type = const.intRect, | |
| originalRect = box100, | |
| targetRect = box(offset, 0, offset + 100, 100), | |
| duration = time, | |
| easing = easing, | |
| flags = const.intfInverse, | |
| autoremove = true, | |
| no_invalidate_on_remove = true, | |
| } | |
| Sleep(time) | |
| end, | |
| } | |
| ----- XTemplateVoice | |
| DefineClass.XTemplateVoice = { | |
| __parents = { "XTemplateThreadElement", }, | |
| properties = { | |
| { id = "TimeBefore", name = "Time before", | |
| editor = "number", default = 0, scale = "sec", }, | |
| { id = "TimeAfter", name = "Time after", | |
| editor = "number", default = 0, scale = "sec", }, | |
| { id = "TimeAdd", name = "Additional time", | |
| editor = "number", default = 0, scale = "sec", }, | |
| { id = "Actor", name = "Actor", | |
| editor = "choice", default = false, items = function (self) return VoiceActors end, }, | |
| { id = "Volume", name = "Volume", | |
| editor = "number", default = 1000, slider = true, min = 0, max = 1000, }, | |
| { id = "Text", name = "Text", | |
| editor = "text", default = "", | |
| context = VoicedContextFromField("Actor"), translate = true, lines = 3, max_lines = 10, }, | |
| { id = "TextId", name = "Text control id", | |
| editor = "text", default = "TEXT", max_lines = 1, }, | |
| { id = "ShowText", name = "Show text", | |
| editor = "choice", default = "Always", items = function (self) return {"Always", "Hide", "If subtitles option is enabled" } end, }, | |
| }, | |
| TreeView = Untranslated("<TextId> <if(Actor)><Actor>: </if><Text>"), | |
| EditorName = "Voiceover", | |
| SoundType = "Voiceover", | |
| } | |
| function XTemplateVoice:GetTextActor() | |
| return self.Text, self.Actor | |
| end | |
| function XTemplateVoice:Eval(parent, context) | |
| local text, actor = self:GetTextActor() | |
| local voice = VoiceSampleByText(text, actor) | |
| Sleep(self.TimeBefore) | |
| local text_control = parent:ResolveId(self.TextId) | |
| if text_control then | |
| if self.ShowText == "Always" then | |
| text_control:SetVisible(true) | |
| elseif self.ShowText == "Hide" then | |
| text_control:SetVisible(false) | |
| else | |
| text_control:SetVisible(GetAccountStorageOptionValue("Subtitles")) | |
| end | |
| if text_control:GetVisible() then | |
| text_control:SetText(text or "") | |
| end | |
| end | |
| local handle = voice and PlaySound(voice, self.SoundType, self.Volume) | |
| local duration = GetSoundDuration(handle or voice) | |
| if not duration or duration <= 0 then | |
| duration = 1000 + #_InternalTranslate(text, text_control and text_control.context) * 50 | |
| end | |
| local dialog = GetParentOfKind(parent, "XDialog") or parent | |
| if dialog and handle then | |
| rawset(dialog, "playing_sounds", rawget(dialog, "playing_sounds") or {}) | |
| dialog.playing_sounds[voice] = handle | |
| end | |
| Sleep(duration + self.TimeAdd) | |
| if dialog and handle then | |
| dialog.playing_sounds[voice] = nil | |
| end | |
| if text_control then | |
| text_control:SetVisible(false) | |
| end | |
| Sleep(self.TimeAfter) | |
| end | |
| ----- globals | |
| function XTemplateSpawn(template_or_class, parent, context) | |
| parent = parent or terminal.desktop | |
| local template = XTemplates[template_or_class] | |
| if template then | |
| return template:Eval(parent, context) | |
| end | |
| local class = g_Classes[template_or_class] | |
| if class then | |
| return class:new({}, parent, context) | |
| end | |
| assert(false, "XTemplate or class not found: " .. tostring(template_or_class)) | |
| end | |
| function LoadXTemplates() | |
| Presets.XTemplate = {} | |
| XTemplates = {} | |
| LoadPresetFiles("Lua/Ged/XTemplates/") | |
| LoadPresetFiles("CommonLua/Ged/XTemplates/") | |
| LoadPresetFiles("CommonLua/X/XTemplates/") | |
| if not Platform.ged then | |
| ForEachLib("XTemplates/", function(lib, path) LoadPresetFiles(path) end) | |
| LoadPresetFiles("Lua/XTemplates/") | |
| end | |
| XTemplate:SortPresets() | |
| for _, group in ipairs(Presets.XTemplate) do | |
| for _, preset in ipairs(group) do | |
| preset:PostLoad() | |
| end | |
| end | |
| if Platform.developer and not Platform.ged then | |
| LoadCollapsedPresetGroups() | |
| end | |
| end | |
| if FirstLoad or ReloadForDlc then | |
| function OnMsg.ClassesBuilt() | |
| LoadXTemplates() | |
| end | |
| end | |
| function XTemplate:GetPresetStatusText() | |
| local scale = terminal.desktop.scale | |
| if scale:x() ~= 1000 or scale:y() ~= 1000 then | |
| return "UIScale is not 100%" | |
| end | |
| return "" | |
| end |