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 [[
]]
end
-- local widgetXml =
-- string.format([[
--
--
--
--
--
-- ]], prop.Name, prop.Name)
local widgetXml =
string.format([[
]]
.. buildCoverAllButton(prop) .. [[
]], 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 = [[ ]]
local tooltipTextId, tooltipTextIdFound = buildPropTooltipName(className, prop.Name)
part0 = part0 .. [["
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 .. [[ ]]
part0 = part0 .. ""
part0 = part0 .. " | "
--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([[
" .. [[
""
""
]], 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 =
[[
"
result = result .. [[]]
-- append enumerated values
for k, v in pairs(prop.Enum) do
result = result .. [[]]
end
result = result .. ""
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([[
]])
for key, prop in pairs(props) do
local widgetXmlDesc, setter, captionXmlDesc = self:buildPropWidget(prop, className)
if widgetXmlDesc ~= nil then
add("")
-- 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 = [[ ]]
part0 = part0 .. [["
part0 = part0 .. [[ ]]
part0 = part0 .. ""
part0 = part0 .. " | "
else
part0 = captionXmlDesc
end
-- build the widget
local part1 = [[ ]]
part1 = part1 .. [["
part1 = part1 .. widgetXmlDesc .. [[ | ]]
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("
")
end
end
add([[]])
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(
[[
]], id, rolloutY, posparent, posref, global_color_over, params_l)
if not isForm then
result = result ..
string.format([[
]], caption)
else
result = result ..
string.format([[]], caption)
end
result = result .. string.format(
[[
%s
]],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(
[[ ]], 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 ..
[[ ]]
else
result = result ..
[[ ]]
end
-- add the content
result = result .. content
-- close
result = result .. ""
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(
[[
]])
if className == "NpcCustom" then
add(
[[
]])
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(
[[
]])
else
add([[]])
end
add([[
]])
-- 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([[]]
)
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([[
]])
end
-- close the dialog
add([[ ]])
if not isForm then
-- scroll bar for property sheet only
add([[ ]])
end
add([[
]])
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
--///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
-- 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(" Can't retrieve form with name " .. tostring(formName))
return
end
if form.Prop == nil then
debugInfo(" no properties found for form with name " .. tostring(formName))
return
end
local formUI = r2:getForm(formName)
if form.Prop == nil then
debugInfo(" 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