imxc 0.3.2 → 0.4.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/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 +137 -34
- 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'] ?? '""';
|
|
@@ -647,8 +727,15 @@ function lowerTextElement(node, body, ctx, loc) {
|
|
|
647
727
|
args.push(cppExpr);
|
|
648
728
|
break;
|
|
649
729
|
case 'float':
|
|
650
|
-
|
|
651
|
-
|
|
730
|
+
if (cppExpr.startsWith('props.')) {
|
|
731
|
+
// Props fields: number could be int or float in C++, cast to double for safe printf
|
|
732
|
+
format += '%g';
|
|
733
|
+
args.push(`(double)${cppExpr}`);
|
|
734
|
+
}
|
|
735
|
+
else {
|
|
736
|
+
format += '%.2f';
|
|
737
|
+
args.push(cppExpr);
|
|
738
|
+
}
|
|
652
739
|
break;
|
|
653
740
|
case 'bool':
|
|
654
741
|
format += '%s';
|
|
@@ -699,8 +786,18 @@ function inferExprType(expr, ctx) {
|
|
|
699
786
|
if (slot)
|
|
700
787
|
return slot.type;
|
|
701
788
|
}
|
|
702
|
-
// Property access: props.name -> look
|
|
789
|
+
// Property access: props.name -> look up field type if available
|
|
703
790
|
if (ts.isPropertyAccessExpression(expr)) {
|
|
791
|
+
const prop = expr.name.text;
|
|
792
|
+
// .length maps to .size() in C++ — always int
|
|
793
|
+
if (prop === 'length')
|
|
794
|
+
return 'int';
|
|
795
|
+
// If accessing a direct field of the props param, look up its type
|
|
796
|
+
if (ctx.propsParam && ts.isIdentifier(expr.expression) && expr.expression.text === ctx.propsParam) {
|
|
797
|
+
const ft = ctx.propsFieldTypes.get(prop);
|
|
798
|
+
if (ft && ft !== 'callback')
|
|
799
|
+
return ft;
|
|
800
|
+
}
|
|
704
801
|
return 'string';
|
|
705
802
|
}
|
|
706
803
|
// Binary expression: infer from operands
|
|
@@ -933,8 +1030,8 @@ function lowerRadio(attrs, rawAttrs, body, ctx, loc) {
|
|
|
933
1030
|
const label = attrs['label'] ?? '""';
|
|
934
1031
|
const index = attrs['index'] ?? '0';
|
|
935
1032
|
const style = attrs['style'];
|
|
936
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
937
|
-
body.push({ kind: 'radio', label, stateVar, valueExpr, onChangeExpr, index, style, loc });
|
|
1033
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1034
|
+
body.push({ kind: 'radio', label, stateVar, valueExpr, onChangeExpr, directBind, index, style, loc });
|
|
938
1035
|
}
|
|
939
1036
|
function lowerInputTextMultiline(attrs, rawAttrs, body, ctx, loc) {
|
|
940
1037
|
const label = attrs['label'] ?? '""';
|
|
@@ -1030,6 +1127,7 @@ function lowerValueOnChange(rawAttrs, ctx) {
|
|
|
1030
1127
|
let stateVar = '';
|
|
1031
1128
|
let valueExpr;
|
|
1032
1129
|
let onChangeExpr;
|
|
1130
|
+
let directBind;
|
|
1033
1131
|
const valueRaw = rawAttrs.get('value');
|
|
1034
1132
|
if (valueRaw && ts.isIdentifier(valueRaw) && ctx.stateVars.has(valueRaw.text)) {
|
|
1035
1133
|
stateVar = valueRaw.text;
|
|
@@ -1043,57 +1141,62 @@ function lowerValueOnChange(rawAttrs, ctx) {
|
|
|
1043
1141
|
onChangeExpr = `${onChangeExpr}()`;
|
|
1044
1142
|
}
|
|
1045
1143
|
}
|
|
1144
|
+
else if (valueRaw && ts.isPropertyAccessExpression(valueRaw)) {
|
|
1145
|
+
// No onChange + property access = direct pointer binding
|
|
1146
|
+
// This covers both props.field and course.field (loop item fields)
|
|
1147
|
+
directBind = true;
|
|
1148
|
+
}
|
|
1046
1149
|
}
|
|
1047
|
-
return { stateVar, valueExpr, onChangeExpr };
|
|
1150
|
+
return { stateVar, valueExpr, onChangeExpr, directBind };
|
|
1048
1151
|
}
|
|
1049
1152
|
function lowerSliderFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
1050
1153
|
const label = attrs['label'] ?? '""';
|
|
1051
1154
|
const min = attrs['min'] ?? '0.0f';
|
|
1052
1155
|
const max = attrs['max'] ?? '1.0f';
|
|
1053
1156
|
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 });
|
|
1157
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1158
|
+
body.push({ kind: 'slider_float', label, stateVar, valueExpr, onChangeExpr, directBind, min, max, style, loc });
|
|
1056
1159
|
}
|
|
1057
1160
|
function lowerSliderInt(attrs, rawAttrs, body, ctx, loc) {
|
|
1058
1161
|
const label = attrs['label'] ?? '""';
|
|
1059
1162
|
const min = attrs['min'] ?? '0';
|
|
1060
1163
|
const max = attrs['max'] ?? '100';
|
|
1061
1164
|
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 });
|
|
1165
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1166
|
+
body.push({ kind: 'slider_int', label, stateVar, valueExpr, onChangeExpr, directBind, min, max, style, loc });
|
|
1064
1167
|
}
|
|
1065
1168
|
function lowerDragFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
1066
1169
|
const label = attrs['label'] ?? '""';
|
|
1067
1170
|
const speed = attrs['speed'] ?? '1.0f';
|
|
1068
1171
|
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 });
|
|
1172
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1173
|
+
body.push({ kind: 'drag_float', label, stateVar, valueExpr, onChangeExpr, directBind, speed, style, loc });
|
|
1071
1174
|
}
|
|
1072
1175
|
function lowerDragInt(attrs, rawAttrs, body, ctx, loc) {
|
|
1073
1176
|
const label = attrs['label'] ?? '""';
|
|
1074
1177
|
const speed = attrs['speed'] ?? '1.0f';
|
|
1075
1178
|
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 });
|
|
1179
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1180
|
+
body.push({ kind: 'drag_int', label, stateVar, valueExpr, onChangeExpr, directBind, speed, style, loc });
|
|
1078
1181
|
}
|
|
1079
1182
|
function lowerCombo(attrs, rawAttrs, body, ctx, loc) {
|
|
1080
1183
|
const label = attrs['label'] ?? '""';
|
|
1081
1184
|
const items = attrs['items'] ?? '';
|
|
1082
1185
|
const style = attrs['style'];
|
|
1083
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1084
|
-
body.push({ kind: 'combo', label, stateVar, valueExpr, onChangeExpr, items, style, loc });
|
|
1186
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1187
|
+
body.push({ kind: 'combo', label, stateVar, valueExpr, onChangeExpr, directBind, items, style, loc });
|
|
1085
1188
|
}
|
|
1086
1189
|
function lowerInputInt(attrs, rawAttrs, body, ctx, loc) {
|
|
1087
1190
|
const label = attrs['label'] ?? '""';
|
|
1088
1191
|
const style = attrs['style'];
|
|
1089
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1090
|
-
body.push({ kind: 'input_int', label, stateVar, valueExpr, onChangeExpr, style, loc });
|
|
1192
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1193
|
+
body.push({ kind: 'input_int', label, stateVar, valueExpr, onChangeExpr, directBind, style, loc });
|
|
1091
1194
|
}
|
|
1092
1195
|
function lowerInputFloat(attrs, rawAttrs, body, ctx, loc) {
|
|
1093
1196
|
const label = attrs['label'] ?? '""';
|
|
1094
1197
|
const style = attrs['style'];
|
|
1095
|
-
const { stateVar, valueExpr, onChangeExpr } = lowerValueOnChange(rawAttrs, ctx);
|
|
1096
|
-
body.push({ kind: 'input_float', label, stateVar, valueExpr, onChangeExpr, style, loc });
|
|
1198
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1199
|
+
body.push({ kind: 'input_float', label, stateVar, valueExpr, onChangeExpr, directBind, style, loc });
|
|
1097
1200
|
}
|
|
1098
1201
|
function lowerColorEdit(attrs, rawAttrs, body, ctx, loc) {
|
|
1099
1202
|
const label = attrs['label'] ?? '""';
|
|
@@ -1110,8 +1213,8 @@ function lowerListBox(attrs, rawAttrs, body, ctx, loc) {
|
|
|
1110
1213
|
const label = attrs['label'] ?? '""';
|
|
1111
1214
|
const items = attrs['items'] ?? '';
|
|
1112
1215
|
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 });
|
|
1216
|
+
const { stateVar, valueExpr, onChangeExpr, directBind } = lowerValueOnChange(rawAttrs, ctx);
|
|
1217
|
+
body.push({ kind: 'list_box', label, stateVar, valueExpr, onChangeExpr, directBind, items, style, loc });
|
|
1115
1218
|
}
|
|
1116
1219
|
function lowerProgressBar(attrs, rawAttrs, body, ctx, loc) {
|
|
1117
1220
|
const value = attrs['value'] ?? '0.0f';
|