myspace / CommonLua /GedMultiSelectAdapter.lua
sirnii's picture
Upload 1816 files
b6a38d7 verified
raw
history blame
7.4 kB
__Undefined = rawget( _G, "__Undefined") or {}
setmetatable(__Undefined, {
__toluacode = function(self, indent, pstr)
local code = "__Undefined"
if pstr then
return pstr:append(code)
else
return code
end
end,
__tostring = function(self)
return "__Undefined__"
end
})
function Undefined()
return __Undefined
end
if FirstLoad then
GedMultiSelectAdapters = setmetatable({}, weak_keys_meta)
end
DefineClass.GedMultiSelectAdapter = {
__parents = { "PropertyObject", "InitDone" },
__objects = {}, -- try to prevent name collisions; we store nested objs/lists directly in the object
properties = false,
property_merge_union = "any", -- or "all"
}
local dont_evaluate = { default = true, preset_filter = true, class_filter = true, setter = true, getter = true, dont_save = true }
local special_treat = { max = Min, min = Max }
local eval = prop_eval
local function MergePropMeta(prop_accumulator, prop_meta, object)
if prop_meta.no_edit and eval(prop_meta.no_edit, object, prop_meta) then
return nil
end
if not prop_accumulator then
prop_accumulator = {}
for meta_name, value in pairs(prop_meta) do
prop_accumulator[meta_name] = dont_evaluate[meta_name] and value or eval(value, object, prop_meta)
end
if prop_accumulator.default == nil then
prop_accumulator.default = PropertyObject.GetDefaultPropertyValue(object, prop_meta.id, prop_meta)
end
prop_accumulator.__count = 1
else
for meta_name, value in pairs(prop_meta) do
value = dont_evaluate[meta_name] and value or eval(value, object, prop_meta)
local acc_value = prop_accumulator[meta_name]
local special_treat_fn = special_treat[meta_name]
if special_treat_fn then
prop_accumulator[meta_name] = special_treat_fn(acc_value, value)
elseif not CompareValues(acc_value, value) then
return nil
end
end
prop_accumulator.__count = prop_accumulator.__count + 1
end
return prop_accumulator
end
local function CalculatePropertyMetadata(objects)
local prop_ids = {} -- keep the order of the properties.
local properties_accumulator = {}
local prop_ids_with_mismatches = {}
for _, object in ipairs(objects) do
local properties = object:GetProperties()
for _, prop_meta in ipairs(properties) do
if not prop_ids_with_mismatches[prop_meta.id] then
local acc = properties_accumulator[prop_meta.id]
if not acc then
prop_ids[#prop_ids+1] = prop_meta.id
end
local resulting_acc = MergePropMeta(acc, prop_meta, object)
properties_accumulator[prop_meta.id] = resulting_acc
if resulting_acc == nil then
prop_ids_with_mismatches[prop_meta.id] = true
end
end
end
end
-- convert to standard prop table
return properties_accumulator, prop_ids
end
local function MultiselectAdapterGetProperties(objects, property_merge_union)
local props = {}
local metas, order = CalculatePropertyMetadata(objects)
for _, prop_id in ipairs(order) do
local meta = metas[prop_id]
if meta then
if property_merge_union == "any" or (meta.__count == #objects and property_merge_union == "all") then
table.insert(props, meta)
props[prop_id] = meta
end
end
end
return props
end
function GedMultiSelectAdapter:Init()
local objects = self.__objects
for i = #objects, 1, -1 do
if not GedIsValidObject(objects[i]) then
table.remove(objects, i)
end
end
for _, obj in ipairs(objects) do
Msg("GedBindObj", obj)
end
self:UpdatePropertyMetadatas()
GedMultiSelectAdapters[self] = true
end
function GedMultiSelectAdapter:UpdatePropertyMetadatas()
self.properties = MultiselectAdapterGetProperties(self.__objects, self.property_merge_union)
-- creates copies of any nested_obj/nested_list properties in the object for Ged to edit
for _, prop in ipairs(self.properties) do
local editor, id = prop.editor, prop.id
if editor == "nested_obj" or editor == "nested_list" then
local value = self:GetProperty(id)
if value ~= Undefined() and rawget(self, id) == nil then
rawset(self, id, self:CopyNestedObjOrList(value))
end
end
end
end
function GedMultiSelectAdapter:CopyNestedObjOrList(value)
local ret = false
if value then
if IsKindOf(value, "PropertyObject") then
ret = value:Clone()
else
ret = {}
for i, item in ipairs(value) do
ret[i] = item:Clone()
end
end
end
return ret
end
function GedMultiSelectAdapter:CopyNestedPropValueToObjects(id)
for _, obj in ipairs(self.__objects) do
obj:SetProperty(id, self:CopyNestedObjOrList(self[id]))
end
end
function GedMultiSelectAdapter:OnEditorSetProperty(prop_id, old_value, ged)
local prop_meta = self:GetPropertyMetadata(prop_id)
if prop_meta.editor == "nested_obj" or prop_meta.editor == "nested_list" then
self:CopyNestedPropValueToObjects(prop_id)
end
end
function GedMultiSelectAdapter:ClearNestedProperty(prop_id)
local prop_meta = self:GetPropertyMetadata(prop_id)
if prop_meta.editor == "nested_obj" or prop_meta.editor == "nested_list" then
self[prop_id] = nil
end
end
function GedMultiSelectAdapterObjModified(obj)
if IsKindOf(obj, "GedMultiSelectAdapter") then
obj:UpdatePropertyMetadatas()
return
end
for adapter in pairs(GedMultiSelectAdapters) do
for id, value in pairs(adapter) do
if (rawequal(obj, value) or type(value) == "table" and table.find(value, obj)) and table.find(adapter.properties, "id", id) then
adapter:CopyNestedPropValueToObjects(id)
end
end
end
end
OnMsg.GedObjectModified = GedMultiSelectAdapterObjModified
function GedMultiSelectAdapter:GetProperty(prop_id)
local value = rawget(self, prop_id)
if value ~= nil then
return value
end
for _, obj in ipairs(self.__objects) do
if GedIsValidObject(obj) then
local new_val = GetProperty(obj, prop_id)
if new_val ~= nil then
if value ~= nil and not CompareValues(new_val, value) then
return Undefined()
end
value = new_val
end
end
end
return value
end
function GedMultiSelectAdapter:GetDefaultPropertyValue(prop_id, prop_meta)
if prop_meta then
local value = rawget(prop_meta, "default")
if value ~= nil then
return value
end
end
return self.properties[prop_id].default
end
function GedMultiSelectAdapter:ExecPropButton(root, prop_id, ged, func, param)
SuspendObjModified("GedMultiSelectAdapter:ExecPropButton")
local errs, undos = {}, {}
for _, obj in ipairs(self.__objects) do
if GedIsValidObject(obj) then
local err, undo
local prop_capture = GedPropCapture(obj)
if type(func) == "function" then
err, undo = func(obj, root, prop_id, ged, param)
elseif obj:HasMember(func) then
err, undo = obj[func](obj, root, prop_id, ged, param)
elseif type(rawget(_G, func)) == "function" then
err, undo = _G[func](root, obj, prop_id, ged, param)
end
local undop = GedCreatePropValuesUndoFn(obj, prop_capture)
if type(err) == "string" then errs [#errs + 1] = err end
if type(undo) == "function" then undos[#undos + 1] = undo end
if type(undop) == "function" then undos[#undos + 1] = undop end
end
end
ResumeObjModified("GedMultiSelectAdapter:ExecPropButton")
return
next(errs) and table.concat(errs, "\n"),
#undos > 0 and function() for i = 1, #undos do undos[i]() end end or nil
end
function GedMultiSelectAdapter:OnEditorSelect(...)
for _, obj in ipairs(self.__objects) do
if GedIsValidObject(obj) and PropObjHasMember(obj, "OnEditorSelect") then
obj:OnEditorSelect(...)
end
end
end