|
DefineClass.ClassDefSubItem = { |
|
__parents = { "PropertyObject" }, |
|
} |
|
|
|
function ClassDefSubItem:ToStringWithColor(value, t) |
|
local text = t and value or ValueToLuaCode(value) |
|
t = t or type(value) |
|
local color |
|
if t == "string" or IsT(value) then |
|
color = RGB(60, 140, 40) |
|
elseif t == "boolean" or t == "nil" then |
|
color = RGB(75, 105, 198) |
|
elseif t == "number" then |
|
color = RGB(150, 50, 20) |
|
elseif t == "function" then |
|
text = string.gsub(text, "^function ", "<color 75 105 198>function</color><color 92 92 92>") |
|
text = string.gsub(text, "end$", "<color 75 105 198>end</color>") |
|
end |
|
if not color then |
|
return text |
|
end |
|
local r, g, b = GetRGB(color) |
|
return string.format("<color %s %s %s><tags off>%s<tags on></color>", r, g, b, text) |
|
end |
|
|
|
|
|
|
|
|
|
local function GetCategoryItems(self) |
|
local categories = PresetGroupCombo("PropertyCategory", "Default")() |
|
local parent |
|
ForEachPreset("ClassDef", function(preset) |
|
parent = parent or table.find(preset, self) and preset |
|
end) |
|
if parent then |
|
local tmp = table.invert(categories) |
|
for _, prop in ipairs(parent) do |
|
if IsKindOf(prop, "PropertyDef") then |
|
tmp[prop.category or ""] = true |
|
end |
|
end |
|
categories = table.keys(tmp) |
|
end |
|
table.sort(categories, function(a, b) |
|
if a and b then |
|
return a < b |
|
else |
|
return b |
|
end |
|
end) |
|
return categories |
|
end |
|
|
|
local reusable_expressions = { |
|
dont_save = "Don't save", |
|
read_only = "Read only", |
|
no_edit = "Hidden", |
|
no_validate = "No validation", |
|
} |
|
|
|
local function reusable_expressions_combo(self) |
|
local ret = { |
|
{ text = "true", value = true }, |
|
{ text = "false", value = false }, |
|
{ text = "expression", value = "expression"}, |
|
} |
|
local preset = GetParentTableOfKind(self, "ClassDef") |
|
for _, property_def in ipairs(preset) do |
|
if IsKindOf(property_def, "PropertyDef") then |
|
for id, name in pairs(reusable_expressions) do |
|
if property_def[id] == "expression" then |
|
table.insert(ret, { |
|
text = "Reuse " .. name .. " from " .. property_def.id, |
|
value = property_def.id .. "." .. id |
|
}) |
|
end |
|
end |
|
end |
|
end |
|
return ret |
|
end |
|
|
|
function ValidateIdentifier(self, value) |
|
return (type(value) ~= "string" or not value:match("^[%a_][%w_]*$")) and "Please enter a valid identifier" |
|
end |
|
|
|
DefineClass.PropertyDef = { |
|
__parents = { "ClassDefSubItem" }, |
|
properties = { |
|
{ category = "Property", id = "category", name = "Category", editor = "combo", items = GetCategoryItems, default = false, }, |
|
{ category = "Property", id = "id", name = "Id", editor = "text", default = "", validate = ValidateIdentifier }, |
|
{ category = "Property", id = "name", name = "Name", editor = "text", translate = function(self) return self.translate_in_ged end, default = false }, |
|
{ category = "Property", id = "help", name = "Help", editor = "text", translate = function(self) return self.translate_in_ged end, lines = 1, max_lines = 3, default = false }, |
|
|
|
{ category = "Property", id = "dont_save", name = "Don't save", editor = "choice", default = false, items = reusable_expressions_combo }, |
|
{ category = "Property", id = "dont_save_expression", name = "Don't save", editor = "expression", default = return_true, params = "self, prop_meta", |
|
no_edit = function(self) return type(self.dont_save) == "boolean" end, |
|
read_only = function(self) return self.dont_save ~= "expression" end, |
|
dont_save = function(self) return self.dont_save ~= "expression" end, }, |
|
{ category = "Property", id = "read_only", name = "Read only", editor = "choice", default = false, items = reusable_expressions_combo }, |
|
{ category = "Property", id = "read_only_expression", name = "Read only", editor = "expression", default = return_true, params = "self, prop_meta", |
|
no_edit = function(self) return type(self.read_only) == "boolean" end, |
|
read_only = function(self) return self.read_only ~= "expression" end, |
|
dont_save = function(self) return self.read_only ~= "expression" end, }, |
|
{ category = "Property", id = "no_edit", name = "Hidden", editor = "choice", default = false, items = reusable_expressions_combo }, |
|
{ category = "Property", id = "no_edit_expression", name = "Hidden", editor = "expression", default = return_true, params = "self, prop_meta", |
|
no_edit = function(self) return type(self.no_edit) == "boolean" end, |
|
read_only = function(self) return self.no_edit ~= "expression" end, |
|
dont_save = function(self) return self.no_edit ~= "expression" end, }, |
|
{ category = "Property", id = "no_validate", name = "No validation", editor = "choice", default = false, items = reusable_expressions_combo }, |
|
{ category = "Property", id = "no_validate_expression", name = "No validation", editor = "expression", default = return_true, params = "self, prop_meta", |
|
no_edit = function(self) return type(self.no_validate) == "boolean" end, |
|
read_only = function(self) return self.no_validate ~= "expression" end, |
|
dont_save = function(self) return self.no_validate ~= "expression" end, }, |
|
|
|
{ category = "Property", id = "buttons", name = "Buttons", editor = "nested_list", base_class = "PropertyDefPropButton", default = false, inclusive = true, |
|
help = "Button function is searched by name in the object, the root parent (Preset?), and then globally.\n\nParameters are (self, root, prop_id, ged) for the object method, (root, obj, prop_id, ged) otherwise." }, |
|
{ category = "Property", id = "template", name = "Template", editor = "bool", default = false, help = "Marks template properties for classes which inherit 'ClassTemplate'"}, |
|
{ category = "Property", id = "validate", name = "Validate", editor = "expression", params = "self, value", help = "A function called by Ged when changing the value. Returns error, updated_value."}, |
|
{ category = "Property", id = "extra_code", name = "Extra Code", editor = "text", lines = 1, max_lines = 5, default = false, help = "Additional code to insert in the property metadata" }, |
|
}, |
|
editor = false, |
|
validate = false, |
|
context = false, |
|
gender = false, |
|
os_path = false, |
|
translate_in_ged = false, |
|
} |
|
|
|
function PropertyDef:GetEditorView() |
|
local category = "" |
|
if self.category then |
|
category = string.format("<color 45 138 138>[%s]</color> ", self.category) |
|
end |
|
return string.format("%s<color 75 105 198>%s</color> %s <color 158 158 158>=</color> <color 150 90 40>%s", |
|
category, self.editor, self.id, self:ToStringWithColor(self.default)) |
|
end |
|
|
|
local function getTranslatableValue(text, translate) |
|
if not text or text == "" then return end |
|
if text then |
|
assert(IsT(text) == translate) |
|
end |
|
return text |
|
end |
|
|
|
local reuse_error_fn = function() return "Unable to locate expression to reuse." end |
|
local reuse_prop_ids = { dont_save_expression = "dont_save", read_only_expression = "read_only", no_edit_expression = "no_edit", no_validate_expression = "no_validate" } |
|
|
|
function PropertyDef:GetProperty(prop) |
|
local main_prop_id = reuse_prop_ids[prop] |
|
if main_prop_id then |
|
local value = self:GetProperty(main_prop_id) |
|
if type(value) == "string" and value ~= "expression" then |
|
local reuse_prop_id, reuse = value:match("([%w_]+)%.([%w_]+)") |
|
if reuse then |
|
local preset = GetParentTableOfKind(self, "ClassDef") |
|
local property_def = table.find_value(preset, "id", reuse_prop_id) |
|
return property_def and property_def[reuse .. "_expression"] or reuse_error_fn |
|
end |
|
end |
|
end |
|
return ClassDefSubItem.GetProperty(self, prop) |
|
end |
|
|
|
function PropertyDef:GenerateExpressionSettingCode(code, id) |
|
local value = self[id] |
|
if type(value) ~= "boolean" then |
|
local expr = self:GetProperty(id .. "_expression") |
|
if expr ~= reuse_error_fn then |
|
code:appendf("%s = function(self) %s end, ", id, GetFuncBody(expr)) |
|
end |
|
elseif value then |
|
code:appendf("%s = true, ", id) |
|
end |
|
end |
|
|
|
function PropertyDef:GenerateCode(code, translate, extra_code_fn) |
|
if self.id == "" then return end |
|
code:append("\t\t{ ") |
|
if self.category and self.category ~= "" then |
|
code:appendf("category = \"%s\", ", self.category) |
|
end |
|
code:append("id = \"", self.id, "\", ") |
|
local name, help = getTranslatableValue(self.name, translate), getTranslatableValue(self.help, translate) |
|
if name then |
|
code:append("name = ", ValueToLuaCode(name), ", ") |
|
end |
|
if help then |
|
code:append("help = ", ValueToLuaCode(help), ", ") |
|
end |
|
code:append("\n\t\t\t") |
|
code:appendf("editor = \"%s\", default = %s, ", self.editor, self:GenerateDefaultValueCode()) |
|
|
|
self:GenerateExpressionSettingCode(code, "dont_save") |
|
self:GenerateExpressionSettingCode(code, "read_only") |
|
self:GenerateExpressionSettingCode(code, "no_edit") |
|
self:GenerateExpressionSettingCode(code, "no_validate") |
|
if self.validate then |
|
code:appendf("validate = function(self, value) %s end, ", GetFuncBody(self.validate)) |
|
end |
|
|
|
if self.buttons and #self.buttons > 0 then |
|
code:append("buttons = {") |
|
for _, data in ipairs(self.buttons) do |
|
if data.Name ~= "" then |
|
if data.IsHidden ~= empty_func then |
|
code:appendf([[ {name = "%s", func = "%s", is_hidden = function(self) %s end }, ]], data.Name, data.FuncName, GetFuncBody(data.IsHidden)) |
|
else |
|
code:appendf([[ {name = "%s", func = "%s"}, ]], data.Name, data.FuncName) |
|
end |
|
end |
|
end |
|
code:append("}, ") |
|
end |
|
if self.template then code:append("template = true, ") end |
|
if self.extra_code and self.extra_code ~= "" or extra_code_fn then |
|
local ext_code = self.extra_code and self.extra_code:gsub(",$", "") |
|
if extra_code_fn then |
|
ext_code = ext_code and (ext_code .. ", " .. extra_code_fn(self)) or extra_code_fn(self) |
|
ext_code = ext_code:gsub(",$", "") |
|
end |
|
if ext_code and ext_code ~= "" then |
|
code:append("\n\t\t\t", ext_code) |
|
code:append(", ") |
|
end |
|
end |
|
self:GenerateAdditionalPropCode(code, translate) |
|
code:append("},\n") |
|
end |
|
|
|
function PropertyDef:GenerateDefaultValueCode() |
|
return ValueToLuaCode(self.default, ' ', nil, {} ) |
|
end |
|
|
|
function PropertyDef:ValidateProperty(prop_meta) |
|
if not self.no_validate then |
|
return PropertyObject.ValidateProperty(self, prop_meta) |
|
end |
|
end |
|
|
|
function PropertyDef:GenerateAdditionalPropCode(code, translate) |
|
end |
|
|
|
function PropertyDef:AppendFunctionCode(code, prop_name) |
|
if not self[prop_name] then return end |
|
local name, params, body = GetFuncSource(self[prop_name]) |
|
code:appendf("%s = function (%s)\n", prop_name, params) |
|
if type(body) == "string" then |
|
body = string.split(body, "\n") |
|
end |
|
code:append("\t", body and table.concat(body, "\n\t") or "", "\n") |
|
code:append("end, \n") |
|
end |
|
|
|
function PropertyDef:GetError() |
|
if not self.no_validate and self.extra_code and (self.extra_code:find("[^%w_]items%s*=") or self.extra_code:find("^items%s*=")) then |
|
return "Please don't define 'items' as extra code. Use the dedicated Items property instead.\nThis is to make items appear in the default value property." |
|
end |
|
end |
|
|
|
function PropertyDef:CleanupForSave() |
|
end |
|
|
|
function PropertyDef:EmulatePropEval(metadata_id, default, prop_meta, validate_fn) |
|
local prop_meta = self |
|
local classdef_preset = GetParentTableOfKind(self, "ClassDef") |
|
if not classdef_preset then return default end |
|
local obj_class = g_Classes[classdef_preset.id] |
|
local instance = obj_class and not obj_class:IsKindOf("CObject") and obj_class:new() or {} |
|
if validate_fn then |
|
return eval_items(prop_meta[metadata_id], instance, prop_meta) |
|
end |
|
return prop_eval(prop_meta[metadata_id], instance, prop_meta, default) |
|
end |
|
|
|
local function EmulatePropEval(metadata_id, default) |
|
return function(self, prop_meta, validate_fn) |
|
return self:EmulatePropEval(metadata_id, default, prop_meta, validate_fn) |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefPropButton = { |
|
__parents = { "PropertyObject" }, |
|
properties = { |
|
{ id = "Name", editor = "text", default = ""}, |
|
{ id = "FuncName", editor = "text", default = ""}, |
|
{ id = "IsHidden", editor = "expression", default = empty_func}, |
|
}, |
|
EditorView = Untranslated("[<Name>] = <FuncName>"), |
|
} |
|
|
|
DefineClass.PropertyDefButtons = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ id = "default", name = "Default value", editor = false, default = false, }, |
|
}, |
|
editor = "buttons", |
|
EditorName = "Buttons property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
DefineClass.PropertyDefBool = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Bool", id = "default", name = "Default value", editor = "bool", default = false, }, |
|
}, |
|
editor = "bool", |
|
EditorName = "Bool property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
DefineClass.PropertyDefTable = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Table", id = "default", name = "Default value", editor = "prop_table", default = false, }, |
|
{ category = "Table", id = "lines", name = "Lines", editor = "number", default = 1, }, |
|
}, |
|
editor = "prop_table", |
|
EditorName = "Table property", |
|
EditorSubmenu = "Objects", |
|
} |
|
|
|
function PropertyDefTable:GenerateAdditionalPropCode(code, translate) |
|
if self.lines > 1 then |
|
code:append("indent = \"\", lines = 1, max_lines = ", self.lines, ", ") |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefPoint = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Point", id = "default", name = "Default value", editor = "point", default = false, }, |
|
}, |
|
editor = "point", |
|
EditorName = "Point property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
DefineClass.PropertyDefPoint2D = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Point2D", id = "default", name = "Default value", editor = "point2d", default = false, }, |
|
}, |
|
editor = "point2d", |
|
EditorName = "Point2D property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
DefineClass.PropertyDefRect = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Rect", id = "default", name = "Default value", editor = "rect", default = false, }, |
|
}, |
|
editor = "rect", |
|
EditorName = "Rect property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
DefineClass.PropertyDefMargins = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Margins", id = "default", name = "Default value", editor = "margins", default = false, }, |
|
}, |
|
editor = "margins", |
|
EditorName = "Margins property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
DefineClass.PropertyDefPadding = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Padding", id = "default", name = "Default value", editor = "padding", default = false, }, |
|
}, |
|
editor = "padding", |
|
EditorName = "Padding property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
DefineClass.PropertyDefBox = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Box", id = "default", name = "Default value", editor = "box", default = false, }, |
|
}, |
|
editor = "box", |
|
EditorName = "Box property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
DefineClass.PropertyDefNumber = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Number", id = "default", name = "Default value", editor = "number", default = false, scale = function(obj) return obj.scale end, min = function(obj) return obj.min end, max = function(obj) return obj.max end, }, |
|
{ category = "Number", id = "scale", name = "Scale", editor = "choice", default = 1, items = function() return table.keys2(const.Scale, true, 1, 10, 100, 1000, 1000000) end, }, |
|
{ category = "Number", id = "step", name = "Step", editor = "number", default = 1, scale = function(obj) return obj.scale end, }, |
|
{ category = "Number", id = "float", name = "Float", editor = "bool", default = false, }, |
|
{ category = "Number", id = "slider", name = "Slider", editor = "bool", default = false, }, |
|
{ category = "Number", id = "min", name = "Min", editor = "number", default = min_int64, scale = function(obj) return obj.scale end, no_edit = PropChecker("custom_lims", true)}, |
|
{ category = "Number", id = "max", name = "Max", editor = "number", default = max_int64, scale = function(obj) return obj.scale end, no_edit = PropChecker("custom_lims", true) }, |
|
{ category = "Number", id = "custom_min", name = "Min", editor = "expression", default = false, no_edit = PropChecker("custom_lims", false) }, |
|
{ category = "Number", id = "custom_max", name = "Max", editor = "expression", default = false, no_edit = PropChecker("custom_lims", false) }, |
|
{ category = "Number", id = "custom_lims", name = "Custom Lims", editor = "bool", default = false, help = "Use custom limits"}, |
|
{ category = "Number", id = "modifiable", name = "Modifiable", editor = "bool", default = false, help = "Marks modifiable properties for classes which inherit 'Modifiable' class"}, |
|
}, |
|
editor = "number", |
|
EditorName = "Number property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefNumber:GenerateAdditionalPropCode(code, translate) |
|
local scale = self.scale |
|
if scale ~= 1 then |
|
code:appendf(type(scale) == "number" and "scale = %d, " or "scale = \"%s\", ", scale) |
|
end |
|
if self.step ~= 1 then code:appendf("step = %d, ", self.step) end |
|
if self.slider then code:append("slider = true, ") end |
|
if self.custom_lims then |
|
if self.custom_min ~= PropertyDefNumber.custom_min then |
|
local name, params, body = GetFuncSource(self.custom_min) |
|
body = type(body) == "table" and table.concat(body, "\n") or body |
|
code:appendf("min = function(self) %s end, ", body) |
|
end |
|
if self.custom_max ~= PropertyDefNumber.custom_max then |
|
local name, params, body = GetFuncSource(self.custom_max) |
|
body = type(body) == "table" and table.concat(body, "\n") or body |
|
code:appendf("max = function(self) %s end, ", body) |
|
end |
|
else |
|
if self.min ~= PropertyDefNumber.min then code:appendf("min = %d, ", self.min) end |
|
if self.max ~= PropertyDefNumber.max then code:appendf("max = %d, ", self.max) end |
|
end |
|
if self.modifiable then code:append("modifiable = true, ") end |
|
end |
|
|
|
function PropertyDefNumber:OnEditorSetProperty(prop_id, old_value, ged) |
|
if prop_id == "slider" and self.slider then |
|
if self.min == PropertyDefNumber.min then self.min = 0 end |
|
if self.max == PropertyDefNumber.max then self.max = 100 * (const.Scale[self.scale] or self.scale) end |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefRange = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Range", id = "default", name = "Default value", editor = "range", scale = function(obj) return obj.scale end, min = function(obj) return obj.min end, max = function(obj) return obj.max end, default = false, }, |
|
{ category = "Range", id = "scale", name = "Scale", editor = "choice", default = 1, items = function() return table.keys2(const.Scale, true, 1, 10, 100, 1000, 1000000) end, }, |
|
{ category = "Range", id = "step", name = "Step", editor = "number", default = 1, scale = function(obj) return obj.scale end, }, |
|
{ category = "Range", id = "slider", name = "Slider", editor = "bool", default = false, }, |
|
{ category = "Range", id = "min", name = "Min", editor = "number", default = min_int64 }, |
|
{ category = "Range", id = "max", name = "Max", editor = "number", default = max_int64 }, |
|
}, |
|
editor = "range", |
|
EditorName = "Range property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefRange:GenerateAdditionalPropCode(code, translate) |
|
if self.scale ~= 1 then |
|
code:appendf(type(self.scale) == "number" and "scale = %d, " or "scale = \"%s\", ", self.scale) |
|
end |
|
if self.step ~= 1 then code:appendf("step = %d, ", self.step) end |
|
if self.slider then code:append("slider = true, ") end |
|
if self.min ~= PropertyDefRange.min then code:appendf("min = %d, ", self.min) end |
|
if self.max ~= PropertyDefRange.max then code:appendf("max = %d, ", self.max) end |
|
end |
|
|
|
function PropertyDefRange:OnEditorSetProperty(prop_id, old_value, ged) |
|
if prop_id == "slider" and self.slider then |
|
if self.min == PropertyDefRange.min then self.min = 0 end |
|
if self.max == PropertyDefRange.max then self.max = 100 * (const.Scale[self.scale] or self.scale) end |
|
end |
|
end |
|
|
|
local function translate_only(obj) return not obj.translate end |
|
TextGenderOptions = { |
|
{value = false, text = "None"}, |
|
{value = "ask", text = "Request translation gender for each language (for nouns)"}, |
|
{value = "variants", text = "Generate separate translation texts for each gender"}, |
|
} |
|
|
|
DefineClass.PropertyDefText = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Text", id = "default", name = "Default value", editor = "text", default = false, translate = function (obj) return obj.translate end, }, |
|
{ category = "Text", id = "translate", name = "Translate", editor = "bool", default = true, }, |
|
{ category = "Text", id = "wordwrap", name = "Wordwrap", editor = "bool", default = false, }, |
|
{ category = "Text", id = "gender", name = "Gramatical gender", editor = "choice", default = false, items = TextGenderOptions, |
|
no_edit = translate_only, dont_save = translate_only }, |
|
{ category = "Text", id = "lines", name = "Lines", editor = "number", default = false, }, |
|
{ category = "Text", id = "max_lines", name = "Max lines", editor = "number", default = false, }, |
|
{ category = "Text", id = "trim_spaces", name = "Trim Spaces", editor = "bool", default = true, }, |
|
{ category = "Text", id = "context", name = "Context", editor = "text", default = "", |
|
no_edit = translate_only, dont_save = translate_only } |
|
}, |
|
editor = "text", |
|
EditorName = "Text property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefText:OnEditorSetProperty(prop_id, old_value, ged) |
|
if prop_id == "translate" then |
|
self:UpdateLocalizedProperty("default", self.translate) |
|
end |
|
end |
|
|
|
function PropertyDefText:GenerateAdditionalPropCode(code, translate) |
|
if self.translate then code:append("translate = true, ") end |
|
if self.wordwrap then code:append("wordwrap = true, ") end |
|
if self.lines then code:appendf("lines = %d, ", self.lines) end |
|
if self.max_lines then code:appendf("max_lines = %d, ", self.max_lines) end |
|
if self.trim_spaces==false then code:append("trim_spaces = false, ") end |
|
local context = self.translate and self.context or "" |
|
if context ~= "" then |
|
assert(not self.gender, "Custom context code is not compatible with gender specification") |
|
code:append("context = ", context, ", ") |
|
elseif self.gender then |
|
code:append('context = "|gender-', self.gender, '", ') |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefChoice = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Choice", id = "default", name = "Default value", editor = "choice", default = false, items = EmulatePropEval("items", {""}) }, |
|
{ category = "Choice", id = "items", name = "Items", editor = "expression", default = false, }, |
|
{ category = "Choice", id = "show_recent_items", name = "Show recent items", editor = "number", default = 0, }, |
|
}, |
|
translate = false, |
|
editor = "choice", |
|
EditorName = "Choice property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefChoice:GenerateAdditionalPropCode(code, translate) |
|
if self.items then |
|
code:append("items = ") |
|
ValueToLuaCode(self.items, nil, code) |
|
code:append(", ") |
|
end |
|
if self.show_recent_items and self.show_recent_items ~= 0 then |
|
code:appendf("show_recent_items = %d,", self.show_recent_items) |
|
end |
|
end |
|
|
|
function PropertyDefChoice:GetConvertToPresetIdClass() |
|
local preset_class |
|
if self.items then |
|
local src = GetFuncSourceString(self.items) |
|
local _, _, capture = string.find(src, 'PresetsCombo%("([%w_+-]*)"%)') |
|
preset_class = capture |
|
end |
|
return preset_class |
|
end |
|
|
|
DefineClass.PropertyDefCombo = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Combo", id = "default", name = "Default value", editor = "combo", default = false, items = EmulatePropEval("items", {""}) }, |
|
{ category = "Combo", id = "items", name = "Items", editor = "expression", default = false, }, |
|
{ category = "Combo", id = "translate", name = "Translate", editor = "bool", default = false, }, |
|
{ category = "Combo", id = "show_recent_items", name = "Show recent items", editor = "number", default = 0, }, |
|
}, |
|
editor = "combo", |
|
EditorName = "Combo property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
PropertyDefCombo.GenerateAdditionalPropCode = PropertyDefChoice.GenerateAdditionalPropCode |
|
|
|
DefineClass.PropertyDefPickerBase = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Picker", id = "default", name = "Default value", editor = "combo", default = false, items = EmulatePropEval("items", {""}) }, |
|
{ category = "Picker", id = "items", name = "Items", editor = "expression", default = false, }, |
|
{ category = "Picker", id = "max_rows", name = "Max rows", editor = "number", default = false, help = "Maximum number of rows displayed." }, |
|
{ category = "Picker", id = "multiple", name = "Multiple selection", editor = "bool", default = false, }, |
|
{ category = "Picker", id = "small_font", name = "Small font", editor = "bool", default = false, }, |
|
{ category = "Picker", id = "filter_by_prop", name = "Filter by prop", editor = "text", default = false, help = "Links this property to a text property with the specified id that serves as a filter." }, |
|
}, |
|
} |
|
|
|
function PropertyDefPickerBase:GenerateAdditionalPropCode(code, translate) |
|
PropertyDefChoice.GenerateAdditionalPropCode(self, code, translate) |
|
if self.max_rows then code:appendf("max_rows = %d, ", self.max_rows) end |
|
if self.multiple then code:append ("multiple = true, ") end |
|
if self.small_font then code:append ("small_font = true, ") end |
|
if self.filter_by_prop then code:appendf("filter_by_prop = \"%s\", ", self.filter_by_prop) end |
|
end |
|
|
|
DefineClass.PropertyDefTextPicker = { |
|
__parents = { "PropertyDefPickerBase" }, |
|
properties = { |
|
{ category = "Picker", id = "horizontal", name = "Horizontal", editor = "bool", default = false, help = "Display items horizontally." }, |
|
}, |
|
editor = "text_picker", |
|
EditorName = "Text picker property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
function PropertyDefTextPicker:GenerateAdditionalPropCode(code, translate) |
|
PropertyDefPickerBase.GenerateAdditionalPropCode(self, code, translate) |
|
if self.horizontal then code:append("horizontal = true, ") end |
|
end |
|
|
|
DefineClass.PropertyDefTexturePicker = { |
|
__parents = { "PropertyDefPickerBase" }, |
|
properties = { |
|
{ category = "Picker", id = "thumb_width", name = "Width", editor = "number", default = false, }, |
|
{ category = "Picker", id = "thumb_height", name = "Height", editor = "number", default = false, }, |
|
{ category = "Picker", id = "thumb_zoom", name = "Zoom", editor = "number", min = 100, max = 200, slider = true, default = false, help = "Scale the texture up, displaying only the middle part with Width x Height dimensions.", }, |
|
{ category = "Picker", id = "alt_prop", name = "Alt prop", editor = "text", default = false, help = "Id of another property that gets set by Alt-click on this property.", }, |
|
{ category = "Picker", id = "base_color_map", name = "Base color map", editor = "bool", default = false, help = "Use to display a base color map texture in the correct colors.", }, |
|
}, |
|
editor = "texture_picker", |
|
EditorName = "Texture picker property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
function PropertyDefTexturePicker:GenerateAdditionalPropCode(code, translate) |
|
PropertyDefPickerBase.GenerateAdditionalPropCode(self, code, translate) |
|
if self.thumb_width then code:appendf("thumb_width = %d, ", self.thumb_width) end |
|
if self.thumb_height then code:appendf("thumb_height = %d, ", self.thumb_height) end |
|
if self.thumb_zoom then code:appendf("thumb_zoom = %d, ", self.thumb_zoom) end |
|
if self.alt_prop then code:appendf("alt_prop = \"%s\", ", self.alt_prop) end |
|
if self.base_color_map then code:append ("base_color_map = true, ") end |
|
end |
|
|
|
DefineClass.PropertyDefSet = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Set", id = "default", name = "Default value", editor = "set", default = false, items = EmulatePropEval("items", {""}), three_state = function(obj) return obj.three_state end, max_items_in_set = function(obj) return obj.max_items_in_set end, }, |
|
{ category = "Set", id = "items", name = "Items", editor = "expression", default = false, }, |
|
{ category = "Set", id = "arbitrary_value", name = "Allow arbitrary value", editor = "bool", default = false, }, |
|
{ category = "Set", id = "three_state", name = "Three-state", editor = "bool", default = false, help = "Each set item can have one of the three value 'nil', 'true', or 'false'." }, |
|
{ category = "Set", id = "max_items_in_set", name = "Max items", editor = "number", default = 0, help = "Max number of items in the set (0 = no limit)." }, |
|
}, |
|
translate = false, |
|
editor = "set", |
|
EditorName = "Set property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefSet:GenerateAdditionalPropCode(code, translate) |
|
if self.three_state then code:append("three_state = true, ") end |
|
if self.arbitrary_value then code:append("arbitrary_value = true, ") end |
|
if self.max_items_in_set ~= 0 then code:appendf("max_items_in_set = %d, ", self.max_items_in_set) end |
|
if self.items then |
|
code:append("items = ") |
|
ValueToLuaCode(self.items, nil, code) |
|
code:append(", ") |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefGameStatefSet = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Set", id = "default", name = "Default value", editor = "set", default = false, items = function() return GetGameStateFilter() end, three_state = true, }, |
|
}, |
|
translate = false, |
|
editor = "set", |
|
EditorName = "GameState Set property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefGameStatefSet:GenerateAdditionalPropCode(code, translate) |
|
code:append("three_state = true, items = function (self) return GetGameStateFilter() end, ") |
|
code:append('buttons = { {name = "Check Game States", func = "PropertyDefGameStatefSetCheck"}, },') |
|
end |
|
|
|
function PropertyDefGameStatefSetCheck(_, obj, prop_id, ged) |
|
ged:ShowMessage("Test Result", GetMismatchGameStates(obj[prop_id])) |
|
end |
|
|
|
DefineClass.PropertyDefColor = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Color", id = "default", name = "Default value", editor = "color", default = RGB(0, 0, 0), }, |
|
}, |
|
editor = "color", |
|
EditorName = "Color property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
DefineClass.PropertyDefImage = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Image", id = "default", name = "Default value", editor = "image", default = false, }, |
|
{ category = "Image", id = "img_size", name = "Image box", editor = "number", default = 200, }, |
|
{ category = "Image", id = "img_box", name = "Image border", editor = "number", default = 1, }, |
|
{ category = "Image", id = "base_color_map", name = "Base color", editor = "bool", default = false, }, |
|
}, |
|
editor = "image", |
|
EditorName = "Image preview property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
function PropertyDefImage:GenerateAdditionalPropCode(code, translate) |
|
code:appendf("img_size = %d, img_box = %d, base_color_map = %s, ", self.img_size, self.img_box, tostring(self.base_color_map)) |
|
end |
|
|
|
DefineClass.PropertyDefGrid = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Grid", id = "default", name = "Default value", editor = "grid", default = false, }, |
|
{ category = "Grid", id = "frame", name = "Frame", editor = "number", default = 0, }, |
|
{ category = "Grid", id = "color", name = "Color", editor = "bool", default = false }, |
|
{ category = "Grid", id = "min", name = "Min Size", editor = "number", default = 0, }, |
|
{ category = "Grid", id = "max", name = "Max Size", editor = "number", default = 0 }, |
|
}, |
|
editor = "grid", |
|
EditorName = "Grid property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
function PropertyDefGrid:GenerateAdditionalPropCode(code, translate) |
|
if self.frame > 0 then code:appendf("frame = %d, ", self.frame) end |
|
if self.min > 0 then code:appendf("min = %d, ", self.min) end |
|
if self.max > 0 then code:appendf("max = %d, ", self.max) end |
|
if self.color then code:append("color = true, ") end |
|
end |
|
|
|
DefineClass.PropertyDefMaterial = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Color", id = "default", name = "Default value", editor = "rgbrm", default = RGBRM(200, 200, 200, 0, 0) }, |
|
}, |
|
editor = "rgbrm", |
|
EditorName = "Material property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
DefineClass.PropertyDefBrowse = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Browse", id = "default", name = "Default value", editor = "browse", default = false, }, |
|
{ category = "Browse", id = "folder", name = "Folder", editor = "text", default = "UI", }, |
|
{ category = "Browse", id = "filter", name = "Filter", editor = "text", default = "Image files|*.tga", }, |
|
{ category = "Browse", id = "extension", name = "Force extension", editor = "text", default = false, |
|
buttons = { { name = "No extension", func = function(self) self.extension = "" ObjModified(self) end, } }, |
|
}, |
|
{ category = "Browse", id = "image_preview_size", name = "Image preview size", editor = "number", default = 0, }, |
|
}, |
|
editor = "browse", |
|
EditorName = "Browse property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefBrowse:GenerateAdditionalPropCode(code, translate) |
|
local folder, filter = self.folder or "", self.filter or "" |
|
if folder ~= "" then |
|
|
|
if folder:match("^%s*[{\"]") then |
|
code:appendf("folder = %s, ", self.folder) |
|
else |
|
code:appendf("folder = \"%s\", ", self.folder) |
|
end |
|
end |
|
if self.filter ~= "" then code:appendf("filter = \"%s\", ", self.filter) end |
|
if self.extension ~= PropertyDefBrowse.extension then code:appendf("force_extension = \"%s\", ", self.extension) end |
|
if self.image_preview_size > 0 then code:appendf("image_preview_size = %i, ", self.image_preview_size) end |
|
end |
|
|
|
|
|
DefineClass.PropertyDefUIImage = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Browse", id = "default", name = "Default value", editor = "ui_image", default = false, }, |
|
{ category = "Browse", id = "filter", name = "Filter", editor = "text", default = "All files|*.*", }, |
|
{ category = "Browse", id = "extension", name = "Force extension", editor = "text", default = false, |
|
buttons = { { name = "No extension", func = function(self) self.extension = "" ObjModified(self) end, } }, |
|
}, |
|
{ category = "Browse", id = "image_preview_size", name = "Image preview size", editor = "number", default = 0, }, |
|
}, |
|
editor = "ui_image", |
|
EditorName = "UI image property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefUIImage:GenerateAdditionalPropCode(code, translate) |
|
if self.filter ~= PropertyDefUIImage.filter then code:appendf("filter = \"%s\", ", self.filter) end |
|
if self.extension ~= PropertyDefUIImage.extension then code:appendf("force_extension = \"%s\", ", self.extension) end |
|
if self.image_preview_size > 0 then code:appendf("image_preview_size = %i, ", self.image_preview_size) end |
|
end |
|
|
|
DefineClass.PropertyDefFunc = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Func", id = "params", name = "Params", editor = "text", default = "self", }, |
|
{ category = "Func", id = "default", name = "Default value", editor = "func", default = empty_func, lines = 1, max_lines = 20, params = function (self) return self.params end, }, |
|
}, |
|
editor = "func", |
|
EditorName = "Func property", |
|
EditorSubmenu = "Code", |
|
} |
|
|
|
function PropertyDefFunc:ToStringWithColor(value) |
|
if value == empty_func then |
|
return PropertyDef.ToStringWithColor(self, string.format("function (%s) end", self.params), "function") |
|
end |
|
return PropertyDef.ToStringWithColor(self, value) |
|
end |
|
|
|
|
|
function PropertyDefFunc:GenerateDefaultValueCode() |
|
if not self.default then return "false" end |
|
return GetFuncSourceString(self.default, "", self.params or "self") |
|
end |
|
|
|
function PropertyDefFunc:GenerateAdditionalPropCode(code, translate) |
|
if self.params and self.params ~= "self" then |
|
code:appendf("params = \"%s\", ", self.params) |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefExpression = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Expression", id = "params", name = "Params", editor = "text", default = "self", }, |
|
{ category = "Expression", id = "default", name = "Default value", editor = "expression", default = false, params = function(self) return self.params end, }, |
|
}, |
|
editor = "expression", |
|
EditorName = "Expression property", |
|
EditorSubmenu = "Code", |
|
} |
|
|
|
function PropertyDefExpression:GenerateDefaultValueCode() |
|
if not self.default then return "false" end |
|
return GetFuncSourceString(self.default, "", self.params or "self") |
|
end |
|
|
|
function PropertyDefExpression:GenerateAdditionalPropCode(code, translate) |
|
if self.params and self.params ~= "self" then |
|
code:appendf("params = \"%s\", ", self.params) |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefShortcut = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Expression", id = "shortcut_type", name = "Shortcut type", editor = "choice", default = "keyboard&mouse", items = { |
|
"keyboard&mouse", |
|
"keyboard", |
|
"gamepad" |
|
}, }, |
|
{ category = "Expression", id = "default", name = "Default value", editor = "text", default = "", no_edit = true, }, |
|
}, |
|
editor = "shortcut", |
|
EditorName = "Shortcut property", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
function PropertyDefShortcut:GenerateAdditionalPropCode(code, translate) |
|
code:appendf("shortcut_type = \"%s\", ", self.shortcut_type) |
|
end |
|
|
|
|
|
|
|
function IsPresetWithConstantGroup(classdef) |
|
if not classdef then return end |
|
local prop = classdef:GetPropertyMetadata("Group") |
|
return not prop or prop_eval(prop.no_edit, classdef, prop, true) or prop_eval(prop.read_only, classdef, prop, true) |
|
end |
|
|
|
DefineClass.PropertyDefPresetIdBase = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "PresetId", id = "preset_class", name = "Preset class", editor = "choice", default = "", |
|
items = ClassDescendantsCombo("Preset", false, function(name, class) |
|
return not IsKindOfClasses(class, "ClassDef", "ClassDefSubItem") |
|
end), |
|
}, |
|
{ category = "PresetId", id = "preset_group", name = "Preset group", editor = "choice", default = "", |
|
help = "Restricts the choice to the specified group of the preset class.", |
|
items = function(obj) |
|
local class = g_Classes[obj.preset_class] |
|
local preset_class = class.PresetClass or obj.preset_class |
|
return class and PresetGroupsCombo(preset_class) or empty_table |
|
end, |
|
no_edit = function(obj) |
|
local class = g_Classes[obj.preset_class] |
|
return not class or IsPresetWithConstantGroup(class) |
|
end, }, |
|
{ category = "PresetId", id = "preset_filter", name = "PresetFilter", editor = "func", params = "preset, obj, prop_meta", lines = 1, max_lines = 20, default = false }, |
|
{ category = "PresetId", id = "extra_item", name = "Extra item", editor = "text", default = false }, |
|
{ category = "PresetId", id = "default", name = "Default value", editor = "choice", |
|
items = function(obj) |
|
local class = g_Classes[obj.preset_class] |
|
if class and (class.GlobalMap or IsPresetWithConstantGroup(class) or obj.preset_group ~= "") then |
|
return PresetsCombo(obj.preset_class, obj.preset_group ~= "" and obj.preset_group, {"", obj.extra_item or nil}) |
|
end |
|
return { false } |
|
end, default = false }, |
|
}, |
|
editor = "preset_id", |
|
EditorName = "PresetId property", |
|
EditorSubmenu = "Basic property", |
|
} |
|
|
|
function PropertyDefPresetIdBase:GenerateAdditionalPropCode(code, translate) |
|
if self.preset_class ~= "" then code:appendf("preset_class = \"%s\", ", self.preset_class) end |
|
if self.preset_group ~= "" then code:appendf("preset_group = \"%s\", ", self.preset_group) end |
|
if self.extra_item then code:appendf("extra_item = \"%s\", ", self.extra_item) end |
|
self:AppendFunctionCode(code, "preset_filter") |
|
end |
|
|
|
function PropertyDefPresetIdBase:OnEditorSetProperty(prop_id, old_value, ...) |
|
if prop_id == "preset_class" then |
|
self.preset_group = nil |
|
self.default = nil |
|
elseif prop_id == "preset_group" then |
|
self.default = nil |
|
end |
|
ObjModified(self) |
|
end |
|
|
|
function PropertyDefPresetIdBase:GetError() |
|
local class = g_Classes[self.preset_class] |
|
if class and not (class.GlobalMap or IsPresetWithConstantGroup(class) or self.preset_group ~= "") then |
|
return string.format("%s doesn't have GlobalMap - all presets can't be listed. Please specify a Preset group.\n\nIf you want all presets to be selectable, either add GlobalMap, or create two properties - one for selecting a preset group and another for selecting a preset from that group.", self.preset_class) |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefPresetId = { |
|
__parents = { "PropertyDefPresetIdBase" }, |
|
} |
|
|
|
DefineClass.PropertyDefPresetIdList = { |
|
__parents = { "PropertyDefPresetIdBase", "WeightedListProps" }, |
|
properties = { |
|
{ category = "PresetId", id = "default", name = "Default value", editor = "preset_id_list", |
|
preset_class = function(obj) return obj.preset_class end, |
|
preset_group = function(obj) return obj.preset_group end, |
|
extra_item = function(obj) return obj.extra_item end, |
|
default = {}, }, |
|
}, |
|
editor = "preset_id_list", |
|
EditorName = "PresetId list property", |
|
EditorSubmenu = "Lists", |
|
} |
|
|
|
function PropertyDefPresetIdList:GenerateAdditionalPropCode(code, translate) |
|
PropertyDefPresetIdBase.GenerateAdditionalPropCode(self, code, translate) |
|
code:append("item_default = \"\"") |
|
self:GenerateWeightPropCode(code) |
|
code:append(", ") |
|
end |
|
|
|
|
|
|
|
|
|
local function BaseClassCombo(obj, prop_meta, validate_fn) |
|
if validate_fn == "validate_fn" then |
|
|
|
return "validate_fn", function(value, obj, prop_meta) |
|
local class = g_Classes[value] |
|
return value == "" or IsKindOf(class, "PropertyObject") and not IsKindOf(class, "CObject") |
|
end |
|
end |
|
return ClassDescendantsList("PropertyObject", function(name, def) |
|
return not def.__ancestors.CObject and name ~= "CObject" |
|
end, "") |
|
end |
|
|
|
DefineClass.PropertyDefObject = { |
|
__parents = { "PropertyDef" }, |
|
default = false, |
|
editor = "object", |
|
properties = { |
|
{ category = "Property", id = "base_class", name = "Base class", editor = "choice", items = function() return ClassDescendantsListInclusive("Object") end, default = "Object" }, |
|
{ category = "Property", id = "format_func", name = "Format", editor = "func", default = GetObjectPropEditorFormatFuncDefault, lines = 1, max_lines = 10, params = "gameobj"}, |
|
}, |
|
EditorName = "Object property", |
|
EditorSubmenu = "Objects", |
|
} |
|
|
|
function PropertyDefObject:GenerateAdditionalPropCode(code, translate) |
|
code:appendf("base_class = \"%s\", ", self.base_class) |
|
self:AppendFunctionCode(code, "format_func") |
|
end |
|
|
|
DefineClass.PropertyDefNestedObj = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Nested Object", id = "base_class", name = "Base class", editor = "choice", items = BaseClassCombo, default = "PropertyObject" }, |
|
{ category = "Nested Object", id = "inclusive", name = "Allow base class", editor = "bool", default = false, }, |
|
{ category = "Nested Object", id = "no_descendants", name = "No descendants", editor = "bool", default = false, }, |
|
{ category = "Nested Object", id = "all_descendants", name = "Allow all descendants", editor = "bool", default = false, no_edit = function (self) return self.no_descendants end, }, |
|
{ category = "Nested Object", id = "class_filter", name = "ClassFilter", editor = "func", default = false, lines = 1, max_lines = 20, params = "name, class, obj"}, |
|
{ category = "Nested Object", id = "format", name = "Format in Ged", editor = "text", default = "<EditorView>", }, |
|
{ category = "Nested Object", id = "auto_expand", name = "Auto Expand", editor = "bool", default = false, }, |
|
{ category = "Nested Object", id = "default", name = "Default value", editor = "bool", default = false, no_edit = true, }, |
|
}, |
|
editor = "nested_obj", |
|
EditorName = "Nested object property", |
|
EditorSubmenu = "Objects", |
|
} |
|
|
|
function PropertyDefNestedObj:GenerateAdditionalPropCode(code, translate) |
|
code:appendf("base_class = \"%s\", ", self.base_class) |
|
if self.inclusive then code:append("inclusive = true, ") end |
|
if self.no_descendants then code:append("no_descendants = true, ") |
|
elseif self.all_descendants then code:append("all_descendants = true, ") end |
|
if self.auto_expand then code:appendf("auto_expand = true, ") end |
|
if self.format ~= PropertyDefNestedObj.format then code:appendf("format = \"%s\"", self.format) end |
|
self:AppendFunctionCode(code, "class_filter") |
|
end |
|
|
|
function PropertyDefNestedObj:GetError() |
|
if self.base_class == "PropertyObject" then |
|
return "Please specify base class for the nested object(s)." |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefNestedList = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Nested List", id = "base_class", name = "Base class", editor = "choice", items = BaseClassCombo, default = "PropertyObject" }, |
|
{ category = "Nested List", id = "inclusive", name = "Allow base class", editor = "bool", default = false, }, |
|
{ category = "Nested List", id = "no_descendants", name = "No descendants", editor = "bool", default = false, }, |
|
{ category = "Nested List", id = "all_descendants", name = "Allow all descendants", editor = "bool", default = false, no_edit = function (self) return self.no_descendants end, }, |
|
{ category = "Nested List", id = "class_filter", name = "ClassFilter", editor = "func", default = false, lines = 1, max_lines = 20, params = "name, class, obj"}, |
|
{ category = "Nested List", id = "format", name = "Format in Ged", editor = "text", default = "<EditorView>", }, |
|
{ category = "Nested List", id = "auto_expand", name = "Auto Expand", editor = "bool", default = false, }, |
|
{ category = "Nested List", id = "default", name = "Default value", editor = "bool", default = false, no_edit = true, }, |
|
}, |
|
editor = "nested_list", |
|
EditorName = "Nested list property", |
|
EditorSubmenu = "Lists", |
|
} |
|
|
|
PropertyDefNestedList.GenerateAdditionalPropCode = PropertyDefNestedObj.GenerateAdditionalPropCode |
|
PropertyDefNestedList.GetError = PropertyDefNestedObj.GetError |
|
|
|
DefineClass.PropertyDefPropertyArray = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Dynamic Props", id = "from", name = "Generate id from", editor = "choice", default = false, |
|
items = { "Table keys", "Table values", "Table field values", "Preset ids" }, |
|
}, |
|
{ category = "Dynamic Props", id = "field", name = "Table field", editor = "text", translate = false, default = "", |
|
no_edit = function(self) return self.from ~= "Table field values" end, |
|
}, |
|
{ category = "Dynamic Props", id = "items", name = "Items", editor = "expression", default = false, |
|
no_edit = function(self) return self.from == "Preset ids" end, |
|
}, |
|
{ category = "Dynamic Props", id = "preset", name = "Preset class", editor = "choice", default = "", |
|
items = ClassDescendantsCombo("Preset"), |
|
no_edit = function(self) return self.from ~= "Preset ids" end, |
|
}, |
|
{ category = "Dynamic Props", id = "prop_meta_update", name = "Update prop_meta", editor = "func", params = "self, prop_meta", default = false, |
|
help = "Update the prop_meta of each generated property from prop_meta.id, prop_meta.index (consecutive number), and prop_meta.prest/value.", |
|
}, |
|
{ category = "Dynamic Props", id = "prop", name = "Property template", editor = "nested_obj", base_class = "PropertyDef", auto_expand = true, default = false, |
|
suppress_props = { id = true, name = true, category = true, dont_save = true, no_edit = true, template = true, }, |
|
}, |
|
}, |
|
editor = "property_array", |
|
EditorName = "Property array", |
|
EditorSubmenu = "Objects", |
|
default = false, |
|
} |
|
|
|
function PropertyDefPropertyArray:GenerateAdditionalPropCode(code, translate) |
|
local from_preset = self.from == "Preset ids" and self.preset ~= "" and self.preset |
|
if self.prop and (from_preset or not from_preset and self.items ~= false) then |
|
if from_preset then |
|
code:appendf("from = '%s', ", self.preset) |
|
else |
|
code:append("items = ") |
|
ValueToLuaCode(self.items, nil, code) |
|
code:appendf(", from = '%s', ", self.from) |
|
if self.from == "Table field values" then |
|
code:appendf("field = '%s', ", self.field) |
|
end |
|
if self.prop_meta_update then |
|
code:appendf("prop_meta_update = ") |
|
ValueToLuaCode(self.prop_meta_update, nil, code) |
|
code:appendf(", ") |
|
end |
|
end |
|
code:append("\nprop_meta =\n") |
|
self.prop.id = " " |
|
self.prop:GenerateCode(code, translate) |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefScript = { |
|
__parents = { "PropertyDef" }, |
|
properties = { |
|
{ category = "Script", id = "condition", name = "Is condition list", editor = "bool", default = false, }, |
|
{ category = "Script", id = "params_exp", name = "Params is an expression", editor = "bool", default = false, }, |
|
{ category = "Script", id = "params", name = "Params", editor = "text", default = "self", }, |
|
{ category = "Script", id = "script_domain", name = "Script domain", editor = "choice", default = false, items = function() return ScriptDomainsCombo() end }, |
|
}, |
|
default = false, |
|
editor = "script", |
|
EditorName = "Script", |
|
EditorSubmenu = "Code", |
|
} |
|
|
|
function PropertyDefScript:GenerateAdditionalPropCode(code, translate) |
|
if self.condition then |
|
code:append('class = "ScriptConditionList", ') |
|
end |
|
if self.params_exp then |
|
code:appendf('params = function(self) return %s end, ', self.params) |
|
else |
|
code:appendf('params = "%s", ', self.params) |
|
end |
|
if self.script_domain then |
|
code:appendf('script_domain = "%s", ', self.script_domain) |
|
end |
|
end |
|
|
|
|
|
|
|
|
|
DefineClass.WeightedListProps = { |
|
__parents = { "PropertyObject" }, |
|
properties = { |
|
{ category = "Weights", id = "weights", name = "Weights", editor = "bool", default = false, |
|
no_edit = function(obj) return obj:DisableWeights() end, help = "Associates weights to the list items"}, |
|
{ category = "Weights", id = "weight_default", name = "Default Weight", editor = "number", default = 100, |
|
no_edit = function(obj) return not obj.weights end, help = "Default weight for each list item" }, |
|
{ category = "Weights", id = "value_key", name = "Value Key", editor = "text", default = "value", |
|
no_edit = function(obj) return not obj.weights end, help = "Name of the 'value' key in each list item. Can be a number too." }, |
|
{ category = "Weights", id = "weight_key", name = "Weight Key", editor = "text", default = "weight", |
|
no_edit = function(obj) return not obj.weights end, help = "Name of the 'weight' key in each list item. Can be a number too." }, |
|
}, |
|
DisableWeights = empty_func, |
|
} |
|
|
|
function WeightedListProps:GetItemKeys() |
|
local value_key = self.value_key |
|
if value_key == "" then |
|
value_key = "value" |
|
end |
|
value_key = tonumber(value_key) or value_key |
|
|
|
local weight_key = self.weight_key |
|
if weight_key == "" then |
|
weight_key = "weight" |
|
end |
|
weight_key = tonumber(weight_key) or weight_key |
|
|
|
return value_key, weight_key |
|
end |
|
|
|
function WeightedListProps:GenerateWeightPropCode(code) |
|
if not self.weights then |
|
return |
|
end |
|
code:append(", weights = true") |
|
local value_key, weight_key = self:GetItemKeys() |
|
if value_key ~= "value" then |
|
code:append(", value_key = ") |
|
ValueToLuaCode(value_key, nil, code) |
|
end |
|
if weight_key ~= "weight" then |
|
code:append(", weight_key = ") |
|
ValueToLuaCode(weight_key, nil, code) |
|
end |
|
if self.weight_default ~= 100 then |
|
code:append(", weight_default = ") |
|
ValueToLuaCode(self.weight_default, nil, code) |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefPrimitiveList = { |
|
__parents = { "PropertyDef", "WeightedListProps" }, |
|
properties = { |
|
{ category = "List", id = "item_default", name = "Item Default", editor = "text", default = false, }, |
|
{ category = "List", id = "items", name = "Items", editor = "expression", default = false, }, |
|
{ category = "List", id = "max_items", name = "Max number of items", editor = "number", default = -1, }, |
|
}, |
|
editor = "", |
|
EditorName = "", |
|
} |
|
|
|
function PropertyDefPrimitiveList:DisableWeights() |
|
return self.editor ~= "number_list" and self.editor ~= "string_list" |
|
end |
|
|
|
function PropertyDefPrimitiveList:GenerateAdditionalPropCode(code, translate) |
|
code:append("item_default = ") |
|
ValueToLuaCode(self.item_default, nil, code) |
|
code:append(", items = ") |
|
ValueToLuaCode(self.items, nil, code) |
|
if self.arbitrary_value then |
|
code:append(", arbitrary_value = true") |
|
end |
|
if self.max_items >= 0 then |
|
code:append(", max_items = ") |
|
ValueToLuaCode(self.max_items, nil, code) |
|
end |
|
self:GenerateWeightPropCode(code) |
|
code:append(", ") |
|
end |
|
|
|
DefineClass.PropertyDefNumberList = { |
|
__parents = { "PropertyDefPrimitiveList" }, |
|
|
|
properties = { |
|
{ category = "List", id = "default", name = "Default value", editor = "number_list", |
|
default = {}, item_default = function(self) return self.item_default end, items = EmulatePropEval("items", {0}) }, |
|
{ category = "List", id = "item_default", name = "Item Default", editor = "number", default = 0, }, |
|
}, |
|
|
|
editor = "number_list", |
|
EditorName = "Number list property", |
|
EditorSubmenu = "Lists", |
|
} |
|
|
|
DefineClass.PropertyDefStringList = { |
|
__parents = { "PropertyDefPrimitiveList" }, |
|
|
|
properties = { |
|
{ category = "List", id = "default", name = "Default value", editor = "string_list", |
|
default = {}, items = EmulatePropEval("items", {""}), |
|
item_default = function(self) return self.item_default end, |
|
arbitrary_value = function(self) return self.arbitrary_value end, }, |
|
{ category = "List", id = "item_default", name = "Item default", editor = "combo", |
|
default = "", items = EmulatePropEval("items", {""}) }, |
|
{ category = "List", id = "arbitrary_value", name = "Allow arbitrary value", editor = "bool", default = false, }, |
|
}, |
|
|
|
editor = "string_list", |
|
EditorName = "String list property", |
|
EditorSubmenu = "Lists", |
|
} |
|
|
|
DefineClass.PropertyDefTList = { |
|
__parents = { "PropertyDefPrimitiveList" }, |
|
|
|
properties = { |
|
{ category = "List", id = "default", name = "Default value", editor = "T_list", |
|
default = {}, item_default = function(self) return self.item_default end, items = EmulatePropEval("items", {""}) }, |
|
{ category = "List", id = "item_default", name = "Item default", editor = "text", default = "", translate = true}, |
|
{ category = "Text", id = "context", name = "Context", editor = "text", default = "", } |
|
}, |
|
|
|
editor = "T_list", |
|
EditorName = "Translated list property", |
|
EditorSubmenu = "Lists", |
|
} |
|
|
|
function PropertyDefTList:GenerateAdditionalPropCode(code, translate) |
|
PropertyDefPrimitiveList.GenerateAdditionalPropCode(self, code, translate) |
|
if self.context and self.context ~= "" then |
|
code:append("context = " .. self.context .. ", ") |
|
end |
|
end |
|
|
|
DefineClass.PropertyDefHelp = { |
|
__parents = { "PropertyDef" }, |
|
default = false, |
|
editor = "help", |
|
EditorName = "Help text", |
|
EditorSubmenu = "Extras", |
|
} |
|
|
|
|
|
|
|
|
|
local const_items = { |
|
{ text = "Bool", value = "bool" }, |
|
{ text = "Number", value = "number" }, |
|
{ text = "Text", value = "text" }, |
|
{ text = "Translated Text", value = "translate" }, |
|
{ text = "Point", value = "point" }, |
|
{ text = "Box", value = "rect" }, |
|
{ text = "Color", value = "color" }, |
|
{ text = "Range", value = "range" }, |
|
{ text = "Image", value = "browse" }, |
|
{ text = "Table", value = "prop_table" }, |
|
{ text = "String List", value = "string_list" }, |
|
{ text = "Number List", value = "number_list" }, |
|
} |
|
|
|
DefineClass.ClassConstDef = { |
|
__parents = { "ClassDefSubItem" }, |
|
properties = { |
|
{ category = "Const", id = "name", name = "Name", editor = "text", default = "", validate = ValidateIdentifier }, |
|
{ category = "Const", id = "type", name = "Type", editor = "choice", default = "bool", items = const_items, }, |
|
{ category = "Const", id = "value", name = "Value", editor = function(self) return self.type == "translate" and "text" or self.type end, |
|
translate = function(self) return self.type == "translate" end, default = false, |
|
lines = function(self) return self.type == "prop_table" and 3 or self.type == "text" and 1 end, |
|
max_lines = function(self) return self.type == "text" and 256 end, }, |
|
{ category = "Const", id = "untranslated", name = "Untranslated", editor = "bool", |
|
no_edit = function(self) return self.type ~= "translate" and self.type ~= "text" end, default = false, } |
|
}, |
|
EditorName = "Class member", |
|
EditorSubmenu = "Code", |
|
} |
|
|
|
function ClassConstDef:OnEditorSetProperty(prop_id, old_value, ged) |
|
if prop_id == "type" then |
|
local value = self.type |
|
if value == "text" and old_value == "translate" then |
|
self:UpdateLocalizedProperty("value", false) |
|
elseif value == "translate" and old_value == "text" then |
|
self:UpdateLocalizedProperty("value", true) |
|
else |
|
self.value = nil |
|
end |
|
end |
|
end |
|
|
|
function ClassConstDef:GetValue() |
|
if not self.value and (self.type == "text" or self.type == "translate") then |
|
return "" |
|
end |
|
return self.value |
|
end |
|
|
|
function ClassConstDef:GetEditorView() |
|
local result = "<color 45 138 138>Class.</color>" |
|
if self.type == "translate" then |
|
result = result .. string.format(self.untranslated and '%s = Untranslated(%s)' or '%s = T(%s)', self.name, self:ToStringWithColor(TDevModeGetEnglishText(self:GetValue()))) |
|
else |
|
result = result .. string.format("%s = %s", self.name, self:ToStringWithColor(self:GetValue())) |
|
end |
|
return result |
|
end |
|
|
|
function ClassConstDef:GenerateCode(code) |
|
if not self.name:match("^[%w_]+$") then return end |
|
if self.untranslated then |
|
code:append("\t", self.name, " = Untranslated(" ) |
|
if self.type == "text" then |
|
ValueToLuaCode(self:GetValue(), nil, code) |
|
elseif self.type == "translate" then |
|
ValueToLuaCode(TDevModeGetEnglishText(self:GetValue()), nil, code) |
|
end |
|
code:append("),\n") |
|
return |
|
end |
|
code:append("\t", self.name, " = ") |
|
ValueToLuaCode(self:GetValue(), nil, code) |
|
code:append(",\n") |
|
end |
|
|
|
|
|
|
|
|
|
local default_methods = { |
|
"", |
|
"GetEditorView()", |
|
"GetError()", |
|
"GetWarning()", |
|
"OnEditorSetProperty(prop_id, old_value, ged)", |
|
"OnEditorNew(parent, ged, is_paste)", |
|
"OnEditorDelete(parent, ged)", |
|
"OnEditorSelect(selected, ged)", |
|
} |
|
|
|
function ClassMethodDefKnownMethodsCombo(method_def) |
|
local defaults = { delete = true } |
|
for _, method in ipairs(default_methods) do |
|
local name = method:match("(.+)%(") |
|
if name then defaults[name] = true end |
|
end |
|
|
|
local methods = {} |
|
local class_def = GetParentTableOfKind(method_def, "ClassDef") |
|
for _, parent in ipairs(class_def.DefParentClassList) do |
|
local class = g_Classes[parent] |
|
while class and class.class ~= "PropertyObject" and class.class ~= "Preset" do |
|
for k, v in pairs(class) do |
|
if type(v) == "function" then |
|
local name, params, body = GetFuncSource(v) |
|
local sep_idx = name and name:find(":", 1, true) |
|
if sep_idx then |
|
name = name:sub(sep_idx + 1) |
|
if not defaults[name] then |
|
methods[#methods + 1] = string.format("%s(%s)", name, params:trim_spaces()) |
|
end |
|
end |
|
end |
|
end |
|
class = getmetatable(class) |
|
end |
|
end |
|
table.sort(methods) |
|
return #methods == 0 and default_methods or table.iappend(table.iappend(table.copy(default_methods), {"---"}), methods) |
|
end |
|
|
|
DefineClass.ClassMethodDef = { |
|
__parents = { "ClassDefSubItem" }, |
|
properties = { |
|
{ category = "Method", id = "name", name = "Name", editor = "combo", default = "", |
|
items = ClassMethodDefKnownMethodsCombo, |
|
validate = function (self, value) |
|
local sep_idx = type(value) == "string" and value:find("(", 1, true) |
|
local name = sep_idx and value:sub(1, sep_idx - 1) or value |
|
if type(value) ~= "string" or not name:match("^[%w_]*$") then |
|
return "Value must be a valid identifier or a function prototype." |
|
end |
|
end, }, |
|
{ category = "Method", id = "params", name = "Params", editor = "text", default = "", }, |
|
{ category = "Method", id = "comment", name = "Comment", editor = "text", default = "", lines = 1, max_lines = 5, }, |
|
{ category = "Method", id = "code", name = "Code", editor = "func", default = false, lines = 1, max_lines = 100, |
|
params = function (self) return self.params == "" and "self" or "self, " .. self.params end, }, |
|
}, |
|
EditorName = "Method", |
|
EditorSubmenu = "Code", |
|
} |
|
|
|
function ClassMethodDef:GetEditorView() |
|
local ret = string.format("<color 75 105 198>function</color> <color 45 138 138>Class:</color>%s(%s)", self.name, self.params) |
|
if self.comment ~= "" then |
|
ret = string.format("%s <color 0 128 0> -- %s", ret, self.comment) |
|
end |
|
return ret |
|
end |
|
|
|
function ClassMethodDef:GenerateCode(code, class_name) |
|
if not self.name:match("^[%w_]+$") then return end |
|
code:appendf("function %s:%s(%s)\n", class_name, self.name, self.params) |
|
local name, params, body = GetFuncSource(self.code) |
|
if type(body) == "string" then |
|
body = string.split(body, "\n") |
|
end |
|
code:append("\t", body and table.concat(body, "\n\t") or "", "\n") |
|
code:append("end\n\n") |
|
end |
|
|
|
function ClassMethodDef:ContainsCode(snippet) |
|
local name, params, body = GetFuncSource(self.code) |
|
if type(body) == "table" then |
|
body = table.concat(body, "\n") |
|
end |
|
return body and body:find(snippet, 1, true) |
|
end |
|
|
|
function ClassMethodDef:OnEditorSetProperty(prop_id, old_value, ged) |
|
local method = self.name |
|
if prop_id == "name" and method:find("(", 1, true) then |
|
self.name = method:match("(.+)%(") |
|
self.params = method:sub(#self.name + 2, -2) |
|
end |
|
end |
|
|
|
|
|
|
|
|
|
DefineClass.ClassGlobalCodeDef = { |
|
__parents = { "ClassDefSubItem" }, |
|
properties = { |
|
{ id = "comment", name = "Comment", editor = "text", default = "", }, |
|
{ id = "code", name = "Code", editor = "func", default = false, lines = 1, max_lines = 100, params = "", }, |
|
}, |
|
EditorName = "Code", |
|
EditorSubmenu = "Code", |
|
} |
|
|
|
function ClassGlobalCodeDef:GetEditorView() |
|
if self.comment == "" then |
|
return "code" |
|
end |
|
return string.format("code <color 0 128 0>-- %s</color>", self.comment) |
|
end |
|
|
|
function ClassGlobalCodeDef:GenerateCode(code, class_name) |
|
local name, params, body = GetFuncSource(self.code) |
|
if not body then return end |
|
code:append("----- ", class_name, " ", self.comment, "\n\n") |
|
if type(body) == "table" then |
|
for _, line in ipairs(body) do |
|
code:append(line, "\n") |
|
end |
|
else |
|
code:append(body) |
|
end |
|
code:append("\n") |
|
end |
|
|