summaryrefslogtreecommitdiff
path: root/indra/newview/scripts/lua
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-04-09 15:21:05 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-04-09 15:21:05 -0400
commit26ce33d8ead68c2dbcc37b2b1e040c072866fe5b (patch)
tree42ff25f1d1db25be3dfc740016ff75d12c847eb1 /indra/newview/scripts/lua
parent3114f674aaef019804803bed50972833f5411f93 (diff)
Add Lua Floater class to simplify Lua script showing floaters.
Add test_luafloater_demo2.lua and test_luafloater_gesture_list2.lua examples.
Diffstat (limited to 'indra/newview/scripts/lua')
-rw-r--r--indra/newview/scripts/lua/Floater.lua151
-rw-r--r--indra/newview/scripts/lua/leap.lua7
-rw-r--r--indra/newview/scripts/lua/test_luafloater_demo2.lua39
-rw-r--r--indra/newview/scripts/lua/test_luafloater_gesture_list2.lua27
4 files changed, 221 insertions, 3 deletions
diff --git a/indra/newview/scripts/lua/Floater.lua b/indra/newview/scripts/lua/Floater.lua
new file mode 100644
index 0000000000..76efd47c43
--- /dev/null
+++ b/indra/newview/scripts/lua/Floater.lua
@@ -0,0 +1,151 @@
+-- Floater base class
+
+local leap = require 'leap'
+local fiber = require 'fiber'
+
+-- list of all the events that a LLLuaFloater might send
+local event_list = leap.request("LLFloaterReg", {op="getFloaterEvents"}).events
+local event_set = {}
+for _, event in pairs(event_list) do
+ event_set[event] = true
+end
+
+local function _event(event_name)
+ if not event_set[event_name] then
+ error("Incorrect event name: " .. event_name, 3)
+ end
+ return event_name
+end
+
+-- ---------------------------------------------------------------------------
+local Floater = {}
+
+-- Pass:
+-- relative file path to floater's XUI definition file
+-- optional: sign up for additional events for defined control
+-- {<control_name>={action1, action2, ...}}
+function Floater:new(path, extra)
+ local obj = setmetatable({}, self)
+ self.__index = self
+
+ local path_parts = string.split(path, '/')
+ obj.name = 'Floater ' .. path_parts[#path_parts]
+
+ obj._command = {op="showLuaFloater", xml_path=LL.abspath(path)}
+ if extra then
+ -- validate each of the actions for each specified control
+ for control, actions in pairs(extra) do
+ for _, action in pairs(actions) do
+ _event(action)
+ end
+ end
+ obj._command.extra_events = extra
+ end
+
+ return obj
+end
+
+function Floater:show()
+ local event = leap.request('LLFloaterReg', self._command)
+ self._pump = event.command_name
+ -- we use the returned reqid to claim subsequent unsolicited events
+ local reqid = event.reqid
+
+ -- The response to 'showLuaFloater' *is* the 'post_build' event. Check if
+ -- subclass has a post_build() method. Honor the convention that if
+ -- handleEvents() returns false, we're done.
+ if not self:handleEvents(event) then
+ return
+ end
+
+ local waitfor = leap.WaitFor:new(-1, self.name)
+ function waitfor:filter(pump, data)
+ if data.reqid == reqid then
+ return data
+ end
+ end
+
+ fiber.launch(
+ self.name,
+ function ()
+ event = waitfor:wait()
+ while event and self:handleEvents(event) do
+ event = waitfor:wait()
+ end
+ end)
+end
+
+function Floater:post(action)
+ leap.send(self._pump, action)
+end
+
+function Floater:request(action)
+ return leap.request(self._pump, action)
+end
+
+-- local inspect = require 'inspect'
+
+function Floater:handleEvents(event_data)
+ local event = event_data.event
+ if event_set[event] == nil then
+ LL.print_warning(string.format('%s received unknown event %q', self.name, event))
+ end
+
+ -- Before checking for a general (e.g.) commit() method, first look for
+ -- commit_ctrl_name(): in other words, concatenate the event name with the
+ -- ctrl_name, with an underscore between. If there exists such a specific
+ -- method, call that.
+ local handler, ret
+ if event_data.ctrl_name then
+ local specific = event .. '_' .. event_data.ctrl_name
+ handler = self[specific]
+ if handler then
+ ret = handler(self, event_data)
+ -- Avoid 'return ret or true' because we explicitly want to allow
+ -- the handler to return false.
+ if ret ~= nil then
+ return ret
+ else
+ return true
+ end
+ end
+ end
+
+ -- No specific "event_on_ctrl()" method found; try just "event()"
+ handler = self[event]
+ if handler then
+ ret = handler(self, event_data)
+ if ret ~= nil then
+ return ret
+ end
+-- else
+-- print(string.format('%s ignoring event %s', self.name, inspect(event_data)))
+ end
+
+ -- We check for event() method before recognizing floater_close in case
+ -- the consumer needs to react specially to closing the floater. Now that
+ -- we've checked, recognize it ourselves. Returning false terminates the
+ -- anonymous fiber function launched by show().
+ if event == _event('floater_close') then
+ LL.print_warning(self.name .. ' closed')
+ return false
+ end
+ return true
+end
+
+-- onCtrl() permits a different dispatch style in which the general event()
+-- method explicitly calls (e.g.)
+-- self:onCtrl(event_data, {
+-- ctrl_name=function()
+-- self:post(...)
+-- end,
+-- ...
+-- })
+function Floater:onCtrl(event_data, ctrl_map)
+ local handler = ctrl_map[event_data.ctrl_name]
+ if handler then
+ handler()
+ end
+end
+
+return Floater
diff --git a/indra/newview/scripts/lua/leap.lua b/indra/newview/scripts/lua/leap.lua
index d19273e8bc..ade91789f0 100644
--- a/indra/newview/scripts/lua/leap.lua
+++ b/indra/newview/scripts/lua/leap.lua
@@ -183,14 +183,15 @@ function leap.generate(pump, data, checklast)
-- bearing that reqid. Stamp the outbound request with that reqid, and
-- send it.
local reqid, waitfor = requestSetup(pump, data)
- local ok, response
+ local ok, response, resumed_with
repeat
ok, response = pcall(waitfor.wait, waitfor)
if not ok then
break
end
- coroutine.yield(response)
- until checklast and checklast(response)
+ -- can resume(false) to terminate generate() and clean up
+ resumed_with = coroutine.yield(response)
+ until (checklast and checklast(response)) or (resumed_with == false)
-- If we break the above loop, whether or not due to error, clean up.
pending[reqid] = nil
if not ok then
diff --git a/indra/newview/scripts/lua/test_luafloater_demo2.lua b/indra/newview/scripts/lua/test_luafloater_demo2.lua
new file mode 100644
index 0000000000..9e24237d28
--- /dev/null
+++ b/indra/newview/scripts/lua/test_luafloater_demo2.lua
@@ -0,0 +1,39 @@
+local Floater = require 'Floater'
+local leap = require 'leap'
+local startup = require 'startup'
+
+local flt = Floater:new(
+ 'luafloater_demo.xml',
+ {show_time_lbl = {"right_mouse_down", "double_click"}})
+
+-- override base-class handleEvents() to report the event data in the floater's display field
+function flt:handleEvents(event_data)
+ self:post({action="add_text", ctrl_name="events_editor", value = event_data})
+ -- forward the call to base-class handleEvents()
+ return Floater.handleEvents(self, event_data)
+end
+
+function flt:commit_disable_ctrl(event_data)
+ self:post({action="set_enabled", ctrl_name="open_btn", value = (1 - event_data.value)})
+end
+
+function flt:commit_title_cmb(event_data)
+ self:post({action="set_title", value=event_data.value})
+end
+
+function flt:commit_open_btn(event_data)
+ floater_name = self:request({action="get_value", ctrl_name='openfloater_cmd'}).value
+ leap.send("LLFloaterReg", {name = floater_name, op = "showInstance"})
+end
+
+local function getCurrentTime()
+ local currentTime = os.date("*t")
+ return string.format("%02d:%02d:%02d", currentTime.hour, currentTime.min, currentTime.sec)
+end
+
+function flt:double_click_show_time_lbl(event_data)
+ self:post({action="set_value", ctrl_name="time_lbl", value=getCurrentTime()})
+end
+
+startup.wait('STATE_LOGIN_WAIT')
+flt:show()
diff --git a/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua b/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua
new file mode 100644
index 0000000000..d702d09c51
--- /dev/null
+++ b/indra/newview/scripts/lua/test_luafloater_gesture_list2.lua
@@ -0,0 +1,27 @@
+local Floater = require 'Floater'
+local LLGesture = require 'LLGesture'
+local startup = require 'startup'
+
+local flt = Floater:new(
+ "luafloater_gesture_list.xml",
+ {gesture_list = {"double_click"}})
+
+function flt:post_build(event_data)
+ local gestures_uuid = LLGesture.getActiveGestures()
+ local action_data = {}
+ action_data.action = "add_list_element"
+ action_data.ctrl_name = "gesture_list"
+ local gestures = {}
+ for uuid, info in pairs(gestures_uuid) do
+ table.insert(gestures, {value = uuid, columns={column = "gesture_name", value = info.name}})
+ end
+ action_data.value = gestures
+ self:post(action_data)
+end
+
+function flt:double_click_gesture_list(event_data)
+ LLGesture.startGesture(event_data.value)
+end
+
+startup.wait('STATE_STARTED')
+flt:show()