@trioforge/anvil 0.0.0-stage → 0.1.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +111 -2
- package/out/adapter.d.ts +16 -0
- package/out/adapter.luau +19 -0
- package/out/frame-loop.d.ts +3 -0
- package/out/frame-loop.luau +56 -0
- package/out/index.d.ts +6 -0
- package/out/init.luau +18 -0
- package/out/modal-state.d.ts +12 -0
- package/out/modal-state.luau +133 -0
- package/out/modal.d.ts +13 -0
- package/out/modal.luau +58 -0
- package/out/press-state.d.ts +35 -0
- package/out/press-state.luau +104 -0
- package/out/props.d.ts +12 -0
- package/out/props.luau +2 -0
- package/out/runtime.d.ts +30 -0
- package/out/runtime.luau +797 -0
- package/out/selection-policy.d.ts +33 -0
- package/out/selection-policy.luau +112 -0
- package/out/use-press.d.ts +22 -0
- package/out/use-press.luau +228 -0
- package/package.json +42 -5
package/out/runtime.luau
ADDED
|
@@ -0,0 +1,797 @@
|
|
|
1
|
+
-- Compiled with roblox-ts v3.0.0
|
|
2
|
+
local TS = _G[script]
|
|
3
|
+
local _charm = TS.import(script, TS.getModule(script, "@rbxts", "charm").src)
|
|
4
|
+
local atom = _charm.atom
|
|
5
|
+
local computed = _charm.computed
|
|
6
|
+
local effect = _charm.effect
|
|
7
|
+
local _services = TS.import(script, TS.getModule(script, "@rbxts", "services"))
|
|
8
|
+
local GuiService = _services.GuiService
|
|
9
|
+
local UserInputService = _services.UserInputService
|
|
10
|
+
local _vide = TS.import(script, TS.getModule(script, "@rbxts", "vide").src)
|
|
11
|
+
local cleanup = _vide.cleanup
|
|
12
|
+
local context = _vide.context
|
|
13
|
+
local videEffect = _vide.effect
|
|
14
|
+
local read = _vide.read
|
|
15
|
+
local source = _vide.source
|
|
16
|
+
local useAtom = TS.import(script, TS.getModule(script, "@rbxts", "vide-charm").src).useAtom
|
|
17
|
+
local adapter = TS.import(script, script.Parent, "adapter").adapter
|
|
18
|
+
local _modal_state = TS.import(script, script.Parent, "modal-state")
|
|
19
|
+
local enter = _modal_state.enter
|
|
20
|
+
local hasModal = _modal_state.hasModal
|
|
21
|
+
local leave = _modal_state.leave
|
|
22
|
+
local top = _modal_state.top
|
|
23
|
+
local _selection_policy = TS.import(script, script.Parent, "selection-policy")
|
|
24
|
+
local decide = _selection_policy.decide
|
|
25
|
+
local emptySelection = _selection_policy.emptySelection
|
|
26
|
+
local ownerContext = context("Base")
|
|
27
|
+
local closeFallbackContext = context(false)
|
|
28
|
+
local state = atom({
|
|
29
|
+
entries = {},
|
|
30
|
+
})
|
|
31
|
+
local modalOpen = computed(function()
|
|
32
|
+
return hasModal(state())
|
|
33
|
+
end)
|
|
34
|
+
local topId = computed(function()
|
|
35
|
+
local _result = top(state())
|
|
36
|
+
if _result ~= nil then
|
|
37
|
+
_result = _result.id
|
|
38
|
+
end
|
|
39
|
+
return _result
|
|
40
|
+
end)
|
|
41
|
+
local selectedObject = atom()
|
|
42
|
+
local textEditing = atom(false)
|
|
43
|
+
local menuOpen = atom(false)
|
|
44
|
+
local roots = {}
|
|
45
|
+
local controls = {}
|
|
46
|
+
local serial = 0
|
|
47
|
+
local baseRestore
|
|
48
|
+
local writing = false
|
|
49
|
+
local generation = 0
|
|
50
|
+
local waiting = {}
|
|
51
|
+
local selectedWatch = {}
|
|
52
|
+
local capturedA
|
|
53
|
+
local runtimeOwners = {}
|
|
54
|
+
-- The primitives draw the hover/selection geometry; blank only kit controls so TopbarPlus keeps its artwork.
|
|
55
|
+
local blankSelectionImage = Instance.new("Frame")
|
|
56
|
+
blankSelectionImage.Name = "SelectionImage"
|
|
57
|
+
blankSelectionImage.BackgroundTransparency = 1
|
|
58
|
+
local function active(owner)
|
|
59
|
+
return if owner == "Base" then not modalOpen() else topId() == owner
|
|
60
|
+
end
|
|
61
|
+
local function native(owner)
|
|
62
|
+
local _condition = active(owner)
|
|
63
|
+
if _condition then
|
|
64
|
+
local _condition_1 = owner == "Base"
|
|
65
|
+
if not _condition_1 then
|
|
66
|
+
local _owner = owner
|
|
67
|
+
local _result = roots[_owner]
|
|
68
|
+
if _result ~= nil then
|
|
69
|
+
_result = _result.mode
|
|
70
|
+
end
|
|
71
|
+
_condition_1 = _result == "Native"
|
|
72
|
+
end
|
|
73
|
+
_condition = _condition_1
|
|
74
|
+
end
|
|
75
|
+
return _condition
|
|
76
|
+
end
|
|
77
|
+
local function finite(value)
|
|
78
|
+
return value == value and math.abs(value) < math.huge
|
|
79
|
+
end
|
|
80
|
+
local function alive(object)
|
|
81
|
+
if not object:FindFirstAncestorOfClass("PlayerGui") then
|
|
82
|
+
return false
|
|
83
|
+
end
|
|
84
|
+
local ancestor = object
|
|
85
|
+
while ancestor do
|
|
86
|
+
if ancestor:IsA("GuiObject") and not ancestor.Visible then
|
|
87
|
+
return false
|
|
88
|
+
end
|
|
89
|
+
if ancestor:IsA("LayerCollector") and not ancestor.Enabled then
|
|
90
|
+
return false
|
|
91
|
+
end
|
|
92
|
+
ancestor = ancestor.Parent
|
|
93
|
+
end
|
|
94
|
+
return true
|
|
95
|
+
end
|
|
96
|
+
local function ready(object, isRoot)
|
|
97
|
+
if (not isRoot and not object.Selectable) or not alive(object) then
|
|
98
|
+
return false
|
|
99
|
+
end
|
|
100
|
+
local ancestor = object
|
|
101
|
+
while ancestor do
|
|
102
|
+
if ancestor:IsA("GuiObject") then
|
|
103
|
+
local size = ancestor.AbsoluteSize
|
|
104
|
+
local position = ancestor.AbsolutePosition
|
|
105
|
+
if not finite(size.X) or not finite(size.Y) or not finite(position.X) or not finite(position.Y) or size.X < 0 or size.Y < 0 then
|
|
106
|
+
return false
|
|
107
|
+
end
|
|
108
|
+
if (ancestor == object or ancestor.ClipsDescendants) and (size.X < 1 or size.Y < 1) then
|
|
109
|
+
return false
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
ancestor = ancestor.Parent
|
|
113
|
+
end
|
|
114
|
+
return true
|
|
115
|
+
end
|
|
116
|
+
local function disconnect(connections)
|
|
117
|
+
for _, connection in connections do
|
|
118
|
+
connection:Disconnect()
|
|
119
|
+
end
|
|
120
|
+
end
|
|
121
|
+
local function watch(object, changed)
|
|
122
|
+
local connections = { object.AncestryChanged:Connect(changed), object:GetPropertyChangedSignal("Selectable"):Connect(changed) }
|
|
123
|
+
local ancestor = object
|
|
124
|
+
while ancestor do
|
|
125
|
+
if ancestor:IsA("GuiObject") then
|
|
126
|
+
local _arg0 = ancestor:GetPropertyChangedSignal("AbsoluteSize"):Connect(changed)
|
|
127
|
+
table.insert(connections, _arg0)
|
|
128
|
+
local _arg0_1 = ancestor:GetPropertyChangedSignal("AbsolutePosition"):Connect(changed)
|
|
129
|
+
table.insert(connections, _arg0_1)
|
|
130
|
+
local _arg0_2 = ancestor:GetPropertyChangedSignal("Visible"):Connect(changed)
|
|
131
|
+
table.insert(connections, _arg0_2)
|
|
132
|
+
local _arg0_3 = ancestor:GetPropertyChangedSignal("ClipsDescendants"):Connect(changed)
|
|
133
|
+
table.insert(connections, _arg0_3)
|
|
134
|
+
elseif ancestor:IsA("LayerCollector") then
|
|
135
|
+
local _arg0 = ancestor:GetPropertyChangedSignal("Enabled"):Connect(changed)
|
|
136
|
+
table.insert(connections, _arg0)
|
|
137
|
+
end
|
|
138
|
+
ancestor = ancestor.Parent
|
|
139
|
+
end
|
|
140
|
+
return connections
|
|
141
|
+
end
|
|
142
|
+
local function cancelRequest()
|
|
143
|
+
generation += 1
|
|
144
|
+
disconnect(waiting)
|
|
145
|
+
waiting = {}
|
|
146
|
+
end
|
|
147
|
+
local function writeSelection(object)
|
|
148
|
+
writing = true
|
|
149
|
+
GuiService.SelectedObject = object
|
|
150
|
+
selectedObject(object)
|
|
151
|
+
writing = false
|
|
152
|
+
end
|
|
153
|
+
local function canSelect(owner)
|
|
154
|
+
return native(owner) and adapter().device() == "Gamepad" and not menuOpen() and not textEditing()
|
|
155
|
+
end
|
|
156
|
+
local function request(owner, target)
|
|
157
|
+
cancelRequest()
|
|
158
|
+
local token = generation
|
|
159
|
+
local _result
|
|
160
|
+
if target == "Root" then
|
|
161
|
+
local _result_1
|
|
162
|
+
if owner == "Base" then
|
|
163
|
+
_result_1 = nil
|
|
164
|
+
else
|
|
165
|
+
local _owner = owner
|
|
166
|
+
local _result_2 = roots[_owner]
|
|
167
|
+
if _result_2 ~= nil then
|
|
168
|
+
_result_2 = _result_2.root
|
|
169
|
+
end
|
|
170
|
+
_result_1 = _result_2
|
|
171
|
+
end
|
|
172
|
+
_result = _result_1
|
|
173
|
+
else
|
|
174
|
+
_result = target
|
|
175
|
+
end
|
|
176
|
+
local object = _result
|
|
177
|
+
if not object then
|
|
178
|
+
return nil
|
|
179
|
+
end
|
|
180
|
+
local queued = false
|
|
181
|
+
local queue
|
|
182
|
+
local retry = function()
|
|
183
|
+
if token ~= generation then
|
|
184
|
+
return nil
|
|
185
|
+
end
|
|
186
|
+
queued = false
|
|
187
|
+
disconnect(waiting)
|
|
188
|
+
waiting = {}
|
|
189
|
+
if not canSelect(owner) then
|
|
190
|
+
return nil
|
|
191
|
+
end
|
|
192
|
+
local _condition = target ~= "Root"
|
|
193
|
+
if _condition then
|
|
194
|
+
local _result_1 = controls[object]
|
|
195
|
+
if _result_1 ~= nil then
|
|
196
|
+
_result_1 = _result_1.owner
|
|
197
|
+
end
|
|
198
|
+
_condition = _result_1 ~= owner
|
|
199
|
+
end
|
|
200
|
+
if _condition then
|
|
201
|
+
return nil
|
|
202
|
+
end
|
|
203
|
+
if ready(object, target == "Root") then
|
|
204
|
+
if target == "Root" then
|
|
205
|
+
writing = true
|
|
206
|
+
GuiService:Select(object)
|
|
207
|
+
selectedObject(GuiService.SelectedObject)
|
|
208
|
+
writing = false
|
|
209
|
+
else
|
|
210
|
+
writeSelection(object)
|
|
211
|
+
end
|
|
212
|
+
else
|
|
213
|
+
waiting = watch(object, queue)
|
|
214
|
+
end
|
|
215
|
+
end
|
|
216
|
+
queue = function()
|
|
217
|
+
if not queued then
|
|
218
|
+
queued = true
|
|
219
|
+
task.defer(retry)
|
|
220
|
+
end
|
|
221
|
+
end
|
|
222
|
+
queue()
|
|
223
|
+
end
|
|
224
|
+
local function dispatch(id, event)
|
|
225
|
+
local _id = id
|
|
226
|
+
local record = roots[_id]
|
|
227
|
+
if not record then
|
|
228
|
+
return nil
|
|
229
|
+
end
|
|
230
|
+
local current = GuiService.SelectedObject
|
|
231
|
+
local _exp = record.selection
|
|
232
|
+
local _exp_1 = event
|
|
233
|
+
local _object = {}
|
|
234
|
+
local _left = "current"
|
|
235
|
+
local _condition = current
|
|
236
|
+
if _condition then
|
|
237
|
+
local _result = controls[current]
|
|
238
|
+
if _result ~= nil then
|
|
239
|
+
_result = _result.owner
|
|
240
|
+
end
|
|
241
|
+
_condition = _result == id
|
|
242
|
+
end
|
|
243
|
+
_object[_left] = if _condition then current else nil
|
|
244
|
+
_object.close = record.close
|
|
245
|
+
_object.alive = function(object)
|
|
246
|
+
local _object_1 = object
|
|
247
|
+
local _result = controls[_object_1]
|
|
248
|
+
if _result ~= nil then
|
|
249
|
+
_result = _result.owner
|
|
250
|
+
end
|
|
251
|
+
local _condition_1 = _result == id
|
|
252
|
+
if _condition_1 then
|
|
253
|
+
_condition_1 = alive(object)
|
|
254
|
+
end
|
|
255
|
+
return _condition_1
|
|
256
|
+
end
|
|
257
|
+
_object.canSelect = canSelect(id)
|
|
258
|
+
local decision = decide(_exp, _exp_1, _object)
|
|
259
|
+
record.selection = decision.selection
|
|
260
|
+
if decision.target ~= nil then
|
|
261
|
+
request(id, decision.target)
|
|
262
|
+
end
|
|
263
|
+
end
|
|
264
|
+
local function cancelA()
|
|
265
|
+
local session = capturedA
|
|
266
|
+
capturedA = nil
|
|
267
|
+
local _result = session
|
|
268
|
+
if _result ~= nil then
|
|
269
|
+
_result = _result.control.buttonAUp
|
|
270
|
+
if _result ~= nil then
|
|
271
|
+
_result(session.input)
|
|
272
|
+
end
|
|
273
|
+
end
|
|
274
|
+
end
|
|
275
|
+
local function selectionChanged()
|
|
276
|
+
local previous = selectedObject()
|
|
277
|
+
local current = GuiService.SelectedObject
|
|
278
|
+
selectedObject(current)
|
|
279
|
+
disconnect(selectedWatch)
|
|
280
|
+
selectedWatch = {}
|
|
281
|
+
if capturedA and capturedA.object ~= current then
|
|
282
|
+
cancelA()
|
|
283
|
+
end
|
|
284
|
+
if not writing then
|
|
285
|
+
cancelRequest()
|
|
286
|
+
end
|
|
287
|
+
local control = current and controls[current]
|
|
288
|
+
local _condition = current and control
|
|
289
|
+
if _condition then
|
|
290
|
+
local _owner = control.owner
|
|
291
|
+
_condition = type(_owner) == "number"
|
|
292
|
+
end
|
|
293
|
+
if _condition then
|
|
294
|
+
dispatch(control.owner, {
|
|
295
|
+
kind = "Selected",
|
|
296
|
+
object = current,
|
|
297
|
+
})
|
|
298
|
+
elseif not writing then
|
|
299
|
+
local previousControl = previous and controls[previous]
|
|
300
|
+
local _owner = previousControl
|
|
301
|
+
if _owner ~= nil then
|
|
302
|
+
_owner = _owner.owner
|
|
303
|
+
end
|
|
304
|
+
local owner = _owner
|
|
305
|
+
local id = topId()
|
|
306
|
+
if previous and type(owner) == "number" and active(owner) then
|
|
307
|
+
dispatch(owner, {
|
|
308
|
+
kind = "Lost",
|
|
309
|
+
removed = not alive(previous),
|
|
310
|
+
})
|
|
311
|
+
elseif id ~= nil and ((current and not control) or (previous and not previousControl)) then
|
|
312
|
+
dispatch(id, {
|
|
313
|
+
kind = "Lost",
|
|
314
|
+
removed = false,
|
|
315
|
+
})
|
|
316
|
+
end
|
|
317
|
+
end
|
|
318
|
+
if current and control then
|
|
319
|
+
selectedWatch = watch(current, function()
|
|
320
|
+
if GuiService.SelectedObject ~= current or not active(control.owner) or alive(current) then
|
|
321
|
+
return nil
|
|
322
|
+
end
|
|
323
|
+
writeSelection()
|
|
324
|
+
local _owner = control.owner
|
|
325
|
+
if type(_owner) == "number" then
|
|
326
|
+
dispatch(control.owner, {
|
|
327
|
+
kind = "Lost",
|
|
328
|
+
removed = true,
|
|
329
|
+
})
|
|
330
|
+
end
|
|
331
|
+
end)
|
|
332
|
+
end
|
|
333
|
+
end
|
|
334
|
+
local function openRoot(mode, onClose)
|
|
335
|
+
serial += 1
|
|
336
|
+
local id = serial
|
|
337
|
+
if not modalOpen() then
|
|
338
|
+
local selected = GuiService.SelectedObject
|
|
339
|
+
local _condition = selected
|
|
340
|
+
if _condition then
|
|
341
|
+
local _result = controls[selected]
|
|
342
|
+
if _result ~= nil then
|
|
343
|
+
_result = _result.owner
|
|
344
|
+
end
|
|
345
|
+
_condition = _result == "Base"
|
|
346
|
+
end
|
|
347
|
+
baseRestore = if _condition then selected else nil
|
|
348
|
+
end
|
|
349
|
+
local _arg1 = {
|
|
350
|
+
id = id,
|
|
351
|
+
serial = id,
|
|
352
|
+
mode = mode,
|
|
353
|
+
onClose = onClose,
|
|
354
|
+
selection = emptySelection(),
|
|
355
|
+
}
|
|
356
|
+
roots[id] = _arg1
|
|
357
|
+
state(enter(state(), {
|
|
358
|
+
id = id,
|
|
359
|
+
serial = id,
|
|
360
|
+
order = nil,
|
|
361
|
+
}))
|
|
362
|
+
return id
|
|
363
|
+
end
|
|
364
|
+
local function attachRoot(id, root)
|
|
365
|
+
local _id = id
|
|
366
|
+
local record = roots[_id]
|
|
367
|
+
if not record then
|
|
368
|
+
return function() end
|
|
369
|
+
end
|
|
370
|
+
local _result = record.stopAttachment
|
|
371
|
+
if _result ~= nil then
|
|
372
|
+
_result()
|
|
373
|
+
end
|
|
374
|
+
record.root = root
|
|
375
|
+
local orderConnection
|
|
376
|
+
local update
|
|
377
|
+
update = function()
|
|
378
|
+
local _id_1 = id
|
|
379
|
+
if roots[_id_1] ~= record then
|
|
380
|
+
return nil
|
|
381
|
+
end
|
|
382
|
+
local _result_1 = orderConnection
|
|
383
|
+
if _result_1 ~= nil then
|
|
384
|
+
_result_1:Disconnect()
|
|
385
|
+
end
|
|
386
|
+
local gui = root:FindFirstAncestorWhichIsA("ScreenGui")
|
|
387
|
+
if gui then
|
|
388
|
+
orderConnection = gui:GetPropertyChangedSignal("DisplayOrder"):Connect(update)
|
|
389
|
+
end
|
|
390
|
+
local _exp = state()
|
|
391
|
+
local _object = {
|
|
392
|
+
id = id,
|
|
393
|
+
serial = record.serial,
|
|
394
|
+
}
|
|
395
|
+
local _left = "order"
|
|
396
|
+
local _result_2 = gui
|
|
397
|
+
if _result_2 ~= nil then
|
|
398
|
+
_result_2 = _result_2.DisplayOrder
|
|
399
|
+
end
|
|
400
|
+
_object[_left] = _result_2
|
|
401
|
+
state(enter(_exp, _object))
|
|
402
|
+
end
|
|
403
|
+
local connection = root.AncestryChanged:Connect(update)
|
|
404
|
+
update()
|
|
405
|
+
local detach = function()
|
|
406
|
+
connection:Disconnect()
|
|
407
|
+
local _result_1 = orderConnection
|
|
408
|
+
if _result_1 ~= nil then
|
|
409
|
+
_result_1:Disconnect()
|
|
410
|
+
end
|
|
411
|
+
end
|
|
412
|
+
record.stopAttachment = detach
|
|
413
|
+
return detach
|
|
414
|
+
end
|
|
415
|
+
local function closeRoot(id)
|
|
416
|
+
local _id = id
|
|
417
|
+
local record = roots[_id]
|
|
418
|
+
if not record then
|
|
419
|
+
return nil
|
|
420
|
+
end
|
|
421
|
+
local _result = record.stopAttachment
|
|
422
|
+
if _result ~= nil then
|
|
423
|
+
_result()
|
|
424
|
+
end
|
|
425
|
+
local wasTop = topId() == id or topId() == nil
|
|
426
|
+
local selected = GuiService.SelectedObject
|
|
427
|
+
local _condition = selected
|
|
428
|
+
if _condition then
|
|
429
|
+
local _result_1 = controls[selected]
|
|
430
|
+
if _result_1 ~= nil then
|
|
431
|
+
_result_1 = _result_1.owner
|
|
432
|
+
end
|
|
433
|
+
_condition = _result_1
|
|
434
|
+
end
|
|
435
|
+
local selectedOwner = _condition
|
|
436
|
+
local restore = wasTop and not record.selection.paused and (selected == nil or selectedOwner == id)
|
|
437
|
+
if selectedOwner == id then
|
|
438
|
+
writeSelection()
|
|
439
|
+
end
|
|
440
|
+
local _id_1 = id
|
|
441
|
+
roots[_id_1] = nil
|
|
442
|
+
state(leave(state(), id))
|
|
443
|
+
if not modalOpen() then
|
|
444
|
+
local target = baseRestore
|
|
445
|
+
baseRestore = nil
|
|
446
|
+
local _condition_1 = restore and target
|
|
447
|
+
if _condition_1 then
|
|
448
|
+
local _result_1 = controls[target]
|
|
449
|
+
if _result_1 ~= nil then
|
|
450
|
+
_result_1 = _result_1.owner
|
|
451
|
+
end
|
|
452
|
+
_condition_1 = _result_1 == "Base"
|
|
453
|
+
end
|
|
454
|
+
if _condition_1 then
|
|
455
|
+
request("Base", target)
|
|
456
|
+
end
|
|
457
|
+
end
|
|
458
|
+
end
|
|
459
|
+
local function registerControl(object, control, fallback)
|
|
460
|
+
if fallback == nil then
|
|
461
|
+
fallback = false
|
|
462
|
+
end
|
|
463
|
+
local _object = object
|
|
464
|
+
local _control = control
|
|
465
|
+
controls[_object] = _control
|
|
466
|
+
object.SelectionImageObject = blankSelectionImage
|
|
467
|
+
local _owner = control.owner
|
|
468
|
+
local _result
|
|
469
|
+
if type(_owner) == "number" then
|
|
470
|
+
local _owner_1 = control.owner
|
|
471
|
+
_result = roots[_owner_1]
|
|
472
|
+
else
|
|
473
|
+
_result = nil
|
|
474
|
+
end
|
|
475
|
+
local record = _result
|
|
476
|
+
if fallback and record then
|
|
477
|
+
record.close = object
|
|
478
|
+
end
|
|
479
|
+
return function()
|
|
480
|
+
local selected = GuiService.SelectedObject == object
|
|
481
|
+
-- Vide builds a replacement before disposing the selected control; clear before Roblox chooses a neighbour.
|
|
482
|
+
if selected then
|
|
483
|
+
writeSelection()
|
|
484
|
+
end
|
|
485
|
+
local _result_1 = capturedA
|
|
486
|
+
if _result_1 ~= nil then
|
|
487
|
+
_result_1 = _result_1.object
|
|
488
|
+
end
|
|
489
|
+
if _result_1 == object then
|
|
490
|
+
cancelA()
|
|
491
|
+
end
|
|
492
|
+
local _object_1 = object
|
|
493
|
+
controls[_object_1] = nil
|
|
494
|
+
local _result_2 = record
|
|
495
|
+
if _result_2 ~= nil then
|
|
496
|
+
_result_2 = _result_2.close
|
|
497
|
+
end
|
|
498
|
+
if _result_2 == object then
|
|
499
|
+
record.close = nil
|
|
500
|
+
end
|
|
501
|
+
local _owner_1 = control.owner
|
|
502
|
+
if type(_owner_1) == "number" then
|
|
503
|
+
dispatch(control.owner, {
|
|
504
|
+
kind = "Unmarked",
|
|
505
|
+
object = object,
|
|
506
|
+
})
|
|
507
|
+
local owner = control.owner
|
|
508
|
+
if selected then
|
|
509
|
+
task.defer(function()
|
|
510
|
+
return dispatch(owner, {
|
|
511
|
+
kind = "Lost",
|
|
512
|
+
removed = true,
|
|
513
|
+
})
|
|
514
|
+
end)
|
|
515
|
+
end
|
|
516
|
+
end
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
local function markControl(owner, object, marked)
|
|
520
|
+
local _owner = owner
|
|
521
|
+
if not (type(_owner) == "number") then
|
|
522
|
+
return nil
|
|
523
|
+
end
|
|
524
|
+
local _owner_1 = owner
|
|
525
|
+
local record = roots[_owner_1]
|
|
526
|
+
local current = GuiService.SelectedObject
|
|
527
|
+
local _condition = current
|
|
528
|
+
if _condition then
|
|
529
|
+
local _result = record
|
|
530
|
+
if _result ~= nil then
|
|
531
|
+
_result = table.find(_result.selection.marked, current) ~= nil
|
|
532
|
+
end
|
|
533
|
+
_condition = _result
|
|
534
|
+
end
|
|
535
|
+
local replaces = if _condition then current else nil
|
|
536
|
+
dispatch(owner, if marked then {
|
|
537
|
+
kind = "Marked",
|
|
538
|
+
object = object,
|
|
539
|
+
replaces = replaces,
|
|
540
|
+
} else {
|
|
541
|
+
kind = "Unmarked",
|
|
542
|
+
object = object,
|
|
543
|
+
})
|
|
544
|
+
end
|
|
545
|
+
local function useSelection(options)
|
|
546
|
+
if options == nil then
|
|
547
|
+
options = {}
|
|
548
|
+
end
|
|
549
|
+
local owner = ownerContext()
|
|
550
|
+
local fallback = closeFallbackContext()
|
|
551
|
+
local object = source()
|
|
552
|
+
local selected = useAtom(selectedObject)
|
|
553
|
+
local selectable = useAtom(function()
|
|
554
|
+
return native(owner)
|
|
555
|
+
end)
|
|
556
|
+
local allowed = useAtom(function()
|
|
557
|
+
return active(owner)
|
|
558
|
+
end)
|
|
559
|
+
videEffect(function()
|
|
560
|
+
local instance = object()
|
|
561
|
+
if instance then
|
|
562
|
+
instance.Selectable = selectable()
|
|
563
|
+
end
|
|
564
|
+
end)
|
|
565
|
+
videEffect(function()
|
|
566
|
+
local instance = object()
|
|
567
|
+
if not instance then
|
|
568
|
+
return nil
|
|
569
|
+
end
|
|
570
|
+
local _condition = options.selectFirst
|
|
571
|
+
if _condition == nil then
|
|
572
|
+
_condition = false
|
|
573
|
+
end
|
|
574
|
+
markControl(owner, instance, read(_condition))
|
|
575
|
+
cleanup(function()
|
|
576
|
+
return markControl(owner, instance, false)
|
|
577
|
+
end)
|
|
578
|
+
end)
|
|
579
|
+
return {
|
|
580
|
+
allowed = allowed,
|
|
581
|
+
selected = function()
|
|
582
|
+
return object() ~= nil and selected() == object()
|
|
583
|
+
end,
|
|
584
|
+
action = function(instance)
|
|
585
|
+
local unregister = registerControl(instance, {
|
|
586
|
+
owner = owner,
|
|
587
|
+
buttonADown = options.buttonADown,
|
|
588
|
+
buttonAUp = options.buttonAUp,
|
|
589
|
+
}, fallback)
|
|
590
|
+
object(instance)
|
|
591
|
+
cleanup(unregister)
|
|
592
|
+
end,
|
|
593
|
+
}
|
|
594
|
+
end
|
|
595
|
+
local start, stop
|
|
596
|
+
local function startMenuRuntime()
|
|
597
|
+
local host = adapter()
|
|
598
|
+
local token = {}
|
|
599
|
+
runtimeOwners[token] = true
|
|
600
|
+
-- ▼ ReadonlySet.size ▼
|
|
601
|
+
local _size = 0
|
|
602
|
+
for _ in runtimeOwners do
|
|
603
|
+
_size += 1
|
|
604
|
+
end
|
|
605
|
+
-- ▲ ReadonlySet.size ▲
|
|
606
|
+
if _size == 1 then
|
|
607
|
+
start(host)
|
|
608
|
+
end
|
|
609
|
+
return function()
|
|
610
|
+
-- ▼ Set.delete ▼
|
|
611
|
+
local _valueExisted = runtimeOwners[token] ~= nil
|
|
612
|
+
runtimeOwners[token] = nil
|
|
613
|
+
-- ▲ Set.delete ▲
|
|
614
|
+
local _condition = _valueExisted
|
|
615
|
+
if _condition then
|
|
616
|
+
_condition = next(runtimeOwners) == nil
|
|
617
|
+
end
|
|
618
|
+
if _condition then
|
|
619
|
+
local _result = stop
|
|
620
|
+
if _result ~= nil then
|
|
621
|
+
_result()
|
|
622
|
+
end
|
|
623
|
+
end
|
|
624
|
+
end
|
|
625
|
+
end
|
|
626
|
+
function start(host)
|
|
627
|
+
local armed = not host.close.held()
|
|
628
|
+
local previousTop
|
|
629
|
+
local connections = { GuiService:GetPropertyChangedSignal("SelectedObject"):Connect(selectionChanged), GuiService:GetPropertyChangedSignal("MenuIsOpen"):Connect(function()
|
|
630
|
+
return menuOpen(GuiService.MenuIsOpen)
|
|
631
|
+
end), UserInputService.TextBoxFocused:Connect(function()
|
|
632
|
+
return textEditing(true)
|
|
633
|
+
end), UserInputService.TextBoxFocusReleased:Connect(function()
|
|
634
|
+
return task.defer(function()
|
|
635
|
+
return textEditing(UserInputService:GetFocusedTextBox() ~= nil)
|
|
636
|
+
end)
|
|
637
|
+
end), UserInputService.InputBegan:Connect(function(input)
|
|
638
|
+
if input.KeyCode ~= Enum.KeyCode.ButtonA or capturedA or textEditing() or menuOpen() then
|
|
639
|
+
return nil
|
|
640
|
+
end
|
|
641
|
+
local object = GuiService.SelectedObject
|
|
642
|
+
local control = object and controls[object]
|
|
643
|
+
local _condition = not object
|
|
644
|
+
if not _condition then
|
|
645
|
+
local _result = control
|
|
646
|
+
if _result ~= nil then
|
|
647
|
+
_result = _result.buttonADown
|
|
648
|
+
end
|
|
649
|
+
_condition = not _result
|
|
650
|
+
if not _condition then
|
|
651
|
+
_condition = not native(control.owner)
|
|
652
|
+
end
|
|
653
|
+
end
|
|
654
|
+
if _condition then
|
|
655
|
+
return nil
|
|
656
|
+
end
|
|
657
|
+
capturedA = {
|
|
658
|
+
object = object,
|
|
659
|
+
input = input,
|
|
660
|
+
control = control,
|
|
661
|
+
}
|
|
662
|
+
control.buttonADown(input)
|
|
663
|
+
end), UserInputService.InputEnded:Connect(function(input)
|
|
664
|
+
local _condition = input.KeyCode == Enum.KeyCode.ButtonA
|
|
665
|
+
if _condition then
|
|
666
|
+
local _result = capturedA
|
|
667
|
+
if _result ~= nil then
|
|
668
|
+
_result = _result.input.UserInputType
|
|
669
|
+
end
|
|
670
|
+
_condition = _result == input.UserInputType
|
|
671
|
+
end
|
|
672
|
+
if _condition then
|
|
673
|
+
cancelA()
|
|
674
|
+
end
|
|
675
|
+
end), UserInputService.GamepadDisconnected:Connect(function(gamepad)
|
|
676
|
+
local _result = capturedA
|
|
677
|
+
if _result ~= nil then
|
|
678
|
+
_result = _result.input.UserInputType
|
|
679
|
+
end
|
|
680
|
+
if _result == gamepad then
|
|
681
|
+
cancelA()
|
|
682
|
+
end
|
|
683
|
+
armed = not host.close.held()
|
|
684
|
+
end) }
|
|
685
|
+
local stopClose = { host.close.onPressed(function()
|
|
686
|
+
local id = topId()
|
|
687
|
+
local record = if id ~= nil then roots[id] else nil
|
|
688
|
+
if not armed or not record or record.mode ~= "Native" or textEditing() or menuOpen() then
|
|
689
|
+
return nil
|
|
690
|
+
end
|
|
691
|
+
armed = false
|
|
692
|
+
local _result = record.onClose
|
|
693
|
+
if _result ~= nil then
|
|
694
|
+
_result()
|
|
695
|
+
end
|
|
696
|
+
end), host.close.onReleased(function()
|
|
697
|
+
armed = not host.close.held()
|
|
698
|
+
end) }
|
|
699
|
+
menuOpen(GuiService.MenuIsOpen)
|
|
700
|
+
textEditing(UserInputService:GetFocusedTextBox() ~= nil)
|
|
701
|
+
selectionChanged()
|
|
702
|
+
local stopEffects = { effect(function()
|
|
703
|
+
local id = topId()
|
|
704
|
+
cancelRequest()
|
|
705
|
+
cancelA()
|
|
706
|
+
armed = not host.close.held()
|
|
707
|
+
local old = previousTop
|
|
708
|
+
previousTop = id
|
|
709
|
+
if id ~= nil and id ~= old then
|
|
710
|
+
task.defer(function()
|
|
711
|
+
if topId() == id then
|
|
712
|
+
dispatch(id, {
|
|
713
|
+
kind = "Shown",
|
|
714
|
+
})
|
|
715
|
+
end
|
|
716
|
+
end)
|
|
717
|
+
end
|
|
718
|
+
end), effect(function()
|
|
719
|
+
local id = topId()
|
|
720
|
+
local editing = textEditing()
|
|
721
|
+
local menu = menuOpen()
|
|
722
|
+
armed = not host.close.held()
|
|
723
|
+
if editing or menu then
|
|
724
|
+
cancelRequest()
|
|
725
|
+
cancelA()
|
|
726
|
+
end
|
|
727
|
+
local _condition = id ~= nil
|
|
728
|
+
if _condition then
|
|
729
|
+
local _result = roots[id]
|
|
730
|
+
if _result ~= nil then
|
|
731
|
+
_result = _result.mode
|
|
732
|
+
end
|
|
733
|
+
_condition = _result == "Native"
|
|
734
|
+
if _condition then
|
|
735
|
+
_condition = not editing
|
|
736
|
+
end
|
|
737
|
+
end
|
|
738
|
+
if _condition then
|
|
739
|
+
if not menu and GuiService.SelectedObject == nil then
|
|
740
|
+
task.defer(function()
|
|
741
|
+
if topId() == id then
|
|
742
|
+
dispatch(id, {
|
|
743
|
+
kind = "Shown",
|
|
744
|
+
})
|
|
745
|
+
end
|
|
746
|
+
end)
|
|
747
|
+
end
|
|
748
|
+
return host.claimMenuInput()
|
|
749
|
+
end
|
|
750
|
+
end), effect(function()
|
|
751
|
+
if host.device() ~= "Gamepad" then
|
|
752
|
+
cancelRequest()
|
|
753
|
+
cancelA()
|
|
754
|
+
return nil
|
|
755
|
+
end
|
|
756
|
+
local id = topId()
|
|
757
|
+
if id ~= nil and GuiService.SelectedObject == nil then
|
|
758
|
+
task.defer(function()
|
|
759
|
+
if topId() == id then
|
|
760
|
+
dispatch(id, {
|
|
761
|
+
kind = "Shown",
|
|
762
|
+
})
|
|
763
|
+
end
|
|
764
|
+
end)
|
|
765
|
+
end
|
|
766
|
+
end) }
|
|
767
|
+
stop = function()
|
|
768
|
+
disconnect(connections)
|
|
769
|
+
for _, dispose in stopClose do
|
|
770
|
+
dispose()
|
|
771
|
+
end
|
|
772
|
+
for _, cleanupEffect in stopEffects do
|
|
773
|
+
cleanupEffect()
|
|
774
|
+
end
|
|
775
|
+
cancelA()
|
|
776
|
+
cancelRequest()
|
|
777
|
+
disconnect(selectedWatch)
|
|
778
|
+
selectedWatch = {}
|
|
779
|
+
stop = nil
|
|
780
|
+
end
|
|
781
|
+
end
|
|
782
|
+
return {
|
|
783
|
+
active = active,
|
|
784
|
+
openRoot = openRoot,
|
|
785
|
+
attachRoot = attachRoot,
|
|
786
|
+
closeRoot = closeRoot,
|
|
787
|
+
registerControl = registerControl,
|
|
788
|
+
markControl = markControl,
|
|
789
|
+
useSelection = useSelection,
|
|
790
|
+
startMenuRuntime = startMenuRuntime,
|
|
791
|
+
ownerContext = ownerContext,
|
|
792
|
+
closeFallbackContext = closeFallbackContext,
|
|
793
|
+
modalOpen = modalOpen,
|
|
794
|
+
selectedObject = selectedObject,
|
|
795
|
+
textEditing = textEditing,
|
|
796
|
+
menuOpen = menuOpen,
|
|
797
|
+
}
|