imxc 0.3.2 → 0.4.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/README.md +28 -0
- package/dist/compile.js +66 -4
- package/dist/components.js +10 -10
- package/dist/emitter.d.ts +1 -1
- package/dist/emitter.js +171 -47
- package/dist/init.js +409 -388
- package/dist/ir.d.ts +14 -0
- package/dist/lowering.d.ts +3 -2
- package/dist/lowering.js +128 -32
- package/package.json +1 -1
package/dist/ir.d.ts
CHANGED
|
@@ -12,6 +12,7 @@ export interface IRComponent {
|
|
|
12
12
|
stateSlots: IRStateSlot[];
|
|
13
13
|
bufferCount: number;
|
|
14
14
|
params: IRPropParam[];
|
|
15
|
+
namedPropsType?: string;
|
|
15
16
|
body: IRNode[];
|
|
16
17
|
}
|
|
17
18
|
export interface IRStateSlot {
|
|
@@ -47,6 +48,7 @@ export interface IRButton {
|
|
|
47
48
|
kind: 'button';
|
|
48
49
|
title: string;
|
|
49
50
|
action: string[];
|
|
51
|
+
disabled?: boolean;
|
|
50
52
|
style?: string;
|
|
51
53
|
loc?: SourceLoc;
|
|
52
54
|
}
|
|
@@ -64,6 +66,7 @@ export interface IRCheckbox {
|
|
|
64
66
|
stateVar: string;
|
|
65
67
|
valueExpr?: string;
|
|
66
68
|
onChangeExpr?: string;
|
|
69
|
+
directBind?: boolean;
|
|
67
70
|
style?: string;
|
|
68
71
|
loc?: SourceLoc;
|
|
69
72
|
}
|
|
@@ -125,6 +128,7 @@ export interface IRSliderFloat {
|
|
|
125
128
|
stateVar: string;
|
|
126
129
|
valueExpr?: string;
|
|
127
130
|
onChangeExpr?: string;
|
|
131
|
+
directBind?: boolean;
|
|
128
132
|
min: string;
|
|
129
133
|
max: string;
|
|
130
134
|
style?: string;
|
|
@@ -136,6 +140,7 @@ export interface IRSliderInt {
|
|
|
136
140
|
stateVar: string;
|
|
137
141
|
valueExpr?: string;
|
|
138
142
|
onChangeExpr?: string;
|
|
143
|
+
directBind?: boolean;
|
|
139
144
|
min: string;
|
|
140
145
|
max: string;
|
|
141
146
|
style?: string;
|
|
@@ -147,6 +152,7 @@ export interface IRDragFloat {
|
|
|
147
152
|
stateVar: string;
|
|
148
153
|
valueExpr?: string;
|
|
149
154
|
onChangeExpr?: string;
|
|
155
|
+
directBind?: boolean;
|
|
150
156
|
speed: string;
|
|
151
157
|
style?: string;
|
|
152
158
|
loc?: SourceLoc;
|
|
@@ -157,6 +163,7 @@ export interface IRDragInt {
|
|
|
157
163
|
stateVar: string;
|
|
158
164
|
valueExpr?: string;
|
|
159
165
|
onChangeExpr?: string;
|
|
166
|
+
directBind?: boolean;
|
|
160
167
|
speed: string;
|
|
161
168
|
style?: string;
|
|
162
169
|
loc?: SourceLoc;
|
|
@@ -167,6 +174,7 @@ export interface IRCombo {
|
|
|
167
174
|
stateVar: string;
|
|
168
175
|
valueExpr?: string;
|
|
169
176
|
onChangeExpr?: string;
|
|
177
|
+
directBind?: boolean;
|
|
170
178
|
items: string;
|
|
171
179
|
style?: string;
|
|
172
180
|
loc?: SourceLoc;
|
|
@@ -177,6 +185,7 @@ export interface IRInputInt {
|
|
|
177
185
|
stateVar: string;
|
|
178
186
|
valueExpr?: string;
|
|
179
187
|
onChangeExpr?: string;
|
|
188
|
+
directBind?: boolean;
|
|
180
189
|
style?: string;
|
|
181
190
|
loc?: SourceLoc;
|
|
182
191
|
}
|
|
@@ -186,6 +195,7 @@ export interface IRInputFloat {
|
|
|
186
195
|
stateVar: string;
|
|
187
196
|
valueExpr?: string;
|
|
188
197
|
onChangeExpr?: string;
|
|
198
|
+
directBind?: boolean;
|
|
189
199
|
style?: string;
|
|
190
200
|
loc?: SourceLoc;
|
|
191
201
|
}
|
|
@@ -193,6 +203,7 @@ export interface IRColorEdit {
|
|
|
193
203
|
kind: 'color_edit';
|
|
194
204
|
label: string;
|
|
195
205
|
stateVar: string;
|
|
206
|
+
directBind?: boolean;
|
|
196
207
|
style?: string;
|
|
197
208
|
loc?: SourceLoc;
|
|
198
209
|
}
|
|
@@ -202,6 +213,7 @@ export interface IRListBox {
|
|
|
202
213
|
stateVar: string;
|
|
203
214
|
valueExpr?: string;
|
|
204
215
|
onChangeExpr?: string;
|
|
216
|
+
directBind?: boolean;
|
|
205
217
|
items: string;
|
|
206
218
|
style?: string;
|
|
207
219
|
loc?: SourceLoc;
|
|
@@ -252,6 +264,7 @@ export interface IRRadio {
|
|
|
252
264
|
stateVar: string;
|
|
253
265
|
valueExpr?: string;
|
|
254
266
|
onChangeExpr?: string;
|
|
267
|
+
directBind?: boolean;
|
|
255
268
|
index: string;
|
|
256
269
|
style?: string;
|
|
257
270
|
loc?: SourceLoc;
|
|
@@ -268,6 +281,7 @@ export interface IRColorPicker {
|
|
|
268
281
|
kind: 'color_picker';
|
|
269
282
|
label: string;
|
|
270
283
|
stateVar: string;
|
|
284
|
+
directBind?: boolean;
|
|
271
285
|
style?: string;
|
|
272
286
|
loc?: SourceLoc;
|
|
273
287
|
}
|
package/dist/lowering.d.ts
CHANGED
|
@@ -1,16 +1,17 @@
|
|
|
1
1
|
import ts from 'typescript';
|
|
2
2
|
import type { ParsedFile } from './parser.js';
|
|
3
3
|
import type { ValidationResult } from './validator.js';
|
|
4
|
-
import type { IRComponent, IRStateSlot } from './ir.js';
|
|
4
|
+
import type { IRComponent, IRStateSlot, IRType } from './ir.js';
|
|
5
5
|
interface LoweringContext {
|
|
6
6
|
stateVars: Map<string, IRStateSlot>;
|
|
7
7
|
setterMap: Map<string, string>;
|
|
8
8
|
propsParam: string | null;
|
|
9
|
+
propsFieldTypes: Map<string, IRType | 'callback'>;
|
|
9
10
|
bufferIndex: number;
|
|
10
11
|
sourceFile: ts.SourceFile;
|
|
11
12
|
customComponents: Map<string, string>;
|
|
12
13
|
}
|
|
13
|
-
export declare function lowerComponent(parsed: ParsedFile, validation: ValidationResult): IRComponent;
|
|
14
|
+
export declare function lowerComponent(parsed: ParsedFile, validation: ValidationResult, externalInterfaces?: Map<string, Map<string, IRType | 'callback'>>): IRComponent;
|
|
14
15
|
/**
|
|
15
16
|
* Convert a TypeScript expression to C++ code string.
|
|
16
17
|
*/
|
package/dist/lowering.js
CHANGED
|
@@ -4,7 +4,7 @@ function getLoc(node, ctx) {
|
|
|
4
4
|
const { line } = ctx.sourceFile.getLineAndCharacterOfPosition(node.getStart());
|
|
5
5
|
return { file: ctx.sourceFile.fileName, line: line + 1 };
|
|
6
6
|
}
|
|
7
|
-
export function lowerComponent(parsed, validation) {
|
|
7
|
+
export function lowerComponent(parsed, validation, externalInterfaces) {
|
|
8
8
|
const func = parsed.component;
|
|
9
9
|
const name = func.name.text;
|
|
10
10
|
// Build state slots
|
|
@@ -24,19 +24,37 @@ export function lowerComponent(parsed, validation) {
|
|
|
24
24
|
}
|
|
25
25
|
// Detect props parameter
|
|
26
26
|
let propsParam = null;
|
|
27
|
+
let namedPropsType;
|
|
27
28
|
const params = [];
|
|
29
|
+
const propsFieldTypes = new Map();
|
|
28
30
|
if (func.parameters.length > 0) {
|
|
29
31
|
const param = func.parameters[0];
|
|
30
32
|
if (ts.isIdentifier(param.name)) {
|
|
31
33
|
propsParam = param.name.text;
|
|
32
34
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
35
|
+
if (param.type) {
|
|
36
|
+
if (ts.isTypeLiteralNode(param.type)) {
|
|
37
|
+
// Inline type literal: extract field types
|
|
38
|
+
for (const member of param.type.members) {
|
|
39
|
+
if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
|
|
40
|
+
const propName = member.name.text;
|
|
41
|
+
const propType = inferPropType(member);
|
|
42
|
+
params.push({ name: propName, type: propType });
|
|
43
|
+
propsFieldTypes.set(propName, propType);
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
else if (ts.isTypeReferenceNode(param.type) && ts.isIdentifier(param.type.typeName)) {
|
|
48
|
+
// Named interface reference: extract the type name and scan source for the interface
|
|
49
|
+
namedPropsType = param.type.typeName.text;
|
|
50
|
+
// First try the source file itself, then fall back to external interfaces
|
|
51
|
+
extractInterfaceFields(namedPropsType, parsed.sourceFile, propsFieldTypes);
|
|
52
|
+
if (propsFieldTypes.size === 0 && externalInterfaces) {
|
|
53
|
+
const ext = externalInterfaces.get(namedPropsType);
|
|
54
|
+
if (ext) {
|
|
55
|
+
for (const [k, v] of ext)
|
|
56
|
+
propsFieldTypes.set(k, v);
|
|
57
|
+
}
|
|
40
58
|
}
|
|
41
59
|
}
|
|
42
60
|
}
|
|
@@ -45,6 +63,7 @@ export function lowerComponent(parsed, validation) {
|
|
|
45
63
|
stateVars,
|
|
46
64
|
setterMap,
|
|
47
65
|
propsParam,
|
|
66
|
+
propsFieldTypes,
|
|
48
67
|
bufferIndex: 0,
|
|
49
68
|
sourceFile: parsed.sourceFile,
|
|
50
69
|
customComponents: validation.customComponents,
|
|
@@ -62,6 +81,7 @@ export function lowerComponent(parsed, validation) {
|
|
|
62
81
|
stateSlots,
|
|
63
82
|
bufferCount: ctx.bufferIndex,
|
|
64
83
|
params,
|
|
84
|
+
namedPropsType,
|
|
65
85
|
body,
|
|
66
86
|
};
|
|
67
87
|
}
|
|
@@ -79,6 +99,45 @@ function inferPropType(member) {
|
|
|
79
99
|
return 'string';
|
|
80
100
|
return 'string';
|
|
81
101
|
}
|
|
102
|
+
/**
|
|
103
|
+
* Scan the source file for an interface declaration matching `interfaceName`
|
|
104
|
+
* and extract its field types into `fieldTypes`.
|
|
105
|
+
* Only handles direct fields — nested interface types are not resolved.
|
|
106
|
+
*/
|
|
107
|
+
function extractInterfaceFields(interfaceName, sourceFile, fieldTypes) {
|
|
108
|
+
for (const stmt of sourceFile.statements) {
|
|
109
|
+
if (ts.isInterfaceDeclaration(stmt) && stmt.name.text === interfaceName) {
|
|
110
|
+
for (const member of stmt.members) {
|
|
111
|
+
if (ts.isPropertySignature(member) && member.name && ts.isIdentifier(member.name)) {
|
|
112
|
+
const fieldName = member.name.text;
|
|
113
|
+
if (!member.type) {
|
|
114
|
+
fieldTypes.set(fieldName, 'string');
|
|
115
|
+
continue;
|
|
116
|
+
}
|
|
117
|
+
if (ts.isFunctionTypeNode(member.type)) {
|
|
118
|
+
fieldTypes.set(fieldName, 'callback');
|
|
119
|
+
continue;
|
|
120
|
+
}
|
|
121
|
+
const typeText = member.type.getText();
|
|
122
|
+
if (typeText === 'number' || typeText === 'number | undefined') {
|
|
123
|
+
fieldTypes.set(fieldName, 'float');
|
|
124
|
+
}
|
|
125
|
+
else if (typeText === 'boolean') {
|
|
126
|
+
fieldTypes.set(fieldName, 'bool');
|
|
127
|
+
}
|
|
128
|
+
else if (typeText === 'string') {
|
|
129
|
+
fieldTypes.set(fieldName, 'string');
|
|
130
|
+
}
|
|
131
|
+
else {
|
|
132
|
+
// Array types, nested interfaces, etc. treated as opaque
|
|
133
|
+
fieldTypes.set(fieldName, 'string');
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
}
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
82
141
|
function inferTypeFromExpr(expr) {
|
|
83
142
|
if (ts.isNumericLiteral(expr)) {
|
|
84
143
|
// Use getText() to check original source text, since TS normalizes 5.0 to "5" in .text
|
|
@@ -151,6 +210,9 @@ export function exprToCpp(node, ctx) {
|
|
|
151
210
|
if (ts.isPropertyAccessExpression(node)) {
|
|
152
211
|
const obj = exprToCpp(node.expression, ctx);
|
|
153
212
|
const prop = node.name.text;
|
|
213
|
+
// JS .length on arrays/vectors translates to C++ .size()
|
|
214
|
+
if (prop === 'length')
|
|
215
|
+
return `${obj}.size()`;
|
|
154
216
|
return `${obj}.${prop}`;
|
|
155
217
|
}
|
|
156
218
|
// Parenthesized expression
|
|
@@ -167,6 +229,13 @@ export function exprToCpp(node, ctx) {
|
|
|
167
229
|
op = '==';
|
|
168
230
|
else if (op === '!==')
|
|
169
231
|
op = '!=';
|
|
232
|
+
// String + non-string: JS string concatenation -> C++ std::string + std::to_string
|
|
233
|
+
if (op === '+' && (ts.isStringLiteral(node.left) || ts.isNoSubstitutionTemplateLiteral(node.left))) {
|
|
234
|
+
const rightType = inferExprType(node.right, ctx);
|
|
235
|
+
if (rightType === 'int' || rightType === 'float') {
|
|
236
|
+
return `(std::string(${left}) + std::to_string(${right}))`;
|
|
237
|
+
}
|
|
238
|
+
}
|
|
170
239
|
return `${left} ${op} ${right}`;
|
|
171
240
|
}
|
|
172
241
|
// Prefix unary expression (e.g., !show)
|
|
@@ -258,8 +327,8 @@ function extractActionStatements(expr, ctx) {
|
|
|
258
327
|
}
|
|
259
328
|
// If not an arrow function, call it
|
|
260
329
|
const code = exprToCpp(expr, ctx);
|
|
261
|
-
// Bare identifier (not already a call) needs () to invoke
|
|
262
|
-
if (ts.isIdentifier(expr)) {
|
|
330
|
+
// Bare identifier or property access (not already a call) needs () to invoke
|
|
331
|
+
if (ts.isIdentifier(expr) || ts.isPropertyAccessExpression(expr)) {
|
|
263
332
|
return [code + '();'];
|
|
264
333
|
}
|
|
265
334
|
return [code + ';'];
|
|
@@ -378,6 +447,12 @@ function lowerJsxElement(node, body, ctx) {
|
|
|
378
447
|
body.push({ kind: 'end_container', tag: containerTag });
|
|
379
448
|
return;
|
|
380
449
|
}
|
|
450
|
+
// DockSpace: detect if any child is a MenuBar
|
|
451
|
+
if (containerTag === 'DockSpace') {
|
|
452
|
+
const hasMenuBar = node.children.some(c => ts.isJsxElement(c) && ts.isIdentifier(c.openingElement.tagName) && c.openingElement.tagName.text === 'MenuBar');
|
|
453
|
+
if (hasMenuBar)
|
|
454
|
+
attrs['hasMenuBar'] = 'true';
|
|
455
|
+
}
|
|
381
456
|
body.push({ kind: 'begin_container', tag: containerTag, props: attrs, loc: getLoc(node, ctx) });
|
|
382
457
|
for (const child of node.children) {
|
|
383
458
|
lowerJsxChild(child, body, ctx);
|
|
@@ -556,8 +631,9 @@ function lowerButton(attrs, rawAttrs, body, ctx, loc) {
|
|
|
556
631
|
if (onPressExpr) {
|
|
557
632
|
action = extractActionStatements(onPressExpr, ctx);
|
|
558
633
|
}
|
|
634
|
+
const disabled = attrs['disabled'] === 'true' ? true : undefined;
|
|
559
635
|
const style = attrs['style'];
|
|
560
|
-
body.push({ kind: 'button', title, action, style, loc });
|
|
636
|
+
body.push({ kind: 'button', title, action, disabled, style, loc });
|
|
561
637
|
}
|
|
562
638
|
function lowerTextInput(attrs, rawAttrs, body, ctx, loc) {
|
|
563
639
|
const label = attrs['label'] ?? '""';
|
|
@@ -596,6 +672,7 @@ function lowerCheckbox(attrs, rawAttrs, body, ctx, loc) {
|
|
|
596
672
|
valueExprStr = exprToCpp(valueExpr, ctx);
|
|
597
673
|
}
|
|
598
674
|
// If not state-bound, get onChange expression
|
|
675
|
+
let directBind;
|
|
599
676
|
if (!stateVar) {
|
|
600
677
|
const onChangeRaw = rawAttrs.get('onChange');
|
|
601
678
|
if (onChangeRaw) {
|
|
@@ -605,9 +682,12 @@ function lowerCheckbox(attrs, rawAttrs, body, ctx, loc) {
|
|
|
605
682
|
onChangeExprStr = `${onChangeExprStr}()`;
|
|
606
683
|
}
|
|
607
684
|
}
|
|
685
|
+
else if (valueExprStr && valueExprStr.startsWith('props.')) {
|
|
686
|
+
directBind = true;
|
|
687
|
+
}
|
|
608
688
|
}
|
|
609
689
|
const style = attrs['style'];
|
|
610
|
-
body.push({ kind: 'checkbox', label, stateVar, valueExpr: valueExprStr, onChangeExpr: onChangeExprStr, style, loc });
|
|
690
|
+
body.push({ kind: 'checkbox', label, stateVar, valueExpr: valueExprStr, onChangeExpr: onChangeExprStr, directBind, style, loc });
|
|
611
691
|
}
|
|
612
692
|
function lowerMenuItem(attrs, rawAttrs, body, ctx, loc) {
|
|
613
693
|
const label = attrs['label'] ?? '""';
|
|
@@ -699,8 +779,18 @@ function inferExprType(expr, ctx) {
|
|
|
699
779
|
if (slot)
|
|
700
780
|
return slot.type;
|
|
701
781
|
}
|
|
702
|
-
// Property access: props.name -> look
|
|
782
|
+
// Property access: props.name -> look up field type if available
|
|
703
783
|
if (ts.isPropertyAccessExpression(expr)) {
|
|
784
|
+
const prop = expr.name.text;
|
|
785
|
+
// .length maps to .size() in C++ — always int
|
|
786
|
+
if (prop === 'length')
|
|
787
|
+
return 'int';
|
|
788
|
+
// If accessing a direct field of the props param, look up its type
|
|
789
|
+
if (ctx.propsParam && ts.isIdentifier(expr.expression) && expr.expression.text === ctx.propsParam) {
|
|
790
|
+
const ft = ctx.propsFieldTypes.get(prop);
|
|
791
|
+
if (ft && ft !== 'callback')
|
|
792
|
+
return ft;
|
|
793
|
+
}
|
|
704
794
|
return 'string';
|
|
705
795
|
}
|
|
706
796
|
// Binary expression: infer from operands
|
|
@@ -933,8 +1023,8 @@ function lowerRadio(attrs, rawAttrs, body, ctx, loc) {
|
|
|
933
1023
|
const label = attrs['label'] ?? '""';
|
|
934
1024
|
const index = attrs['index'] ?? '0';
|
|
935
1025
|
const style = attrs['style'];
|
|
936
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
937
|
-
body.push({ kind: 'radio', label, stateVar, valueExpr, onChangeExpr, index, style, loc });
|
|
1026
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1027
|
+
body.push({ kind: 'radio', label, stateVar, valueExpr, onChangeExpr, directBind, index, style, loc });
|
|
938
1028
|
}
|
|
939
1029
|
function lowerInputTextMultiline(attrs, rawAttrs, body, ctx, loc) {
|
|
940
1030
|
const label = attrs['label'] ?? '""';
|
|
@@ -1030,6 +1120,7 @@ function lowerValueOnChange(rawAttrs, ctx) {
|
|
|
1030
1120
|
let stateVar = '';
|
|
1031
1121
|
let valueExpr;
|
|
1032
1122
|
let onChangeExpr;
|
|
1123
|
+
let directBind;
|
|
1033
1124
|
const valueRaw = rawAttrs.get('value');
|
|
1034
1125
|
if (valueRaw && ts.isIdentifier(valueRaw) && ctx.stateVars.has(valueRaw.text)) {
|
|
1035
1126
|
stateVar = valueRaw.text;
|
|
@@ -1043,57 +1134,62 @@ function lowerValueOnChange(rawAttrs, ctx) {
|
|
|
1043
1134
|
onChangeExpr = `${onChangeExpr}()`;
|
|
1044
1135
|
}
|
|
1045
1136
|
}
|
|
1137
|
+
else if (valueRaw && ts.isPropertyAccessExpression(valueRaw)) {
|
|
1138
|
+
// No onChange + property access = direct pointer binding
|
|
1139
|
+
// This covers both props.field and course.field (loop item fields)
|
|
1140
|
+
directBind = true;
|
|
1141
|
+
}
|
|
1046
1142
|
}
|
|
1047
|
-
return { stateVar, valueExpr, onChangeExpr };
|
|
1143
|
+
return { stateVar, valueExpr, onChangeExpr, directBind };
|
|
1048
1144
|
}
|
|
1049
1145
|
function lowerSliderFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
1050
1146
|
const label = attrs['label'] ?? '""';
|
|
1051
1147
|
const min = attrs['min'] ?? '0.0f';
|
|
1052
1148
|
const max = attrs['max'] ?? '1.0f';
|
|
1053
1149
|
const style = attrs['style'];
|
|
1054
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1055
|
-
body.push({ kind: 'slider_float', label, stateVar, valueExpr, onChangeExpr, min, max, style, loc });
|
|
1150
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1151
|
+
body.push({ kind: 'slider_float', label, stateVar, valueExpr, onChangeExpr, directBind, min, max, style, loc });
|
|
1056
1152
|
}
|
|
1057
1153
|
function lowerSliderInt(attrs, rawAttrs, body, ctx, loc) {
|
|
1058
1154
|
const label = attrs['label'] ?? '""';
|
|
1059
1155
|
const min = attrs['min'] ?? '0';
|
|
1060
1156
|
const max = attrs['max'] ?? '100';
|
|
1061
1157
|
const style = attrs['style'];
|
|
1062
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1063
|
-
body.push({ kind: 'slider_int', label, stateVar, valueExpr, onChangeExpr, min, max, style, loc });
|
|
1158
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1159
|
+
body.push({ kind: 'slider_int', label, stateVar, valueExpr, onChangeExpr, directBind, min, max, style, loc });
|
|
1064
1160
|
}
|
|
1065
1161
|
function lowerDragFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
1066
1162
|
const label = attrs['label'] ?? '""';
|
|
1067
1163
|
const speed = attrs['speed'] ?? '1.0f';
|
|
1068
1164
|
const style = attrs['style'];
|
|
1069
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1070
|
-
body.push({ kind: 'drag_float', label, stateVar, valueExpr, onChangeExpr, speed, style, loc });
|
|
1165
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1166
|
+
body.push({ kind: 'drag_float', label, stateVar, valueExpr, onChangeExpr, directBind, speed, style, loc });
|
|
1071
1167
|
}
|
|
1072
1168
|
function lowerDragInt(attrs, rawAttrs, body, ctx, loc) {
|
|
1073
1169
|
const label = attrs['label'] ?? '""';
|
|
1074
1170
|
const speed = attrs['speed'] ?? '1.0f';
|
|
1075
1171
|
const style = attrs['style'];
|
|
1076
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1077
|
-
body.push({ kind: 'drag_int', label, stateVar, valueExpr, onChangeExpr, speed, style, loc });
|
|
1172
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1173
|
+
body.push({ kind: 'drag_int', label, stateVar, valueExpr, onChangeExpr, directBind, speed, style, loc });
|
|
1078
1174
|
}
|
|
1079
1175
|
function lowerCombo(attrs, rawAttrs, body, ctx, loc) {
|
|
1080
1176
|
const label = attrs['label'] ?? '""';
|
|
1081
1177
|
const items = attrs['items'] ?? '';
|
|
1082
1178
|
const style = attrs['style'];
|
|
1083
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1084
|
-
body.push({ kind: 'combo', label, stateVar, valueExpr, onChangeExpr, items, style, loc });
|
|
1179
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1180
|
+
body.push({ kind: 'combo', label, stateVar, valueExpr, onChangeExpr, directBind, items, style, loc });
|
|
1085
1181
|
}
|
|
1086
1182
|
function lowerInputInt(attrs, rawAttrs, body, ctx, loc) {
|
|
1087
1183
|
const label = attrs['label'] ?? '""';
|
|
1088
1184
|
const style = attrs['style'];
|
|
1089
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1090
|
-
body.push({ kind: 'input_int', label, stateVar, valueExpr, onChangeExpr, style, loc });
|
|
1185
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1186
|
+
body.push({ kind: 'input_int', label, stateVar, valueExpr, onChangeExpr, directBind, style, loc });
|
|
1091
1187
|
}
|
|
1092
1188
|
function lowerInputFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
1093
1189
|
const label = attrs['label'] ?? '""';
|
|
1094
1190
|
const style = attrs['style'];
|
|
1095
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1096
|
-
body.push({ kind: 'input_float', label, stateVar, valueExpr, onChangeExpr, style, loc });
|
|
1191
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1192
|
+
body.push({ kind: 'input_float', label, stateVar, valueExpr, onChangeExpr, directBind, style, loc });
|
|
1097
1193
|
}
|
|
1098
1194
|
function lowerColorEdit(attrs, rawAttrs, body, ctx, loc) {
|
|
1099
1195
|
const label = attrs['label'] ?? '""';
|
|
@@ -1110,8 +1206,8 @@ function lowerListBox(attrs, rawAttrs, body, ctx, loc) {
|
|
|
1110
1206
|
const label = attrs['label'] ?? '""';
|
|
1111
1207
|
const items = attrs['items'] ?? '';
|
|
1112
1208
|
const style = attrs['style'];
|
|
1113
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1114
|
-
body.push({ kind: 'list_box', label, stateVar, valueExpr, onChangeExpr, items, style, loc });
|
|
1209
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1210
|
+
body.push({ kind: 'list_box', label, stateVar, valueExpr, onChangeExpr, directBind, items, style, loc });
|
|
1115
1211
|
}
|
|
1116
1212
|
function lowerProgressBar(attrs, rawAttrs, body, ctx, loc) {
|
|
1117
1213
|
const value = attrs['value'] ?? '0.0f';
|