2340 lines
86 KiB
Lua
2340 lines
86 KiB
Lua
|
--------------------------------------------------------------------------------------------
|
||
|
-- PROPERTY SHEETS & FORMS
|
||
|
-- ======================
|
||
|
-- This file contains code to generate xml of generic property sheets & forms that are used to change
|
||
|
-- properties of editor objects / tables
|
||
|
-- NB : Currenlty there can be only a single property sheet displayed at a time
|
||
|
|
||
|
|
||
|
-- To speed up reset of editor, we keep a cache to avoid to rebuild ui for class
|
||
|
-- whose properties have not changed
|
||
|
-- this cache is kept between 2 reset of the editor
|
||
|
-- the cache is a simple table : key = class name & value = property of the class
|
||
|
-- NB : we don't use the r2 table because it is reseted each time !!
|
||
|
if r2ClassDescCache == nil then
|
||
|
-- first build of the table
|
||
|
r2ClassDescCache = {}
|
||
|
debugInfo(colorTag(255, 0, 255) .. "Init of property sheet cache")
|
||
|
end
|
||
|
-- same thing for forms
|
||
|
if r2FormsCache == nil then
|
||
|
-- first build of the table
|
||
|
r2FormsCache = {}
|
||
|
debugInfo(colorTag(255, 0, 255) .. "Init of forms cache")
|
||
|
end
|
||
|
|
||
|
function resetR2UICache()
|
||
|
r2FormsCache = nil
|
||
|
r2ClassDescCache = nil
|
||
|
end
|
||
|
|
||
|
|
||
|
r2.DefaultPropertySheetTitleClampSize = -28
|
||
|
|
||
|
local eventArgs = {} -- static table here to avoid costly allocs with the ellipsis ...
|
||
|
local emptyArgs = {}
|
||
|
-- build an edit box for an arbitrary type
|
||
|
function r2:buildEditBox(prop, textRef, entryType, multiLine, maxNumChars, onChangeAction, onFocusLostAction)
|
||
|
local result =
|
||
|
[[<instance template="edit_box_widget" text_y="-1" posref="ML ML" sizeref="w" w="-8" fontsize="14" x="4" reset_focus_on_hide="true"
|
||
|
child_resize_hmargin="4"
|
||
|
max_historic="0"
|
||
|
y="-2"
|
||
|
negative_filter = '"{}[]'
|
||
|
prompt="" enter_loose_focus="true"
|
||
|
color="255 255 255 255"
|
||
|
continuous_text_update="true"
|
||
|
bg_texture="grey_40.tga"
|
||
|
onchange="lua" onchange_params="getUICaller():setupDisplayText(); getUICaller():find('edit_text'):updateCoords(); getUICaller():getEnclosingContainer().Env.updateSize()"
|
||
|
onenter="lua" on_focus_lost="lua"]] ..
|
||
|
[[ id= ]] .. strify(prop.Name) ..
|
||
|
[[ text_ref = ]] .. strify(textRef) ..
|
||
|
[[ entry_type = ]] .. strify(entryType) ..
|
||
|
[[ multi_line = ]] .. strify(multiLine) ..
|
||
|
[[ max_num_chars = ]] .. strify(maxNumChars) ..
|
||
|
[[ params = ]] .. strify(onChangeAction) ..
|
||
|
[[ on_focus_lost_params = ]] .. strify(onFocusLostAction) ..
|
||
|
"/>"
|
||
|
return result
|
||
|
end
|
||
|
|
||
|
|
||
|
-- build an edit box for an arbitrary type
|
||
|
--function r2:buildComboEditBox(prop, textRef, entryType, multiLine, maxNumChars, onChangeAction)
|
||
|
-- return
|
||
|
-- [[
|
||
|
-- <instance template="edit_box_widget" text_y="-1" posref="ML ML" sizeref="w" w="-32" fontsize="14" x="4" reset_focus_on_hide="true"
|
||
|
-- child_resize_hmargin="4"
|
||
|
-- max_historic="0"
|
||
|
-- y="-2"
|
||
|
-- prompt="" enter_loose_focus="true"
|
||
|
-- color="255 255 255 255"
|
||
|
-- continuous_text_update="true"
|
||
|
-- bg_texture="grey_40.tga"
|
||
|
-- onchange="lua" onchange_params="getUICaller():setupDisplayText(); getUICaller():find('edit_text'):updateCoords(); getUICaller():getEnclosingContainer().Env.updateSize()"
|
||
|
-- onenter="lua" on_focus_lost="lua"]] ..
|
||
|
-- [[ id= ]] .. strify(prop.Name) ..
|
||
|
-- [[ text_ref = ]] .. strify(textRef) ..
|
||
|
-- [[ entry_type = ]] .. strify(entryType) ..
|
||
|
-- [[ multi_line = ]] .. strify(multiLine) ..
|
||
|
-- [[ max_num_chars = ]] .. strify(maxNumChars) ..
|
||
|
-- [[ params = ]] .. strify(onChangeAction) ..
|
||
|
-- [[ on_focus_lost_params = ]] .. strify(onChangeAction) ..
|
||
|
-- [[ />
|
||
|
--
|
||
|
--
|
||
|
--
|
||
|
-- ]]
|
||
|
--
|
||
|
--end
|
||
|
|
||
|
|
||
|
-- widget styles, key is the type, value is a table containing the widget factory (each wdget being identified by its 'WidgetStyle')
|
||
|
r2.WidgetStyles =
|
||
|
{
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
--//////////////////////
|
||
|
--// STRINGS WIDGETS //
|
||
|
--//////////////////////
|
||
|
|
||
|
-- Build widget factory for 'Strings'
|
||
|
--
|
||
|
-- Each key gives the name of the widget style. Each value is a function that returns the xml code for the widget
|
||
|
-- that must edit the 'prop' value.
|
||
|
-- Moreover, a "setter" function" must be returned, that will update the content of the widget from external modification
|
||
|
--
|
||
|
-- The widget may also return a table in place of the setter function, if it is of type 'refid', and wants to handle modification of its target
|
||
|
-- In this case, the table must have the following format :
|
||
|
-- local refIdTable = {}
|
||
|
-- -- Each function below takes 3 parameters :
|
||
|
-- -- widget : pointer to the ui widget
|
||
|
-- -- value : current value of the property that is displayed by the widget
|
||
|
-- -- prop : definition of the property displayed by this widget (taken from the definition of the class that contain that property)
|
||
|
--
|
||
|
-- function refIdTable:onSet(widget, value, prop) .. end -- handles modification of the reference
|
||
|
-- function refIdTable:onTargetCreated(widget, value, prop) .. end -- handles creation of the targetted object
|
||
|
-- function refIdTable:onTargetErased(widget, value, prop) .. end -- handles deletion of the targetted object
|
||
|
-- function refIdTable:onTargetPreHrcMove(widget, value, prop) .. end -- targeted object is about to move in the object hierarchy
|
||
|
-- function refIdTable:onTargetPostHrcMove(widget, value, prop) .. end -- targeted object has moved in the object hierarchy
|
||
|
-- function refIdTable:onTargetAttrModified(widget, value, prop, targetAttr, targetIndexinArray) .. end -- handles modifications of the deleted object
|
||
|
--
|
||
|
|
||
|
function r2.returnOk(param)
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
function r2.refuseEmptyString(param)
|
||
|
assert(param)
|
||
|
assert(type(param) == "string")
|
||
|
if string.len(param) == 0 then
|
||
|
local ucStringMsg = i18n.get("uiR2EdNoEmptyString")
|
||
|
displaySystemInfo(ucStringMsg, "BC")
|
||
|
return false
|
||
|
end
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
r2.WidgetStyles.String =
|
||
|
{
|
||
|
-- default string edition, using an edit box
|
||
|
Default = function(prop, className)
|
||
|
|
||
|
local function setter(widget, prop, value)
|
||
|
local ok = true
|
||
|
if prop.ValidationFun then
|
||
|
ok = r2.assert(loadstring('return '.. prop.ValidationFun))()(value)
|
||
|
end
|
||
|
if ok then
|
||
|
local ucValue = ucstring()
|
||
|
--debugInfo("value = " .. tostring(value))
|
||
|
ucValue:fromUtf8(value)
|
||
|
widget.eb.uc_input_string = ucValue
|
||
|
widget.eb.Env.CurrString = ucValue
|
||
|
--debugInfo("setting" .. widget.eb.id .. " to " .. tostring(value))
|
||
|
else
|
||
|
widget.eb.uc_input_string = widget.eb.Env.CurrString
|
||
|
widget.eb.input_string = widget.eb.uc_input_string:toUtf8()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local validation = ""
|
||
|
|
||
|
if prop.ValidationFun then
|
||
|
validation = string.format([[ if not %s(utf8Value) then editBox.uc_input_string = editBox.Env.CurrString; return end]], prop.ValidationFun)
|
||
|
end
|
||
|
|
||
|
local onChangeAction =
|
||
|
string.format(
|
||
|
[[
|
||
|
local editBox = getUICaller()
|
||
|
if editBox.input_string == editBox.Env.CurrString then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
local utf8Value = editBox.uc_input_string:toUtf8()
|
||
|
%s
|
||
|
editBox.Env.CurrString = editBox.input_string
|
||
|
r2:requestSetObjectProperty('%s', utf8Value)
|
||
|
]], validation, prop.Name)
|
||
|
|
||
|
local onFocusLostAction = onChangeAction
|
||
|
if prop.ValidateOnEnter then
|
||
|
onChangeAction = onChangeAction .. "r2:validateForm(r2.CurrentForm)"
|
||
|
end
|
||
|
return r2:buildEditBox(prop, "TL TL", defaulting(prop.EntryType, "text"), true, defaulting(prop.MaxNumChar, 256), onChangeAction, onFocusLostAction),
|
||
|
setter,
|
||
|
nil
|
||
|
end,
|
||
|
-- string property displayed as a static text (not editable)
|
||
|
StaticText = function(prop, className)
|
||
|
--debugInfo("Building static text")
|
||
|
local function setter(widget, prop, value)
|
||
|
--debugInfo("value = " .. tostring(value))
|
||
|
local ucValue = ucstring()
|
||
|
ucValue:fromUtf8(value)
|
||
|
widget.uc_hardtext = ucValue
|
||
|
end
|
||
|
local widgetXml =
|
||
|
string.format([[ <view type="text" id="%s" color="192 192 192 255" posparent="parent" active="true" posref="ML ML" x="4" y="-2" global_color="true" fontsize="12" shadow="true" hardtext="toto" auto_clamp="true"/> ]], prop.Name)
|
||
|
return widgetXml, setter, nil
|
||
|
end,
|
||
|
|
||
|
StaticTextMultiline = function(prop, className)
|
||
|
--debugInfo("Building static text")
|
||
|
local function setter(widget, prop, value)
|
||
|
--debugInfo("value = " .. tostring(value))
|
||
|
local ucValue = ucstring()
|
||
|
ucValue:fromUtf8(value)
|
||
|
widget.uc_hardtext = ucValue
|
||
|
end
|
||
|
local widgetXml =
|
||
|
string.format([[ <view type="text" id="%s" color="192 192 192 255" posparent="parent" active="true" posref="ML ML" x="4" y="-2" global_color="true" fontsize="12" shadow="true" hardtext="toto" multi_line="true" auto_clamp="true"/> ]], prop.Name)
|
||
|
return widgetXml, setter, nil
|
||
|
end
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- helper : build the name of a property tooltip : looks in the bas class until a translation is found
|
||
|
local function buildPropTooltipName(className, propName)
|
||
|
assert(className)
|
||
|
assert(propName)
|
||
|
local tt = "uiR2EdPropertyToolTip_" .. className .. "_" .. propName
|
||
|
if i18n.hasTranslation(tt) then
|
||
|
--debugInfo("### Translation found for " .. propName .. " in " .. className)
|
||
|
return tt, true
|
||
|
end
|
||
|
|
||
|
-- this Form is not a Class (its a form not a property sheet) so don't search into its parents
|
||
|
if r2.Classes[className] == nil then
|
||
|
return tt, false
|
||
|
end
|
||
|
|
||
|
local parentClassName = r2.Classes[className].BaseClass
|
||
|
if parentClassName ~= "" and parentClassName~=nil then
|
||
|
local parentClass = r2.Classes[parentClassName]
|
||
|
if parentClass.NameToProp[propName] ~= nil then
|
||
|
--debugInfo("### Translation not found for " .. propName .. " in " .. className .. ".Looking in parent class " .. parentClassName)
|
||
|
local translation, found = buildPropTooltipName(parentClassName, propName)
|
||
|
if found then return translation, true end
|
||
|
end
|
||
|
end
|
||
|
return tt, false -- not found, a 'NotExist' string will be displayed
|
||
|
end
|
||
|
|
||
|
--/////////////////////
|
||
|
--// REF ID WIDGETS //
|
||
|
--/////////////////////
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
--///////////////////////////
|
||
|
--// DEFAULT REF ID PICKER //
|
||
|
--///////////////////////////
|
||
|
|
||
|
-- handle updates of the "RefId" widget
|
||
|
-- this table is common to all the ref id widgets
|
||
|
local refIdDefaultEventHandler ={}
|
||
|
--
|
||
|
function refIdDefaultEventHandler:onSet(widget, prop, value)
|
||
|
--debugInfo("set received")
|
||
|
self:update(widget, value, r2:getInstanceFromId(value))
|
||
|
end
|
||
|
--
|
||
|
function refIdDefaultEventHandler:onTargetCreated(widget, prop, value)
|
||
|
self:update(widget, value, r2:getInstanceFromId(value))
|
||
|
end
|
||
|
--
|
||
|
function refIdDefaultEventHandler:onTargetErased(widget, prop, value)
|
||
|
self:update(widget, value, nil)
|
||
|
end
|
||
|
--
|
||
|
function refIdDefaultEventHandler:onTargetAttrModified(widget, prop, value, targetAttr, targetIndexInArray)
|
||
|
-- we are only interested by a change of the instance name
|
||
|
if targetAttr == "Name" then
|
||
|
self:update(widget, value, r2:getInstanceFromId(value))
|
||
|
end
|
||
|
end
|
||
|
--
|
||
|
function refIdDefaultEventHandler:update(widget, value, target)
|
||
|
local text = widget:find("name")
|
||
|
if target then
|
||
|
local newName = ucstring()
|
||
|
newName:fromUtf8(target.Name)
|
||
|
text.uc_hardtext = newName
|
||
|
else
|
||
|
text.uc_hardtext = i18n.get("uiR2EDNone")
|
||
|
end
|
||
|
end
|
||
|
--
|
||
|
function refIdDefaultEventHandler:onTargetPreHrcMove(widget, prop, value)
|
||
|
--debugInfo(string.format("displayer : pre hrc move : (%s)", prop.Name))
|
||
|
end
|
||
|
--
|
||
|
function refIdDefaultEventHandler:onTargetPostHrcMove(widget, prop, value)
|
||
|
--debugInfo(string.format("displayer : post hrc move : (%s)", prop.Name))
|
||
|
end
|
||
|
|
||
|
|
||
|
-- globals for the 'RefId' default widget
|
||
|
r2.currentRefIdWidgetParentInstance = nil
|
||
|
r2.currentRefIdWidgetFilter = nil
|
||
|
r2.currentRefIdWidgetAttrName = nil
|
||
|
r2.currentRefIdIndexInArray = nil
|
||
|
--
|
||
|
function r2:testCanPickRefIdWidgetTarget(instanceId)
|
||
|
if instanceId == r2.currentRefIdWidgetParentInstance.InstanceId then return false end
|
||
|
return r2:getInstanceFromId(instanceId):isKindOf(r2.currentRefIdWidgetFilter)
|
||
|
end
|
||
|
--
|
||
|
function r2:setRefIdWidgetTarget(instanceId)
|
||
|
--r2.requestSetNode(r2.currentRefIdWidgetParentInstance.InstanceId, r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
--debugInfo("requestSetNode")
|
||
|
end
|
||
|
|
||
|
function r2:canPickTaskComponent(instanceId)
|
||
|
local taskClasses = {}
|
||
|
table.insert(taskClasses, "GiveItem")
|
||
|
table.insert(taskClasses, "RequestItem")
|
||
|
table.insert(taskClasses, "TalkTo")
|
||
|
table.insert(taskClasses, "VisitZone")
|
||
|
table.insert(taskClasses, "TargetMob")
|
||
|
table.insert(taskClasses, "KillNpc")
|
||
|
table.insert(taskClasses, "HuntTask")
|
||
|
table.insert(taskClasses, "DeliveryTask")
|
||
|
table.insert(taskClasses, "GetItemFromSceneryObjectTaskStep")
|
||
|
table.insert(taskClasses, "SceneryObjectInteractionTaskStep")
|
||
|
|
||
|
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
--check act?
|
||
|
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
assert(tmpInstance)
|
||
|
local class = tmpInstance.Class
|
||
|
local k, v = next(taskClasses, nil)
|
||
|
while k do
|
||
|
if class == v then
|
||
|
return true
|
||
|
end
|
||
|
k, v = next(taskClasses, k)
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
function r2:setTaskComponentTarget(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
if r2:canPickTaskComponent(instanceId) then
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
function r2:canPickSceneryObject(instanceId)
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
if r2.Translator.checkActForPicking(comp.InstanceId, instanceId) == false then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
|
||
|
if tmpInstance:isBotObject() then
|
||
|
return true
|
||
|
else
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
function r2:setSceneryObjectTarget(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
if r2:canPickSceneryObject(instanceId) then
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:canPickCivilian(instanceId)
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
if r2.Translator.checkActForPicking(comp.InstanceId, instanceId) == false then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
|
||
|
--if not (tmpInstance.Class == "NpcCustom" or tmpInstance.Class == "Npc") or tmpInstance:isBotObject()
|
||
|
--or tmpInstance:isGrouped() then
|
||
|
-- return false
|
||
|
if tmpInstance:isGrouped() or string.find(tmpInstance.Base, "civil") == nil then
|
||
|
return false
|
||
|
else
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
function r2:setCivilian(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
if r2:canPickCivilian(instanceId) then
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
function r2:canPickTalkingNpc(instanceId)
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
if r2.Translator.checkActForPicking(comp.InstanceId, instanceId) == false then
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
|
||
|
if not (tmpInstance.Class == "NpcCustom" or tmpInstance.Class == "Npc") or tmpInstance:isBotObject()
|
||
|
or tmpInstance:isGrouped() then
|
||
|
return false
|
||
|
else
|
||
|
return true
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
function r2:setTalkingNpc(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
if r2:canPickTalkingNpc(instanceId) then
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
function r2:canPickNpcOrGroup(instanceId)
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then return true end
|
||
|
local componentId = comp.InstanceId
|
||
|
--if r2.Translator.checkActForPicking(componentId, instanceId) == false then
|
||
|
-- return false
|
||
|
--end
|
||
|
if instanceId == r2.currentRefIdWidgetParentInstance.InstanceId then return false
|
||
|
else
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
|
||
|
if tmpInstance and not tmpInstance:isBotObject() then
|
||
|
if tmpInstance:isKindOf("Npc")
|
||
|
or tmpInstance.ParentInstance:isKindOf("NpcGrpFeature")
|
||
|
or tmpInstance:isKindOf("NpcGrpFeature") then
|
||
|
return true
|
||
|
else return false end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
function r2:setNpcOrGroupRefIdTarget(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
-- if the instance is a npc belonging to a npcgrp
|
||
|
if not tmpInstance:isBotObject() and tmpInstance:isKindOf("Npc") and tmpInstance.ParentInstance:isKindOf("NpcGrpFeature") then
|
||
|
--debugInfo("inserted: " ..tmpInstance.ParentInstance.Name)
|
||
|
--r2.requestSetNode(r2.currentRefIdWidgetParentInstance.InstanceId, r2.currentRefIdWidgetAttrName, tmpInstance.ParentInstance.InstanceId)
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, tmpInstance.ParentInstance.InstanceId)
|
||
|
-- else if the instance is npc or a npcgrp
|
||
|
elseif not tmpInstance:isBotObject() and tmpInstance:isKindOf("NpcGrpFeature") or tmpInstance:isKindOf("Npc") then
|
||
|
--r2.requestSetNode(r2.currentRefIdWidgetParentInstance.InstanceId, r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:canPickEasterEgg(instanceId)
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then return true end
|
||
|
local componentId = comp.InstanceId
|
||
|
if r2.Translator.checkActForPicking(componentId, instanceId) == false then
|
||
|
return false
|
||
|
end
|
||
|
if instanceId == r2.currentRefIdWidgetParentInstance.InstanceId then return false
|
||
|
else
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
|
||
|
if tmpInstance then
|
||
|
if tmpInstance:isKindOf("EasterEgg") then return true
|
||
|
else return false end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:setEasterEggRefIdTarget(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
-- if the instance is a npc belonging to a npcgrp
|
||
|
if tmpInstance:isKindOf("EasterEgg") then
|
||
|
--r2.requestSetNode(r2.currentRefIdWidgetParentInstance.InstanceId, r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:canPickNotGroupedNpc(instanceId)
|
||
|
--if instanceId == r2.currentRefIdWidgetParentInstance.InstanceId then return false
|
||
|
--else
|
||
|
if r2:getSelectedInstance() and instanceId ~= "" then
|
||
|
local componentId = r2:getSelectedInstance().InstanceId
|
||
|
if r2.Translator.checkActForPicking(componentId, instanceId) == false then
|
||
|
return false
|
||
|
end
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
|
||
|
if tmpInstance then
|
||
|
if not tmpInstance:isBotObject() and tmpInstance:isKindOf("Npc") and not tmpInstance.ParentInstance:isKindOf("NpcGrpFeature") then return true
|
||
|
else return false end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
return true
|
||
|
--end
|
||
|
end
|
||
|
|
||
|
function r2:setNotGroupedNpcRefIdTarget(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
if not tmpInstance:isBotObject() and tmpInstance:isKindOf("Npc") and not tmpInstance.ParentInstance:isKindOf("NpcGrpFeature") then
|
||
|
--r2.requestSetNode(r2.currentRefIdWidgetParentInstance.InstanceId, r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:canPickZone(instanceId)
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then return true end
|
||
|
local componentId = comp.InstanceId
|
||
|
if r2.Translator.checkActForPicking(componentId, instanceId) == false then
|
||
|
return false
|
||
|
end
|
||
|
if instanceId == r2.currentRefIdWidgetParentInstance.InstanceId then return false
|
||
|
else
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
if tmpInstance:isKindOf("Region") then return true
|
||
|
else return false end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:setZoneRefIdTarget(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance and tmpInstance:isKindOf("Region") then
|
||
|
--r2.requestSetNode(r2.currentRefIdWidgetParentInstance.InstanceId, r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:canPickDialog(instanceId)
|
||
|
local comp = r2:getSelectedInstance()
|
||
|
if not comp or instanceId == "" then return true end
|
||
|
local componentId = comp.InstanceId
|
||
|
if r2.Translator.checkActForPicking(componentId, instanceId) == false then
|
||
|
return false
|
||
|
end
|
||
|
if instanceId == r2.currentRefIdWidgetParentInstance.InstanceId then return false
|
||
|
else
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
|
||
|
if tmpInstance then
|
||
|
if tmpInstance:isKindOf("ChatSequence") then return true
|
||
|
else return false end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
end
|
||
|
|
||
|
function r2:setDialogRefIdTarget(instanceId)
|
||
|
local tmpInstance = r2:getInstanceFromId(instanceId)
|
||
|
if tmpInstance then
|
||
|
-- if the instance is a npc belonging to a npcgrp
|
||
|
if tmpInstance:isKindOf("ChatSequence") then
|
||
|
--r2.requestSetNode(r2.currentRefIdWidgetParentInstance.InstanceId, r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
r2.currentRefIdWidgetParentInstance:setRefIdValue(r2.currentRefIdWidgetAttrName, instanceId)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
--///////////////////////
|
||
|
--// PLOT ITEMS PICKER //
|
||
|
--///////////////////////
|
||
|
|
||
|
-- handle updates of the "RefId" widget for plot items
|
||
|
local maxNumPlotItems = tonumber(getDefine("r2ed_max_num_plot_items"))
|
||
|
|
||
|
local refIdPlotItemEventHandler = clone(refIdDefaultEventHandler)
|
||
|
--
|
||
|
|
||
|
function refIdPlotItemEventHandler:updateSheet(widget, targetPlotItem)
|
||
|
for k = 0, maxNumPlotItems - 1 do
|
||
|
local dbPath = "LOCAL:R2:PLOT_ITEMS:" .. tostring(k)
|
||
|
if getDbProp(dbPath .. ":SHEET") == targetPlotItem.SheetId then
|
||
|
widget.sheet.sheet = dbPath
|
||
|
r2.ScratchUCStr:fromUtf8(targetPlotItem.Name)
|
||
|
widget.t.uc_hardtext = r2.ScratchUCStr
|
||
|
return true
|
||
|
end
|
||
|
end
|
||
|
return false
|
||
|
end
|
||
|
|
||
|
function refIdPlotItemEventHandler:update(widget, value, target)
|
||
|
local targetPlotItem = r2:getInstanceFromId(value)
|
||
|
widget:find("edit_plot_item").frozen = (targetPlotItem == nil)
|
||
|
-- target object must already have created its display in the database -> point the same object
|
||
|
if targetPlotItem then
|
||
|
if self:updateSheet(widget, targetPlotItem) then return end
|
||
|
-- update may fail because update of the db for the plot items is done in the main loop
|
||
|
-- and may not has been done yet, so force a refresh and retry
|
||
|
r2.PlotItemDisplayerCommon:updateAll()
|
||
|
if self:updateSheet(widget, targetPlotItem) then return end
|
||
|
end
|
||
|
|
||
|
widget.sheet.sheet = ""
|
||
|
widget.t.uc_hardtext = i18n.get("uiR2EDChooseItem")
|
||
|
end
|
||
|
|
||
|
-- ui handling for selection of plot items from the scenario
|
||
|
r2.PlotItemsWidget =
|
||
|
{
|
||
|
SelectionId = "",
|
||
|
DestProp = "" -- the dest property to which new item selection must bedone
|
||
|
}
|
||
|
|
||
|
-- called when user click on the item sheet -> allows to choose a newplot item
|
||
|
function r2.PlotItemsWidget:changeItem(propName)
|
||
|
if r2.Scenario.PlotItems.Size == 0 then
|
||
|
enableModalWindow(getUICaller(), "ui:interface:r2ed_dm_gift_no_plot_items")
|
||
|
return
|
||
|
end
|
||
|
enableModalWindow(getUICaller(), "ui:interface:r2ed_choose_property_sheet_plot_item")
|
||
|
self.SelectionId = r2:getSelectedInstance().InstanceId
|
||
|
self.DestProp = propName
|
||
|
end
|
||
|
|
||
|
-- called when user has chosen a new sheet to affect
|
||
|
function r2.PlotItemsWidget:validateItem(sheet)
|
||
|
local target = r2:getInstanceFromId(self.SelectionId)
|
||
|
if not target then
|
||
|
return -- maybe the target has been deleted by someone else between the first click and the choice ?
|
||
|
end
|
||
|
if sheet == "UI:EMPTY" or sheet == "UI:DUMMY" then
|
||
|
-- empty choice ...
|
||
|
r2.requestSetNode(self.SelectionId, self.DestProp, "")
|
||
|
else
|
||
|
local sheetId = getDbProp(sheet .. ":SHEET")
|
||
|
-- search plot item with the same sheet
|
||
|
for k, v in specPairs(r2.Scenario.PlotItems) do
|
||
|
if v.SheetId == sheetId then
|
||
|
r2.requestNewAction(i18n.get("uiR2EDChangePlotItem"))
|
||
|
r2.requestSetNode(self.SelectionId, self.DestProp, v.InstanceId) -- makeref to the new item
|
||
|
return
|
||
|
end
|
||
|
end
|
||
|
debugInfo("Plot item not found from its sheet")
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- called when the user hit the 'new' button -> pop a dialog to create a new plot item
|
||
|
function r2.PlotItemsWidget:newPlotItem(propName)
|
||
|
r2.PlotItemsPanel:createNewItemAnAffectToRefId(r2:getSelectedInstance().InstanceId, propName)
|
||
|
end
|
||
|
|
||
|
-- called when the user hit the 'edit' button -> pop a dialog to change the name of the edited plot item
|
||
|
function r2.PlotItemsWidget:editPlotItem(propName)
|
||
|
r2.PlotItemDisplayerCommon:editPlotItemName(r2:getInstanceFromId(r2:getSelectedInstance()[propName]))
|
||
|
end
|
||
|
|
||
|
|
||
|
-- build widget factory for 'RefId'
|
||
|
r2.WidgetStyles.RefId =
|
||
|
{
|
||
|
Default = function(prop, className)
|
||
|
local testFunction = ""
|
||
|
local pickFunction = ""
|
||
|
if not prop.PickFunction or prop.PickFunction == "" then
|
||
|
testFunction = "r2:testCanPickRefIdWidgetTarget"
|
||
|
else
|
||
|
testFunction = prop.PickFunction
|
||
|
end
|
||
|
|
||
|
if not prop.SetRefIdFunction or prop.SetRefIdFunction == "" then
|
||
|
pickFunction = "r2:setRefIdWidgetTarget"
|
||
|
else
|
||
|
pickFunction = prop.SetRefIdFunction
|
||
|
end
|
||
|
|
||
|
--- TestFunction
|
||
|
|
||
|
local widgetXml =
|
||
|
string.format(
|
||
|
[[
|
||
|
<group id="%s" child_resize_w="true" child_resize_h="true">
|
||
|
<ctrl style="text_button_16" id="pick" posref="TL TL" color="255 255 255 255" col_over="255 255 255 255" col_pushed="255 255 255 255"
|
||
|
onclick_l="lua"
|
||
|
params_l="r2.currentRefIdWidgetParentInstance = r2:getPropertySheetTarget()
|
||
|
r2.currentRefIdWidgetAttrName = '%s'
|
||
|
r2.currentRefIdIndexInArray = -1
|
||
|
r2.currentRefIdWidgetFilter = '%s'
|
||
|
runAH(nil, 'r2ed_picker_lua', 'TestFunc=%s|PickFunc=%s')"
|
||
|
hardtext="uiR2EDPick"/>
|
||
|
<ctrl style="text_button_16" id="clear" posref="TR TL" posparent="pick" color="255 255 255 255" col_over="255 255 255 255" col_pushed="255 255 255 255"
|
||
|
onclick_l="lua"
|
||
|
params_l="r2.requestSetNode(r2:getPropertySheetTarget().InstanceId, '%s', '')"
|
||
|
hardtext="uiR2EDClear"/>
|
||
|
<view type="text" id="name" y="-2" color="192 192 192 255" posparent="clear" posref="MR ML" x="4" global_color="true" fontsize="12" shadow="true" hardtext="uiR2EDNone" auto_clamp="false"/>
|
||
|
</group>
|
||
|
]], prop.Name, prop.Name, select(prop.Filter, prop.Filter, "BaseClass"), testFunction, pickFunction, prop.Name
|
||
|
)
|
||
|
return widgetXml, refIdDefaultEventHandler, nil
|
||
|
end,
|
||
|
PlotItem = function(prop, className)
|
||
|
widgetXml =
|
||
|
string.format(
|
||
|
[[
|
||
|
<instance template="r2ed_property_sheet_plot_item" id="%s" value=""/>
|
||
|
]], prop.Name)
|
||
|
return widgetXml, refIdPlotItemEventHandler, nil
|
||
|
end,
|
||
|
}
|
||
|
|
||
|
|
||
|
-------------------------------------------------------------------------------------
|
||
|
-- Signal that a property of object being currently edited (in a property sheet or a form)
|
||
|
-- has been changed. This will update the object property with value 'value'. The appropriate net msg will be sent.
|
||
|
-- This function should be called by edition widgets.
|
||
|
function r2:requestSetObjectProperty(propName, value, isLocal)
|
||
|
if getUICaller() == nil then
|
||
|
debugInfo("<r2:requestSetObjectProperty> should be called by a widget")
|
||
|
return
|
||
|
end
|
||
|
local container = getUICaller().parent:getEnclosingContainer()
|
||
|
-- TODO nico : do distinction between forms and property sheet in a better way (with polymorphism)
|
||
|
if container.Env.Form ~= nil then
|
||
|
-- this is a form (update is done in local)
|
||
|
local form = container.Env.Form
|
||
|
local prop = form.NameToProp[propName]
|
||
|
if prop.convertFromWidgetValue ~= nil then
|
||
|
-- if there's a conversion function then use it
|
||
|
value = prop.convertFromWidgetValue(value)
|
||
|
end
|
||
|
container.Env.FormInstance[propName] = value
|
||
|
container.Env.setter(propName, value)
|
||
|
-- if there's a 'onChange' function then call it
|
||
|
if type(prop.onChange) == "function" then
|
||
|
prop.onChange(container.Env.FormInstance)
|
||
|
end
|
||
|
-- visibility of some properties may depend on this one, so update them
|
||
|
container.Env.updatePropVisibility()
|
||
|
else
|
||
|
local target = r2:getPropertySheetTarget()
|
||
|
local class = r2:getClass(target)
|
||
|
local prop = class.NameToProp[propName]
|
||
|
if target[propName] == value then
|
||
|
return -- not really modified -> no op
|
||
|
end
|
||
|
local ucActionName = r2:getPropertyTranslation(prop)
|
||
|
r2.requestNewAction(concatUCString(i18n.get("uiR2EDChangePropertyAction"), ucActionName, i18n.get("uiR2EDChangePropertyOf"), target:getDisplayName()))
|
||
|
-- this is a property sheet
|
||
|
|
||
|
|
||
|
-- if the instance is currently being erased, no use
|
||
|
-- to send pending properties (may happen ifthe user being to enter a string
|
||
|
-- an click on the erase button -> then the propertu sheet is closed and this function
|
||
|
-- is fired)
|
||
|
if target.User.Erased == true then
|
||
|
return
|
||
|
end
|
||
|
|
||
|
if prop.convertFromWidgetValue ~= nil then
|
||
|
-- if there's a conversion function then use it
|
||
|
value = prop.convertFromWidgetValue(value)
|
||
|
end
|
||
|
--debugInfo(string.format("Setting node : prop name = %s, value = %s", tostring(propName), tostring(value)))
|
||
|
|
||
|
if isLocal then
|
||
|
r2.requestSetLocalNode(target.InstanceId, propName, value)
|
||
|
else
|
||
|
r2.requestSetNode(target.InstanceId, propName, value)
|
||
|
end
|
||
|
|
||
|
if prop.SecondRequestFunc and prop.SecondRequestFunc~="" then
|
||
|
prop.SecondRequestFunc(value)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-------------------------------------------------------------------------------------
|
||
|
-- Signal that a property of object being currently edited (in a property sheet or a form)
|
||
|
-- has been changed. This will update the object property with value 'value'. should be called by edition widget
|
||
|
-- This is a local version of 'r2:requestSetObjectProperty' : no net msg is sent, value is modified locally.
|
||
|
-- Value is actually sent at commit time (when calling r2:requestCommitLocalObjectProperty)
|
||
|
function r2:requestSetLocalObjectProperty(propName, value)
|
||
|
self:requestSetObjectProperty(propName, value, true)
|
||
|
end
|
||
|
|
||
|
-------------------------------------------------------------------------------------
|
||
|
-- Commit last modifications done on the object that is currently being edited (using r2:requestSetLocalObjectProperty)
|
||
|
-- A net msg is sent to update the object property on the server.
|
||
|
-- The local value is copied to the client value that was previously shadowed by a call to 'r2:requestSetLocalObjectProperty'
|
||
|
function r2:requestCommitLocalObjectProperty(propName, value)
|
||
|
if getUICaller() == nil then
|
||
|
debugInfo("<r2:requestSetObjectProperty> should be called by a widget")
|
||
|
return
|
||
|
end
|
||
|
local container = getUICaller().parent:getEnclosingContainer()
|
||
|
if container.Env.Form == nil then
|
||
|
-- this is a property sheet
|
||
|
local target = r2:getPropertySheetTarget()
|
||
|
local class = r2:getClass(target)
|
||
|
local prop = class.NameToProp[propName]
|
||
|
--debugInfo(string.format("Setting node : prop name = %s, value = %s", tostring(propName), tostring(value)))
|
||
|
r2.requestCommitLocalNode(target.InstanceId, propName)
|
||
|
r2.requestEndAction()
|
||
|
end
|
||
|
-- no op for forms (no 'commit' notion)
|
||
|
end
|
||
|
|
||
|
-------------------------------------------------------------------------------------
|
||
|
-- Cancel last modifications done on the object that is currently being edited (using r2:requestSetLocalObjectProperty)
|
||
|
-- Object property is restored to its initial value (technically, it stop being 'shadowed' by the local value, so any
|
||
|
-- third party modification will be seen from here)
|
||
|
-- As a consequence no net msg is sent
|
||
|
function r2:requestRollbackLocalObjectProperty(propName, value)
|
||
|
if getUICaller() == nil then
|
||
|
debugInfo("<r2:requestSetObjectProperty> should be called by a widget")
|
||
|
return
|
||
|
end
|
||
|
local container = getUICaller().parent:getEnclosingContainer()
|
||
|
if container.Env.Form ~= nil then
|
||
|
-- this is a form (update is done in local)
|
||
|
local form = container.Env.Form
|
||
|
local prop = form.NameToProp[propName]
|
||
|
if prop.convertFromWidgetValue ~= nil then
|
||
|
-- if there's a conversion function then use it
|
||
|
value = prop.convertFromWidgetValue(value)
|
||
|
end
|
||
|
container.Env.FormInstance[propName] = value
|
||
|
container.Env.setter(propName, value)
|
||
|
else
|
||
|
-- this is a property sheet
|
||
|
local target = r2:getPropertySheetTarget()
|
||
|
local class = r2:getClass(target)
|
||
|
local prop = class.NameToProp[propName]
|
||
|
--debugInfo(string.format("Setting node : prop name = %s, value = %s", tostring(propName), tostring(value)))
|
||
|
r2.requestRollbackLocalNode(target.InstanceId, propName)
|
||
|
end
|
||
|
-- no op for forms (no 'commit' notion)
|
||
|
end
|
||
|
|
||
|
-------------------------------------------------------------------------------------
|
||
|
-- get the object whose property sheet is currently displayed
|
||
|
-- should be used only with property sheets
|
||
|
function r2:getPropertySheetTarget()
|
||
|
if not r2.CurrentPropertyWindow then return nil end
|
||
|
-- can only be the selection for now ...
|
||
|
return r2.CurrentPropertyWindow.Env.TargetInstance
|
||
|
end
|
||
|
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- get name of ui for default property sheet from the class name
|
||
|
function r2:getDefaultPropertySheetUIPath(className)
|
||
|
return "ui:interface:r2ed_property_sheet_" .. className
|
||
|
end
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- get definition of property edited from its widget
|
||
|
function r2:getPropertyDefinition(propName, uiCaller)
|
||
|
-- useful infos are stored in the parent container
|
||
|
assert(uiCaller)
|
||
|
local container = uiCaller:getEnclosingContainer()
|
||
|
if container.Env.Form ~= nil then
|
||
|
-- this is a form (update is done in local)
|
||
|
return container.Env.Form.NameToProp[propName]
|
||
|
else
|
||
|
-- this is a property sheet
|
||
|
local target = r2:getPropertySheetTarget()
|
||
|
local class = r2:getClass(target)
|
||
|
return class.NameToProp[propName]
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- return pointer to a property sheet of an object from its class name
|
||
|
function r2:getPropertySheet(instance)
|
||
|
local class = instance:getClass()
|
||
|
local uiPath = r2:evalProp(class.PropertySheetUIPath, instance, r2:getDefaultPropertySheetUIPath(class.Name))
|
||
|
return getUI(uiPath)
|
||
|
end
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- get a form from its name
|
||
|
function r2:getForm(name)
|
||
|
assert(name) -- why is nam nil???
|
||
|
return getUI("ui:interface:r2ed_form_" .. name)
|
||
|
end
|
||
|
|
||
|
--/////////////////////
|
||
|
--// NUMBER WIDGETS //
|
||
|
--/////////////////////
|
||
|
|
||
|
-- widget styles for 'Numbers'
|
||
|
r2.WidgetStyles.Number =
|
||
|
{
|
||
|
--------------------------------------------------------------------------------------------------------------------
|
||
|
Default = function(prop, className)
|
||
|
local function setter(widget, prop, value)
|
||
|
widget.eb.input_string = tostring(value)
|
||
|
widget.eb.Env.CurrString = tostring(value)
|
||
|
end
|
||
|
local onChangeAction =
|
||
|
string.format(
|
||
|
[[
|
||
|
local editBox = getUICaller()
|
||
|
if editBox.input_string == editBox.Env.CurrString then
|
||
|
return
|
||
|
end
|
||
|
editBox.Env.CurrString = editBox.input_string
|
||
|
local newValue = tonumber(getUICaller().input_string)
|
||
|
if newValue == nil then
|
||
|
debugInfo('Invalid number value : ' .. getUICaller().input_string)
|
||
|
return
|
||
|
end
|
||
|
local prop = r2:getPropertyDefinition('%s', getUICaller())
|
||
|
assert(prop)
|
||
|
local clamped = false
|
||
|
if prop.Min and newValue < tonumber(prop.Min) then
|
||
|
newValue = tonumber(prop.Min)
|
||
|
clamped = true
|
||
|
end
|
||
|
if prop.Max and newValue > tonumber(prop.Max) then
|
||
|
newValue = tonumber(prop.Max)
|
||
|
clamped = true
|
||
|
end
|
||
|
if clamped then
|
||
|
editBox.input_string = tostring(newValue)
|
||
|
editBox.Env.CurrString = tostring(newValue)
|
||
|
end
|
||
|
r2:requestSetObjectProperty('%s', newValue)
|
||
|
]], prop.Name, prop.Name)
|
||
|
return r2:buildEditBox(prop, "TR TR", "integer", false, 16, onChangeAction, onChangeAction), setter, nil
|
||
|
end,
|
||
|
--------------------------------------------------------------------------------------------------------------------
|
||
|
Boolean = function(prop, className)
|
||
|
local function setter(widget, prop, value)
|
||
|
--debugInfo("setter : " .. tostring(value))
|
||
|
-- widget is a pointer to the enclosing group
|
||
|
if value == 1 then
|
||
|
value = true
|
||
|
else
|
||
|
value = false
|
||
|
end
|
||
|
widget.butt.pushed = value
|
||
|
--widget.text_true.active = value
|
||
|
--widget.text_false.active = not value
|
||
|
end
|
||
|
local function buildCoverAllButton(prop)
|
||
|
return [[ <ctrl type="button" button_type="push_button"
|
||
|
id="b_]] .. prop.Name .. [["
|
||
|
tx_normal="blank.tga" tx_pushed="blank.tga" tx_over="blank.tga"
|
||
|
sizeref="wh"
|
||
|
scale="true"
|
||
|
posref="ML ML"
|
||
|
color="0 0 0 0"
|
||
|
col_pushed="0 0 0 0"
|
||
|
col_over="0 0 0 0"
|
||
|
onclick_l="lua"
|
||
|
params_l="local value; if getUICaller().parent:getEnclosingContainer():find(']] .. prop.Name .. [[').butt.pushed then value = 0 else value = 1 end; r2:requestSetObjectProperty(']] .. prop.Name .. [[', value)"
|
||
|
/>
|
||
|
]]
|
||
|
end
|
||
|
-- local widgetXml =
|
||
|
-- string.format([[
|
||
|
-- <group id="%s" posref="TL TL" child_resize_h="true" x="2" child_resize_hmargin="4" child_resize_w="true" child_resize_wmargin="4">
|
||
|
-- <ctrl type="button" id="butt" button_type="toggle_button" posref="ML ML" x="2" y="0"
|
||
|
-- tx_normal="w_slot_on.tga" tx_pushed="w_opacity_on.tga" tx_over="w_slot_on.tga"
|
||
|
-- color="255 255 255 255" col_pushed="255 255 255 255" col_over="255 255 255 0"
|
||
|
-- onclick_l="lua"
|
||
|
-- params_l="local value; if getUICaller().pushed == true then value = 1 else value = 0 end; r2:requestSetObjectProperty('%s', value)"
|
||
|
-- />
|
||
|
-- <view type="text" id="text_true" posparent="butt" posref="MR ML" x="4" y="-3" active="false" global_color="true" fontsize="12" shadow="true" hardtext="uiR2EDTrue"/>
|
||
|
-- <view type="text" id="text_false" posparent="butt" posref="MR ML" x="4" y="-3" active="true" global_color="true" fontsize="12" shadow="true" hardtext="uiR2EDFalse"/>
|
||
|
-- </group>
|
||
|
-- ]], prop.Name, prop.Name)
|
||
|
local widgetXml =
|
||
|
string.format([[
|
||
|
<group id="%s" posref="TL TL" child_resize_h="true" x="2" child_resize_hmargin="4" sizeref="w"> ]]
|
||
|
.. buildCoverAllButton(prop) .. [[
|
||
|
<ctrl type="button" id="butt" button_type="toggle_button" posref="ML ML" x="0" y="0"
|
||
|
tx_normal="w_slot_on.tga" tx_pushed="w_opacity_on.tga" tx_over="w_slot_on.tga"
|
||
|
color="255 255 255 255" col_pushed="255 255 255 255" col_over="255 255 255 0"
|
||
|
onclick_l="lua"
|
||
|
params_l="local value; if getUICaller().pushed == true then value = 1 else value = 0 end; r2:requestSetObjectProperty('%s', value)"
|
||
|
/>
|
||
|
</group>
|
||
|
]], prop.Name, prop.Name)
|
||
|
-- Caption is special here :
|
||
|
-- It contains a button to avoid to have to click in the tiny checkbox, which is inconvenient
|
||
|
local iwidth0 = defaulting(prop.CaptionWidth, 35)
|
||
|
local width0 = string.format("%d%%", iwidth0)
|
||
|
local width1 = string.format("%d%%", 100 - iwidth0)
|
||
|
local invertWidget = defaulting(prop.InvertWidget, false)
|
||
|
|
||
|
if invertWidget then
|
||
|
local tmp = width0
|
||
|
width0 = width1
|
||
|
width1 = tmp
|
||
|
end
|
||
|
|
||
|
local part0 = [[<TD width=]] .. strify(width0) .. [[ ignore_max_width="true" ignore_min_width="true" bgcolor="80 80 80 127" height="0" align="left" valign="middle" id= "l_]] .. prop.Name .. [[" > ]]
|
||
|
|
||
|
|
||
|
local tooltipTextId, tooltipTextIdFound = buildPropTooltipName(className, prop.Name)
|
||
|
part0 = part0 .. [[<group id="caption_group" sizeref="w" child_resize_h="true" child_resize_hmargin="4" posref="ML ML"
|
||
|
tooltip_parent="win"
|
||
|
tooltip_posref="auto"
|
||
|
instant_help="true"
|
||
|
tooltip=]] .. strify(tooltipTextId) .. ">"
|
||
|
part0 = part0 .. buildCoverAllButton(prop)
|
||
|
|
||
|
local color = "255 255 255 255"
|
||
|
local globalColor = "true"
|
||
|
local hardText
|
||
|
local found
|
||
|
hardText, found = r2:getPropertyTranslationId(prop)
|
||
|
if not found and config.R2EDExtendedDebug == 1 then
|
||
|
color = "255 0 0 255"
|
||
|
globalColor = "false"
|
||
|
hardText = hardText .. " (NOT TRANSLATED)"
|
||
|
end
|
||
|
|
||
|
part0 = part0 .. [[ <view type="text" y="-2" sizeref="w" over_extend_view_text="true" over_extend_parent_rect="true"]] ..
|
||
|
[[ id = ]] .. strify(prop.Name .. "_Caption") ..
|
||
|
[[ hardtext = ]] .. strify(hardText) ..
|
||
|
[[ color = ]] .. strify(color) ..
|
||
|
[[ global_color=]] .. strify(globalColor) .. [[ fontsize="12" shadow="true" auto_clamp="true"/> ]]
|
||
|
part0 = part0 .. "</group>"
|
||
|
part0 = part0 .. "</TD>"
|
||
|
|
||
|
--dumpSplittedString(widgetXml)
|
||
|
return widgetXml, setter, part0
|
||
|
end,
|
||
|
--------------------------------------------------------------------------------------------------------------------
|
||
|
Slider = function(prop, className)
|
||
|
local function setter(widget, prop, value)
|
||
|
if widget.c.value ~= nil then
|
||
|
widget.c.value = value
|
||
|
end
|
||
|
end
|
||
|
--
|
||
|
local widgetXml =
|
||
|
string.format([[
|
||
|
<group posref="TL TL" x="4" y="3" sizeref="w" w="-4" child_resize_h="true" child_resize_hmargin="3" id= ]] .. strify(prop.Name) .. ">" .. [[
|
||
|
<view type="bitmap" id="bk" posref="BL BL" scale="true" y="4" sizeref="w" h="2" texture="W_line_hor2.tga" />
|
||
|
<ctrl type="scroll" id="c" posparent="bk" posref="MM MM" x="0" y="-1" sizeref="w" h="12"
|
||
|
vertical="false" align="L" tracksize="12"
|
||
|
cancelable="true"
|
||
|
tx_topright="w_scroll_R.tga" tx_middle="w_scroll_M.tga" tx_bottomleft="w_scroll_L.tga"
|
||
|
onscroll="lua" params="r2:requestSetLocalObjectProperty('%s', getUICaller().value)"
|
||
|
onscrollend="lua" end_params="r2:requestCommitLocalObjectProperty('%s')"
|
||
|
onscrollcancel="lua" cancel_params="r2:requestRollbackLocalObjectProperty('%s')"
|
||
|
min="%s"
|
||
|
max="%s"
|
||
|
step_value="%s"
|
||
|
/>
|
||
|
|
||
|
<group id="bitmaps" active="%s" y="7" posparent="bk" posref="TL BL" sizeref="w" child_resize_h="true" >
|
||
|
|
||
|
<view type="bitmap" id="l_t" posref="BL BL" x="0" y="0" texture="%s"
|
||
|
/>
|
||
|
|
||
|
<view type="bitmap" id="m_t" posref="BM BM" x="0" y="0" texture="%s"
|
||
|
/>
|
||
|
|
||
|
<view type="bitmap" id="r_t" posref="BR BR" x="0" y="0" texture="%s"
|
||
|
/>
|
||
|
|
||
|
"</group>"
|
||
|
|
||
|
"</group>"
|
||
|
]], prop.Name, prop.Name, prop.Name, defaulting(prop.Min, 0), defaulting(prop.Max, 100), defaulting(prop.StepValue, 1),
|
||
|
defaulting(prop.ActiveBitmaps, 'false'), defaulting(prop.LeftBitmap, ""), defaulting(prop.MiddleBitmap, ""), defaulting(prop.RightBitmap, ""))
|
||
|
--
|
||
|
--debugInfo(string.format("Creating slider widget, min = %s, max = %s", defaulting(prop.Min, 0), defaulting(prop.Min, 100)))
|
||
|
return widgetXml, setter
|
||
|
end,
|
||
|
--------------------------------------------------------------------------------------------------------------------
|
||
|
EnumDropDown = function(prop, className)
|
||
|
if type(prop.Enum) ~= "table" then
|
||
|
debugInfo("Can't create enum combo box, the 'Enum' table is not found or of bad type")
|
||
|
return ""
|
||
|
end
|
||
|
local function setter(widget, prop, value)
|
||
|
if widget.selection ~= nil then
|
||
|
widget.parent.Env.Locked = true
|
||
|
widget.selection = value
|
||
|
widget.parent.Env.Locked = false
|
||
|
end
|
||
|
end
|
||
|
local result =
|
||
|
[[
|
||
|
<group type="combo_box" sizeref="w" w="-2" x="2" y="0" child_resize_h="true" child_resize_hmargin="10" linked_to_db="false" posref="TL TL" id=]]
|
||
|
.. strify(prop.Name) ..
|
||
|
string.format([[ on_change="lua" on_change_params="if getUICaller().parent.Env.Locked ~= true then r2:requestSetObjectProperty('%s', getUICaller().selection) end"]], prop.Name) ..
|
||
|
">"
|
||
|
result = result .. [[<instance template="combo_box_def1" />]]
|
||
|
-- append enumerated values
|
||
|
|
||
|
for k, v in pairs(prop.Enum) do
|
||
|
result = result .. [[<combo_text name="]] .. tostring(v) .. [[" />]]
|
||
|
end
|
||
|
result = result .. "</group>"
|
||
|
return result, setter
|
||
|
end,
|
||
|
}
|
||
|
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- build a widget from the definition of the property
|
||
|
function r2:buildPropWidget(prop, className)
|
||
|
local widgetFactory = r2.WidgetStyles[prop.Type]
|
||
|
if widgetFactory == nil then
|
||
|
--debugInfo("Type '" .. tostring(prop.Type) .. "' not found. Widget not built")
|
||
|
return nil
|
||
|
end
|
||
|
local widgetStyle = prop.WidgetStyle
|
||
|
if widgetStyle == nil then
|
||
|
widgetStyle = "Default"
|
||
|
end
|
||
|
if widgetFactory[widgetStyle] == nil then
|
||
|
debugInfo("Widget style '" .. tostring(widgetStyle) .. "' not found for type '" .. tostring(prop.Type) ..
|
||
|
"', widget not built" )
|
||
|
return nil
|
||
|
end
|
||
|
local result, setter, caption = widgetFactory[widgetStyle](prop, className)
|
||
|
-- add common functionnality of setter
|
||
|
if setter ~= nil then
|
||
|
-- if there's a conversion function on set, then call it
|
||
|
if prop.convertToWidgetValue ~= nil then
|
||
|
if type(setter) == "function" then
|
||
|
local oldSetter = setter
|
||
|
setter = function(widget, prop, value)
|
||
|
oldSetter(widget, prop, prop.convertToWidgetValue(value))
|
||
|
end
|
||
|
else
|
||
|
assert(type(setter) == "table")
|
||
|
if (setter.onSet) then
|
||
|
local oldSetter = setter.onSet
|
||
|
function setter:onSet(widget, prop, value)
|
||
|
self:oldSetter(widget, prop, prop.convertToWidgetValue(value))
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return result, setter, caption
|
||
|
end
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- create a table of properties
|
||
|
function r2:createPropertyXmlTable(props, className, posparent, posref, x, y, widgetEventHandlerTable)
|
||
|
local result = "" -- the resulting xml
|
||
|
-- add a new string to the resulting string
|
||
|
local function add(value)
|
||
|
result = result .. value
|
||
|
end
|
||
|
add([[<group type="table" sizeparent="parent"]] ..
|
||
|
[[ posparent= ]] .. strify(posparent) ..
|
||
|
[[ posref= ]] .. strify(posref) ..
|
||
|
[[ x= ]] .. strify(x) ..
|
||
|
[[ y= ]] .. strify(y) ..
|
||
|
[[ id="prop_table" sizeref="w" width="100%" border="0" bgcolor="0 0 0 255"
|
||
|
cellspacing="1"
|
||
|
cellpadding="0"
|
||
|
continuous_update="true"
|
||
|
>
|
||
|
]])
|
||
|
|
||
|
for key, prop in pairs(props) do
|
||
|
local widgetXmlDesc, setter, captionXmlDesc = self:buildPropWidget(prop, className)
|
||
|
if widgetXmlDesc ~= nil then
|
||
|
add("<TR>")
|
||
|
-- build the caption
|
||
|
local color = "255 255 255 255"
|
||
|
local globalColor = "true"
|
||
|
--if SeenNames[prop.Name] == nil then
|
||
|
-- debugInfo(prop.Name)
|
||
|
-- SeenNames[prop.Name] = true
|
||
|
--end
|
||
|
|
||
|
local hardText
|
||
|
local found
|
||
|
hardText, found = r2:getPropertyTranslationId(prop)
|
||
|
if not found and config.R2EDExtendedDebug == 1 then
|
||
|
color = "255 0 0 255"
|
||
|
globalColor = "false"
|
||
|
hardText = hardText .. " (NOT TRANSLATED)"
|
||
|
end
|
||
|
--
|
||
|
local iwidth0 = defaulting(prop.CaptionWidth, 35)
|
||
|
local width0 = string.format("%d%%", iwidth0)
|
||
|
local width1 = string.format("%d%%", 100 - iwidth0)
|
||
|
local invertWidget = defaulting(prop.InvertWidget, false)
|
||
|
|
||
|
if invertWidget then
|
||
|
local tmp = width0
|
||
|
width0 = width1
|
||
|
width1 = tmp
|
||
|
end
|
||
|
|
||
|
local tooltipTextId, tooltipTextIdFound = buildPropTooltipName(className, prop.Name)
|
||
|
--debugInfo(string.format("%60s %s", tooltipTextId, " [@{F00F} FILL ME ! :" .. prop.Name .. "]"))
|
||
|
|
||
|
local part0
|
||
|
if not captionXmlDesc then
|
||
|
part0 = [[<TD width=]] .. strify(width0) .. [[ ignore_max_width="true" ignore_min_width="true" bgcolor="80 80 80 127" height="0" align="left" valign="middle" id= "l_]] .. prop.Name .. [[" > ]]
|
||
|
|
||
|
part0 = part0 .. [[<group id="caption_group" sizeref="w" child_resize_h="true" posref="ML ML"
|
||
|
tooltip_parent="win"
|
||
|
tooltip_posref="auto"
|
||
|
instant_help="true"
|
||
|
tooltip=]] .. strify(tooltipTextId) .. ">"
|
||
|
part0 = part0 .. [[ <view type="text" y="-2" sizeref="w" over_extend_view_text="true" over_extend_parent_rect="true"]] ..
|
||
|
[[ id = ]] .. strify(prop.Name .. "_Caption") ..
|
||
|
[[ hardtext = ]] .. strify(hardText) ..
|
||
|
[[ color = ]] .. strify(color) ..
|
||
|
[[ global_color=]] .. strify(globalColor) .. [[ fontsize="12" shadow="true" auto_clamp="true"/> ]]
|
||
|
part0 = part0 .. "</group>"
|
||
|
part0 = part0 .. "</TD>"
|
||
|
else
|
||
|
part0 = captionXmlDesc
|
||
|
end
|
||
|
|
||
|
-- build the widget
|
||
|
local part1 = [[<TD width=]] .. strify(width1) .. [[ ignore_max_width="true" ignore_min_width="true" bgcolor="64 64 64 127" height="0" align="left" valign="middle" id= "r_]] .. prop.Name .. [[" > ]]
|
||
|
part1 = part1 .. [[<group id="widget_group" sizeref="w" child_resize_h="true" posref="ML ML"
|
||
|
tooltip_parent="win"
|
||
|
tooltip_posref="auto"
|
||
|
tooltip_posref_alt="TL TR"
|
||
|
instant_help="true"
|
||
|
tooltip=]] .. strify(tooltipTextId) .. ">"
|
||
|
part1 = part1 .. widgetXmlDesc .. [[</group></TD>]]
|
||
|
|
||
|
if invertWidget then
|
||
|
add(part1 .. part0)
|
||
|
else
|
||
|
add(part0 .. part1)
|
||
|
end
|
||
|
-- add the setter function in the table
|
||
|
--debugInfo("inserting entry" .. prop.Name)
|
||
|
if type(setter) == "function" then
|
||
|
-- setter is a plain 'set' function
|
||
|
-- => event handler is a simple table with a 'onSet' method ...
|
||
|
widgetEventHandlerTable[prop.Name] =
|
||
|
{
|
||
|
onSet= function(this, widget, prop, value)
|
||
|
setter(widget, prop, value)
|
||
|
end
|
||
|
}
|
||
|
else
|
||
|
-- debugInfo(prop.Name .. " : " .. type(setter))
|
||
|
-- setter is a complete object (a lua table) with event handling methods
|
||
|
if type(setter) ~= "table" then
|
||
|
debugInfo(type(setter))
|
||
|
inspect(setter)
|
||
|
assert(0)
|
||
|
end
|
||
|
widgetEventHandlerTable[prop.Name] = setter
|
||
|
end
|
||
|
add("</TR>")
|
||
|
end
|
||
|
end
|
||
|
add([[</group>]])
|
||
|
return result
|
||
|
end
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- build xml for a rollout containing a table of properties
|
||
|
function r2:buildPropRolloutXml2(className, caption, id, posparent, posref, props, rolloutY, widgetEventHandlerTable, isForm)
|
||
|
local content = self:createPropertyXmlTable(props, className, "caption", "BL TL", 0, -4, widgetEventHandlerTable)
|
||
|
-- todo : use something more clear than string.format !!!
|
||
|
local global_color_over = "255 255 255 192"
|
||
|
local params_l = "r2:openCloseRollout('prop_table')"
|
||
|
if isForm then
|
||
|
global_color_over = "127 127 127 127"
|
||
|
params_l = ""
|
||
|
end
|
||
|
local result = string.format(
|
||
|
[[ <group id ="%s" x = "0" y="%s" sizeref="w" child_resize_h="true" posparent="%s" posref="%s" w="0">
|
||
|
<group id="caption" sizeref="w" w="0" child_resize_h="true" child_resize_hmargin="2" posref="TL TL">
|
||
|
<ctrl type="button" id="rollout_button" button_type="push_button" sizeref = "wh" posref="TL TL"
|
||
|
tx_normal="grey_40.tga"
|
||
|
tx_pushed="grey_80.tga"
|
||
|
tx_over="grey_60.tga"
|
||
|
scale="true"
|
||
|
tooltip=""
|
||
|
global_color="true"
|
||
|
global_color_normal="127 127 127 127"
|
||
|
global_color_over="%s"
|
||
|
global_color_pushed="false"
|
||
|
onclick_l="lua"
|
||
|
params_l="%s"
|
||
|
/>
|
||
|
]], id, rolloutY, posparent, posref, global_color_over, params_l)
|
||
|
|
||
|
|
||
|
if not isForm then
|
||
|
result = result ..
|
||
|
string.format([[
|
||
|
<group id="open_indicator" child_resize_h="true" x="3" y="-1" child_resize_w="true" posref="ML ML" posparent="rollout_button">
|
||
|
<view type="bitmap" render_layer="2" id="opened" active="true" posref="TL TL" texture="rollout_opened.tga" color="255 255 255 255"/>
|
||
|
<view type="bitmap" render_layer="2" id="closed" active="false" posref="TL TL" texture="rollout_closed.tga" color="255 255 255 255"/>
|
||
|
</group>
|
||
|
<view type="text" render_layer="2" id="rollout_text" auto_clamp="true" posref="MR ML" x="2" y="-1" posparent="open_indicator" global_color="true" fontsize="12" shadow="false" hardtext="%s"
|
||
|
over_extend_view_text="true" over_extend_parent_rect="true"
|
||
|
/>]], caption)
|
||
|
else
|
||
|
result = result ..
|
||
|
string.format([[<view type="text" render_layer="2" id="rollout_text" auto_clamp="true" posref="ML ML" x="2" y="-1" posparent="parent" global_color="true" fontsize="12" shadow="false" hardtext="%s"
|
||
|
over_extend_view_text="true" over_extend_parent_rect="true"
|
||
|
/>]], caption)
|
||
|
end
|
||
|
|
||
|
result = result .. string.format(
|
||
|
[[ <view type="bitmap" render_layer="2" scale="true" id="top" sizeref="w" h="1" posref="TL TL" texture="blank.tga" color="0 0 0 255"/>
|
||
|
<view type="bitmap" render_layer="2" scale="true" id="left" sizeref="h" w="1" posref="TL TL" texture="blank.tga" color="0 0 0 255"/>
|
||
|
<view type="bitmap" render_layer="2" scale="true" id="right" sizeref="h" w="1" posref="TR TR" texture="blank.tga" color="0 0 0 255"/>
|
||
|
</group>
|
||
|
<view type="bitmap" scale="true" render_layer="2" id="bottom" posparent="caption" sizeref="w" h="1" y="0" posref="BL TL" texture="blank.tga" color="0 0 0 255"/>
|
||
|
|
||
|
%s <!-- the content -->
|
||
|
</group>
|
||
|
]],content)
|
||
|
|
||
|
return result
|
||
|
end
|
||
|
|
||
|
-- build xml for a rollout containing a table of properties
|
||
|
function r2:buildPropRolloutXml(caption, id, posparent, posref, props, className, rolloutY, widgetEventHandlerTable, isForm)
|
||
|
local content = self:createPropertyXmlTable(props, className, "caption", "BL TL", 0, -4, widgetEventHandlerTable)
|
||
|
-- add the caption
|
||
|
local result = string.format(
|
||
|
[[ <group id ="%s" x = "0" y="%s" sizeref="w"
|
||
|
child_resize_h="true" posparent="%s"
|
||
|
posref="%s" w="0"> ]], id, rolloutY, posparent, posref)
|
||
|
|
||
|
local color = "255 255 255 255"
|
||
|
local globalColor = "true"
|
||
|
--if SeenRolloutCaptions[caption] == nil then
|
||
|
-- debugInfo(caption)
|
||
|
-- SeenRolloutCaptions[caption] = true
|
||
|
--end
|
||
|
if not i18n.hasTranslation(caption) then
|
||
|
if config.R2EDExtendedDebug == 1 then
|
||
|
color = "255 0 0 255"
|
||
|
globalColor = "false"
|
||
|
caption = caption .. "(NOT TRANSLATED)"
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- add the rollout bar
|
||
|
if not isForm then
|
||
|
result = result ..
|
||
|
[[ <instance template="rollout_bar" caption=]] .. strify(caption) ..
|
||
|
[[ color=]] .. strify(color) ..
|
||
|
[[ global_color=]] .. strify(globalColor) ..
|
||
|
[[ content_name="prop_table"/> ]]
|
||
|
else
|
||
|
result = result ..
|
||
|
[[ <instance template="form_bar" caption=]] .. strify(caption) ..
|
||
|
[[ color=]] .. strify(color) ..
|
||
|
[[ global_color=]] .. strify(globalColor) ..
|
||
|
[[ /> ]]
|
||
|
end
|
||
|
|
||
|
-- add the content
|
||
|
result = result .. content
|
||
|
|
||
|
-- close
|
||
|
result = result .. "</group>"
|
||
|
|
||
|
return result
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
----------------------------------------------------------------------------------------------------------------------------------------
|
||
|
----------------------------------------------------------------------------------------------------------------------------------------
|
||
|
-- Generation of property sheet ui xml code from a class definition
|
||
|
-- this function will return 2 values :
|
||
|
-- xml code to generate the dialog to edit instance of the class
|
||
|
-- A registration function for that dialog, that must be called prior to use (and once the ui has been created from the xml code)
|
||
|
-- Note : Registration isn't done at creation in order to pack several class descriptions in
|
||
|
-- a single xml script to speed up parsing
|
||
|
|
||
|
function r2:buildPropertySheetXml(class, className, id, title, isForm)
|
||
|
|
||
|
-- The following table contains for each property a set method that allow to change it from the outside
|
||
|
-- these value is filled by each widget "ctor" function.
|
||
|
-- In a similar way, each widget is given a setter function.
|
||
|
local widgetEventHandlerTable = {}
|
||
|
--
|
||
|
--local function dump()
|
||
|
-- for key, value in pairs(widgetEventHandlerTable) do
|
||
|
-- debugInfo('*')
|
||
|
-- debugInfo(tostring(key, value))
|
||
|
-- end
|
||
|
--end
|
||
|
--
|
||
|
local result = "" -- the resulting xml
|
||
|
-- add a new string to the resulting string
|
||
|
local function add(value)
|
||
|
result = result .. value
|
||
|
end
|
||
|
|
||
|
|
||
|
local rolloutsX = 12
|
||
|
local rolloutsW = -14
|
||
|
if isForm then
|
||
|
rolloutsX = 0
|
||
|
rolloutsW = -2
|
||
|
end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
add(
|
||
|
[[
|
||
|
<group type="container" savable="false" title_delta_max_w="]] .. tostring(r2.DefaultPropertySheetTitleClampSize) .. [[" title="]] .. title .. [[" global_color="false" line_at_bottom="false"
|
||
|
active="false"
|
||
|
escapable="true"
|
||
|
movable="true" opened="true" openable="false" header_color="UI:SAVE:WIN:COLORS:]] .. select(isForm, "R2_FORM", "R2_PROP_WINDOW") ..
|
||
|
[[" pop_min_h="32" pop_max_h="10000"
|
||
|
on_active="lua"
|
||
|
]])
|
||
|
---------------------------------
|
||
|
if isForm then -- for forms, closing the form is equivalent to clicking on 'cancel'
|
||
|
add(' resizer="true" ')
|
||
|
local w = defaulting(class.Width, 500)
|
||
|
add(' pop_min_w=' .. strify(w))
|
||
|
add(' pop_max_w=' .. strify(w))
|
||
|
add(' w=' .. strify(w))
|
||
|
local cancelCode =
|
||
|
[[ local form = getUICaller()
|
||
|
if form.Env.Choice == nil then
|
||
|
form.Env.Choice= 'Cancel'
|
||
|
if form.Env.onCancel then
|
||
|
form.Env.onCancel(form.Env.FormInstance, form)
|
||
|
end
|
||
|
end
|
||
|
]]
|
||
|
add(string.format([[ on_deactive="lua" on_deactive_params="%s" on_escape="lua" on_escape_params="%s" ]], cancelCode, cancelCode))
|
||
|
add([[on_enter="lua" on_enter_params="r2:validateForm(getUICaller())" ]])
|
||
|
add([[on_alpha_settings_changed="lua:r2:onFormAlphaSettingsChanged()" ]])
|
||
|
add([[on_active_params="if r2 ~= nil then
|
||
|
local updateAll = getUICaller().Env.updateAll
|
||
|
if updateAll then updateAll() end
|
||
|
r2:restoreContAlphaSettings('R2_FORM')
|
||
|
end;" ]])
|
||
|
else
|
||
|
add(' resizer="true" ')
|
||
|
add('pop_min_w="150"')
|
||
|
add(' pop_max_w="800" ')
|
||
|
add(' w="250" ')
|
||
|
add([[on_alpha_settings_changed="lua:r2:onPropertySheetAlphaSettingsChanged()" ]])
|
||
|
add([[on_active_params="if r2 ~= nil then
|
||
|
local updateAll = getUICaller().Env.updateAll
|
||
|
if updateAll then updateAll() end
|
||
|
r2:restoreContAlphaSettings('R2_PROP_SHEET')
|
||
|
end;" ]])
|
||
|
end
|
||
|
|
||
|
---------------------------------
|
||
|
if not isForm then -- for property sheets, closing the sheet is equivalent to clicking on the 'toggle property window' button
|
||
|
add([[ on_deactive="lua" on_deactive_params="r2.PropertyWindowVisible = false" ]])
|
||
|
end
|
||
|
---------------------------------
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
add([[id=]] .. strify(id) .. [[
|
||
|
>]])
|
||
|
|
||
|
|
||
|
|
||
|
if className == "NpcCustom" then
|
||
|
add(
|
||
|
[[
|
||
|
<group id="header_opened" x="0" y="0" w="0" h="16" posref="TL TL"
|
||
|
group_onclick_r="active_menu"
|
||
|
group_params_r="menu=ui:interface:base_menu_with_color"
|
||
|
>
|
||
|
|
||
|
<ctrl style="button_ok" id="help" active="true" x="-16" y="0" posref="MR MR" color="255 255 255 255"
|
||
|
text_y="-2" onclick_l="lua" params_l="r2.displayFeatureHelp('Npc')" hardtext="uiR2EdHelp" fontsize="10" />
|
||
|
</group>
|
||
|
]])
|
||
|
elseif r2.hasDisplayInfo(className) == 1 or string.find(className, "_Form") ~= nil then
|
||
|
debugInfo("Adding help header for "..className)
|
||
|
local featureName = className
|
||
|
if string.find(className, "_Form") ~= nil then
|
||
|
local len = string.len(featureName)
|
||
|
featureName = string.sub(featureName, 1, len - 5)
|
||
|
end
|
||
|
|
||
|
add(
|
||
|
[[
|
||
|
<group id="header_opened" x="0" y="0" w="0" h="16" posref="TL TL"
|
||
|
group_onclick_r="active_menu"
|
||
|
group_params_r="menu=ui:interface:base_menu_with_color"
|
||
|
>
|
||
|
|
||
|
<ctrl style="button_ok" id="help" active="true" x="-16" y="0" posref="MR MR" color="255 255 255 255"
|
||
|
text_y="-2" onclick_l="lua" params_l="r2.displayFeatureHelp(']]..featureName..[[')" hardtext="uiR2EdHelp" fontsize="10" />
|
||
|
</group>
|
||
|
]])
|
||
|
else
|
||
|
add([[<group id="header_opened" x="0" y="0" w="430" h="16" posref="TL TL"
|
||
|
group_onclick_r="active_menu"
|
||
|
group_params_r="menu=ui:interface:base_menu_with_color"
|
||
|
>
|
||
|
</group>]])
|
||
|
end
|
||
|
|
||
|
|
||
|
add([[
|
||
|
<group id="content" x="0" y="-4" sizeref="wh" w="0" h="0" posref="TL TL" >
|
||
|
<group id="enclosing" sizeref="wh" posref="TL TL" x="0" y="-4" w="0">
|
||
|
|
||
|
<group id="rollouts" sizeref="w" w="]] .. rolloutsW .. [[" posref="TL TL" x="]] .. rolloutsX .. [[" y="0" max_h="-4" max_sizeref="h" child_resize_h="true"
|
||
|
child_resize_hmargin="4"
|
||
|
>
|
||
|
|
||
|
]])
|
||
|
|
||
|
|
||
|
|
||
|
-- sort properties by category
|
||
|
local categories = {}
|
||
|
local numCategories = 0
|
||
|
for key, prop in pairs(class.Prop) do
|
||
|
if prop.Visible ~= false then
|
||
|
local category = prop.Category
|
||
|
if category == nil then
|
||
|
category = "uiR2EDRollout_Default"
|
||
|
end
|
||
|
if categories[category] == nil then
|
||
|
--debugInfo("Adding new category " .. tostring(category))
|
||
|
-- create a new table if no entries for that category of properties
|
||
|
categories[category] = {}
|
||
|
numCategories = numCategories + 1
|
||
|
end
|
||
|
table.insert(categories[category], prop)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
local posparent = "parent"
|
||
|
local posref= "TL TL"
|
||
|
local rolloutY = -4
|
||
|
|
||
|
-- if there's a xml property sheet header, use it
|
||
|
if class.PropertySheetHeader then
|
||
|
-- enclose the header in a group to keep good width
|
||
|
|
||
|
add([[<group id="sheet_header" posref="TL TL" y="-4" sizeref="w" child_resize_h="true" child_resize_hmargin="0">]] ..
|
||
|
class.PropertySheetHeader ..
|
||
|
[[</group>]]
|
||
|
)
|
||
|
posref="BL TL"
|
||
|
posparent="sheet_header"
|
||
|
end
|
||
|
|
||
|
-- if there's just a 'default' category, then don't create a rollout
|
||
|
if numCategories == 1 and categories["uiR2EDRollout_Default"] ~= nil then
|
||
|
add(self:createPropertyXmlTable(categories["uiR2EDRollout_Default"], className, posparent, posref, 0, rolloutY, widgetEventHandlerTable))
|
||
|
posparent="prop_table"
|
||
|
else
|
||
|
-- add each rollout and its properties
|
||
|
rolloutY = -2
|
||
|
local categoryIndex = 0
|
||
|
for k, v in pairs(categories) do
|
||
|
add(self:buildPropRolloutXml(k, tostring(categoryIndex), posparent, posref, v, className, rolloutY, widgetEventHandlerTable, isForm))
|
||
|
posparent = tostring(categoryIndex)
|
||
|
posref ="BL TL"
|
||
|
rolloutY = -4
|
||
|
categoryIndex = categoryIndex + 1
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- if the dialog is a form, then add 'ok' & 'cancel' button
|
||
|
if isForm then
|
||
|
add([[ <group id="okcancel" posparent="]] .. posparent .. [[" posref="BL TL" y="-4" sizeref="w" child_resize_h="true">
|
||
|
<ctrl style="text_button_16" id="validate" posref="MM ML" x="12" wmargin="8" color="255 255 255 255" col_over="255 255 255 255" col_pushed="255 255 255 255" onclick_l="lua" params_l="r2:validateForm(getUICaller().parent:getEnclosingContainer())" hardtext="uiR2EDValidateForm"/>
|
||
|
<ctrl style="text_button_16" id="cancel" posref="MM MR" x="8" wmargin="8" color="255 255 255 255" col_over="255 255 255 255" col_pushed="255 255 255 255" onclick_l="lua" params_l="r2:cancelForm(getUICaller().parent:getEnclosingContainer())" hardtext="uiR2EDCancelForm"/>
|
||
|
</group>
|
||
|
]])
|
||
|
end
|
||
|
|
||
|
|
||
|
-- close the dialog
|
||
|
add([[ </group> <!-- rollout --> ]])
|
||
|
if not isForm then
|
||
|
-- scroll bar for property sheet only
|
||
|
add([[ <ctrl style="skin_scroll" id="scroll_bar" align="T" target="rollouts" y="4"/>]])
|
||
|
end
|
||
|
add([[
|
||
|
</group> <!-- enclosing -->
|
||
|
</group> <!-- content -->
|
||
|
</group>
|
||
|
<tree node=]] .. strify(id) .. [[ >
|
||
|
</tree>
|
||
|
]])
|
||
|
|
||
|
|
||
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
-- THE REGISTRATION FUNCTION, called after the ui has been created for real from the xml definition
|
||
|
local function registrationFunction()
|
||
|
local propertySheet = getUI("ui:interface:" .. id) -- tmp : hardcoded name here
|
||
|
local form = propertySheet -- alias, if the dialog is actually a form
|
||
|
local propNameToWidget = {}
|
||
|
local propNameToLCaption= {}
|
||
|
local propNameToRCaption= {}
|
||
|
-- keep a pointer to each widget
|
||
|
-- can only do it now, because this registration is called only once the ui has been created
|
||
|
for k, prop in pairs(class.Prop) do
|
||
|
propNameToWidget[prop.Name] = propertySheet:find(prop.Name)
|
||
|
propNameToLCaption[prop.Name] = propertySheet:find("l_" .. prop.Name)
|
||
|
propNameToRCaption[prop.Name] = propertySheet:find("r_" .. prop.Name)
|
||
|
end
|
||
|
-- Fucntion to retrieve a reference on the currently edited object
|
||
|
local function getTargetInstance()
|
||
|
if isForm then
|
||
|
return form.Env.FormInstance
|
||
|
else
|
||
|
return r2:getPropertySheetTarget()
|
||
|
end
|
||
|
end
|
||
|
------------------------------------------------------
|
||
|
if propertySheet ~= nil then -- should not be nil if parsing succeeded
|
||
|
-- create a handleEvent function and put it in the lua environment of the property sheet
|
||
|
-- (in the C++ code, each group in the interface, such as a container, has a 'Env' lua table attached to it)
|
||
|
function propertySheet.Env.handleEvent(eventName, attributeName, args)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
if propertySheet.active == false then
|
||
|
return -- no update if dialog not visible (updateAll() is called when dialog is shown again)
|
||
|
end
|
||
|
local targetInstance = getTargetInstance()
|
||
|
local widgetEventHandler = widgetEventHandlerTable[attributeName] -- closure here : use locally defined widgetEventHandlerTable
|
||
|
if widgetEventHandler == nil then
|
||
|
return -- no display for that widget
|
||
|
end
|
||
|
local handlingMethod = widgetEventHandler[eventName]
|
||
|
if handlingMethod == nil then
|
||
|
-- no handler for this event, just return
|
||
|
debugInfo("Event not handled for : " .. attributeName)
|
||
|
inspect(getTargetInstance())
|
||
|
return
|
||
|
end
|
||
|
local propWidget = propNameToWidget[attributeName] -- closure here : use locally defined propertySheet
|
||
|
-- find the name of the widget by its id
|
||
|
if propWidget == nil then
|
||
|
debugInfo("Can't retrieve widget associated with property '" .. attributeName .. "'")
|
||
|
return
|
||
|
end
|
||
|
-- call the actual event handler with the widget as its first parameter
|
||
|
handlingMethod(widgetEventHandler, propWidget, class.NameToProp[attributeName], getTargetInstance()[attributeName], unpack(args))
|
||
|
end
|
||
|
local handleEventFunction = propertySheet.Env.handleEvent
|
||
|
-- syntaxic sugar : 'setter' function for simple set operation
|
||
|
function propertySheet.Env.setter(attributeName, value)
|
||
|
table.clear(eventArgs)
|
||
|
table.insert(eventArgs, value)
|
||
|
handleEventFunction("onSet", attributeName, eventArgs)
|
||
|
end
|
||
|
local setter = propertySheet.Env.setter
|
||
|
------------------------------------------------------------------------------------------------------------------
|
||
|
-- this function is called when the property sheet is shown for the first time
|
||
|
-- in order to update its content
|
||
|
local function updateAll()
|
||
|
--debugInfo("updateAll")
|
||
|
local target = getTargetInstance()
|
||
|
if not target then return end -- 'updateAll' will be triggered at init time when
|
||
|
-- windows are positionned
|
||
|
for k, prop in pairs(class.Prop) do
|
||
|
-- update the 'visible' state of each property
|
||
|
local active = true
|
||
|
if type(prop.Visible) == "function" then
|
||
|
active = prop.Visible(target)
|
||
|
|
||
|
|
||
|
local oldActive = propNameToLCaption[prop.Name].active
|
||
|
propNameToLCaption[prop.Name].active = active
|
||
|
propNameToRCaption[prop.Name].active = active
|
||
|
|
||
|
if oldActive ~= active then
|
||
|
propNameToLCaption[prop.Name]:invalidateCoords()
|
||
|
propNameToLCaption[prop.Name]:updateCoords()
|
||
|
end
|
||
|
|
||
|
|
||
|
end
|
||
|
setter(prop.Name, target[prop.Name]) -- retrieve value from object and assign to setter
|
||
|
end
|
||
|
propertySheet:invalidateCoords()
|
||
|
propertySheet:updateCoords()
|
||
|
debugInfo("*")
|
||
|
end
|
||
|
|
||
|
propertySheet.Env.updateAll = updateAll
|
||
|
end
|
||
|
------------------------------------------------------------------------------------------------------------------
|
||
|
-- this function is called by forms or proprty sheets to update visible properties
|
||
|
-- when visibility depends on other properties
|
||
|
local function updatePropVisibility()
|
||
|
local target = getTargetInstance()
|
||
|
local modified = false
|
||
|
for k, prop in pairs(class.Prop) do
|
||
|
-- update the 'visible' state of each property
|
||
|
local active = true
|
||
|
if type(prop.Visible) == "function" then
|
||
|
local active = prop.Visible(target)
|
||
|
if active ~= propNameToLCaption[prop.Name].active then
|
||
|
modified = true
|
||
|
propNameToLCaption[prop.Name].active = active
|
||
|
propNameToRCaption[prop.Name].active = active
|
||
|
propNameToRCaption[prop.Name]:invalidateContent()
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
return modified
|
||
|
end
|
||
|
------------------------------------------------------
|
||
|
propertySheet.active = false
|
||
|
-- if this is a form, then the dialog should be resized when text is entered (for multi line texts)
|
||
|
-- (else no-op for update coords)
|
||
|
-- We should resize it by script, because by default, container impose size of their children
|
||
|
if isForm then
|
||
|
function propertySheet.Env.updateSize()
|
||
|
local rollouts = propertySheet:find("rollouts")
|
||
|
local deltaH = 40
|
||
|
propertySheet:invalidateCoords()
|
||
|
propertySheet:updateCoords()
|
||
|
local newHReal = rollouts.h_real
|
||
|
-- must resize the parent
|
||
|
local newH = newHReal + deltaH
|
||
|
local yOffset = newH - propertySheet.h
|
||
|
--propertySheet.h = newH
|
||
|
propertySheet.y = propertySheet.y + yOffset / 2
|
||
|
propertySheet.pop_min_h = newH
|
||
|
propertySheet.pop_max_h = newH
|
||
|
propertySheet:invalidateCoords()
|
||
|
propertySheet:updateCoords()
|
||
|
end
|
||
|
propertySheet.Env.updatePropVisibility = function()
|
||
|
local modified = updatePropVisibility() -- call local function defined above
|
||
|
-- for forms, update size if content was modified
|
||
|
if modified then
|
||
|
propertySheet.Env.updateSize()
|
||
|
end
|
||
|
end
|
||
|
else
|
||
|
propertySheet.Env.updatePropVisibility = updatePropVisibility -- call local function defined above
|
||
|
function propertySheet.Env.updateSize()
|
||
|
-- no op for property sheet (user can change the size of the window)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
return result, registrationFunction
|
||
|
end
|
||
|
|
||
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||
|
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- called when the user has clicked on a rollout
|
||
|
-- TODO nico : also used by the scenario window, so factor the code
|
||
|
function r2:setRolloutOpened(rollout, content, opened)
|
||
|
if not rollout or not content then
|
||
|
debugInfo("r2:setRolloutOpened : rollout or content is nil")
|
||
|
return
|
||
|
end
|
||
|
content.active = opened
|
||
|
rollout:find("open_indicator").opened.active = opened
|
||
|
rollout:find("open_indicator").closed.active = not opened
|
||
|
end
|
||
|
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
function r2:buildAllPropertySheetsAndForms()
|
||
|
-- TMP TMP
|
||
|
--SeenNames = {}
|
||
|
--SeenRolloutCaptions = {}
|
||
|
local xmlScript = ""
|
||
|
local registrationFunctions = {}
|
||
|
--debugInfo('building property sheets')
|
||
|
local mustReparse = false
|
||
|
for k, class in pairs(r2.Classes) do
|
||
|
-- only build if class require a property sheet
|
||
|
--if class.BuildPropertySheet == true then
|
||
|
if true then
|
||
|
-- to avoid costly parsing, see in the cache if the class was not already parsed
|
||
|
local mustRebuild = true
|
||
|
local propSheetCacheInfo
|
||
|
if class.ClassMethods then
|
||
|
propSheetCacheInfo = class.ClassMethods.getGenericPropertySheetCacheInfos(class)
|
||
|
if r2ClassDescCache[class.Name] ~= nil then
|
||
|
if isEqualIgnoreFunctions(r2ClassDescCache[class.Name], propSheetCacheInfo) then
|
||
|
mustRebuild = false
|
||
|
else
|
||
|
debugInfo("Class " .. class.Name .. " found in cache, but different, rebuilding")
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
local result, registerFunc = r2:buildPropertySheetXml(class, class.Name, "r2ed_property_sheet_" .. class.Name, "uiR2EDProperties", false)
|
||
|
table.insert(registrationFunctions, registerFunc)
|
||
|
if mustRebuild then
|
||
|
xmlScript = xmlScript .. result
|
||
|
mustReparse = true
|
||
|
r2ClassDescCache[class.Name] = propSheetCacheInfo -- update cache
|
||
|
--debugInfo("Rebuilding property sheet")
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
-- register feature Forms
|
||
|
do
|
||
|
local k, feature = next (r2.Features, nil)
|
||
|
while k do
|
||
|
if feature.registerForms then
|
||
|
feature.registerForms()
|
||
|
end
|
||
|
k, feature = next (r2.Features, k)
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- register userComponentManager forms
|
||
|
do
|
||
|
if r2_core.UserComponentManager then
|
||
|
debugInfo("Registering UserComponentManager forms...")
|
||
|
r2_core.UserComponentManager.registerForms()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
--debugInfo('building forms')
|
||
|
if r2.Forms ~= nil then
|
||
|
for formName, form in pairs(r2.Forms) do
|
||
|
local mustRebuild = true
|
||
|
if r2FormsCache[formName] ~= nil then
|
||
|
if isEqualIgnoreFunctions(r2FormsCache[formName], form.Prop) then
|
||
|
mustRebuild = false
|
||
|
end
|
||
|
end
|
||
|
local result, registerFunc = r2:buildPropertySheetXml(form, formName, "r2ed_form_" .. formName, "uiR2EDForm", true)
|
||
|
table.insert(registrationFunctions, registerFunc)
|
||
|
if mustRebuild then
|
||
|
xmlScript = xmlScript .. result
|
||
|
mustReparse = true
|
||
|
r2FormsCache[formName] = form.Prop -- updating cache
|
||
|
--debugInfo("Rebuilding property form")
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
--debugInfo('parsing')
|
||
|
if mustReparse then
|
||
|
debugInfo(colorTag(255, 0, 255) .. "Reparsing generated xml")
|
||
|
local startTime = nltime.getLocalTime()
|
||
|
-- TMP TMP
|
||
|
--local f = io.open("testui.log", "w")
|
||
|
--f:write(r2:encloseXmlScript(xmlScript))
|
||
|
--f:flush()
|
||
|
--f:close()
|
||
|
parseInterfaceFromString(ucstring(r2:encloseXmlScript(xmlScript)):toUtf8())
|
||
|
local endTime = nltime.getLocalTime()
|
||
|
debugInfo(string.format("Reparsing generated xml took %f second", (endTime - startTime) / 1000))
|
||
|
end
|
||
|
-- do the registration
|
||
|
for k, regFunc in pairs(registrationFunctions) do
|
||
|
regFunc()
|
||
|
end
|
||
|
-- center all windows at start
|
||
|
local function initPropertySheetPos(wnd)
|
||
|
if wnd == nil then return end
|
||
|
wnd.active = true
|
||
|
r2:initDefaultPropertyWindowPosition(wnd) -- position definition in r2_ui_windows.lua
|
||
|
wnd.active = false
|
||
|
end
|
||
|
--
|
||
|
for k, class in pairs(r2.Classes) do
|
||
|
-- only build if class require a property sheet
|
||
|
if class.BuildPropertySheet == true then
|
||
|
--debugInfo('*3')
|
||
|
local wnd = getUI(r2:getDefaultPropertySheetUIPath(class.Name))
|
||
|
if wnd ~= nil then
|
||
|
r2:adjustPropertySheetTitleClampSize(wnd)
|
||
|
initPropertySheetPos(wnd)
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
if r2.Forms ~= nil then
|
||
|
-- for formName, form in pairs(r2.Forms) do
|
||
|
for formName, form in pairs(r2.Forms) do
|
||
|
local wnd = r2:getForm(formName)
|
||
|
if wnd then
|
||
|
|
||
|
-- prevent update of window content here (no selection exists)
|
||
|
local oldOnActiveParams = wnd.on_active_params
|
||
|
local oldOnDeactiveParams = wnd.on_deactive_params
|
||
|
wnd.on_active_params = ""
|
||
|
wnd.on_deactive_params = ""
|
||
|
wnd.active = true
|
||
|
r2:adjustPropertySheetTitleClampSize(wnd)
|
||
|
wnd.Env.updateSize()
|
||
|
wnd.active = false
|
||
|
wnd.on_active_params = oldOnActiveParams
|
||
|
wnd.on_deactive_params = oldOnDeactiveParams
|
||
|
|
||
|
|
||
|
--wnd.active = true
|
||
|
--wnd:invalidateCoords()
|
||
|
--wnd:updateCoords()
|
||
|
--local maxH = wnd:find("rollouts").h_real
|
||
|
--wnd.pop_max_h = maxH + 40
|
||
|
--wnd.pop_min_h = maxH + 40
|
||
|
--wnd:center()
|
||
|
--wnd:invalidateCoords()
|
||
|
--wnd:updateCoords()
|
||
|
--wnd:center()
|
||
|
-- force the y size (no scroll) by evaluating content size
|
||
|
--wnd.active = false
|
||
|
end
|
||
|
end
|
||
|
-- end
|
||
|
end
|
||
|
|
||
|
-- force to center all windows at start
|
||
|
--debugInfo('*4')
|
||
|
initPropertySheetPos(getUI("ui:interface:r2ed_property_sheet_no_properties"))
|
||
|
initPropertySheetPos(getUI("ui:interface:r2ed_property_sheet_no_selection"))
|
||
|
|
||
|
--debugInfo('*5')
|
||
|
end
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- TMP
|
||
|
function r2:testPropertySheet()
|
||
|
-- tmp
|
||
|
local result, registrationFunction = r2:buildPropertySheetXml(r2.Classes.MapDescription, "r2ed_property_sheet")
|
||
|
-- parse & register
|
||
|
parseInterfaceFromString(r2:encloseXmlScript(result)) -- parseInterfaceFromString :C++ function exported from the interface manager to parse an new interface
|
||
|
-- from its xml description
|
||
|
registrationFunction()
|
||
|
local propertySheet = getUI("ui:interface:r2ed_property_sheet")
|
||
|
if propertySheet ~= nil then
|
||
|
propertySheet.active = false
|
||
|
propertySheet.active = true -- force an update
|
||
|
propertySheet:center()
|
||
|
updateAllLocalisedElements()
|
||
|
end
|
||
|
end
|
||
|
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- Displayer to update the content of the property sheet
|
||
|
local propertySheetDisplayerTable = {}
|
||
|
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onCreate(instance)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onErase(instance)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onPreHrcMove(instance)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onPostHrcMove(instance)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onFocus(instance, hasFocus)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onSelect(instance, isSelected)
|
||
|
end
|
||
|
|
||
|
------------------------------------------------
|
||
|
-- handle an event on a property, possibly with additionnal parameters
|
||
|
function propertySheetDisplayerTable:handleAttrEvent(eventName, instance, attributeName, args)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
local class = instance:getClass()
|
||
|
if not class.BuildPropertySheet then
|
||
|
return false
|
||
|
end
|
||
|
local propertySheet = r2:getPropertySheet(instance)
|
||
|
if propertySheet == nil or propertySheet.active == false then
|
||
|
return false
|
||
|
end
|
||
|
--debugInfo("Property sheet test")
|
||
|
--debugInfo(ct .. "Instance " .. instance.InstanceId .." has an attribute modified : " .. attributeName)
|
||
|
-- call event handler into the ui
|
||
|
propertySheet.Env.handleEvent(eventName, attributeName, args)
|
||
|
return true
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onAttrModified(instance, attributeName, indexInArray)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
if self.handleAttrEvent and self:handleAttrEvent("onSet", instance, attributeName, emptyArgs) then
|
||
|
-- special case for "Name" : title of the container depends on it
|
||
|
-- update if the property sheet is visible
|
||
|
local propertySheet = r2:getPropertySheet(instance)
|
||
|
if propertySheet then
|
||
|
if attributeName == "Name" and instance == r2:getSelectedInstance() then
|
||
|
propertySheet.uc_title = concatUCString(i18n.get("uiRE2DPropertiesOf"), instance:getDisplayName())
|
||
|
end
|
||
|
propertySheet.Env.updatePropVisibility()
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onTargetInstanceCreated(instance, refIdName, refIdIndexInArray)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
self:handleAttrEvent("onTargetCreated", instance, refIdName, emptyArgs)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onTargetInstanceErased(instance, refIdName, refIdIndexInArray)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
self:handleAttrEvent("onTargetErased", instance, refIdName, emptyArgs)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onTargetInstancePreHrcMove(instance, refIdName, refIdIndexInArray)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
self:handleAttrEvent("onTargetPreHrcMove", instance, refIdName, emptyArgs)
|
||
|
end
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onTargetInstancePostHrcMove(instance, refIdName, refIdIndexInArray)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
self:handleAttrEvent("onTargetPostHrcMove", instance, refIdName, emptyArgs)
|
||
|
end
|
||
|
|
||
|
------------------------------------------------
|
||
|
function propertySheetDisplayerTable:onTargetInstanceAttrModified(instance, refIdName, refIdIndexInArray, targetAttrName, targetAttrIndexInArray)
|
||
|
-- TODO nico : arrays not handled yet
|
||
|
--debugInfo(tostring(refIdName))
|
||
|
--debugInfo(tostring(refIdIndexInArray))
|
||
|
--debugInfo(tostring(targetAttrName))
|
||
|
--debugInfo(tostring(targetAttrIndexInArray))
|
||
|
table.clear(eventArgs)
|
||
|
table.insert(eventArgs, targetAttrName)
|
||
|
table.insert(eventArgs, targetAttrIndexInArray)
|
||
|
self:handleAttrEvent("onTargetAttrModified", instance, refIdName) -- additionnal parameters
|
||
|
end
|
||
|
|
||
|
function r2:propertySheetDisplayer()
|
||
|
return propertySheetDisplayerTable -- generic property displayer is shared by all instance
|
||
|
end
|
||
|
|
||
|
|
||
|
-- last coordinate of property window (for generic property window)
|
||
|
r2.PropertyWindowCoordsBackup = nil
|
||
|
|
||
|
-- see if a property sheet window coords must be backuped
|
||
|
function r2:getPropertySheetBackupFlag(wnd)
|
||
|
local result = true
|
||
|
if not wnd then return false end
|
||
|
local targetInstance = wnd.Env.TargetInstance
|
||
|
if targetInstance then
|
||
|
local targetClass = r2:getClass(targetInstance)
|
||
|
if targetClass and not targetClass.isNil then
|
||
|
result = defaulting(targetClass.BackupPropertySheetSize, true)
|
||
|
end
|
||
|
end
|
||
|
return result
|
||
|
end
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- 'show properties' handler : display properties for selected instance
|
||
|
-- TODO nico : maybe would better fit inside 'r2_ui_windows.lua' ?
|
||
|
function r2:showProperties(instance)
|
||
|
|
||
|
r2.PropertyWindowVisible = false
|
||
|
-- alias on r2.PropertyWindowCoordsBackup
|
||
|
local wndCoord = r2.PropertyWindowCoordsBackup
|
||
|
-- hide previous window
|
||
|
if r2:getPropertySheetBackupFlag(r2.CurrentPropertyWindow) then
|
||
|
wndCoord = r2:backupWndCoords(r2.CurrentPropertyWindow)
|
||
|
end
|
||
|
if r2.CurrentPropertyWindow then
|
||
|
r2.CurrentPropertyWindow.active = false
|
||
|
end
|
||
|
local newPropWindow
|
||
|
if instance == nil then
|
||
|
-- display the 'no selected instance window'
|
||
|
newPropWindow = getUI("ui:interface:r2ed_property_sheet_no_selection")
|
||
|
else
|
||
|
local class = instance:getClass()
|
||
|
if class.BuildPropertySheet ~= true then
|
||
|
newPropWindow = getUI("ui:interface:r2ed_property_sheet_no_properties")
|
||
|
else
|
||
|
newPropWindow = r2:getPropertySheet(instance)
|
||
|
end
|
||
|
end
|
||
|
r2.CurrentPropertyWindow = newPropWindow
|
||
|
|
||
|
if newPropWindow ~= nil then
|
||
|
if instance ~= nil then
|
||
|
newPropWindow.Env.TargetInstance = instance -- set the instance being edited
|
||
|
end
|
||
|
newPropWindow.active = false
|
||
|
newPropWindow:invalidateCoords()
|
||
|
newPropWindow.active = true
|
||
|
r2.PropertyWindowVisible = true
|
||
|
-- see if window want to restore size from previous property sheet (for generic property windows)
|
||
|
if r2:getPropertySheetBackupFlag(r2.CurrentPropertyWindow) then
|
||
|
if wndCoord ~= nil then
|
||
|
newPropWindow.x = wndCoord.x
|
||
|
newPropWindow.y = wndCoord.y
|
||
|
newPropWindow.w = math.max(wndCoord.w, newPropWindow.w)
|
||
|
newPropWindow.h = math.max(wndCoord.h, newPropWindow.h)
|
||
|
end
|
||
|
end
|
||
|
if instance and instance:getClass().BuildPropertySheet then
|
||
|
newPropWindow.uc_title = concatUCString(i18n.get("uiRE2DPropertiesOf"), instance:getDisplayName())
|
||
|
end
|
||
|
end
|
||
|
r2.CurrentPropertyWindow = newPropWindow
|
||
|
|
||
|
return newPropWindow
|
||
|
end
|
||
|
|
||
|
|
||
|
r2.CurrentForm = nil
|
||
|
|
||
|
------------------------------------------------------------------------------------------------------------
|
||
|
-- display a form with the given init parameters, & call a function to notify when ok has been pressed
|
||
|
-- the callback is called with
|
||
|
function r2:doForm(formName, initialTable, validateCallback, cancelCallback)
|
||
|
if r2.CurrentForm then r2:cancelForm(r2.CurrentForm) end
|
||
|
local form = r2.Forms[formName]
|
||
|
if form == nil then
|
||
|
debugInfo("<r2:doForm> Can't retrieve form with name " .. tostring(formName))
|
||
|
return
|
||
|
end
|
||
|
if form.Prop == nil then
|
||
|
debugInfo("<r2:doForm> no properties found for form with name " .. tostring(formName))
|
||
|
return
|
||
|
end
|
||
|
local formUI = r2:getForm(formName)
|
||
|
if form.Prop == nil then
|
||
|
debugInfo("<r2:doForm> can't find ui for form with name " .. tostring(formName))
|
||
|
return
|
||
|
end
|
||
|
-- fill all properties with their default values
|
||
|
for k, prop in pairs(form.Prop) do
|
||
|
if initialTable[prop.Name] == nil then
|
||
|
if prop.Default ~= nil then
|
||
|
initialTable[prop.Name] = prop.Default
|
||
|
else
|
||
|
-- TODO nico : add a table here when more types are available
|
||
|
if prop.Type == "String" then
|
||
|
initialTable[prop.Name] = ""
|
||
|
else
|
||
|
initialTable[prop.Name] = 0
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
--
|
||
|
formUI.Env.Choice = nil -- no choice made yet
|
||
|
formUI.Env.Form = form
|
||
|
formUI.Env.FormInstance = initialTable
|
||
|
formUI.Env.onValidate = validateCallback
|
||
|
formUI.Env.onCancel = cancelCallback
|
||
|
-- TMP for debug : directly call the callback
|
||
|
--validateCallback(formUI.Env.FormInstance)
|
||
|
|
||
|
formUI.active = true
|
||
|
formUI.Env.updateAll()
|
||
|
formUI.Env.updateSize()
|
||
|
formUI:updateCoords()
|
||
|
formUI:center()
|
||
|
formUI:updateCoords()
|
||
|
if form.Caption ~= nil then
|
||
|
formUI.uc_title = i18n.get(form.Caption)
|
||
|
else
|
||
|
formUI.uc_title = i18n.get("uiR2EDForm")
|
||
|
end
|
||
|
r2.CurrentForm = formUI
|
||
|
if type(form.onShow) == "function" then
|
||
|
form.onShow(initialTable)
|
||
|
end
|
||
|
--runAH(nil, "enter_modal", "group=" .. formUI.id)
|
||
|
end
|
||
|
|
||
|
-- called when the user hit the 'ok' boutton of a form
|
||
|
function r2:validateForm(form)
|
||
|
form.Env.Choice="Ok"
|
||
|
form.active = false
|
||
|
if form.Env.onValidate then
|
||
|
form.Env.onValidate(form.Env.FormInstance, form)
|
||
|
end
|
||
|
|
||
|
--r2.CurrentForm = nil
|
||
|
end
|
||
|
|
||
|
-- called when the user hit the 'cancel' boutton of a form
|
||
|
function r2:cancelForm(form)
|
||
|
form.Env.Choice="Cancel"
|
||
|
form.active = false
|
||
|
r2.CurrentForm = nil
|
||
|
if form.Env.onCancel then
|
||
|
form.Env.onCancel(form.Env.FormInstance, form)
|
||
|
end
|
||
|
|
||
|
end
|
||
|
|
||
|
-- test if there's an help button in the window. If so, clamp more of the title
|
||
|
function r2:adjustPropertySheetTitleClampSize(wnd)
|
||
|
if wnd.header_opened == nil then return end
|
||
|
local helpBut = wnd.header_opened.help
|
||
|
if helpBut ~= nil and helpBut.active then
|
||
|
helpBut:getViewText():updateCoords()
|
||
|
helpBut:updateCoords()
|
||
|
if wnd.title_delta_max_w == r2.DefaultPropertySheetTitleClampSize then
|
||
|
wnd.title_delta_max_w = wnd.title_delta_max_w - helpBut.w_real - 4
|
||
|
end
|
||
|
end
|
||
|
end
|
||
|
|
||
|
-- test of forms
|
||
|
function r2:testForm()
|
||
|
local function onOk(resultTable)
|
||
|
debugInfo('ok was pressed')
|
||
|
inspect(resultTable)
|
||
|
end
|
||
|
local function onCancel()
|
||
|
debugInfo('cancel was pressed')
|
||
|
end
|
||
|
r2:doForm("TestForm", {}, onOk, onCancel)
|
||
|
end
|
||
|
|
||
|
--function mysetDbProp(dbpath, value)
|
||
|
-- debugInfo("Setting " .. dbpath .. " to " .. tostring(value))
|
||
|
-- setDbProp(dbpath, value)
|
||
|
--end
|
||
|
|
||
|
--function mygetDbProp(dbPath)
|
||
|
-- debugInfo("Getting" .. dbPath .. " -> value is " .. tostring(getDbProp(dbPath)))
|
||
|
-- return getDbProp(dbPath)
|
||
|
--end
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
function r2:onContAlphaSettingsChanged(dbPath)
|
||
|
--debugInfo("onContAlphaSettingsChanged " .. dbPath)
|
||
|
--debugInfo('1')
|
||
|
local cont = getUICaller()
|
||
|
setDbProp("UI:SAVE:" .. dbPath ..":CONTAINER_ALPHA", cont.container_alpha)
|
||
|
setDbProp("UI:SAVE:" .. dbPath ..":CONTENT_ALPHA", cont.content_alpha)
|
||
|
setDbProp("UI:SAVE:" .. dbPath ..":ROLLOVER_CONTENT_ALPHA", cont.rollover_content_alpha)
|
||
|
setDbProp("UI:SAVE:" .. dbPath ..":ROLLOVER_CONTAINER_ALPHA", cont.rollover_container_alpha)
|
||
|
setDbProp("UI:SAVE:" .. dbPath ..":USE_GLOBAL_ALPHA_SETTINGS", select(cont.use_global_alpha_settings, 1, 0))
|
||
|
--debugInfo('2')
|
||
|
end
|
||
|
|
||
|
-- called by action handler attached to the container when alpha settings of a property sheets have been modified
|
||
|
function r2:onPropertySheetAlphaSettingsChanged()
|
||
|
--debugInfo("onPropertySheetAlphaSettingsChanged")
|
||
|
r2:onContAlphaSettingsChanged("R2_PROP_SHEET")
|
||
|
end
|
||
|
|
||
|
-- called by action handler attached to the container when alpha settings of a form have been modified
|
||
|
function r2:onFormAlphaSettingsChanged()
|
||
|
--debugInfo("onFormAlphaSettingsChanged")
|
||
|
r2:onContAlphaSettingsChanged("R2_FORM")
|
||
|
end
|
||
|
|
||
|
-- called by action handler attached to the container when it is opened to restore
|
||
|
-- its alpha settings from the databse (this is because all prop / forms window share the same alpha settings)
|
||
|
function r2:restoreContAlphaSettings(dbPath)
|
||
|
--debugInfo('restoreContAlphaSettings ' .. dbPath)
|
||
|
local cont = getUICaller()
|
||
|
local oldHandler = cont.on_alpha_settings_changed
|
||
|
cont.on_alpha_settings_changed = ""
|
||
|
cont.container_alpha = getDbProp("UI:SAVE:" .. dbPath ..":CONTAINER_ALPHA")
|
||
|
cont.content_alpha = getDbProp("UI:SAVE:" .. dbPath ..":CONTENT_ALPHA")
|
||
|
cont.rollover_content_alpha = getDbProp("UI:SAVE:" .. dbPath ..":ROLLOVER_CONTENT_ALPHA")
|
||
|
cont.rollover_container_alpha = getDbProp("UI:SAVE:" .. dbPath ..":ROLLOVER_CONTAINER_ALPHA")
|
||
|
local use_global_alpha_settings = getDbProp("UI:SAVE:" .. dbPath ..":USE_GLOBAL_ALPHA_SETTINGS")
|
||
|
--debugInfo("use_global_alpha_settings = " .. tostring(use_global_alpha_settings))
|
||
|
cont.use_global_alpha_settings = use_global_alpha_settings ~= 0
|
||
|
cont.on_alpha_settings_changed = oldHandler
|
||
|
end
|
||
|
|