khanat-opennel-code/code/ryzom/common/data_common/r2/r2_base_class.lua

871 lines
34 KiB
Lua
Raw Normal View History

2014-09-18 19:54:34 +00:00
---------------------------------------------
-- Base class for R2 components / features --
---------------------------------------------
-- NB : throughout the file 'this' is used instead of the lua 'self' to denote the fact
-- that method are not called on the class definition, but on the instances of this class
baseClass = -- not local here because of the implementation ...
{
----------------------
-- CLASS PROPERTIES --
----------------------
BaseClass = "", -- Name of the base class
Version = 0,
Name = "BaseClass", -- Name of the class
BuildPropertySheet = true, -- True if objects of this class should be editable by using a generic property sheet
-- Setting to 'true' will cause the framework to create the property sheet ui at launch
Menu="", -- ui path of the contextual menu for this class
--
DisplayerUI = "", -- name of the C++ class that displays this object in the ui
DisplayerUIParams = "", -- parameters passed to the ui displayer when it is created
--
DisplayerProperties = "R2::CDisplayerLua", -- 'lua' type of displayer takes the name of a lua function that must return the class of the displayer
DisplayerPropertiesParams = "propertySheetDisplayer", -- name of the function that build the displayer that update the property sheet.
--
TreeIcon="", -- icon to be displayed in the tree (or a method returning it)
PermanentTreeIcon="", -- icon to be displayed in the tree if in permanent content (or a method returning it)
SelectBarType = "", -- type in select bar
-- rollout header for the generic property sheet (a string giving the xml code for the header)
PropertySheetHeader = nil,
-------------------
-- CLASS METHODS --
-------------------
ClassMethods = {},
--------------------------
-- INSTANCES PROPERTIES --
--------------------------
-- * Unlike class properties above, they are created in each instance of the class. They are directly accessible in the objects.
-- * They are C++ objects exposed through the metatable mechanism
-- * They are *READ-ONLY*. They should be modified by network commands like r2.requestSetNode and the like
-- To store client side transcient values, use the native property 'User' (detailed below) instead
-- TODO complete doc (available types, widgets ...)
Prop =
{
{Name="InstanceId", Type="String", WidgetStyle="StaticText", Category="Advanced", Visible=false },
},
-- 'VIRTUAL' PROPERTIES (NOT IMPLEMENTED)
-- Not really properties of this class, but 'shortcuts' to other, real properties
-- The virtual properties are use by the property sheet to display properties than are jnot directly in the object,
-- but that can be found in another place. (son object for example, or object that require an indirection)
-- each virtual prop should provide a 'getPath' function which takes the InstanceId of the instance in which it is contained as its parameter
-- It should return a couple : realOwnerInstanceId, realPropName (arrays not supported yet)
-- an observer is placed on the real property to take its changes in account in the property sheet
-- IMPORTANT: the getPath function will be called each frame to see if observers should be removed
-- and placed on another target
-- Example : indirection to fictive string property 'Toto' in the Scenario
--VirtualProp =
--{
-- {Name="InstanceId", Type="String", WidgetStyle="StaticText", Category="Advanced", Visible=true,
-- getPath = function()
-- return r2.Scenario.InstanceId, "Toto"
-- end,
-- },
--},
---------------------------------
-- NATIVE / SPECIAL PROPERTIES --
---------------------------------
-- They are implemented in C++ (thanks to the lua metatables)
-- Parent : (R/O) : The direct parent of this object. If parent object is in a table, returns the table
-- ParentInstance : (R/O) : Next parent of this object with an InstanceId. In object is contained in a property that
-- is a table, the object containing the table will be returned, not the table
-- IndexInParent : (R/O) : If parent is a table, then return index into it, -1 otherwise
-- User : Read/Write lua table attached to the object. The 'User' field itself is R/O This is the place to store client side
-- edition variables.
-- Size : (R/O) : If object is a table, returns its size, nil otherwise
-- DisplayerUI : (R/O) : for instances : returns reference to the ui displayer. May be nil.
-- In the case where the field 'DisplayerUI' of this class definition id 'R2::CDisplayerLua', it would return
-- the displayer object created by a call to the function defined in 'DisplayerUIParams' (in this class definition)
-- DisplayerVisual : (R/O) : Same as DisplayerUI but for 'in scene' displayer
-- DisplayerProperties : (R/O) : Same as DisplayerUI but for the properties displayer
-- Selectable : (R/W) : default is true. When false, the object can't be selected in the scene. This flag is local to the instance (ancestor state not inherited)
-- SelectableFromRoot : (R/O) : True if this object and also its ancestor are selectable
------------
-- EVENTS --
------------
-- Events that are sent to the displayers, are also sent to instances that hold those displayers :
-- By default they are not handled
-- To handle, one shouldd redefine :
-- function baseClass.onCreate(this)
-- function baseClass.onErase(this)
-- etc ...
-- see r2_ui_displayers.lua for details
}
---------------------
-- GENERAL METHODS --
---------------------
-- Methods are defined in the class definition and are nevertheless callable on instances as follow :
-- instance:methodName(params ...)
-- In the class, the method would be defined as follow:
-- methodName = function(this, param1, param2 ...) ... some code ... end
-- 'this' will be filled at runtime by a reference on the instance on which the method is called.
-- Method calling is possible thanks to the metamethod mechanism (in this case it is implemented in C++)
-- Calling a method is in fact equivalent to doing the following :
-- r2:getClass(instance).methodName(instance, param1, param2 ..)
---------------------------------------
-- TYPE / CLASS / PROPERTIES METHODS --
---------------------------------------
---------------------------------------------------------------------------------------------------------
-- return a reference to the class of this object
function baseClass.getClass(this)
return r2:getClass(this)
end
---------------------------------------------------------------------------------------------------------
-- get description of a property (as found in the 'Prop' table of the class definition) from its name
function baseClass.getPropDesc(this, propName)
return this:getClass().NameToProp[propName]
end
---------------------------------------------------------------------------------------------------------
-- return name of the parent class
function baseClass.getClassName(this)
return this.Class
end
---------------------------------------------------------------------------------------------------------
-- test if object is of the given class (or derived from the class)
-- param 'class' should be a string identifying the class
function baseClass.isKindOf(this, className)
assert( type(this) == "userdata")
local currClass = this:getClass()
while currClass do
if currClass.Name == className then
return true
end
currClass = r2.Classes[currClass.BaseClass]
end
return false
end
---------------------------------------------------------------------------------------------------------
-- return a 'this' of the base class
-- Use this to access a method defined in a base class from a derived class
--
-- example : this:delegate():doThis() -- Call the doThis function in the parent class
--
-- Expected behavior is the same than with C++ :
-- Call from a delegated pointer is static
-- any further call is the call chain is polymorphic
-- Calls to delegate can be chained
-- NB : this function shouldn't be redefined in derived classes (the delegation mechanism uses a pointer on this function)
--function baseClass.delegate(this)
-- return __baseClassImpl.delegate(this) -- implementation defined in "r2_base_class_private.lua"
--end
---------------------------------------------------------------------------------------------------------
-- Get actual C++ "this" for this object. Because of the delegation mechanism, this may be a raw C++ object
-- or a lua table that performs the delegation
-- OBSOLETE, TO REMOVE
function baseClass.getRawThis(this)
-- return __baseClassImpl.getRawThis(this) -- implementation defined in "r2_base_class_private.lua"
return this
end
---------------------------------------------------------------------------------------------------------
-- compare current "this", with another "this" pointer
-- This should be the standard way to compare instance in memory because 'this' may sometime be a userdata
-- (raw C++ pointer to internal C++ object), or a table (delegated 'this' pointer)
-- OBSOLETE, TO REMOVE
function baseClass.isSameObjectThan(this, other)
--if this:isKindOf("Act") then
-- breakPoint()
--end
--return this:getRawThis() == other:getRawThis()
return this == other
end
---------------------------------------------------------------------------------------------------------
-- Helper : Return world position (that is, absolute position). By default, object deriving from the base class have no position
function baseClass.getWorldPos()
return { x = 0, y = 0, z = 0 }
end
---------------------------------------------------------------------------------------------------------
-- When adding content, pionneer have a limited budget. This method gives the 'cost' of this object (0 by default)
--function baseClass.getUsedQuota(this)
-- return 0
--end
-------------------
-- SCENARIO COST --
-------------------
---------------------------------------------------------------------------------------------------------
-- See wether this element has a cost in the scenario
function baseClass.hasScenarioCost(this)
return false
end
---------------------------------------------------------------------------------------------------------
-- get local cost cached in object
function baseClass.getLocalCost(this)
return defaulting(this.User.Cost, 0)
end
---------------------------------------------------------------------------------------------------------
-- set local cost in object
function baseClass.setLocalCost(this, cost)
this.User.Cost = cost
end
---------------------------------------------------------------------------------------------------------
-- get local static cost cached in object
function baseClass.getLocalStaticCost(this)
return defaulting(this.User.StaticCost, 0)
end
---------------------------------------------------------------------------------------------------------
-- set local static cost in object
function baseClass.setLocalStaticCost(this, cost)
this.User.StaticCost = cost
end
function baseClass.getStaticObjectCost(this)
return 0
end
function baseClass.getAiCost(this)
return 0
end
----------------------
-- OBJECT HIERARCHY --
----------------------
---------------------------------------------------------------------------------------------------------
-- append all sub-content that is "kind of" 'kind' to 'destTable'
-- NB : this is very SLOW!!! please use iterators instead (see r2:enumInstances)
function baseClass.appendInstancesByType(this, destTable, kind)
assert(type(kind) == "string")
if this.CompareClass and this.CompareClass == true then
if this.Class == kind then
if destTable == nil then
dumpCallStack(1)
end
table.insert(destTable, this:getRawThis())
end
elseif this:isKindOf(kind) then
if destTable == nil then
dumpCallStack(1)
end
table.insert(destTable, this:getRawThis())
end
end
---------------------------------------------------------------------------------------------------------
-- Append all instances rooted at this object (including this one)
function baseClass.getSons(this, destTable)
r2:exploreInstanceTree(this, destTable)
end
---------------------------------------------------------------------------------------------------------
-- Search first ancestor of the wanted kind (that is of class 'className' or a derived class)
function baseClass.getParentOfKind(this, className)
local parent = this.ParentInstance
while parent do
assert(parent.isKindOf)
if parent:isKindOf(className) then return parent end
parent = parent.ParentInstance
end
return nil
end
---------------------------------------------------------------------------------------------------------
-- Search parent until an act is found
function baseClass.getParentAct(this)
return this:getParentOfKind("Act")
end
---------------------------------------------------------------------------------------------------------
-- Search parent until a scenario is found
function baseClass.getParentScenario(this)
return this:getParentOfKind("Scenario")
end
---------------------------------------------------------------------------------------------------------
-- See if hits object is inserted in the default feature (that is : single npcs, bot objects, roads etc. with no enclosing group or feature)
function baseClass.isInDefaultFeature(this)
return this.ParentInstance:isKindOf('DefaultFeature')
end
--------------------------
-- UI METHODS / DISPLAY --
--------------------------
---------------------------------------------------------------------------------------------------------
-- Called by the contextual menu/toolbar when the 'delete' option is chosen by the user
-- on THIS client
-- This is the place to perform additionnal deletion tasks
-- Example : a vertex may want to delete its containing region when there are 2 vertices left only
-- default -> just call 'r2.requestEraseNode'
function baseClass.onDelete(this)
if this.User.DeleteInProgress == true then return end
this.User.DeleteInProgress = true
this:setDeleteActionName()
this:selectNext()
r2.requestEraseNode(this.InstanceId, "", -1)
r2.requestEndAction()
end
-- helper : add "delete : name_of_the_thing_being_deleted" in the action historic as the name of the delete action that is about
-- to be done
function baseClass.setDeleteActionName(this)
r2.requestNewAction(concatUCString(i18n.get("uiR2EDDeleteAction"), this:getDisplayName()))
end
---------------------------------------------------------------------------------------------------------
-- Test wether the user can delete this object
function baseClass.isDeletable(this)
if this.Deletable and this.Deletable == 0 then return false end
return true
end
---------------------------------------------------------------------------------------------------------
-- called when the instance is selected (default is no op)
function baseClass.onSelect(this)
end
---------------------------------------------------------------------------------------------------------
-- Tell if object can be selected as next object if a predecessor object
-- has been selected in the parent list
function baseClass.isNextSelectable(this)
return false
end
---------------------------------------------------------------------------------------------------------
-- get next selectable object (or nil else)
function baseClass.getNextSelectableObject(this)
local startIndex = this.IndexInParent
if type(startIndex) ~= "number" then return nil end
local currIndex = startIndex
while true do
currIndex = currIndex + 1
if currIndex == this.Parent.Size then
currIndex = 0
end
local instance = this.Parent[currIndex]
if currIndex == startIndex then break end
if instance ~= nil then
local firstSon = instance:getFirstSelectableSon()
if firstSon ~= nil and firstSon:isNextSelectable() then
return firstSon
elseif instance.Selectable and instance:isNextSelectable() then
return instance
end
end
end
if this.ParentInstance:isKindOf("DefaultFeature") then
return this.ParentInstance:getNextSelectableObject()
end
return nil
end
---------------------------------------------------------------------------------------------------------
-- select object next to this one, if there's one
function baseClass.selectNext(this)
local nextSelection = this
while 1 do
nextSelection = nextSelection:getNextSelectableObject()
if not nextSelection or nextSelection == this then
r2:setSelectedInstanceId("")
return
end
if nextSelection then
-- should not be frozen or hiden
if (not nextSelection.DisplayerVisual) or (nextSelection.DisplayerVisual.DisplayMode ~= 1 and nextSelection.DisplayerVisual.DisplayMode ~= 2) then
r2:setSelectedInstanceId(nextSelection.InstanceId)
return
end
end
end
end
---------------------------------------------------------------------------------------------------------
-- if an object is not selectable if may nevertheless contain selectable object, the first one is returned by this method
function baseClass.getFirstSelectableSon(this)
return nil
end
---------------------------------------------------------------------------------------------------------
-- get select bar type
function baseClass.getSelectBarType(this)
return r2:evalProp(this:getClass().SelectBarType, this, "")
end
---------------------------------------------------------------------------------------------------------
-- get name of tree icon
function baseClass.getTreeIcon(this)
return r2:evalProp(this:getClass().TreeIcon, this, "")
end
---------------------------------------------------------------------------------------------------------
-- get name of tree icon
function baseClass.getPermanentTreeIcon(this)
return r2:evalProp(this:getClass().PermanentTreeIcon, this, "")
end
---------------------------------------------------------------------------------------------------------
-- get name of tree icon according to permanent or current act
function baseClass.getContextualTreeIcon(this)
if this:getParentAct() and this:getParentAct():isBaseAct() then
return this:getPermanentTreeIcon()
else
return this:getTreeIcon()
end
end
---------------------------------------------------------------------------------------------------------
-- get name of permanent statut icon
function baseClass.getPermanentStatutIcon(this)
return ""
end
---------------------------------------------------------------------------------------------------------
-- get name of icon to be displayed in the slect bar
function baseClass.getSelectBarIcon(this)
return this:getContextualTreeIcon()
end
---------------------------------------------------------------------------------------------------------
-- Get the display name (in i18n format). This name will be displayed in the property sheet or inthe instance tree
function baseClass.getDisplayName(this)
local displayName = ucstring()
if this.Name ~= nil and this.Name ~= "" then
displayName:fromUtf8(this.Name)
else
return i18n.get("uiR2EDNoName")
-- local className = this.Class
-- -- tmp patch
-- if this:isKindOf("Npc") then
-- if this:isBotObject() then
-- className = "Bot object"
-- end
-- end
-- className = className .. " : " .. this.InstanceId
-- displayName:fromUtf8(className)
end
return displayName
end
---------------------------------------------------------------------------------------------------------
-- Get the base name for instance name generation (should return a ucstring)
function baseClass.getBaseName(this)
return ucstring("")
end
---------------------------------------------------------------------------------------------------------
-- return true if this instance can by displayed as a button in the select bar
function baseClass.displayInSelectBar(this)
return true
end
---------------------------------------------------------------------------------------------------------
-- get first parent that is selectable in the select bar
function baseClass.getFirstSelectBarParent(this)
local curr = this.ParentInstance
while curr and not curr:displayInSelectBar() do
curr = curr.ParentInstance
end
return curr
end
---------------------------------------------------------------------------------------------------------
-- search the first son that could be inserted in the select bar
-- default is to look recursively in the 'son select bar container'
function baseClass.getFirstSelectBarSon(this)
local sons = this:getSelectBarSons()
if not sons then return nil end
for k, v in specPairs(sons) do
if v:displayInSelectBar() then
return v
end
local firstSelectBarSon = v:getFirstSelectBarSon()
if firstSelectBarSon ~= nil then
return firstSelectBarSon
end
end
end
---------------------------------------------------------------------------------------------------------
-- test if object can have sons than are displayable in the select bar
function baseClass.canHaveSelectBarSons(this)
return false;
end
---------------------------------------------------------------------------------------------------------
-- return the default container that may contain object displayable in the select bar
function baseClass.getSelectBarSons()
return nil
end
---------------------------------------------------------------------------------------------------------
-- called by the select bar when it displays its menu. Additionnal can be added there
function baseClass.completeSelectBarMenu(rootMenu)
-- no-op
end
---------------------------------------------------------------------------------------------------------
-- The following method is called when the default ui displayer wants to know where to attach an object in the instance tree
-- Default behaviour is to return the tree node of the parent object when one is found
function baseClass.getParentTreeNode(this)
parent = this.ParentInstance
while parent ~= nil do
if parent.User.TreeNodes ~= nil then
return parent.User.TreeNodes
end
parent = parent.ParentInstance
end
return nil
end
--------------------------------------------------------------------------------------------
-- Helper function for features : return the feature parent tree node in their act
function baseClass.getFeatureParentTreeNode(this)
--return this:getParentAct():getContentTreeNodes("macro_components")
return this:getParentAct():getContentTreeNodes()
end
--------------------------------------------------------------------------------------------
-- TODO: test if the object can be exported (true by default)
function baseClass.isExportable(this)
return true
end
---------------------------------------------------------------------------------------------------------
-- This method is called by the C++ when the contextual menu is about to be displayed
function baseClass.onSetupMenu(this)
local class = r2:getClass(this)
local menuName = class.Menu
if menuName == nil then return end
local menu = getUI(menuName)
-- setup menu entries to select parents
--for i = 1,8 do
-- menu["selectParent" .. tostring(i)].active = false
--end
-- local parent = this.ParentInstance
-- for i = 1,9 do
-- if parent == nil or parent.Parent == nil then break end
-- menu["selectParent" .. tostring(i)].active = true
-- menu["selectParent" .. tostring(i)].uc_hardtext = i18n.get("uimR2EDSelectParent") + (parent.InstanceId .. " (" .. parent.Class .. ")")
-- --debugInfo(colorTag(0, 255, 255) .. tostring(i))
-- parent = parent.ParentInstance
-- end
-- -- setup cut & paste entries
-- local cuttedSelection = r2:getCuttedSelection()
-- if cuttedSelection and this.accept ~= nil then
-- local canPaste = this:accept(cuttedSelection)
-- debugInfo("canPaste = " .. tostring(canPaste))
-- menu.paste.grayed = not canPaste
-- else
-- menu.paste.grayed = true
-- end
-- debug options
local extDebug = config.R2EDExtendedDebug == 1
menu.dump_lua_table.active = extDebug
menu.inspect_lua_table.active = extDebug
menu.translateFeatures.active = extDebug
menu.dump_dialogs_as_text.active = extDebug
menu.update_dialogs_from_text.active = extDebug
menu.cut.active = extDebug
menu.paste.active = extDebug
r2.ContextualCommands:setupMenu(this, menu)
-- delete entries for dynamic content
-- local menuRoot = menu:getRootMenu()
-- local startLine = menuRoot:getLineFromId("dynamic_content_start")
-- local endLine = menuRoot:getLineFromId("dynamic_content_end")
-- assert(startLine ~= -1 and endLine ~= -1)
-- for lineToDel = endLine - 1, startLine + 1, -1 do
-- menuRoot:removeLine(lineToDel)
-- end
-- retrieve dynamic commands
-- local commands = this:getAvailableCommands()
-- local currentLine = startLine + 1
-- local commandIndex = 1
-- for commandIndex, command in commands do
-- menuRoot:addLineAtIndex(currentLine, i18n.get(command.TextId), "lua", "", "dyn_command_" .. tostring(commandIndex))
-- if there's a bitmap, build a group with the buitmap in it, and add to menu
-- if command.ButtonBitmap and command.ButtonBitmap ~= "" then
-- local menuButton = createGroupInstance("r2_menu_button", "", { bitmap = command.ButtonBitmap, })
-- if menuButton then
-- menuRoot:setUserGroupLeft(currentLine, menuButton)
-- end
-- end
--currentLine = currentLine + 1
--end
end
---------------------------------------------------------------------------------------------------------
-- Show the property window for this instance
-- (react to the event 'show properties' triggered in the ui, by contextual menu or toolbar)
function baseClass.onShowProperties(this)
-- for now a global (see r2_ui_property_sheet.lua)
r2:showProperties(this)
end
---------------------------------------------------------------------------------------------------------
-- Return list of currently available commands to launch on that instance.
-- such commands are displayed in the contextual toolbar or in the contextual menu.
-- Returned value should be an array (starting at index 1) with commands of the following format :
--
-- { DoCommand = function(instance) ..., -- code to execute when the command is triggered (by menu or toolbar)
-- -- Because the function takes 'instance' as a parameter, it may be
-- -- either a global function or a method of this class
-- Id = "", -- Id of the action. The action "r2ed_context_command" defined in actions.xml
-- -- will search for this id when a key is pressed to find the good action
-- TextId = "...", -- Text id for entry menu & toolbar tooltip
-- ButtonBitmap = "filename.tga", -- Name of the button to display in the toolbar, nil
-- -- or "" if the command should not appear in the contextual toolbar
-- Separator = "true", -- optionnal, false by default : specify if there should be a separator
-- -- between this button and previous buttons
-- ShowInMenu = false, -- false if the entry shouldn't be displayed in the menu
-- IsActivity = false -- true if event is an activity
-- }
--
-- 'getAvailableCommands' should be called by derived class, possibly adding their
-- own commands
--
-- See also : 'buildCommand'
function baseClass.getAvailableCommands(this, dest)
if this.ParentInstance:isKindOf("UserComponentHolder") then
table.insert(dest, this:buildCommand(this.onRemoveFromUserComponent, "removeFromUserComponent", "uimR2EDRemoveFromUserComponent", ""))
end
if this:isDeletable() and this.User.DeleteInProgress ~= true then
table.insert(dest, this:buildCommand(this.onDelete, "delete", "uimR2EDMenuDelete", "r2_toolbar_delete.tga"))
end
if this:getClass().BuildPropertySheet then
table.insert(dest, this:buildCommand(this.onShowProperties, "properties", "uimR2EDMenuProperties", "r2_toolbar_properties.tga", true))
end
if this:isKindOf("NpcCustom") then
table.insert(dest, this:buildCommand(this.customizeLook, "customize_look", "uiR2EDCustomizeLook", "r2_toolbar_customize_look.tga", false))
end
end
---------------------------------------------------------------------------------------------------------
-- Build a single command entry to be used by 'getAvailableCommands'
-- A command entry translates into a button in the contextual toolbar
function baseClass.buildCommand(this, command, id, textId, bitmap, separator, showInMenu)
if showInMenu == nil then showInMenu = true end
return
{
DoCommand = command,
TextId = textId,
Id = id,
ButtonBitmap = bitmap,
Separator = separator,
ShowInMenu = showInMenu,
IsActivity = false
}
end
---------------------------------------------------------------------------------------------------------
-- same as 'buildCommand', but for activities
function baseClass.buildActivityCommand(this, command, id, textId, bitmap, separator, showInMenu)
local result = this:buildCommand(command, id, textId, bitmap, separator, showInMenu)
result.IsActivity = true
return result
end
---------------------------------------------------------------------------------------------------------
-- Special, class method (not instance method) for dev : returns a table containing all infos on which the xml generic property sheet depends
-- When this table is modified, then the xml property sheet will be rebuild for this class (when 'resetEditor'
-- is called for example.
function baseClass.ClassMethods.getGenericPropertySheetCacheInfos(this)
local infos = {}
infos.Prop = this.Prop -- if one of the properties change, then must rebuild the property sheet
infos.PropertySheetHeader = this.PropertySheetHeader -- if the xml header change, then must rebuild the sheet, too
return infos
end
---------------------------------------------------------------------------------------------------------
-- get list of command for display in the mini toolbar
function baseClass.getAvailableMiniCommands(this, result)
-- OBSOLETE
-- table.insert(result, this:buildCommand(this.editDialogs, "edit_dialogs", "uiR2EDEditDialogs", "r2_icon_dialog_mini.tga"))
-- table.insert(result, this:buildCommand(this.editActions, "edit_actions", "uiR2EDEditActions", "r2_icon_action_mini.tga"))
-- table.insert(result, this:buildCommand(this.editReactions, "edit_reactions", "uiR2EDEditReactions", "r2_icon_reaction_mini.tga"))
end
---------------------------------------------------------------------------------------------------------
-- Return true if sequences can be edited on that object
function baseClass.isSequencable(this)
return false
end
---------------------------------------------------------------------------------------------------------
-- For sequencable object only (baseClass.isSequencable) : return the lookup string for a verb from an activity name
-- Indeed, an activity may have different name depending on who performs it
-- for example, the "Feed In Zone" activity will be name "work" for a worker kitin instead of "feed" for a carnivore
function baseClass.getActivityVerbLookupName(this, activityName)
return activityName
end
---------------------------------------------------------------------------------------------------------
-- is the object global to the scenario ? The select bar will call this to force the good update
-- for global objects that are selectable (plot items ...)
function baseClass.isGlobalObject(this)
return false
end
function baseClass.onRemoveFromUserComponent(this)
r2_core.CurrentHolderId = this.ParentInstance.InstanceId
r2_core:removeUserComponentElement(this.InstanceId)
end
-------------
-- REF IDS --
-------------
-- Set the value of a refId inside this object. (empty string to delete)
-- This will push a new action name & call r2.requestNode
function baseClass.setRefIdValue(this, refIdName, targetId)
local name = this:getDisplayName()
local refIdUCName = r2:getPropertyTranslation(this:getClass().NameToProp[refIdName])
if targetId == "" then
r2.requestNewAction(concatUCString(i18n.get("uiR2EDRemovingTargetAction"), name,
i18n.get("uiR2EDAddingReferenceSeparator"), refIdname))
else
local targetName = r2:getInstanceFromId(targetId):getDisplayName()
r2.requestNewAction(concatUCString(i18n.get("uiR2EDAddingReferenceAction"), name,
i18n.get("uiR2EDAddingReferenceSeparator"), refIdUCName,
i18n.get("uiR2EDAddingReferenceToAction"), targetName))
end
r2.requestSetNode(this.InstanceId, refIdName, targetId)
end
---------------------------
-- COPY / PASTE HANDLING --
---------------------------
---------------------------------------------------------------------------------------------------------
-- see if this object support copy (false by default)
function baseClass.isCopyable(this)
return false
end
---------------------------------------------------------------------------------------------------------
-- Create a canonical copy of this object, this copy can be used by subsequent calls to 'newCopy'
function baseClass.copy(this)
-- implementation in "r2_base_class_private.lua"
end
-- Create a new copy from a canonical copy
-- New instance ids are generated
-- Default behavior is to remove all external dependencies and to rename
-- internal dependencies
-- The result can be used as input to 'paste' & 'ghostPaste'
function baseClass.newCopy(canonicalCopy)
-- implementation in "r2_base_class_private.lua"
end
---------------------------------------------------------------------------------------------------------
-- Paste the current clipboard
-- not really a method here, because 'src' id a lua table (should be the content of the clipboard ...) that can be used with
-- a r2.request.. command.
-- - this function should copy the result in a suitable place (maybe into current selection, or at global scope)
-- NB : if newPlace is not true, then the result should be past at the coordinates found in src
-- - It should check that there is some room in the scenario before doing the copy
function baseClass.paste(src, newPlace, srcInstanceId)
if r2:getLeftQuota() <= 0 then
r2:makeRoomMsg()
return
end
end
function baseClass.pasteGhost(src)
if r2:getLeftQuota() <= 0 then
r2:makeRoomMsg()
return
end
end
-- TMP TMP : move events test
--
function baseClass.onTargetInstancePreHrcMove(this, targetAttr, targetIndexInArray)
debugInfo(string.format("instance: pre hrc move : %s", targetAttr))
end
--
function baseClass.onTargetInstancePostHrcMove(this, targetAttr, targetIndexInArray)
debugInfo(string.format("instance : post hrc move : %s", targetAttr))
end
-- IMPLEMENTATION
r2.doFile("r2_base_class_private.lua")
r2.registerComponent(baseClass)
baseClass = nil