khanat-client-data-NeL/data/ryz/ryz_ring/r2_ui_select_bar.lua

337 lines
12 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
}
-- 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, 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
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
debugInfo(tostring(k))
local butt = createGroupInstance("r2ed_select_bar_button", bar.id,
{
id = string.format("b%d", k),
onclick_l="lua",
params_l=string.format("r2.SelectBar:onButtonPushed(%d)", k),
onclick_r="lua",
params_r=string.format("r2.SelectBar:onRightButtonPushed(%d)", k)
})
butt.active = false
bar:addChild(butt)
end
end
--------------------------------------------------------
-- mark the select bar as modified for update
function r2.SelectBar:touch()
self.Touched = true
end
--------------------------------------------------------
-- update select bar content if necessary
function r2.SelectBar:update()
if not self.Touched then return 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()
self:getBar().active = true
-- count number of elligible elements for display in the select bar
local buttCount = 0
local currElem = selection
-- setup a button from an instance
local function setupButton(butt, instance)
butt.active = true
butt.b.pushed = (instance == selection)
butt.b.uc_hardtext = instance:getDisplayName()
local icon = instance:getSelectBarIcon()
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:invalidateCoords()
end
if selection then
while currElem do
if currElem:displayInSelectBar() then
buttCount = buttCount + 1
end
currElem = currElem.ParentInstance
end
end
buttCount =math.min(buttCount, self:getMaxNumEntries())
local target = selection
if buttCount < 2 then
target = r2:getCurrentAct() -- ensure that at least 'scenario' and 'act' are visible
buttCount = 2
end
-- add the buttons for real
-- parents
local buttIndex = buttCount
local currElem = target
while currElem do
if currElem:displayInSelectBar() then
local butt =
setupButton(self:getButton(buttIndex), currElem)
self.Content[buttIndex] = currElem
self.ObserverHandles[currElem.InstanceId] = r2:addInstanceObserver(currElem.InstanceId, selectBarObserver)
buttIndex = buttIndex - 1
end
currElem = currElem.ParentInstance
end
-- 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 ...)
buttIndex = buttCount + 1
-- 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
-- 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
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
--------------------------------------------------------
-- 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:popMenu(index)
local target = r2:getInstanceFromId(self.Content[index].InstanceId)
--r2:setSelectedInstanceId(target.InstanceId)
local menu = getUI("ui:interface:r2ed_select_bar_menu")
local rm = self:getRootMenu()
r2:clearMenu(rm)
local st = os.clock()
-- retrieve all sons (to optimize if needed ...)
local 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
table.insert(allSons, v)
end
else
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 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
local currentLine = 0
for k, v in pairs(sons) do
r2:addMenuLine(rm, v:getDisplayName(), "lua", "r2:setSelectedInstanceId('" .. v.InstanceId .."')", tostring(k), v:getSelectBarIcon(), 14)
--rm:addLine(v:getDisplayName(), "lua", "r2:setSelectedInstanceId('" .. v.InstanceId .."')", tostring(k))
--if v:getSelectBarIcon() ~= "" then
-- local menuButton = createGroupInstance("r2_menu_button", "", { bitmap = v:getSelectBarIcon(), size="14" })
-- if menuButton then
-- rm:setUserGroupLeft(currentLine, menuButton)
-- end
-- end
currentLine = currentLine + 1
end
target:completeSelectBarMenu(rm)
if rm:getNumLine() == 0 then
rm:addLine(i18n.get("uiR2EDEmpty"), "", "", "empty")
end
et = os.clock()
debugInfo("#4 " .. tostring(et - st))
et = os.clock()
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
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]
rm:addLine(ucstring(r2:getSequenceName(sequence)), "lua", "r2:selectActivitiesSequence(".. tostring(s) .. ")", "s")
end
rm:addSeparator()
r2:addMenuLine(rm, i18n.get("uiR2EDNewSequence"), "lua", "r2:newMiniActivitySequence()", "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