578 lines
19 KiB
Lua
578 lines
19 KiB
Lua
-- réed selection bar
|
|
|
|
|
|
r2.SelectBar =
|
|
{
|
|
Content={}, -- array of instance for the current select bar that is displayed
|
|
ObserverHandles = {}, -- for each observed instance, gives its observer handle
|
|
Touched = false,
|
|
LastMenuPopper = nil, -- last instance in the scenario that popped the mnu
|
|
LastMenuHideTrigger = nil, -- last element that triggered the disparition of the select bar menu
|
|
InstancesType = "",
|
|
InstancesTypes = {
|
|
{["type"]=i18n.get("uiR2EDScene"):toUtf8(), ["icon"]="r2_palette_entities.tga" },
|
|
{["type"]=i18n.get("uiR2EDMacroComponents"):toUtf8(), ["icon"]="r2_palette_components.tga" },
|
|
{["type"]=i18n.get("uiR2EDbotObjects"):toUtf8(), ["icon"]="r2_palette_objets.tga" },
|
|
{["type"]=i18n.get("uiR2EDPlotItems"):toUtf8(), ["icon"]="ICO_mission_purse.tga" }
|
|
},
|
|
}
|
|
|
|
|
|
-- select bar observer : allows to know when a targeted object has been modified, or
|
|
-- if its name has changed
|
|
local selectBarObserver = {}
|
|
|
|
function selectBarObserver:onInstanceCreated(instance)
|
|
-- no-op
|
|
end
|
|
|
|
function selectBarObserver:onInstanceErased(instance)
|
|
-- debugInfo(tostring(instance))
|
|
-- nb : we don't use the 'instance' as a key because it is a pointer
|
|
-- to the C++ "weak pointer object", thus 2 references to the same instance may have a different
|
|
-- value when tested with rawequal ( == operator gives correct results however ...)
|
|
r2:removeInstanceObserver(r2.SelectBar.ObserverHandles[instance.InstanceId])
|
|
r2.SelectBar.ObserverHandles[instance.InstanceId] = nil
|
|
-- object is not erased yet (notification is sent before the true erase), so need to clean the table before the update
|
|
local maxElem = r2.SelectBar:getMaxNumEntries()
|
|
for k, v in pairs(r2.SelectBar.Content) do
|
|
if v == instance then
|
|
for index = k, maxElem do
|
|
r2.SelectBar.Content[index] = nil
|
|
end
|
|
break
|
|
end
|
|
end
|
|
if instance ~= r2:getSelectedInstance() then
|
|
-- nb : if instance is the selection, no need to update the bar right now, because setSelecteInstance(nil) is
|
|
-- called just after 'erase' notification messages have been sent
|
|
r2.SelectBar:touch()
|
|
end
|
|
r2.SelectBar:touch()
|
|
end
|
|
|
|
function selectBarObserver:onPostHrcMove(instance)
|
|
r2.SelectBar:touch()
|
|
end
|
|
|
|
function selectBarObserver:onAttrModified(instance, attrName, attrIndex)
|
|
if attrName == "Name" or attrName == "Title" then
|
|
r2.SelectBar:touch()
|
|
end
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- retrieve a reference to the select bar
|
|
function r2.SelectBar:getBar()
|
|
return getUI("ui:interface:r2ed_select_bar:buttons")
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- get a button in the bar
|
|
function r2.SelectBar:getButton(index)
|
|
return self:getBar():find(string.format("b%d", index))
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- return the max number of button in the select bar
|
|
function r2.SelectBar:getMaxNumEntries()
|
|
return tonumber(getDefine("r2ed_max_num_select_bar_button"))
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- init the select bar
|
|
function r2.SelectBar:init()
|
|
|
|
assert(next(self.ObserverHandles) == nil) -- observer table should be empty
|
|
local bar = self:getBar()
|
|
bar:clear()
|
|
for k = 1, self:getMaxNumEntries() do
|
|
local butt = createGroupInstance("r2ed_select_bar_button", bar.id,
|
|
{
|
|
id = string.format("b%d", k),
|
|
onclick_l="lua",
|
|
onclick_r="lua",
|
|
params_l=string.format("r2.SelectBar:onButtonPushed(%d)", k),
|
|
params_r=string.format("r2.SelectBar:onRightButtonPushed(%d)", k),
|
|
})
|
|
butt.active = false
|
|
bar:addChild(butt)
|
|
end
|
|
bar.active = false
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- mark the select bar as modified for update
|
|
function r2.SelectBar:touch()
|
|
self.Touched = true
|
|
local selection = r2:getSelectedInstance()
|
|
if selection and selection:isKindOf("Act") then
|
|
self.InstancesType = ""
|
|
end
|
|
end
|
|
|
|
---------------------------------------------------------------
|
|
-- update bar in special case of act
|
|
function r2.SelectBar:openInstancesOfType(instancesType)
|
|
r2.SelectBar:touch()
|
|
self.InstancesType = instancesType
|
|
end
|
|
--------------------------------------------------------
|
|
-- update select bar content if necessary
|
|
function r2.SelectBar:update()
|
|
|
|
if not self.Touched then return end
|
|
if r2.Scenario == nil then
|
|
return -- no scenario created for now
|
|
end
|
|
self.Touched = false
|
|
|
|
-- clear the observer table
|
|
for k, v in pairs(self.ObserverHandles) do
|
|
r2:removeInstanceObserver(v)
|
|
end
|
|
table.clear(self.ObserverHandles)
|
|
local selection = r2:getSelectedInstance()
|
|
if selection then
|
|
self:getBar().active = (selection.Ghost ~= true)
|
|
else
|
|
self:getBar().active = true
|
|
end
|
|
|
|
|
|
|
|
local function setupButtonWithIconAndText(butt, text, icon, buttIndex)
|
|
butt.active = true
|
|
butt.b.uc_hardtext = text
|
|
local icon = icon
|
|
if icon ~= "" and icon ~= nil then
|
|
butt.icon.texture = icon
|
|
butt.icon.active = true
|
|
-- butt.icon.color_rgba = CRGBA(255, 255, 255, 255)
|
|
butt.b.text_x = 28
|
|
butt.b.wmargin = 10
|
|
else
|
|
-- butt.icon.color_rgba = CRGBA(127, 127, 127, 255)
|
|
butt.icon.active = false
|
|
butt.b.text_x = 12
|
|
butt.b.wmargin = 12
|
|
end
|
|
--butt.b.pushed = (instance == selection)
|
|
butt:invalidateCoords()
|
|
end
|
|
|
|
-- setup a button from an instance
|
|
local function setupButton(butt, instance, buttIndex)
|
|
setupButtonWithIconAndText(butt, instance:getDisplayName(), instance:getSelectBarIcon(), buttIndex)
|
|
butt.Env.Types = false
|
|
end
|
|
|
|
-- setup a button from a type
|
|
local function setupButtonType(butt, type, buttIndex)
|
|
local icon
|
|
for k, v in pairs(self.InstancesTypes) do
|
|
if v.type == type then
|
|
icon = v.icon
|
|
break
|
|
end
|
|
end
|
|
setupButtonWithIconAndText(butt, ucstring(type), icon, buttIndex)
|
|
butt.Env.Types = true
|
|
end
|
|
|
|
-- count number of elligible elements for display in the select bar
|
|
local buttCount = 0
|
|
local currElem = selection
|
|
if selection then
|
|
while currElem do
|
|
if currElem:displayInSelectBar() then
|
|
buttCount = buttCount + 1
|
|
|
|
if currElem:isKindOf("Act") and self.InstancesType~="" then
|
|
buttCount = buttCount + 1
|
|
end
|
|
end
|
|
currElem = currElem.ParentInstance
|
|
end
|
|
end
|
|
|
|
local target = selection
|
|
if buttCount < 1 then
|
|
target = r2:getCurrentAct() -- ensure that at least an act is visible
|
|
buttCount = 1
|
|
if self.InstancesType~="" then
|
|
buttCount = buttCount + 1
|
|
end
|
|
end
|
|
|
|
local buttIndex = buttCount
|
|
-- special case for scenario wide objects (only plot items for now)
|
|
if selection and selection:isGlobalObject() then
|
|
|
|
-- current act
|
|
currElem = r2:getCurrentAct()
|
|
setupButton(self:getButton(1), currElem, 1)
|
|
self.Content[1] = currElem
|
|
self.ObserverHandles[currElem.InstanceId] = r2:addInstanceObserver(currElem.InstanceId, selectBarObserver)
|
|
|
|
-- special button for type
|
|
if self.InstancesType~="" then
|
|
setupButtonType(self:getButton(2), self.InstancesType, 2)
|
|
self.Content[2] = currElem
|
|
end
|
|
|
|
-- plot item
|
|
currElem = selection
|
|
setupButton(self:getButton(3), currElem, 3)
|
|
self.Content[3] = currElem
|
|
self.ObserverHandles[currElem.InstanceId] = r2:addInstanceObserver(currElem.InstanceId, selectBarObserver)
|
|
buttIndex = 4
|
|
|
|
-- special case if current selection is the scenario (display a single button)
|
|
elseif selection and selection:isSameObjectThan(r2.Scenario) then
|
|
setupButton(self:getButton(1), selection, buttIndex)
|
|
self.Content[1] = selection
|
|
self.ObserverHandles[selection.InstanceId] = r2:addInstanceObserver(selection.InstanceId, selectBarObserver)
|
|
buttIndex = 2
|
|
target = r2:getCurrentAct() -- continue with sons of current act
|
|
else
|
|
-- special case for plot items
|
|
-- add the buttons for real
|
|
-- parents
|
|
local currElem = target
|
|
while currElem do
|
|
if currElem:displayInSelectBar() then
|
|
if buttIndex <= self:getMaxNumEntries() then
|
|
if currElem:isKindOf("Act") then
|
|
if currElem:isBaseAct() then
|
|
currElem = r2:getCurrentAct()
|
|
end
|
|
|
|
if self.InstancesType~="" then
|
|
-- special button for different types
|
|
local ucname = ucstring()
|
|
ucname:fromUtf8(self.InstancesType)
|
|
setupButtonType(self:getButton(buttIndex), ucname, buttIndex)
|
|
self.Content[buttIndex] = currElem
|
|
buttIndex = buttIndex - 1
|
|
end
|
|
end
|
|
setupButton(self:getButton(buttIndex), currElem, buttIndex)
|
|
self.Content[buttIndex] = currElem
|
|
self.ObserverHandles[currElem.InstanceId] = r2:addInstanceObserver(currElem.InstanceId, selectBarObserver)
|
|
end
|
|
buttIndex = buttIndex - 1
|
|
end
|
|
currElem = currElem.ParentInstance
|
|
end
|
|
buttIndex = buttCount + 1
|
|
-- sons
|
|
-- preserve previous sons if they where in previous selection,
|
|
-- possibly renaming them
|
|
-- (nb : update may be triggered by modification of sons from a third party, so
|
|
-- the simpler approach 'if curr selection was in previous then leave unchanged'
|
|
-- doesn't work here ...)
|
|
-- get next son that can be displayed in the select bar
|
|
--local currParent = target
|
|
--while self.Content[buttIndex] ~= nil and not self.Content[buttIndex].isNil do
|
|
-- currElem = self.Content[buttIndex]
|
|
-- if currElem:getFirstSelectBarParent() == currParent then
|
|
-- -- there's a match so keep this entry
|
|
-- setupButton(self:getButton(buttIndex), currElem)
|
|
-- currParent = self.Content[buttIndex]
|
|
-- buttIndex = buttIndex + 1
|
|
-- self.ObserverHandles[currElem.InstanceId] = r2:addInstanceObserver(currElem.InstanceId, selectBarObserver)
|
|
-- else
|
|
-- -- no match -> exit
|
|
-- break
|
|
-- end
|
|
--end
|
|
end
|
|
|
|
-- old version
|
|
-- walk down sons until we reach the max number of buttons
|
|
-- local currSon = target:getFirstSelectBarSon()
|
|
-- while currSon and buttIndex <= self:getMaxNumEntries() do
|
|
-- setupButton(self:getButton(buttIndex), currSon)
|
|
-- self.Content[buttIndex] = currSon
|
|
-- self.ObserverHandles[currSon.InstanceId] = r2:addInstanceObserver(currSon.InstanceId, selectBarObserver)
|
|
-- currSon = currSon:getFirstSelectBarSon()
|
|
-- buttIndex = buttIndex +1
|
|
-- end
|
|
|
|
|
|
-- if there's room, add a selection button to traverse down the hierarchy
|
|
if buttIndex <= self:getMaxNumEntries() then
|
|
local butt = self:getButton(buttIndex)
|
|
butt.active = true
|
|
butt.b.uc_hardtext = i18n.get("uiR2EDSelectSubObject")
|
|
butt.icon.active = false
|
|
butt.b.text_x = 12
|
|
butt.b.wmargin = 12
|
|
butt:invalidateCoords()
|
|
--butt.b.pushed = false
|
|
self.Content[buttIndex] = nil
|
|
buttIndex = buttIndex + 1
|
|
end
|
|
|
|
-- hide remaining buttons
|
|
for k = buttIndex, self:getMaxNumEntries() do
|
|
self:getButton(k).active = false
|
|
self.Content[k] = nil
|
|
end
|
|
|
|
-- show/hide sequence browser if necessary
|
|
local sequenceMenuButton = self:getSequenceButton()
|
|
if not selection then
|
|
sequenceMenuButton.active = false
|
|
else
|
|
sequenceMenuButton.active = selection:isSequencable() and (selection.Ghost ~= true)
|
|
end
|
|
-- touch the contextual toolbar, because it y depends on us
|
|
r2.ContextualCommands:getToolbar():invalidateCoords()
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- called by the ui when one of the select bar button has been pushed
|
|
-- function r2.SelectBar:onButtonPushed(index)
|
|
-- local instanceId = self.Content[index].InstanceId
|
|
-- local selectedInstance = r2:getSelectedInstance()
|
|
-- if selectedInstance and instanceId == selectedInstance.InstanceId then
|
|
-- -- on second click the contextual menu is displayed
|
|
-- self:popMenu(index)
|
|
-- end
|
|
-- r2:setSelectedInstanceId(instanceId)
|
|
-- self:getButton(index).b.pushed = true
|
|
-- end
|
|
--
|
|
-- --------------------------------------------------------
|
|
-- -- called by the ui when one of the select bar button has been pushed with the right button
|
|
-- function r2.SelectBar:onRightButtonPushed(index)
|
|
-- r2:setSelectedInstanceId(self.Content[index].InstanceId)
|
|
-- self:update()
|
|
-- self:onButtonPushed(index)
|
|
-- end
|
|
|
|
|
|
--------------------------------------------------------
|
|
-- mark the select bar as modified for update
|
|
function r2.SelectBar:onMenuPostClickOut()
|
|
local uiCaller = getUICaller()
|
|
if uiCaller and uiCaller.parent and uiCaller.parent.parent then
|
|
local parentGroup = uiCaller.parent.parent
|
|
if parentGroup == getUI("ui:interface:r2ed_select_bar:buttons") then
|
|
self.LastMenuHideTrigger = getUICaller()
|
|
return
|
|
end
|
|
end
|
|
self.LastMenuHideTrigger = nil
|
|
self.LastMenuPopper = nil
|
|
end
|
|
|
|
|
|
--------------------------------------------------------
|
|
-- called by the ui when one of the select bar button has been pushed
|
|
function r2.SelectBar:onButtonPushed(index)
|
|
local butt = self:getButton(index)
|
|
local selectedInstance = self.Content[index]
|
|
if selectedInstance == nil then
|
|
-- pop menu for sons of parents
|
|
self:popMenu(index)
|
|
return
|
|
end
|
|
if butt.b == self.LastMenuHideTrigger and selectedInstance == self.LastMenuPopper then
|
|
self.LastMenuHideTrigger = nil
|
|
return
|
|
end
|
|
self.LastMenuPopper = selectedInstance
|
|
self.LastMenuHideTrigger = nil
|
|
r2:setSelectedInstanceId(selectedInstance.InstanceId)
|
|
self:touch()
|
|
-- on second click the contextual menu is displayed
|
|
self:popMenu(index)
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- called by the ui when one of the select bar button has been pushed with the right button
|
|
function r2.SelectBar:onRightButtonPushed(index)
|
|
self:onButtonPushed(index)
|
|
end
|
|
|
|
|
|
|
|
--------------------------------------------------------
|
|
-- get root menu for the select bar
|
|
function r2.SelectBar:getRootMenu()
|
|
local menu = getUI("ui:interface:r2ed_select_bar_menu")
|
|
return menu:getRootMenu()
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- get menu for the select bar
|
|
function r2.SelectBar:getMenu()
|
|
return getUI("ui:interface:r2ed_select_bar_menu")
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- get the 'sequences' button
|
|
function r2.SelectBar:getSequenceButton()
|
|
return getUI("ui:interface:r2ed_select_bar:sequences")
|
|
end
|
|
|
|
|
|
|
|
--------------------------------------------------------
|
|
-- display sub-instance menu for the given button
|
|
function r2.SelectBar:getMenu()
|
|
return getUI("ui:interface:r2ed_select_bar_menu")
|
|
end
|
|
|
|
local allSons = {}
|
|
|
|
--------------------------------------------------------
|
|
-- display sub-instance menu for the given button
|
|
function r2.SelectBar:popMenu(index)
|
|
|
|
local target
|
|
if self.Content[index] == nil then
|
|
-- the "select" button was pressed
|
|
target = r2:getSelectedInstance()
|
|
if target == nil then
|
|
target = r2:getCurrentAct()
|
|
end
|
|
else
|
|
target = r2:getInstanceFromId(self.Content[index].InstanceId)
|
|
if not target:isSameObjectThan(r2.Scenario) then
|
|
-- to get objects of same type, just enumerate from the parent (except for scenario)
|
|
target = target:getFirstSelectBarParent()
|
|
end
|
|
end
|
|
|
|
--r2:setSelectedInstanceId(target.InstanceId)
|
|
local menu = self:getMenu()
|
|
local rm = self:getRootMenu()
|
|
r2:clearMenu(rm)
|
|
local st = os.clock()
|
|
-- retrieve all sons (optimize this if needed ...)
|
|
table.clear(allSons)
|
|
|
|
if target:isKindOf("Scenario") then
|
|
-- special case for scenario : 'appendInstancesByType' would only add the active act, and we want them all
|
|
for k, v in specPairs(target.Acts) do
|
|
if not v:isBaseAct() then
|
|
table.insert(allSons, v)
|
|
end
|
|
end
|
|
elseif target:isKindOf("Act") and self:getButton(index).Env.Types~=true then
|
|
|
|
for k, v in specPairs(r2.Scenario.PlotItems) do
|
|
table.insert(allSons, v)
|
|
end
|
|
r2.Scenario:getBaseAct():appendInstancesByType(allSons, "BaseClass")
|
|
r2.Scenario:getCurrentAct():appendInstancesByType(allSons, "BaseClass")
|
|
local allSonsTemp = {}
|
|
for k, v in pairs(allSons) do
|
|
if v:getSelectBarType()==self.InstancesType then
|
|
table.insert(allSonsTemp, v)
|
|
end
|
|
end
|
|
allSons = allSonsTemp
|
|
|
|
elseif target ~= nil then
|
|
target:appendInstancesByType(allSons, "BaseClass")
|
|
end
|
|
|
|
local et = os.clock()
|
|
--debugInfo("#1 " .. tostring(et - st))
|
|
st = os.clock()
|
|
local sons = {}
|
|
-- retrieve direct selectable sons
|
|
for k,v in pairs(allSons) do
|
|
if v:displayInSelectBar() and (v:getFirstSelectBarParent()==target or (target:isKindOf("Act") and v:getFirstSelectBarParent()==r2.Scenario:getBaseAct())) then
|
|
table.insert(sons, v)
|
|
end
|
|
end
|
|
|
|
et = os.clock()
|
|
--debugInfo("#2 " .. tostring(et - st))
|
|
st = os.clock()
|
|
-- sort by category, then by icon
|
|
local function sorter(lhs, rhs)
|
|
if lhs:getClassName() ~= rhs:getClassName() then return lhs:getClassName() < rhs:getClassName() end
|
|
if lhs:getSelectBarIcon() ~= rhs:getSelectBarIcon() then return lhs:getSelectBarIcon() < rhs:getSelectBarIcon() end
|
|
return lhs:getDisplayName() < rhs:getDisplayName()
|
|
end
|
|
table.sort(sons, sorter)
|
|
et = os.clock()
|
|
--debugInfo("#3 " .. tostring(et - st))
|
|
st = os.clock()
|
|
-- fill menu
|
|
|
|
-- special case for act
|
|
if index==2 then
|
|
for k, v in pairs(self.InstancesTypes) do
|
|
local ucname = ucstring()
|
|
ucname:fromUtf8(v.type)
|
|
r2:addMenuLine(rm, ucname, "lua", "r2.SelectBar:openInstancesOfType('".. v.type .."','" .. v.icon .."')", v.type, v.icon, 14)
|
|
end
|
|
else
|
|
for k, v in pairs(sons) do
|
|
r2:addMenuLine(rm, v:getDisplayName(), "lua", "r2:setSelectedInstanceId('" .. v.InstanceId .."')", tostring(k), v:getSelectBarIcon(), 14)
|
|
end
|
|
end
|
|
|
|
target:completeSelectBarMenu(rm)
|
|
if rm:getNumLine() == 0 then
|
|
rm:addLine(i18n.get("uiR2EDEmpty"), "", "", "empty")
|
|
end
|
|
if self.Content[index] and self.Content[index].InstanceId == r2:getSelectedInstance().InstanceId then
|
|
if r2:getSelectedInstance().BuildPropertySheet then
|
|
rm:addSeparator()
|
|
r2:addMenuLine(rm, concatUCString(i18n.get("uiRE2DPropertiesOf"), r2:getSelectedInstance():getDisplayName()), "lua", "r2:showProperties(r2:getSelectedInstance())", "prop", "r2_icon_properties.tga", 14)
|
|
end
|
|
end
|
|
et = os.clock()
|
|
--debugInfo("#4 " .. tostring(et - st))
|
|
et = os.clock()
|
|
|
|
rm:setMaxVisibleLine(15)
|
|
launchContextMenuInGame(menu.id)
|
|
local butt = self:getButton(index)
|
|
menu.x = butt.x_real
|
|
menu.y = butt.y_real + butt.h_real
|
|
menu:updateCoords()
|
|
et = os.clock()
|
|
--debugInfo("#5 " .. tostring(et - st))
|
|
end
|
|
|
|
--------------------------------------------------------
|
|
-- TMP placeholder: called when the "sequence" menu is clicked
|
|
--------------------------------------------------------
|
|
-- called when the "sequence" menu is clicked
|
|
function r2.SelectBar:browseSequences()
|
|
|
|
--r2:updateActivitiesAndChatsUI(r2:getSelectedInstance())
|
|
r2.activities:initEditorAfterFirstCall()
|
|
|
|
local logicEntity = r2:getSelectedInstance()
|
|
local activitySequences = logicEntity:getBehavior().Activities
|
|
|
|
local menu = self:getMenu()
|
|
local rm = menu:getRootMenu()
|
|
r2:clearMenu(rm)
|
|
for s = 0, activitySequences.Size - 1 do
|
|
local sequence = activitySequences[s]
|
|
local uc_sequ = ucstring()
|
|
uc_sequ:fromUtf8(sequence:getName())
|
|
rm:addLine(uc_sequ, "lua", "r2.activities:triggerSelectSequence('".. sequence.InstanceId .. "')", sequence.InstanceId)
|
|
end
|
|
rm:addSeparator()
|
|
r2:addMenuLine(rm, i18n.get("uiR2EDNewSequence"), "lua", "r2.activities:newSequenceInst()", "new_sequence", "r2_icon_create.tga", 14)
|
|
|
|
local sequenceMenuButton = self:getSequenceButton()
|
|
sequenceMenuButton:updateCoords()
|
|
launchContextMenuInGame(menu.id)
|
|
menu.x = sequenceMenuButton.x_real
|
|
menu.y = sequenceMenuButton.y_real + sequenceMenuButton.h_real
|
|
menu:updateCoords()
|
|
end
|