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, " "), EditorView = Untranslated(""), 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 "), 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 " 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 "), 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 "), 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, "<__class>','')>')>"), 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 "" 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: "), 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 "), 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 = "", 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, "Mode "), 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 "), 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 "), 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 " " .. 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 "), 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 "), 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 "), 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 -> for "), 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 "), 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("Dialog Thread [Close] "), 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