-
Notifications
You must be signed in to change notification settings - Fork 25
/
Copy pathvideo.js
563 lines (520 loc) · 26.2 KB
/
video.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
//https://developers.google.com/youtube/iframe_api_reference
/* this code failed on chrome app dueto security restrictions,
so for now I just show a url in a separate browser window
when the select value changes.
function init_video(){
// 2. This code loads the IFrame Player API code asynchronously.
var tag = document.createElement('script');
tag.src = "https://www.youtube.com/iframe_api";
var firstScriptTag = document.getElementsByTagName('script')[0];
firstScriptTag.parentNode.insertBefore(tag, firstScriptTag);
}
var video_player;
function onYouTubeIframeAPIReady() {
video_player = new YT.Player('video_player_id', {
height: '390',
width: '640',
events: {
'onReady': onPlayerReady
}
});
}
function onPlayerReady(event) {
event.target.setVolume(100);
event.target.playVideo();
}
*/
//gets rid of innHTML and all the event listeners, needed when switching
//between dexter sim and stl view
//https://stackoverflow.com/questions/9251837/how-to-remove-all-listeners-in-an-element
var THREE = require('three')
var THREE_GLTFLoader = require('three-gltf-loader')
function clear_out_sim_graphics_pane_id(){
if(window.sim_graphics_pane_id){
var new_element = sim_graphics_pane_id.cloneNode(false);
sim_graphics_pane_id.parentNode.replaceChild(new_element, sim_graphics_pane_id)
}
}
function setSimPaneHTML(content)
{
destroySimulation();
sim_pane_content_id = content;
}
var prev_make_instruction_src = undefined
var init_sim_in_process = false
//choose_file_path matters if select_val == "Choose File", and is only passed in
//when initing DDE/ It is the full file path of the file to be shown
//see ready.js $('#misc_pane_menu_id').on('select' ...)
//Use the below global var for "reading" the misc_pane_menu_label and
//the function for setting it.
//neigher of these are good for DDE users, they're system level.
//Users should use: show_in_misc_pane
var misc_pane_menu_selection //workaround for $("#misc_pane_menu_id").jqxComboBox('val') jqxwidget bug
//this does NOT do the action of the selection, just changes the text shown in the menu.
function set_misc_pane_menu_selection(label){
misc_pane_menu_selection = label
$('#misc_pane_menu_id').jqxComboBox('val', label)
}
function show_in_misc_pane(content, arg1 = "", arg2){
if(content!="Choose File"&&content!="Simulate Dexter")
{
destroySimulation();
}
//if Choose File is called from outside dialog, and user cancels, we don't want to
//change the combo_box value OR persistent save it.
//But if user doesn't cancel, we DO want to change the combo box value, and,
//if the value is good, persistent save it.
if (content === "Choose File") {
choose_file({},
function(err, path) {
if(err) { //user canceled from choose file dialog so don't persistent-save the value.
//leave combo_box val at "choose file" which won't match content, but we might
// not want to "refresh" the content, and since that always happens
//if we did $('#misc_pane_menu_id').jqxComboBox('val', the_prev_val),
//just leave it as "Choose File"
let prev_val = persistent_get("misc_pane_content")
set_misc_pane_menu_selection(prev_val)
return
}
else {
$("#misc_pane_menu_id").jqxComboBox('unselectItem', "Choose File") //must do!
// just let it fall through ////old: return show_in_misc_pane(content) //$('#misc_pane_menu_id').jqxComboBox('val', content) //causes show_in_misc_pane to be called with the chosen value
set_misc_pane_menu_selection(path)
destroySimulation();
show_in_misc_pane(path)
return
}
})
}
//let orig_content = $('#misc_pane_menu_id').jqxComboBox('val') //warning: this doesn't always get the
//content showing in the combo box. Bug in jqxwidgets. So just always set it.
if(content !== misc_pane_menu_selection) {
let label = content
if((typeof(content) === "string") && content.startsWith("<")) {
label = "HTML"
}
set_misc_pane_menu_selection(label)
}
//$('#misc_pane_menu_id').jqxComboBox('val', content) //this will cause combon box's onchange event, defined in ready.js to call show_in_misc_pane again,
// but this new time, content WILL equal what's in the combo-box val so tis clause doesn't hit
// setTimeout(function() {
// show_in_misc_pane(content)
// }, 100)
//return //note that calling $("#misc_pane_menu_id").jqxComboBox('val', content), will cause
//show_in_misc_pane to be called again due to the combo box's on select.
if(MakeInstruction.is_shown()) { //so that in case this or some later call to show_in_misc_pane
// is "Make Instruction", we know what content to fill it with
prev_make_instruction_src = MakeInstruction.dialog_to_instruction_src()
}
let content_is_good = false //presume bad until proven otherwise, esp because some of the time we don't find out
// if it's bad until after a callback, and we don't want to save a bad value.
// we'd rather leave the prev good value in the persistent save.
if(content instanceof HTMLElement){
sim_pane_content_id.innerHTML = ""
let content_copy = content.cloneNode(true) //true means copy all children on down.
//must copy because otherwise content is removed from its original place and put here,
//but we want to leave it in its button_column for example.
sim_pane_content_id.appendChild(content_copy)
return
//do not attempt to save the elt persistently. We just don't return to this if we launch dde.
}
content = replace_substrings(content, "__dirname", __dirname)
if((content == "Simulate Dexter") && init_sim_in_process){
return
}
else {
init_sim_in_process = false
}
try {
if (content === "Simulate Dexter") {
init_sim_in_process = true
sim_pane_content_id.innerHTML = make_sim_html();
// '<div style="white-space:nowrap;"> ' + //Simulate Job/Robot: <select id="job_or_robot_to_simulate_id">' +
// '<b>Move Dur: </b><span id="sim_pane_move_dur_id"></span> s' +
// ' <button onclick="SimBuild.init()">Load SimBuild</button> ' +
// '<span title="Inspect simulator Details." ' +
// 'onclick="SimUtils.inspect_dexter_sim_instance()" ' +
// 'style="margin-left:15px;color:blue;cursor:pointer;font-weight:bold;"> ⓘ </span> ' +
// '</div>' +
// '<b title="X position of end effector in meters.">X: </b><span id="sim_pane_x_id" style="min-width:50px; text-align:left; display:inline-block"></span>' + //"margin-left:5px;
// '<b title="Y position of end effector in meters."> Y: </b><span id="sim_pane_y_id" style="min-width:50px; text-align:left; display:inline-block"></span>' + //"margin-left:5px;
// '<b title="Z position of end effector in meters."> Z: </b><span id="sim_pane_z_id" style="min-width:50px; text-align:left; display:inline-block"></span>' + //"margin-left:5px;
// '<div style="white-space:nowrap;">' +
// '<b title="Joint 1 angle in degrees."> J1: </b><span id="sim_pane_j1_id" style="min-width:30px; text-align:left; display:inline-block"></span>' + //"margin-left:5px;
// '<b title="Joint 2 angle in degrees."> J2: </b><span id="sim_pane_j2_id" style="min-width:30px; text-align:left; display:inline-block"></span>' +
// '<b title="Joint 3 angle in degrees."> J3: </b><span id="sim_pane_j3_id" style="min-width:30px; text-align:left; display:inline-block"></span>' +
// '<b title="Joint 4 angle in degrees."> J4: </b><span id="sim_pane_j4_id" style="min-width:30px; text-align:left; display:inline-block"></span>' +
// '<b title="Joint 5 angle in degrees."> J5: </b><span id="sim_pane_j5_id" style="min-width:30px; text-align:left; display:inline-block"></span>' +
// '<b title="Joint 6 angle in degrees."> J6: </b><span id="sim_pane_j6_id" style="min-width:30px; text-align:left; display:inline-block"></span>' +
// '<b title="Joint 7 angle in degrees."> J7: </b><span id="sim_pane_j7_id" style="min-width:30px; text-align:left; display:inline-block"></span></div>' +
// '<div id="sim_graphics_pane_id"></div>'
open_doc(simulate_pane_doc_id)
init_simulation()
//sim.renderer.render(sim.scene, sim.camera);
setTimeout(function() {
SimUtils.render_multi_with_prev_args_maybe()},
100)
//}
content_is_good = true
}
else if (content === "create_dexter_marker"){
sim_pane_content_id.innerHTML ='<div id="sim_graphics_pane_id"></div>'
init_simulation()
let xyz = arg1
let rotzyz = (arg2 ? arg2 : [0, 0, 0])
create_marker_mesh(xyz, rotzyz)
sim.renderer.render(sim.scene, sim.camera)
//SimUtils.render_once_with_prev_args_maybe()
content_is_good = true
}
else if(content === "Dexter Photo"){
let file_name = __dirname + "/doc/HD+Robotics-8517.jpg" //Dexter and Kent
sim_pane_content_id.innerHTML = "<img src='" + file_name + "' style='width:100%;'/>"
content_is_good = true
}
else if(content === "Dexter Architecture"){
let file_name = __dirname + "/doc/dexter_architecture.jpg"
sim_pane_content_id.innerHTML = "<img src='" + file_name + "' style='width:100%;'/>"
content_is_good = true
}
else if (content === "Reference Manual"){
let div_html = `<div contenteditable='false'
style='height:100%; width:100%; padding:5%; background-color:#DDDDDD; overflow:scroll;'>` +
"<div style='font-size:18px; font-weight:700;'>Reference Manual</div>"
content = read_file(__dirname + "/doc/ref_man.html")
//sim_graphics_pane_id.style = "width:97%; height:90%; padding:5%; background-color:white; overflow:scroll !important;"
sim_pane_content_id.innerHTML = div_html + content + "</div>"
content_is_good = true
}
else if (content === "Make Instruction"){
let src = ((arg1 === "") ? prev_make_instruction_src : arg1)
//instr, show_doc, set_misc_pane_menu_label
MakeInstruction.show(src, true, false) //if arg value is undefined, show the default move_all_joints, otherwise, its previous state
//must pass set_misc_pane_menu_label as false or will get infinite loop.
open_doc(make_instruction_pane_doc_id)
content_is_good = true
}
else if (content === "Haddington Website"){ //Will work for https:// ...
content = "<iframe src='http://www.hdrobotic.com' width='100%' height='100%'/>" //no way to catch an error like 404 here due to security restrictions.
sim_pane_content_id.innerHTML = content
content_is_good = true
}
else if (content === "Reward Board"){
sim_pane_content_id.innerHTML = Metrics.make_html()
content_is_good = true
}
else if (content.startsWith("http")){ //Will work for https:// ...
// Put before extension checking because of http://foo.jpg could be displayed if http checking before extension checking
content = "<iframe src='" + content + "' width='100%' height='100%'/>" //no way to catch an error like 404 here due to security restrictions.
sim_pane_content_id.innerHTML = content
//might error with file not found or can't use content, so don't persist the url just in case.
}
else if (content.endsWith(".stl")){
if(file_exists(content)){
sim_pane_content_id.innerHTML = '<div id="sim_graphics_pane_id"></div>'
//from: init_simulation()
the_scene = new THREE.Scene();
the_scene.name = "scene"
the_scene.background = new THREE.Color( 0x000000 ) // 0x000000black is the default
//from createRenderer
let the_renderer = new THREE.WebGLRenderer({ antialias:true });//antialias helps with drawing the table lines. //example: https://threejs.org/docs/#Manual/Introduction/Creating_a_scene
the_renderer.setSize( //sim.container.clientWidth, sim.container.clientHeight) //causes no canvas to appear
window.innerWidth, window.innerHeight );
//renderer.setPixelRatio( window.devicePixelRatio ); //causes no canvas to appear
//sim_graphics_pane_id.innerHTML = "" //done in video.js
//sim.renderer.shadowMap.enabled = true;
sim_pane_content_id.appendChild(the_renderer.domElement)
//createCamera() //sets sim.camera
//let the_camera = sim.camera
var the_camera = new THREE.PerspectiveCamera( 10, 2, 0.01, 100 );
var OrbitControls = require('three-orbitcontrols')
var the_controls = new OrbitControls( the_camera, the_renderer.domElement );
the_controls.target.set(0, 0, 0) //orientation of cam. what its looking at.
the_camera.position.set( 2.5, 3.3, 5.2);
the_controls.update();
//clear_out_sim_graphics_pane_id()
//stl_init_viewer()
function animate() {
requestAnimationFrame( animate );
// required if controls.enableDamping or controls.autoRotate are set to true
the_controls.update();
the_renderer.render( the_scene, the_camera );
}
var STLLoader = require('three-stl-loader')(THREE)
var loader = new STLLoader()
loader.load(content, function (geometry) {
var material = new THREE.MeshNormalMaterial()
var mesh = new THREE.Mesh(geometry, material)
mesh.scale.set(0.001, 0.001, 0.001)
mesh.name = content
the_scene.add(mesh)
//the_renderer.render(sim.scene, sim.camera)
animate()
})
/*let geometryt = new THREE.BoxGeometry(1, 1, 1);
let materialt = new THREE.MeshNormalMaterial({});
let mesh = new THREE.Mesh(geometryt, materialt)
the_scene.add(mesh)
// from https://threejs.org/docs/#examples/en/controls/OrbitControls
animate()*/
content_is_good = true
}
else {
warning("Could not find file: " + content)
}
}
else if (content.endsWith(".fbx")){
clear_out_sim_graphics_pane_id()
stl_init_viewer()
// from https://github.com/ckddbs/three-fbx-loader/commit/b3bc39bef2a4253abf2acc780870a03f5f9cd510
var FBXLoader = require('three-fbx-loader')
var loader = new FBXLoader()
//loader.load(content, function (object) { sim.scene.add(object)})
loader.load(content,
function (object) {
// object3d is a THREE.Group (THREE.Object3D)
//const mixer = new THREE.AnimationMixer(object3d);
// animations is a list of THREE.AnimationClip
//mixer.clipAction(object3d.animations[0]).play();
//https://discourse.threejs.org/t/fbx-model-default-material-is-meshphongmaterial-how-to-change/2855/2
object.traverse( function ( child ) {
if ( child.type === "Mesh" ) {
// switch the material here - you'll need to take the settings from the
//original material, or create your own new settings, something like:
const oldMat = child.material;
//https://discourse.threejs.org/t/fbx-model-default-material-is-meshphongmaterial-how-to-change/2855/2
//says in is experience, all fbx files have only material of MeshPhongMaterial, but at least one of
//Dexter's materials from fusion 360 is an ARRAY of 3 MeshPhongMaterial. Maybe that causes a problem
const old_color = (Array.isArray(oldMat) ? oldMat[0].color : oldMat.color)
child.material = new THREE.MeshNormalMaterial({})
//new THREE.MeshLambertMaterial( {color: old_color, map: oldMat.map,} );
/*let geom = child.geometry
geom.scale(0.001, 0.001, 0.001)
let pos = child.position
child.position.set(pos.x * 0.001,
pos.y * 0.001,
pos.z * 0.001)
*/
sim.scene.add(child)
}
} );
//var mixer = new THREE.AnimationMixer( object );
//var action = mixer.clipAction( object.animations[ 0 ] );
//action.play();
// sim.scene.add(object)
},
undefined,
function (err) {
console.error( err );
}
)
setTimeout(fbx_render, 400)
}
else if (content.endsWith(".gltf")){
// clear_out_sim_graphics_pane_id()
// stl_init_viewer()
// from https://github.com/ckddbs/three-fbx-loader/commit/b3bc39bef2a4253abf2acc780870a03f5f9cd510
//https://threejs.org/docs/#examples/en/loaders/GLTFLoader
var loader = new THREE_GLTFLoader()
function chainLink ( children, i ) {
// The previous link (base if i is 0).
let linkPrv = children[i-1];
let Lprv = new THREE.Matrix4();
Lprv.copy ( linkPrv.matrix );
let nLprv = new THREE.Matrix4();
nLprv.getInverse ( Lprv );
// The link's position WRT base.
let link = children[i];
let B = new THREE.Matrix4();
B.copy ( link.matrix );
// The link's position WRT the previous link.
let L = nLprv.multiply ( B );
// Remove the link from the current object tree.
children.splice ( i, 1 );
// Add it as a child to the previous link.
link.matrix.identity();
linkPrv.add ( link );
// Set it's position.
let p = new THREE.Vector3();
let q = new THREE.Quaternion();
let s = new THREE.Vector3();
L.decompose ( p, q, s );
link.position.set ( p.x, p.y, p.z );
link.setRotationFromQuaternion ( q );
} // chainLink()
loader.load(content,
function (gltf) {
// sim.scene.add(gltf.scene)
let root = gltf.scene;
let c0 = root.children[0]
c0.scale.set(0.001, 0.001, 0.001);
// Remove imported lights, cameras. Just want Object3D.
let objs = [];
c0.children.forEach ( c => {
if ( c.constructor.name === 'Object3D' ) {
objs.push(c); } } );
c0.children = objs;
// sim.scene.add(root)
sim.table.add(root)
// Set link parent-child relationships.
//
gltf_render(); // One render here to set the matrices.
// Now link.
chainLink ( objs[0].children, 7 );
chainLink ( objs[0].children, 6 );
chainLink ( objs[0].children, 5 );
chainLink ( objs[0].children, 4 );
chainLink ( objs[0].children, 3 );
chainLink ( objs[0].children, 2 );
chainLink ( objs[0].children, 1 );
},
undefined,
function (err) {
console.error( err );
}
)
// setTimeout(gltf_render, 400)
}
else if (content.endsWith(".jpg") ||
content.endsWith(".png") ||
content.endsWith(".gif") ||
content.endsWith(".bmp") ||
content.endsWith(".svg")
){
if(file_exists(content)){
let div_html = "<img style='width:100%;' src='" + content + "'/>"
sim_pane_content_id.innerHTML = div_html
content_is_good = true
}
else {
warning("Could not find file: " + content + "<br/>to show in the Misc pane.")
}
}
else if (content.endsWith(".txt") ||
content.endsWith(".js") ||
content.endsWith(".json") ||
content.endsWith(".dde")){
if(file_exists(content)){
let div_html =
"<div contenteditable='false' style='height:300px; width:800px; padding:5%; background-color:white; overflow:scroll;'>"
content = read_file(content)
content = replace_substrings(content, "<", "<")
//sim_graphics_pane_id.style = "width:97%; height:90%; padding:5%; background-color:white; overflow:scroll !important;"
sim_pane_content_id.innerHTML = div_html + "<pre>" + content + "</pre></div>"
content_is_good = true
}
else {
warning("Could not find file: " + content + "<br/>to show in the Misc pane.")
}
}
else if(file_exists(content)) { //content could be: (content.endsWith(".html") || content.endsWith(".htm") ||
//some random other file that hopefully can be displayed as html.
//but if we get an error, the below catch will catch it.
let div_html =
"<div contenteditable='false' style='height:300px; width:800px; padding:5%; background-color:white; overflow:scroll;'>"
content = read_file(content)
//sim_graphics_pane_id.style = "width:97%; height:90%; padding:5%; background-color:white; overflow:scroll !important;"
sim_pane_content_id.innerHTML = div_html + content + "</div>"
content_is_good = true //questionable, but maybe ok
}
//display any old html.
else if((typeof(content) === "string") && content.startsWith("<")){
sim_pane_content_id.innerHTML = content
}
else {
warning("Could not find file: " + content + "<br/>to show in the Misc pane.")
return
}
} //end try
catch(err){
warning("Could not load: " + content +
"<br/>into the Misc pane because: " + err.message)
content_is_good = false
}
if(content_is_good){
persistent_set("misc_pane_content", content)
}
}
//////// toggle_misc_pane_size
global.orig_left_splitter_pane_size = null //init on startup
global.orig_top_splitter_pane_size = null
global.misc_pane_should_increase = null
//the top level fn. determines if we are to grow or to shrink misc_pane.
function toggle_misc_pane_size(){
if(!global.orig_left_splitter_pane_size){
global.orig_left_splitter_pane_size = //global var
$('#outer_splitter_id').jqxSplitter('panels')[0].size
global.global.orig_top_splitter_pane_size = //global var
$('#right_splitter_id').jqxSplitter('panels')[0].size
global.misc_pane_should_increase = true //global var
}
if (global.misc_pane_should_increase) { increase_misc_pane_size() }
else { decrease_misc_pane_size() }
}
function increase_misc_pane_size(){
let left_width = $('#outer_splitter_id').jqxSplitter('panels')[0].size //the width of the Editor & output pane
let top_width = $('#right_splitter_id').jqxSplitter('panels')[0].size //the height of the Doc pane
let keep_going = false
if(left_width > 0) {
let new_size = (persistent_get("animate_ui") ? left_width - 6 : 0)
$('#outer_splitter_id').jqxSplitter({panels: [{ size: new_size}]})
keep_going = true
}
if(top_width > 0) {
let new_size = (persistent_get("animate_ui") ? top_width - 2 : 0)
$('#right_splitter_id').jqxSplitter({panels: [{ size: new_size}]})
keep_going = true
}
if(keep_going){
setTimeout(increase_misc_pane_size, 3)
}
else { //we're done
global.misc_pane_should_increase = false //next time we toggle, shrink
console.log("done with increase. now misc_pane_should_increase: " + misc_pane_should_increase)
}
}
function decrease_misc_pane_size(){
console.log("top of decrease_misc_pane_size")
let left_width = $('#outer_splitter_id').jqxSplitter('panels')[0].size
let top_width = $('#right_splitter_id').jqxSplitter('panels')[0].size
let keep_going = false
if(left_width < orig_left_splitter_pane_size) {
let new_size = (persistent_get("animate_ui") ? left_width + 6 : orig_left_splitter_pane_size)
$('#outer_splitter_id').jqxSplitter({panels: [{ size: new_size}]})
keep_going = true
}
if(top_width < orig_top_splitter_pane_size) {
let new_size = (persistent_get("animate_ui") ? top_width + 2 : orig_top_splitter_pane_size)
$('#right_splitter_id').jqxSplitter({panels: [{ size: new_size}]})
keep_going = true
}
if(keep_going){
setTimeout(decrease_misc_pane_size, 4)
}
else { //we're done
global.misc_pane_should_increase = true //next time we toggle, shrink
global.orig_left_splitter_pane_size = null //and reset the min size for when we shrink after that
}
}
////// end toggle_misc_pane_size
/* no longer called now that sim pane robot menu is gone.
function refresh_job_or_robot_to_simulate_id(){
if(window["job_or_robot_to_simulate_id"]){
let options_html = "<option>All</option>\n<option>Dexter.default</option>"
for(let job of Job.all_jobs()){
options_html += "<option>Job." + job.name + "</option>\n"
}
//for(let robot_name of Dexter.all_names){
// options_html += "<option>Dexter." + robot_name + "</option>\n"
//}
job_or_robot_to_simulate_id.innerHTML = options_html
}
}*/
//returns a string
/*function job_or_robot_to_simulate_name(){
if(window["job_or_robot_to_simulate_id"] && job_or_robot_to_simulate_id.value) {
return job_or_robot_to_simulate_id.value
}
else { return "Dexter.dexter0" }
}*/
var {replace_substrings} = require("./core/utils.js")