summaryrefslogtreecommitdiff
path: root/indra/newview/scripts/lua/require
diff options
context:
space:
mode:
authorNat Goodspeed <nat@lindenlab.com>2024-08-23 17:18:14 -0400
committerNat Goodspeed <nat@lindenlab.com>2024-08-23 17:18:14 -0400
commita80b9487dc7c893f5e96f48f15140a5f82b99e30 (patch)
treed6f048acac23e5f5cdb72920587f0ca240dbb1ca /indra/newview/scripts/lua/require
parent7ee93ea34dfc41640f852279888bbee0cafcecbe (diff)
Allow UI to have lazily-loaded submodules.
Equip UI with an __index metamethod. When someone references an unknown key/field in UI, require() that module and cache it for future reference. Add util.setmetamethods() as a way to find or create a metatable on a specified table containing specified metamethods. Exercise the new functionality by referencing UI.popup in test_popup.lua.
Diffstat (limited to 'indra/newview/scripts/lua/require')
-rw-r--r--indra/newview/scripts/lua/require/UI.lua22
-rw-r--r--indra/newview/scripts/lua/require/util.lua46
2 files changed, 55 insertions, 13 deletions
diff --git a/indra/newview/scripts/lua/require/UI.lua b/indra/newview/scripts/lua/require/UI.lua
index 464e6547ea..969a2cbded 100644
--- a/indra/newview/scripts/lua/require/UI.lua
+++ b/indra/newview/scripts/lua/require/UI.lua
@@ -1,10 +1,26 @@
-- Engage the viewer's UI
local leap = require 'leap'
-local Timer = (require 'timers').Timer
local mapargs = require 'mapargs'
-
-local UI = {}
+local Timer = (require 'timers').Timer
+local util = require 'util'
+
+-- Allow lazily accessing certain other modules on demand, e.g. a reference to
+-- UI.Floater lazily loads the Floater module. Use of UI's __index metamethod
+-- theoretically permits any other module you can require() to appear as a
+-- submodule of UI, but it doesn't make sense to support (e.g.) UI.Queue.
+local submods = { 'Floater', 'popup' }
+local UI = util.setmetamethods{
+ __index=function(t, key)
+ if not table.find(submods, key) then
+ error(`Invalid UI submodule {key}`, 2)
+ end
+ local mod = require(key)
+ -- cache the submodule
+ t[key] = mod
+ return mod
+ end
+}
-- ***************************************************************************
-- registered menu actions
diff --git a/indra/newview/scripts/lua/require/util.lua b/indra/newview/scripts/lua/require/util.lua
index bfbfc8637c..a000359226 100644
--- a/indra/newview/scripts/lua/require/util.lua
+++ b/indra/newview/scripts/lua/require/util.lua
@@ -15,16 +15,9 @@ local util = {}
-- util.classctor(MyClass, MyClass.construct)
-- return MyClass
function util.classctor(class, ctor)
- -- get the metatable for the passed class
- local mt = getmetatable(class)
- if mt == nil then
- -- if it doesn't already have a metatable, then create one
- mt = {}
- setmetatable(class, mt)
- end
- -- now that class has a metatable, set its __call method to the specified
- -- constructor method (class.new if not specified)
- mt.__call = ctor or class.new
+ -- set class's __call metamethod to the specified constructor function
+ -- (class.new if not specified)
+ util.setmetamethods{class, __call=(ctor or class.new)}
end
-- check if array-like table contains certain value
@@ -66,4 +59,37 @@ function util.equal(t1, t2)
return util.empty(temp)
end
+-- Find or create the metatable for a specified table (a new empty table if
+-- omitted), and to that metatable assign the specified keys.
+-- Setting multiple keys at once is more efficient than a function to set only
+-- one at a time, e.g. setametamethod().
+-- t = util.setmetamethods{__index=readfunc, __len=lenfunc}
+-- returns a new table with specified metamethods __index, __len
+-- util.setmetamethods{t, __call=action}
+-- finds or creates the metatable for existing table t and sets __call
+-- util.setmetamethods{table=t, __call=action}
+-- same as util.setmetamethods{t, __call=action}
+function util.setmetamethods(specs)
+ -- first determine the target table
+ assert(not (specs.table and specs[1]),
+ "Pass setmetamethods table either as positional or table=, not both")
+ local t = specs.table or specs[1] or {}
+ -- remove both ways of specifying table, leaving only the metamethods
+ specs.table = nil
+ specs[1] = nil
+ local mt = getmetatable(t)
+ if not mt then
+ -- t doesn't already have a metatable: just set specs
+ setmetatable(t, specs)
+ else
+ -- t already has a metatable: copy specs into it
+ local key, value
+ for key, value in pairs(specs) do
+ mt[key] = value
+ end
+ end
+ -- having set or enriched t's metatable, return t
+ return t
+end
+
return util