@design-core/core 0.0.1 → 0.0.3

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 (254) hide show
  1. package/.eslintrc.json +14 -7
  2. package/.github/workflows/DesignCoreQA.yml +3 -1
  3. package/README.md +11 -4
  4. package/TODO.md +19 -0
  5. package/core/core/core.js +49 -42
  6. package/core/designCore.js +61 -2
  7. package/core/dimensions/alignedDimension.js +142 -0
  8. package/core/dimensions/angularDimension.js +550 -0
  9. package/core/dimensions/baseCircularDimension.js +244 -0
  10. package/core/dimensions/baseDimension.js +558 -0
  11. package/core/dimensions/baseLinearDimension.js +371 -0
  12. package/core/dimensions/diametricDimension.js +82 -0
  13. package/core/dimensions/dimension.js +298 -0
  14. package/core/dimensions/linearDimension.js +29 -0
  15. package/core/dimensions/radialDimension.js +78 -0
  16. package/core/dimensions/rotatedDimension.js +167 -0
  17. package/core/entities/arc.js +314 -60
  18. package/core/entities/arctext.js +642 -0
  19. package/core/entities/basePolyline.js +553 -94
  20. package/core/entities/circle.js +181 -54
  21. package/core/entities/entity.js +154 -74
  22. package/core/entities/hatch.js +807 -0
  23. package/core/entities/insert.js +200 -39
  24. package/core/entities/line.js +196 -134
  25. package/core/entities/lwpolyline.js +21 -44
  26. package/core/entities/point.js +194 -29
  27. package/core/entities/polyline.js +54 -7
  28. package/core/entities/rectangle.js +43 -13
  29. package/core/entities/solid.js +43 -6
  30. package/core/entities/text.js +324 -181
  31. package/core/lib/boundingBox.js +73 -13
  32. package/core/lib/canvas.js +256 -65
  33. package/core/lib/clipboard.js +198 -0
  34. package/core/lib/colour.js +144 -0
  35. package/core/lib/colours.js +367 -301
  36. package/core/lib/commandLine.js +16 -28
  37. package/core/lib/commandManager.js +115 -58
  38. package/core/lib/constants.js +23 -0
  39. package/core/lib/dxf/dxf.js +249 -34
  40. package/core/lib/dxf/dxfFile.js +23 -38
  41. package/core/lib/dxf/dxfIterator.js +17 -5
  42. package/core/lib/dxf/dxfRead.js +23 -7
  43. package/core/lib/dxf/dxfWrite.js +39 -129
  44. package/core/lib/dxf/handleManager.js +97 -0
  45. package/core/lib/dxf/sections/blocks.js +16 -2
  46. package/core/lib/dxf/sections/entities.js +17 -3
  47. package/core/lib/dxf/sections/header.js +10 -1
  48. package/core/lib/dxf/sections/objects.js +36 -0
  49. package/core/lib/dxf/sections/section.js +43 -5
  50. package/core/lib/dxf/sections/tables.js +17 -3
  51. package/core/lib/entityManager.js +178 -0
  52. package/core/lib/fileio.js +14 -4
  53. package/core/lib/headers.js +229 -0
  54. package/core/lib/input.js +46 -0
  55. package/core/lib/inputManager.js +199 -194
  56. package/core/lib/intersect.js +341 -468
  57. package/core/lib/logging.js +25 -1
  58. package/core/lib/matrix.js +6 -8
  59. package/core/lib/mouse.js +24 -79
  60. package/core/lib/patterns.js +690 -0
  61. package/core/lib/promptOptions.js +133 -0
  62. package/core/lib/scene.js +71 -174
  63. package/core/lib/selectionManager.js +74 -48
  64. package/core/lib/selectionWindow.js +24 -10
  65. package/core/lib/settings.js +18 -11
  66. package/core/lib/snapping.js +129 -21
  67. package/core/lib/stateManager.js +288 -0
  68. package/core/lib/strings.js +57 -5
  69. package/core/lib/utils.js +95 -11
  70. package/core/objects/dictionary.js +43 -0
  71. package/core/objects/dictionaryManager.js +80 -0
  72. package/core/properties/dimType.js +117 -0
  73. package/core/properties/flags.js +66 -0
  74. package/core/properties/property.js +26 -0
  75. package/core/properties/propertyManager.js +65 -19
  76. package/core/tables/appId.js +31 -0
  77. package/core/tables/appIdManager.js +44 -0
  78. package/core/tables/block.js +323 -0
  79. package/core/tables/blockManager.js +48 -0
  80. package/core/tables/blockRecord.js +29 -0
  81. package/core/tables/blockRecordManager.js +37 -0
  82. package/core/tables/dimStyle.js +627 -0
  83. package/core/tables/dimStyleManager.js +187 -0
  84. package/core/tables/endblk.js +28 -0
  85. package/core/tables/layer.js +219 -0
  86. package/core/tables/layerManager.js +47 -0
  87. package/core/tables/ltype.js +85 -0
  88. package/core/tables/ltypeManager.js +65 -0
  89. package/core/tables/style.js +145 -0
  90. package/core/tables/styleManager.js +55 -0
  91. package/core/tables/styleManagerBase.js +110 -0
  92. package/core/tables/tableManagerBase.js +354 -0
  93. package/core/tables/ucs.js +28 -0
  94. package/core/tables/ucsManager.js +44 -0
  95. package/core/tables/view.js +28 -0
  96. package/core/tables/viewManager.js +44 -0
  97. package/core/tables/vport.js +70 -0
  98. package/core/tables/vportManager.js +65 -0
  99. package/core/tools/chamfer.js +343 -0
  100. package/core/tools/chamferFilletBase.js +162 -0
  101. package/core/tools/copy.js +68 -40
  102. package/core/tools/copybase.js +65 -0
  103. package/core/tools/copyclip.js +59 -0
  104. package/core/tools/cornerEntity.js +138 -0
  105. package/core/tools/cutclip.js +72 -0
  106. package/core/tools/distance.js +37 -9
  107. package/core/tools/erase.js +43 -13
  108. package/core/tools/explode.js +117 -0
  109. package/core/tools/extend.js +71 -32
  110. package/core/tools/fillet.js +336 -0
  111. package/core/tools/identify.js +33 -6
  112. package/core/tools/matchProp.js +106 -0
  113. package/core/tools/mirror.js +141 -0
  114. package/core/tools/move.js +65 -32
  115. package/core/tools/offset.js +321 -0
  116. package/core/tools/pan.js +54 -0
  117. package/core/tools/pasteclip.js +93 -0
  118. package/core/tools/purge.js +90 -0
  119. package/core/tools/rotate.js +105 -70
  120. package/core/tools/scale.js +166 -0
  121. package/core/tools/tool.js +14 -4
  122. package/core/tools/trim.js +71 -32
  123. package/core/tools/zoom.js +152 -0
  124. package/package.json +3 -305
  125. package/test/dimensions/alignedDimension.test.js +211 -0
  126. package/test/dimensions/angularDimension.test.js +243 -0
  127. package/test/dimensions/baseDimension.test.js +239 -0
  128. package/test/dimensions/diametricDimension.test.js +203 -0
  129. package/test/dimensions/dimension.test.js +102 -0
  130. package/test/dimensions/radialDimension.test.js +203 -0
  131. package/test/dimensions/rotatedDimension.test.js +224 -0
  132. package/test/entities/arc.test.js +463 -41
  133. package/test/entities/arctext.test.js +329 -0
  134. package/test/entities/basePolyline.test.js +459 -10
  135. package/test/entities/circle.test.js +312 -7
  136. package/test/entities/entity.test.js +28 -9
  137. package/test/entities/hatch.test.js +606 -0
  138. package/test/entities/insert.test.js +90 -0
  139. package/test/entities/line.test.js +182 -6
  140. package/test/entities/point.test.js +375 -37
  141. package/test/entities/solid.test.js +156 -0
  142. package/test/entities/text.test.js +533 -7
  143. package/test/integration/exportIntegration.reference.dxf +1706 -0
  144. package/test/integration/exportIntegration.test.js +186 -0
  145. package/test/integration/importExportIntegration.test.js +126 -0
  146. package/test/integration/intersectionIntegration.test.js +880 -0
  147. package/test/integration/userInputIntegration.reference.dxf +1410 -0
  148. package/test/integration/userInputIntegration.test.js +269 -0
  149. package/test/lib/boundingBox.test.js +26 -2
  150. package/test/lib/canvas.test.js +613 -5
  151. package/test/lib/clipboard.test.js +70 -0
  152. package/test/lib/colour.test.js +114 -0
  153. package/test/lib/colours.test.js +63 -18
  154. package/test/lib/commandLine.test.js +159 -22
  155. package/test/lib/commandManager.test.js +4 -4
  156. package/test/lib/constants.test.js +9 -0
  157. package/test/lib/dxf/dxfFile.test.js +6 -2
  158. package/test/lib/dxf/dxfIterator.test.js +1 -1
  159. package/test/lib/dxf/dxfWrite.test.js +173 -0
  160. package/test/lib/dxf/handleManager.test.js +137 -0
  161. package/test/lib/dxf/sections/blocks.test.js +5 -5
  162. package/test/lib/dxf/sections/entities.test.js +4 -4
  163. package/test/lib/dxf/sections/header.test.js +18 -4
  164. package/test/lib/dxf/sections/objects.test.js +132 -0
  165. package/test/lib/dxf/sections/section.test.js +29 -29
  166. package/test/lib/dxf/sections/tables.test.js +3 -3
  167. package/test/lib/entityManager.test.js +163 -0
  168. package/test/lib/headers.test.js +233 -0
  169. package/test/lib/inputManager.test.js +1144 -5
  170. package/test/lib/intersect.test.js +454 -331
  171. package/test/lib/logging.test.js +1 -1
  172. package/test/lib/matrix.test.js +1 -1
  173. package/test/lib/mouse.test.js +327 -4
  174. package/test/lib/patterns.test.js +105 -0
  175. package/test/lib/promptOptions.test.js +179 -0
  176. package/test/lib/scene.test.js +16 -52
  177. package/test/lib/selectionManager.test.js +17 -5
  178. package/test/lib/settings.test.js +111 -5
  179. package/test/lib/snapping.test.js +142 -4
  180. package/test/lib/stateManager.test.js +155 -0
  181. package/test/lib/utils.test.js +81 -1
  182. package/test/objects/dictionary.test.js +81 -0
  183. package/test/objects/dictionaryManager.test.js +34 -0
  184. package/test/properties/dimType.test.js +62 -0
  185. package/test/properties/flags.test.js +164 -0
  186. package/test/properties/property.test.js +13 -0
  187. package/test/properties/propertyManager.test.js +10 -11
  188. package/test/tables/appId.test.js +46 -0
  189. package/test/tables/appIdManager.test.js +72 -0
  190. package/test/tables/block.test.js +157 -0
  191. package/test/tables/blockManager.test.js +52 -0
  192. package/test/tables/blockRecord.test.js +39 -0
  193. package/test/tables/blockRecordManager.test.js +60 -0
  194. package/test/tables/dimstyle.test.js +72 -0
  195. package/test/tables/endblk.test.js +30 -0
  196. package/test/tables/layer.test.js +95 -0
  197. package/test/tables/layerManager.test.js +172 -0
  198. package/test/{styles → tables}/ltype.test.js +7 -7
  199. package/test/{styles → tables}/ltypeManager.test.js +2 -2
  200. package/test/tables/style.test.js +44 -0
  201. package/test/tables/stylemanagerbase.test.js +220 -0
  202. package/test/tables/tableManagerBase.test.js +194 -0
  203. package/test/tables/ucs.test.js +37 -0
  204. package/test/tables/ucsManager.test.js +48 -0
  205. package/test/tables/view.test.js +37 -0
  206. package/test/tables/viewManager.test.js +48 -0
  207. package/test/tables/vport.test.js +117 -0
  208. package/test/tables/vportManager.test.js +54 -0
  209. package/test/test-helpers/test-helpers.js +66 -0
  210. package/test/tools/chamfer.test.js +970 -0
  211. package/test/tools/chamferFilletBase.test.js +446 -0
  212. package/test/tools/copy.test.js +22 -14
  213. package/test/tools/copybase.test.js +93 -0
  214. package/test/tools/copyclip.test.js +92 -0
  215. package/test/tools/cornerEntity.test.js +201 -0
  216. package/test/tools/cutclip.test.js +94 -0
  217. package/test/tools/distance.test.js +140 -18
  218. package/test/tools/erase.test.js +12 -12
  219. package/test/tools/explode.test.js +45 -0
  220. package/test/tools/extend.test.js +326 -44
  221. package/test/tools/fillet.test.js +831 -0
  222. package/test/tools/identify.test.js +115 -16
  223. package/test/tools/matchProp.test.js +84 -0
  224. package/test/tools/mirror.test.js +475 -0
  225. package/test/tools/move.test.js +75 -19
  226. package/test/tools/offset.test.js +748 -0
  227. package/test/tools/pan.test.js +72 -0
  228. package/test/tools/pasteclip.test.js +100 -0
  229. package/test/tools/purge.test.js +89 -0
  230. package/test/tools/rotate.test.js +89 -23
  231. package/test/tools/scale.test.js +529 -0
  232. package/test/tools/trim.test.js +419 -84
  233. package/test/tools/zoom.test.js +504 -0
  234. package/core/entities/alignedDimension.js +0 -279
  235. package/core/entities/angularDimension.js +0 -194
  236. package/core/entities/baseDimension.js +0 -227
  237. package/core/entities/block.js +0 -247
  238. package/core/entities/diametricDimension.js +0 -133
  239. package/core/entities/dimension.js +0 -202
  240. package/core/entities/radialDimension.js +0 -126
  241. package/core/styles/dimStyle.js +0 -719
  242. package/core/styles/dimStyleManager.js +0 -47
  243. package/core/styles/layer.js +0 -133
  244. package/core/styles/layerManager.js +0 -40
  245. package/core/styles/ltype.js +0 -86
  246. package/core/styles/ltypeManager.js +0 -50
  247. package/core/styles/style.js +0 -158
  248. package/core/styles/styleManager.js +0 -43
  249. package/core/styles/styleManagerBase.js +0 -299
  250. package/test/entities/block.test.js +0 -22
  251. package/test/styles/dimstyle.test.js +0 -19
  252. package/test/styles/layerManager.test.js +0 -150
  253. package/test/styles/style.test.js +0 -33
  254. package/test/styles/stylemanagerbase.test.js +0 -219
@@ -1,122 +1,27 @@
1
- import {Tool} from '../tools/tool.js';
2
- import {Snapping} from './snapping.js';
3
- import {Utils} from './utils.js';
4
-
5
- import {DesignCore} from '../designCore.js';
6
-
7
- export class PromptOptions {
8
- constructor(promptMessage = 'error', types = [], options = []) {
9
- this.promptMessage = promptMessage;
10
- this.types = types;
11
- this.options = options;
12
- this.resolve = undefined;
13
- this.reject = undefined;
14
- }
15
-
16
- /**
17
- * Return data to the input request
18
- * @param {any} input
19
- */
20
- respond(input) {
21
- if (this.types.includes(Input.getType(input))) {
22
- // expected type input, pass to active command
23
- this.resolve(input);
24
- } else if (this.parseInputToOption(input) !== undefined) {
25
- // input matches command option, pass to active command
26
- this.resolve(this.parseInputToOption(input));
27
- } else {
28
- throw Error('Invalid response type');
29
- }
30
- }
31
-
32
- /**
33
- * Match the input to a command option
34
- * @param {any} input
35
- * @returns undefined or the matched option
36
- */
37
- parseInputToOption(input) {
38
- if (this.options.length === 0) {
39
- return;
40
- }
41
-
42
- for (let i = 0; i < this.options.length; i++) {
43
- const option = this.options[i];
44
- // convert the option to uppercase and substring to the input length for comparison
45
- const optionSubstring = option.toUpperCase().substring(0, input.length);
46
- if (optionSubstring === input.toUpperCase()) {
47
- return option;
48
- }
49
- }
50
-
51
- return;
52
- }
1
+ import { Tool } from '../tools/tool.js';
2
+ import { Snapping } from './snapping.js';
3
+ import { Utils } from './utils.js';
53
4
 
54
- /**
55
- * Reject the input request
56
- */
57
- reject() {
58
- this.reject();
59
- }
5
+ import { DesignCore } from '../designCore.js';
6
+ import { Point } from '../entities/point.js';
7
+ import { Input, MouseDown, MouseUp } from './input.js';
60
8
 
61
- /**
62
- * Return the prompt for the input request
63
- * @returns
64
- */
65
- getPrompt() {
66
- let msg = `${this.promptMessage}`;
67
- if (this.options.length) {
68
- msg = `${this.promptMessage} [${this.options}]`;
69
- }
70
- return msg;
71
- }
72
-
73
- /**
74
- * Set the resolve callback
75
- * @param {any} resolve - callback function
76
- */
77
- setResolve(resolve) {
78
- this.resolve = resolve;
79
- }
80
-
81
- /**
82
- * Set the reject callback
83
- * @param {any} reject - callback function
84
- */
85
- setReject(reject) {
86
- this.reject = reject;
87
- }
88
- }
89
-
90
- export class Input {
91
- static Type = {
92
- POINT: 'Point',
93
- SELECTIONSET: 'SelectionSet',
94
- SINGLESELECTION: 'SingleSelection',
95
- NUMBER: 'Number',
96
- STRING: 'String',
97
- };
98
-
99
- /**
100
- * Return the Input.Type for value
101
- * @param {any} value
102
- * @returns
103
- */
104
- static getType(value) {
105
- if (value === undefined) {
106
- throw Error('Input.Type: Undefined input type');
107
- }
108
-
109
- return value.constructor.name;
110
- }
111
- }
9
+ export { Input, MouseDown, MouseUp } from './input.js';
10
+ export { PromptOptions } from './promptOptions.js';
112
11
 
12
+ /** InputManager Class */
113
13
  export class InputManager {
14
+ /** Create InputManager */
114
15
  constructor() {
115
16
  this.activeCommand = undefined;
116
17
 
117
18
  this.selection = undefined;
118
19
  this.promptOption = undefined;
119
20
 
21
+ // save the last point input
22
+ // this is needed for snapping, polar, ortho etc.
23
+ this.inputPoint = null;
24
+
120
25
  this.snapping = new Snapping();
121
26
  }
122
27
 
@@ -125,17 +30,23 @@ export class InputManager {
125
30
  */
126
31
  reset() {
127
32
  this.snapping.active = false;
33
+ this.inputPoint = null;
128
34
  DesignCore.CommandLine.resetPrompt();
129
35
  this.activeCommand = undefined;
130
- // this.promptOption.reject('reject');
36
+
37
+ if (this.promptOption) {
38
+ this.promptOption.cancel();
39
+ }
40
+
131
41
  this.promptOption = undefined;
132
42
  DesignCore.Scene.reset();
43
+ DesignCore.Canvas.setCursorForInputTypes([]);
133
44
  }
134
45
 
135
46
  /**
136
47
  * Create input request
137
48
  * @param {PromptOption} promptOption
138
- * @returns promise
49
+ * @return {Object} promise
139
50
  */
140
51
  requestInput(promptOption) {
141
52
  this.promptOption = promptOption;
@@ -152,14 +63,25 @@ export class InputManager {
152
63
  }
153
64
  });
154
65
 
155
- if (promptOption.types.includes(Input.Type.POINT)) {
156
- // turn on snapping
157
- this.snapping.active = true;
158
- }
66
+ this.snapping.active = promptOption.types.includes(Input.Type.POINT);
67
+ DesignCore.Canvas.setCursorForInputTypes(promptOption.types, promptOption.cursor);
68
+
69
+ return promptOption.createPromise().then((input) => {
70
+ if (input === undefined) return undefined;
71
+
72
+ // Handle DYNAMIC: convert number to projected point
73
+ if (promptOption.types.includes(Input.Type.DYNAMIC) && !isNaN(input)) {
74
+ const angle = this.inputPoint.angle(DesignCore.Mouse.pointOnScene());
75
+ input = this.inputPoint.project(angle, input);
76
+ }
159
77
 
160
- return new Promise((resolve, reject) => {
161
- this.promptOption.setResolve(resolve);
162
- this.promptOption.setReject(reject);
78
+ // Track the last input point
79
+ if (input instanceof Point) {
80
+ this.inputPoint = input;
81
+ }
82
+
83
+ this.snapping.active = false;
84
+ return input;
163
85
  });
164
86
  }
165
87
 
@@ -168,22 +90,79 @@ export class InputManager {
168
90
  * @param {any} input
169
91
  */
170
92
  onCommand(input) {
93
+ // If the active prompt would accept this input, pass it through directly
94
+ if (this.activeCommand !== undefined && this.promptOption) {
95
+ const accepted = this.promptOption.acceptsInput(input) ||
96
+ this.promptOption.parseInputToOption(input) !== undefined;
97
+ if (accepted) {
98
+ this.promptOption.respond(input);
99
+ return;
100
+ }
101
+ }
102
+
103
+ // If it's a recognised command/shortcut, switch commands without
104
+ // passing through the prompt (avoids a spurious invalid-input notification)
105
+ if (DesignCore.CommandManager.isCommandOrShortcut(input)) {
106
+ this.startCommand(input);
107
+ return;
108
+ }
109
+
110
+ // Input is neither accepted by the prompt nor a command — let the prompt notify
171
111
  if (this.activeCommand !== undefined) {
172
- this.promptOption.respond(input);
173
- } else if (DesignCore.CommandManager.isCommand(input) || DesignCore.CommandManager.isShortcut(input)) {
174
- this.initialiseItem(DesignCore.CommandManager.getCommand(input));
175
- this.activeCommand.execute();
112
+ this.handlePromptInput(input);
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Handle a command triggered by a UI button press.
118
+ * Always resets any active command and starts the new one,
119
+ * bypassing the active prompt entirely.
120
+ * @param {string} command
121
+ */
122
+ onCommandButton(command) {
123
+ if (DesignCore.CommandManager.isCommandOrShortcut(command)) {
124
+ this.startCommand(command);
176
125
  }
177
126
  }
178
127
 
128
+ /**
129
+ * Reset any active command and start a new one.
130
+ * @param {string} command - command name or shortcut
131
+ */
132
+ startCommand(command) {
133
+ if (this.activeCommand !== undefined) {
134
+ this.reset();
135
+ }
136
+
137
+ const resolvedCommand = DesignCore.CommandManager.getCommand(command);
138
+ DesignCore.CommandLine.addToCommandHistory(resolvedCommand);
139
+ this.activeCommand = DesignCore.CommandManager.createNew(resolvedCommand);
140
+ this.activeCommand.execute();
141
+ }
142
+
143
+ /**
144
+ * Try to handle input with the active prompt
145
+ * @param {any} input
146
+ * @return {boolean} true if handled
147
+ */
148
+ handlePromptInput(input) {
149
+ if (!this.promptOption) {
150
+ return false;
151
+ }
152
+
153
+ return this.promptOption.respond(input);
154
+ }
155
+
179
156
  /**
180
157
  * Handle enter / return presses
181
158
  */
182
159
  onEnterPressed() {
183
160
  if (this.activeCommand !== undefined) {
184
- if (this.promptOption.types.includes(Input.Type.SELECTIONSET) && DesignCore.Scene.selectionManager.selectionSet.accepted !== true) {
161
+ if (this.promptOption?.types.includes(Input.Type.SELECTIONSET) && DesignCore.Scene.selectionManager.selectionSet.accepted !== true) {
185
162
  DesignCore.Scene.selectionManager.selectionSet.accepted = true;
186
163
  this.promptOption.respond(DesignCore.Scene.selectionManager.selectionSet);
164
+ } else if (this.promptOption?.defaultValue !== undefined) {
165
+ this.promptOption.respond(this.promptOption.defaultValue);
187
166
  } else {
188
167
  this.reset();
189
168
  }
@@ -191,8 +170,7 @@ export class InputManager {
191
170
  const lastCommand = DesignCore.CommandLine.lastCommand[0];
192
171
  // if there was a previous command - repeat it...
193
172
  if (lastCommand) {
194
- this.initialiseItem(lastCommand);
195
- this.activeCommand.execute();
173
+ this.startCommand(lastCommand);
196
174
  }
197
175
  }
198
176
  }
@@ -226,7 +204,12 @@ export class InputManager {
226
204
  // Select entity only mouse is close to an entity and no snap point is available
227
205
  // Do allow selection when there is no command active
228
206
  // Don't allow selection of there is an active command that does't require a selection i.e. prompt option includes SINGLESELECTION
229
- if (index !== undefined && !snap && (this.activeCommand === undefined || this.promptOption !== undefined && (this.promptOption.types.includes(Input.Type.SINGLESELECTION)|| this.promptOption.types.includes(Input.Type.SELECTIONSET)))) {
207
+ const canSelectEntity = index !== undefined && !snap &&
208
+ (this.activeCommand === undefined ||
209
+ this.promptOption?.types.includes(Input.Type.SINGLESELECTION) ||
210
+ this.promptOption?.types.includes(Input.Type.SELECTIONSET));
211
+
212
+ if (canSelectEntity) {
230
213
  const selection = DesignCore.Scene.selectionManager.singleSelect(DesignCore.Mouse.pointOnScene());
231
214
  this.onSelection(selection);
232
215
  } else if (this.promptOption !== undefined && this.promptOption.types.includes(Input.Type.POINT)) {
@@ -239,42 +222,42 @@ export class InputManager {
239
222
  * Handle mouse position changes
240
223
  */
241
224
  mouseMoved() {
242
- DesignCore.Scene.tempItems = [];
243
- DesignCore.Scene.auxiliaryItems = [];
225
+ DesignCore.Scene.tempEntities.clear();
226
+ DesignCore.Scene.auxiliaryEntities.clear();
244
227
 
245
- // selection window active
246
228
  if (DesignCore.Mouse.buttonOneDown) {
247
- if (this.promptOption !== undefined) {
248
- // check if the active command requires a selection set
249
- if (!this.promptOption.types.includes(Input.Type.SELECTIONSET)) {
250
- return;
251
- }
252
- }
229
+ const windowSelect = (this.activeCommand === undefined && !this.promptOption) ||
230
+ this.promptOption?.types.includes(Input.Type.SELECTIONSET);
253
231
 
254
- DesignCore.Scene.selectionManager.drawSelectionWindow();
255
- }
256
-
257
- // store the snapped point
258
- let snapped;
259
- let selecting = false;
260
- if (this.snapping.active) {
261
- snapped = this.snapping.snap();
232
+ if (windowSelect) {
233
+ DesignCore.Scene.selectionManager.drawSelectionWindow();
234
+ }
262
235
  }
263
236
 
264
- // Determine if the mouse is over a scene item only if no snap point is available
265
- if (snapped === undefined) {
266
- if (this.activeCommand === undefined || this.activeCommand !== undefined && (this.promptOption.types.includes(Input.Type.SINGLESELECTION) || this.promptOption.types.includes(Input.Type.SELECTIONSET))) {
267
- const index = DesignCore.Scene.selectionManager.findClosestItem(DesignCore.Mouse.pointOnScene());
268
- if (index !== undefined) {
269
- const copyofitem = Utils.cloneObject(DesignCore.Scene.items[index]);
270
- // copyofitem.colour = DesignCore.Core.settings.selecteditemscolour.toString();
271
- copyofitem.lineWidth = copyofitem.lineWidth * 2;
272
- DesignCore.Scene.addToTempItems(copyofitem);
273
- selecting = true;
274
- }
237
+ const snapped = this.snapping.snap();
238
+
239
+ // Apply polar/ortho snap and draw the tracking line only when no entity snap is active,
240
+ // a previous point exists, and no mouse buttons are down
241
+ if (!snapped &&
242
+ this.snapping.active &&
243
+ this.inputPoint !== null &&
244
+ !DesignCore.Mouse.buttonOneDown &&
245
+ !DesignCore.Mouse.buttonTwoDown &&
246
+ !DesignCore.Mouse.buttonThreeDown) {
247
+ let trackPoint;
248
+ if (DesignCore.Settings.polar) {
249
+ trackPoint = this.snapping.polarSnap(this.inputPoint);
250
+ } else if (DesignCore.Settings.ortho) {
251
+ trackPoint = this.snapping.orthoSnap(this.inputPoint);
252
+ }
253
+ if (trackPoint) {
254
+ DesignCore.Mouse.setPosFromScenePoint(trackPoint);
255
+ this.snapping.addTrackingLine(this.inputPoint, trackPoint);
275
256
  }
276
257
  }
277
258
 
259
+ const selecting = !snapped && this.highlightEntityUnderMouse();
260
+
278
261
  // preview active commands when items are not being selected
279
262
  if (this.activeCommand !== undefined && !selecting) {
280
263
  this.activeCommand.preview();
@@ -283,34 +266,57 @@ export class InputManager {
283
266
  DesignCore.Canvas.requestPaint();
284
267
  }
285
268
 
269
+ /**
270
+ * Highlight the entity under the mouse cursor
271
+ * @return {boolean} true if an entity was highlighted
272
+ */
273
+ highlightEntityUnderMouse() {
274
+ if (DesignCore.Mouse.buttonOneDown || DesignCore.Mouse.buttonTwoDown || DesignCore.Mouse.buttonThreeDown) {
275
+ return false;
276
+ }
277
+
278
+ if (this.activeCommand !== undefined &&
279
+ !this.promptOption?.types.includes(Input.Type.SINGLESELECTION) &&
280
+ !this.promptOption?.types.includes(Input.Type.SELECTIONSET)) {
281
+ return false;
282
+ }
283
+
284
+ const index = DesignCore.Scene.selectionManager.findClosestItem(DesignCore.Mouse.pointOnScene());
285
+ if (index !== undefined) {
286
+ DesignCore.Scene.tempEntities.add(Utils.cloneObject(DesignCore.Scene.entities.get(index)));
287
+ return true;
288
+ }
289
+
290
+ return false;
291
+ }
292
+
286
293
  /**
287
294
  * Handle single selection
288
295
  */
289
296
  singleSelect() {
290
- // console.log('single select');
291
- const point = DesignCore.Mouse.pointOnScene();
292
- this.onLeftClick(point);
297
+ this.inputPoint = DesignCore.Mouse.pointOnScene();
298
+ this.onLeftClick(this.inputPoint);
293
299
  }
294
300
 
295
301
  /**
296
302
  * Handle window selection
297
303
  */
298
304
  windowSelect() {
299
- // console.log('window select');
300
305
  DesignCore.Scene.selectionManager.windowSelect();
301
306
  }
302
307
 
303
308
 
304
309
  /**
305
310
  * Handle mouse down
306
- * @param {integer} button
311
+ * @param {number} button
307
312
  */
308
313
  mouseDown(button) {
309
314
  switch (button) {
310
315
  case 0: // left button
311
- // TODO: can't select and window select at the same time
312
- // This needs combining with canvas.mouseMove to define selection, snapping and window selection
313
316
  this.singleSelect();
317
+ if (this.promptOption?.types.includes(Input.Type.MOUSEDOWN)) {
318
+ this.promptOption.resolve?.(new MouseDown());
319
+ }
314
320
  break;
315
321
  case 1: // middle button
316
322
  break;
@@ -321,19 +327,22 @@ export class InputManager {
321
327
 
322
328
  /**
323
329
  * Handle mouse up
324
- * @param {integer} button
330
+ * @param {number} button
325
331
  */
326
332
  mouseUp(button) {
327
333
  switch (button) {
328
334
  case 0: // left button
329
335
  // Clear tempItems - This is here to remove the crossing window
330
- DesignCore.Scene.auxiliaryItems = [];
336
+ DesignCore.Scene.auxiliaryEntities.clear();
337
+ if (this.promptOption?.types.includes(Input.Type.MOUSEUP)) {
338
+ this.promptOption.resolve?.(new MouseUp());
339
+ return;
340
+ }
331
341
 
332
- if (this.promptOption !== undefined) {
333
- // check if the active command requires a selection set
334
- if (!this.promptOption.types.includes(Input.Type.SELECTIONSET)) {
335
- return;
336
- }
342
+ // Skip window selection when there is an active prompt or command, unless it is a selection set
343
+ if ((this.promptOption !== undefined || this.activeCommand !== undefined) &&
344
+ !this.promptOption?.types.includes(Input.Type.SELECTIONSET)) {
345
+ return;
337
346
  }
338
347
 
339
348
  // check if the mouse position has changed since mousedown
@@ -352,43 +361,36 @@ export class InputManager {
352
361
 
353
362
  /**
354
363
  * Handle canvas selection
355
- * @param {*} selection
364
+ * @param {Selection} selection
356
365
  */
357
366
  onSelection(selection) {
358
- if (this.activeCommand !== undefined && this.promptOption.types.includes(Input.Type.SINGLESELECTION)) {
367
+ if (this.activeCommand !== undefined && this.promptOption?.types.includes(Input.Type.SINGLESELECTION)) {
359
368
  this.promptOption.respond(selection);
360
- } else {
361
- if (Input.getType(selection) === Input.Type.SINGLESELECTION) {
362
- DesignCore.Scene.selectionManager.addToSelectionSet(selection.selectedItemIndex);
363
- }
369
+ return;
370
+ }
364
371
 
365
- // update selection set
372
+ if (Input.getType(selection) === Input.Type.SINGLESELECTION) {
373
+ DesignCore.Scene.selectionManager.addToSelectionSet(selection.selectedItemIndex);
366
374
  }
367
375
  }
368
376
 
369
- /**
370
- * Initialise commands
371
- * @param {string} command
372
- */
373
- initialiseItem(command) {
374
- DesignCore.Scene.saveRequired();
375
- DesignCore.CommandLine.addToCommandHistory(command);
376
- this.activeCommand = DesignCore.CommandManager.createNew(command);
377
- };
378
-
379
377
  /**
380
378
  * Set the command prompt
381
379
  * @param {string} prompt
382
380
  */
383
381
  setPrompt(prompt) {
384
- // TODO: single line method required?
385
- DesignCore.CommandLine.setPrompt(`${this.activeCommand.type} - ${prompt}`);
382
+ // return if there is no active command
383
+ if (this.activeCommand === undefined) {
384
+ return;
385
+ }
386
+
387
+ DesignCore.CommandLine.setPrompt(`${this.activeCommand.type}${prompt ? '- ':''}${prompt}`);
386
388
  }
387
389
 
388
390
  /**
389
391
  * Execute the currently active command then reset
390
- * @param {*} item - item to create
391
- * @param {*} index - index of item in scene.items
392
+ * @param {Object} item - item to create
393
+ * @param {number} index - index of item
392
394
  */
393
395
  executeCommand(item, index = undefined) {
394
396
  this.actionCommand(item, index);
@@ -397,17 +399,20 @@ export class InputManager {
397
399
 
398
400
  /**
399
401
  * Execute the currently active command without reset
400
- * @param {*} item - item to create
401
- * @param {*} index - index of item in scene.items
402
+ * @param {Object} item - item to create
403
+ * @param {number} index - index of item
404
+ * @return {number}
402
405
  */
403
406
  actionCommand(item, index = undefined) {
404
407
  if (this.activeCommand instanceof Tool) {
405
408
  this.activeCommand.action();
406
409
  } else {
410
+ if (item !== undefined) {
407
411
  // set the items layer to the current layer
408
- item.layer = DesignCore.LayerManager.getCstyle();
409
- // return the item index
410
- return DesignCore.Scene.addItem(item.type, item, index);
412
+ item.layer = DesignCore.LayerManager.getCstyle();
413
+ // return the item index
414
+ return DesignCore.Scene.addItem(item.type, item, index);
415
+ }
411
416
  }
412
417
  }
413
418
  }