1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
|
-- 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()
-- leap.eventstream() returns the first response, and launches a
-- background fiber to call the passed callback with all subsequent
-- responses.
local event = leap.eventstream(
'LLFloaterReg',
self._command,
-- handleEvents() returns false when done.
-- eventstream() expects a true return when done.
function(event) return not self:handleEvents(event) end)
self._pump = event.command_name
-- we might need the returned reqid to cancel the eventstream() fiber
self.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
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 leap.eventstream().
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
|