@vizualmodel/vmblu-cli 0.3.3 → 0.3.4

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.
@@ -44,6 +44,14 @@ rectRect(ctx,x,y,w,h,cLine,cFill) {
44
44
  }
45
45
  },
46
46
 
47
+ circle(ctx, x,y,r, color) {
48
+ ctx.beginPath();
49
+ ctx.strokeStyle=color;
50
+ ctx.moveTo(x,y);
51
+ ctx.arc(x,y,r,0, 2*Math.PI);
52
+ ctx.stroke();
53
+ },
54
+
47
55
  diamond(ctx,x,y,w,h,cFill) {
48
56
  ctx.beginPath();
49
57
  ctx.fillStyle = cFill;
@@ -349,28 +357,29 @@ centerLineText(ctx, text,cText,cLine,x,y,w,h) {
349
357
  ctx.fillText(text, x + (w - tm.width)/2, y+0.75*h);
350
358
  },
351
359
 
352
- interfaceText(ctx, text, font, cText, cLine,x,y,w,h) {
360
+ // interface text - link = 0, 1 or 2
361
+ ifName(ctx, text,color,rc) {
362
+
363
+ const {x,y,w,h} = rc;
353
364
 
354
365
  ctx.beginPath();
355
366
 
356
- // change the font
357
- const saveFont = ctx.font;
358
- ctx.font = font;
359
-
360
- ctx.strokeStyle = cLine;
367
+ ctx.strokeStyle = color.line;
368
+ ctx.fillStyle = color.line;
361
369
  const tm = ctx.measureText(text);
362
370
  const guard = 5;
363
371
 
364
- ctx.moveTo(x,y+h/2);
365
- ctx.lineTo(x + (w - tm.width)/2 - guard, y+h/2);
366
- ctx.moveTo(x + (w + tm.width)/2 + guard, y+h/2);
367
- ctx.lineTo(x+w,y+h/2);
368
- ctx.stroke();
372
+ const left = x + (w - tm.width)/2;
373
+ const cy = y+h/2;
369
374
 
370
- ctx.fillStyle = cText;
371
- ctx.fillText(text, x + (w - tm.width)/2, y+0.75*h);
375
+ ctx.moveTo(x,cy);
376
+ ctx.lineTo(left - guard, cy);
377
+ ctx.moveTo(left + tm.width + guard, cy);
378
+ ctx.lineTo(x+w,cy);
379
+ ctx.stroke();
372
380
 
373
- ctx.font = saveFont;
381
+ ctx.fillStyle = color.text;
382
+ ctx.fillText(text, left, y+0.75*h);
374
383
  },
375
384
 
376
385
  centerTextCursor(ctx,rc,text,pChar) {
@@ -1116,7 +1125,7 @@ const I = '|';
1116
1125
 
1117
1126
  const convert = {
1118
1127
 
1119
- rectToString : rc => `x ${Math.round(rc.x)} y ${Math.round(rc.y)} w ${Math.round(rc.w)} h ${Math.round(rc.h)}`,
1128
+ rectToString : rc => rc ? `x ${Math.round(rc.x)} y ${Math.round(rc.y)} w ${Math.round(rc.w)} h ${Math.round(rc.h)}` : 'x 0 y 0 w 0 h 0',
1120
1129
 
1121
1130
  stringToRect : str => {
1122
1131
 
@@ -1427,26 +1436,26 @@ const convert = {
1427
1436
  let middle = str.slice(opbr+1, clbr).split(',').map(n=>n.trim()).filter(Boolean).join(',');
1428
1437
  let post = str.slice(clbr+1).trim();
1429
1438
 
1430
- // if there is no point or hyphen, we add a space
1439
+ // if there is no period, hyphen or underscore, we add a period
1431
1440
  const last = pre.at(-1);
1432
- if ((pre.length > 0)&&(last != '.') && (last != '-') && (last != '_')) pre = pre + ' ';
1441
+ if ((pre.length > 0) && (last != '.') && (last != '-') && (last != '_')) pre = pre + ' ';
1433
1442
  const first = post[0];
1434
- if ((post.length > 0)&&(first != '.') && (first != '-') && (first != '_')) post = ' ' + post;
1443
+ if ((post.length > 0) && (first != '.') && (first != '-') && (first != '_')) post = ' ' + post;
1435
1444
 
1436
1445
  return [pre, middle, post]
1437
1446
  },
1438
1447
 
1439
- // a pin name that has been edited can start or end with a '+
1440
- //hasPlus: str => str[0] == '+' || str.at(-1) == '+' ,
1441
-
1448
+ // a pin name that has been edited can start or end with a special character
1449
+ // that indicates that th einterface name will be added as prefix / postfix
1450
+ // + indicates a single space
1442
1451
  needsPrefix: str => {
1443
1452
  const first = str[0];
1444
- return (first == '+' || first == '.' || first == '-' || first == '_')
1453
+ return (first == '+' || first == '.' || first == '-' || first == '_' || first == '/')
1445
1454
  },
1446
1455
 
1447
1456
  needsPostfix: str => {
1448
1457
  const last = str.at(-1);
1449
- return (last == '+' || last == '.' || last == '-' || last == '_')
1458
+ return (last == '+' || last == '.' || last == '-' || last == '_' || last == '/')
1450
1459
  },
1451
1460
 
1452
1461
  // add the prefix / postfix to a message
@@ -1458,13 +1467,9 @@ const convert = {
1458
1467
  const first = name[0];
1459
1468
 
1460
1469
  // Prefix
1461
- if (first == '.' || first == '-' || first == '_') {
1462
- const clean = name.slice(1).trim();
1463
- complete = prefix + first + clean;
1464
- }
1465
- else if (first == '+') {
1470
+ if (first == '+' || first == '.' || first == '-' || first == '_' || first == '/') {
1466
1471
  const clean = name.slice(1).trim();
1467
- complete = prefix + ' ' + clean;
1472
+ complete = first == '+' ? prefix + ' ' + clean : prefix + first + clean;
1468
1473
  }
1469
1474
 
1470
1475
  // done
@@ -1472,19 +1477,15 @@ const convert = {
1472
1477
  },
1473
1478
 
1474
1479
  // add the prefix / postfix to a message
1475
- combineWithPostfix(postFix, name) {
1480
+ combineWithPostfix(postfix, name) {
1476
1481
 
1477
1482
  // Default is just the name
1478
1483
  let complete = name;
1479
1484
  const last = name.at(-1);
1480
1485
 
1481
- if (last == '.' || last == '-' || last == '_') {
1482
- const clean = name.slice(0,-1).trim();
1483
- complete = clean + last + postFix;
1484
- }
1485
- else if (last == '+') {
1486
+ if (last == '+' || last == '.' || last == '-' || last == '_' || last == '/') {
1486
1487
  const clean = name.slice(0,-1).trim();
1487
- complete = clean + ' ' + postFix;
1488
+ complete = last == '+' ? clean + ' ' + postfix : clean + last + postfix;
1488
1489
  }
1489
1490
 
1490
1491
  // done
@@ -1492,57 +1493,20 @@ const convert = {
1492
1493
  },
1493
1494
 
1494
1495
  prefixMatch(prefix, name) {
1495
-
1496
1496
  if (name.startsWith(prefix)) {
1497
-
1498
1497
  const first = name[prefix.length];
1499
- return ((first == '.') || (first == '-') || (first == ' ') || (first == '_'))
1498
+ return ((first == '.') || (first == '-') || (first == ' ') || (first == '_') || (first == '/'))
1500
1499
  }
1501
1500
  },
1502
1501
 
1503
1502
  postfixMatch(postfix, name) {
1504
-
1505
1503
  if (name.endsWith(postfix)) {
1506
-
1507
1504
  const last = name.at(-postfix.length-1);
1508
- return ((last == '.') || (last == '-') || (last == ' ') || (last == "_"))
1509
- }
1510
- },
1511
-
1512
- // add the prefix / postfix to a message
1513
- xxcombineWithPrefix(prefix, name) {
1514
-
1515
- // Default is just the name
1516
- let complete = name;
1517
-
1518
- // Prefix
1519
- if (name[0] == '+') {
1520
-
1521
- const clean = name.slice(1).trim();
1522
-
1523
- // if there is some sort of a seperation character keep it
1524
- if ((clean[0] == '.') || (clean[0] == '-') || (prefix.at(-1) == '.') || (prefix.at(-1) == '-'))
1525
- complete = prefix + clean;
1526
- else
1527
- // otherwise use a space
1528
- complete = prefix + ' ' + clean;
1529
- }
1530
- // Postfix
1531
- else if (name.at(-1) == '+') {
1532
-
1533
- const clean = name.slice(0,-1).trim();
1534
-
1535
- if ((clean.at(-1) == '.') || (clean.at(-1) == '-') || (prefix[0] == '.') || (prefix[0] == '-'))
1536
- complete = clean + prefix;
1537
- else
1538
- complete = clean + ' ' + prefix;
1505
+ return ((last == '.') || (last == '-') || (last == ' ') || (last == "_") || (last == '/'))
1539
1506
  }
1540
-
1541
- // done
1542
- return complete
1543
1507
  },
1544
1508
 
1545
- // change a string abcdef to abcdef(1) and a string abcdef(3) to abcdef(n)
1509
+ // change a string abcdef to abcdef(n) and a string abcdef(m) to abcdef(n)
1546
1510
  addNumber: (str, n) => {
1547
1511
 
1548
1512
  // Find the position of the last '(' in the string
@@ -1943,7 +1907,7 @@ function StyleFactory() {
1943
1907
  cClose: color.vIcon1, cFullscreen: color.vIcon2, cCalibrate: color.vIcon3, cGrid: color.vIcon4
1944
1908
  };
1945
1909
  this.placement = {
1946
- marginTop: 30, marginLeft: 30, marginLeftPads: 210, nodesPerRow: 5, rowStep: 360, colStep: 270
1910
+ marginTop: 30, marginLeft: 30, marginLeftPads: 210, nodesPerRow: 5, rowStep: 360, colStep: 270, spacing: 50, tolerance: 10
1947
1911
  };
1948
1912
  }
1949
1913
  StyleFactory.prototype = {
@@ -2335,6 +2299,7 @@ function jsonDeepCopy(toCopy) {
2335
2299
  return toCopy ? JSON.parse(JSON.stringify(toCopy)) : null;
2336
2300
  }
2337
2301
 
2302
+ // REVIEW THIS
2338
2303
  function updateDerivedSettings(original, derived) {
2339
2304
 
2340
2305
  // If the original is null, return the derived as is
@@ -2347,10 +2312,14 @@ function updateDerivedSettings(original, derived) {
2347
2312
  return JSON.parse(JSON.stringify(original));
2348
2313
  }
2349
2314
 
2315
+ // keep arrays as is
2316
+ // MAYBE CHECK IF THE ELEMENT OF THE ARRAY ?
2317
+ if (Array.isArray(original) && Array.isArray(derived)) return derived;
2318
+
2350
2319
  // Iterate over the keys in the original settings
2351
2320
  for (let key in original) {
2352
2321
  if (original.hasOwnProperty(key)) {
2353
- if (typeof original[key] === 'object' && !Array.isArray(original[key]) && original[key] !== null) {
2322
+ if ( (typeof original[key] === 'object') && !Array.isArray(original[key]) && (original[key] !== null)) {
2354
2323
  // Recursively update if both original and derived have this key as an object
2355
2324
  derived[key] = updateDerivedSettings(original[key], derived[key] || {});
2356
2325
  } else {
@@ -2375,16 +2344,23 @@ function updateDerivedSettings(original, derived) {
2375
2344
  return derived;
2376
2345
  }
2377
2346
 
2347
+ var version = "0.3.4";
2348
+ var schemaVersion = "0.8.4";
2349
+ var pckg = {
2350
+ version: version,
2351
+ schemaVersion: schemaVersion};
2352
+
2378
2353
  function ModelHeader() {
2379
2354
 
2380
2355
  const today = new Date();
2381
2356
 
2382
- this.version = '0.0.1';
2357
+ // Set the schema version in the header
2358
+ this.version = pckg.schemaVersion;
2383
2359
  this.created = today.toLocaleString();
2384
2360
  this.saved = today.toLocaleString();
2385
2361
  this.utc = today.toJSON();
2386
2362
  this.style = style$1;
2387
- this.runtime = '@vizualmodel/vmblu';
2363
+ this.runtime = '@vizualmodel/vmblu-runtime';
2388
2364
  }
2389
2365
  ModelHeader.prototype = {
2390
2366
 
@@ -2419,7 +2395,7 @@ ModelHeader.prototype = {
2419
2395
  this.style = style$1.create(raw.style);
2420
2396
 
2421
2397
  // get the runtime
2422
- this.runtime = raw.runtime?.slice() ?? '@vizualmodel/vmblu';
2398
+ this.runtime = raw.runtime?.slice() ?? '@vizualmodel/vmblu-runtime';
2423
2399
  },
2424
2400
  };
2425
2401
 
@@ -2746,27 +2722,27 @@ async save(body) {
2746
2722
  return post(this.url+query, body)
2747
2723
  },
2748
2724
 
2749
- async getFolder() {
2725
+ // async getFolder() {
2750
2726
 
2751
- // check
2752
- if (!this.validURL()) return null
2727
+ // // check
2728
+ // if (!this.validURL()) return null
2753
2729
 
2754
- // wet have to add the api and service
2755
- let href = this.url.origin + '/api/folder' + this.url.pathname;
2730
+ // // wet have to add the api and service
2731
+ // let href = this.url.origin + '/api/folder' + this.url.pathname
2756
2732
 
2757
- const url = new URL(href);
2733
+ // const url = new URL(href)
2758
2734
 
2759
- // request the file - return the body
2760
- return await get(url)
2761
- .then( async response => {
2735
+ // // request the file - return the body
2736
+ // return await HTTP.get(url)
2737
+ // .then( async response => {
2762
2738
 
2763
- // the size of the body could be 0 - that is ok
2764
- if (response.headers.get('Content-Length') == '0') return null
2739
+ // // the size of the body could be 0 - that is ok
2740
+ // if (response.headers.get('Content-Length') == '0') return null
2765
2741
 
2766
- // convert
2767
- return await response.json()
2768
- })
2769
- },
2742
+ // // convert
2743
+ // return await response.json()
2744
+ // })
2745
+ // },
2770
2746
 
2771
2747
  // javascript source files can be imported
2772
2748
  async jsImport() {
@@ -2777,36 +2753,36 @@ async jsImport() {
2777
2753
  return import(this.url)
2778
2754
  },
2779
2755
 
2780
- async getFolderContent(){
2756
+ // async getFolderContent(){
2781
2757
 
2782
- const content = {
2783
- files: [],
2784
- folders: []
2785
- };
2758
+ // const content = {
2759
+ // files: [],
2760
+ // folders: []
2761
+ // }
2786
2762
 
2787
- // get the folder - return the promise
2788
- return this.getFolder()
2789
- .then( raw => {
2763
+ // // get the folder - return the promise
2764
+ // return this.getFolder()
2765
+ // .then( raw => {
2790
2766
 
2791
- // convert to arls...
2792
- content.files = raw.files.map(name => this.resolve(this.userPath + '/' + name)),
2793
- content.folders = raw.folders.map(name => this.resolve(this.userPath + '/' + name));
2767
+ // // convert to arls...
2768
+ // content.files = raw.files.map(name => this.resolve(this.userPath + '/' + name)),
2769
+ // content.folders = raw.folders.map(name => this.resolve(this.userPath + '/' + name))
2794
2770
 
2795
- // return result - that resolves the promise
2796
- return content
2797
- })
2798
- .catch (error => {
2771
+ // // return result - that resolves the promise
2772
+ // return content
2773
+ // })
2774
+ // .catch (error => {
2799
2775
 
2800
- // debug
2801
- console.error(error);
2776
+ // // debug
2777
+ // console.error(error)
2802
2778
 
2803
- // if the path was not found, fail silently else throw
2804
- if (error.options?.status != '404') throw error
2779
+ // // if the path was not found, fail silently else throw
2780
+ // if (error.options?.status != '404') throw error
2805
2781
 
2806
- // return result
2807
- return content
2808
- })
2809
- }
2782
+ // // return result
2783
+ // return content
2784
+ // })
2785
+ // }
2810
2786
 
2811
2787
  // async post(body, mime='application/json', query=null) {
2812
2788
 
@@ -2875,7 +2851,7 @@ async readSourceMap() {
2875
2851
 
2876
2852
  // get the full path
2877
2853
  const fullPath = this.arl?.getFullPath();
2878
- console.log('FULLPATH', fullPath);
2854
+
2879
2855
  // check
2880
2856
  if (!fullPath) return null
2881
2857
 
@@ -3107,7 +3083,7 @@ generateToolSpecs() {
3107
3083
  }
3108
3084
 
3109
3085
  const tool = {
3110
- name: meta.mcpName || `${node}_${pin}`,
3086
+ name: meta.mcpName || `${pin} @ ${node}`,
3111
3087
  description: meta.mcpDescription || meta.summary || `Trigger ${pin} on ${node}`,
3112
3088
  parameters: Array.from(paramMap.values()),
3113
3089
  returns: meta.returns || '',
@@ -4110,8 +4086,14 @@ const messageHandling = {
4110
4086
  },
4111
4087
 
4112
4088
  onShowSettings() {
4113
- this.canvas.getBoundingClientRect();
4114
4089
 
4090
+ // check
4091
+ if (!this.doc?.model) return
4092
+
4093
+ // Get the
4094
+ // const rect = this.canvas.getBoundingClientRect();
4095
+
4096
+ // notation
4115
4097
  const header = this.doc.model.header;
4116
4098
  const redraw = () => this.redraw();
4117
4099
 
@@ -4310,6 +4292,10 @@ const messageHandling = {
4310
4292
  },
4311
4293
 
4312
4294
  onSavePointSet({}) {
4295
+
4296
+ // check
4297
+ if (!this.doc?.model) return;
4298
+
4313
4299
  // make this accessible..
4314
4300
  const doc = this.doc;
4315
4301
 
@@ -4319,8 +4305,6 @@ const messageHandling = {
4319
4305
  message: '',
4320
4306
  pos: { x: 500, y: 100 },
4321
4307
  ok: () => {
4322
- // check
4323
- if (!doc?.model) return;
4324
4308
 
4325
4309
  // Get the actual node to save (mostly the root...)
4326
4310
  const toSave = doc.getNodeToSave();
@@ -4339,6 +4323,10 @@ const messageHandling = {
4339
4323
  },
4340
4324
 
4341
4325
  onSavePointBack({}) {
4326
+
4327
+ // check
4328
+ if (! this.doc?.model) return;
4329
+
4342
4330
  // make this accessible..
4343
4331
  const editor = this;
4344
4332
  const doc = this.doc;
@@ -4620,7 +4608,7 @@ const pinAreaHandling = {
4620
4608
  // select the pins that are in the widgets array
4621
4609
  pinAreaSelect(widgets) {
4622
4610
 
4623
- if (widgets.length == 0) return
4611
+ if (!widgets?.length) return
4624
4612
 
4625
4613
  // reset (not necessary ?)
4626
4614
  this.widgets.length = 0;
@@ -4629,12 +4617,15 @@ const pinAreaHandling = {
4629
4617
  for (const widget of widgets) {
4630
4618
  if (widget.is.pin || widget.is.ifName) {
4631
4619
  this.widgets.push(widget);
4632
- widget.is.selected = true;
4620
+ widget.doSelect();
4633
4621
  }
4634
4622
  }
4635
4623
 
4636
4624
  // set a rectangle around the widgets
4637
4625
  this.pinAreaRectangle();
4626
+
4627
+ // this is a widget selection
4628
+ this.what = selex.pinArea;
4638
4629
  },
4639
4630
 
4640
4631
  // the pins have been sorted in the y position
@@ -4642,7 +4633,7 @@ const pinAreaHandling = {
4642
4633
  pinAreaRectangle() {
4643
4634
 
4644
4635
  // check
4645
- if (this.widgets.length == 0) return;
4636
+ if (!this.widgets.length) return;
4646
4637
 
4647
4638
  // sort the array
4648
4639
  this.widgets.sort( (a,b) => a.rect.y - b.rect.y);
@@ -4656,12 +4647,9 @@ const pinAreaHandling = {
4656
4647
  this.activate( look.rect.x - style$1.pin.wOutside, first.y,
4657
4648
  look.rect.w + 2*style$1.pin.wOutside, last.y + last.h - first.y,
4658
4649
  style$1.selection.cRect);
4659
-
4660
- // this is a widget selection
4661
- this.what = selex.pinArea;
4662
4650
  },
4663
4651
 
4664
- pinAreaDrag(delta) {
4652
+ widgetsDrag(delta) {
4665
4653
 
4666
4654
  // check
4667
4655
  if (this.widgets.length == 0) return
@@ -4676,6 +4664,142 @@ const pinAreaHandling = {
4676
4664
  // move as required
4677
4665
  this.rect.y += delta.y;
4678
4666
  },
4667
+
4668
+ interfaceSelect(node, ifName) {
4669
+
4670
+ // reset the selection
4671
+ this.reset();
4672
+
4673
+ // find the widgets that belong to the interface
4674
+ const ifPins = node.look.getInterface(ifName);
4675
+
4676
+ // select the pins
4677
+ this.pinAreaSelect(ifPins);
4678
+
4679
+ // set the selection type
4680
+ this.what = selex.ifArea;
4681
+ },
4682
+
4683
+ extend(widget) {
4684
+
4685
+ if (this.what != selex.ifArea || widget.node != this.widgets[0].node) return
4686
+
4687
+ this.widgets.push(widget);
4688
+
4689
+ this.pinAreaRectangle();
4690
+ },
4691
+
4692
+ // adjust the selction when a widget is added
4693
+ adjustForNewWidget(widget) {
4694
+
4695
+ switch(this.what) {
4696
+
4697
+ case selex.singleNode:
4698
+
4699
+ // just switch to the new widget
4700
+ this.switchToWidget(widget);
4701
+ break;
4702
+
4703
+ case selex.ifArea:
4704
+
4705
+ if (widget.node != this.widgets[0].node) return
4706
+
4707
+ if (widget.is.pin) {
4708
+ widget.doSelect();
4709
+ this.widgets.push(widget);
4710
+ this.pinAreaRectangle();
4711
+ }
4712
+ else if (widget.is.ifName) {
4713
+
4714
+ // unddo the previous selection
4715
+ this.reset();
4716
+
4717
+ // select the new interface
4718
+ widget.doSelect();
4719
+ this.widgets = [widget];
4720
+ this.pinAreaRectangle();
4721
+ }
4722
+ break
4723
+ }
4724
+ },
4725
+
4726
+ // adjust the selction when a widget is removed
4727
+ adjustForRemovedWidget(widget) {
4728
+
4729
+ switch(this.what) {
4730
+
4731
+ case selex.singleNode:
4732
+
4733
+ // try above ...
4734
+ const above = this.widgetAbove(widget);
4735
+ if (above) return this.switchToWidget(above);
4736
+
4737
+ // if no pin is given try below
4738
+ const below = this.widgetBelow(widget);
4739
+ if (below) return this.switchToWidget(below);
4740
+ break;
4741
+
4742
+ case selex.ifArea:
4743
+
4744
+ if (widget.node != this.widgets[0].node) return
4745
+
4746
+ if (widget.is.pin) {
4747
+
4748
+ // kick the widget out
4749
+ const index = this.widgets.findIndex( w => w === widget);
4750
+ if (index != -1) this.widgets.splice(index, 1);
4751
+
4752
+ // make a new selection
4753
+ this.pinAreaRectangle();
4754
+ }
4755
+ break
4756
+ }
4757
+ },
4758
+
4759
+ behind() {
4760
+
4761
+ // check
4762
+ if (this.what !== selex.singleNode && this.what !== selex.ifArea) return null;
4763
+
4764
+ // we add new pins at the end
4765
+ const last = this.widgets.at(-1);
4766
+
4767
+ // check
4768
+ if (last) return {x: last.rect.x, y: last.rect.y + last.rect.h};
4769
+
4770
+ // it could be that the node has no pins yet !
4771
+ return this.nodes[0] ? {x: 0, y: this.nodes[0].look.makePlace(null, 0)} : null;
4772
+ },
4773
+
4774
+ whereToAdd() {
4775
+
4776
+ switch(this.what) {
4777
+
4778
+ case selex.singleNode: {
4779
+
4780
+ // get the selected node (only one !)
4781
+ const node = this.getSingleNode();
4782
+
4783
+ // get the selected widget
4784
+ const widget = this.getSelectedWidget();
4785
+
4786
+ // determine the position for the widget
4787
+ const pos = widget ? {x: widget.is.left ? widget.rect.x : widget.rect.x + widget.rect.w, y: widget.rect.y + widget.rect.h} :
4788
+ {x: 0, y: node.look.makePlace(null, 0)};
4789
+
4790
+ // done
4791
+ return [node, pos]
4792
+ }
4793
+
4794
+ case selex.ifArea: {
4795
+
4796
+ const node = this.getSelectedWidget()?.node;
4797
+ const pos = this.behind();
4798
+ return [node, pos]
4799
+ }
4800
+ }
4801
+ },
4802
+
4679
4803
  };
4680
4804
 
4681
4805
  // a constant for indicating the selection type
@@ -4683,15 +4807,15 @@ const selex = {
4683
4807
  nothing: 0,
4684
4808
  freeRect: 1,
4685
4809
  pinArea: 2,
4810
+ ifArea: 3,
4686
4811
  singleNode: 4,
4687
- multiNode: 5
4812
+ multiNode: 5,
4688
4813
  };
4689
4814
 
4690
4815
  // nodes etc. selectd in the editor
4691
- function Selection(view=null) {
4692
-
4816
+ function Selection(view = null) {
4693
4817
  // the rectangle
4694
- this.rect= {x:0, y:0, w:0, h:0};
4818
+ this.rect = { x: 0, y: 0, w: 0, h: 0 };
4695
4819
 
4696
4820
  // when selecting widgets inside a node this is where the selection started
4697
4821
  this.yWidget = 0;
@@ -4706,41 +4830,51 @@ function Selection(view=null) {
4706
4830
  this.viewPath = view ? view.getNamePath() : '';
4707
4831
 
4708
4832
  // the selected elements
4709
- this.nodes= [];
4710
- this.pads= [];
4711
- this.buses= [];
4712
- this.tacks= [];
4713
- this.widgets= [];
4833
+ this.nodes = [];
4834
+ this.pads = [];
4835
+ this.buses = [];
4836
+ this.tacks = [];
4837
+ this.widgets = [];
4714
4838
  }
4715
4839
  Selection.prototype = {
4716
-
4717
4840
  render(ctx) {
4718
-
4719
- // we only use width as a check
4720
- if (this.what === selex.freeRect || this.what === selex.pinArea) {
4721
-
4841
+ // we only use width as a check
4842
+ if (
4843
+ this.what === selex.freeRect ||
4844
+ this.what === selex.pinArea ||
4845
+ this.what === selex.ifArea
4846
+ ) {
4722
4847
  // notation
4723
4848
  const rc = this.rect;
4724
4849
 
4725
4850
  // draw the rectangle
4726
- shape.roundedRect(ctx, rc.x, rc.y, rc.w, rc.h, style$1.selection.rCorner, 1, this.color.slice(0,7), this.color );
4851
+ shape.roundedRect(
4852
+ ctx,
4853
+ rc.x,
4854
+ rc.y,
4855
+ rc.w,
4856
+ rc.h,
4857
+ style$1.selection.rCorner,
4858
+ 1,
4859
+ this.color.slice(0, 7),
4860
+ this.color
4861
+ );
4727
4862
  }
4728
4863
  },
4729
4864
 
4730
4865
  // keep viewpath and color
4731
4866
  reset() {
4732
-
4733
4867
  // not active
4734
4868
  this.what = selex.nothing;
4735
4869
 
4736
- // reset yWidget
4870
+ // reset yWidget
4737
4871
  this.yWidget = 0;
4738
4872
 
4739
4873
  // unselect the pins if any
4740
4874
  for (const pin of this.widgets) pin.unSelect();
4741
4875
 
4742
4876
  // unselect the nodes if any
4743
- for(const node of this.nodes) node.unSelect();
4877
+ for (const node of this.nodes) node.unSelect();
4744
4878
 
4745
4879
  // clear the selected objects
4746
4880
  this.nodes.length = 0;
@@ -4751,12 +4885,11 @@ Selection.prototype = {
4751
4885
  },
4752
4886
 
4753
4887
  shallowCopy() {
4754
-
4755
4888
  const selection = new Selection();
4756
4889
 
4757
- selection.rect = {...this.rect};
4890
+ selection.rect = { ...this.rect };
4758
4891
  selection.yWidget = this.yWidget;
4759
- selection.color= this.color;
4892
+ selection.color = this.color;
4760
4893
  selection.what = this.what;
4761
4894
  selection.viewPath = this.viewPath;
4762
4895
  selection.nodes = this.nodes?.slice();
@@ -4765,20 +4898,22 @@ Selection.prototype = {
4765
4898
  selection.tacks = this.tacks?.slice();
4766
4899
  selection.widgets = this.widgets?.slice();
4767
4900
 
4768
- return selection
4901
+ return selection;
4769
4902
  },
4770
4903
 
4771
4904
  canCancel(hit) {
4772
-
4773
4905
  // if we have hit a selection we cannot cancel it
4774
- // if we have not hit it we can cancel the rectangle selections
4906
+ // if we have not hit it we can cancel the rectangle selections
4775
4907
  // The single node selection is not cancelled normally
4776
4908
 
4777
- return (hit.what == zap.selection) ? false : (this.what === selex.freeRect || this.what === selex.pinArea)
4909
+ return hit.what == zap.selection
4910
+ ? false
4911
+ : this.what === selex.freeRect ||
4912
+ this.what === selex.pinArea ||
4913
+ this.what === selex.ifArea;
4778
4914
  },
4779
4915
 
4780
- setRect(x,y,w,h) {
4781
-
4916
+ setRect(x, y, w, h) {
4782
4917
  const rc = this.rect;
4783
4918
 
4784
4919
  rc.x = x;
@@ -4787,27 +4922,24 @@ Selection.prototype = {
4787
4922
  rc.h = h;
4788
4923
  },
4789
4924
 
4790
- activate(x,y,w,h, color) {
4791
-
4792
- this.setRect(x,y,w,h);
4925
+ activate(x, y, w, h, color) {
4926
+ this.setRect(x, y, w, h);
4793
4927
  if (color) this.color = color;
4794
4928
  },
4795
4929
 
4796
4930
  // start a free rectangle selection
4797
4931
  freeStart(where) {
4798
-
4799
4932
  // reset the current selection
4800
4933
  this.reset();
4801
4934
 
4802
4935
  // free rectangle selection
4803
4936
  this.what = selex.freeRect;
4804
-
4937
+
4805
4938
  // set the x and y value for the selection rectangle
4806
4939
  this.setRect(where.x, where.y, 0, 0);
4807
4940
  },
4808
4941
 
4809
4942
  singleNode(node) {
4810
-
4811
4943
  // unselect other - if any
4812
4944
  this.reset();
4813
4945
 
@@ -4822,7 +4954,6 @@ Selection.prototype = {
4822
4954
  },
4823
4955
 
4824
4956
  singleNodeAndWidget(node, pin) {
4825
-
4826
4957
  // unselect
4827
4958
  this.reset();
4828
4959
 
@@ -4832,18 +4963,16 @@ Selection.prototype = {
4832
4963
  pin.doSelect();
4833
4964
  },
4834
4965
 
4835
- // extend an existing selection
4966
+ // extend an existing selection
4836
4967
  extend(node) {
4837
-
4838
4968
  // if there are no nodes this is the first selection
4839
- if (this.nodes.length <1) {
4969
+ if (this.nodes.length < 1) {
4840
4970
  this.singleNode(node);
4841
- return
4971
+ return;
4842
4972
  }
4843
4973
 
4844
4974
  // if the node is selected - unselect
4845
4975
  if (this.nodes.includes(node)) {
4846
-
4847
4976
  // remove the node from the array
4848
4977
  eject(this.nodes, node);
4849
4978
 
@@ -4851,7 +4980,7 @@ Selection.prototype = {
4851
4980
  node.unSelect();
4852
4981
 
4853
4982
  // done
4854
- return
4983
+ return;
4855
4984
  }
4856
4985
 
4857
4986
  // save the node
@@ -4866,90 +4995,91 @@ Selection.prototype = {
4866
4995
 
4867
4996
  // get the single selected node
4868
4997
  getSingleNode() {
4869
- return this.what == selex.singleNode ? this.nodes[0] : null
4998
+ return this.what == selex.singleNode ? this.nodes[0] : null;
4870
4999
  },
4871
5000
 
4872
5001
  getSelectedWidget() {
4873
- return this.what == selex.singleNode ? this.widgets[0] : null
5002
+ if (this.what == selex.singleNode) return this.widgets[0];
5003
+ if (this.what === selex.ifArea) return this.widgets[0];
5004
+ return null;
4874
5005
  },
4875
5006
 
4876
5007
  getPinAreaNode() {
4877
- return ((this.what == selex.pinArea) && this.widgets[0]) ? this.widgets[0].node : null
5008
+ return (this.what === selex.pinArea || this.what === selex.ifArea) &&
5009
+ this.widgets[0]
5010
+ ? this.widgets[0].node
5011
+ : null;
4878
5012
  },
4879
5013
 
4880
- // switch the selected widget
4881
- switchWidget(pin) {
4882
-
4883
- if (pin) {
4884
- this.widgets[0]?.unSelect();
4885
- pin.doSelect();
4886
- this.widgets[0] = pin;
4887
- return
4888
- }
4889
-
4890
- // if no pin is given try below
4891
- const below = this.widgetBelow();
4892
- if (below) return this.switchWidget(below)
5014
+ // switch to the selected widget
5015
+ switchToWidget(pin) {
4893
5016
 
4894
- // try above ...
4895
- const above = this.widgetAbove();
4896
- if (above) return this.switchWidget(above)
4897
- },
5017
+ if (!pin) return;
4898
5018
 
4899
- widgetBelow() {
5019
+ // unselect the current
5020
+ this.widgets[0]?.unSelect();
4900
5021
 
4901
- // get node and widget
4902
- const [node, current] = (this.what != selex.singleNode) ? [null, null] : [this.nodes[0], this.widgets[0]];
5022
+ // select the new one
5023
+ pin.doSelect();
5024
+ this.widgets[0] = pin;
5025
+ return;
5026
+ },
4903
5027
 
4904
- // check
4905
- if (!current || !node) return null
5028
+ widgetBelow(current) {
4906
5029
 
4907
5030
  let below = null;
4908
- for(const widget of node.look.widgets) {
4909
-
4910
- if ((widget.is.pin || widget.is.ifName) &&
4911
- (widget.rect.y > current.rect.y) &&
4912
- (!below || (widget.rect.y < below.rect.y))) below = widget;
5031
+ for (const widget of current.node.look.widgets) {
5032
+ if ((widget.is.pin || widget.is.ifName) && widget.rect.y > current.rect.y && (!below || widget.rect.y < below.rect.y)) below = widget;
4913
5033
  }
4914
5034
 
4915
5035
  // done
4916
- return below
5036
+ return below;
4917
5037
  },
4918
5038
 
4919
- widgetAbove() {
4920
-
4921
- // get node and widget
4922
- const [node, current] = (this.what != selex.singleNode) ? [null, null] : [this.nodes[0], this.widgets[0]];
4923
-
4924
- // check
4925
- if (!current || !node) return null
5039
+ widgetAbove(current) {
4926
5040
 
4927
5041
  let above = null;
4928
- for(const widget of node.look.widgets) {
4929
-
4930
- if ((widget.is.pin || widget.is.ifName) &&
4931
- (widget.rect.y < current.rect.y) &&
4932
- (!above || (widget.rect.y > above.rect.y))) above = widget;
5042
+ for (const widget of current.node.look.widgets) {
5043
+ if ((widget.is.pin || widget.is.ifName) && widget.rect.y < current.rect.y && (!above || widget.rect.y > above.rect.y)) above = widget;
4933
5044
  }
4934
5045
 
4935
5046
  // done
4936
- return above
5047
+ return above;
4937
5048
  },
4938
5049
 
4939
5050
  // check if we have hit the selection
4940
5051
  hitTest(xyLocal) {
4941
-
4942
5052
  // If there is a rectangle, we have a simple criterion
4943
- if ((this.what == selex.freeRect || this.what == selex.pinArea) && inside(xyLocal, this.rect)) return [zap.selection, this, null]
5053
+ if (
5054
+ (this.what == selex.freeRect ||
5055
+ this.what == selex.pinArea ||
5056
+ this.what == selex.ifArea) &&
5057
+ inside(xyLocal, this.rect)
5058
+ )
5059
+ return [zap.selection, this, null];
4944
5060
 
4945
5061
  // multi-node or single node
4946
5062
  // search the nodes (in reverse - visible node on top of another will be found first)
4947
- for (let i = this.nodes.length-1; i>=0; i--) {
4948
- if (inside(xyLocal, this.nodes[i].look.rect)) return [zap.selection, this, this.nodes[i]]
5063
+ for (let i = this.nodes.length - 1; i >= 0; i--) {
5064
+ if (inside(xyLocal, this.nodes[i].look.rect))
5065
+ return [zap.selection, this, this.nodes[i]];
4949
5066
  }
4950
5067
 
4951
- // nothing
4952
- return [zap.nothing, null, null]
5068
+ // nothing
5069
+ return [zap.nothing, null, null];
5070
+ },
5071
+
5072
+ widgetHit(xyLocal) {
5073
+ if (!this.widgets?.length) return null;
5074
+
5075
+ for (const widget of this.widgets) {
5076
+ if (
5077
+ xyLocal.y > widget.rect.y &&
5078
+ xyLocal.y < widget.rect.y + widget.rect.h
5079
+ )
5080
+ return widget;
5081
+ }
5082
+ return null;
4953
5083
  },
4954
5084
 
4955
5085
  setColor(color) {
@@ -4968,11 +5098,10 @@ Selection.prototype = {
4968
5098
  },
4969
5099
 
4970
5100
  drag(delta) {
5101
+ // *1* move
4971
5102
 
4972
- // *1* move
4973
-
4974
- // move the nodes in the selection
4975
- for( const node of this.nodes) node.look.moveDelta(delta.x, delta.y);
5103
+ // move the nodes in the selection
5104
+ for (const node of this.nodes) node.look.moveDelta(delta.x, delta.y);
4976
5105
 
4977
5106
  // also move the pads
4978
5107
  for (const pad of this.pads) pad.move(delta);
@@ -4980,24 +5109,21 @@ Selection.prototype = {
4980
5109
  // move the buses if there are nodes in the selection
4981
5110
  if (this.nodes.length > 0)
4982
5111
  for (const bus of this.buses) bus.move(delta.x, delta.y);
4983
-
4984
- // or otherwise just the bus tacks
4985
- else
4986
- for (const tack of this.tacks) tack.slide(delta);
5112
+ // or otherwise just the bus tacks
5113
+ else for (const tack of this.tacks) tack.slide(delta);
4987
5114
 
4988
5115
  // move the routes that have start end end points in the selection
4989
-
4990
5116
 
4991
5117
  // *2* Route adjustments
4992
5118
 
4993
5119
  // now we adjust the end points of the routes again
4994
- for( const node of this.nodes) node.look.adjustRoutes();
5120
+ for (const node of this.nodes) node.look.adjustRoutes();
4995
5121
 
4996
5122
  // adjust the routes for the pads
4997
- for(const pad of this.pads) pad.adjustRoutes();
5123
+ for (const pad of this.pads) pad.adjustRoutes();
4998
5124
 
4999
5125
  // also for the buses
5000
- for (const bus of this.buses) bus.adjustRoutes();
5126
+ for (const bus of this.buses) bus.adjustRoutes();
5001
5127
 
5002
5128
  // *3* move the selection rectangle
5003
5129
 
@@ -5005,55 +5131,37 @@ Selection.prototype = {
5005
5131
  this.rect.y += delta.y;
5006
5132
  },
5007
5133
 
5008
- // shallowCopy() {
5009
-
5010
- // const slct = new Selection()
5011
-
5012
- // // make a shallow copy of the nodes etc
5013
- // for (const node of this.nodes) slct.nodes.push(node)
5014
- // for (const bus of this.buses) slct.buses.push(bus)
5015
- // for (const pad of this.pads) slct.pads.push(pad)
5016
- // for (const pin of this.widgets) slct.widgets.push(pin)
5017
- // for (const tack of this.tacks) slct.tacks.push(tack)
5018
-
5019
- // // make a real copy of the rect
5020
- // slct.rect = {...this.rect}
5021
-
5022
- // // copy the color
5023
- // slct.color = this.color
5024
-
5025
- // return slct
5026
- // },
5027
-
5028
5134
  // return the top left node in the selection
5029
5135
  topLeftNode() {
5030
-
5031
- if (this.nodes.length == 0) return null
5136
+ if (this.nodes.length == 0) return null;
5032
5137
 
5033
5138
  let topleft = this.nodes[0];
5034
5139
 
5035
- for(const node of this.nodes) {
5036
-
5037
- if ((node.look.rect.y < topleft.look.rect.y) && (node.look.rect.x < topleft.look.rect.x)) topleft = node;
5140
+ for (const node of this.nodes) {
5141
+ if (
5142
+ node.look.rect.y < topleft.look.rect.y &&
5143
+ node.look.rect.x < topleft.look.rect.x
5144
+ )
5145
+ topleft = node;
5038
5146
  }
5039
5147
 
5040
- return topleft
5148
+ return topleft;
5041
5149
  },
5042
5150
 
5043
5151
  // make the view wider then the selection because of the added pads
5044
5152
  makeViewRect() {
5045
-
5046
5153
  const rc = this.rect;
5047
5154
 
5048
- return {x: rc.x - style$1.view.wExtra,
5049
- y: rc.y - style$1.view.hExtra,
5050
- w: rc.w + 2*style$1.view.wExtra,
5051
- h: rc.h + 2*style$1.view.hExtra}
5155
+ return {
5156
+ x: rc.x - style$1.view.wExtra,
5157
+ y: rc.y - style$1.view.hExtra,
5158
+ w: rc.w + 2 * style$1.view.wExtra,
5159
+ h: rc.h + 2 * style$1.view.hExtra,
5160
+ };
5052
5161
  },
5053
5162
 
5054
- // position the new group look as close as possible to the top left node
5163
+ // position the new group look as close as possible to the top left node
5055
5164
  makeLookRect() {
5056
-
5057
5165
  const topleft = this.topLeftNode();
5058
5166
  const rcSel = this.rect;
5059
5167
 
@@ -5061,17 +5169,14 @@ Selection.prototype = {
5061
5169
  const y = topleft ? topleft.look.rect.y : rcSel.y;
5062
5170
 
5063
5171
  // leave w and h at 0
5064
- return {x,y,w:0,h:0}
5172
+ return { x, y, w: 0, h: 0 };
5065
5173
  },
5066
5174
 
5067
5175
  adjustPaths(ref) {
5068
-
5069
- if (!this.nodes) return
5176
+ if (!this.nodes) return;
5070
5177
 
5071
5178
  for (const node of this.nodes) node.adjustPaths(ref);
5072
5179
  },
5073
-
5074
-
5075
5180
  };
5076
5181
  Object.assign(Selection.prototype, pinAreaHandling);
5077
5182
 
@@ -5152,12 +5257,13 @@ const mouseMoveHandling = {
5152
5257
  state.lookWidget.drag(xyLocal);
5153
5258
  return true
5154
5259
 
5260
+ // OBSOLETE
5155
5261
  case doing.pinAreaDrag:
5156
5262
  // move the rectangle
5157
- this.selection.pinAreaDrag(dxdyLocal);
5263
+ // this.selection.pinAreaDrag(dxdyLocal)
5158
5264
 
5159
5265
  // move the pins
5160
- this.selection.getPinAreaNode().look.dragPinArea(this.selection.widgets, this.selection.rect);
5266
+ // this.selection.getPinAreaNode().look.dragPinArea(this.selection.widgets, this.selection.rect)
5161
5267
  return true
5162
5268
 
5163
5269
  case doing.interfaceNameDrag:
@@ -5167,7 +5273,7 @@ const mouseMoveHandling = {
5167
5273
  case doing.interfaceDrag:
5168
5274
 
5169
5275
  // move the rectangle
5170
- this.selection.pinAreaDrag(dxdyLocal);
5276
+ this.selection.widgetsDrag(dxdyLocal);
5171
5277
 
5172
5278
  // swap the widgets if necessary
5173
5279
  this.selection.widgets[0].node.look.swapInterface(xyLocal, this.selection.widgets);
@@ -5268,7 +5374,7 @@ const mouseMoveHandling = {
5268
5374
  if ( inside(xyLocal, this.selection.widgets[0].rect)) return false;
5269
5375
 
5270
5376
  // moving: unselect the node
5271
- this.selection.nodes[0].unSelect();
5377
+ //this.selection.nodes[0].unSelect()
5272
5378
 
5273
5379
  // // set a selection rectangle around the selected pins
5274
5380
  // this.selection.pinAreaRectangle()
@@ -5483,8 +5589,8 @@ const mouseDownHandling = {
5483
5589
 
5484
5590
  case NONE:{
5485
5591
 
5486
- // set the node as selected
5487
- this.selection.singleNodeAndWidget(hit.node, hit.lookWidget);
5592
+ // we select the entire interface here
5593
+ this.selection.interfaceSelect(hit.node,hit.lookWidget);
5488
5594
 
5489
5595
  // highlight the ifName group
5490
5596
  this.selection.widgets = hit.node.look.highLightInterface(hit.lookWidget);
@@ -5747,6 +5853,35 @@ const mouseDownHandling = {
5747
5853
  // drag the whole selection
5748
5854
  editor.doEdit('selectionDrag', {view: this});
5749
5855
  this.stateSwitch(doing.selectionDrag);
5856
+ }
5857
+ else if (this.selection.what === selex.ifArea) {
5858
+
5859
+ // check the widget that was hit
5860
+ const widget = this.selection.widgetHit(xyLocal);
5861
+
5862
+ if (!widget) return
5863
+
5864
+ if (widget.is.ifName) {
5865
+ // highlight the ifName group
5866
+ this.selection.widgets = widget.node.look.highLightInterface(widget);
5867
+
5868
+ // state switch
5869
+ this.stateSwitch(doing.interfaceNameClicked);
5870
+ }
5871
+ else {
5872
+ // save the widget & node
5873
+ state.lookWidget = widget;
5874
+ state.node = widget.node;
5875
+
5876
+ // and highlight the routes
5877
+ widget.highLightRoutes();
5878
+
5879
+ // new state
5880
+ this.stateSwitch(doing.pinClicked);
5881
+
5882
+ // set the node and pin as selected
5883
+ this.selection.singleNodeAndWidget(widget.node, widget);
5884
+ }
5750
5885
  }
5751
5886
  }
5752
5887
  break
@@ -5764,7 +5899,7 @@ const mouseDownHandling = {
5764
5899
  // first switch the state - might end the previous selection !
5765
5900
  this.stateSwitch(doing.pinAreaSelect);
5766
5901
  }
5767
- else if (this.selection.what == selex.pinArea) {
5902
+ else if (this.selection.what === selex.pinArea || this.selection.what === selex.ifArea) {
5768
5903
 
5769
5904
  // ..and only then start a new selection
5770
5905
  this.selection.pinAreaStart(this.selection.getPinAreaNode(), xyLocal);
@@ -5793,19 +5928,47 @@ const mouseDownHandling = {
5793
5928
 
5794
5929
  break;
5795
5930
 
5796
- case selex.pinArea:
5797
-
5931
+ case selex.ifArea:
5798
5932
  // set state to drag the pin/proxy up and down
5799
- this.stateSwitch(doing.pinAreaDrag);
5933
+ this.stateSwitch(doing.interfaceDrag);
5800
5934
 
5801
- // save the edit - the view contains the selection
5802
- editor.doEdit('pinAreaDrag', this);
5935
+ // notation
5936
+ const pins = this.selection.widgets;
5803
5937
 
5938
+ // drag the area
5939
+ editor.doEdit('interfaceDrag',{ group: pins.slice(), oldY: pins[0].rect.y, newY: pins[0].rect.y});
5804
5940
  break;
5805
5941
  }
5806
5942
 
5807
5943
  }
5808
5944
  break
5945
+
5946
+ case CTRL|SHIFT:{
5947
+
5948
+ if (this.selection.what == selex.ifArea) {
5949
+
5950
+ // check the widget that was hit
5951
+ const widget = this.selection.widgetHit(xyLocal);
5952
+
5953
+ if (!widget) return
5954
+
5955
+ if (widget.is.ifName) {
5956
+
5957
+ // Save the edit
5958
+ editor.doEdit('interfaceNameDrag',{ifName: widget});
5959
+
5960
+ // save the widget
5961
+ this.state.lookWidget = hit.lookWidget;
5962
+
5963
+ // set the node as selected
5964
+ this.selection.singleNodeAndWidget(widget.node, widget);
5965
+
5966
+ // switch to dragging the ifName
5967
+ this.stateSwitch(doing.interfaceNameDrag);
5968
+ }
5969
+ }
5970
+ }
5971
+ break
5809
5972
  }
5810
5973
  }
5811
5974
  break
@@ -6058,8 +6221,11 @@ const mouseUpHandling = {
6058
6221
  //this.state.bus.fuseSegment(this.state.busSegment)
6059
6222
  this.state.bus.is.selected = false;
6060
6223
 
6061
- // adjust the parameters for the undo operation
6062
- undo = editor.getParam();
6224
+ // remove highlight
6225
+ this.state.bus.unHighLight();
6226
+
6227
+ // adjust the parameters for the undo operation
6228
+ undo = editor.getParam();
6063
6229
  undo.newWire = this.state.bus.copyWire();
6064
6230
  undo.newTackWires = this.state.bus.copyTackWires();
6065
6231
  break
@@ -6106,8 +6272,9 @@ const mouseUpHandling = {
6106
6272
  editor.getParam().newPos = {left: pin.is.left, y: pin.rect.y};
6107
6273
  break
6108
6274
 
6275
+ // OBSOLETE
6109
6276
  case doing.pinAreaDrag:
6110
- editor.getParam().newY = this.selection.widgets[0].rect.y;
6277
+ // editor.getParam().newY = this.selection.widgets[0].rect.y
6111
6278
  break
6112
6279
 
6113
6280
  case doing.interfaceNameDrag: {
@@ -6273,7 +6440,7 @@ const nodeCxMenu = {
6273
6440
  node:null,
6274
6441
  xyLocal: null,
6275
6442
 
6276
- // prepres the menu list before showing it
6443
+ // prepare the menu list before showing it
6277
6444
  prepare(view) {
6278
6445
 
6279
6446
  this.view = view;
@@ -6364,43 +6531,332 @@ function unGroup() {
6364
6531
  editor.doEdit('unGroup', {view: nodeCxMenu.view, node: nodeCxMenu.node});
6365
6532
  }
6366
6533
 
6534
+ const noLink$1 = [
6535
+ {
6536
+ text: 'new output',
6537
+ char: 'o',
6538
+ icon: 'logout',
6539
+ state: 'enabled',
6540
+ action: newOutput$1,
6541
+ },
6542
+ {
6543
+ text: 'new input',
6544
+ char: 'i',
6545
+ icon: 'login',
6546
+ state: 'enabled',
6547
+ action: newInput$1,
6548
+ },
6549
+ {
6550
+ text: 'new interface',
6551
+ char: 'p',
6552
+ icon: 'drag_handle',
6553
+ state: 'enabled',
6554
+ action: newInterfaceName$1,
6555
+ },
6556
+ {
6557
+ text: 'new request',
6558
+ char: 'q',
6559
+ icon: 'switch_left',
6560
+ state: 'enabled',
6561
+ action: newRequest$1,
6562
+ },
6563
+ {
6564
+ text: 'new reply',
6565
+ char: 'r',
6566
+ icon: 'switch_right',
6567
+ state: 'enabled',
6568
+ action: newReply$1,
6569
+ },
6570
+ {
6571
+ text: 'in/out switch',
6572
+ icon: 'cached',
6573
+ state: 'disabled',
6574
+ action: inOutSwitch$1,
6575
+ },
6576
+ {
6577
+ text: 'add channel',
6578
+ icon: 'adjust',
6579
+ state: 'disabled',
6580
+ action: channelOnOff,
6581
+ },
6582
+ {
6583
+ text: 'paste pins',
6584
+ char: 'ctrl v',
6585
+ icon: 'content_copy',
6586
+ state: 'enabled',
6587
+ action: pasteWidgetsFromClipboard,
6588
+ },
6589
+ { text: 'profile', icon: 'info', state: 'disabled', action: showProfile },
6590
+ {
6591
+ text: 'all pins swap left right',
6592
+ icon: 'swap_horiz',
6593
+ state: 'enabled',
6594
+ action: pinsSwap$1,
6595
+ },
6596
+ {
6597
+ text: 'all pins left',
6598
+ icon: 'arrow_back',
6599
+ state: 'enabled',
6600
+ action: pinsLeft$1,
6601
+ },
6602
+ {
6603
+ text: 'all pins right',
6604
+ icon: 'arrow_forward',
6605
+ state: 'enabled',
6606
+ action: pinsRight$1,
6607
+ },
6608
+ {
6609
+ text: 'disconnect',
6610
+ icon: 'power_off',
6611
+ state: 'disabled',
6612
+ action: disconnectPin,
6613
+ },
6614
+ { text: 'delete', icon: 'delete', state: 'enabled', action: deletePin },
6615
+ ];
6616
+
6617
+ const withLink$1 = [
6618
+ { text: 'profile', icon: 'info', state: 'disabled', action: showProfile },
6619
+ {
6620
+ text: 'all pins swap left right',
6621
+ icon: 'swap_horiz',
6622
+ state: 'enabled',
6623
+ action: pinsSwap$1,
6624
+ },
6625
+ {
6626
+ text: 'all pins left',
6627
+ icon: 'arrow_back',
6628
+ state: 'enabled',
6629
+ action: pinsLeft$1,
6630
+ },
6631
+ {
6632
+ text: 'all pins right',
6633
+ icon: 'arrow_forward',
6634
+ state: 'enabled',
6635
+ action: pinsRight$1,
6636
+ },
6637
+ {
6638
+ text: 'disconnect',
6639
+ icon: 'power_off',
6640
+ state: 'disabled',
6641
+ action: disconnectPin,
6642
+ },
6643
+ ];
6644
+
6645
+ // click on the node
6646
+ const pinCxMenu = {
6647
+ choices: null,
6648
+
6649
+ view: null,
6650
+ node: null,
6651
+ widget: null,
6652
+ xyLocal: null,
6653
+ xyScreen: null,
6654
+
6655
+ // a specific function to turn on/off the options of the right click menu
6656
+ prepare(view) {
6657
+ this.view = view;
6658
+ this.node = view.hit.node;
6659
+ this.widget = view.hit.lookWidget;
6660
+ this.xyLocal = view.hit.xyLocal;
6661
+ this.xyScreen = view.hit.xyScreen;
6662
+
6663
+ // linked nodes hve much less options
6664
+ if (this.node.link) {
6665
+ // The number of options is reduced
6666
+ this.choices = withLink$1;
6667
+
6668
+ // only pins can be disconnected
6669
+ let entry = this.choices.find((c) => c.action == disconnectPin);
6670
+ entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6671
+
6672
+ // profiles are only available for pins
6673
+ entry = this.choices.find((c) => c.action == showProfile);
6674
+ entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6675
+
6676
+ return;
6677
+ }
6678
+
6679
+ this.choices = noLink$1;
6680
+
6681
+ // only pins can be disconnected
6682
+ let entry = this.choices.find((c) => c.action == disconnectPin);
6683
+ entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6684
+
6685
+ // swap input to output
6686
+ entry = this.choices.find((c) => c.action == inOutSwitch$1);
6687
+ let enable = this.widget?.is.pin && this.widget.routes.length == 0;
6688
+ entry.state = enable ? 'enabled' : 'disabled';
6689
+ entry.text =
6690
+ enable && this.widget.is.input
6691
+ ? 'change to output'
6692
+ : 'change to input';
6693
+
6694
+ // switch channel on or off
6695
+ entry = this.choices.find((c) => c.action == channelOnOff);
6696
+ enable = this.widget?.is.pin; // && ! this.widget.is.proxy
6697
+ entry.state = enable ? 'enabled' : 'disabled';
6698
+ entry.text =
6699
+ enable && this.widget.is.channel ? 'remove channel' : 'add channel';
6700
+
6701
+ // profiles are only available for pins
6702
+ entry = this.choices.find((c) => c.action == showProfile);
6703
+ entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6704
+
6705
+ // switch the delete action
6706
+ entry = this.choices.find((c) => c.text == 'delete');
6707
+ entry.action = this.widget?.is.pin
6708
+ ? deletePin
6709
+ : this.widget?.is.ifName
6710
+ ? deleteInterfaceName
6711
+ : () => {};
6712
+
6713
+ // check if there are pins to paste
6714
+ entry = this.choices.find((c) => c.text == 'paste pins');
6715
+ },
6716
+ };
6717
+
6718
+ // is = {channel, input, request, proxy}
6719
+ function newInput$1() {
6720
+ // set the flags
6721
+ const is = { channel: false, input: true, proxy: pinCxMenu.node.is.group };
6722
+ editor.doEdit('newPin', {
6723
+ view: pinCxMenu.view,
6724
+ node: pinCxMenu.node,
6725
+ pos: pinCxMenu.xyLocal,
6726
+ is,
6727
+ });
6728
+ }
6729
+ function newOutput$1() {
6730
+ // set the flags
6731
+ const is = { channel: false, input: false, proxy: pinCxMenu.node.is.group };
6732
+ editor.doEdit('newPin', {
6733
+ view: pinCxMenu.view,
6734
+ node: pinCxMenu.node,
6735
+ pos: pinCxMenu.xyLocal,
6736
+ is,
6737
+ });
6738
+ }
6739
+ function newRequest$1() {
6740
+ // set the flags
6741
+ const is = { channel: true, input: false, proxy: pinCxMenu.node.is.group };
6742
+ editor.doEdit('newPin', {
6743
+ view: pinCxMenu.view,
6744
+ node: pinCxMenu.node,
6745
+ pos: pinCxMenu.xyLocal,
6746
+ is,
6747
+ });
6748
+ }
6749
+ function newReply$1() {
6750
+ // set the flags
6751
+ const is = { channel: true, input: true, proxy: pinCxMenu.node.is.group };
6752
+ editor.doEdit('newPin', {
6753
+ view: pinCxMenu.view,
6754
+ node: pinCxMenu.node,
6755
+ pos: pinCxMenu.xyLocal,
6756
+ is,
6757
+ });
6758
+ }
6759
+ function inOutSwitch$1() {
6760
+ editor.doEdit('ioSwitch', { pin: pinCxMenu.widget });
6761
+ }
6762
+ function channelOnOff() {
6763
+ editor.doEdit('channelOnOff', { pin: pinCxMenu.widget });
6764
+ }
6765
+ function disconnectPin() {
6766
+ editor.doEdit('disconnectPin', { pin: pinCxMenu.widget });
6767
+ }
6768
+ function deletePin() {
6769
+ editor.doEdit('deletePin', { view: pinCxMenu.view, pin: pinCxMenu.widget });
6770
+ }
6771
+ function newInterfaceName$1() {
6772
+ editor.doEdit('newInterfaceName', {
6773
+ view: pinCxMenu.view,
6774
+ node: pinCxMenu.node,
6775
+ pos: pinCxMenu.xyLocal,
6776
+ });
6777
+ }
6778
+ function deleteInterfaceName() {
6779
+ editor.doEdit('deleteInterfaceName', {
6780
+ view: pinCxMenu.view,
6781
+ ifName: pinCxMenu.widget,
6782
+ });
6783
+ }
6784
+ function showProfile(e) {
6785
+ editor.doEdit('showProfile', {
6786
+ pin: pinCxMenu.widget,
6787
+ pos: { x: pinCxMenu.xyScreen.x, y: pinCxMenu.xyScreen.y + 10 },
6788
+ });
6789
+ }
6790
+
6791
+ function pinsSwap$1() {
6792
+ editor.doEdit('swapPins', {
6793
+ node: pinCxMenu.node,
6794
+ left: true,
6795
+ right: true,
6796
+ });
6797
+ }
6798
+
6799
+ function pinsLeft$1() {
6800
+ editor.doEdit('swapPins', {
6801
+ node: pinCxMenu.node,
6802
+ left: true,
6803
+ right: false,
6804
+ });
6805
+ }
6806
+ function pinsRight$1() {
6807
+ editor.doEdit('swapPins', {
6808
+ node: pinCxMenu.node,
6809
+ left: false,
6810
+ right: true,
6811
+ });
6812
+ }
6813
+ function pasteWidgetsFromClipboard() {
6814
+ // request the clipboard - also set the target, the clipboard can come from another file
6815
+ editor.tx.request('clipboard get', editor.doc).then((clipboard) => {
6816
+ editor.doEdit('pasteWidgetsFromClipboard', {
6817
+ view: pinCxMenu.view,
6818
+ clipboard,
6819
+ });
6820
+ });
6821
+ //.catch( error => console.log('paste: clipboard get error -> ' + error))
6822
+ }
6823
+
6824
+ const withLink = [
6825
+
6826
+ {text:"left/right swap", icon:"swap_horiz",state:"enabled", action:ifPinsSwap},
6827
+ {text:"all pins left", icon:"arrow_back",state:"enabled", action:ifPinsLeft},
6828
+ {text:"all pins right", icon:"arrow_forward",state:"enabled", action:ifPinsRight},
6829
+ {text:"copy interface", char:'ctrl c',icon:"content_copy",state:"enabled", action:ifToClipboard},
6830
+ {text:"disconnect", icon:"power_off",state:"enabled", action:ifDisconnect},
6831
+ ];
6832
+
6367
6833
  const noLink = [
6368
6834
 
6369
6835
  {text:"new output", char:'o', icon:"logout",state:"enabled", action:newOutput},
6370
6836
  {text:"new input", char:'i', icon:"login",state:"enabled", action:newInput},
6371
- {text:"new ifName", char:'p', icon:"drag_handle",state:"enabled", action:newInterfaceName},
6837
+ {text:"new interface", char:'p', icon:"drag_handle",state:"enabled", action:newInterfaceName},
6372
6838
  {text:"new request", char:'q', icon:"switch_left",state:"enabled", action:newRequest},
6373
6839
  {text:"new reply", char:'r', icon:"switch_right",state:"enabled", action:newReply},
6374
- {text:"change to output", icon:"cached",state:"disabled", action:inOutSwap},
6375
- {text:"add channel", icon:"adjust",state:"disabled", action:channelOnOff},
6376
- {text:"paste pins", char:'ctrl v',icon:"content_copy",state:"enabled", action:pasteWidgetsFromClipboard},
6377
- {text:"profile", icon:"info",state:"disabled", action:showProfile},
6378
- {text:"all pins swap left right", icon:"swap_horiz",state:"enabled", action:pinsSwap$1},
6379
- {text:"all pins left", icon:"arrow_back",state:"enabled", action:pinsLeft$1},
6380
- {text:"all pins right", icon:"arrow_forward",state:"enabled", action:pinsRight$1},
6381
- {text:"disconnect", icon:"power_off",state:"disabled", action:disconnectPin},
6382
- {text:"delete", icon:"delete",state:"enabled", action:deletePin},
6383
-
6384
- ];
6385
6840
 
6386
- const withLink = [
6387
-
6388
- {text:"profile", icon:"info",state:"disabled", action:showProfile},
6389
- {text:"all pins swap left right", icon:"swap_horiz",state:"enabled", action:pinsSwap$1},
6390
- {text:"all pins left", icon:"arrow_back",state:"enabled", action:pinsLeft$1},
6391
- {text:"all pins right", icon:"arrow_forward",state:"enabled", action:pinsRight$1},
6392
- {text:"disconnect", icon:"power_off",state:"disabled", action:disconnectPin},
6841
+ {text:"left/right swap", icon:"swap_horiz",state:"enabled", action:ifPinsSwap},
6842
+ {text:"all pins left", icon:"arrow_back",state:"enabled", action:ifPinsLeft},
6843
+ {text:"all pins right", icon:"arrow_forward",state:"enabled", action:ifPinsRight},
6844
+ {text:"i/o swicth", icon:"cached",state:"enabled", action:ioSwitch},
6393
6845
 
6846
+ {text:"copy interface", char:'ctrl c',icon:"content_copy",state:"enabled", action:ifToClipboard},
6847
+ {text:"paste pins", char:'ctrl v',icon:"content_copy",state:"enabled", action:pastePinsFromClipboard},
6848
+ {text:"disconnect", icon:"power_off",state:"enabled", action:ifDisconnect},
6849
+ {text:"delete", icon:"delete",state:"enabled", action:ifDelete},
6394
6850
  ];
6395
6851
 
6396
6852
  // click on the node
6397
- const pinAreaCxMenu = {
6853
+ const ifCxMenu = {
6398
6854
 
6399
6855
  choices: null,
6400
6856
 
6401
6857
  view: null,
6402
6858
  node: null,
6403
- widget: null,
6859
+ ifWidget: null,
6404
6860
  xyLocal: null,
6405
6861
  xyScreen: null,
6406
6862
 
@@ -6408,135 +6864,97 @@ const pinAreaCxMenu = {
6408
6864
  prepare(view) {
6409
6865
 
6410
6866
  this.view = view;
6411
- this.node = view.hit.node;
6412
- this.widget = view.hit.lookWidget;
6413
- this.xyLocal = view.hit.xyLocal;
6414
- this.xyScreen = view.hit.xyScreen;
6415
-
6416
- // linked nodes hve much less options
6417
- if (this.node.link) {
6418
-
6419
- // The number of options is reduced
6420
- this.choices = withLink;
6421
6867
 
6422
- // only pins can be disconnected
6423
- let entry = this.choices.find( c => c.action == disconnectPin);
6424
- entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6868
+ // Get the data from the selection !
6869
+ if (view.selection.what == selex.ifArea) {
6425
6870
 
6426
- // profiles are only available for pins
6427
- entry = this.choices.find( c => c.action == showProfile);
6428
- entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6871
+ // check - should never fail
6872
+ const ifWidget = view.selection.widgets[0];
6873
+ if (!ifWidget?.is.ifName) return;
6429
6874
 
6430
- return
6875
+ this.node = ifWidget.node;
6876
+ this.ifWidget = ifWidget;
6877
+ this.xyLocal = view.hit.xyLocal;
6878
+ this.xyScreen = view.hit.xyScreen;
6879
+ }
6880
+ // get the data from the view hit
6881
+ else {
6882
+ this.node = view.hit.node;
6883
+ this.ifWidget = view.hit.lookWidget;
6884
+ this.xyLocal = view.hit.xyLocal;
6885
+ this.xyScreen = view.hit.xyScreen;
6431
6886
  }
6432
-
6433
- this.choices = noLink;
6434
-
6435
- // only pins can be disconnected
6436
- let entry = this.choices.find( c => c.action == disconnectPin);
6437
- entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6438
-
6439
- // swap input to output
6440
- entry = this.choices.find(c => c.action == inOutSwap);
6441
- let enable = this.widget?.is.pin && this.widget.routes.length == 0;
6442
- entry.state = enable ? "enabled" : "disabled";
6443
- entry.text = (enable && this.widget.is.input ) ? "change to output" : "change to input";
6444
-
6445
- // switch channel on or off
6446
- entry = this.choices.find(c => c.action == channelOnOff);
6447
- enable = this.widget?.is.pin; // && ! this.widget.is.proxy
6448
- entry.state = enable ? "enabled" : "disabled";
6449
- entry.text = (enable && this.widget.is.channel ) ? "remove channel" : "add channel";
6450
-
6451
- // profiles are only available for pins
6452
- entry = this.choices.find( c => c.action == showProfile);
6453
- entry.state = this.widget?.is.pin ? 'enabled' : 'disabled';
6454
6887
 
6455
- // switch the delete action
6456
- entry = this.choices.find( c => c.text == "delete");
6457
- entry.action = this.widget?.is.pin ? deletePin : this.widget?.is.ifName ? deleteInterfaceName : ()=>{};
6888
+ // set the options
6889
+ this.choices = this.node.link ? withLink : noLink;
6458
6890
 
6459
6891
  // check if there are pins to paste
6460
- entry = this.choices.find( c => c.text == "paste pins");
6461
- },
6892
+ const entry = this.choices.find( c => c.text == "paste pins");
6893
+ if (entry) {
6894
+ entry.state = "disabled";
6895
+ editor.tx.request('clipboard get',editor.doc)
6896
+ .then( clipboard => {
6897
+ entry.state = (clipboard.selection.what === selex.ifArea || clipboard.selection.what === selex.pinArea) ? "enabled" : "disabled";
6898
+ })
6899
+ .catch( error => {});
6900
+ }
6901
+ }
6462
6902
  };
6463
6903
 
6464
6904
  // is = {channel, input, request, proxy}
6465
6905
  function newInput() {
6466
-
6467
- pinAreaCxMenu.node?.cannotBeModified();
6468
-
6469
- // set the flags
6470
- const is = { channel: false,
6471
- input: true,
6472
- proxy: pinAreaCxMenu.node.is.group
6473
- };
6474
- editor.doEdit('newPin',{view: pinAreaCxMenu.view, node:pinAreaCxMenu.node, pos:pinAreaCxMenu.xyLocal, is});
6906
+ const is = {channel: false, input: true, proxy: ifCxMenu.node.is.group};
6907
+ editor.doEdit('newPin',{view: ifCxMenu.view, node:ifCxMenu.node, pos:ifCxMenu.xyLocal, is});
6475
6908
  }
6476
6909
  function newOutput() {
6477
- // set the flags
6478
- const is = { channel: false,
6479
- input: false,
6480
- proxy: pinAreaCxMenu.node.is.group
6481
- };
6482
- editor.doEdit('newPin',{view: pinAreaCxMenu.view, node:pinAreaCxMenu.node, pos:pinAreaCxMenu.xyLocal, is});
6910
+ const is = {channel: false, input: false, proxy: ifCxMenu.node.is.group};
6911
+ editor.doEdit('newPin',{view: ifCxMenu.view, node:ifCxMenu.node, pos:ifCxMenu.xyLocal, is});
6483
6912
  }
6484
6913
  function newRequest() {
6485
- // set the flags
6486
- const is = { channel: true,
6487
- input: false,
6488
- proxy: pinAreaCxMenu.node.is.group
6489
- };
6490
- editor.doEdit('newPin',{view: pinAreaCxMenu.view, node:pinAreaCxMenu.node, pos:pinAreaCxMenu.xyLocal, is});
6914
+ const is = {channel: true, input: false,proxy: ifCxMenu.node.is.group};
6915
+ editor.doEdit('newPin',{view: ifCxMenu.view, node:ifCxMenu.node, pos:ifCxMenu.xyLocal, is});
6491
6916
  }
6492
6917
  function newReply() {
6493
- // set the flags
6494
- const is = { channel: true,
6495
- input: true,
6496
- proxy: pinAreaCxMenu.node.is.group
6497
- };
6498
- editor.doEdit('newPin',{view: pinAreaCxMenu.view, node:pinAreaCxMenu.node, pos:pinAreaCxMenu.xyLocal, is});
6918
+ const is = {channel: true,input: true,proxy: ifCxMenu.node.is.group};
6919
+ editor.doEdit('newPin',{view: ifCxMenu.view, node:ifCxMenu.node, pos:ifCxMenu.xyLocal, is});
6499
6920
  }
6500
- function inOutSwap() {
6501
- editor.doEdit('ioSwap',{pin: pinAreaCxMenu.widget});
6921
+ function newInterfaceName() {
6922
+ editor.doEdit('newInterfaceName', {view: ifCxMenu.view, node:ifCxMenu.node, pos: ifCxMenu.xyLocal});
6502
6923
  }
6503
- function channelOnOff() {
6504
- editor.doEdit('channelOnOff',{pin: pinAreaCxMenu.widget});
6924
+ function ioSwitch() {
6925
+ editor.doEdit('ioSwitchPinArea', {view: ifCxMenu.view});
6505
6926
  }
6506
- function disconnectPin() {
6507
- editor.doEdit('disconnectPin', {pin: pinAreaCxMenu.widget});
6927
+ function ifDisconnect() {
6928
+ editor.doEdit('disconnectPinArea', {});
6508
6929
  }
6509
- function deletePin() {
6510
- editor.doEdit('deletePin',{view: pinAreaCxMenu.view,pin: pinAreaCxMenu.widget});
6930
+ function ifDelete() {
6931
+ editor.doEdit('deletePinArea',{view: ifCxMenu.view});
6511
6932
  }
6512
- function newInterfaceName() {
6513
- editor.doEdit('newInterfaceName', {view: pinAreaCxMenu.view, node:pinAreaCxMenu.node, pos: pinAreaCxMenu.xyLocal});
6933
+
6934
+ // pin swapping
6935
+ function ifPinsSwap() {
6936
+ editor.doEdit('swapPinArea',{node:ifCxMenu.node,left:true, right:true});
6514
6937
  }
6515
- function deleteInterfaceName() {
6516
- editor.doEdit('deleteInterfaceName',{view: pinAreaCxMenu.view,ifName: pinAreaCxMenu.widget});
6938
+ function ifPinsLeft() {
6939
+ editor.doEdit('swapPinArea',{node:ifCxMenu.node,left:true, right:false});
6517
6940
  }
6518
- function showProfile(e) {
6519
- editor.doEdit('showProfile',{pin: pinAreaCxMenu.widget, pos: {x:pinAreaCxMenu.xyScreen.x, y:pinAreaCxMenu.xyScreen.y + 10}});
6941
+ function ifPinsRight() {
6942
+ editor.doEdit('swapPinArea',{node:ifCxMenu.node,left:false, right:true});
6520
6943
  }
6521
6944
 
6522
- function pinsSwap$1() {
6523
- editor.doEdit('swapPins',{node:pinAreaCxMenu.node,left:true, right:true});
6945
+ function ifToClipboard() {
6946
+ editor.doEdit('selectionToClipboard',{view: ifCxMenu.view});
6524
6947
  }
6525
6948
 
6526
- function pinsLeft$1() {
6527
- editor.doEdit('swapPins',{node:pinAreaCxMenu.node,left:true, right:false});
6528
- }
6529
- function pinsRight$1() {
6530
- editor.doEdit('swapPins',{node:pinAreaCxMenu.node,left:false, right:true});
6531
- }
6532
- function pasteWidgetsFromClipboard() {
6949
+ // paste widgets
6950
+ function pastePinsFromClipboard() {
6533
6951
 
6534
6952
  // request the clipboard - also set the target, the clipboard can come from another file
6535
6953
  editor.tx.request('clipboard get',editor.doc).then( clipboard => {
6536
6954
 
6537
- editor.doEdit('pasteWidgetsFromClipboard',{ view: pinAreaCxMenu.view, clipboard});
6538
- });
6539
- //.catch( error => console.log('paste: clipboard get error -> ' + error))
6955
+ editor.doEdit('pasteWidgetsFromClipboard',{ view: ifCxMenu.view, clipboard});
6956
+ })
6957
+ .catch( error => console.log('paste: clipboard get error -> ' + error));
6540
6958
  }
6541
6959
 
6542
6960
  const selectFreeCxMenu = {
@@ -6590,7 +7008,7 @@ function group() {
6590
7008
  }
6591
7009
 
6592
7010
  // click on the node
6593
- const selectWidgetsCxMenu = {
7011
+ const pinAreaCxMenu = {
6594
7012
 
6595
7013
  choices: [
6596
7014
  {text:"copy", icon:"content_copy",state:"enabled", action:selectionToClipboard},
@@ -6599,6 +7017,8 @@ const selectWidgetsCxMenu = {
6599
7017
  {text:"all pins swap left right", icon:"swap_horiz",state:"enabled", action:pinsSwap},
6600
7018
  {text:"all pins left", icon:"arrow_back",state:"enabled", action:pinsLeft},
6601
7019
  {text:"all pins right", icon:"arrow_forward",state:"enabled", action:pinsRight},
7020
+ {text:"in/out switch", icon:"cached",state:"disabled", action:inOutSwitch},
7021
+
6602
7022
  ],
6603
7023
 
6604
7024
  view: null,
@@ -6618,22 +7038,25 @@ const selectWidgetsCxMenu = {
6618
7038
  },
6619
7039
  };
6620
7040
  function selectionToClipboard() {
6621
- editor.doEdit('selectionToClipboard',{view: selectWidgetsCxMenu.view});
7041
+ editor.doEdit('selectionToClipboard',{view: pinAreaCxMenu.view});
6622
7042
  }
6623
7043
  function disconnectPinArea() {
6624
- editor.doEdit('disconnectPinArea', {view: selectWidgetsCxMenu.view, node: selectWidgetsCxMenu.node, widgets: selectWidgetsCxMenu.widgets});
7044
+ editor.doEdit('disconnectPinArea', {view: pinAreaCxMenu.view, node: pinAreaCxMenu.node, widgets: pinAreaCxMenu.widgets});
6625
7045
  }
6626
7046
  function deletePinArea() {
6627
- editor.doEdit('deletePinArea',{view: selectWidgetsCxMenu.view, node: selectWidgetsCxMenu.node, widgets: selectWidgetsCxMenu.widgets});
7047
+ editor.doEdit('deletePinArea',{view: pinAreaCxMenu.view, node: pinAreaCxMenu.node, widgets: pinAreaCxMenu.widgets});
6628
7048
  }
6629
7049
  function pinsSwap() {
6630
- editor.doEdit('swapPinArea',{view: selectWidgetsCxMenu.view, left:true, right:true});
7050
+ editor.doEdit('swapPinArea',{view: pinAreaCxMenu.view, left:true, right:true});
6631
7051
  }
6632
7052
  function pinsLeft() {
6633
- editor.doEdit('swapPinArea',{view: selectWidgetsCxMenu.view, left:true, right:false});
7053
+ editor.doEdit('swapPinArea',{view: pinAreaCxMenu.view, left:true, right:false});
6634
7054
  }
6635
7055
  function pinsRight() {
6636
- editor.doEdit('swapPinArea',{view: selectWidgetsCxMenu.view, left:false, right:true});
7056
+ editor.doEdit('swapPinArea',{view: pinAreaCxMenu.view, left:false, right:true});
7057
+ }
7058
+ function inOutSwitch() {
7059
+ editor.doEdit('ioSwitchPinArea', {view});
6637
7060
  }
6638
7061
 
6639
7062
  const busCxMenu = {
@@ -6775,72 +7198,123 @@ function deletePad() {
6775
7198
  }
6776
7199
 
6777
7200
  const contextHandling = {
6778
-
6779
7201
  // show the rightclick menu
6780
7202
  onContextMenu(xyLocal, e) {
6781
-
6782
7203
  // save the location
6783
7204
  this.saveHitSpot(xyLocal, e);
6784
7205
 
6785
7206
  // check what was hit inside the window !
6786
7207
  this.mouseHit(xyLocal);
6787
7208
 
6788
- switch(this.hit.what) {
6789
-
7209
+ switch (this.hit.what) {
6790
7210
  case zap.header:
6791
- case zap.icon: {
6792
- nodeCxMenu.prepare(this);
6793
- editor.tx.send("show context menu", {menu:nodeCxMenu.choices, event:e});
6794
- }
6795
- break
7211
+ case zap.icon:
7212
+ {
7213
+ nodeCxMenu.prepare(this);
7214
+ editor.tx.send('show context menu', {
7215
+ menu: nodeCxMenu.choices,
7216
+ event: e,
7217
+ });
7218
+ }
7219
+ break;
6796
7220
 
6797
7221
  case zap.node:
6798
7222
  case zap.pin:
6799
- case zap.ifName:{
6800
- pinAreaCxMenu.prepare(this);
6801
- editor.tx.send("show context menu", {menu: pinAreaCxMenu.choices, event:e});
6802
- }
6803
- break
7223
+ {
7224
+ pinCxMenu.prepare(this);
7225
+ editor.tx.send('show context menu', {
7226
+ menu: pinCxMenu.choices,
7227
+ event: e,
7228
+ });
7229
+ }
7230
+ break;
7231
+
7232
+ case zap.ifName:
7233
+ {
7234
+ // we select the entire interface here
7235
+ this.selection.interfaceSelect(
7236
+ this.hit.node,
7237
+ this.hit.lookWidget
7238
+ );
7239
+
7240
+ // prepare the context menu
7241
+ ifCxMenu.prepare(this);
7242
+
7243
+ editor.tx.send('show context menu', {
7244
+ menu: ifCxMenu.choices,
7245
+ event: e,
7246
+ });
7247
+ }
7248
+ break;
6804
7249
 
6805
7250
  case zap.busSegment:
6806
- case zap.busLabel: {
6807
- busCxMenu.prepare(this);
6808
- editor.tx.send("show context menu", {menu:busCxMenu.choices, event:e});
6809
- }
6810
- break
7251
+ case zap.busLabel:
7252
+ {
7253
+ busCxMenu.prepare(this);
7254
+ editor.tx.send('show context menu', {
7255
+ menu: busCxMenu.choices,
7256
+ event: e,
7257
+ });
7258
+ }
7259
+ break;
6811
7260
 
6812
7261
  case zap.pad:
6813
- case zap.padArrow: {
6814
- padCxMenu.prepare(this);
6815
- editor.tx.send("show context menu", {menu:padCxMenu.choices, event:e});
6816
- }
6817
- break
6818
-
6819
- case zap.selection: {
7262
+ case zap.padArrow:
7263
+ {
7264
+ padCxMenu.prepare(this);
7265
+ editor.tx.send('show context menu', {
7266
+ menu: padCxMenu.choices,
7267
+ event: e,
7268
+ });
7269
+ }
7270
+ break;
6820
7271
 
6821
- switch(this.selection.what) {
7272
+ case zap.selection:
7273
+ {
7274
+ switch (this.selection.what) {
7275
+ case selex.freeRect:
7276
+ case selex.multiNode:
7277
+ {
7278
+ selectFreeCxMenu.prepare(this);
7279
+ editor.tx.send('show context menu', {
7280
+ menu: selectFreeCxMenu.choices,
7281
+ event: e,
7282
+ });
7283
+ }
7284
+ break;
6822
7285
 
6823
- case selex.freeRect:
6824
- case selex.multiNode: {
6825
- selectFreeCxMenu.prepare(this);
6826
- editor.tx.send("show context menu", {menu:selectFreeCxMenu.choices, event:e});
6827
- }
6828
- break
7286
+ case selex.ifArea:
7287
+ {
7288
+ ifCxMenu.prepare(this);
7289
+ editor.tx.send('show context menu', {
7290
+ menu: ifCxMenu.choices,
7291
+ event: e,
7292
+ });
7293
+ }
7294
+ break;
6829
7295
 
6830
- case selex.pinArea: {
6831
- selectWidgetsCxMenu.prepare(this);
6832
- editor.tx.send("show context menu", {menu:selectWidgetsCxMenu.choices, event:e});
7296
+ case selex.pinArea:
7297
+ {
7298
+ pinAreaCxMenu.prepare(this);
7299
+ editor.tx.send('show context menu', {
7300
+ menu: pinAreaCxMenu.choices,
7301
+ event: e,
7302
+ });
7303
+ }
7304
+ break;
6833
7305
  }
6834
- break
6835
7306
  }
6836
- }
6837
- break
7307
+ break;
6838
7308
 
6839
- case zap.nothing: {
6840
- bgCxMenu.prepare(this);
6841
- editor.tx.send("show context menu", {menu:bgCxMenu.choices, event:e});
6842
- }
6843
- break
7309
+ case zap.nothing:
7310
+ {
7311
+ bgCxMenu.prepare(this);
7312
+ editor.tx.send('show context menu', {
7313
+ menu: bgCxMenu.choices,
7314
+ event: e,
7315
+ });
7316
+ }
7317
+ break;
6844
7318
  }
6845
7319
  },
6846
7320
  };
@@ -6961,16 +7435,14 @@ const selectionHandling = {
6961
7435
  // cb is the clipboard
6962
7436
  deltaForPaste(pos, cb) {
6963
7437
 
7438
+ if (!pos) return null;
7439
+
6964
7440
  // increment the copy count
6965
7441
  cb.copyCount++;
6966
7442
 
6967
7443
  const slct = cb.selection;
6968
7444
 
6969
- const ref = (slct.what == selex.freeRect)
6970
- ? slct.rect
6971
- : (slct.what == selex.multiNode)
6972
- ? slct.nodes[0].look.rect
6973
- : {x:0, y:0};
7445
+ const ref = (slct.what == selex.freeRect) ? slct.rect : (slct.what == selex.multiNode) ? slct.nodes[0].look.rect : {x:0, y:0};
6974
7446
 
6975
7447
  // if the position is the same as the reference - move the first, otherwise only move starting from 2
6976
7448
  return ((ref.x == pos.x) && (ref.y == pos.y))
@@ -6990,10 +7462,9 @@ const selectionHandling = {
6990
7462
 
6991
7463
  // calculate where the selection has to be pasted
6992
7464
  const delta = this.deltaForPaste(pos, clipboard);
6993
- //const pasteHere = this.pastePosition(pos, clipboard)
6994
7465
 
6995
7466
  // if we have selected a node and a position inside the node, get it here (before we reset)
6996
- const [node, inside] = this.selectedNodeAndPosition();
7467
+ const [node, inside] = this.selection.whereToAdd();
6997
7468
 
6998
7469
  // initialise the selection
6999
7470
  this.selection.reset();
@@ -7089,6 +7560,7 @@ const selectionHandling = {
7089
7560
  }
7090
7561
  break
7091
7562
 
7563
+ case selex.ifArea:
7092
7564
  case selex.pinArea: {
7093
7565
 
7094
7566
  // check
@@ -7097,11 +7569,13 @@ const selectionHandling = {
7097
7569
  // paste the widgets
7098
7570
  const copies = node.look.copyPinArea(cbslct.widgets, inside);
7099
7571
 
7100
- // add the pads or the adjust the rx/tx tables
7572
+ // add the pads or adjust the rx/tx tables
7101
7573
  node.is.source ? node.rxtxAddPinArea(copies) : node.addPads(copies);
7102
7574
 
7103
7575
  // the selection becomes the widgets that were copied
7104
7576
  this.selection.pinAreaSelect(copies);
7577
+
7578
+ this.selection.what = cbslct.what;
7105
7579
  }
7106
7580
  break
7107
7581
  }
@@ -7185,7 +7659,7 @@ const selectionHandling = {
7185
7659
 
7186
7660
 
7187
7661
  // get the node and the position where a pin must be added
7188
- selectedNodeAndPosition() {
7662
+ xxxselectedNodeAndPosition() {
7189
7663
 
7190
7664
  // get the selected node (only one !)
7191
7665
  const node = this.selection.getSingleNode();
@@ -7819,351 +8293,372 @@ const alignHandling = {
7819
8293
  function canProceed(view) {
7820
8294
 
7821
8295
  // get the node and the position where to add
7822
- const [node, pos] = view.selectedNodeAndPosition();
8296
+ let [node, pos] = view.selection.whereToAdd();
8297
+
8298
+ // maybe we have a valid hit position
8299
+ if (!pos) pos = view.hit.xyLocal;
7823
8300
 
7824
8301
  // check
7825
- if (!node || !pos) return [false, null, null]
8302
+ if (!node || !pos) return [false, null, null];
7826
8303
 
7827
8304
  // check if we can modify the node
7828
- if (node.cannotBeModified()) return [false, null, null]
8305
+ if (node.cannotBeModified()) return [false, null, null];
7829
8306
 
7830
8307
  // ok
7831
- return [true, node, pos]
8308
+ return [true, node, pos];
7832
8309
  }
7833
8310
 
7834
8311
  // The table with the <ctrl> + key combinations
7835
8312
  const justKeyTable = {
7836
-
7837
8313
  // add input
7838
8314
  i: (view) => {
7839
-
7840
8315
  //check
7841
8316
  const [ok, node, pos] = canProceed(view);
7842
- if (!ok) return
8317
+ if (!ok) return;
7843
8318
 
7844
8319
  // type of pin
7845
- const is = {
7846
- channel: false,
7847
- input: true,
7848
- proxy: node.is.group
7849
- };
8320
+ const is = {
8321
+ channel: false,
8322
+ input: true,
8323
+ proxy: node.is.group};
7850
8324
 
7851
8325
  // add the pin
7852
- editor.doEdit('newPin',{view, node, pos, is});
8326
+ editor.doEdit('newPin', { view, node, pos, is });
7853
8327
  },
7854
8328
 
7855
8329
  // add output
7856
8330
  o: (view) => {
7857
-
7858
8331
  //check
7859
8332
  const [ok, node, pos] = canProceed(view);
7860
- if (!ok) return
8333
+ if (!ok) return;
7861
8334
 
7862
- const is = {
7863
- channel: false,
7864
- input: false,
8335
+ const is = {
8336
+ channel: false,
8337
+ input: false,
7865
8338
  proxy: node.is.group
7866
8339
  };
7867
8340
 
7868
8341
  // add an input pin where the click happened
7869
- editor.doEdit('newPin',{view, node, pos, is});
8342
+ editor.doEdit('newPin', { view, node, pos, is });
7870
8343
  },
7871
8344
 
7872
8345
  // add request
7873
8346
  q: (view) => {
7874
-
7875
8347
  //check
7876
8348
  const [ok, node, pos] = canProceed(view);
7877
- if (!ok) return
8349
+ if (!ok) return;
7878
8350
 
7879
8351
  // type of pin
7880
- const is = {
7881
- channel: true,
7882
- input: false,
7883
- proxy: node.is.group
8352
+ const is = {
8353
+ channel: true,
8354
+ input: false,
8355
+ proxy: node.is.group,
7884
8356
  };
7885
8357
 
7886
8358
  // add the pin
7887
- editor.doEdit('newPin',{view, node, pos, is});
8359
+ editor.doEdit('newPin', { view, node, pos, is });
7888
8360
  },
7889
8361
 
7890
8362
  // add reply
7891
8363
  r: (view) => {
7892
-
7893
8364
  //check
7894
8365
  const [ok, node, pos] = canProceed(view);
7895
- if (!ok) return
8366
+ if (!ok) return;
7896
8367
 
7897
8368
  // type of pin
7898
- const is = {
7899
- channel: true,
7900
- input: true,
7901
- proxy: node.is.group
8369
+ const is = {
8370
+ channel: true,
8371
+ input: true,
8372
+ proxy: node.is.group,
7902
8373
  };
7903
8374
 
7904
8375
  // add the pin
7905
- editor.doEdit('newPin',{view, node, pos, is});
8376
+ editor.doEdit('newPin', { view, node, pos, is });
7906
8377
  },
7907
8378
 
7908
8379
  // add ifName
7909
8380
  p: (view) => {
7910
-
7911
8381
  //check
7912
8382
  const [ok, node, pos] = canProceed(view);
7913
- if (!ok) return
8383
+ if (!ok) return;
7914
8384
 
7915
8385
  // add an input pin where the click happened
7916
- editor.doEdit('newInterfaceName',{view, node, pos});
8386
+ editor.doEdit('newInterfaceName', { view, node, pos });
7917
8387
  },
7918
8388
 
7919
8389
  // add a label
7920
- a: (view) => {
7921
-
8390
+ a: (view) => {
7922
8391
  // get the selected node (only one !)
7923
8392
  const node = view.selection.getSingleNode();
7924
- if (! node ) return
8393
+ if (!node) return;
7925
8394
 
7926
8395
  // check if already a lable
7927
8396
  const label = node.look.findLabel();
7928
- if (label)
7929
- editor.doEdit('widgetTextEdit',{view, widget: label});
7930
- else
7931
- editor.doEdit('addLabel',{node});
8397
+ if (label) editor.doEdit('widgetTextEdit', { view, widget: label });
8398
+ else editor.doEdit('addLabel', { node });
7932
8399
  },
7933
8400
 
7934
8401
  // highlight/unhighlight
7935
8402
  h: (view) => {
7936
8403
  // get the selected node (only one !)
7937
8404
  const node = view.selection.getSingleNode();
7938
- if (! node ) return
8405
+ if (!node) return;
7939
8406
 
7940
8407
  // highlight/unhighlight
7941
- editor.doEdit('nodeHighLight', {node});
8408
+ editor.doEdit('nodeHighLight', { node });
7942
8409
  },
7943
8410
 
7944
8411
  '+': (view) => {
7945
-
7946
8412
  const widget = view.selection.getSelectedWidget();
7947
8413
 
7948
8414
  // check
7949
8415
  if (!widget || !widget.node || widget.node.cannotBeModified()) return;
7950
8416
 
7951
8417
  // ok
7952
- editor.doEdit('widgetTextEdit',{view, widget, cursor:-1});
8418
+ editor.doEdit('widgetTextEdit', { view, widget, cursor: -1 });
7953
8419
  },
7954
8420
 
7955
8421
  '-': (view) => {
7956
-
7957
8422
  const widget = view.selection.getSelectedWidget();
7958
8423
 
7959
8424
  // check
7960
8425
  if (!widget || !widget.node || widget.node.cannotBeModified()) return;
7961
8426
 
7962
- // start
7963
- editor.doEdit('widgetTextEdit',{view, widget, cursor:0, clear:true});
8427
+ // start
8428
+ editor.doEdit('widgetTextEdit', {
8429
+ view,
8430
+ widget,
8431
+ cursor: 0,
8432
+ clear: true,
8433
+ });
7964
8434
  },
7965
8435
 
7966
8436
  // delete the selection or the single node
7967
- 'Clear': (view) => {
7968
-
8437
+ Clear: (view) => {
7969
8438
  // get the selected node only if nothing else is selected
7970
- const node = view.selection.what == selex.singleNode ? view.selection.getSingleNode() : null;
8439
+ const node =
8440
+ view.selection.what == selex.singleNode
8441
+ ? view.selection.getSingleNode()
8442
+ : null;
7971
8443
 
7972
- if (node)
7973
- editor.doEdit('disconnectNode',{node});
7974
- else
7975
- editor.doEdit('disconnectSelection', {view});
8444
+ if (node) editor.doEdit('disconnectNode', { node });
8445
+ else editor.doEdit('disconnectSelection', { view });
7976
8446
  },
7977
8447
 
7978
8448
  // delete the selection or the single node
7979
- 'Delete': (view) => {
7980
-
7981
- switch(view.selection.what) {
7982
-
8449
+ Delete: (view) => {
8450
+ switch (view.selection.what) {
7983
8451
  case selex.nothing:
7984
- break
8452
+ break;
7985
8453
 
7986
8454
  case selex.freeRect:
7987
- editor.doEdit('deleteSelection', {view});
7988
- break
8455
+ editor.doEdit('deleteSelection', { view });
8456
+ break;
7989
8457
 
7990
8458
  case selex.pinArea:
7991
-
7992
8459
  //check if ok
7993
8460
  const [ok, node, pos] = canProceed(view);
7994
- if (!ok) return
8461
+ if (!ok) return;
7995
8462
 
7996
- editor.doEdit('deletePinArea',{ view,
7997
- node: view.selection.getSingleNode(),
7998
- widgets: view.selection.widgets});
7999
- break
8463
+ editor.doEdit('deletePinArea', {
8464
+ view,
8465
+ node: view.selection.getSingleNode(),
8466
+ widgets: view.selection.widgets,
8467
+ });
8468
+ break;
8000
8469
 
8001
8470
  case selex.singleNode:
8002
-
8003
8471
  // maybe there is a widget selected
8004
8472
  const widget = view.selection.getSelectedWidget();
8005
8473
 
8006
8474
  // check
8007
8475
  if (!widget) {
8008
-
8009
8476
  // get the node, delete and done
8010
8477
  const node = view.selection.getSingleNode();
8011
- if (node) editor.doEdit('deleteNode',{node});
8012
- return
8478
+ if (node) editor.doEdit('deleteNode', { node });
8479
+ return;
8013
8480
  }
8014
8481
 
8015
8482
  // check
8016
- if (widget.node.cannotBeModified()) return
8483
+ if (widget.node.cannotBeModified()) return;
8017
8484
 
8018
8485
  // which pin
8019
- if (widget.is.pin)
8020
- editor.doEdit('deletePin',{view, pin: widget});
8021
- else if (widget.is.ifName)
8022
- editor.doEdit('deleteInterfaceName',{view, ifName: widget});
8023
- break
8486
+ if (widget.is.pin)
8487
+ editor.doEdit('deletePin', { view, pin: widget });
8488
+ else if (widget.is.ifName)
8489
+ editor.doEdit('deleteInterfaceName', {
8490
+ view,
8491
+ ifName: widget,
8492
+ });
8493
+ break;
8024
8494
 
8025
8495
  case selex.multiNode:
8026
- editor.doEdit('deleteSelection', {view});
8027
- break
8028
-
8496
+ editor.doEdit('deleteSelection', { view });
8497
+ break;
8029
8498
  }
8030
8499
  },
8031
8500
 
8032
- 'Enter': (view) => {
8033
-
8501
+ Enter: (view) => {
8034
8502
  // if there is a pin selected, we start editing the pin
8035
8503
  const editable = view.selection.getSelectedWidget();
8036
8504
  if (editable) {
8037
-
8038
8505
  // check
8039
- if (editable.node.cannotBeModified()) return
8506
+ if (editable.node.cannotBeModified()) return;
8040
8507
 
8041
8508
  // start editing
8042
- editor.doEdit('widgetTextEdit',{view, widget: editable});
8509
+ editor.doEdit('widgetTextEdit', { view, widget: editable });
8043
8510
  }
8044
8511
  },
8045
8512
 
8046
- 'ArrowDown': (view) => {
8047
- const below = view.selection.widgetBelow();
8048
- if (below) view.selection.switchWidget(below);
8513
+ ArrowDown: (view) => {
8514
+ const below = view.selection.widgetBelow();
8515
+ if (below) view.selection.switchToWidget(below);
8049
8516
  },
8050
8517
 
8051
- 'ArrowUp': (view) => {
8052
- const above = view.selection.widgetAbove();
8053
- if (above) view.selection.switchWidget(above);
8518
+ ArrowUp: (view) => {
8519
+ const above = view.selection.widgetAbove();
8520
+ if (above) view.selection.switchToWidget(above);
8054
8521
  },
8055
8522
 
8056
8523
  // undo
8057
- 'Undo': (view) => editor.undoLastEdit(),
8524
+ Undo: (view) => editor.undoLastEdit(),
8058
8525
 
8059
8526
  // redo
8060
- 'Redo': (view) => editor.redoLastEdit(),
8527
+ Redo: (view) => editor.redoLastEdit(),
8061
8528
 
8062
- // escape
8063
- 'Escape' : (view) => { view.selection.reset();}
8529
+ // escape
8530
+ Escape: (view) => {
8531
+ view.selection.reset();
8532
+ },
8064
8533
  };
8065
8534
 
8066
8535
  // The table with the <ctrl> + key combinations
8067
8536
  const ctrlKeyTable = {
8068
-
8069
8537
  // a new source node
8070
8538
  s: (view) => {
8071
-
8072
8539
  // only do this if there is no selection
8073
8540
  // if (view.selection.what != selex.nothing) return
8074
8541
 
8075
8542
  // create a new source node
8076
- editor.doEdit('newSourceNode',{view, pos: view.hit.xyLocal});
8543
+ editor.doEdit('newSourceNode', { view, pos: view.hit.xyLocal });
8077
8544
  },
8078
8545
 
8079
8546
  // a new group node
8080
8547
  g: (view) => {
8081
-
8082
8548
  // only do this if there is no selection
8083
8549
  // if (view.selection.what != selex.nothing) return
8084
8550
 
8085
8551
  // create a new source node
8086
- editor.doEdit('newGroupNode',{view, pos: view.hit.xyLocal});
8552
+ editor.doEdit('newGroupNode', { view, pos: view.hit.xyLocal });
8087
8553
  },
8088
8554
 
8089
8555
  // a new bus
8090
8556
  b: (view) => {
8091
-
8092
8557
  // only do this if there is no selection
8093
8558
  // if (view.selection.what != selex.nothing) return
8094
8559
 
8095
8560
  // create a new busbar
8096
- editor.doEdit('busCreate',{view, pos: view.hit.xyLocal, cable:false});
8561
+ editor.doEdit('busCreate', {
8562
+ view,
8563
+ pos: view.hit.xyLocal,
8564
+ cable: false,
8565
+ });
8097
8566
  },
8098
8567
 
8099
8568
  // a new bus
8100
8569
  k: (view) => {
8101
-
8102
8570
  // only do this if there is no selection
8103
8571
  // if (view.selection.what != selex.nothing) return
8104
8572
 
8105
8573
  // create a new cable
8106
- editor.doEdit('busCreate',{view, pos: view.hit.xyLocal, cable:true});
8574
+ editor.doEdit('busCreate', {
8575
+ view,
8576
+ pos: view.hit.xyLocal,
8577
+ cable: true,
8578
+ });
8107
8579
  },
8108
8580
 
8109
8581
  // copy
8110
8582
  c: (view) => {
8111
- editor.doEdit('selectionToClipboard', {view});
8583
+ editor.doEdit('selectionToClipboard', { view });
8112
8584
  },
8113
8585
 
8114
8586
  // a new input pad
8115
8587
  i: (view) => {
8116
- editor.doEdit('padCreate', {view,pos: view.hit.xyLocal, input:true});
8588
+ editor.doEdit('padCreate', {
8589
+ view,
8590
+ pos: view.hit.xyLocal,
8591
+ input: true,
8592
+ });
8117
8593
  },
8118
8594
 
8119
8595
  // add a new output pad
8120
8596
  o: (view) => {
8121
- editor.doEdit('padCreate', {view,pos: view.hit.xyLocal, input:false});
8597
+ editor.doEdit('padCreate', {
8598
+ view,
8599
+ pos: view.hit.xyLocal,
8600
+ input: false,
8601
+ });
8122
8602
  },
8123
8603
 
8124
8604
  // paste as link
8125
8605
  l: (view) => {
8126
-
8127
- // request the clipboard - also set the target, the clipboard can come from another file
8128
- editor.tx.request('clipboard get',editor.doc).then( clipboard => {
8129
-
8130
- // get the type of selection
8131
- const what = clipboard.selection.what;
8132
-
8133
- // if there is nothing , done
8134
- if (what == selex.nothing) return
8135
-
8136
- // link pin area paste operation is not defined
8137
- if (what == selex.pinArea) return
8138
-
8139
- // other cases do the standard link operation
8140
- editor.doEdit('linkFromClipboard',{view, pos: view.hit.xyLocal, clipboard});
8141
- })
8142
- .catch( error => console.log('ctrl-l : clipboard get error -> ' + error));
8606
+ // request the clipboard - also set the target, the clipboard can come from another file
8607
+ editor.tx
8608
+ .request('clipboard get', editor.doc)
8609
+ .then((clipboard) => {
8610
+ // get the type of selection
8611
+ const what = clipboard.selection.what;
8612
+
8613
+ // if there is nothing , done
8614
+ if (what == selex.nothing) return;
8615
+
8616
+ // link pin area paste operation is not defined
8617
+ if (what == selex.pinArea) return;
8618
+
8619
+ // other cases do the standard link operation
8620
+ editor.doEdit('linkFromClipboard', {
8621
+ view,
8622
+ pos: view.hit.xyLocal,
8623
+ clipboard,
8624
+ });
8625
+ })
8626
+ .catch((error) =>
8627
+ console.log('ctrl-l : clipboard get error -> ' + error)
8628
+ );
8143
8629
  },
8144
8630
 
8145
8631
  // paste
8146
8632
  v: (view) => {
8147
-
8148
8633
  // request the clipboard - also set the target, the clipboard can come from another file
8149
- editor.tx.request('clipboard get',editor.doc).then( clipboard => {
8150
-
8151
- // get the type of selection
8152
- const what = clipboard.selection.what;
8153
-
8154
- // if there is nothing , done
8155
- if (what == selex.nothing) return
8156
-
8157
- // The pin area paste operation is defined elsewhere..
8158
- if (what == selex.pinArea) {
8159
- editor.doEdit('pasteWidgetsFromClipboard', {view, clipboard});
8160
- return
8161
- }
8634
+ editor.tx
8635
+ .request('clipboard get', editor.doc)
8636
+ .then((clipboard) => {
8637
+ // get the type of selection
8638
+ const what = clipboard.selection.what;
8639
+
8640
+ // if there is nothing , done
8641
+ if (what == selex.nothing) return;
8642
+
8643
+ // The pin area paste operation is defined elsewhere..
8644
+ if (what == selex.pinArea) {
8645
+ editor.doEdit('pasteWidgetsFromClipboard', {
8646
+ view,
8647
+ clipboard,
8648
+ });
8649
+ return;
8650
+ }
8162
8651
 
8163
- // other cases do the standard paste operation
8164
- editor.doEdit('pasteFromClipboard',{view, pos: view.hit.xyLocal, clipboard});
8165
- })
8166
- .catch( error => console.log('ctrl-v : clipboard get error -> ' + error));
8652
+ // other cases do the standard paste operation
8653
+ editor.doEdit('pasteFromClipboard', {
8654
+ view,
8655
+ pos: view.hit.xyLocal,
8656
+ clipboard,
8657
+ });
8658
+ })
8659
+ .catch((error) =>
8660
+ console.log('ctrl-v : clipboard get error -> ' + error)
8661
+ );
8167
8662
  },
8168
8663
 
8169
8664
  // undo
@@ -8174,24 +8669,22 @@ const ctrlKeyTable = {
8174
8669
 
8175
8670
  // wider
8176
8671
  '+': (view) => {
8177
-
8178
8672
  // get the selected node (only one !)
8179
8673
  const node = view.selection.getSingleNode();
8180
- if (! node ) return
8674
+ if (!node) return;
8181
8675
 
8182
8676
  // make wider
8183
- editor.doEdit('wider', {node});
8677
+ editor.doEdit('wider', { node });
8184
8678
  },
8185
8679
 
8186
8680
  // thinner
8187
8681
  '-': (view) => {
8188
-
8189
8682
  // get the selected node (only one !)
8190
8683
  const node = view.selection.getSingleNode();
8191
- if (! node ) return
8684
+ if (!node) return;
8192
8685
 
8193
8686
  // make wider
8194
- editor.doEdit('smaller', {node});
8687
+ editor.doEdit('smaller', { node });
8195
8688
  },
8196
8689
  };
8197
8690
 
@@ -8418,7 +8911,8 @@ function Header(rect, node) {
8418
8911
  // binary state
8419
8912
  this.is = {
8420
8913
  header: true,
8421
- highLighted: false
8914
+ highLighted: false,
8915
+ alert: false
8422
8916
  };
8423
8917
  // the title is the name of the node
8424
8918
  this.title = node.name;
@@ -8471,6 +8965,8 @@ Header.prototype = {
8471
8965
 
8472
8966
  // draw the text
8473
8967
  shape.centerText(ctx, this.title, st.font, color, x, y, w, h);
8968
+
8969
+ if (this.is.alert) shape.circle(x,y,10,'#ff0000');
8474
8970
  },
8475
8971
 
8476
8972
  // true if the title area was hit (the y-hit is already established !)
@@ -8612,11 +9108,12 @@ const pinNameHandling = {
8612
9108
  // there is a prefix or a postfix that is not displayed
8613
9109
  withoutPrefix() {
8614
9110
 
8615
- //const x = '\u271A '
8616
- const space = '+ ';
8617
-
8618
- if (this.pxlen == 0) return this.name
9111
+ // change a space into a subscript '+' sign
9112
+ const space = '\u208A';
8619
9113
 
9114
+ if (this.pxlen == 0) {
9115
+ return this.name
9116
+ }
8620
9117
  else if (this.pxlen > 0) {
8621
9118
 
8622
9119
  let noPrefix = this.name.slice(this.pxlen);
@@ -8797,7 +9294,7 @@ const pinNameHandling = {
8797
9294
  // The messages between the pins must overlap
8798
9295
  const allPinMsgs = pin.is.multi ? convert.expandMultis(pin.lowerCase()) : [pin.lowerCase()];
8799
9296
  const allThisMsgs = this.is.multi ? convert.expandMultis(this.lowerCase()) : [this.lowerCase()];
8800
-
9297
+ //console.log('MULTI', allPinMsgs, allThisMsgs)
8801
9298
  // at the first common message we return
8802
9299
  for(const pinMsg of allPinMsgs) {
8803
9300
  if ( allThisMsgs.includes(pinMsg)) return true
@@ -8870,10 +9367,9 @@ const pinNameHandling = {
8870
9367
  }
8871
9368
  };
8872
9369
 
8873
- function Pin(rect,node,name,is){
8874
-
9370
+ function Pin(rect, node, name, is) {
8875
9371
  // copy the rectangle
8876
- this.rect = {...rect};
9372
+ this.rect = { ...rect };
8877
9373
 
8878
9374
  // the node for which this is a pin
8879
9375
  this.node = node;
@@ -8891,20 +9387,20 @@ function Pin(rect,node,name,is){
8891
9387
  this.is = {
8892
9388
  pin: true,
8893
9389
  proxy: false,
8894
- channel: is.channel ?? false,
9390
+ channel: is.channel ?? false,
8895
9391
  input: is.input ?? false,
8896
- left: is.left ?? false, // default set inputs right
8897
- multi: is.multi ?? false, // the pin can send / receive several messages
8898
- selected: false, // when the pin is selected
9392
+ left: is.left ?? false, // default set inputs right
9393
+ multi: is.multi ?? false, // the pin can send / receive several messages
9394
+ selected: false, // when the pin is selected
8899
9395
  highLighted: false,
8900
- hoverOk:false, // to give feedback when hovering over the pin
9396
+ hoverOk: false, // to give feedback when hovering over the pin
8901
9397
  hoverNok: false,
8902
- zombie: is.zombie ?? false, // for pins that are invalid
8903
- added: false, // for pins that have been added (or name change)
8904
- duplicate: false
9398
+ zombie: is.zombie ?? false, // for pins that are invalid
9399
+ added: false, // for pins that have been added (or name change)
9400
+ duplicate: false,
8905
9401
  };
8906
9402
 
8907
- // the parameter profile
9403
+ // the parameter profile
8908
9404
  this.profile = '';
8909
9405
 
8910
9406
  // The prompt for the input handler or a description of when the output is sent
@@ -8916,195 +9412,283 @@ function Pin(rect,node,name,is){
8916
9412
 
8917
9413
  // The pin prototype
8918
9414
  Pin.prototype = {
8919
-
8920
-
8921
9415
  // pChar is where the cursor has to come
8922
- drawCursor(ctx, pChar,on) {
8923
-
9416
+ drawCursor(ctx, pChar, on) {
8924
9417
  // notation
8925
9418
  const rc = this.rect;
8926
9419
  const m = style$1.pin.wMargin;
8927
9420
 
8928
9421
  // relative x position of the cursor
8929
- const cx = ctx.measureText(this.name.slice(0,pChar)).width;
9422
+ const cx = ctx.measureText(this.name.slice(0, pChar)).width;
8930
9423
 
8931
9424
  // absolute position of the cursor...
8932
- const xCursor = this.is.left ? rc.x + m + cx : rc.x + rc.w - m - ctx.measureText(this.name).width + cx;
9425
+ const xCursor = this.is.left
9426
+ ? rc.x + m + cx
9427
+ : rc.x + rc.w - m - ctx.measureText(this.name).width + cx;
8933
9428
 
8934
9429
  // the color for the blink effect
8935
9430
  const color = on ? style$1.std.cBlinkOn : style$1.std.cBlinkOff;
8936
9431
  //const color = on ? style.pin.cConnected : style.box.cBackground
8937
9432
 
8938
9433
  // and draw the cursor
8939
- shape.cursor(ctx, xCursor, rc.y, style$1.std.wCursor, rc.h, color);
9434
+ shape.cursor(ctx, xCursor, rc.y, style$1.std.wCursor, rc.h, color);
8940
9435
  },
8941
9436
 
8942
9437
  // arrows in and out
8943
9438
  render(ctx) {
8944
-
8945
9439
  // notation
8946
9440
  const st = style$1.pin;
8947
9441
  const rc = this.rect;
8948
9442
 
8949
9443
  // the name to display
8950
- const displayName = this.pxlen == 0 ? this.name : this.withoutPrefix();
9444
+ const displayName = this.pxlen == 0 ? this.name : this.withoutPrefix();
8951
9445
 
8952
9446
  // select the color for the widget
8953
- const {cArrow, cText} = this.setColor();
9447
+ const { cArrow, cText } = this.setColor();
8954
9448
 
8955
9449
  // the y position of the arrow
8956
- const yArrow = rc.y+(st.hPin-st.wArrow)/2;
9450
+ const yArrow = rc.y + (st.hPin - st.wArrow) / 2;
8957
9451
 
8958
9452
  // we shift the arrow a little bit...
8959
- const dx = style$1.box.wLine/2;
9453
+ const dx = style$1.box.wLine / 2;
8960
9454
 
8961
9455
  // The shape for a channel is different
8962
- const pointLeft = this.is.channel ? shape.triangleBall : shape.leftTriangle;
8963
- const pointRight = this.is.channel ? shape.ballTriangle : shape.rightTriangle;
9456
+ const pointLeft = this.is.channel
9457
+ ? shape.triangleBall
9458
+ : shape.leftTriangle;
9459
+ const pointRight = this.is.channel
9460
+ ? shape.ballTriangle
9461
+ : shape.rightTriangle;
8964
9462
 
8965
- // debug : draws a green rectangle around the pin
8966
- // shape.rectRect(ctx,rc.x, rc.y, rc.w, rc.h,"#00FF00", null)
9463
+ // debug : draws a green rectangle around the pin
9464
+ // shape.rectRect(ctx,rc.x, rc.y, rc.w, rc.h,"#00FF00", null)
8967
9465
 
8968
9466
  // render the text and arrow : 4 cases : left in >-- out <-- right in --< out -->
8969
9467
  if (this.is.left) {
8970
9468
  const xArrow = rc.x + st.wOutside;
8971
- this.is.multi ? shape.leftTextMulti(ctx,displayName,st.fMulti,cText, rc.x + style$1.pin.wMargin,rc.y, rc.w, rc.h)
8972
- : shape.leftText(ctx,displayName,cText, rc.x + style$1.pin.wMargin,rc.y, rc.w, rc.h);
8973
- this.is.input ? pointRight(ctx,xArrow-dx, yArrow,st.hArrow, st.wArrow,cArrow)
8974
- : pointLeft(ctx,xArrow - st.hArrow + dx,yArrow,st.hArrow, st.wArrow,cArrow);
8975
- }
8976
- else {
9469
+ this.is.multi
9470
+ ? shape.leftTextMulti(
9471
+ ctx,
9472
+ displayName,
9473
+ st.fMulti,
9474
+ cText,
9475
+ rc.x + style$1.pin.wMargin,
9476
+ rc.y,
9477
+ rc.w,
9478
+ rc.h
9479
+ )
9480
+ : shape.leftText(
9481
+ ctx,
9482
+ displayName,
9483
+ cText,
9484
+ rc.x + style$1.pin.wMargin,
9485
+ rc.y,
9486
+ rc.w,
9487
+ rc.h
9488
+ );
9489
+ this.is.input
9490
+ ? pointRight(
9491
+ ctx,
9492
+ xArrow - dx,
9493
+ yArrow,
9494
+ st.hArrow,
9495
+ st.wArrow,
9496
+ cArrow
9497
+ )
9498
+ : pointLeft(
9499
+ ctx,
9500
+ xArrow - st.hArrow + dx,
9501
+ yArrow,
9502
+ st.hArrow,
9503
+ st.wArrow,
9504
+ cArrow
9505
+ );
9506
+ } else {
8977
9507
  const xArrow = rc.x + rc.w - st.wOutside;
8978
- this.is.multi ? shape.rightTextMulti(ctx, displayName, st.fMulti, cText,rc.x, rc.y,rc.w - style$1.pin.wMargin, rc.h)
8979
- : shape.rightText(ctx, displayName, cText,rc.x, rc.y,rc.w - style$1.pin.wMargin, rc.h);
8980
- this.is.input ? pointLeft(ctx,xArrow - st.hArrow + dx,yArrow,st.hArrow, st.wArrow,cArrow)
8981
- : pointRight(ctx,xArrow -dx ,yArrow,st.hArrow, st.wArrow,cArrow);
9508
+ this.is.multi
9509
+ ? shape.rightTextMulti(
9510
+ ctx,
9511
+ displayName,
9512
+ st.fMulti,
9513
+ cText,
9514
+ rc.x,
9515
+ rc.y,
9516
+ rc.w - style$1.pin.wMargin,
9517
+ rc.h
9518
+ )
9519
+ : shape.rightText(
9520
+ ctx,
9521
+ displayName,
9522
+ cText,
9523
+ rc.x,
9524
+ rc.y,
9525
+ rc.w - style$1.pin.wMargin,
9526
+ rc.h
9527
+ );
9528
+ this.is.input
9529
+ ? pointLeft(
9530
+ ctx,
9531
+ xArrow - st.hArrow + dx,
9532
+ yArrow,
9533
+ st.hArrow,
9534
+ st.wArrow,
9535
+ cArrow
9536
+ )
9537
+ : pointRight(
9538
+ ctx,
9539
+ xArrow - dx,
9540
+ yArrow,
9541
+ st.hArrow,
9542
+ st.wArrow,
9543
+ cArrow
9544
+ );
8982
9545
  }
8983
9546
 
8984
9547
  // show name clashes
8985
9548
  if (this.is.duplicate) {
8986
- shape.rectRect(ctx,rc.x, rc.y, rc.w, rc.h,st.cBad, null);
9549
+ shape.rectRect(ctx, rc.x, rc.y, rc.w, rc.h, st.cBad, null);
8987
9550
  }
8988
9551
  },
8989
9552
 
8990
9553
  setColor() {
8991
-
8992
9554
  // color of the arrow ( unconnected connected selected)
8993
- const cArrow = this.is.hoverNok ? style$1.pin.cBad
8994
- : this.is.hoverOk ? style$1.pin.cSelected
8995
- : this.is.highLighted ? style$1.pin.cHighLighted
8996
- : this.is.selected ? style$1.pin.cSelected
8997
- : this.routes.length > 0 ? style$1.pin.cConnected
8998
- : style$1.pin.cNormal;
9555
+ const cArrow = this.is.hoverNok
9556
+ ? style$1.pin.cBad
9557
+ : this.is.hoverOk
9558
+ ? style$1.pin.cSelected
9559
+ : this.is.highLighted
9560
+ ? style$1.pin.cHighLighted
9561
+ : this.is.selected
9562
+ ? style$1.pin.cSelected
9563
+ : this.routes.length > 0
9564
+ ? style$1.pin.cConnected
9565
+ : style$1.pin.cNormal;
8999
9566
 
9000
9567
  // color of the text
9001
- const cText = this.is.hoverNok ? style$1.pin.cBad
9002
- : this.is.hoverOk ? style$1.pin.cSelected
9003
- : this.is.added ? style$1.pin.cAdded
9004
- : this.is.zombie ? style$1.pin.cBad
9005
- : this.is.highLighted ? style$1.pin.cHighLighted
9006
- : this.is.selected ? style$1.pin.cSelected
9007
- : this.routes.length > 0 ? style$1.pin.cConnected
9568
+ const cText = this.is.hoverNok
9569
+ ? style$1.pin.cBad
9570
+ : this.is.hoverOk
9571
+ ? style$1.pin.cSelected
9572
+ : this.is.added
9573
+ ? style$1.pin.cAdded
9574
+ : this.is.zombie
9575
+ ? style$1.pin.cBad
9576
+ : this.is.highLighted
9577
+ ? style$1.pin.cHighLighted
9578
+ : this.is.selected
9579
+ ? style$1.pin.cSelected
9580
+ : this.routes.length > 0
9581
+ ? style$1.pin.cConnected
9008
9582
  : style$1.pin.cText;
9009
-
9010
- return {cArrow, cText}
9583
+
9584
+ return { cArrow, cText };
9011
9585
  },
9012
9586
 
9013
9587
  // returns the center of the pin (h of the arrow is along x-axis here !)
9014
9588
  center() {
9015
-
9016
9589
  const wOut = style$1.pin.wOutside;
9017
9590
  const rc = this.rect;
9018
- return this.is.left ? {x: rc.x + wOut, y: rc.y + rc.h/2} : {x: rc.x + rc.w - wOut, y: rc.y + rc.h/2}
9591
+ return this.is.left
9592
+ ? { x: rc.x + wOut, y: rc.y + rc.h / 2 }
9593
+ : { x: rc.x + rc.w - wOut, y: rc.y + rc.h / 2 };
9019
9594
  },
9020
9595
 
9021
9596
  // checks if a pin can connect to another pin
9022
9597
  canConnect(pin) {
9023
-
9024
- // from and to are the same
9025
- if (this == pin) return false
9598
+ // from and to are the same
9599
+ if (this == pin) return false;
9026
9600
 
9027
9601
  // both cannot be outputs or inputs
9028
- if (this.is.input === pin.is.input) return false
9602
+ if (this.is.input === pin.is.input) return false;
9029
9603
 
9030
9604
  // multi messages can only be connected if there is a (partial) overlap
9031
- if ((this.is.multi || pin.is.multi) && !this.hasMultiOverlap(pin)) return false
9605
+ if ((this.is.multi || pin.is.multi) && !this.hasMultiOverlap(pin))
9606
+ return false;
9032
9607
 
9033
9608
  // check if we have already a connection between the pins
9034
- if (this.haveRoute(pin)) return false
9609
+ if (this.haveRoute(pin)) return false;
9035
9610
 
9036
9611
  // its ok
9037
- return true
9612
+ return true;
9038
9613
  },
9039
9614
 
9040
- // There is a route to the widget, but check if messages can flow
9615
+ // There is a route to the widget, but check if messages can flow
9041
9616
  areConnected(widget) {
9042
-
9043
9617
  if (widget.is.pin) {
9044
-
9045
9618
  // should not happen
9046
- if (widget.is.input == this.is.input) return false
9619
+ if (widget.is.input == this.is.input) return false;
9047
9620
 
9048
9621
  // multis
9049
- if ((widget.is.multi || this.is.multi ) && !this.hasMultiOverlap(widget)) return false
9050
- }
9051
- else if (widget.is.pad) {
9052
-
9622
+ if (
9623
+ (widget.is.multi || this.is.multi) &&
9624
+ !this.hasMultiOverlap(widget)
9625
+ )
9626
+ return false;
9627
+ } else if (widget.is.pad) {
9053
9628
  // should not happen
9054
- if (widget.proxy.is.input != this.is.input) return false
9629
+ if (widget.proxy.is.input != this.is.input) return false;
9055
9630
 
9056
9631
  // multis
9057
- if (widget.proxy.is.multi && !this.hasMultiOverlap(widget.proxy)) return false
9632
+ if (widget.proxy.is.multi && !this.hasMultiOverlap(widget.proxy))
9633
+ return false;
9058
9634
  }
9059
- return true
9060
- },
9635
+ return true;
9636
+ },
9061
9637
 
9062
9638
  toJSON() {
9063
-
9064
- this.is.input ? (this.is.channel ? 'reply' : 'input') : (this.is.channel ? 'request' : 'output');
9065
-
9066
- // seperate data into editor and
9639
+ this.is.input
9640
+ ? this.is.channel
9641
+ ? 'reply'
9642
+ : 'input'
9643
+ : this.is.channel
9644
+ ? 'request'
9645
+ : 'output';
9646
+
9647
+ // seperate data into editor and
9067
9648
  const json = {
9068
9649
  name: this.name,
9069
- kind: this.is.input ? (this.is.channel ? 'reply' : 'input') : (this.is.channel ? 'request' : 'output'),
9650
+ kind: this.is.input
9651
+ ? this.is.channel
9652
+ ? 'reply'
9653
+ : 'input'
9654
+ : this.is.channel
9655
+ ? 'request'
9656
+ : 'output',
9070
9657
  editor: {
9071
9658
  id: this.wid,
9072
- align: (this.is.left ? 'left' : 'right')
9073
- }
9659
+ align: this.is.left ? 'left' : 'right',
9660
+ },
9074
9661
  };
9075
9662
 
9076
9663
  // if the pin is a proxy, we add the pad-related stuff
9077
9664
  if (this.is.proxy) {
9078
-
9079
9665
  json.editor.pad = {
9080
9666
  rect: convert.rectToString(this.pad.rect),
9081
- align: this.pad.is.leftText ? 'left' : 'right'
9667
+ align: this.pad.is.leftText ? 'left' : 'right',
9082
9668
  };
9083
9669
  }
9084
9670
 
9085
- return json
9086
- },
9671
+ return json;
9672
+ },
9087
9673
 
9088
9674
  // remove a route from the routes array
9089
9675
  removeRoute(route) {
9090
-
9091
9676
  eject(this.routes, route);
9092
9677
  },
9093
9678
 
9094
-
9095
9679
  adjustRoutes() {
9096
- for(const route of this.routes) route.adjust();
9680
+ for (const route of this.routes) route.adjust();
9097
9681
  },
9098
9682
 
9099
9683
  // changes the position from left to right
9100
9684
  leftRightSwap() {
9101
-
9102
9685
  // notation
9103
9686
  const rc = this.node.look.rect;
9104
9687
 
9105
9688
  // change the x coordinate
9106
- this.rect.x = this.is.left ? rc.x + rc.w - this.rect.w + style$1.pin.wOutside
9107
- : rc.x - style$1.pin.wOutside;
9689
+ this.rect.x = this.is.left
9690
+ ? rc.x + rc.w - this.rect.w + style$1.pin.wOutside
9691
+ : rc.x - style$1.pin.wOutside;
9108
9692
  // change
9109
9693
  this.is.left = !this.is.left;
9110
9694
 
@@ -9113,18 +9697,25 @@ Pin.prototype = {
9113
9697
  },
9114
9698
 
9115
9699
  drag(pos) {
9116
-
9117
9700
  // notation
9118
9701
  const rc = this.node.look.rect;
9119
9702
 
9120
9703
  // notation
9121
- const center = rc.x + rc.w/2;
9704
+ const center = rc.x + rc.w / 2;
9122
9705
 
9123
9706
  // switch left right ?
9124
- if ((this.is.left && (pos.x > center)) || ( !this.is.left && (pos.x < center))) this.leftRightSwap();
9707
+ if (
9708
+ (this.is.left && pos.x > center) ||
9709
+ (!this.is.left && pos.x < center)
9710
+ )
9711
+ this.leftRightSwap();
9125
9712
 
9126
9713
  // find pin or ifName to swap with
9127
- const next = this.node.look.findNextWidget(this, pos, next => next.is.pin || next.is.ifName);
9714
+ const next = this.node.look.findNextWidget(
9715
+ this,
9716
+ pos,
9717
+ (next) => next.is.pin || next.is.ifName
9718
+ );
9128
9719
 
9129
9720
  // if no next - done
9130
9721
  if (!next) return;
@@ -9141,7 +9732,6 @@ Pin.prototype = {
9141
9732
  },
9142
9733
 
9143
9734
  moveTo(left, y) {
9144
-
9145
9735
  // check if the pin needs to swap from left to right
9146
9736
  if (left != this.is.left) this.leftRightSwap();
9147
9737
 
@@ -9150,16 +9740,15 @@ Pin.prototype = {
9150
9740
 
9151
9741
  // a widget between the new and the old place has to be moved up or down
9152
9742
  for (const widget of this.node.look.widgets) {
9153
-
9154
9743
  // notation
9155
9744
  const wrc = widget.rect;
9156
9745
 
9157
9746
  // up or down
9158
- if ((prc.y > y) && (wrc.y >= y) && (wrc.y < prc.y)) {
9747
+ if (prc.y > y && wrc.y >= y && wrc.y < prc.y) {
9159
9748
  wrc.y += prc.h;
9160
9749
  if (widget.is.pin) widget.adjustRoutes();
9161
9750
  }
9162
- if ((prc.y < y) && (wrc.y <= y) && (wrc.y > prc.y)) {
9751
+ if (prc.y < y && wrc.y <= y && wrc.y > prc.y) {
9163
9752
  wrc.y -= prc.h;
9164
9753
  if (widget.is.pin) widget.adjustRoutes();
9165
9754
  }
@@ -9172,48 +9761,45 @@ Pin.prototype = {
9172
9761
  },
9173
9762
 
9174
9763
  disconnect() {
9175
-
9176
9764
  // make a copy of the routes - the pin.routes array will be modified during this proc
9177
9765
  const routes = this.routes.slice();
9178
-
9766
+
9179
9767
  // for all widgets that have routes..
9180
9768
  for (const route of routes) {
9181
-
9182
9769
  // get the other widget
9183
9770
  const other = route.from == this ? route.to : route.from;
9184
-
9771
+
9185
9772
  // disconnect
9186
- other.is.pin ? route.rxtxPinPinDisconnect()
9187
- : other.is.pad ? route.rxtxPinPadDisconnect()
9188
- : other.is.tack ? route.rxtxPinBusDisconnect()
9189
- : null;
9190
-
9773
+ other.is.pin
9774
+ ? route.rxtxPinPinDisconnect()
9775
+ : other.is.pad
9776
+ ? route.rxtxPinPadDisconnect()
9777
+ : other.is.tack
9778
+ ? route.rxtxPinBusDisconnect()
9779
+ : null;
9780
+
9191
9781
  // remove the route at both ends
9192
9782
  route.remove();
9193
9783
  }
9194
9784
  },
9195
-
9785
+
9196
9786
  // this function is used in the undo action (see redox)
9197
9787
  reconnect(routes) {
9198
-
9199
9788
  // just restore the routes of the pin
9200
9789
  this.routes = routes;
9201
-
9790
+
9202
9791
  // and also put the routes back in all destinations
9203
9792
  for (const route of routes) {
9204
-
9205
9793
  // get the other widget
9206
9794
  const other = route.from == this ? route.to : route.from;
9207
-
9795
+
9208
9796
  if (other.is.pin) {
9209
9797
  other.routes.push(route);
9210
9798
  route.rxtxPinPin();
9211
- }
9212
- else if (other.is.pad) {
9799
+ } else if (other.is.pad) {
9213
9800
  other.routes.push(route);
9214
9801
  route.rxtxPinPad();
9215
- }
9216
- else if (other.is.tack) {
9802
+ } else if (other.is.tack) {
9217
9803
  other.bus.tacks.push(other);
9218
9804
  route.rxtxPinBus();
9219
9805
  }
@@ -9222,35 +9808,34 @@ Pin.prototype = {
9222
9808
 
9223
9809
  // checks if there is already a route
9224
9810
  haveRoute(other) {
9225
-
9226
- for(const route of this.routes) if (route.from == other || route.to == other) return true
9227
- return false
9811
+ for (const route of this.routes)
9812
+ if (route.from == other || route.to == other) return true;
9813
+ return false;
9228
9814
  },
9229
9815
 
9230
- ioSwap() {
9231
-
9232
- // check
9233
- if (this.routes.length > 0) return false
9234
- if (this.is.proxy && (this.pad.routes.length > 0)) return false
9816
+ ioSwitch() {
9235
9817
 
9818
+ // check
9819
+ if (this.routes.length > 0) return false;
9820
+ if (this.is.proxy && this.pad.routes.length > 0) return false;
9821
+
9236
9822
  // change the type of pin
9237
9823
  this.is.input = !this.is.input;
9238
9824
 
9239
9825
  // succesful
9240
- return true
9826
+ return true;
9241
9827
  },
9242
9828
 
9243
9829
  channelOnOff() {
9244
-
9245
9830
  // toggle the channel bit
9246
9831
  this.is.channel = !this.is.channel;
9247
9832
 
9248
9833
  // If the pin is connected to a bus, the bus tack has to be updated
9249
- for(const route of this.routes) {
9834
+ for (const route of this.routes) {
9250
9835
  const other = route.from == this ? route.to : route.from;
9251
9836
  if (other.is.tack) other.is.channel = this.is.channel;
9252
9837
  }
9253
- return true
9838
+ return true;
9254
9839
  },
9255
9840
 
9256
9841
  doSelect() {
@@ -9274,28 +9859,26 @@ Pin.prototype = {
9274
9859
  [a,b,c,d] -> pad - proxy [a,b,c] -> pin [b,c,d] only messages b,c get through.
9275
9860
  */
9276
9861
  highLightRoutes() {
9277
-
9278
9862
  // highlight the connections of the pin
9279
9863
  for (const route of this.routes) {
9280
-
9281
9864
  // check the other part of the route - note that it might be missing during a disconnect operation !
9282
9865
  const other = route.from == this ? route.to : route.from;
9283
9866
 
9284
9867
  // check
9285
- if (!other) continue
9868
+ if (!other) continue;
9286
9869
 
9287
9870
  // pin
9288
9871
  if (other.is.pin) {
9289
- if (!this.areConnected(other)) continue
9872
+ if (!this.areConnected(other)) continue;
9290
9873
  route.highLight();
9291
- continue
9874
+ continue;
9292
9875
  }
9293
9876
 
9294
9877
  // pad
9295
9878
  if (other.is.pad) {
9296
- if (!this.areConnected(other)) continue
9879
+ if (!this.areConnected(other)) continue;
9297
9880
  route.highLight();
9298
- continue
9881
+ continue;
9299
9882
  }
9300
9883
 
9301
9884
  // bus
@@ -9307,10 +9890,8 @@ Pin.prototype = {
9307
9890
  },
9308
9891
 
9309
9892
  unHighLightRoutes() {
9310
-
9311
9893
  // highlight the connections of the pin
9312
9894
  for (const route of this.routes) {
9313
-
9314
9895
  // unhighlight
9315
9896
  route.unHighLight();
9316
9897
 
@@ -9318,20 +9899,20 @@ Pin.prototype = {
9318
9899
  const other = route.from == this ? route.to : route.from;
9319
9900
 
9320
9901
  // check
9321
- if (!other) continue
9902
+ if (!other) continue;
9322
9903
 
9323
9904
  // pin
9324
9905
  if (other.is.pin) {
9325
- if (!this.areConnected(other)) continue
9906
+ if (!this.areConnected(other)) continue;
9326
9907
  if (other.is.proxy) other.pad.unHighLightRoutes();
9327
- continue
9908
+ continue;
9328
9909
  }
9329
9910
 
9330
9911
  // pad
9331
9912
  if (other.is.pad) {
9332
- if (!this.areConnected(other)) continue
9913
+ if (!this.areConnected(other)) continue;
9333
9914
  other.proxy.unHighLightRoutes();
9334
- continue
9915
+ continue;
9335
9916
  }
9336
9917
 
9337
9918
  // bus
@@ -9342,16 +9923,26 @@ Pin.prototype = {
9342
9923
  },
9343
9924
 
9344
9925
  makePadRect(pos) {
9345
-
9346
9926
  // The width of the pad
9347
- const width = style$1.pad.wExtra + this.node.look.getTextWidth(this.name, this.is.multi);
9927
+ const width =
9928
+ style$1.pad.wExtra +
9929
+ this.node.look.getTextWidth(this.name, this.is.multi);
9348
9930
 
9349
9931
  // determine the rectangle for the pad widget
9350
- return this.is.left ? {x: pos.x, y: pos.y-style$1.pad.hPad/2, w: width, h:style$1.pad.hPad}
9351
- : {x: pos.x, y: pos.y-style$1.pad.hPad/2, w: width, h:style$1.pad.hPad}
9932
+ return this.is.left
9933
+ ? {
9934
+ x: pos.x,
9935
+ y: pos.y - style$1.pad.hPad / 2,
9936
+ w: width,
9937
+ h: style$1.pad.hPad,
9938
+ }
9939
+ : {
9940
+ x: pos.x,
9941
+ y: pos.y - style$1.pad.hPad / 2,
9942
+ w: width,
9943
+ h: style$1.pad.hPad,
9944
+ };
9352
9945
  },
9353
-
9354
-
9355
9946
  };
9356
9947
  Object.assign(Pin.prototype, pinNameHandling);
9357
9948
 
@@ -9679,7 +10270,9 @@ BusTack.prototype = {
9679
10270
  this.rect.y += dy;
9680
10271
 
9681
10272
  // check that we have enough segments
9682
- if (this.route.wire.length == 2) this.route.addTwoSegments(this.route.wire[0], this.route.wire[1]);
10273
+ //if (this.route.wire.length == 2) this.route.addTwoSegments(this.route.wire[0], this.route.wire[1])
10274
+ if (this.route.wire.length == 2) this.route.fourPointRoute();
10275
+
9683
10276
 
9684
10277
  // move the endpoint of the route as well..
9685
10278
  const a = this.route.from == this ? this.route.wire[0] : this.route.wire.at(-1);
@@ -10006,7 +10599,7 @@ function InterfaceName(rect, text, node) {
10006
10599
  this.is = {
10007
10600
  ifName: true,
10008
10601
  added: false , // has been added
10009
- zombie: false, // ifName has been deleted (not used -> interfaceNames are free form ...)
10602
+ zombie: false, // interface name has been deleted (not used -> interfaceNames are free form ...)
10010
10603
  selected: false,
10011
10604
  highLighted: false
10012
10605
  };
@@ -10048,7 +10641,6 @@ InterfaceName.prototype = {
10048
10641
 
10049
10642
  render(ctx, look) {
10050
10643
  // notation
10051
- const {x,y,w,h} = this.rect;
10052
10644
  const st = style$1.ifName;
10053
10645
 
10054
10646
  const color = this.is.added ? st.cAdded :
@@ -10057,7 +10649,8 @@ InterfaceName.prototype = {
10057
10649
  this.is.selected ? st.cSelected :
10058
10650
  st.cNormal;
10059
10651
 
10060
- shape.interfaceText(ctx, this.text, st.font, color, st.cBackground, x,y,w,h);
10652
+ // draw
10653
+ shape.ifName(ctx, this.text, {line:st.cBackground, text:color},this.rect);
10061
10654
  },
10062
10655
 
10063
10656
  toJSON() {
@@ -12012,410 +12605,421 @@ changeFactory: {
12012
12605
  * @node editor editor
12013
12606
  */
12014
12607
  const redoxWidget = {
12608
+ newPin: {
12609
+ doit({ view, node, pos, is }) {
12610
+ // we add new pins at the end of a selection if, or else we keep the pos value
12611
+ pos = view.selection.behind() ?? pos;
12015
12612
 
12016
- newPin: {
12613
+ // create the pin
12614
+ const pin = node.look.addPin('', pos, is);
12017
12615
 
12018
- doit({view, node, pos, is}){
12019
- // create the pin
12020
- const pin = node.look.addPin('', pos, is);
12021
-
12022
- // add a pad or the pin to the rx / tx table
12023
- pin.is.proxy ? node.addPad(pin) : node.rxtxAddPin(pin);
12616
+ // add a pad or the pin to the rx / tx table
12617
+ pin.is.proxy ? node.addPad(pin) : node.rxtxAddPin(pin);
12024
12618
 
12025
- // switch the selected pin
12026
- view.selection.switchWidget(pin);
12619
+ // if there is a selection maybe it has to be adjusted
12620
+ view.selection.adjustForNewWidget(pin);
12027
12621
 
12028
- // edit the name field
12029
- view.beginTextEdit(pin);
12030
-
12031
- // store and report the new edit - here the rxtx or the pad is added !
12032
- editor.saveEdit('newPin', {view,pin});
12033
- },
12034
- undo({view,pin}) {
12622
+ // edit the name field
12623
+ view.beginTextEdit(pin);
12035
12624
 
12036
- // if the pin was not created (no valid name) just return
12037
- if (!pin || !pin.node.look.widgets.includes(pin)) return
12038
-
12039
- // the node
12040
- const node = pin.node;
12625
+ // store and report the new edit - here the rxtx or the pad is added !
12626
+ editor.saveEdit('newPin', { view, pin });
12627
+ },
12628
+ undo({ view, pin }) {
12629
+ // if the pin was not created (no valid name) just return
12630
+ if (!pin || !pin.node.look.widgets.includes(pin)) return;
12041
12631
 
12042
- // switch selection
12043
- view.selection.switchWidget();
12632
+ // the node
12633
+ const node = pin.node;
12044
12634
 
12045
- // remove the pin
12046
- node.look.removePin(pin);
12635
+ // adjust selection before deleting the pin
12636
+ view.selection.adjustForRemovedWidget(pin);
12047
12637
 
12048
- // it is the last entry in the rx/tx table
12049
- pin.is.proxy ? node.pads.pop() : node.rxtxPopPin(pin);
12050
- },
12051
- redo({view,pin}) {
12638
+ // remove the pin
12639
+ node.look.removePin(pin);
12052
12640
 
12053
- // if the pin was not created (no valid name) just return
12054
- if (!pin || !pin.node.look.widgets.includes(pin)) return
12641
+ // it is the last entry in the rx/tx table
12642
+ pin.is.proxy ? node.pads.pop() : node.rxtxPopPin(pin);
12643
+ },
12644
+ redo({ view, pin }) {
12645
+ // if the pin was not created (no valid name) just return
12646
+ if (!pin || !pin.node.look.widgets.includes(pin)) return;
12055
12647
 
12056
- // the node
12057
- const node = pin.node;
12648
+ // the node
12649
+ const node = pin.node;
12058
12650
 
12059
- // restore the pin to its previous place in the look
12060
- node.look.restorePin(pin);
12651
+ // restore the pin to its previous place in the look
12652
+ node.look.restorePin(pin);
12061
12653
 
12062
- // add the pin to the rx / tx table
12063
- pin.is.proxy ? node.addPad(pin) : node.rxtxAddPin(pin);
12654
+ // add the pin to the rx / tx table
12655
+ pin.is.proxy ? node.addPad(pin) : node.rxtxAddPin(pin);
12064
12656
 
12065
- // switch the selected pin
12066
- view.selection.switchWidget(pin);
12067
- }
12068
- },
12657
+ // switch the selected pin
12658
+ view.selection.adjustForNewWidget(pin);
12659
+ },
12660
+ },
12069
12661
 
12070
- disconnectPin: {
12662
+ disconnectPin: {
12663
+ doit({ pin }) {
12664
+ // save the routes before disconnecting ...
12665
+ const savedRoutes = pin.routes.slice();
12071
12666
 
12072
- doit({pin}) {
12073
- // save the routes before disconnecting ...
12074
- const savedRoutes = pin.routes.slice();
12075
-
12076
- // disconnect
12077
- pin.disconnect();
12667
+ // disconnect
12668
+ pin.disconnect();
12078
12669
 
12079
- // store and report the new edit
12080
- editor.saveEdit('disconnectPin',{pin,routes:savedRoutes});
12081
- },
12082
- undo({pin, routes}) {
12083
- pin.reconnect(routes);
12670
+ // store and report the new edit
12671
+ editor.saveEdit('disconnectPin', { pin, routes: savedRoutes });
12672
+ },
12673
+ undo({ pin, routes }) {
12674
+ pin.reconnect(routes);
12675
+ },
12676
+ redo({ pin, routes }) {
12677
+ pin.disconnect();
12678
+ },
12084
12679
  },
12085
- redo({pin, routes}) {
12086
- pin.disconnect();
12087
- }
12088
- },
12089
-
12090
- deletePin: {
12091
12680
 
12092
- doit({view, pin}) {
12093
- // save the routes
12094
- const pinRoutes = pin.routes.slice();
12681
+ deletePin: {
12682
+ doit({ view, pin }) {
12683
+ // save the routes
12684
+ const pinRoutes = pin.routes.slice();
12095
12685
 
12096
- // also for the pad if applicable
12097
- const padRoutes = pin.is.proxy ? pin.pad.routes.slice() : null;
12686
+ // also for the pad if applicable
12687
+ const padRoutes = pin.is.proxy ? pin.pad.routes.slice() : null;
12098
12688
 
12099
- // save the edit *before* the delete !
12100
- editor.saveEdit('deletePin',{view, pin, pinRoutes, padRoutes});
12689
+ // save the edit *before* the delete !
12690
+ editor.saveEdit('deletePin', { view, pin, pinRoutes, padRoutes });
12101
12691
 
12102
- // switch the selection
12103
- view.selection.switchWidget();
12692
+ // adjust selection before deleting the pin
12693
+ view.selection.adjustForRemovedWidget(pin);
12104
12694
 
12105
- // disconnect
12106
- pin.disconnect();
12695
+ // disconnect
12696
+ pin.disconnect();
12107
12697
 
12108
- // delete the pin in the node
12109
- pin.node.look.removePin(pin);
12698
+ // delete the pin in the node
12699
+ pin.node.look.removePin(pin);
12110
12700
 
12111
- // if proxy remove pad
12112
- if (pin.is.proxy) {
12701
+ // if proxy remove pad
12702
+ if (pin.is.proxy) {
12703
+ pin.pad.disconnect();
12113
12704
 
12114
- pin.pad.disconnect();
12705
+ pin.node.removePad(pin.pad);
12706
+ }
12707
+ // if not remove from rx table
12708
+ else pin.node.rxtxRemovePin(pin);
12709
+ },
12710
+ undo({ view, pin, pinRoutes, padRoutes }) {
12711
+ // copy the routes (redo destroys the array - we want to keep it on the undo stack !)
12712
+ const copyRoutes = pinRoutes.slice();
12115
12713
 
12116
- pin.node.removePad(pin.pad);
12117
- }
12118
- // if not remove from rx table
12119
- else pin.node.rxtxRemovePin(pin);
12120
- },
12121
- undo({view, pin, pinRoutes, padRoutes}) {
12714
+ // put the pin back
12715
+ pin.node.look.restorePin(pin);
12122
12716
 
12123
- // copy the routes (redo destroys the array - we want to keep it on the undo stack !)
12124
- const copyRoutes = pinRoutes.slice();
12717
+ // if there is a selection maybe it has to be adjusted
12718
+ view.selection.adjustForNewWidget(pin);
12125
12719
 
12126
- // put the pin back
12127
- pin.node.look.restorePin(pin);
12720
+ // reconnect the routes to the pin
12721
+ pin.reconnect(copyRoutes);
12128
12722
 
12129
- // switch the selection
12130
- view.selection.switchWidget(pin);
12723
+ // reconnect the routes to the pad
12724
+ if (pin.is.proxy) {
12725
+ // first add the pad again ?
12131
12726
 
12132
- // reconnect the routes to the pin
12133
- pin.reconnect(copyRoutes);
12727
+ // reconnect the routes
12728
+ pin.pad.reconnect(padRoutes);
12729
+ }
12730
+ },
12134
12731
 
12135
- // reconnect the routes to the pad
12136
- if (pin.is.proxy) {
12732
+ redo({ view, pin, pinRoutes, padRoutes }) {
12733
+ // first disconnect
12734
+ pin.disconnect();
12137
12735
 
12138
- // first add the pad again ?
12736
+ // adjust selection before deleting the pin
12737
+ view.selection.adjustForRemovedWidget(pin);
12139
12738
 
12140
- // reconnect the routes
12141
- pin.pad.reconnect(padRoutes);
12142
- }
12739
+ // remove the pin
12740
+ pin.node.look.removePin(pin);
12741
+ },
12143
12742
  },
12144
12743
 
12145
- redo({view, pin, pinRoutes, padRoutes}) {
12146
-
12147
- // first disconnect
12148
- pin.disconnect();
12149
-
12150
- // switch the selection
12151
- view.selection.switchWidget();
12152
-
12153
- // remove the pin
12154
- pin.node.look.removePin(pin);
12155
- }
12156
- },
12157
-
12158
- // change the pin from an input type to an output type
12159
- ioSwap: {
12160
-
12161
- doit({pin}) {
12162
-
12163
- if (pin.ioSwap()) editor.saveEdit('ioSwap',pin);
12164
- },
12165
- undo({pin}) {
12166
- pin.ioSwap();
12744
+ // change the pin from an input type to an output type
12745
+ ioSwitch: {
12746
+ doit({ pin }) {
12747
+ if (pin.ioSwitch()) editor.saveEdit('ioSwitch', pin);
12748
+ },
12749
+ undo({ pin }) {
12750
+ pin.ioSwitch();
12751
+ },
12752
+ redo({ pin }) {
12753
+ pin.ioSwitch();
12754
+ },
12167
12755
  },
12168
- redo({pin}) {
12169
- pin.ioSwap();
12170
- }
12171
- },
12172
-
12173
- // change the pin from an input type to an output type
12174
- channelOnOff: {
12175
-
12176
- doit({pin}) {
12177
12756
 
12178
- if (pin.channelOnOff()) editor.saveEdit('channelOnOff',pin);
12179
- },
12180
- undo({pin}) {
12181
- pin.channelOnOff();
12757
+ // change the pin from an input type to an output type
12758
+ channelOnOff: {
12759
+ doit({ pin }) {
12760
+ if (pin.channelOnOff()) editor.saveEdit('channelOnOff', pin);
12761
+ },
12762
+ undo({ pin }) {
12763
+ pin.channelOnOff();
12764
+ },
12765
+ redo({ pin }) {
12766
+ pin.channelOnOff();
12767
+ },
12182
12768
  },
12183
- redo({pin}) {
12184
- pin.channelOnOff();
12185
- }
12186
- },
12187
-
12188
- pinDrag: {
12189
12769
 
12190
- doit({pin}) {
12191
- editor.saveEdit('pinDrag', {pin, oldPos: {left: pin.is.left, y: pin.rect.y}, newPos: null});
12192
- },
12193
- undo({pin, oldPos, newPos}) {
12194
- pin.moveTo(oldPos.left, oldPos.y);
12770
+ pinDrag: {
12771
+ doit({ pin }) {
12772
+ // just save the current position
12773
+ editor.saveEdit('pinDrag', {
12774
+ pin,
12775
+ oldPos: { left: pin.is.left, y: pin.rect.y },
12776
+ newPos: null,
12777
+ });
12778
+ },
12779
+ undo({ pin, oldPos, newPos }) {
12780
+ pin.moveTo(oldPos.left, oldPos.y);
12781
+ },
12782
+ redo({ pin, oldPos, newPos }) {
12783
+ pin.moveTo(newPos.left, newPos.y);
12784
+ },
12195
12785
  },
12196
- redo({pin, oldPos, newPos}) {
12197
- pin.moveTo(newPos.left, newPos.y);
12198
- }
12199
- },
12200
12786
 
12787
+ /*
12201
12788
  pinAreaDrag: {
12202
12789
 
12203
12790
  doit(view) {
12204
12791
 
12205
12792
  // The widgets that are being dragged
12206
- const widgets = view.selection.widgets;
12793
+ const widgets = view.selection.widgets
12207
12794
 
12208
12795
  // get the current y-position of the selected widgets
12209
- editor.saveEdit('pinAreaDrag', {widgets, oldY:widgets[0].rect.y, newY:widgets[0].rect.y});
12796
+ editor.saveEdit('pinAreaDrag', {widgets, oldY:widgets[0].rect.y, newY:widgets[0].rect.y})
12210
12797
  },
12211
12798
  undo({widgets, oldY, newY}) {
12212
12799
  },
12213
12800
  redo({widgets, oldY, newY}) {
12214
12801
  }
12215
12802
  },
12803
+ */
12804
+ showProfile: {
12805
+ doit({ pin, pos }) {
12806
+ // check that we have a model
12807
+ if (!editor.doc?.model) return;
12216
12808
 
12217
- showProfile: {
12218
-
12219
- doit({pin, pos}) {
12809
+ // get the pin profile (can be a single profile or an array !)
12810
+ const profile = pin.is.input
12811
+ ? editor.doc.model.getInputPinProfile(pin)
12812
+ : editor.doc.model.getOutputPinProfile(pin);
12220
12813
 
12221
- // check that we have a model
12222
- if ( ! (editor.doc?.model) ) return
12223
-
12224
- // get the pin profile (can be a single profile or an array !)
12225
- const profile = pin.is.input ? editor.doc.model.getInputPinProfile(pin) : editor.doc.model.getOutputPinProfile(pin);
12226
-
12227
- // check
12228
- if (!profile) {
12229
-
12230
- console.log(`NO PROFILE ${pin.name}`);
12231
-
12232
- return
12233
- }
12234
-
12235
- // show the profile
12236
- editor.tx.send('pin profile',{pos, pin, profile,
12237
-
12238
- // The function that is called when clicking the handler name
12239
- open(loc){
12240
-
12241
- //const arl = new ARL(loc.file)
12242
-
12243
- // resolve the file name with the model name
12244
- const arl = editor.doc.model.arl.resolve(loc.file);
12814
+ // check
12815
+ if (!profile) {
12816
+ console.log(`NO PROFILE ${pin.name}`);
12245
12817
 
12246
- // request to open the source file
12247
- editor.tx.send('open source file',{arl, line:loc.line});
12818
+ return;
12248
12819
  }
12249
- });
12250
- },
12251
-
12252
- undo() {},
12253
- redo(){}
12254
- },
12255
12820
 
12821
+ // show the profile
12822
+ editor.tx.send('pin profile', {
12823
+ pos,
12824
+ pin,
12825
+ profile,
12256
12826
 
12257
- newInterfaceName: {
12827
+ // The function that is called when clicking the handler name
12828
+ open(loc) {
12829
+ //const arl = new ARL(loc.file)
12258
12830
 
12259
- doit({view, node, pos}) {
12260
- // make a new ifName and put it in edit mode
12261
- let ifName = node.look.addIfName('',pos);
12831
+ // resolve the file name with the model name
12832
+ const arl = editor.doc.model.arl.resolve(loc.file);
12262
12833
 
12263
- // set the field in edit mode
12264
- view.beginTextEdit(ifName);
12265
-
12266
- // switch the selected pin
12267
- view.selection.switchWidget(ifName);
12268
-
12269
- // store and report the new edit
12270
- editor.saveEdit( 'newInterfaceName', {ifName});
12271
- },
12272
- undo({ifName}) {
12273
- ifName.node.look.removeInterfaceName(ifName);
12274
- },
12275
- redo({ifName}) {
12276
- ifName.node.look.restoreInterfaceName(ifName);
12277
- }
12278
- },
12279
-
12280
- deleteInterfaceName: {
12281
-
12282
- doit({view,ifName}) {
12283
-
12284
- // switch the selection
12285
- view.selection.switchWidget();
12286
-
12287
- // show the full names of the ifName group
12288
- const pxlenArray = ifName.node.look.showPrefixes(ifName);
12289
-
12290
- // remove the pin
12291
- ifName.node.look.removeInterfaceName(ifName);
12292
-
12293
- // store and report the new edit
12294
- editor.saveEdit('deleteInterfaceName',{view,ifName, pxlenArray});
12295
- },
12296
- undo({view,ifName, pxlenArray}) {
12297
- // restore the ifName
12298
- ifName.node.look.restoreInterfaceName(ifName);
12299
-
12300
- // restore the prefixes
12301
- ifName.node.look.hidePrefixes(ifName, pxlenArray);
12834
+ // request to open the source file
12835
+ editor.tx.send('open source file', { arl, line: loc.line });
12836
+ },
12837
+ });
12838
+ },
12302
12839
 
12303
- // switch the selection
12304
- view.selection.switchWidget(ifName);
12840
+ undo() {},
12841
+ redo() {},
12305
12842
  },
12306
- redo({view,ifName, pxlenArray}) {
12307
-
12308
- // switch the selection
12309
- view.selection.switchWidget();
12310
-
12311
- // show the full names of the ifName group
12312
- ifName.node.look.showPrefixes(ifName);
12313
-
12314
- // remove the ifName
12315
- ifName.node.look.removeInterfaceName(ifName);
12316
- }
12317
- },
12318
-
12319
- interfaceDrag: {
12320
12843
 
12321
- doit({group, oldY, newY}) {
12844
+ addLabel: {
12845
+ doit({ node }) {
12846
+ // find the label of the look or add an empty one
12847
+ let label =
12848
+ node.look.widgets.find((widget) => widget.is.label) ??
12849
+ node.look.addLabel('');
12322
12850
 
12323
- // just save the parameters...
12324
- editor.saveEdit('interfaceDrag',{group, oldY, newY});
12325
- },
12326
- undo({group, oldY, newY}) {
12851
+ // start editing the field - parameters = object - must have the edit ifPins !
12852
+ editor.doc?.focus?.beginTextEdit(label);
12327
12853
 
12328
- const dy = oldY - newY;
12329
- const node = group[0].node;
12330
- node.look.groupMove(group, dy);
12854
+ // signal the edit
12855
+ editor.saveEdit('addLabel', { node, label });
12856
+ },
12857
+ undo({ node, label }) {
12858
+ node.look.removeLabel();
12859
+ },
12860
+ redo({ node, label }) {
12861
+ node.look.restoreLabel(label);
12862
+ },
12331
12863
  },
12332
12864
 
12333
- redo({group, oldY, newY}) {
12334
-
12335
- const dy = newY - oldY;
12336
- const node = group[0].node;
12337
- node.look.groupMove(group, dy);
12338
- }
12339
- },
12340
-
12341
- interfaceNameDrag: {
12865
+ widgetTextEdit: {
12866
+ doit({ view, widget, cursor, clear }) {
12867
+ // check if field is editable - must return the prop that will be edited
12868
+ const prop = widget.startEdit?.();
12342
12869
 
12343
- doit({ifName}) {
12344
- editor.saveEdit('interfaceNameDrag', {ifName, oldY: ifName.rect.y, newY:ifName.rect.y});
12345
- },
12346
- undo({ifName, oldY, newY}) {
12347
- ifName.moveTo(oldY);
12348
- },
12349
- redo({ifName, oldY, newY}) {
12350
- ifName.moveTo(newY);
12351
- }
12352
- },
12870
+ // check
12871
+ if (!prop) return;
12872
+
12873
+ // save the old value
12874
+ editor.saveEdit('widgetTextEdit', {
12875
+ widget,
12876
+ prop,
12877
+ oldText: widget[prop],
12878
+ newText: '',
12879
+ });
12353
12880
 
12354
- addLabel: {
12355
- doit({node}) {
12881
+ // keyboard handling etc is done here
12882
+ view.beginTextEdit(widget, cursor, clear ?? false);
12883
+ },
12884
+ undo({ widget, prop, oldText, newText }) {
12885
+ /*
12886
+ better is to call simply undoTextEdit
12887
+ ======================================
12356
12888
 
12357
- // find the label of the look or add an empty one
12358
- let label = node.look.widgets.find( widget => widget.is.label ) ?? node.look.addLabel('');
12889
+ widget.undoTextEdit(oldText)
12890
+ */
12359
12891
 
12360
- // start editing the field - parameters = object - must have the edit ifPins !
12361
- editor.doc?.focus?.beginTextEdit(label);
12892
+ // save the new text now also !
12893
+ newText = widget[prop];
12894
+ editor.getParam().newText = newText;
12895
+ widget[prop] = oldText;
12362
12896
 
12363
- // signal the edit
12364
- editor.saveEdit('addLabel',{node, label});
12365
- },
12366
- undo({node, label}) {
12897
+ // signal the widget that the value has changed
12898
+ widget.endEdit(newText);
12899
+ },
12900
+ redo({ widget, prop, oldText, newText }) {
12901
+ widget[prop] = newText;
12367
12902
 
12368
- node.look.removeLabel();
12903
+ widget.endEdit(oldText);
12904
+ },
12369
12905
  },
12370
- redo({node, label}) {
12906
+ };
12907
+
12908
+ /**
12909
+ * @node editor editor
12910
+ */
12911
+ const redoxInterface = {
12912
+ newInterfaceName: {
12913
+ doit({ view, node, pos }) {
12914
+ // get the position behind the selection, if any
12915
+ pos = view.selection.behind() ?? pos;
12371
12916
 
12372
- node.look.restoreLabel(label);
12373
- }
12374
- },
12917
+ // make a new ifName and put it in edit mode
12918
+ let ifName = node.look.addIfName('', pos);
12375
12919
 
12376
- widgetTextEdit: {
12920
+ // set the field in edit mode
12921
+ view.beginTextEdit(ifName);
12377
12922
 
12378
- doit({view, widget, cursor, clear}) {
12923
+ // switch the selected pin
12924
+ view.selection.adjustForNewWidget(ifName);
12379
12925
 
12380
- // check if field is editable - must return the prop that will be edited
12381
- const prop = widget.startEdit?.();
12926
+ // store and report the new edit
12927
+ editor.saveEdit('newInterfaceName', { ifName });
12928
+ },
12929
+ undo({ ifName }) {
12930
+ ifName.node.look.removeInterfaceName(ifName);
12931
+ },
12932
+ redo({ ifName }) {
12933
+ ifName.node.look.restoreInterfaceName(ifName);
12934
+ },
12935
+ },
12382
12936
 
12383
- // check
12384
- if (!prop) return
12937
+ deleteInterfaceName: {
12938
+ doit({ view, ifName }) {
12939
+ // switch the selected pin
12940
+ view.selection.adjustForRemovedWidget(ifName);
12385
12941
 
12386
- // save the old value
12387
- editor.saveEdit('widgetTextEdit',{widget, prop, oldText: widget[prop], newText:''});
12942
+ // show the full names of the ifName group
12943
+ const pxlenArray = ifName.node.look.showPrefixes(ifName);
12388
12944
 
12389
- // keyboard handling etc is done here
12390
- view.beginTextEdit(widget, cursor, clear ?? false);
12391
- },
12392
- undo({widget, prop, oldText, newText}) {
12945
+ // remove the pin
12946
+ ifName.node.look.removeInterfaceName(ifName);
12393
12947
 
12394
- /*
12395
- better is to call simply undoTextEdit
12396
- ======================================
12948
+ // store and report the new edit
12949
+ editor.saveEdit('deleteInterfaceName', {
12950
+ view,
12951
+ ifName,
12952
+ pxlenArray,
12953
+ });
12954
+ },
12955
+ undo({ view, ifName, pxlenArray }) {
12956
+ // restore the ifName
12957
+ ifName.node.look.restoreInterfaceName(ifName);
12397
12958
 
12398
- widget.undoTextEdit(oldText)
12399
- */
12959
+ // restore the prefixes
12960
+ ifName.node.look.hidePrefixes(ifName, pxlenArray);
12400
12961
 
12401
- // save the new text now also !
12402
- newText = widget[prop];
12403
- editor.getParam().newText = newText;
12404
- widget[prop] = oldText;
12962
+ // switch the selection
12963
+ view.selection.switchToWidget(ifName);
12964
+ },
12965
+ redo({ view, ifName, pxlenArray }) {
12966
+ // switch the selection
12967
+ view.selection.switchToWidget();
12405
12968
 
12406
- // signal the widget that the value has changed
12407
- widget.endEdit(newText);
12969
+ // show the full names of the ifName group
12970
+ ifName.node.look.showPrefixes(ifName);
12408
12971
 
12972
+ // remove the ifName
12973
+ ifName.node.look.removeInterfaceName(ifName);
12974
+ },
12409
12975
  },
12410
- redo({widget, prop, oldText, newText}) {
12411
12976
 
12412
- widget[prop] = newText;
12977
+ interfaceDrag: {
12978
+ doit({ group, oldY, newY }) {
12979
+ // just save the parameters...
12980
+ editor.saveEdit('interfaceDrag', { group, oldY, newY });
12981
+ },
12982
+ undo({ group, oldY, newY }) {
12983
+ const dy = oldY - newY;
12984
+ const node = group[0].node;
12985
+ node.look.groupMove(group, dy);
12986
+ },
12413
12987
 
12414
- widget.endEdit(oldText);
12415
- }
12416
- }
12988
+ redo({ group, oldY, newY }) {
12989
+ const dy = newY - oldY;
12990
+ const node = group[0].node;
12991
+ node.look.groupMove(group, dy);
12992
+ },
12993
+ },
12417
12994
 
12995
+ interfaceNameDrag: {
12996
+ doit({ ifName }) {
12997
+ // just save the parameters
12998
+ editor.saveEdit('interfaceNameDrag', {
12999
+ ifName,
13000
+ oldY: ifName.rect.y,
13001
+ newY: ifName.rect.y,
13002
+ });
13003
+ },
13004
+ undo({ ifName, oldY, newY }) {
13005
+ ifName.moveTo(oldY);
13006
+ },
13007
+ redo({ ifName, oldY, newY }) {
13008
+ ifName.moveTo(newY);
13009
+ },
13010
+ },
12418
13011
 
13012
+ // deleteInterface: {
13013
+ // doit({ ifName }) {
13014
+ // editor.saveEdit('deleteInterface');
13015
+ // },
13016
+ // undo({ ifName, oldY, newY }) {
13017
+ // ifName.moveTo(oldY);
13018
+ // },
13019
+ // redo({ ifName, oldY, newY }) {
13020
+ // ifName.moveTo(newY);
13021
+ // },
13022
+ // },
12419
13023
  };
12420
13024
 
12421
13025
  const redoxRoute = {
@@ -13524,7 +14128,7 @@ unGroup: {
13524
14128
 
13525
14129
  };
13526
14130
 
13527
- const redoxSelectWidgets = {
14131
+ const redoxPinArea = {
13528
14132
 
13529
14133
  disconnectPinArea: {
13530
14134
 
@@ -13619,13 +14223,13 @@ pasteWidgetsFromClipboard: {
13619
14223
  doit({view, clipboard}){
13620
14224
 
13621
14225
  // check that the clipboard contains a pin area selection
13622
- if (clipboard.selection.what != selex.pinArea) return
14226
+ if (clipboard.selection.what != selex.pinArea && clipboard.selection.what != selex.ifArea) return
13623
14227
 
13624
14228
  // get the single node and widget
13625
- const [node, pos] = view.selectedNodeAndPosition();
14229
+ const [node, pos] = view.selection.whereToAdd();
13626
14230
 
13627
14231
  // check
13628
- if (node.cannotBeModified()) return
14232
+ if (!node || node.cannotBeModified()) return
13629
14233
 
13630
14234
  // get the widgets from the clipboard
13631
14235
  view.clipboardToSelection(pos,clipboard);
@@ -13677,6 +14281,31 @@ multiToPinArea: {
13677
14281
  redo() {}
13678
14282
  },
13679
14283
 
14284
+ ioSwitchPinArea: {
14285
+
14286
+ doit({view}) {
14287
+
14288
+ // check
14289
+ if (!view.selection.widgets.length) return
14290
+
14291
+ // we switch all the selected widgets to
14292
+ const switched = [];
14293
+
14294
+ // note that a switch only happens when a pin is not connected !
14295
+ for (const pin of view.selection.widgets) {
14296
+ if (pin.is.pin && pin.ioSwitch()) switched.push(pin);
14297
+ }
14298
+
14299
+ // check fro switches...
14300
+ if (switched.length) editor.saveEdit('ioSwitchPinArea',{view, switched});
14301
+ },
14302
+ undo({view, switched}) {
14303
+
14304
+ for (const pin of switched) pin.ioSwitch();
14305
+ },
14306
+ redo() {}
14307
+ }
14308
+
13680
14309
  };
13681
14310
 
13682
14311
  const redoxView = {
@@ -13730,7 +14359,7 @@ zooming: {
13730
14359
 
13731
14360
  // we call this redox - oxydation / reduction
13732
14361
  const redox = {};
13733
- Object.assign(redox, redoxNode, redoxLink, redoxWidget, redoxRoute, redoxBus, redoxPad, redoxSelect, redoxSelectWidgets, redoxView);
14362
+ Object.assign(redox, redoxNode, redoxLink, redoxWidget, redoxInterface, redoxRoute, redoxBus, redoxPad, redoxSelect, redoxPinArea, redoxView);
13734
14363
 
13735
14364
  const undoRedoHandling = {
13736
14365
 
@@ -14245,7 +14874,7 @@ const nodeClickHandling = {
14245
14874
  break
14246
14875
  }
14247
14876
 
14248
- },
14877
+ }
14249
14878
 
14250
14879
  };
14251
14880
 
@@ -14420,16 +15049,16 @@ function Link(model, lName) {
14420
15049
 
14421
15050
  //The format of lName is node @ group1 @ group2 ...
14422
15051
  this.lName = lName;
14423
- //this.uid = null
15052
+
14424
15053
  this.is = {
14425
- bad: false
15054
+ bad: false,
14426
15055
  };
14427
15056
  }
14428
15057
  Link.prototype = {
14429
15058
 
14430
15059
  copy() {
15060
+
14431
15061
  const newLink = new Link(this.model, this.lName);
14432
- //newLink.uid = this.uid
14433
15062
  return newLink
14434
15063
  },
14435
15064
 
@@ -14438,10 +15067,7 @@ Link.prototype = {
14438
15067
  // get the key for the link
14439
15068
  const path = (this.model && !this.model.is.main) ? this.model.arl.userPath : './';
14440
15069
 
14441
- return {
14442
- path,
14443
- node: this.lName
14444
- }
15070
+ return { path, node: this.lName}
14445
15071
  }
14446
15072
  };
14447
15073
 
@@ -15279,9 +15905,8 @@ const padRouteFunctions = {
15279
15905
  // to slide a route it must have at least three segments
15280
15906
  // make a copy of teh wire ! Points in the point array are overwritten !
15281
15907
  if (p.length == 2) {
15282
- //const p0 = {...p[0]}
15283
- //const p1 = {...p[1]}
15284
- route.addTwoSegments({...p[0]},{...p[1]});
15908
+ //route.addTwoSegments({...p[0]},{...p[1]})
15909
+ route.fourPointRoute();
15285
15910
  }
15286
15911
 
15287
15912
  // notation
@@ -16539,6 +17164,54 @@ const iconHandling = {
16539
17164
  // schedule the first blink function
16540
17165
  requestAnimationFrame(blinkFunction);
16541
17166
  },
17167
+
17168
+ xxxblinkToWarn() {
17169
+
17170
+ // time is in ms
17171
+ const blinkFunction = (time) => {
17172
+
17173
+ // check the time
17174
+ if (time - lastTime >= blinkRate) {
17175
+
17176
+ // change the color
17177
+ icon.is.highLighted = !icon.is.highLighted;
17178
+ header.is.highLighted = !header.is.highLighted;
17179
+
17180
+ // redraw
17181
+ editor.redraw();
17182
+
17183
+ // save the time
17184
+ lastTime = time;
17185
+
17186
+ // increment count
17187
+ count++;
17188
+ }
17189
+
17190
+ // Continue fro the number of blinks requested
17191
+ if (count < maxBlinks) {
17192
+ requestAnimationFrame(blinkFunction);
17193
+ }
17194
+ else {
17195
+ icon.is.highLighted = false;
17196
+ header.is.highLighted = false;
17197
+ editor.redraw();
17198
+ }
17199
+ };
17200
+
17201
+ const icon = this.widgets.find(w => w.is.icon && (w.type == 'link' || w.type == 'lock'));
17202
+ const header = this.widgets.find( w => w.is.header);
17203
+
17204
+ if (!icon || !header) return
17205
+
17206
+ const maxBlinks = style$1.icon.nBlinks * 2;
17207
+ const blinkRate = style$1.icon.blinkRate;
17208
+
17209
+ let count = 0;
17210
+ let lastTime = 0;
17211
+
17212
+ // schedule the first blink function
17213
+ requestAnimationFrame(blinkFunction);
17214
+ },
16542
17215
  };
16543
17216
 
16544
17217
  const moveHandling = {
@@ -17798,9 +18471,48 @@ const jsonHandling$1 = {
17798
18471
  },
17799
18472
 
17800
18473
  // places a node according to a grid
17801
- // ideally we take into account the placement of the other nodes !
17802
18474
  placeNode(node) {
17803
18475
 
18476
+ const place = style$1.placement;
18477
+ const marginLeft = this.pads.length ? place.marginLeftPads : place.marginLeft;
18478
+ const spacing = place.spacing; // small gap so nodes do not touch
18479
+ const tolerance = place.tolerance; // allow a little drift when matching columns
18480
+
18481
+ const placedNodes = this.nodes.filter(other => (other !== node) && other.look && other.is.placed);
18482
+ const idx = this.nodes.indexOf(node) >= 0 ? this.nodes.indexOf(node) : this.nodes.length - 1;
18483
+
18484
+ // keep the column grid, but stack vertically based on actual heights
18485
+ const col = idx % place.nodesPerRow;
18486
+ const columnX = marginLeft + col * place.colStep;
18487
+
18488
+ // start at the default top margin for this column
18489
+ let y = place.marginTop;
18490
+
18491
+ // find the bottom of the lowest node already in this column
18492
+ for (const other of placedNodes) {
18493
+ const ox = other.look.rect.x;
18494
+ if (Math.abs(ox - columnX) <= tolerance) {
18495
+ const bottom = other.look.rect.y + other.look.rect.h;
18496
+ if (bottom + spacing > y) y = bottom + spacing;
18497
+ }
18498
+ }
18499
+
18500
+ // move down further if we still overlap any node (safety for slightly misaligned columns)
18501
+ const expand = rect => ({x: rect.x - spacing, y: rect.y - spacing, w: rect.w + 2 * spacing, h: rect.h + 2 * spacing});
18502
+ const overlap = (a, b) => !((a.x + a.w <= b.x) || (a.x >= b.x + b.w) || (a.y + a.h <= b.y) || (a.y >= b.y + b.h));
18503
+ let candidate = {x: columnX, y, w: node.look.rect.w, h: node.look.rect.h};
18504
+ while (placedNodes.some(other => overlap(expand(candidate), expand(other.look.rect)))) {
18505
+ candidate.y += spacing;
18506
+ }
18507
+
18508
+ node.look.moveTo(candidate.x, candidate.y);
18509
+ node.is.placed = true;
18510
+ },
18511
+
18512
+
18513
+ // places a node according to a grid
18514
+ OLD_placeNode(node) {
18515
+
17804
18516
  const place = style$1.placement;
17805
18517
  const index = this.nodes.length - 1;
17806
18518
 
@@ -19285,81 +19997,100 @@ const routeDrawing = {
19285
19997
  }
19286
19998
  },
19287
19999
 
19288
- sixPointRoute() {
19289
-
19290
- // reset points
19291
- if (this.wire.length > 0) this.wire.length = 0;
19292
-
19293
- // create a simple route between the two widgets
20000
+ sixPointRoute(nodes=[]) {
20001
+
20002
+ // reset points
20003
+ if (this.wire.length > 0) this.wire.length = 0;
20004
+
20005
+ // create a simple route between the two widgets
19294
20006
  const wire = this.wire;
19295
20007
  const from = this.from;
19296
20008
  const to = this.to;
19297
20009
  const f = from.center();
19298
20010
  const t = to.center();
19299
20011
 
19300
- let x1=0, x2=0, y1=0;
19301
-
19302
- // if both pins
19303
- if (from.is.pin && to.is.pin) {
19304
-
19305
- // reasonable delta with some variation in it
19306
- const delta = style$1.look.dxCopy * (2 - Math.random());
19307
-
19308
- x1 = from.is.left ? f.x - delta : f.x + delta;
19309
- x2 = to.is.left ? t.x - delta : t.x + delta;
19310
-
19311
- const frc = from.node.look.rect;
19312
- const trc = to.node.look.rect;
19313
-
19314
- y1 = f.y + (frc.h/4 + trc.h/4)*(2 - Math.random());
19315
- }
19316
-
19317
- wire.push(f);
19318
- wire.push({x:x1, y:f.y});
20012
+ // deterministic offsets away from node bodies
20013
+ const margin = style$1.look.dxCopy;
20014
+
20015
+ let x1 = from.is.left ? f.x - margin : f.x + margin;
20016
+ let x2 = to.is.left ? t.x - margin : t.x + margin;
20017
+
20018
+ const frc = from.node.look.rect;
20019
+ const trc = to.node.look.rect;
20020
+ let y1 = f.y + (frc.h/4 + trc.h/4);
20021
+
20022
+ // If the vertical segment would cut through nodes, push y1 downward until clear
20023
+ const segmentCuts = (p1, p2, rect) => cutsRectangle(p1, p2, rect);
20024
+ const blockers = nodes.filter(n => n && n.look?.rect && n !== from.node && n !== to.node);
20025
+ const expandY = Math.max(style$1.route.split, 10);
20026
+ const tryClearY = (yCandidate) => {
20027
+ const pA = {x:x1, y:f.y};
20028
+ const pB = {x:x1, y:yCandidate};
20029
+ const pC = {x:x2, y:yCandidate};
20030
+ // check both vertical legs and the horizontal connector
20031
+ return blockers.some(n => segmentCuts(pA, pB, n.look.rect) || segmentCuts(pB, pC, n.look.rect) || segmentCuts(pC, {x:x2, y:t.y}, n.look.rect))
20032
+ };
20033
+ let guard = 0;
20034
+ while (tryClearY(y1) && guard < 20) { y1 += expandY; guard++; }
20035
+
20036
+ wire.push(f);
20037
+ wire.push({x:x1, y:f.y});
19319
20038
  wire.push({x:x1, y:y1});
19320
20039
  wire.push({x:x2, y:y1});
19321
20040
  wire.push({x:x2, y:t.y});
19322
20041
  wire.push(t);
19323
20042
  },
19324
20043
 
19325
- fourPointRoute() {
19326
-
19327
- // reset points
19328
- if (this.wire.length > 0) this.wire.length = 0;
19329
-
19330
- // create a simple route between the two widgets
20044
+ fourPointRoute(nodes=[]) {
20045
+
20046
+ // reset points
20047
+ if (this.wire.length > 0) this.wire.length = 0;
20048
+
20049
+ // create a simple route between the two widgets
19331
20050
  const wire = this.wire;
19332
20051
  const from = this.from;
19333
20052
  const to = this.to;
19334
20053
  const f = from.center();
19335
20054
  const t = to.center();
19336
20055
 
19337
- let xNew = 0;
19338
-
19339
- // if both pins are at the same side of the node
19340
- if ((from.is.pin && to.is.pin)&&(from.is.left == to.is.left)) {
19341
-
19342
- // reasonable delta with some variation in it
19343
- const delta = style$1.look.dxCopy * (2 - Math.random());
19344
-
19345
- if (from.is.left)
19346
- xNew = from.rect.x < to.rect.x ? from.rect.x - delta : to.rect.x - delta;
19347
- else
19348
- xNew = from.rect.x + from.rect.w > to.rect.x + to.rect.w ? from.rect.x + from.rect.w + delta : to.rect.x + to.rect.w + delta;
19349
- }
19350
- else {
19351
-
19352
- //set an extra point somewhere between the two...
19353
- const delta = Math.abs(f.x-t.x) * 0.5 * Math.random();
19354
-
19355
- // xNew is somewhere between the two centers
19356
- xNew = f.x < t.x ? f.x + (t.x-f.x)*0.25 + delta
19357
- : f.x - (f.x-t.x)*0.25 - delta;
19358
-
19359
- }
19360
-
19361
- wire.push(f);
19362
- wire.push({ x: xNew, y: f.y});
20056
+ let xNew = 0;
20057
+ const margin = style$1.look.dxCopy;
20058
+ const blockers = nodes.filter(n => n && n.look?.rect && n !== from.node && n !== to.node);
20059
+ const segmentCuts = (p1, p2, rect) => cutsRectangle(p1, p2, rect);
20060
+
20061
+ // if both pins are at the same side of the node
20062
+ if ((from.is.pin && to.is.pin)&&(from.is.left == to.is.left)) {
20063
+
20064
+ const left = from.is.left;
20065
+ if (left)
20066
+ xNew = from.rect.x < to.rect.x ? from.rect.x - margin : to.rect.x - margin;
20067
+ else
20068
+ xNew = from.rect.x + from.rect.w > to.rect.x + to.rect.w ? from.rect.x + from.rect.w + margin : to.rect.x + to.rect.w + margin;
20069
+ }
20070
+ else {
20071
+
20072
+ // place the bend between the two centers with a fixed offset
20073
+ const delta = Math.abs(f.x - t.x) * 0.25;
20074
+ xNew = f.x < t.x ? f.x + delta : f.x - delta;
20075
+
20076
+ }
20077
+
20078
+ // nudge xNew left/right if the vertical legs would cut through other nodes
20079
+ const tryClearX = (xCandidate) => {
20080
+ const pA = {x:xCandidate, y:f.y};
20081
+ const pB = {x:xCandidate, y:t.y};
20082
+ return blockers.some(n => segmentCuts(pA, pB, n.look.rect))
20083
+ };
20084
+ if (tryClearX(xNew)) {
20085
+ const shifts = [margin, -margin, margin*2, -margin*2];
20086
+ const base = xNew;
20087
+ for (const dx of shifts) {
20088
+ if (!tryClearX(base + dx)) { xNew = base + dx; break }
20089
+ }
20090
+ }
20091
+
20092
+ wire.push(f);
20093
+ wire.push({ x: xNew, y: f.y});
19363
20094
  wire.push({ x: xNew, y: t.y});
19364
20095
  wire.push(t);
19365
20096
  },
@@ -19477,66 +20208,66 @@ const routeDrawing = {
19477
20208
 
19478
20209
  // and draw the next point using the xy
19479
20210
  this.drawXY(xyLocal);
19480
- },
19481
-
19482
- // checks if there is an unobstructed path from p1 to p2
19483
- lineOfSight(nodes) {
19484
-
19485
- const cFrom = this.from.center();
19486
- const cTo = this.to.center();
19487
-
19488
- for (const node of nodes) {
19489
- if (cutsRectangle(cFrom, cTo, node.look.rect)) return false
19490
- }
19491
- return true
19492
- },
19493
-
19494
-
19495
-
20211
+ },
20212
+
20213
+ // checks if there is an unobstructed path from p1 to p2
20214
+ lineOfSight(nodes) {
20215
+
20216
+ const cFrom = this.from.center();
20217
+ const cTo = this.to.center();
20218
+
20219
+ for (const node of nodes) {
20220
+ // ignore the nodes that own the endpoints
20221
+ if ((node == this.from.node) || (node == this.to.node)) continue
20222
+ if (cutsRectangle(cFrom, cTo, node.look.rect)) return false
20223
+ }
20224
+ return true
20225
+ },
20226
+
19496
20227
  autoRoute(nodes) {
19497
20228
 
19498
- // get the type of connection
19499
- const conx = this.typeString();
19500
-
19501
- switch (conx) {
19502
-
19503
- case 'PIN-PIN':
19504
-
19505
- // if there is no route yet we can swap left/right to have a better fit
19506
- this.checkLeftRight();
19507
-
19508
- // check for line of sight
19509
- this.lineOfSight(nodes) ? this.fourPointRoute() : this.sixPointRoute();
19510
-
19511
- break
19512
-
19513
- case 'PIN-PAD':
19514
- this.fourPointRoute();
19515
- break
19516
-
19517
- case 'PAD-PIN':
19518
- this.fourPointRoute();
19519
- break
19520
-
19521
- case 'PIN-BUS':
19522
- this.to.horizontal() ? this.fourPointRoute() : this.threePointRoute(true);
19523
- break
19524
-
19525
- case 'BUS-PIN':
19526
- this.from.horizontal() ? this.fourPointRoute() : this.threePointRoute(true);
19527
- break
19528
-
19529
- case 'PAD-BUS':
19530
- this.to.horizontal() ? this.fourPointRoute() : this.threePointRoute(true);
19531
- break
19532
-
19533
- case 'BUS-PAD':
19534
- this.from.horizontal() ? this.fourPointRoute() : this.threePointRoute(true);
19535
- break
19536
- }
19537
- },
19538
-
19539
- checkLeftRight() {
20229
+ // get the type of connection
20230
+ const conx = this.typeString();
20231
+
20232
+ switch (conx) {
20233
+
20234
+ case 'PIN-PIN':
20235
+
20236
+ // if there is no route yet we can swap left/right to have a better fit
20237
+ this.checkLeftRight();
20238
+
20239
+ // check for line of sight
20240
+ this.lineOfSight(nodes) ? this.fourPointRoute(nodes) : this.sixPointRoute(nodes);
20241
+
20242
+ break
20243
+
20244
+ case 'PIN-PAD':
20245
+ this.fourPointRoute(nodes);
20246
+ break
20247
+
20248
+ case 'PAD-PIN':
20249
+ this.fourPointRoute(nodes);
20250
+ break
20251
+
20252
+ case 'PIN-BUS':
20253
+ this.to.horizontal() ? this.fourPointRoute(nodes) : this.threePointRoute(true);
20254
+ break
20255
+
20256
+ case 'BUS-PIN':
20257
+ this.from.horizontal() ? this.fourPointRoute(nodes) : this.threePointRoute(true);
20258
+ break
20259
+
20260
+ case 'PAD-BUS':
20261
+ this.to.horizontal() ? this.fourPointRoute(nodes) : this.threePointRoute(true);
20262
+ break
20263
+
20264
+ case 'BUS-PAD':
20265
+ this.from.horizontal() ? this.fourPointRoute(nodes) : this.threePointRoute(true);
20266
+ break
20267
+ }
20268
+ },
20269
+
20270
+ checkLeftRight() {
19540
20271
 
19541
20272
  const cFrom = this.from.center();
19542
20273
  const cTo = this.to.center();
@@ -19552,19 +20283,27 @@ const routeDrawing = {
19552
20283
 
19553
20284
  },
19554
20285
 
19555
- // sometimes a route can be pathological - this is a fix for that
19556
- healWire(){
19557
-
19558
- if (this.wire.length == 3) {
19559
-
19560
- this.wire[3] = this.wire[2];
19561
- this.wire[2] = this.wire[1];
19562
- this.wire[2].y = this.wire[3].y;
19563
- this.wire[1].y = this.wire[0].y;
19564
- }
19565
-
19566
- }
19567
-
20286
+ // sometimes a route can be pathological - this is a fix for that
20287
+ healWire(){
20288
+
20289
+ if (this.wire.length == 3) {
20290
+
20291
+ const p0 = this.wire[0];
20292
+ const p1 = this.wire[1];
20293
+ const p2 = this.wire[2];
20294
+
20295
+ // rebuild as a clean orthogonal path
20296
+ this.wire.length = 0;
20297
+ this.wire.push(
20298
+ {x:p0.x, y:p0.y},
20299
+ {x:p1.x, y:p0.y},
20300
+ {x:p1.x, y:p2.y},
20301
+ {x:p2.x, y:p2.y},
20302
+ );
20303
+ }
20304
+
20305
+ }
20306
+
19568
20307
  };
19569
20308
 
19570
20309
  // the route used for a connection between an output and an input
@@ -21718,7 +22457,7 @@ Bus.prototype = {
21718
22457
 
21719
22458
  // returns the segment that was hit
21720
22459
  hitSegment(pos) {
21721
-
22460
+
21722
22461
  // notation
21723
22462
  const L = this.wire.length;
21724
22463
  const x = pos.x;
@@ -22599,27 +23338,27 @@ async save(body) {
22599
23338
  return fs.writeFile(this.url, body)
22600
23339
  },
22601
23340
 
22602
- async getFolder() {
23341
+ // async getFolder() {
22603
23342
 
22604
- // check
22605
- if (!this.validURL()) return null
23343
+ // // check
23344
+ // if (!this.validURL()) return null
22606
23345
 
22607
- // wet have to add the api and service
22608
- let href = this.url.origin + '/api/folder' + this.url.pathname;
23346
+ // // wet have to add the api and service
23347
+ // let href = this.url.origin + '/api/folder' + this.url.pathname
22609
23348
 
22610
- const url = new URL(href);
23349
+ // const url = new URL(href)
22611
23350
 
22612
- // request the file - return the body
22613
- return await get(url)
22614
- .then( async response => {
23351
+ // // request the file - return the body
23352
+ // return await HTTP.get(url)
23353
+ // .then( async response => {
22615
23354
 
22616
- // the size of the body could be 0 - that is ok
22617
- if (response.headers.get('Content-Length') == '0') return null
23355
+ // // the size of the body could be 0 - that is ok
23356
+ // if (response.headers.get('Content-Length') == '0') return null
22618
23357
 
22619
- // convert
22620
- return await response.json()
22621
- })
22622
- },
23358
+ // // convert
23359
+ // return await response.json()
23360
+ // })
23361
+ // },
22623
23362
 
22624
23363
  // javascript source files can be imported
22625
23364
  async jsImport() {
@@ -22630,36 +23369,36 @@ async jsImport() {
22630
23369
  return import(this.url)
22631
23370
  },
22632
23371
 
22633
- async getFolderContent(){
23372
+ // async getFolderContent(){
22634
23373
 
22635
- const content = {
22636
- files: [],
22637
- folders: []
22638
- };
23374
+ // const content = {
23375
+ // files: [],
23376
+ // folders: []
23377
+ // }
22639
23378
 
22640
- // get the folder - return the promise
22641
- return this.getFolder()
22642
- .then( raw => {
23379
+ // // get the folder - return the promise
23380
+ // return this.getFolder()
23381
+ // .then( raw => {
22643
23382
 
22644
- // convert to arls...
22645
- content.files = raw.files.map(name => this.resolve(this.userPath + '/' + name)),
22646
- content.folders = raw.folders.map(name => this.resolve(this.userPath + '/' + name));
23383
+ // // convert to arls...
23384
+ // content.files = raw.files.map(name => this.resolve(this.userPath + '/' + name)),
23385
+ // content.folders = raw.folders.map(name => this.resolve(this.userPath + '/' + name))
22647
23386
 
22648
- // return result - that resolves the promise
22649
- return content
22650
- })
22651
- .catch (error => {
23387
+ // // return result - that resolves the promise
23388
+ // return content
23389
+ // })
23390
+ // .catch (error => {
22652
23391
 
22653
- // debug
22654
- console.error(error);
23392
+ // // debug
23393
+ // console.error(error)
22655
23394
 
22656
- // if the path was not found, fail silently else throw
22657
- if (error.options?.status != '404') throw error
23395
+ // // if the path was not found, fail silently else throw
23396
+ // if (error.options?.status != '404') throw error
22658
23397
 
22659
- // return result
22660
- return content
22661
- })
22662
- }
23398
+ // // return result
23399
+ // return content
23400
+ // })
23401
+ // }
22663
23402
  };
22664
23403
 
22665
23404
  // extractHandlersFromFile.js
@@ -23329,14 +24068,8 @@ function getEnclosingHandlerName(callExpression) {
23329
24068
  return null;
23330
24069
  }
23331
24070
 
23332
- var version = "0.3.2";
23333
- var pckg = {
23334
- version: version};
23335
-
23336
24071
  const PROFILE_VERSION = pckg.version;
23337
24072
 
23338
- // const PROFILE_VERSION = '0.2';
23339
-
23340
24073
  // The main function for the profile tool
23341
24074
  async function profile(argv = process.argv.slice(2)) {
23342
24075