@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.
- package/LICENSE.md +7 -0
- package/browser/src/common-harness/host-imports.ts +430 -0
- package/browser/src/common-harness/interop.ts +39 -0
- package/browser/src/common-harness/managed-harness-bitmap-host.ts +92 -0
- package/browser/src/common-harness/managed-harness-fetch-host.ts +201 -0
- package/browser/src/common-harness/managed-harness-file-host.ts +1101 -0
- package/browser/src/common-harness/managed-harness-file-payloads.ts +143 -0
- package/browser/src/common-harness/managed-harness-file-types.ts +106 -0
- package/browser/src/common-harness/managed-harness-session.ts +15 -0
- package/browser/src/common-harness/managed-harness.ts +1323 -0
- package/browser/src/common-harness/managed-history.ts +168 -0
- package/browser/src/common-harness/persisted-restore-policy.ts +50 -0
- package/browser/src/common-harness/persisted-ui-state-controller.ts +309 -0
- package/browser/src/common-harness/text-session-bridge.ts +452 -0
- package/browser/src/common-harness/types.ts +205 -0
- package/browser/src/common-harness/ui-chrome.ts +191 -0
- package/browser/src/common-harness/ui-imports.ts +529 -0
- package/browser/src/common-harness/wasm-module-cache.ts +47 -0
- package/browser/src/common-harness.ts +27 -0
- package/browser/src/file-processing-worker.ts +89 -0
- package/browser/src/host-events.ts +97 -0
- package/browser/src/host-services.ts +203 -0
- package/browser/src/index.ts +62 -0
- package/browser/src/persisted-ui-state.ts +206 -0
- package/browser/src/routed-harness.ts +198 -0
- package/browser/src/worker-bootstrap.ts +483 -0
- package/browser/src/worker-manager.ts +230 -0
- package/browser/src/worker-types.ts +50 -0
- package/package.json +89 -0
- package/scripts/build-demo-as.sh +91 -0
- package/scripts/build.sh +325 -0
- package/scripts/generate-host-events.ts +175 -0
- package/scripts/generate-host-services.ts +157 -0
- package/src/Fui.ts +205 -0
- package/src/FuiExports.ts +55 -0
- package/src/FuiPrimitives.ts +15 -0
- package/src/FuiWorker.ts +3 -0
- package/src/FuiWorkerExports.ts +6 -0
- package/src/bindings/ui.ts +531 -0
- package/src/color.ts +86 -0
- package/src/controls/AntiSelectionArea.ts +23 -0
- package/src/controls/Button.ts +750 -0
- package/src/controls/Checkbox.ts +181 -0
- package/src/controls/ContextMenu.ts +885 -0
- package/src/controls/ControlTemplateSet.ts +37 -0
- package/src/controls/Dialog.ts +355 -0
- package/src/controls/Dropdown.ts +856 -0
- package/src/controls/Form.ts +110 -0
- package/src/controls/NavLink.ts +211 -0
- package/src/controls/Popup.ts +129 -0
- package/src/controls/ProgressBar.ts +180 -0
- package/src/controls/RadioButton.ts +135 -0
- package/src/controls/RadioGroup.ts +244 -0
- package/src/controls/SelectionArea.ts +75 -0
- package/src/controls/Slider.ts +471 -0
- package/src/controls/Switch.ts +132 -0
- package/src/controls/TextArea.ts +20 -0
- package/src/controls/TextInput.ts +7 -0
- package/src/controls/index.ts +18 -0
- package/src/controls/internal/ButtonPresenter.ts +95 -0
- package/src/controls/internal/CheckboxIndicatorPresenter.ts +93 -0
- package/src/controls/internal/DropdownChevronPresenter.ts +67 -0
- package/src/controls/internal/DropdownFieldPresenter.ts +110 -0
- package/src/controls/internal/DropdownOptionRowPresenter.ts +82 -0
- package/src/controls/internal/PopupPresenter.ts +198 -0
- package/src/controls/internal/PressableIndicatorPresenter.ts +32 -0
- package/src/controls/internal/PressableLabeledControl.ts +221 -0
- package/src/controls/internal/RadioIndicatorPresenter.ts +73 -0
- package/src/controls/internal/SliderPresenter.ts +157 -0
- package/src/controls/internal/SwitchIndicatorPresenter.ts +72 -0
- package/src/controls/internal/TextInputCore.ts +695 -0
- package/src/controls/internal/TextInputPresenter.ts +72 -0
- package/src/controls/templating.ts +54 -0
- package/src/core/Action.ts +94 -0
- package/src/core/Actions.ts +37 -0
- package/src/core/Animation.ts +412 -0
- package/src/core/Application.ts +328 -0
- package/src/core/Assets.ts +264 -0
- package/src/core/AttachedProperties.ts +32 -0
- package/src/core/Bitmap.ts +70 -0
- package/src/core/BoundCallback.ts +104 -0
- package/src/core/Callbacks.ts +17 -0
- package/src/core/ContextMenuManager.ts +466 -0
- package/src/core/DebugApi.ts +30 -0
- package/src/core/Disposable.ts +10 -0
- package/src/core/DragDropManager.ts +179 -0
- package/src/core/DragGesture.ts +184 -0
- package/src/core/DynamicAssetIds.ts +24 -0
- package/src/core/Errors.ts +48 -0
- package/src/core/EventRouter.ts +408 -0
- package/src/core/ExternalDropManager.ts +122 -0
- package/src/core/Fetch.ts +264 -0
- package/src/core/FetchFfi.ts +15 -0
- package/src/core/File.ts +1002 -0
- package/src/core/FocusAdornerManager.ts +263 -0
- package/src/core/FocusVisibility.ts +36 -0
- package/src/core/FrameScheduler.ts +28 -0
- package/src/core/KeyboardScroll.ts +161 -0
- package/src/core/KeyboardScrollTracker.ts +386 -0
- package/src/core/Logger.ts +80 -0
- package/src/core/Navigation.ts +13 -0
- package/src/core/Node.ts +1708 -0
- package/src/core/PersistedState.ts +102 -0
- package/src/core/PersistedUiState.ts +142 -0
- package/src/core/Platform.ts +219 -0
- package/src/core/Signal.ts +89 -0
- package/src/core/Theme.ts +365 -0
- package/src/core/Timers.ts +129 -0
- package/src/core/ToolTip.ts +122 -0
- package/src/core/ToolTipManager.ts +459 -0
- package/src/core/Transitions.ts +34 -0
- package/src/core/Typography.ts +204 -0
- package/src/core/Worker.ts +196 -0
- package/src/core/bind.ts +37 -0
- package/src/core/event_exports.ts +596 -0
- package/src/core/ffi.ts +728 -0
- package/src/host-services/runtime.ts +25 -0
- package/src/nodes/FlexBox.ts +789 -0
- package/src/nodes/GradientStop.ts +9 -0
- package/src/nodes/Grid.ts +183 -0
- package/src/nodes/Image.ts +189 -0
- package/src/nodes/Portal.ts +14 -0
- package/src/nodes/RichText.ts +312 -0
- package/src/nodes/ScrollBar.ts +570 -0
- package/src/nodes/ScrollBox.ts +415 -0
- package/src/nodes/ScrollState.ts +10 -0
- package/src/nodes/ScrollView.ts +511 -0
- package/src/nodes/Svg.ts +142 -0
- package/src/nodes/Text.ts +145 -0
- package/src/nodes/TextCore.ts +558 -0
- package/src/nodes/VirtualList.ts +431 -0
- package/src/nodes/helpers.ts +25 -0
- package/src/nodes/index.ts +14 -0
- package/src/tsconfig.json +7 -0
- package/src/worker/Worker.ts +169 -0
- package/src/worker/WorkerJob.ts +65 -0
- package/src/worker/ffi.ts +23 -0
|
@@ -0,0 +1,183 @@
|
|
|
1
|
+
import * as ui from "../bindings/ui";
|
|
2
|
+
import { setGridSharedSizeScope } from "../core/AttachedProperties";
|
|
3
|
+
import { GridUnit, HandleValue, NodeType } from "../core/ffi";
|
|
4
|
+
import { Node } from "../core/Node";
|
|
5
|
+
import { FlexBox } from "./FlexBox";
|
|
6
|
+
|
|
7
|
+
class GridPlacement {
|
|
8
|
+
readonly child: Node;
|
|
9
|
+
readonly row: u32;
|
|
10
|
+
readonly col: u32;
|
|
11
|
+
readonly rowSpan: u32;
|
|
12
|
+
readonly colSpan: u32;
|
|
13
|
+
|
|
14
|
+
constructor(child: Node, row: u32, col: u32, rowSpan: u32, colSpan: u32) {
|
|
15
|
+
this.child = child;
|
|
16
|
+
this.row = row;
|
|
17
|
+
this.col = col;
|
|
18
|
+
this.rowSpan = rowSpan;
|
|
19
|
+
this.colSpan = colSpan;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export class Grid extends FlexBox {
|
|
24
|
+
private columnValues: Float32Array | null = null;
|
|
25
|
+
private columnTypes: Uint8Array | null = null;
|
|
26
|
+
private rowValues: Float32Array | null = null;
|
|
27
|
+
private rowTypes: Uint8Array | null = null;
|
|
28
|
+
private readonly columnSharedSizeGroups: Array<string> = new Array<string>();
|
|
29
|
+
private readonly rowSharedSizeGroups: Array<string> = new Array<string>();
|
|
30
|
+
private readonly placements: Array<GridPlacement> = new Array<GridPlacement>();
|
|
31
|
+
|
|
32
|
+
static sharedSizeScope(target: Node, enabled: bool = true): void {
|
|
33
|
+
if (!setGridSharedSizeScope(target._attachedPropertyKey(), enabled)) {
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const handle = target.builtHandle;
|
|
37
|
+
if (handle != <u64>HandleValue.Invalid) {
|
|
38
|
+
ui.setIsSharedSizeScope(handle, enabled);
|
|
39
|
+
target._notifyRetainedLayoutMutation();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
columns(count: u32, values: Array<f32>, types: Array<GridUnit>): this {
|
|
44
|
+
const valueCount = <u32>values.length;
|
|
45
|
+
const typeCount = <u32>types.length;
|
|
46
|
+
this.columnValues = new Float32Array(count);
|
|
47
|
+
this.columnTypes = new Uint8Array(count);
|
|
48
|
+
for (let i: u32 = 0; i < count; ++i) {
|
|
49
|
+
if (i < valueCount) {
|
|
50
|
+
unchecked(changetype<Float32Array>(this.columnValues)[i] = unchecked(values[i]));
|
|
51
|
+
}
|
|
52
|
+
if (i < typeCount) {
|
|
53
|
+
unchecked(changetype<Uint8Array>(this.columnTypes)[i] = <u8>unchecked(types[i]));
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
return this;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
rows(count: u32, values: Array<f32>, types: Array<GridUnit>): this {
|
|
60
|
+
const valueCount = <u32>values.length;
|
|
61
|
+
const typeCount = <u32>types.length;
|
|
62
|
+
this.rowValues = new Float32Array(count);
|
|
63
|
+
this.rowTypes = new Uint8Array(count);
|
|
64
|
+
for (let i: u32 = 0; i < count; ++i) {
|
|
65
|
+
if (i < valueCount) {
|
|
66
|
+
unchecked(changetype<Float32Array>(this.rowValues)[i] = unchecked(values[i]));
|
|
67
|
+
}
|
|
68
|
+
if (i < typeCount) {
|
|
69
|
+
unchecked(changetype<Uint8Array>(this.rowTypes)[i] = <u8>unchecked(types[i]));
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
placeChild(child: Node, row: u32, col: u32, rowSpan: u32 = 1, colSpan: u32 = 1): this {
|
|
76
|
+
this.appendChild(child);
|
|
77
|
+
this.placements.push(new GridPlacement(child, row, col, rowSpan, colSpan));
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
columnSharedSizeGroup(index: u32, group: string): this {
|
|
82
|
+
while (<u32>this.columnSharedSizeGroups.length <= index) {
|
|
83
|
+
this.columnSharedSizeGroups.push("");
|
|
84
|
+
}
|
|
85
|
+
unchecked(this.columnSharedSizeGroups[index] = group);
|
|
86
|
+
if (this.hasBuiltHandle()) {
|
|
87
|
+
ui.gridSetColumnSharedSizeGroup(this.handle, index, group);
|
|
88
|
+
this.notifyRetainedLayoutMutation();
|
|
89
|
+
}
|
|
90
|
+
return this;
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
clearColumnSharedSizeGroup(index: u32): this {
|
|
94
|
+
if (index < <u32>this.columnSharedSizeGroups.length) {
|
|
95
|
+
unchecked(this.columnSharedSizeGroups[index] = "");
|
|
96
|
+
if (this.hasBuiltHandle()) {
|
|
97
|
+
ui.gridSetColumnSharedSizeGroup(this.handle, index, "");
|
|
98
|
+
this.notifyRetainedLayoutMutation();
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return this;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
rowSharedSizeGroup(index: u32, group: string): this {
|
|
105
|
+
while (<u32>this.rowSharedSizeGroups.length <= index) {
|
|
106
|
+
this.rowSharedSizeGroups.push("");
|
|
107
|
+
}
|
|
108
|
+
unchecked(this.rowSharedSizeGroups[index] = group);
|
|
109
|
+
if (this.hasBuiltHandle()) {
|
|
110
|
+
ui.gridSetRowSharedSizeGroup(this.handle, index, group);
|
|
111
|
+
this.notifyRetainedLayoutMutation();
|
|
112
|
+
}
|
|
113
|
+
return this;
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
clearRowSharedSizeGroup(index: u32): this {
|
|
117
|
+
if (index < <u32>this.rowSharedSizeGroups.length) {
|
|
118
|
+
unchecked(this.rowSharedSizeGroups[index] = "");
|
|
119
|
+
if (this.hasBuiltHandle()) {
|
|
120
|
+
ui.gridSetRowSharedSizeGroup(this.handle, index, "");
|
|
121
|
+
this.notifyRetainedLayoutMutation();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
return this;
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
onClick(cb: () => void): this {
|
|
128
|
+
super.onClick(cb);
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
onPointerEnter(cb: () => void): this {
|
|
133
|
+
super.onPointerEnter(cb);
|
|
134
|
+
return this;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
onPointerLeave(cb: () => void): this {
|
|
138
|
+
super.onPointerLeave(cb);
|
|
139
|
+
return this;
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
build(): u64 {
|
|
143
|
+
if (this.hasBuiltHandle()) {
|
|
144
|
+
return this.handle;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
this.buildStyledNode(NodeType.Grid, false);
|
|
148
|
+
if (this.columnValues !== null && this.columnTypes !== null) {
|
|
149
|
+
ui.gridSetColumns(this.handle, changetype<Float32Array>(this.columnValues), changetype<Uint8Array>(this.columnTypes));
|
|
150
|
+
}
|
|
151
|
+
if (this.rowValues !== null && this.rowTypes !== null) {
|
|
152
|
+
ui.gridSetRows(this.handle, changetype<Float32Array>(this.rowValues), changetype<Uint8Array>(this.rowTypes));
|
|
153
|
+
}
|
|
154
|
+
for (let i = 0; i < this.columnSharedSizeGroups.length; ++i) {
|
|
155
|
+
const group = unchecked(this.columnSharedSizeGroups[i]);
|
|
156
|
+
if (group.length > 0) {
|
|
157
|
+
ui.gridSetColumnSharedSizeGroup(this.handle, <u32>i, group);
|
|
158
|
+
}
|
|
159
|
+
}
|
|
160
|
+
for (let i = 0; i < this.rowSharedSizeGroups.length; ++i) {
|
|
161
|
+
const group = unchecked(this.rowSharedSizeGroups[i]);
|
|
162
|
+
if (group.length > 0) {
|
|
163
|
+
ui.gridSetRowSharedSizeGroup(this.handle, <u32>i, group);
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
for (let i = 0; i < this.placements.length; ++i) {
|
|
167
|
+
const placement = unchecked(this.placements[i]);
|
|
168
|
+
const childHandle = placement.child.build();
|
|
169
|
+
ui.addChild(this.handle, childHandle);
|
|
170
|
+
ui.setGridPlacement(childHandle, placement.row, placement.col, placement.rowSpan, placement.colSpan);
|
|
171
|
+
}
|
|
172
|
+
return this.handle;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
dispose(): void {
|
|
176
|
+
this.placements.length = 0;
|
|
177
|
+
super.dispose();
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
protected usesFlexChildLayoutDiagnostics(): bool {
|
|
181
|
+
return false;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
@@ -0,0 +1,189 @@
|
|
|
1
|
+
import {
|
|
2
|
+
acquireTextureAsset,
|
|
3
|
+
AssetLoadState,
|
|
4
|
+
getTextureAssetError,
|
|
5
|
+
getTextureAssetHeight,
|
|
6
|
+
getTextureAssetState,
|
|
7
|
+
getTextureAssetUrl,
|
|
8
|
+
getTextureAssetWidth,
|
|
9
|
+
releaseTextureAsset,
|
|
10
|
+
} from "../core/Assets";
|
|
11
|
+
import * as ui from "../bindings/ui";
|
|
12
|
+
import { HandleValue, NodeType, ObjectFit, SemanticRole } from "../core/ffi";
|
|
13
|
+
import { Signal } from "../core/Signal";
|
|
14
|
+
import { FlexBox, FlexBoxProps } from "./FlexBox";
|
|
15
|
+
|
|
16
|
+
export class Image extends FlexBox {
|
|
17
|
+
private textureIdValue: u32;
|
|
18
|
+
private sourceUrlValue: string = "";
|
|
19
|
+
private objectFitValue: ObjectFit;
|
|
20
|
+
private ownedTextureAssetId: u32 = 0;
|
|
21
|
+
private hasNinePatch: bool = false;
|
|
22
|
+
private insetLeft: f32 = 0.0;
|
|
23
|
+
private insetTop: f32 = 0.0;
|
|
24
|
+
private insetRight: f32 = 0.0;
|
|
25
|
+
private insetBottom: f32 = 0.0;
|
|
26
|
+
|
|
27
|
+
constructor(textureId: u32 = 0, objectFit: ObjectFit = ObjectFit.Fill) {
|
|
28
|
+
super();
|
|
29
|
+
this.textureIdValue = textureId;
|
|
30
|
+
this.objectFitValue = objectFit;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
static from(props: FlexBoxProps, textureId: u32 = 0, objectFit: ObjectFit = ObjectFit.Fill): Image {
|
|
34
|
+
const image = new Image(textureId, objectFit);
|
|
35
|
+
return image.applyProps(props);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
static load(url: string, objectFit: ObjectFit = ObjectFit.Fill): Image {
|
|
39
|
+
return new Image(0, objectFit).source(url);
|
|
40
|
+
}
|
|
41
|
+
|
|
42
|
+
static fromUrl(props: FlexBoxProps, url: string, objectFit: ObjectFit = ObjectFit.Fill): Image {
|
|
43
|
+
return Image.load(url, objectFit).applyProps(props);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
texture(textureId: u32): this {
|
|
47
|
+
this.releaseOwnedSourceAsset();
|
|
48
|
+
this.sourceUrlValue = "";
|
|
49
|
+
this.textureIdValue = textureId;
|
|
50
|
+
if (this.hasBuiltHandle()) {
|
|
51
|
+
this.applyImageSource();
|
|
52
|
+
this.notifyRetainedMutation();
|
|
53
|
+
}
|
|
54
|
+
return this;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
source(url: string): this {
|
|
58
|
+
if (url.length == 0) {
|
|
59
|
+
return this.clearSource();
|
|
60
|
+
}
|
|
61
|
+
if (this.ownedTextureAssetId != 0 && this.sourceUrlValue == url) {
|
|
62
|
+
return this;
|
|
63
|
+
}
|
|
64
|
+
this.releaseOwnedSourceAsset();
|
|
65
|
+
this.sourceUrlValue = url;
|
|
66
|
+
this.textureIdValue = acquireTextureAsset(url);
|
|
67
|
+
this.ownedTextureAssetId = this.textureIdValue;
|
|
68
|
+
if (this.hasBuiltHandle()) {
|
|
69
|
+
this.applyImageSource();
|
|
70
|
+
this.notifyRetainedMutation();
|
|
71
|
+
}
|
|
72
|
+
return this;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
clearSource(): this {
|
|
76
|
+
this.releaseOwnedSourceAsset();
|
|
77
|
+
this.sourceUrlValue = "";
|
|
78
|
+
this.textureIdValue = 0;
|
|
79
|
+
this.hasNinePatch = false;
|
|
80
|
+
this.insetLeft = 0.0;
|
|
81
|
+
this.insetTop = 0.0;
|
|
82
|
+
this.insetRight = 0.0;
|
|
83
|
+
this.insetBottom = 0.0;
|
|
84
|
+
if (this.hasBuiltHandle()) {
|
|
85
|
+
this.applyImageSource();
|
|
86
|
+
this.notifyRetainedMutation();
|
|
87
|
+
}
|
|
88
|
+
return this;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
objectFit(objectFit: ObjectFit): this {
|
|
92
|
+
this.objectFitValue = objectFit;
|
|
93
|
+
if (this.hasBuiltHandle()) {
|
|
94
|
+
this.applyImageSource();
|
|
95
|
+
this.notifyRetainedMutation();
|
|
96
|
+
}
|
|
97
|
+
return this;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
altText(value: string): this {
|
|
101
|
+
this.semanticRole(SemanticRole.Image);
|
|
102
|
+
this.semanticLabel(value);
|
|
103
|
+
return this;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
imageNine(insetLeft: f32, insetTop: f32, insetRight: f32, insetBottom: f32): this {
|
|
107
|
+
this.hasNinePatch = true;
|
|
108
|
+
this.insetLeft = insetLeft;
|
|
109
|
+
this.insetTop = insetTop;
|
|
110
|
+
this.insetRight = insetRight;
|
|
111
|
+
this.insetBottom = insetBottom;
|
|
112
|
+
if (this.hasBuiltHandle()) {
|
|
113
|
+
this.applyImageSource();
|
|
114
|
+
this.notifyRetainedMutation();
|
|
115
|
+
}
|
|
116
|
+
return this;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
clearImageNine(): this {
|
|
120
|
+
this.hasNinePatch = false;
|
|
121
|
+
this.insetLeft = 0.0;
|
|
122
|
+
this.insetTop = 0.0;
|
|
123
|
+
this.insetRight = 0.0;
|
|
124
|
+
this.insetBottom = 0.0;
|
|
125
|
+
if (this.hasBuiltHandle()) {
|
|
126
|
+
this.applyImageSource();
|
|
127
|
+
this.notifyRetainedMutation();
|
|
128
|
+
}
|
|
129
|
+
return this;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
build(): u64 {
|
|
133
|
+
this.buildStyledNode(NodeType.Image, false);
|
|
134
|
+
this.applyImageSource();
|
|
135
|
+
return this.handle;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
dispose(): void {
|
|
139
|
+
this.releaseOwnedSourceAsset();
|
|
140
|
+
super.dispose();
|
|
141
|
+
}
|
|
142
|
+
|
|
143
|
+
assetStateSignal(): Signal<AssetLoadState> {
|
|
144
|
+
return getTextureAssetState(this.textureIdValue);
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
assetState(): AssetLoadState {
|
|
148
|
+
return this.assetStateSignal().value;
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
assetError(): string {
|
|
152
|
+
return getTextureAssetError(this.textureIdValue);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
assetUrl(): string {
|
|
156
|
+
return this.sourceUrlValue.length > 0 ? this.sourceUrlValue : getTextureAssetUrl(this.textureIdValue);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
assetWidth(): f32 {
|
|
160
|
+
return getTextureAssetWidth(this.textureIdValue);
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
assetHeight(): f32 {
|
|
164
|
+
return getTextureAssetHeight(this.textureIdValue);
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private applyImageSource(): void {
|
|
168
|
+
if (this.hasNinePatch) {
|
|
169
|
+
ui.setImageNine(
|
|
170
|
+
this.handle,
|
|
171
|
+
this.textureIdValue,
|
|
172
|
+
this.insetLeft,
|
|
173
|
+
this.insetTop,
|
|
174
|
+
this.insetRight,
|
|
175
|
+
this.insetBottom,
|
|
176
|
+
);
|
|
177
|
+
return;
|
|
178
|
+
}
|
|
179
|
+
ui.setImage(this.handle, this.textureIdValue, <u32>this.objectFitValue);
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
private releaseOwnedSourceAsset(): void {
|
|
183
|
+
if (this.ownedTextureAssetId == 0) {
|
|
184
|
+
return;
|
|
185
|
+
}
|
|
186
|
+
releaseTextureAsset(this.ownedTextureAssetId);
|
|
187
|
+
this.ownedTextureAssetId = 0;
|
|
188
|
+
}
|
|
189
|
+
}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { FlexBox, FlexBoxProps } from "./FlexBox";
|
|
2
|
+
|
|
3
|
+
export class Portal extends FlexBox {
|
|
4
|
+
constructor() {
|
|
5
|
+
super();
|
|
6
|
+
this.clipToBounds(false);
|
|
7
|
+
this.setPortalFlag(true);
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
static from(props: FlexBoxProps): Portal {
|
|
11
|
+
const portal = new Portal();
|
|
12
|
+
return portal.applyProps(props);
|
|
13
|
+
}
|
|
14
|
+
}
|
|
@@ -0,0 +1,312 @@
|
|
|
1
|
+
import { activeTheme } from "../core/Theme";
|
|
2
|
+
import { warn } from "../core/Logger";
|
|
3
|
+
import { FontFamily, FontStack, FontStyle, FontWeight } from "../core/Typography";
|
|
4
|
+
import { Text } from "./Text";
|
|
5
|
+
|
|
6
|
+
export class RichTextSpan {
|
|
7
|
+
private static readonly DECORATION_UNDERLINE: u32 = 1;
|
|
8
|
+
private static readonly DECORATION_STRIKETHROUGH: u32 = 2;
|
|
9
|
+
|
|
10
|
+
private readonly value: string;
|
|
11
|
+
private hasColorValue: bool = false;
|
|
12
|
+
private colorValue: u32 = 0;
|
|
13
|
+
private hasBackgroundColorValue: bool = false;
|
|
14
|
+
private backgroundColorValue: u32 = 0;
|
|
15
|
+
private decorationFlags: u32 = 0;
|
|
16
|
+
private hasFontFamilyValue: bool = false;
|
|
17
|
+
private fontFamilyValue: FontFamily | null = null;
|
|
18
|
+
private hasFontSizeValue: bool = false;
|
|
19
|
+
private fontSizeValue: f32 = 0.0;
|
|
20
|
+
private hasFontWeightValue: bool = false;
|
|
21
|
+
private fontWeightValue: FontWeight = FontWeight.Regular;
|
|
22
|
+
private hasFontStyleValue: bool = false;
|
|
23
|
+
private fontStyleValue: FontStyle = FontStyle.Normal;
|
|
24
|
+
|
|
25
|
+
constructor(text: string) {
|
|
26
|
+
this.value = text;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
get text(): string {
|
|
30
|
+
return this.value;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
color(color: u32): this {
|
|
34
|
+
this.hasColorValue = true;
|
|
35
|
+
this.colorValue = color;
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
bgColor(color: u32): this {
|
|
40
|
+
this.hasBackgroundColorValue = true;
|
|
41
|
+
this.backgroundColorValue = color;
|
|
42
|
+
return this;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
underline(): this {
|
|
46
|
+
this.decorationFlags |= RichTextSpan.DECORATION_UNDERLINE;
|
|
47
|
+
return this;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
strikethrough(): this {
|
|
51
|
+
this.decorationFlags |= RichTextSpan.DECORATION_STRIKETHROUGH;
|
|
52
|
+
return this;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
fontFamily(family: FontFamily): this {
|
|
56
|
+
this.hasFontFamilyValue = true;
|
|
57
|
+
this.fontFamilyValue = family;
|
|
58
|
+
return this;
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
fontSize(size: f32): this {
|
|
62
|
+
this.hasFontSizeValue = true;
|
|
63
|
+
this.fontSizeValue = size;
|
|
64
|
+
return this;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
fontWeight(weight: FontWeight): this {
|
|
68
|
+
this.hasFontWeightValue = true;
|
|
69
|
+
this.fontWeightValue = weight;
|
|
70
|
+
return this;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
fontStyle(style: FontStyle): this {
|
|
74
|
+
this.hasFontStyleValue = true;
|
|
75
|
+
this.fontStyleValue = style;
|
|
76
|
+
return this;
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
bold(): this {
|
|
80
|
+
return this.fontWeight(FontWeight.Bold);
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
italic(): this {
|
|
84
|
+
return this.fontStyle(FontStyle.Italic);
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
_hasColor(): bool {
|
|
88
|
+
return this.hasColorValue;
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
_colorOr(defaultColor: u32): u32 {
|
|
92
|
+
return this.hasColorValue ? this.colorValue : defaultColor;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
_resolvedFontSize(defaultSize: f32): f32 {
|
|
96
|
+
return this.hasFontSizeValue ? this.fontSizeValue : defaultSize;
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
_hasBackgroundColor(): bool {
|
|
100
|
+
return this.hasBackgroundColorValue;
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
_backgroundColorOr(defaultColor: u32): u32 {
|
|
104
|
+
return this.hasBackgroundColorValue ? this.backgroundColorValue : defaultColor;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
_decorationFlags(): u32 {
|
|
108
|
+
return this.decorationFlags;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
_hasFontFamily(): bool {
|
|
112
|
+
return this.hasFontFamilyValue;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
_hasFontWeight(): bool {
|
|
116
|
+
return this.hasFontWeightValue;
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
_hasFontStyle(): bool {
|
|
120
|
+
return this.hasFontStyleValue;
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
_fontFamilyOr(defaultFamily: FontFamily): FontFamily {
|
|
124
|
+
return this.hasFontFamilyValue && this.fontFamilyValue !== null
|
|
125
|
+
? changetype<FontFamily>(this.fontFamilyValue)
|
|
126
|
+
: defaultFamily;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
_fontWeightOr(defaultWeight: FontWeight): FontWeight {
|
|
130
|
+
return this.hasFontWeightValue ? this.fontWeightValue : defaultWeight;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
_fontStyleOr(defaultStyle: FontStyle): FontStyle {
|
|
134
|
+
return this.hasFontStyleValue ? this.fontStyleValue : defaultStyle;
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
export class Span extends RichTextSpan {
|
|
139
|
+
constructor(text: string) {
|
|
140
|
+
super(text);
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
export function span(text: string): RichTextSpan {
|
|
145
|
+
return new Span(text);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
const STYLE_RUN_WORD_STRIDE: i32 = 7;
|
|
149
|
+
|
|
150
|
+
export class RichText extends Text {
|
|
151
|
+
private hasBaseFontValue: bool = false;
|
|
152
|
+
private baseUsesDirectFontId: bool = false;
|
|
153
|
+
private baseFontIdValue: u32 = 0;
|
|
154
|
+
private baseFontFamilyValue: FontFamily | null = null;
|
|
155
|
+
private hasBaseFontSizeValue: bool = false;
|
|
156
|
+
private baseFontSizeValue: f32 = 0.0;
|
|
157
|
+
private hasBaseFontWeightValue: bool = false;
|
|
158
|
+
private baseFontWeightValue: FontWeight = FontWeight.Regular;
|
|
159
|
+
private hasBaseFontStyleValue: bool = false;
|
|
160
|
+
private baseFontStyleValue: FontStyle = FontStyle.Normal;
|
|
161
|
+
private hasBaseColorValue: bool = false;
|
|
162
|
+
private baseColorValue: u32 = 0;
|
|
163
|
+
private fragments: Array<RichTextSpan> = new Array<RichTextSpan>();
|
|
164
|
+
|
|
165
|
+
constructor(fragments: Array<RichTextSpan> = new Array<RichTextSpan>()) {
|
|
166
|
+
super("");
|
|
167
|
+
this.fragmentsValue(fragments);
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
fragmentsValue(fragments: Array<RichTextSpan>): this {
|
|
171
|
+
this.fragments.length = 0;
|
|
172
|
+
for (let i = 0; i < fragments.length; ++i) {
|
|
173
|
+
this.fragments.push(unchecked(fragments[i]));
|
|
174
|
+
}
|
|
175
|
+
this.rebuildAttributedText();
|
|
176
|
+
return this;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
font(fontId: u32, size: f32): this {
|
|
180
|
+
this.hasBaseFontValue = true;
|
|
181
|
+
this.baseUsesDirectFontId = true;
|
|
182
|
+
this.baseFontIdValue = fontId;
|
|
183
|
+
this.baseFontFamilyValue = null;
|
|
184
|
+
this.hasBaseFontSizeValue = true;
|
|
185
|
+
this.baseFontSizeValue = size;
|
|
186
|
+
if (fontId == 0) {
|
|
187
|
+
warn("Typography", "RichText.font() received font id 0; the text will render with the default font fallback.");
|
|
188
|
+
}
|
|
189
|
+
this.rebuildAttributedText();
|
|
190
|
+
return this;
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
fontStack(stack: FontStack, size: f32): this {
|
|
194
|
+
return this.font(stack.id, size);
|
|
195
|
+
}
|
|
196
|
+
|
|
197
|
+
fontFamily(family: FontFamily): this {
|
|
198
|
+
this.hasBaseFontValue = true;
|
|
199
|
+
this.baseUsesDirectFontId = false;
|
|
200
|
+
this.baseFontFamilyValue = family;
|
|
201
|
+
this.rebuildAttributedText();
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
fontWeight(weight: FontWeight): this {
|
|
206
|
+
this.hasBaseFontValue = true;
|
|
207
|
+
this.baseFontWeightValue = weight;
|
|
208
|
+
this.hasBaseFontWeightValue = true;
|
|
209
|
+
this.rebuildAttributedText();
|
|
210
|
+
return this;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
fontStyle(style: FontStyle): this {
|
|
214
|
+
this.hasBaseFontValue = true;
|
|
215
|
+
this.baseFontStyleValue = style;
|
|
216
|
+
this.hasBaseFontStyleValue = true;
|
|
217
|
+
this.rebuildAttributedText();
|
|
218
|
+
return this;
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
fontSize(size: f32): this {
|
|
222
|
+
this.hasBaseFontValue = true;
|
|
223
|
+
this.baseFontSizeValue = size;
|
|
224
|
+
this.hasBaseFontSizeValue = true;
|
|
225
|
+
this.rebuildAttributedText();
|
|
226
|
+
return this;
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
textColor(color: u32): this {
|
|
230
|
+
this.baseColorValue = color;
|
|
231
|
+
this.hasBaseColorValue = true;
|
|
232
|
+
this.rebuildAttributedText();
|
|
233
|
+
return this;
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
push(fragment: RichTextSpan): this {
|
|
237
|
+
this.fragments.push(fragment);
|
|
238
|
+
this.rebuildAttributedText();
|
|
239
|
+
return this;
|
|
240
|
+
}
|
|
241
|
+
|
|
242
|
+
static fromText(text: string): RichText {
|
|
243
|
+
return new RichText([span(text)]);
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
text(content: string): this {
|
|
247
|
+
return this.fragmentsValue([span(content)]);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
private rebuildAttributedText(): void {
|
|
251
|
+
const fonts = activeTheme.value.fonts;
|
|
252
|
+
const defaultFamily = this.baseFontFamilyValue !== null ? changetype<FontFamily>(this.baseFontFamilyValue) : fonts.bodyFamily;
|
|
253
|
+
const defaultWeight = this.hasBaseFontWeightValue ? this.baseFontWeightValue : FontWeight.Regular;
|
|
254
|
+
const defaultStyle = this.hasBaseFontStyleValue ? this.baseFontStyleValue : FontStyle.Normal;
|
|
255
|
+
const defaultSize = this.hasBaseFontSizeValue ? this.baseFontSizeValue : fonts.sizeBody;
|
|
256
|
+
const defaultColor = this.hasBaseColorValue ? this.baseColorValue : activeTheme.value.colors.textPrimary;
|
|
257
|
+
if (this.hasBaseFontValue || this.fragments.length > 0) {
|
|
258
|
+
if (this.baseUsesDirectFontId) {
|
|
259
|
+
super.font(this.baseFontIdValue, defaultSize);
|
|
260
|
+
} else {
|
|
261
|
+
super.font(
|
|
262
|
+
defaultFamily.resolve(defaultWeight, defaultStyle),
|
|
263
|
+
defaultSize,
|
|
264
|
+
);
|
|
265
|
+
}
|
|
266
|
+
}
|
|
267
|
+
super.textColor(defaultColor);
|
|
268
|
+
let merged = "";
|
|
269
|
+
for (let i = 0; i < this.fragments.length; ++i) {
|
|
270
|
+
merged += unchecked(this.fragments[i]).text;
|
|
271
|
+
}
|
|
272
|
+
super.text(merged);
|
|
273
|
+
if (this.fragments.length === 0) {
|
|
274
|
+
this.setTextStyleRunsWords(null);
|
|
275
|
+
return;
|
|
276
|
+
}
|
|
277
|
+
const words = new Uint32Array(this.fragments.length * STYLE_RUN_WORD_STRIDE);
|
|
278
|
+
let byteOffset: i32 = 0;
|
|
279
|
+
for (let i = 0; i < this.fragments.length; ++i) {
|
|
280
|
+
const piece = unchecked(this.fragments[i]);
|
|
281
|
+
const pieceBytes = String.UTF8.encode(piece.text, false).byteLength;
|
|
282
|
+
const start = byteOffset;
|
|
283
|
+
const end = byteOffset + pieceBytes;
|
|
284
|
+
const base = i * STYLE_RUN_WORD_STRIDE;
|
|
285
|
+
const pieceFamily = piece._hasFontFamily() ? piece._fontFamilyOr(defaultFamily) : defaultFamily;
|
|
286
|
+
const pieceWeight = piece._fontWeightOr(defaultWeight);
|
|
287
|
+
const pieceStyle = piece._fontStyleOr(defaultStyle);
|
|
288
|
+
const resolvedFontId = this.baseUsesDirectFontId && !piece._hasFontFamily()
|
|
289
|
+
? this.baseFontIdValue
|
|
290
|
+
: pieceFamily.resolve(pieceWeight, pieceStyle);
|
|
291
|
+
if (resolvedFontId == 0) {
|
|
292
|
+
warn(
|
|
293
|
+
"Typography",
|
|
294
|
+
"RichText fragment resolved font id 0 for bytes " +
|
|
295
|
+
start.toString() +
|
|
296
|
+
".." +
|
|
297
|
+
end.toString() +
|
|
298
|
+
"; check the configured FontFamily or font id.",
|
|
299
|
+
);
|
|
300
|
+
}
|
|
301
|
+
words[base] = <u32>start;
|
|
302
|
+
words[base + 1] = <u32>end;
|
|
303
|
+
words[base + 2] = <u32>resolvedFontId;
|
|
304
|
+
words[base + 3] = reinterpret<u32>(piece._resolvedFontSize(defaultSize));
|
|
305
|
+
words[base + 4] = piece._colorOr(defaultColor);
|
|
306
|
+
words[base + 5] = piece._backgroundColorOr(0);
|
|
307
|
+
words[base + 6] = piece._decorationFlags();
|
|
308
|
+
byteOffset = end;
|
|
309
|
+
}
|
|
310
|
+
this.setTextStyleRunsWords(words);
|
|
311
|
+
}
|
|
312
|
+
}
|