@effindomv2/fui-as 0.1.36 → 0.1.39
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/browser/routed-app-conventions.ts +1 -1
- package/browser/src/common-harness.ts +1 -27
- package/browser/src/index.ts +19 -26
- package/browser/src/routed-harness.ts +1 -194
- package/browser/src/shared-browser.ts +6 -0
- package/package.json +26 -16
- package/scripts/build.sh +51 -47
- package/scripts/framework-host-services.ts +1 -1
- package/scripts/generate-host-events.ts +15 -241
- package/scripts/generate-host-services.ts +13 -261
- package/scripts/hostgen/assemblyscript-host-events.ts +165 -0
- package/scripts/hostgen/assemblyscript-host-services.ts +207 -0
- package/scripts/hostgen/common.ts +73 -0
- package/scripts/hostgen/registry.ts +159 -0
- package/src/Fui.ts +70 -4
- package/src/FuiExports.ts +13 -1
- package/src/bindings/ui.ts +165 -8
- package/src/controls/Button.ts +98 -71
- package/src/controls/Checkbox.ts +23 -21
- package/src/controls/ComboBox.ts +1201 -0
- package/src/controls/ContextMenu.ts +279 -165
- package/src/controls/Dialog.ts +91 -17
- package/src/controls/Dropdown.ts +101 -333
- package/src/controls/NavLink.ts +29 -6
- package/src/controls/Popup.ts +10 -5
- package/src/controls/ProgressBar.ts +1 -2
- package/src/controls/RadioButton.ts +34 -13
- package/src/controls/RadioGroup.ts +32 -19
- package/src/controls/Slider.ts +21 -23
- package/src/controls/Switch.ts +34 -17
- package/src/controls/index.ts +2 -1
- package/src/controls/internal/ButtonPresenter.ts +5 -2
- package/src/controls/internal/CheckboxIndicatorPresenter.ts +10 -10
- package/src/controls/internal/DropdownChevronPresenter.ts +3 -3
- package/src/controls/internal/DropdownFieldPresenter.ts +6 -6
- package/src/controls/internal/DropdownOptionRowPresenter.ts +5 -4
- package/src/controls/internal/PressableLabeledControl.ts +4 -7
- package/src/controls/internal/RadioIndicatorPresenter.ts +7 -7
- package/src/controls/internal/SelectablePopupList.ts +463 -0
- package/src/controls/internal/SliderPresenter.ts +5 -5
- package/src/controls/internal/SwitchIndicatorPresenter.ts +63 -17
- package/src/controls/internal/TextInputCore.ts +307 -41
- package/src/controls/internal/TextInputPresenter.ts +2 -2
- package/src/controls/templating.ts +10 -0
- package/src/core/Application.ts +19 -9
- package/src/core/Bitmap.ts +219 -1
- package/src/core/ContextMenuManager.ts +128 -44
- package/src/core/DebugApi.ts +17 -2
- package/src/core/DragGesture.ts +8 -7
- package/src/core/EventRouter.ts +332 -12
- package/src/core/Fetch.ts +15 -7
- package/src/core/FetchFfi.ts +1 -15
- package/src/core/File.ts +75 -34
- package/src/core/FocusAdornerManager.ts +3 -3
- package/src/core/FocusVisibility.ts +7 -0
- package/src/core/FrameScheduler.ts +126 -0
- package/src/core/ImageSampling.ts +43 -0
- package/src/core/Logger.ts +2 -0
- package/src/core/MobileTextSelectionToolbarManager.ts +901 -0
- package/src/core/Node.ts +1039 -97
- package/src/core/Platform.ts +16 -16
- package/src/core/SelectionHandleAdornerManager.ts +697 -0
- package/src/core/Theme.ts +34 -20
- package/src/core/ToolTipManager.ts +3 -3
- package/src/core/Typography.ts +411 -19
- package/src/core/Worker.ts +69 -33
- package/src/core/event_exports.ts +123 -5
- package/src/core/ffi.ts +5 -746
- package/src/core/generated/FetchHostAbi.ts +10 -0
- package/src/core/generated/FrameworkHostServices.ts +1 -1
- package/src/core/generated/HostAbi.ts +220 -0
- package/src/core/generated/UiAbi.ts +356 -0
- package/src/core/generated/UiEnums.ts +186 -0
- package/src/drawing/DrawCallback.ts +34 -0
- package/src/drawing/DrawContext.ts +189 -0
- package/src/drawing/Paint.ts +34 -0
- package/src/drawing/Path.ts +40 -0
- package/src/nodes/CustomDrawable.ts +61 -0
- package/src/nodes/FlexBox.ts +57 -11
- package/src/nodes/Grid.ts +5 -5
- package/src/nodes/Image.ts +20 -1
- package/src/nodes/RichText.ts +36 -25
- package/src/nodes/ScrollBar.ts +2 -1
- package/src/nodes/ScrollBox.ts +7 -2
- package/src/nodes/ScrollView.ts +17 -6
- package/src/nodes/Svg.ts +18 -1
- package/src/nodes/Text.ts +1 -1
- package/src/nodes/TextCore.ts +115 -20
- package/src/nodes/index.ts +3 -1
- package/src/text/DynamicTextLayout.ts +275 -0
- package/src/text/TextLayout.ts +308 -0
- package/src/worker/Worker.ts +3 -36
- package/src/worker/WorkerJob.ts +5 -9
- package/src/worker/ffi.ts +0 -6
- package/browser/src/common-harness/host-imports.ts +0 -447
- package/browser/src/common-harness/interop.ts +0 -39
- package/browser/src/common-harness/managed-harness-bitmap-host.ts +0 -92
- package/browser/src/common-harness/managed-harness-fetch-host.ts +0 -201
- package/browser/src/common-harness/managed-harness-file-host.ts +0 -1066
- package/browser/src/common-harness/managed-harness-file-payloads.ts +0 -143
- package/browser/src/common-harness/managed-harness-file-types.ts +0 -71
- package/browser/src/common-harness/managed-harness-session.ts +0 -15
- package/browser/src/common-harness/managed-harness.ts +0 -1451
- package/browser/src/common-harness/managed-history.ts +0 -168
- package/browser/src/common-harness/persisted-restore-policy.ts +0 -50
- package/browser/src/common-harness/persisted-ui-state-controller.ts +0 -309
- package/browser/src/common-harness/text-session-bridge.ts +0 -452
- package/browser/src/common-harness/types.ts +0 -205
- package/browser/src/common-harness/ui-chrome.ts +0 -206
- package/browser/src/common-harness/ui-imports.ts +0 -553
- package/browser/src/common-harness/wasm-module-cache.ts +0 -47
- package/browser/src/file-processing-worker.ts +0 -89
- package/browser/src/host-events.ts +0 -118
- package/browser/src/host-services.ts +0 -483
- package/browser/src/persisted-ui-state.ts +0 -206
- package/browser/src/routed-app-conventions.ts +0 -292
- package/browser/src/worker-bootstrap.ts +0 -916
- package/browser/src/worker-manager.ts +0 -234
- package/browser/src/worker-types.ts +0 -68
|
@@ -16,10 +16,11 @@ import {
|
|
|
16
16
|
import { HandlerAction } from "../core/Action";
|
|
17
17
|
import { Disposable, disposeAll } from "../core/Disposable";
|
|
18
18
|
import { navigateTo } from "../core/Navigation";
|
|
19
|
+
import { Node, PointerEventArgs, VisibilityChangedEventArgs } from "../core/Node";
|
|
19
20
|
import { Theme, activeTheme } from "../core/Theme";
|
|
20
21
|
import { warn } from "../core/Logger";
|
|
21
22
|
import { FontFamily, FontStyle, FontWeight } from "../core/Typography";
|
|
22
|
-
import { FlexBox, Grid, Portal, TextCore } from "../nodes";
|
|
23
|
+
import { Border, FlexBox, Grid, Portal, TextCore } from "../nodes";
|
|
23
24
|
import { PopupPresenter } from "./internal/PopupPresenter";
|
|
24
25
|
|
|
25
26
|
const MENU_WIDTH: f32 = 220.0;
|
|
@@ -27,6 +28,10 @@ const MENU_SEPARATOR_HEIGHT: f32 = 9.0;
|
|
|
27
28
|
const MENU_EDGE_PADDING: f32 = 8.0;
|
|
28
29
|
const DEFAULT_PANEL_BACKGROUND_BLUR_SIGMA: f32 = 10.0;
|
|
29
30
|
|
|
31
|
+
function isPrimaryActivationPointer(event: PointerEventArgs): bool {
|
|
32
|
+
return event.button == 0 || event.pointerType == 2 || event.pointerType == 3;
|
|
33
|
+
}
|
|
34
|
+
|
|
30
35
|
enum MenuItemKind {
|
|
31
36
|
Action = 0,
|
|
32
37
|
Separator = 1,
|
|
@@ -34,17 +39,20 @@ enum MenuItemKind {
|
|
|
34
39
|
|
|
35
40
|
class ContextMenuEntry extends Grid {
|
|
36
41
|
private readonly labelNode: TextCore = new TextCore("")
|
|
37
|
-
.
|
|
42
|
+
.fontFamily(activeTheme.value.contextMenu.item.fontFamily)
|
|
43
|
+
.fontSize(activeTheme.value.contextMenu.item.fontSize)
|
|
38
44
|
.textColor(activeTheme.value.contextMenu.item.textColor)
|
|
39
45
|
.overflow(TextOverflow.Ellipsis)
|
|
40
46
|
.selectable(false) as TextCore;
|
|
41
47
|
private readonly shortcutNode: TextCore = new TextCore("")
|
|
42
|
-
.
|
|
48
|
+
.fontFamily(activeTheme.value.contextMenu.item.fontFamily)
|
|
49
|
+
.fontSize(activeTheme.value.contextMenu.item.fontSize)
|
|
43
50
|
.textColor(activeTheme.value.colors.textMuted)
|
|
44
51
|
.textAlign(TextAlign.Left)
|
|
45
52
|
.selectable(false) as TextCore;
|
|
46
53
|
private readonly slot: i32;
|
|
47
54
|
private hovered: bool = false;
|
|
55
|
+
private pressed: bool = false;
|
|
48
56
|
private disabled: bool = false;
|
|
49
57
|
private itemHeightValue: f32 = activeTheme.value.contextMenu.item.height;
|
|
50
58
|
private paddingLeftValue: f32 = activeTheme.value.contextMenu.item.paddingLeft;
|
|
@@ -56,12 +64,10 @@ class ContextMenuEntry extends Grid {
|
|
|
56
64
|
private shortcutTextColorValue: u32 = activeTheme.value.colors.textMuted;
|
|
57
65
|
private backgroundColorValue: u32 = activeTheme.value.contextMenu.item.background;
|
|
58
66
|
private hoverBackgroundColorValue: u32 = activeTheme.value.contextMenu.item.hoverBackground;
|
|
59
|
-
private fontIdValue: u32 = activeTheme.value.contextMenu.item.fontId;
|
|
60
67
|
private fontFamilyValue: FontFamily = activeTheme.value.contextMenu.item.fontFamily;
|
|
61
68
|
private fontSizeValue: f32 = activeTheme.value.contextMenu.item.fontSize;
|
|
62
69
|
private fontWeightValue: FontWeight = FontWeight.Regular;
|
|
63
70
|
private fontStyleValue: FontStyle = FontStyle.Normal;
|
|
64
|
-
private usesDirectFontId: bool = false;
|
|
65
71
|
|
|
66
72
|
constructor(slot: i32) {
|
|
67
73
|
super();
|
|
@@ -94,6 +100,8 @@ class ContextMenuEntry extends Grid {
|
|
|
94
100
|
}
|
|
95
101
|
|
|
96
102
|
item(item: MenuItem): this {
|
|
103
|
+
this.hovered = false;
|
|
104
|
+
this.pressed = false;
|
|
97
105
|
this.disabled = item.disabled;
|
|
98
106
|
this.semanticLabel(item.label);
|
|
99
107
|
this.semanticDisabled(this.disabled);
|
|
@@ -113,12 +121,10 @@ class ContextMenuEntry extends Grid {
|
|
|
113
121
|
textColor: u32,
|
|
114
122
|
backgroundColor: u32,
|
|
115
123
|
hoverBackgroundColor: u32,
|
|
116
|
-
fontId: u32,
|
|
117
124
|
fontFamily: FontFamily,
|
|
118
125
|
fontSize: f32,
|
|
119
126
|
fontWeight: FontWeight,
|
|
120
127
|
fontStyle: FontStyle,
|
|
121
|
-
usesDirectFontId: bool,
|
|
122
128
|
): void {
|
|
123
129
|
this.itemHeightValue = itemHeight;
|
|
124
130
|
this.paddingLeftValue = paddingLeft;
|
|
@@ -129,12 +135,10 @@ class ContextMenuEntry extends Grid {
|
|
|
129
135
|
this.textColorValue = textColor;
|
|
130
136
|
this.backgroundColorValue = backgroundColor;
|
|
131
137
|
this.hoverBackgroundColorValue = hoverBackgroundColor;
|
|
132
|
-
this.fontIdValue = fontId;
|
|
133
138
|
this.fontFamilyValue = fontFamily;
|
|
134
139
|
this.fontSizeValue = fontSize;
|
|
135
140
|
this.fontWeightValue = fontWeight;
|
|
136
141
|
this.fontStyleValue = fontStyle;
|
|
137
|
-
this.usesDirectFontId = usesDirectFontId;
|
|
138
142
|
this.applyTheme();
|
|
139
143
|
}
|
|
140
144
|
|
|
@@ -143,21 +147,16 @@ class ContextMenuEntry extends Grid {
|
|
|
143
147
|
this.padding(this.paddingLeftValue, this.paddingTopValue, this.paddingRightValue, this.paddingBottomValue);
|
|
144
148
|
this.corners(this.cornerRadiusValue, this.cornerRadiusValue, this.cornerRadiusValue, this.cornerRadiusValue);
|
|
145
149
|
this.bgColor(this.hovered && !this.disabled ? this.hoverBackgroundColorValue : this.backgroundColorValue);
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
this.
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
this.
|
|
156
|
-
.fontFamily(this.fontFamilyValue)
|
|
157
|
-
.fontWeight(this.fontWeightValue)
|
|
158
|
-
.fontStyle(this.fontStyleValue)
|
|
159
|
-
.fontSize(this.fontSizeValue);
|
|
160
|
-
}
|
|
150
|
+
this.labelNode
|
|
151
|
+
.fontFamily(this.fontFamilyValue)
|
|
152
|
+
.fontWeight(this.fontWeightValue)
|
|
153
|
+
.fontStyle(this.fontStyleValue)
|
|
154
|
+
.fontSize(this.fontSizeValue);
|
|
155
|
+
this.shortcutNode
|
|
156
|
+
.fontFamily(this.fontFamilyValue)
|
|
157
|
+
.fontWeight(this.fontWeightValue)
|
|
158
|
+
.fontStyle(this.fontStyleValue)
|
|
159
|
+
.fontSize(this.fontSizeValue);
|
|
161
160
|
this.shortcutTextColorValue = activeTheme.value.colors.textMuted;
|
|
162
161
|
this.labelNode.textColor(this.disabled ? this.shortcutTextColorValue : this.textColorValue);
|
|
163
162
|
this.shortcutNode.textColor(this.shortcutTextColorValue);
|
|
@@ -171,14 +170,26 @@ class ContextMenuEntry extends Grid {
|
|
|
171
170
|
}
|
|
172
171
|
if (eventType == PointerEventType.Leave) {
|
|
173
172
|
this.hovered = false;
|
|
173
|
+
this.pressed = false;
|
|
174
174
|
this.applyTheme();
|
|
175
175
|
return;
|
|
176
176
|
}
|
|
177
177
|
if (eventType == PointerEventType.Down) {
|
|
178
|
-
|
|
179
|
-
|
|
178
|
+
this.pressed = !this.disabled;
|
|
179
|
+
return;
|
|
180
|
+
}
|
|
181
|
+
if (eventType == PointerEventType.Up) {
|
|
182
|
+
const shouldInvoke = this.pressed &&
|
|
183
|
+
this.hovered &&
|
|
184
|
+
!this.disabled;
|
|
185
|
+
this.pressed = false;
|
|
186
|
+
if (shouldInvoke) {
|
|
187
|
+
ContextMenu.invokeActiveSlot(this.slot);
|
|
180
188
|
}
|
|
181
|
-
|
|
189
|
+
return;
|
|
190
|
+
}
|
|
191
|
+
if (eventType == PointerEventType.Cancel) {
|
|
192
|
+
this.pressed = false;
|
|
182
193
|
return;
|
|
183
194
|
}
|
|
184
195
|
super._handlePointerEvent(eventType, x, y, modifiers);
|
|
@@ -233,6 +244,7 @@ export class MenuItem {
|
|
|
233
244
|
readonly shortcutLabel: string | null;
|
|
234
245
|
readonly disabled: bool;
|
|
235
246
|
readonly targetHandle: u64;
|
|
247
|
+
readonly focusTargetAfterAction: bool;
|
|
236
248
|
selectionStart: u32;
|
|
237
249
|
selectionEnd: u32;
|
|
238
250
|
private readonly kindValue: MenuItemKind;
|
|
@@ -247,6 +259,7 @@ export class MenuItem {
|
|
|
247
259
|
targetHandle: u64 = <u64>HandleValue.Invalid,
|
|
248
260
|
selectionStart: u32 = 0,
|
|
249
261
|
selectionEnd: u32 = 0,
|
|
262
|
+
focusTargetAfterAction: bool = false,
|
|
250
263
|
) {
|
|
251
264
|
this.label = label;
|
|
252
265
|
this.action = action;
|
|
@@ -255,6 +268,7 @@ export class MenuItem {
|
|
|
255
268
|
this.shortcutLabel = shortcutLabel;
|
|
256
269
|
this.disabled = disabled;
|
|
257
270
|
this.targetHandle = targetHandle;
|
|
271
|
+
this.focusTargetAfterAction = focusTargetAfterAction;
|
|
258
272
|
this.selectionStart = selectionStart;
|
|
259
273
|
this.selectionEnd = selectionEnd;
|
|
260
274
|
}
|
|
@@ -274,6 +288,128 @@ export class MenuItem {
|
|
|
274
288
|
}
|
|
275
289
|
}
|
|
276
290
|
|
|
291
|
+
function writePayloadToClipboard(text: string): void {
|
|
292
|
+
const bytes = Uint8Array.wrap(String.UTF8.encode(text, false));
|
|
293
|
+
ffi.fui_copy_text(bytes.length > 0 ? bytes.dataStart : 0, <u32>bytes.length);
|
|
294
|
+
}
|
|
295
|
+
|
|
296
|
+
function commitFocusedTextAction(handle: u64): void {
|
|
297
|
+
ffi.fui_commit_text_action_focus(handle);
|
|
298
|
+
}
|
|
299
|
+
|
|
300
|
+
function commitFocusedTextActionIfNeeded(item: MenuItem): void {
|
|
301
|
+
if (item.focusTargetAfterAction && item.targetHandle != <u64>HandleValue.Invalid) {
|
|
302
|
+
commitFocusedTextAction(item.targetHandle);
|
|
303
|
+
}
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
export function runContextMenuAction(item: MenuItem): void {
|
|
307
|
+
if (item.disabled) {
|
|
308
|
+
const actionNeedsLiveSelection =
|
|
309
|
+
item.targetHandle != <u64>HandleValue.Invalid &&
|
|
310
|
+
(item.action == ContextMenuAction.CopyCurrentSelection || item.action == ContextMenuAction.CutTextSelection) &&
|
|
311
|
+
(ffi.fui_has_text_selection_snapshot(item.targetHandle) || ui.hasTextSelection(item.targetHandle));
|
|
312
|
+
if (!actionNeedsLiveSelection) {
|
|
313
|
+
return;
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
if (item.action == ContextMenuAction.CopyCurrentSelection) {
|
|
317
|
+
if (item.payload !== null) {
|
|
318
|
+
writePayloadToClipboard(changetype<string>(item.payload));
|
|
319
|
+
commitFocusedTextActionIfNeeded(item);
|
|
320
|
+
return;
|
|
321
|
+
}
|
|
322
|
+
if (item.targetHandle != <u64>HandleValue.Invalid && ffi.fui_copy_text_selection_snapshot(item.targetHandle)) {
|
|
323
|
+
commitFocusedTextActionIfNeeded(item);
|
|
324
|
+
return;
|
|
325
|
+
}
|
|
326
|
+
if (item.targetHandle != <u64>HandleValue.Invalid) {
|
|
327
|
+
ui.copyTextSelection(item.targetHandle);
|
|
328
|
+
commitFocusedTextActionIfNeeded(item);
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
ui.copyCurrentSelection();
|
|
332
|
+
return;
|
|
333
|
+
}
|
|
334
|
+
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.UndoTextEdit) {
|
|
335
|
+
ui.undoTextEdit(item.targetHandle);
|
|
336
|
+
commitFocusedTextActionIfNeeded(item);
|
|
337
|
+
return;
|
|
338
|
+
}
|
|
339
|
+
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.RedoTextEdit) {
|
|
340
|
+
ui.redoTextEdit(item.targetHandle);
|
|
341
|
+
commitFocusedTextActionIfNeeded(item);
|
|
342
|
+
return;
|
|
343
|
+
}
|
|
344
|
+
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.CutTextSelection) {
|
|
345
|
+
if (item.payload !== null) {
|
|
346
|
+
writePayloadToClipboard(changetype<string>(item.payload));
|
|
347
|
+
}
|
|
348
|
+
if (item.selectionStart != item.selectionEnd && ffi.fui_cut_text_selection_snapshot(item.targetHandle)) {
|
|
349
|
+
commitFocusedTextActionIfNeeded(item);
|
|
350
|
+
return;
|
|
351
|
+
}
|
|
352
|
+
if (ffi.fui_cut_text_selection_snapshot(item.targetHandle)) {
|
|
353
|
+
commitFocusedTextActionIfNeeded(item);
|
|
354
|
+
return;
|
|
355
|
+
}
|
|
356
|
+
if (
|
|
357
|
+
item.selectionStart != item.selectionEnd &&
|
|
358
|
+
ffi.fui_delete_focused_text_range(item.selectionStart, item.selectionEnd)
|
|
359
|
+
) {
|
|
360
|
+
commitFocusedTextActionIfNeeded(item);
|
|
361
|
+
return;
|
|
362
|
+
}
|
|
363
|
+
if (ffi.fui_cut_focused_text_selection()) {
|
|
364
|
+
commitFocusedTextActionIfNeeded(item);
|
|
365
|
+
return;
|
|
366
|
+
}
|
|
367
|
+
if (item.payload === null) {
|
|
368
|
+
ffi.fui_copy_text_selection_snapshot(item.targetHandle);
|
|
369
|
+
}
|
|
370
|
+
ui.cutTextSelection(item.targetHandle);
|
|
371
|
+
commitFocusedTextActionIfNeeded(item);
|
|
372
|
+
return;
|
|
373
|
+
}
|
|
374
|
+
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.PasteText) {
|
|
375
|
+
ui.pasteText(item.targetHandle);
|
|
376
|
+
commitFocusedTextActionIfNeeded(item);
|
|
377
|
+
return;
|
|
378
|
+
}
|
|
379
|
+
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.SelectAllText) {
|
|
380
|
+
ui.selectAllText(item.targetHandle);
|
|
381
|
+
commitFocusedTextActionIfNeeded(item);
|
|
382
|
+
return;
|
|
383
|
+
}
|
|
384
|
+
if (item.action == ContextMenuAction.ReloadPage) {
|
|
385
|
+
ffi.fui_reload_page();
|
|
386
|
+
return;
|
|
387
|
+
}
|
|
388
|
+
if (item.action == ContextMenuAction.NavigateBack) {
|
|
389
|
+
ffi.fui_navigate_back();
|
|
390
|
+
return;
|
|
391
|
+
}
|
|
392
|
+
if (item.action == ContextMenuAction.NavigateForward) {
|
|
393
|
+
ffi.fui_navigate_forward();
|
|
394
|
+
return;
|
|
395
|
+
}
|
|
396
|
+
if (item.payload !== null && item.action == ContextMenuAction.OpenLink) {
|
|
397
|
+
navigateTo(changetype<string>(item.payload), false);
|
|
398
|
+
return;
|
|
399
|
+
}
|
|
400
|
+
if (item.payload !== null && item.action == ContextMenuAction.OpenLinkInNewTab) {
|
|
401
|
+
navigateTo(changetype<string>(item.payload), true);
|
|
402
|
+
return;
|
|
403
|
+
}
|
|
404
|
+
if (item.payload !== null && item.action == ContextMenuAction.OpenImage) {
|
|
405
|
+
navigateTo(changetype<string>(item.payload), false);
|
|
406
|
+
return;
|
|
407
|
+
}
|
|
408
|
+
if (item.payload !== null && item.action == ContextMenuAction.OpenImageInNewTab) {
|
|
409
|
+
navigateTo(changetype<string>(item.payload), true);
|
|
410
|
+
}
|
|
411
|
+
}
|
|
412
|
+
|
|
277
413
|
export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
278
414
|
static readonly MAX_ITEMS: i32 = 25;
|
|
279
415
|
private static activeInstance: ContextMenu | null = null;
|
|
@@ -282,13 +418,17 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
282
418
|
.positionAbsolute()
|
|
283
419
|
.width(MENU_WIDTH, Unit.Pixel)
|
|
284
420
|
.padding(4.0, 4.0, 4.0, 4.0)
|
|
285
|
-
.border(1.0, activeTheme.value.contextMenu.panelBorderColor
|
|
421
|
+
.border(1.0, activeTheme.value.contextMenu.panelBorderColor) as FlexBox;
|
|
286
422
|
private readonly popupPresenter!: PopupPresenter;
|
|
287
423
|
private readonly entries: Array<ContextMenuEntry> = new Array<ContextMenuEntry>();
|
|
288
424
|
private readonly separators: Array<ContextMenuSeparator> = new Array<ContextMenuSeparator>();
|
|
425
|
+
private readonly itemsValue: Array<MenuItem> = new Array<MenuItem>();
|
|
289
426
|
private readonly currentItems: Array<MenuItem> = new Array<MenuItem>();
|
|
427
|
+
private readonly currentItemTops: Array<f32> = new Array<f32>();
|
|
428
|
+
private readonly currentItemHeights: Array<f32> = new Array<f32>();
|
|
290
429
|
private readonly disposables: Array<Disposable> = new Array<Disposable>();
|
|
291
430
|
private isMenuVisible: bool = false;
|
|
431
|
+
private suppressNextPointerUpActivation: bool = false;
|
|
292
432
|
private keyFilterToken: u32 = 0;
|
|
293
433
|
private menuWidthValue: f32 = MENU_WIDTH;
|
|
294
434
|
private itemHeightValue: f32 = activeTheme.value.contextMenu.item.height;
|
|
@@ -300,12 +440,10 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
300
440
|
private itemTextColorValue: u32 = activeTheme.value.contextMenu.item.textColor;
|
|
301
441
|
private itemBackgroundColorValue: u32 = activeTheme.value.contextMenu.item.background;
|
|
302
442
|
private itemHoverColorValue: u32 = activeTheme.value.contextMenu.item.hoverBackground;
|
|
303
|
-
private itemFontIdValue: u32 = activeTheme.value.contextMenu.item.fontId;
|
|
304
443
|
private itemFontFamilyValue: FontFamily = activeTheme.value.contextMenu.item.fontFamily;
|
|
305
444
|
private itemFontSizeValue: f32 = activeTheme.value.contextMenu.item.fontSize;
|
|
306
445
|
private itemFontWeightValue: FontWeight = FontWeight.Regular;
|
|
307
446
|
private itemFontStyleValue: FontStyle = FontStyle.Normal;
|
|
308
|
-
private itemUsesDirectFontIdValue: bool = false;
|
|
309
447
|
private panelBackgroundColorValue: u32 = activeTheme.value.contextMenu.panelBackground;
|
|
310
448
|
private panelBorderWidthValue: f32 = 1.0;
|
|
311
449
|
private panelBorderColorValue: u32 = activeTheme.value.contextMenu.panelBorderColor;
|
|
@@ -329,9 +467,9 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
329
467
|
private panelShadowOverridden: bool = false;
|
|
330
468
|
private panelBackgroundBlurOverridden: bool = false;
|
|
331
469
|
private itemMetricsOverridden: bool = false;
|
|
332
|
-
private visibilityChangedCallback: ((
|
|
470
|
+
private visibilityChangedCallback: ((event: VisibilityChangedEventArgs) => void) | null = null;
|
|
333
471
|
|
|
334
|
-
constructor() {
|
|
472
|
+
constructor(items: Array<MenuItem> | null = null) {
|
|
335
473
|
super();
|
|
336
474
|
this.popupPresenter = new PopupPresenter(this, this.panel);
|
|
337
475
|
|
|
@@ -340,13 +478,18 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
340
478
|
this.width(100.0, Unit.Percent);
|
|
341
479
|
this.height(100.0, Unit.Percent);
|
|
342
480
|
|
|
343
|
-
this.popupPresenter.overlayNode.
|
|
481
|
+
this.popupPresenter.overlayNode.onPointerUpWith(this, (menu, event: PointerEventArgs): void => {
|
|
482
|
+
menu.handleOverlayPointerUp(event);
|
|
483
|
+
});
|
|
344
484
|
Grid.sharedSizeScope(this.panel, true);
|
|
345
485
|
|
|
346
486
|
for (let index = 0; index < ContextMenu.MAX_ITEMS; ++index) {
|
|
347
487
|
this.entries.push(new ContextMenuEntry(index));
|
|
348
488
|
this.separators.push(new ContextMenuSeparator());
|
|
349
489
|
}
|
|
490
|
+
if (items !== null) {
|
|
491
|
+
this.items(changetype<Array<MenuItem>>(items));
|
|
492
|
+
}
|
|
350
493
|
this.applyTheme();
|
|
351
494
|
this.track(activeTheme.addAction(new HandlerAction<ContextMenu, Theme>(this, (menu: ContextMenu, _theme: Theme): void => {
|
|
352
495
|
menu.handleThemeChanged();
|
|
@@ -376,6 +519,15 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
376
519
|
}
|
|
377
520
|
}
|
|
378
521
|
|
|
522
|
+
static consumeOpeningPointerUpSuppression(): bool {
|
|
523
|
+
const menu = ContextMenu.activeInstance;
|
|
524
|
+
if (menu === null || !menu.suppressNextPointerUpActivation) {
|
|
525
|
+
return false;
|
|
526
|
+
}
|
|
527
|
+
menu.suppressNextPointerUpActivation = false;
|
|
528
|
+
return true;
|
|
529
|
+
}
|
|
530
|
+
|
|
379
531
|
menuWidth(value: f32): this {
|
|
380
532
|
if (value <= 0.0) {
|
|
381
533
|
warn("Layout", "ContextMenu.menuWidth() received " + value.toString() + "; clamping to 1.0.");
|
|
@@ -405,7 +557,7 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
405
557
|
return this;
|
|
406
558
|
}
|
|
407
559
|
|
|
408
|
-
onVisibilityChanged(callback: ((
|
|
560
|
+
onVisibilityChanged(callback: ((event: VisibilityChangedEventArgs) => void) | null): this {
|
|
409
561
|
this.visibilityChangedCallback = callback;
|
|
410
562
|
return this;
|
|
411
563
|
}
|
|
@@ -417,11 +569,20 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
417
569
|
return this;
|
|
418
570
|
}
|
|
419
571
|
|
|
420
|
-
panelBorder(width: f32, color: u32
|
|
572
|
+
panelBorder(width: f32, color: u32): this {
|
|
421
573
|
this.panelBorderOverridden = true;
|
|
422
574
|
this.panelBorderWidthValue = width;
|
|
423
575
|
this.panelBorderColorValue = color;
|
|
424
|
-
this.panelBorderStyleValue =
|
|
576
|
+
this.panelBorderStyleValue = BorderStyle.Solid;
|
|
577
|
+
this.applyTheme();
|
|
578
|
+
return this;
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
panelBorderConfig(border: Border): this {
|
|
582
|
+
this.panelBorderOverridden = true;
|
|
583
|
+
this.panelBorderWidthValue = border.width;
|
|
584
|
+
this.panelBorderColorValue = border.color;
|
|
585
|
+
this.panelBorderStyleValue = border.style;
|
|
425
586
|
this.applyTheme();
|
|
426
587
|
return this;
|
|
427
588
|
}
|
|
@@ -491,19 +652,9 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
491
652
|
return this;
|
|
492
653
|
}
|
|
493
654
|
|
|
494
|
-
itemFont(fontId: u32, size: f32): this {
|
|
495
|
-
this.itemFontOverridden = true;
|
|
496
|
-
this.itemFontIdValue = fontId;
|
|
497
|
-
this.itemFontSizeValue = size;
|
|
498
|
-
this.itemUsesDirectFontIdValue = true;
|
|
499
|
-
this.applyTheme();
|
|
500
|
-
return this;
|
|
501
|
-
}
|
|
502
|
-
|
|
503
655
|
itemFontFamily(family: FontFamily): this {
|
|
504
656
|
this.itemFontOverridden = true;
|
|
505
657
|
this.itemFontFamilyValue = family;
|
|
506
|
-
this.itemUsesDirectFontIdValue = false;
|
|
507
658
|
this.applyTheme();
|
|
508
659
|
return this;
|
|
509
660
|
}
|
|
@@ -511,7 +662,6 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
511
662
|
itemFontWeight(weight: FontWeight): this {
|
|
512
663
|
this.itemFontOverridden = true;
|
|
513
664
|
this.itemFontWeightValue = weight;
|
|
514
|
-
this.itemUsesDirectFontIdValue = false;
|
|
515
665
|
this.applyTheme();
|
|
516
666
|
return this;
|
|
517
667
|
}
|
|
@@ -519,7 +669,6 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
519
669
|
itemFontStyle(style: FontStyle): this {
|
|
520
670
|
this.itemFontOverridden = true;
|
|
521
671
|
this.itemFontStyleValue = style;
|
|
522
|
-
this.itemUsesDirectFontIdValue = false;
|
|
523
672
|
this.applyTheme();
|
|
524
673
|
return this;
|
|
525
674
|
}
|
|
@@ -527,7 +676,6 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
527
676
|
itemFontSize(size: f32): this {
|
|
528
677
|
this.itemFontOverridden = true;
|
|
529
678
|
this.itemFontSizeValue = size;
|
|
530
|
-
this.itemUsesDirectFontIdValue = false;
|
|
531
679
|
this.applyTheme();
|
|
532
680
|
return this;
|
|
533
681
|
}
|
|
@@ -539,15 +687,48 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
539
687
|
return this;
|
|
540
688
|
}
|
|
541
689
|
|
|
542
|
-
|
|
690
|
+
items(items: Array<MenuItem>): this {
|
|
691
|
+
this.itemsValue.length = 0;
|
|
692
|
+
for (let index = 0; index < items.length; ++index) {
|
|
693
|
+
this.itemsValue.push(unchecked(items[index]));
|
|
694
|
+
}
|
|
695
|
+
return this;
|
|
696
|
+
}
|
|
697
|
+
|
|
698
|
+
clearItems(): this {
|
|
699
|
+
this.itemsValue.length = 0;
|
|
700
|
+
return this;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
show(target: Node | null, x: f32, y: f32): void {
|
|
704
|
+
this.showImpl(target, x, y, false);
|
|
705
|
+
}
|
|
706
|
+
|
|
707
|
+
showFromContextPointer(target: Node | null, x: f32, y: f32): void {
|
|
708
|
+
this.showImpl(target, x, y, true);
|
|
709
|
+
}
|
|
710
|
+
|
|
711
|
+
private showImpl(target: Node | null, x: f32, y: f32, suppressOpeningPointerUp: bool): void {
|
|
712
|
+
let absoluteX = x;
|
|
713
|
+
let absoluteY = y;
|
|
714
|
+
if (target !== null) {
|
|
715
|
+
const bounds = changetype<Node>(target).getBounds();
|
|
716
|
+
absoluteX += unchecked(bounds[0]);
|
|
717
|
+
absoluteY += unchecked(bounds[1]);
|
|
718
|
+
}
|
|
719
|
+
|
|
543
720
|
this.clearPanel();
|
|
544
721
|
this.applyTheme();
|
|
545
722
|
|
|
546
723
|
this.currentItems.length = 0;
|
|
724
|
+
this.currentItemTops.length = 0;
|
|
725
|
+
this.currentItemHeights.length = 0;
|
|
547
726
|
let actionCount = 0;
|
|
548
727
|
let separatorCount = 0;
|
|
549
728
|
let estimatedHeight: f32 = 8.0;
|
|
729
|
+
let contentY: f32 = 0.0;
|
|
550
730
|
let lastWasSeparator = true;
|
|
731
|
+
const items = this.itemsValue;
|
|
551
732
|
const count = items.length < ContextMenu.MAX_ITEMS ? items.length : ContextMenu.MAX_ITEMS;
|
|
552
733
|
if (items.length > ContextMenu.MAX_ITEMS) {
|
|
553
734
|
warn(
|
|
@@ -571,6 +752,7 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
571
752
|
this.panel.addChildNode(separator);
|
|
572
753
|
separatorCount += 1;
|
|
573
754
|
estimatedHeight += MENU_SEPARATOR_HEIGHT;
|
|
755
|
+
contentY += MENU_SEPARATOR_HEIGHT;
|
|
574
756
|
lastWasSeparator = true;
|
|
575
757
|
continue;
|
|
576
758
|
}
|
|
@@ -579,23 +761,27 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
579
761
|
entry.item(item);
|
|
580
762
|
entry.applyTheme();
|
|
581
763
|
this.currentItems.push(item);
|
|
764
|
+
this.currentItemTops.push(contentY);
|
|
765
|
+
this.currentItemHeights.push(this.itemHeightValue);
|
|
582
766
|
this.panel.addChildNode(entry);
|
|
583
767
|
actionCount += 1;
|
|
584
768
|
estimatedHeight += this.itemHeightValue;
|
|
769
|
+
contentY += this.itemHeightValue;
|
|
585
770
|
lastWasSeparator = false;
|
|
586
771
|
}
|
|
587
772
|
|
|
588
773
|
const maxX = <f32>Math.max(0.0, ui.getViewportWidth() - this.menuWidthValue - MENU_EDGE_PADDING);
|
|
589
774
|
const maxY = <f32>Math.max(0.0, ui.getViewportHeight() - estimatedHeight - MENU_EDGE_PADDING);
|
|
590
|
-
const clampedX = <f32>Math.max(MENU_EDGE_PADDING, Math.min(
|
|
591
|
-
const clampedY = <f32>Math.max(MENU_EDGE_PADDING, Math.min(
|
|
775
|
+
const clampedX = <f32>Math.max(MENU_EDGE_PADDING, Math.min(absoluteX, maxX));
|
|
776
|
+
const clampedY = <f32>Math.max(MENU_EDGE_PADDING, Math.min(absoluteY, maxY));
|
|
592
777
|
|
|
593
778
|
this.popupPresenter.showAtPoint(clampedX, clampedY, this.menuWidthValue, estimatedHeight);
|
|
594
779
|
this.isMenuVisible = true;
|
|
780
|
+
this.suppressNextPointerUpActivation = suppressOpeningPointerUp;
|
|
595
781
|
ContextMenu.activeInstance = this;
|
|
596
782
|
const visibilityChangedCallback = this.visibilityChangedCallback;
|
|
597
783
|
if (visibilityChangedCallback !== null) {
|
|
598
|
-
visibilityChangedCallback(true);
|
|
784
|
+
visibilityChangedCallback(new VisibilityChangedEventArgs(true));
|
|
599
785
|
}
|
|
600
786
|
if (this.keyFilterToken == 0) {
|
|
601
787
|
this.keyFilterToken = EventRouter.pushKeyFilter(this);
|
|
@@ -608,6 +794,8 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
608
794
|
}
|
|
609
795
|
this.clearPanel();
|
|
610
796
|
this.currentItems.length = 0;
|
|
797
|
+
this.currentItemTops.length = 0;
|
|
798
|
+
this.currentItemHeights.length = 0;
|
|
611
799
|
this.popupPresenter.hide();
|
|
612
800
|
this.isMenuVisible = false;
|
|
613
801
|
if (ContextMenu.activeInstance === this) {
|
|
@@ -615,7 +803,7 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
615
803
|
}
|
|
616
804
|
const visibilityChangedCallback = this.visibilityChangedCallback;
|
|
617
805
|
if (visibilityChangedCallback !== null) {
|
|
618
|
-
visibilityChangedCallback(false);
|
|
806
|
+
visibilityChangedCallback(new VisibilityChangedEventArgs(false));
|
|
619
807
|
}
|
|
620
808
|
if (this.keyFilterToken != 0) {
|
|
621
809
|
EventRouter.removeKeyFilter(this.keyFilterToken);
|
|
@@ -651,126 +839,56 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
651
839
|
if (slot < 0 || slot >= this.currentItems.length) {
|
|
652
840
|
return;
|
|
653
841
|
}
|
|
654
|
-
|
|
842
|
+
runContextMenuAction(unchecked(this.currentItems[slot]));
|
|
655
843
|
this.hide();
|
|
656
844
|
}
|
|
657
845
|
|
|
658
|
-
private
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
}
|
|
662
|
-
|
|
663
|
-
private commitFocusedTextAction(handle: u64): void {
|
|
664
|
-
ffi.fui_commit_text_action_focus(handle);
|
|
665
|
-
}
|
|
666
|
-
|
|
667
|
-
private runAction(item: MenuItem): void {
|
|
668
|
-
if (item.disabled) {
|
|
669
|
-
const actionNeedsLiveSelection =
|
|
670
|
-
item.targetHandle != <u64>HandleValue.Invalid &&
|
|
671
|
-
(item.action == ContextMenuAction.CopyCurrentSelection || item.action == ContextMenuAction.CutTextSelection) &&
|
|
672
|
-
(ffi.fui_has_text_selection_snapshot(item.targetHandle) || ui.hasTextSelection(item.targetHandle));
|
|
673
|
-
if (!actionNeedsLiveSelection) {
|
|
674
|
-
return;
|
|
675
|
-
}
|
|
846
|
+
private handleOverlayPointerUp(event: PointerEventArgs): void {
|
|
847
|
+
if (!this.isMenuVisible) {
|
|
848
|
+
return;
|
|
676
849
|
}
|
|
677
|
-
if (
|
|
678
|
-
if (
|
|
679
|
-
|
|
680
|
-
if (item.targetHandle != <u64>HandleValue.Invalid) {
|
|
681
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
682
|
-
}
|
|
683
|
-
return;
|
|
684
|
-
}
|
|
685
|
-
if (item.targetHandle != <u64>HandleValue.Invalid && ffi.fui_copy_text_selection_snapshot(item.targetHandle)) {
|
|
686
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
850
|
+
if (!isPrimaryActivationPointer(event)) {
|
|
851
|
+
if (ContextMenu.consumeOpeningPointerUpSuppression()) {
|
|
852
|
+
event.handled = true;
|
|
687
853
|
return;
|
|
688
854
|
}
|
|
689
|
-
|
|
690
|
-
ui.copyTextSelection(item.targetHandle);
|
|
691
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
692
|
-
return;
|
|
693
|
-
}
|
|
694
|
-
ui.copyCurrentSelection();
|
|
695
|
-
return;
|
|
696
|
-
}
|
|
697
|
-
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.UndoTextEdit) {
|
|
698
|
-
ui.undoTextEdit(item.targetHandle);
|
|
699
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
855
|
+
event.handled = true;
|
|
700
856
|
return;
|
|
701
857
|
}
|
|
702
|
-
|
|
703
|
-
|
|
704
|
-
|
|
705
|
-
|
|
706
|
-
}
|
|
707
|
-
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.CutTextSelection) {
|
|
708
|
-
if (item.payload !== null) {
|
|
709
|
-
this.writePayloadToClipboard(changetype<string>(item.payload));
|
|
710
|
-
}
|
|
711
|
-
if (item.selectionStart != item.selectionEnd && ffi.fui_cut_text_selection_snapshot(item.targetHandle)) {
|
|
712
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
713
|
-
return;
|
|
714
|
-
}
|
|
715
|
-
if (ffi.fui_cut_text_selection_snapshot(item.targetHandle)) {
|
|
716
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
717
|
-
return;
|
|
718
|
-
}
|
|
719
|
-
if (
|
|
720
|
-
item.selectionStart != item.selectionEnd &&
|
|
721
|
-
ffi.fui_delete_focused_text_range(item.selectionStart, item.selectionEnd)
|
|
722
|
-
) {
|
|
723
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
724
|
-
return;
|
|
858
|
+
for (let slot = 0; slot < this.currentItems.length; ++slot) {
|
|
859
|
+
const entry = unchecked(this.entries[slot]);
|
|
860
|
+
if (entry.builtHandle == <u64>HandleValue.Invalid) {
|
|
861
|
+
continue;
|
|
725
862
|
}
|
|
726
|
-
|
|
727
|
-
|
|
863
|
+
const bounds = entry.getBounds();
|
|
864
|
+
const left = unchecked(bounds[0]);
|
|
865
|
+
const top = unchecked(bounds[1]);
|
|
866
|
+
const right = left + unchecked(bounds[2]);
|
|
867
|
+
const bottom = top + unchecked(bounds[3]);
|
|
868
|
+
if (event.sceneX >= left && event.sceneX <= right && event.sceneY >= top && event.sceneY <= bottom) {
|
|
869
|
+
event.handled = true;
|
|
870
|
+
this.invokeSlot(slot);
|
|
728
871
|
return;
|
|
729
872
|
}
|
|
730
|
-
if (item.payload === null) {
|
|
731
|
-
ffi.fui_copy_text_selection_snapshot(item.targetHandle);
|
|
732
|
-
}
|
|
733
|
-
ui.cutTextSelection(item.targetHandle);
|
|
734
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
735
|
-
return;
|
|
736
|
-
}
|
|
737
|
-
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.PasteText) {
|
|
738
|
-
ui.pasteText(item.targetHandle);
|
|
739
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
740
|
-
return;
|
|
741
|
-
}
|
|
742
|
-
if (item.targetHandle != <u64>HandleValue.Invalid && item.action == ContextMenuAction.SelectAllText) {
|
|
743
|
-
ui.selectAllText(item.targetHandle);
|
|
744
|
-
this.commitFocusedTextAction(item.targetHandle);
|
|
745
|
-
return;
|
|
746
873
|
}
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
751
|
-
|
|
752
|
-
ffi.fui_navigate_back();
|
|
753
|
-
return;
|
|
754
|
-
}
|
|
755
|
-
if (item.action == ContextMenuAction.NavigateForward) {
|
|
756
|
-
ffi.fui_navigate_forward();
|
|
757
|
-
return;
|
|
758
|
-
}
|
|
759
|
-
if (item.payload !== null && item.action == ContextMenuAction.OpenLink) {
|
|
760
|
-
navigateTo(changetype<string>(item.payload), false);
|
|
761
|
-
return;
|
|
762
|
-
}
|
|
763
|
-
if (item.payload !== null && item.action == ContextMenuAction.OpenLinkInNewTab) {
|
|
764
|
-
navigateTo(changetype<string>(item.payload), true);
|
|
765
|
-
return;
|
|
766
|
-
}
|
|
767
|
-
if (item.payload !== null && item.action == ContextMenuAction.OpenImage) {
|
|
768
|
-
navigateTo(changetype<string>(item.payload), false);
|
|
874
|
+
const localX = event.sceneX - this.popupPresenter.surfaceX;
|
|
875
|
+
const localY = event.sceneY - this.popupPresenter.surfaceY;
|
|
876
|
+
if (localX < 0.0 || localX > this.menuWidthValue || localY < 0.0) {
|
|
877
|
+
event.handled = true;
|
|
878
|
+
this.hide();
|
|
769
879
|
return;
|
|
770
880
|
}
|
|
771
|
-
|
|
772
|
-
|
|
881
|
+
for (let slot = 0; slot < this.currentItems.length; ++slot) {
|
|
882
|
+
const top = unchecked(this.currentItemTops[slot]);
|
|
883
|
+
const height = unchecked(this.currentItemHeights[slot]);
|
|
884
|
+
if (localY >= top && localY <= top + height) {
|
|
885
|
+
event.handled = true;
|
|
886
|
+
this.invokeSlot(slot);
|
|
887
|
+
return;
|
|
888
|
+
}
|
|
773
889
|
}
|
|
890
|
+
event.handled = true;
|
|
891
|
+
this.hide();
|
|
774
892
|
}
|
|
775
893
|
|
|
776
894
|
private applyTheme(): void {
|
|
@@ -778,7 +896,7 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
778
896
|
this.panel.bgColor(this.panelBackgroundColorValue);
|
|
779
897
|
this.panel.backgroundBlur(this.panelBackgroundBlurSigmaValue);
|
|
780
898
|
this.panel.cornerRadius(this.panelCornerRadiusValue);
|
|
781
|
-
this.panel.
|
|
899
|
+
this.panel.borderConfig(new Border(this.panelBorderWidthValue, this.panelBorderColorValue, this.panelBorderStyleValue));
|
|
782
900
|
this.panel.dropShadow(
|
|
783
901
|
this.panelShadowColorValue,
|
|
784
902
|
0.0,
|
|
@@ -797,12 +915,10 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
797
915
|
this.itemTextColorValue,
|
|
798
916
|
this.itemBackgroundColorValue,
|
|
799
917
|
this.itemHoverColorValue,
|
|
800
|
-
this.itemFontIdValue,
|
|
801
918
|
this.itemFontFamilyValue,
|
|
802
919
|
this.itemFontSizeValue,
|
|
803
920
|
this.itemFontWeightValue,
|
|
804
921
|
this.itemFontStyleValue,
|
|
805
|
-
this.itemUsesDirectFontIdValue,
|
|
806
922
|
);
|
|
807
923
|
unchecked(this.separators[index]).configureStyle(this.separatorColorValue);
|
|
808
924
|
}
|
|
@@ -834,12 +950,10 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
834
950
|
this.itemCornerRadiusValue = theme.contextMenu.item.cornerRadius;
|
|
835
951
|
}
|
|
836
952
|
if (!this.itemFontOverridden) {
|
|
837
|
-
this.itemFontIdValue = theme.contextMenu.item.fontId;
|
|
838
953
|
this.itemFontFamilyValue = theme.contextMenu.item.fontFamily;
|
|
839
954
|
this.itemFontSizeValue = theme.contextMenu.item.fontSize;
|
|
840
955
|
this.itemFontWeightValue = FontWeight.Regular;
|
|
841
956
|
this.itemFontStyleValue = FontStyle.Normal;
|
|
842
|
-
this.itemUsesDirectFontIdValue = false;
|
|
843
957
|
}
|
|
844
958
|
if (!this.separatorColorOverridden) {
|
|
845
959
|
this.separatorColorValue = theme.contextMenu.separatorColor;
|
|
@@ -882,4 +996,4 @@ export class ContextMenu extends Portal implements GlobalKeyHandler {
|
|
|
882
996
|
private track(disposable: Disposable): void {
|
|
883
997
|
this.disposables.push(disposable);
|
|
884
998
|
}
|
|
885
|
-
}
|
|
999
|
+
}
|