@effindomv2/fui-as 0.1.0

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.
Files changed (137) hide show
  1. package/LICENSE.md +7 -0
  2. package/browser/src/common-harness/host-imports.ts +430 -0
  3. package/browser/src/common-harness/interop.ts +39 -0
  4. package/browser/src/common-harness/managed-harness-bitmap-host.ts +92 -0
  5. package/browser/src/common-harness/managed-harness-fetch-host.ts +201 -0
  6. package/browser/src/common-harness/managed-harness-file-host.ts +1101 -0
  7. package/browser/src/common-harness/managed-harness-file-payloads.ts +143 -0
  8. package/browser/src/common-harness/managed-harness-file-types.ts +106 -0
  9. package/browser/src/common-harness/managed-harness-session.ts +15 -0
  10. package/browser/src/common-harness/managed-harness.ts +1323 -0
  11. package/browser/src/common-harness/managed-history.ts +168 -0
  12. package/browser/src/common-harness/persisted-restore-policy.ts +50 -0
  13. package/browser/src/common-harness/persisted-ui-state-controller.ts +309 -0
  14. package/browser/src/common-harness/text-session-bridge.ts +452 -0
  15. package/browser/src/common-harness/types.ts +205 -0
  16. package/browser/src/common-harness/ui-chrome.ts +191 -0
  17. package/browser/src/common-harness/ui-imports.ts +529 -0
  18. package/browser/src/common-harness/wasm-module-cache.ts +47 -0
  19. package/browser/src/common-harness.ts +27 -0
  20. package/browser/src/file-processing-worker.ts +89 -0
  21. package/browser/src/host-events.ts +97 -0
  22. package/browser/src/host-services.ts +203 -0
  23. package/browser/src/index.ts +62 -0
  24. package/browser/src/persisted-ui-state.ts +206 -0
  25. package/browser/src/routed-harness.ts +198 -0
  26. package/browser/src/worker-bootstrap.ts +483 -0
  27. package/browser/src/worker-manager.ts +230 -0
  28. package/browser/src/worker-types.ts +50 -0
  29. package/package.json +89 -0
  30. package/scripts/build-demo-as.sh +91 -0
  31. package/scripts/build.sh +325 -0
  32. package/scripts/generate-host-events.ts +175 -0
  33. package/scripts/generate-host-services.ts +157 -0
  34. package/src/Fui.ts +205 -0
  35. package/src/FuiExports.ts +55 -0
  36. package/src/FuiPrimitives.ts +15 -0
  37. package/src/FuiWorker.ts +3 -0
  38. package/src/FuiWorkerExports.ts +6 -0
  39. package/src/bindings/ui.ts +531 -0
  40. package/src/color.ts +86 -0
  41. package/src/controls/AntiSelectionArea.ts +23 -0
  42. package/src/controls/Button.ts +750 -0
  43. package/src/controls/Checkbox.ts +181 -0
  44. package/src/controls/ContextMenu.ts +885 -0
  45. package/src/controls/ControlTemplateSet.ts +37 -0
  46. package/src/controls/Dialog.ts +355 -0
  47. package/src/controls/Dropdown.ts +856 -0
  48. package/src/controls/Form.ts +110 -0
  49. package/src/controls/NavLink.ts +211 -0
  50. package/src/controls/Popup.ts +129 -0
  51. package/src/controls/ProgressBar.ts +180 -0
  52. package/src/controls/RadioButton.ts +135 -0
  53. package/src/controls/RadioGroup.ts +244 -0
  54. package/src/controls/SelectionArea.ts +75 -0
  55. package/src/controls/Slider.ts +471 -0
  56. package/src/controls/Switch.ts +132 -0
  57. package/src/controls/TextArea.ts +20 -0
  58. package/src/controls/TextInput.ts +7 -0
  59. package/src/controls/index.ts +18 -0
  60. package/src/controls/internal/ButtonPresenter.ts +95 -0
  61. package/src/controls/internal/CheckboxIndicatorPresenter.ts +93 -0
  62. package/src/controls/internal/DropdownChevronPresenter.ts +67 -0
  63. package/src/controls/internal/DropdownFieldPresenter.ts +110 -0
  64. package/src/controls/internal/DropdownOptionRowPresenter.ts +82 -0
  65. package/src/controls/internal/PopupPresenter.ts +198 -0
  66. package/src/controls/internal/PressableIndicatorPresenter.ts +32 -0
  67. package/src/controls/internal/PressableLabeledControl.ts +221 -0
  68. package/src/controls/internal/RadioIndicatorPresenter.ts +73 -0
  69. package/src/controls/internal/SliderPresenter.ts +157 -0
  70. package/src/controls/internal/SwitchIndicatorPresenter.ts +72 -0
  71. package/src/controls/internal/TextInputCore.ts +695 -0
  72. package/src/controls/internal/TextInputPresenter.ts +72 -0
  73. package/src/controls/templating.ts +54 -0
  74. package/src/core/Action.ts +94 -0
  75. package/src/core/Actions.ts +37 -0
  76. package/src/core/Animation.ts +412 -0
  77. package/src/core/Application.ts +328 -0
  78. package/src/core/Assets.ts +264 -0
  79. package/src/core/AttachedProperties.ts +32 -0
  80. package/src/core/Bitmap.ts +70 -0
  81. package/src/core/BoundCallback.ts +104 -0
  82. package/src/core/Callbacks.ts +17 -0
  83. package/src/core/ContextMenuManager.ts +466 -0
  84. package/src/core/DebugApi.ts +30 -0
  85. package/src/core/Disposable.ts +10 -0
  86. package/src/core/DragDropManager.ts +179 -0
  87. package/src/core/DragGesture.ts +184 -0
  88. package/src/core/DynamicAssetIds.ts +24 -0
  89. package/src/core/Errors.ts +48 -0
  90. package/src/core/EventRouter.ts +408 -0
  91. package/src/core/ExternalDropManager.ts +122 -0
  92. package/src/core/Fetch.ts +264 -0
  93. package/src/core/FetchFfi.ts +15 -0
  94. package/src/core/File.ts +1002 -0
  95. package/src/core/FocusAdornerManager.ts +263 -0
  96. package/src/core/FocusVisibility.ts +36 -0
  97. package/src/core/FrameScheduler.ts +28 -0
  98. package/src/core/KeyboardScroll.ts +161 -0
  99. package/src/core/KeyboardScrollTracker.ts +386 -0
  100. package/src/core/Logger.ts +80 -0
  101. package/src/core/Navigation.ts +13 -0
  102. package/src/core/Node.ts +1708 -0
  103. package/src/core/PersistedState.ts +102 -0
  104. package/src/core/PersistedUiState.ts +142 -0
  105. package/src/core/Platform.ts +219 -0
  106. package/src/core/Signal.ts +89 -0
  107. package/src/core/Theme.ts +365 -0
  108. package/src/core/Timers.ts +129 -0
  109. package/src/core/ToolTip.ts +122 -0
  110. package/src/core/ToolTipManager.ts +459 -0
  111. package/src/core/Transitions.ts +34 -0
  112. package/src/core/Typography.ts +204 -0
  113. package/src/core/Worker.ts +196 -0
  114. package/src/core/bind.ts +37 -0
  115. package/src/core/event_exports.ts +596 -0
  116. package/src/core/ffi.ts +728 -0
  117. package/src/host-services/runtime.ts +25 -0
  118. package/src/nodes/FlexBox.ts +789 -0
  119. package/src/nodes/GradientStop.ts +9 -0
  120. package/src/nodes/Grid.ts +183 -0
  121. package/src/nodes/Image.ts +189 -0
  122. package/src/nodes/Portal.ts +14 -0
  123. package/src/nodes/RichText.ts +312 -0
  124. package/src/nodes/ScrollBar.ts +570 -0
  125. package/src/nodes/ScrollBox.ts +415 -0
  126. package/src/nodes/ScrollState.ts +10 -0
  127. package/src/nodes/ScrollView.ts +511 -0
  128. package/src/nodes/Svg.ts +142 -0
  129. package/src/nodes/Text.ts +145 -0
  130. package/src/nodes/TextCore.ts +558 -0
  131. package/src/nodes/VirtualList.ts +431 -0
  132. package/src/nodes/helpers.ts +25 -0
  133. package/src/nodes/index.ts +14 -0
  134. package/src/tsconfig.json +7 -0
  135. package/src/worker/Worker.ts +169 -0
  136. package/src/worker/WorkerJob.ts +65 -0
  137. package/src/worker/ffi.ts +23 -0
@@ -0,0 +1,408 @@
1
+ import { CursorStyle, fui_set_cursor, HandleValue, KeyEventType, PointerEventType } from "./ffi";
2
+ import {
3
+ resetKeyboardFocusVisibility,
4
+ showKeyboardFocusForKeyEvent,
5
+ showKeyboardFocusForPointerEvent,
6
+ } from "./FocusVisibility";
7
+ import { ToolTipManager } from "./ToolTipManager";
8
+ import {
9
+ registerKeyboardScrollNode,
10
+ resetKeyboardScrollTracking,
11
+ trackKeyboardScrollPointerUp,
12
+ unregisterKeyboardScrollNode,
13
+ } from "./KeyboardScrollTracker";
14
+ import { DragDropEffects, DragSession, ExternalDropItemInfo, Node } from "./Node";
15
+ import { DragDropManager } from "./DragDropManager";
16
+ import { ExternalDragEventType, ExternalDropManager } from "./ExternalDropManager";
17
+ import { isCoarsePointer } from "./Platform";
18
+
19
+ export interface GlobalKeyHandler {
20
+ handleGlobalKeyEvent(eventType: KeyEventType, key: string, modifiers: u32): bool;
21
+ }
22
+
23
+ function getHandleIndex(handle: u64): u32 {
24
+ return <u32>handle;
25
+ }
26
+
27
+ function getGeneration(handle: u64): u32 {
28
+ return <u32>(handle >> 32);
29
+ }
30
+
31
+ export class EventRouter {
32
+ private static readonly nodes: Map<u32, Node> = new Map<u32, Node>();
33
+ private static readonly generations: Map<u32, u32> = new Map<u32, u32>();
34
+ private static readonly hoverStack: Array<Node> = new Array<Node>();
35
+ private static readonly keyFilterHandlers: Array<GlobalKeyHandler> = new Array<GlobalKeyHandler>();
36
+ private static readonly keyFilterTokens: Array<u32> = new Array<u32>();
37
+ private static capturedPointerHandle: u64 = <u64>HandleValue.Invalid;
38
+ private static currentCursorStyle: CursorStyle = CursorStyle.Default;
39
+ private static nextKeyFilterToken: u32 = 1;
40
+ private static focusedNode: Node | null = null;
41
+
42
+ static register(handle: u64, node: Node): void {
43
+ const index = getHandleIndex(handle);
44
+ node._bindRegisteredHandle(handle);
45
+ this.nodes.set(index, node);
46
+ this.generations.set(index, getGeneration(handle));
47
+ registerKeyboardScrollNode(node);
48
+ }
49
+
50
+ static unregister(handle: u64): void {
51
+ const node = this.resolveNode(handle);
52
+ if (node !== null) {
53
+ DragDropManager.handleNodeDestroyed(changetype<Node>(node));
54
+ ExternalDropManager.handleNodeDestroyed(changetype<Node>(node));
55
+ this.removeFromHoverStack(changetype<Node>(node));
56
+ if (this.focusedNode === node) {
57
+ this.focusedNode = null;
58
+ }
59
+ unregisterKeyboardScrollNode(changetype<Node>(node));
60
+ }
61
+ if (this.capturedPointerHandle == handle) {
62
+ this.capturedPointerHandle = <u64>HandleValue.Invalid;
63
+ }
64
+ const index = getHandleIndex(handle);
65
+ this.nodes.delete(index);
66
+ this.generations.delete(index);
67
+ this.applyCurrentCursor();
68
+ }
69
+
70
+ static dispatchPointerEvent(handle: u64, eventType: PointerEventType, x: f32, y: f32, modifiers: u32 = 0): void {
71
+ showKeyboardFocusForPointerEvent(eventType);
72
+ const pointedNode = this.resolveNode(handle);
73
+ if (eventType == PointerEventType.Up) {
74
+ trackKeyboardScrollPointerUp(pointedNode, x, y);
75
+ }
76
+ if (eventType == PointerEventType.Move || eventType == PointerEventType.Up) {
77
+ const capturedNode = this.resolveNode(this.capturedPointerHandle);
78
+ if (capturedNode !== null) {
79
+ const capturedHandle = this.capturedPointerHandle;
80
+ capturedNode._handlePointerEvent(eventType, x, y, modifiers);
81
+ DragDropManager.handlePointerEvent(pointedNode, eventType, x, y, modifiers);
82
+ if (eventType == PointerEventType.Up && this.capturedPointerHandle == capturedHandle) {
83
+ this.capturedPointerHandle = <u64>HandleValue.Invalid;
84
+ }
85
+ this.applyCurrentCursor();
86
+ return;
87
+ }
88
+ if (this.capturedPointerHandle != <u64>HandleValue.Invalid) {
89
+ this.capturedPointerHandle = <u64>HandleValue.Invalid;
90
+ }
91
+ }
92
+
93
+ if (handle == <u64>HandleValue.Invalid) {
94
+ if (eventType == PointerEventType.Leave) {
95
+ this.clearHoverStack();
96
+ }
97
+ DragDropManager.handlePointerEvent(null, eventType, x, y, modifiers);
98
+ this.applyCurrentCursor();
99
+ return;
100
+ }
101
+
102
+ const node = pointedNode;
103
+ if (node === null) {
104
+ if (eventType == PointerEventType.Leave) {
105
+ this.clearHoverStack();
106
+ }
107
+ DragDropManager.handlePointerEvent(null, eventType, x, y, modifiers);
108
+ this.applyCurrentCursor();
109
+ return;
110
+ }
111
+ if (eventType == PointerEventType.Enter) {
112
+ this.pushHover(changetype<Node>(node));
113
+ } else if (eventType == PointerEventType.Leave) {
114
+ this.popHover(changetype<Node>(node));
115
+ }
116
+ node._handlePointerEvent(eventType, x, y, modifiers);
117
+ DragDropManager.handlePointerEvent(node, eventType, x, y, modifiers);
118
+ this.applyCurrentCursor();
119
+ }
120
+
121
+ static dispatchFocusChanged(handle: u64, focused: bool): void {
122
+ const node = this.resolveNode(handle);
123
+ if (node === null) {
124
+ return;
125
+ }
126
+ if (focused) {
127
+ this.focusedNode = node;
128
+ } else if (this.focusedNode === node) {
129
+ this.focusedNode = null;
130
+ }
131
+ node._handleFocusChanged(focused);
132
+ }
133
+
134
+ static dispatchKeyEvent(handle: u64, eventType: KeyEventType, key: string, modifiers: u32): bool {
135
+ showKeyboardFocusForKeyEvent(eventType, key, modifiers);
136
+ const node = this.resolveNode(handle);
137
+ if (node === null) {
138
+ return false;
139
+ }
140
+ return node._handleKeyEvent(eventType, key, modifiers);
141
+ }
142
+
143
+ static dispatchGlobalKeyEvent(eventType: KeyEventType, key: string, modifiers: u32): bool {
144
+ showKeyboardFocusForKeyEvent(eventType, key, modifiers);
145
+ for (let index = this.keyFilterHandlers.length - 1; index >= 0; --index) {
146
+ const handler = unchecked(this.keyFilterHandlers[index]);
147
+ if (handler.handleGlobalKeyEvent(eventType, key, modifiers)) {
148
+ return true;
149
+ }
150
+ }
151
+ return false;
152
+ }
153
+
154
+ static dispatchScroll(
155
+ handle: u64,
156
+ offsetX: f32,
157
+ offsetY: f32,
158
+ contentWidth: f32,
159
+ contentHeight: f32,
160
+ viewportWidth: f32,
161
+ viewportHeight: f32,
162
+ ): void {
163
+ ToolTipManager.handleScroll();
164
+ const node = this.resolveNode(handle);
165
+ if (node === null) {
166
+ return;
167
+ }
168
+ node._handleScroll(offsetX, offsetY, contentWidth, contentHeight, viewportWidth, viewportHeight);
169
+ }
170
+
171
+ static dispatchTextChanged(handle: u64, text: string): void {
172
+ const node = this.resolveNode(handle);
173
+ if (node === null) {
174
+ return;
175
+ }
176
+ node._handleTextChanged(text);
177
+ }
178
+
179
+ static dispatchTextReplaced(handle: u64, start: u32, end: u32, text: string): void {
180
+ const node = this.resolveNode(handle);
181
+ if (node === null) {
182
+ return;
183
+ }
184
+ node._handleTextReplaced(start, end, text);
185
+ }
186
+
187
+ static dispatchSelectionChanged(handle: u64, start: u32, end: u32): void {
188
+ const node = this.resolveNode(handle);
189
+ if (node === null) {
190
+ return;
191
+ }
192
+ node._handleSelectionChanged(start, end);
193
+ }
194
+
195
+ static dispatchCrossSelectionChanged(handle: u64, text: string): void {
196
+ const node = this.resolveNode(handle);
197
+ if (node === null) {
198
+ return;
199
+ }
200
+ node._handleCrossSelectionChanged(text);
201
+ }
202
+
203
+ static dispatchExternalDropEvent(
204
+ handle: u64,
205
+ eventType: ExternalDragEventType,
206
+ x: f32,
207
+ y: f32,
208
+ modifiers: u32,
209
+ items: Array<ExternalDropItemInfo>,
210
+ ): DragDropEffects {
211
+ return ExternalDropManager.handleEvent(this.resolveNode(handle), eventType, x, y, modifiers, items);
212
+ }
213
+
214
+ static getRegisteredNode(handle: u64): Node | null {
215
+ return this.resolveNode(handle);
216
+ }
217
+
218
+ static getFocusedNode(): Node | null {
219
+ return this.focusedNode;
220
+ }
221
+
222
+ static capturePointer(handle: u64): void {
223
+ if (this.resolveNode(handle) === null) {
224
+ return;
225
+ }
226
+ this.capturedPointerHandle = handle;
227
+ this.applyCurrentCursor();
228
+ }
229
+
230
+ static releasePointer(handle: u64): void {
231
+ if (this.capturedPointerHandle == handle) {
232
+ this.capturedPointerHandle = <u64>HandleValue.Invalid;
233
+ this.applyCurrentCursor();
234
+ }
235
+ }
236
+
237
+ static reset(): void {
238
+ this.nodes.clear();
239
+ this.generations.clear();
240
+ this.capturedPointerHandle = <u64>HandleValue.Invalid;
241
+ this.hoverStack.length = 0;
242
+ this.focusedNode = null;
243
+ this.keyFilterHandlers.length = 0;
244
+ this.keyFilterTokens.length = 0;
245
+ this.nextKeyFilterToken = 1;
246
+ resetKeyboardFocusVisibility();
247
+ resetKeyboardScrollTracking();
248
+ DragDropManager.reset();
249
+ ExternalDropManager.reset();
250
+ this.applyCursor(CursorStyle.Default);
251
+ }
252
+
253
+ static beginDragSession(source: Node): bool {
254
+ return DragDropManager.beginSession(source);
255
+ }
256
+
257
+ static cancelDragSession(session: DragSession): void {
258
+ DragDropManager.cancelSession(session);
259
+ this.applyCurrentCursor();
260
+ }
261
+
262
+ static cancelDragSessionForSource(source: Node): void {
263
+ DragDropManager.cancelSessionForSource(source);
264
+ this.applyCurrentCursor();
265
+ }
266
+
267
+ static pushKeyFilter(handler: GlobalKeyHandler): u32 {
268
+ const token = this.nextKeyFilterToken;
269
+ this.nextKeyFilterToken += 1;
270
+ this.keyFilterHandlers.push(handler);
271
+ this.keyFilterTokens.push(token);
272
+ return token;
273
+ }
274
+
275
+ static removeKeyFilter(token: u32): void {
276
+ for (let index = this.keyFilterTokens.length - 1; index >= 0; --index) {
277
+ if (unchecked(this.keyFilterTokens[index]) != token) {
278
+ continue;
279
+ }
280
+ for (let cursor = index; cursor < this.keyFilterTokens.length - 1; ++cursor) {
281
+ unchecked(this.keyFilterTokens[cursor] = unchecked(this.keyFilterTokens[cursor + 1]));
282
+ unchecked(this.keyFilterHandlers[cursor] = unchecked(this.keyFilterHandlers[cursor + 1]));
283
+ }
284
+ this.keyFilterTokens.length = this.keyFilterTokens.length - 1;
285
+ this.keyFilterHandlers.length = this.keyFilterHandlers.length - 1;
286
+ return;
287
+ }
288
+ }
289
+
290
+ static removeFromHoverStack(node: Node): void {
291
+ const index = this.indexOfHoveredNode(node);
292
+ if (index < 0) {
293
+ return;
294
+ }
295
+ this.removeHoverAt(index);
296
+ this.applyCurrentCursor();
297
+ }
298
+
299
+ static handleCursorStyleChanged(node: Node): void {
300
+ const captured = this.resolveCapturedNode();
301
+ if (captured === node) {
302
+ this.applyCurrentCursor();
303
+ return;
304
+ }
305
+ if (captured !== null) {
306
+ return;
307
+ }
308
+ if (this.hoverStack.length == 0) {
309
+ return;
310
+ }
311
+ const top = unchecked(this.hoverStack[this.hoverStack.length - 1]);
312
+ if (top === node) {
313
+ this.applyCursor(node.cursorStyle);
314
+ }
315
+ }
316
+
317
+ private static resolveNode(handle: u64): Node | null {
318
+ if (handle == <u64>HandleValue.Invalid) {
319
+ return null;
320
+ }
321
+ const index = getHandleIndex(handle);
322
+ if (!this.generations.has(index)) {
323
+ return null;
324
+ }
325
+ const generation = this.generations.get(index);
326
+ if (generation != getGeneration(handle) || !this.nodes.has(index)) {
327
+ return null;
328
+ }
329
+ return this.nodes.get(index);
330
+ }
331
+
332
+ private static pushHover(node: Node): void {
333
+ const existingIndex = this.indexOfHoveredNode(node);
334
+ if (existingIndex >= 0) {
335
+ this.removeHoverAt(existingIndex);
336
+ }
337
+ this.hoverStack.push(node);
338
+ this.applyCurrentCursor();
339
+ }
340
+
341
+ private static popHover(node: Node): void {
342
+ const index = this.indexOfHoveredNode(node);
343
+ if (index < 0) {
344
+ return;
345
+ }
346
+ this.removeHoverAt(index);
347
+ this.applyCurrentCursor();
348
+ }
349
+
350
+ private static clearHoverStack(): void {
351
+ if (this.hoverStack.length == 0) {
352
+ this.applyCurrentCursor();
353
+ return;
354
+ }
355
+ this.hoverStack.length = 0;
356
+ this.applyCurrentCursor();
357
+ }
358
+
359
+ private static resolveCapturedNode(): Node | null {
360
+ return this.resolveNode(this.capturedPointerHandle);
361
+ }
362
+
363
+ private static applyCurrentCursor(): void {
364
+ const dragCursor = DragDropManager.cursorOverrideStyle();
365
+ if (dragCursor != CursorStyle.Default) {
366
+ this.applyCursor(dragCursor);
367
+ return;
368
+ }
369
+ const captured = this.resolveCapturedNode();
370
+ if (captured !== null) {
371
+ this.applyCursor(captured.cursorStyle);
372
+ return;
373
+ }
374
+ if (this.hoverStack.length == 0) {
375
+ this.applyCursor(CursorStyle.Default);
376
+ return;
377
+ }
378
+ const top = unchecked(this.hoverStack[this.hoverStack.length - 1]);
379
+ this.applyCursor(top.cursorStyle);
380
+ }
381
+
382
+ private static applyCursor(style: CursorStyle): void {
383
+ if (this.currentCursorStyle == style) {
384
+ return;
385
+ }
386
+ this.currentCursorStyle = style;
387
+ if (isCoarsePointer()) {
388
+ return;
389
+ }
390
+ fui_set_cursor(<u32>style);
391
+ }
392
+
393
+ private static indexOfHoveredNode(target: Node): i32 {
394
+ for (let index = this.hoverStack.length - 1; index >= 0; --index) {
395
+ if (unchecked(this.hoverStack[index]) === target) {
396
+ return index;
397
+ }
398
+ }
399
+ return -1;
400
+ }
401
+
402
+ private static removeHoverAt(index: i32): void {
403
+ for (let cursor = index; cursor < this.hoverStack.length - 1; ++cursor) {
404
+ unchecked(this.hoverStack[cursor] = unchecked(this.hoverStack[cursor + 1]));
405
+ }
406
+ this.hoverStack.length = this.hoverStack.length - 1;
407
+ }
408
+ }
@@ -0,0 +1,122 @@
1
+ import { DragDropEffects, DropProposal, ExternalDropEventArgs, ExternalDropItemInfo, Node } from "./Node";
2
+
3
+ export enum ExternalDragEventType {
4
+ Enter = 1,
5
+ Over = 2,
6
+ Leave = 3,
7
+ Drop = 4,
8
+ }
9
+
10
+ function normalizeEffect(candidate: DragDropEffects): DragDropEffects {
11
+ const masked = <i32>candidate & (<i32>DragDropEffects.Copy | <i32>DragDropEffects.Move | <i32>DragDropEffects.Link);
12
+ if (masked == <i32>DragDropEffects.None) {
13
+ return DragDropEffects.None;
14
+ }
15
+ if ((masked & <i32>DragDropEffects.Move) != 0) {
16
+ return DragDropEffects.Move;
17
+ }
18
+ if ((masked & <i32>DragDropEffects.Copy) != 0) {
19
+ return DragDropEffects.Copy;
20
+ }
21
+ if ((masked & <i32>DragDropEffects.Link) != 0) {
22
+ return DragDropEffects.Link;
23
+ }
24
+ return DragDropEffects.None;
25
+ }
26
+
27
+ function isDefaultProposal(proposal: DropProposal): bool {
28
+ return proposal.effect == DragDropEffects.None && !proposal.showInsertionMarker;
29
+ }
30
+
31
+ export class ExternalDropManager {
32
+ private static activeTarget: Node | null = null;
33
+ private static activeEffect: DragDropEffects = DragDropEffects.None;
34
+
35
+ static handleEvent(
36
+ pointedNode: Node | null,
37
+ eventType: ExternalDragEventType,
38
+ x: f32,
39
+ y: f32,
40
+ modifiers: u32,
41
+ items: Array<ExternalDropItemInfo>,
42
+ ): DragDropEffects {
43
+ if (eventType == ExternalDragEventType.Leave) {
44
+ this.finish(x, y, modifiers, items, true);
45
+ return DragDropEffects.None;
46
+ }
47
+
48
+ const target = this.resolveDropTarget(pointedNode);
49
+ const args = new ExternalDropEventArgs(x, y, modifiers, items);
50
+ let proposal = DropProposal.none();
51
+ if (target !== this.activeTarget) {
52
+ const previousTarget = this.activeTarget;
53
+ if (previousTarget !== null) {
54
+ previousTarget._handleExternalDragLeave(args);
55
+ }
56
+ this.activeTarget = target;
57
+ this.activeEffect = DragDropEffects.None;
58
+ if (target !== null && target._hasExternalDragEnterHandler()) {
59
+ proposal = target._handleExternalDragEnter(args);
60
+ }
61
+ }
62
+
63
+ if (target === null) {
64
+ this.activeEffect = DragDropEffects.None;
65
+ return DragDropEffects.None;
66
+ }
67
+
68
+ if (target._hasExternalDragOverHandler()) {
69
+ proposal = target._handleExternalDragOver(args);
70
+ } else if (isDefaultProposal(proposal)) {
71
+ proposal = new DropProposal(this.activeEffect, false);
72
+ }
73
+
74
+ const effect = normalizeEffect(proposal.effect);
75
+ this.activeEffect = effect;
76
+ if (eventType == ExternalDragEventType.Drop) {
77
+ if (effect != DragDropEffects.None) {
78
+ target._handleExternalDropEvent(args);
79
+ }
80
+ this.finish(x, y, modifiers, items, true);
81
+ }
82
+ return effect;
83
+ }
84
+
85
+ static handleNodeDestroyed(node: Node): void {
86
+ if (this.activeTarget === node) {
87
+ this.activeTarget = null;
88
+ this.activeEffect = DragDropEffects.None;
89
+ }
90
+ }
91
+
92
+ static reset(): void {
93
+ this.activeTarget = null;
94
+ this.activeEffect = DragDropEffects.None;
95
+ }
96
+
97
+ private static resolveDropTarget(pointedNode: Node | null): Node | null {
98
+ let current = pointedNode;
99
+ while (current !== null) {
100
+ if (current._allowsExternalDrop()) {
101
+ return current;
102
+ }
103
+ current = current.parentNode;
104
+ }
105
+ return null;
106
+ }
107
+
108
+ private static finish(
109
+ x: f32,
110
+ y: f32,
111
+ modifiers: u32,
112
+ items: Array<ExternalDropItemInfo>,
113
+ notifyTargetLeave: bool,
114
+ ): void {
115
+ const target = this.activeTarget;
116
+ this.activeTarget = null;
117
+ this.activeEffect = DragDropEffects.None;
118
+ if (notifyTargetLeave && target !== null) {
119
+ target._handleExternalDragLeave(new ExternalDropEventArgs(x, y, modifiers, items));
120
+ }
121
+ }
122
+ }