2017-03-15 19:29: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