dazscript-framework 0.1.14 → 0.1.16

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (82) hide show
  1. package/README.md +365 -93
  2. package/babel.config.js +33 -33
  3. package/dist/babel/trace-babel-plugin.js +243 -243
  4. package/dist/babel/trace-log-babel-plugin.js +164 -164
  5. package/dist/scripts/install-generator.js +185 -185
  6. package/package.json +72 -70
  7. package/src/common/dz-dump.ts +120 -120
  8. package/src/common/log.ts +56 -57
  9. package/src/common/trace.ts +26 -26
  10. package/src/core/action-decorator.ts +15 -15
  11. package/src/core/base-script.ts +30 -30
  12. package/src/core/custom-action.ts +11 -11
  13. package/src/core/global.ts +4 -4
  14. package/src/dialog/basic-dialog.ts +40 -32
  15. package/src/dialog/builders/button-builder.ts +52 -52
  16. package/src/dialog/builders/checkbox-builder.ts +29 -29
  17. package/src/dialog/builders/color-picker-builder.ts +36 -0
  18. package/src/dialog/builders/combo-box-builder.ts +38 -35
  19. package/src/dialog/builders/combo-edit-builder.ts +35 -35
  20. package/src/dialog/builders/dialog-builder.ts +49 -49
  21. package/src/dialog/builders/groupbox-builder.ts +121 -73
  22. package/src/dialog/builders/label-builder.ts +33 -29
  23. package/src/dialog/builders/layout-builder.ts +59 -59
  24. package/src/dialog/builders/line-edit-builder.ts +124 -119
  25. package/src/dialog/builders/list-box-builder.ts +103 -0
  26. package/src/dialog/builders/list-view-builder.ts +396 -328
  27. package/src/dialog/builders/node-selection-builder.ts +55 -55
  28. package/src/dialog/builders/path-combo-box-builder.ts +24 -24
  29. package/src/dialog/builders/popup-menu-builder.ts +46 -46
  30. package/src/dialog/builders/radio-builder.ts +42 -42
  31. package/src/dialog/builders/slider-builder.ts +40 -0
  32. package/src/dialog/builders/splitter-builder.ts +88 -88
  33. package/src/dialog/builders/tab-builder.ts +120 -106
  34. package/src/dialog/builders/widget-builder.ts +136 -124
  35. package/src/dialog/builders/widgets-builder.ts +140 -125
  36. package/src/dialog/input-dialog.ts +30 -27
  37. package/src/dialog/input-validator.ts +8 -8
  38. package/src/dialog/selection-dialog.ts +47 -0
  39. package/src/dialog/shared.ts +8 -8
  40. package/src/helpers/action-helper.ts +214 -81
  41. package/src/helpers/array-helper.ts +170 -145
  42. package/src/helpers/camera-helper.ts +12 -12
  43. package/src/helpers/custom-action-helper.ts +176 -176
  44. package/src/helpers/directory-helper.ts +14 -0
  45. package/src/helpers/file-helper.ts +90 -90
  46. package/src/helpers/http-helper.ts +186 -0
  47. package/src/helpers/input-helper.ts +18 -18
  48. package/src/helpers/list-view-helper.ts +105 -89
  49. package/src/helpers/menu-helper.ts +28 -28
  50. package/src/helpers/message-box-helper.ts +25 -15
  51. package/src/helpers/node-helper.ts +461 -236
  52. package/src/helpers/number-helper.ts +10 -10
  53. package/src/helpers/numeric-property-helper.ts +91 -91
  54. package/src/helpers/object-helper.ts +2 -2
  55. package/src/helpers/pane-helper.ts +28 -20
  56. package/src/helpers/progress-helper.ts +51 -33
  57. package/src/helpers/property-helper.ts +61 -52
  58. package/src/helpers/record-helper.ts +16 -16
  59. package/src/helpers/scene-helper.ts +144 -95
  60. package/src/helpers/script-helper.ts +15 -15
  61. package/src/helpers/skeleton-helper.ts +26 -26
  62. package/src/helpers/splitter-helper.ts +8 -8
  63. package/src/helpers/string-helper.ts +39 -31
  64. package/src/helpers/surface-helper.ts +5 -5
  65. package/src/helpers/undo-helper.ts +8 -7
  66. package/src/helpers/viewport-helper.ts +21 -8
  67. package/src/lib/delayed.ts +38 -38
  68. package/src/lib/dictionary.ts +3 -0
  69. package/src/lib/frame-keys.ts +67 -67
  70. package/src/lib/guid.ts +2 -2
  71. package/src/lib/menu-item.ts +10 -9
  72. package/src/lib/observable.ts +147 -94
  73. package/src/lib/set.ts +50 -25
  74. package/src/lib/settings.ts +112 -104
  75. package/src/lib/tree-node.ts +149 -145
  76. package/src/samples/config.ts +2 -2
  77. package/src/samples/hello-world.dsa.ts +12 -12
  78. package/src/samples/sample-dialog.dsa.ts +51 -51
  79. package/src/samples/sample-dialog.ts +48 -48
  80. package/src/shared/set-keyboard-shortcut.ts +146 -102
  81. package/tsconfig.json +116 -116
  82. package/webpack.config.js +70 -70
@@ -1,236 +1,461 @@
1
- import { app, sceneHelper } from '@dsf/core/global';
2
- import { TreeNode } from '@dsf/lib/tree-node';
3
- import { group } from './array-helper';
4
- import { entries } from './record-helper';
5
-
6
- export const isBone = (node: DzNode): boolean => {
7
- return node.iskindof('DzBone')
8
- }
9
-
10
- export const isFigure = (node: DzNode): boolean => {
11
- return node.iskindof('DzSkeleton')
12
- }
13
-
14
- /**
15
- * Returns the root of a node
16
- * @param node
17
- * @returns The root of the node, if the node is part of a figure, return the figure (skeleton) otherwise return the node itself
18
- */
19
- export const getRoot = (node: DzNode): DzNode => {
20
- if (node && node.className() === "DzBone" && node.getSkeleton)
21
- return node.getSkeleton();
22
- else
23
- return node;
24
- }
25
-
26
- export const getFigure = (node: DzNode): DzSkeleton | null => {
27
- return node.getSkeleton?.() ?? null
28
- }
29
-
30
- /**
31
- * Find a property by the given name or internal name
32
- * @param node the node to search on
33
- * @param name the name or internal name of the property
34
- * @returns The first property with the given name or internal name, or NULL.
35
- */
36
- export const findProperty = <T extends DzProperty = DzProperty>(node: DzNode, name: string): T | null => {
37
- return sceneHelper.findPropertyOnNode(name, node) as T
38
- ?? sceneHelper.findPropertyOnNodeByInternalName(name, node) as T
39
- }
40
-
41
- /**
42
- * Get all properties associated with the node.
43
- * @param node The node to get the properties from.
44
- * @param includeModifiers Whether or not to include the properties of DzModifiers.
45
- * @returns All properties associated with the node.
46
- */
47
- export const getProperties = (node: DzNode, includeModifiers: boolean = false): DzProperty[] => {
48
- return sceneHelper.getPropertiesOnNode(node, includeModifiers)
49
- }
50
-
51
- export const getChildren = (node: DzNode, recursive: boolean, includeParented?: boolean, includeFittedTo?: boolean) => {
52
- return node.getNodeChildren(recursive ?? false).filter(n =>
53
- includeParented || isBodyPartOf(n, node.getSkeleton())
54
- && (includeFittedTo || !isFitting(getFigure(n), node)))
55
- }
56
-
57
- /**
58
- * Returns true if the specified node is a body part of a figure
59
- * @param node
60
- * @param figure
61
- * @returns
62
- */
63
- export const isBodyPartOf = (node: DzNode, figure: DzSkeleton): boolean => {
64
- return isBone(node) && isChildOf(node, figure) && node.getSkeleton()?.getLabel() == figure.getSkeleton()?.getLabel()
65
- }
66
-
67
- /**
68
- * Returns true if the specified node is parented or a body part of a figure
69
- * @param node
70
- * @param figure
71
- * @returns
72
- */
73
- export const isChildOf = (node: DzNode, figure: DzNode): boolean => {
74
- return node.isNodeDescendantOf(figure, true)
75
- }
76
-
77
- /**
78
- * Get the fitting target of the node
79
- * @param node
80
- * @returns the fitting target (skeleton) of the node or null
81
- */
82
- export const getFittingTarget = (node: DzNode): DzSkeleton | null => {
83
- return getRoot(node).getSkeleton()?.getFollowTarget()
84
- }
85
-
86
- /**
87
- * Returns true if the node is fitted to another node (eg: it's a clothing item)
88
- * @param figure
89
- * @param target if specified, check if the node is fitted to the target node, otherwise check if the node is fitted to any other node
90
- * @returns true if the node is fitted to another node
91
- */
92
- export const isFitting = (figure: DzSkeleton, target?: DzNode): boolean => {
93
- return target
94
- ? figure?.getFollowTarget() == target
95
- : figure?.getFollowTarget() != null
96
- }
97
-
98
- export const isClothingType = (node: DzNode): boolean => {
99
- if (!isFigure(node)) return false
100
- const figure = getFigure(node)!
101
- const assetMgr = app.getAssetMgr()
102
- const type = assetMgr.getTypeForNode(figure)
103
- return assetMgr.isClothingType(type) || type === 'Follower'
104
- }
105
-
106
- export const isHairType = (node: DzNode): boolean => {
107
- if (!isFigure(node)) return false
108
- const figure = getFigure(node)!
109
- const assetMgr = app.getAssetMgr()
110
- const type = assetMgr.getTypeForNode(figure)
111
- return assetMgr.isHairType(type)
112
- }
113
-
114
- export const isGeoShell = (node: DzNode): boolean => {
115
- return node.inherits('DzGeometryShellNode')
116
- }
117
-
118
- export const getTransforms = (node: DzNode, include: { rotations?: boolean, translations?: boolean, scale?: boolean }) => {
119
- let transforms: DzFloatProperty[] = []
120
-
121
- if (include.rotations === true) transforms = getRotations(node)
122
- if (include.translations === true) transforms = transforms.concat(getTranslations(node))
123
- if (include.scale === true) transforms = transforms.concat(getScales(node))
124
-
125
- return transforms
126
- }
127
-
128
- export const getRotations = (node: DzNode): DzFloatProperty[] => {
129
- if (!node) return [];
130
-
131
- const xRotate = sceneHelper.findPropertyOnNode('XRotate', node) as DzFloatProperty
132
- const yRotate = sceneHelper.findPropertyOnNode('YRotate', node) as DzFloatProperty
133
- const zRotate = sceneHelper.findPropertyOnNode('ZRotate', node) as DzFloatProperty
134
-
135
- return [xRotate, yRotate, zRotate];
136
- }
137
-
138
- export const getTranslations = (node: DzNode): DzFloatProperty[] => {
139
- return !node ? [] : [node.getXPosControl(), node.getYPosControl(), node.getZPosControl()];
140
- }
141
-
142
- export const getScales = (node: DzNode): DzFloatProperty[] => {
143
- return [node.getXScaleControl(), node.getYScaleControl(), node.getZScaleControl(), node.getScaleControl()];
144
- }
145
-
146
- export const getPropertiesTree = <T = DzProperty>(node: DzNode, map?: (property: DzProperty) => T/*, filter?: (property: DzProperty) => boolean*/, showProgress: boolean = false): TreeNode<T>[] => {
147
- if (showProgress) startProgress(`Collecting Properties`, 3)
148
- let root: TreeNode<T>;
149
-
150
- // Fetch properties and group them by their path
151
- const properties = sceneHelper.getPropertiesOnNode(node);
152
- if (showProgress) stepProgress()
153
-
154
- const grouped = group(properties, (p) => p.getPath());
155
- if (showProgress) stepProgress()
156
-
157
- // Root TreeNode
158
- root = new TreeNode<T>('root', '');
159
- const pathMap: Record<string, TreeNode<T>> = { '': root };
160
-
161
- // Process grouped entries
162
- const groupedEntries = entries(grouped);
163
- if (showProgress) stepProgress()
164
-
165
- if (showProgress) startProgress(`Processing ${groupedEntries.length} properties`, groupedEntries.length)
166
- for (const [path, props] of groupedEntries) {
167
- const paths = path.split('/');
168
- let currentPath = '';
169
-
170
- // Create nodes for the path hierarchy
171
- for (let i = 0; i < paths.length; i++) {
172
- currentPath = paths.slice(0, i + 1).join('/');
173
- if (!pathMap[currentPath]) {
174
- const newNode = new TreeNode<T>(paths[i], currentPath);
175
- pathMap[currentPath] = newNode;
176
-
177
- if (i > 0) {
178
- const parentPath = paths.slice(0, i).join('/');
179
- const parentNode = pathMap[parentPath];
180
- parentNode?.addChild(newNode);
181
- newNode.parent = parentNode;
182
- }
183
- }
184
- }
185
-
186
- // Add property nodes to the current path
187
- const currentNode = pathMap[path];
188
- if (currentNode) {
189
- for (const property of props) {
190
- const newNode = new TreeNode<T>(
191
- property.getLabel(),
192
- property.getPath(),
193
- map?.(property) ?? (property as T)
194
- );
195
- currentNode.addChild(newNode);
196
- newNode.parent = currentNode;
197
- }
198
- }
199
- if (showProgress) stepProgress()
200
- }
201
- if (showProgress) finishProgress()
202
- if (showProgress) finishProgress()
203
-
204
- // Return root children or an empty array if none exist
205
- return root.children.length > 0 ? root.children : [];
206
- };
207
-
208
- export const getPropertiesPathsTree = (node: DzNode): TreeNode<string>[] => {
209
- let items = entries(group(sceneHelper.getPropertiesOnNode(node), (p) => p.getPath())).map(x => ({ path: x[0], properties: x[1] }))
210
-
211
- const root = new TreeNode<string>('root', '')
212
- const pathMap: { [key: string]: TreeNode<string> } = { '': root }
213
-
214
- items.forEach(element => {
215
- const paths = element.path.split('/')
216
- let currentPath = ''
217
-
218
- paths.forEach((path, index) => {
219
- currentPath += `${index === 0 ? '' : '/'}${path}`
220
- if (!pathMap[currentPath]) {
221
- const newNode = new TreeNode<string>(path, currentPath)
222
- pathMap[currentPath] = newNode
223
-
224
- if (index !== 0) {
225
- const parentPath = currentPath.substring(0, currentPath.lastIndexOf('/'))
226
- const parentNode = pathMap[parentPath]
227
- parentNode?.addChild(newNode)
228
- newNode.parent = parentNode
229
- }
230
- }
231
- })
232
- })
233
-
234
- const rootChildren = pathMap[''].children
235
- return rootChildren && rootChildren.length > 0 ? rootChildren : root.children
236
- }
1
+ import { app, sceneHelper } from '@dsf/core/global';
2
+ import { TreeNode } from '@dsf/lib/tree-node';
3
+ import { find, group } from './array-helper';
4
+ import { entries } from './record-helper';
5
+ import { getSelectedPropertyGroups } from './scene-helper';
6
+ import { contains } from './string-helper';
7
+
8
+ export enum NamedAxis {
9
+ Bend = 'Bend',
10
+ Twist = 'Twist',
11
+ SideSide = 'Side-Side',
12
+ FrontBack = 'Front-Back',
13
+ UpDown = 'Up-Down',
14
+ }
15
+
16
+ export const isBone = (node: DzNode): boolean => {
17
+ return node.iskindof('DzBone')
18
+ }
19
+
20
+ export const isFigure = (node: DzNode): boolean => {
21
+ return node.iskindof('DzSkeleton')
22
+ }
23
+
24
+ /**
25
+ * Returns the root of a node
26
+ * @param node
27
+ * @returns The root of the node, if the node is part of a figure, return the figure (skeleton) otherwise return the node itself
28
+ */
29
+ export const getRoot = (node: DzNode): DzNode => {
30
+ if (node && node.className() === "DzBone" && node.getSkeleton)
31
+ return node.getSkeleton();
32
+ else
33
+ return node;
34
+ }
35
+
36
+ export const getFigure = (node: DzNode): DzSkeleton | null => {
37
+ return node.getSkeleton?.() ?? null
38
+ }
39
+
40
+ /**
41
+ * Find a property by the given name or internal name
42
+ * @param node the node to search on
43
+ * @param name the name or internal name of the property
44
+ * @returns The first property with the given name or internal name, or NULL.
45
+ */
46
+ export const findProperty = <T extends DzProperty = DzProperty>(node: DzNode, name: string): T | null => {
47
+ return sceneHelper.findPropertyOnNode(name, node) as T
48
+ ?? sceneHelper.findPropertyOnNodeByInternalName(name, node) as T
49
+ }
50
+
51
+ /**
52
+ * Get all properties associated with the node.
53
+ * @param node The node to get the properties from.
54
+ * @param includeModifiers Whether or not to include the properties of DzModifiers.
55
+ * @returns All properties associated with the node.
56
+ */
57
+ export const getProperties = (node: DzNode, includeModifiers: boolean = false): DzProperty[] => {
58
+ return sceneHelper.getPropertiesOnNode(node, includeModifiers)
59
+ }
60
+
61
+ export const getChildren = (node: DzNode, recursive: boolean, includeParented?: boolean, includeFittedTo?: boolean) => {
62
+ return node.getNodeChildren(recursive ?? false).filter(n =>
63
+ includeParented || isBodyPartOf(n, node.getSkeleton())
64
+ && (includeFittedTo || !isFitting(getFigure(n), node)))
65
+ }
66
+
67
+ /**
68
+ * Returns true if the specified node is a body part of a figure
69
+ * @param node
70
+ * @param figure
71
+ * @returns
72
+ */
73
+ export const isBodyPartOf = (node: DzNode, figure: DzSkeleton): boolean => {
74
+ return isBone(node) && isChildOf(node, figure) && node.getSkeleton()?.getLabel() == figure.getSkeleton()?.getLabel()
75
+ }
76
+
77
+ /**
78
+ * Returns true if the specified node is parented or a body part of a figure
79
+ * @param node
80
+ * @param figure
81
+ * @returns
82
+ */
83
+ export const isChildOf = (node: DzNode, figure: DzNode): boolean => {
84
+ return node.isNodeDescendantOf(figure, true)
85
+ }
86
+
87
+ /**
88
+ * Get the fitting target of the node
89
+ * @param node
90
+ * @returns the fitting target (skeleton) of the node or null
91
+ */
92
+ export const getFittingTarget = (node: DzNode): DzSkeleton | null => {
93
+ return getRoot(node).getSkeleton()?.getFollowTarget()
94
+ }
95
+
96
+ /**
97
+ * Returns true if the node is fitted to another node (eg: it's a clothing item)
98
+ * @param figure
99
+ * @param target if specified, check if the node is fitted to the target node, otherwise check if the node is fitted to any other node
100
+ * @returns true if the node is fitted to another node
101
+ */
102
+ export const isFitting = (figure: DzSkeleton, target?: DzNode): boolean => {
103
+ return target
104
+ ? figure?.getFollowTarget() == target
105
+ : figure?.getFollowTarget() != null
106
+ }
107
+
108
+ export const isClothingType = (node: DzNode): boolean => {
109
+ if (!isFigure(node)) return false
110
+ const figure = getFigure(node)!
111
+ const assetMgr = app.getAssetMgr()
112
+ const type = assetMgr.getTypeForNode(figure)
113
+ return assetMgr.isClothingType(type) || type === 'Follower'
114
+ }
115
+
116
+ export const isHairType = (node: DzNode): boolean => {
117
+ if (!isFigure(node)) {
118
+ return node.className() === 'DzStrandHairNode'
119
+ }
120
+ const figure = getFigure(node)!
121
+ const assetMgr = app.getAssetMgr()
122
+ const type = assetMgr.getTypeForNode(figure)
123
+ return assetMgr.isHairType(type) || contains(type.valueOf(), 'Hair')
124
+ }
125
+
126
+ export const isGeoShell = (node: DzNode): boolean => {
127
+ return node.inherits('DzGeometryShellNode')
128
+ }
129
+
130
+ export const getTransforms = (node: DzNode, include: { rotations?: boolean, translations?: boolean, scale?: boolean }) => {
131
+ let transforms: DzFloatProperty[] = []
132
+
133
+ if (include.rotations === true) transforms = getRotations(node)
134
+ if (include.translations === true) transforms = transforms.concat(getTranslations(node))
135
+ if (include.scale === true) transforms = transforms.concat(getScales(node))
136
+
137
+ return transforms
138
+ }
139
+
140
+ export const getRotations = (node: DzNode, includeExtraRotations: boolean = true): DzFloatProperty[] => {
141
+ if (!node) return [];
142
+
143
+ const xRotate = sceneHelper.findPropertyOnNode('XRotate', node) as DzFloatProperty;
144
+ const xRotate2 = sceneHelper.findPropertyOnNode('XRotate2', node) as DzFloatProperty;
145
+ const yRotate = sceneHelper.findPropertyOnNode('YRotate', node) as DzFloatProperty;
146
+ const yRotate2 = sceneHelper.findPropertyOnNode('YRotate2', node) as DzFloatProperty;
147
+ const zRotate = sceneHelper.findPropertyOnNode('ZRotate', node) as DzFloatProperty;
148
+ const zRotate2 = sceneHelper.findPropertyOnNode('ZRotate2', node) as DzFloatProperty;
149
+
150
+ if (includeExtraRotations) {
151
+ return [xRotate, xRotate2, yRotate, yRotate2, zRotate, zRotate2].filter(Boolean);
152
+ }
153
+
154
+ // Prefer Rotate2 if available, otherwise fallback to Rotate
155
+ return [
156
+ xRotate2 ?? xRotate,
157
+ yRotate2 ?? yRotate,
158
+ zRotate2 ?? zRotate
159
+ ].filter(Boolean);
160
+ }
161
+
162
+ export const getRotationsForAxis = (node: DzNode, axis: 'x' | 'y' | 'z'): DzFloatProperty => {
163
+ debug(`Getting rotation property for axis: ${axis} on node: ${node.getName()} - isBone: ${isBone(node)}`);
164
+
165
+ let prop: DzFloatProperty | undefined;
166
+
167
+ if (isBone(node)) {
168
+ prop = getNamedRotationForAxis(node, axis);
169
+ if (!prop) {
170
+ debug(`Named rotation not found for ${axis} on bone ${node.getName()}, falling back to generic search`);
171
+ }
172
+ }
173
+
174
+ if (!prop) {
175
+ prop = find(
176
+ getRotations(node, false),
177
+ (rotation) => rotation.getName().valueOf()[0].toLowerCase() === axis
178
+ ) as DzFloatProperty;
179
+ }
180
+
181
+ return prop;
182
+ }
183
+
184
+ export const getNamedRotations = (node: DzNode): DzFloatProperty[] => {
185
+ const rotations: DzFloatProperty[] = []
186
+
187
+ for (let namedAxis in NamedAxis) {
188
+ let property = sceneHelper.findPropertyOnNodeByLabel(NamedAxis[namedAxis], node) as DzFloatProperty
189
+ if (property) rotations.push(property)
190
+ }
191
+
192
+ return rotations
193
+ }
194
+
195
+ export const getRotationAxisFor = (node: DzNode, axis: NamedAxis): string => {
196
+ const rotations = getNamedRotations(node)
197
+ if (!rotations) return null
198
+
199
+ for (let rotation of rotations) {
200
+ if (rotation.getLabel() == axis) {
201
+ const axis = rotation.getName().valueOf()[0].toLowerCase()
202
+ return axis
203
+ }
204
+ }
205
+
206
+ return null
207
+ }
208
+
209
+ export const getNamedRotationForAxis = (node: DzNode, axis: 'x' | 'y' | 'z'): DzFloatProperty | null => {
210
+ const rotations = getNamedRotations(node)
211
+ if (!rotations) return null
212
+
213
+ for (let rotation of rotations) {
214
+ if (rotation.getName().valueOf()[0].toLowerCase() == axis) {
215
+ return rotation
216
+ }
217
+ }
218
+
219
+ return null
220
+ }
221
+
222
+ export const getTranslations = (node: DzNode): DzFloatProperty[] => {
223
+ return !node ? [] : [node.getXPosControl(), node.getYPosControl(), node.getZPosControl()];
224
+ }
225
+
226
+ export const getScales = (node: DzNode): DzFloatProperty[] => {
227
+ return [node.getXScaleControl(), node.getYScaleControl(), node.getZScaleControl(), node.getScaleControl()];
228
+ }
229
+
230
+ export const getPropertiesFromSelectedGroup = (nodes: DzNode[], recursive: boolean = false, traverse: boolean = false, pane?: DzAbstractNodeEditorPane): DzProperty[] => {
231
+ var properties: DzProperty[] = [];
232
+ var propertyGroups = getSelectedPropertyGroups(pane);
233
+
234
+ nodes.forEach(node => {
235
+ propertyGroups.forEach(path => {
236
+ properties.push(...getPropertiesInPath(node, path, recursive, traverse));
237
+ });
238
+ });
239
+
240
+ return properties;
241
+ }
242
+
243
+ /**
244
+ * A function for getting the list properties for an element
245
+ * @param node
246
+ * @param path
247
+ * @param recursive
248
+ * @returns
249
+ */
250
+ export const getPropertiesInPath = (node: DzNode, path: string, recursive: boolean, traverse: boolean = false): DzProperty[] => {
251
+ if (!path) return getProperties(node);
252
+
253
+ var groupTree = node.getPropertyGroups();
254
+ var propertyGroup: DzPropertyGroup | null = null;
255
+ var name = "";
256
+ var index = -1;
257
+ var subPath = path;
258
+
259
+ while (!subPath.isEmpty()) {
260
+ index = subPath.indexOf("/");
261
+ if (index < 0) {
262
+ name = subPath;
263
+ subPath = "";
264
+ }
265
+ else {
266
+ name = subPath.left(index);
267
+ subPath = subPath.right(subPath.length - index - 1);
268
+ }
269
+ propertyGroup = propertyGroup ? propertyGroup.findChild(name) : groupTree.findChild(name);
270
+
271
+ if (propertyGroup === null) break;
272
+ }
273
+
274
+ if (!propertyGroup) return [];
275
+
276
+ return getPropertiesInGroup(propertyGroup, traverse, recursive);
277
+ }
278
+
279
+ const getPropertiesInGroup = (group: DzPropertyGroup, traverse: boolean, recursive: boolean): DzProperty[] => {
280
+ var properties: DzProperty[] = [];
281
+
282
+ if (!group) return properties;
283
+
284
+ var propertiesCount = group.getNumProperties();
285
+
286
+ properties = new Array(propertiesCount);
287
+
288
+ for (var i = 0; i < propertiesCount; i += 1) {
289
+ properties[i] = group.getProperty(i);
290
+ }
291
+
292
+ // If we are recursing
293
+ if (recursive) {
294
+ // Concatenate the properties array from child groups
295
+ properties = properties.concat(
296
+ getPropertiesInGroup(group.getFirstChild(), true, recursive));
297
+ }
298
+
299
+ // If we are traversing
300
+ if (traverse) {
301
+ // Concatenate the properties array from sibling groups
302
+ properties = properties.concat(
303
+ getPropertiesInGroup(group.getNextSibling(), traverse, recursive));
304
+ }
305
+
306
+ return properties;
307
+ }
308
+
309
+ /**
310
+ * Method for building a bounding box; optionally excluding a node and/or its children
311
+ * @param node
312
+ * @param excludeBase
313
+ * @param excludeChildren
314
+ * @param recursive
315
+ * @returns
316
+ * http://docs.daz3d.com/doku.php/public/software/dazstudio/4/referenceguide/scripting/api_reference/samples/core/frame_camera/start
317
+ */
318
+ export const buildBoundingBox = (node: DzNode, excludeBase: boolean, excludeChildren: boolean, recursive: boolean): DzBox3 => {
319
+ var boxBounding = new DzBox3();
320
+ var g_oArrayHelper = new DzArrayHelper();
321
+
322
+ if (!node) return null;
323
+
324
+ // Define an array of nodes to exclude
325
+ var aExcludeNodes = (excludeChildren ? node.getNodeChildren(recursive) : []);
326
+
327
+ // If we're excluding the base node
328
+ if (excludeBase) {
329
+ // Add the base node to the front of the list
330
+ aExcludeNodes.unshift(node);
331
+ }
332
+
333
+ // Declare working variable
334
+ var boxNode: DzBox3;
335
+
336
+ // Define a flag to indicate whether the box grows
337
+ var bHasGrown = false;
338
+
339
+ // Get whether a node is selected
340
+ var bSelectedNode = (Scene.getPrimarySelection() != undefined);
341
+ // Get the number of nodes to process
342
+ var nNodes = (bSelectedNode ? Scene.getNumSelectedNodes() : Scene.getNumNodes());
343
+ // Iterate over the nodes
344
+ for (var i = 0; i < nNodes; i += 1) {
345
+ // Get the 'current' node; based on selection
346
+ var oNode = (bSelectedNode ? Scene.getSelectedNode(i) : Scene.getNode(i));
347
+ // If we have a node and it is not in the exclude list
348
+ if (oNode && g_oArrayHelper.isInArray(aExcludeNodes, oNode) < 0) {
349
+ // Get the world space bounding box
350
+ boxNode = oNode.getWSBoundingBox();
351
+ // Grow our box to include the node box
352
+ boxBounding.include(boxNode.max);
353
+ boxBounding.include(boxNode.min);
354
+ // Update the flag
355
+ bHasGrown = true;
356
+ }
357
+ }
358
+
359
+ // If the box has not grown
360
+ if (!bHasGrown) {
361
+ // We're done here...
362
+ return undefined;
363
+ }
364
+
365
+ // Return the bounding box
366
+ return boxBounding;
367
+
368
+ }
369
+
370
+ export const getPropertiesTree = <T = DzProperty>(node: DzNode, map?: (property: DzProperty) => T, filter?: (property: DzProperty) => boolean, showProgress: boolean = false): TreeNode<T>[] => {
371
+ if (showProgress) startProgress(`Collecting Properties`, 3)
372
+ let root: TreeNode<T>;
373
+
374
+ // Fetch properties and group them by their path
375
+ const properties = sceneHelper.getPropertiesOnNode(node);
376
+ if (showProgress) stepProgress()
377
+
378
+ const grouped = group(properties, (p) => p.getPath());
379
+ if (showProgress) stepProgress()
380
+
381
+ // Root TreeNode
382
+ root = new TreeNode<T>('root', '');
383
+ const pathMap: Record<string, TreeNode<T>> = { '': root };
384
+
385
+ // Process grouped entries
386
+ const groupedEntries = entries(grouped);
387
+ if (showProgress) stepProgress()
388
+
389
+ if (showProgress) startProgress(`Processing ${groupedEntries.length} properties`, groupedEntries.length)
390
+ for (const [path, props] of groupedEntries) {
391
+ const paths = path.split('/');
392
+ let currentPath = '';
393
+
394
+ // Create nodes for the path hierarchy
395
+ for (let i = 0; i < paths.length; i++) {
396
+ currentPath = paths.slice(0, i + 1).join('/');
397
+ if (!pathMap[currentPath]) {
398
+ const newNode = new TreeNode<T>(paths[i], currentPath);
399
+ pathMap[currentPath] = newNode;
400
+
401
+ if (i > 0) {
402
+ const parentPath = paths.slice(0, i).join('/');
403
+ const parentNode = pathMap[parentPath];
404
+ parentNode?.addChild(newNode);
405
+ newNode.parent = parentNode;
406
+ }
407
+ }
408
+ }
409
+
410
+ // Add property nodes to the current path
411
+ const currentNode = pathMap[path];
412
+ if (currentNode) {
413
+ for (const property of props) {
414
+ if (filter && !filter(property)) continue
415
+ const newNode = new TreeNode<T>(
416
+ property.getLabel(),
417
+ property.getPath(),
418
+ map?.(property) ?? (property as T)
419
+ );
420
+ currentNode.addChild(newNode);
421
+ newNode.parent = currentNode;
422
+ }
423
+ }
424
+ if (showProgress) stepProgress()
425
+ }
426
+ if (showProgress) finishProgress()
427
+ if (showProgress) finishProgress()
428
+
429
+ // Return root children or an empty array if none exist
430
+ return root.children.length > 0 ? root.children : [];
431
+ };
432
+
433
+ export const getPropertiesPathsTree = (node: DzNode): TreeNode<string>[] => {
434
+ let items = entries(group(sceneHelper.getPropertiesOnNode(node), (p) => p.getPath())).map(x => ({ path: x[0], properties: x[1] }))
435
+
436
+ const root = new TreeNode<string>('root', '')
437
+ const pathMap: { [key: string]: TreeNode<string> } = { '': root }
438
+
439
+ items.forEach(element => {
440
+ const paths = element.path.split('/')
441
+ let currentPath = ''
442
+
443
+ paths.forEach((path, index) => {
444
+ currentPath += `${index === 0 ? '' : '/'}${path}`
445
+ if (!pathMap[currentPath]) {
446
+ const newNode = new TreeNode<string>(path, currentPath)
447
+ pathMap[currentPath] = newNode
448
+
449
+ if (index !== 0) {
450
+ const parentPath = currentPath.substring(0, currentPath.lastIndexOf('/'))
451
+ const parentNode = pathMap[parentPath]
452
+ parentNode?.addChild(newNode)
453
+ newNode.parent = parentNode
454
+ }
455
+ }
456
+ })
457
+ })
458
+
459
+ const rootChildren = pathMap[''].children
460
+ return rootChildren && rootChildren.length > 0 ? rootChildren : root.children
461
+ }