circuitscript 0.5.4 → 0.5.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (62) hide show
  1. package/README.md +105 -2
  2. package/dist/cjs/BaseVisitor.js +11 -10
  3. package/dist/cjs/builtinMethods.js +6 -5
  4. package/dist/cjs/environment/environment.js +2 -2
  5. package/dist/cjs/errors.js +140 -0
  6. package/dist/cjs/execute.js +12 -5
  7. package/dist/cjs/index.js +1 -0
  8. package/dist/cjs/main.js +3 -2
  9. package/dist/cjs/objects/ClassComponent.js +4 -4
  10. package/dist/cjs/objects/ExecutionScope.js +2 -2
  11. package/dist/cjs/objects/NumericValue.js +15 -0
  12. package/dist/cjs/objects/PinDefinition.js +2 -2
  13. package/dist/cjs/objects/types.js +2 -2
  14. package/dist/cjs/parser.js +3 -2
  15. package/dist/cjs/pipeline.js +21 -14
  16. package/dist/cjs/regenerate-tests.js +6 -6
  17. package/dist/cjs/render/draw_symbols.js +17 -17
  18. package/dist/cjs/render/geometry.js +6 -6
  19. package/dist/cjs/render/layout.js +325 -253
  20. package/dist/cjs/render/render.js +21 -18
  21. package/dist/cjs/semantic-tokens/getSemanticTokens.js +2 -2
  22. package/dist/cjs/sizing.js +2 -2
  23. package/dist/cjs/utils.js +13 -110
  24. package/dist/cjs/validate/validateScript.js +2 -2
  25. package/dist/cjs/visitor.js +14 -12
  26. package/dist/esm/BaseVisitor.js +2 -1
  27. package/dist/esm/builtinMethods.js +6 -5
  28. package/dist/esm/environment/environment.js +1 -1
  29. package/dist/esm/errors.js +119 -0
  30. package/dist/esm/execute.js +10 -3
  31. package/dist/esm/index.js +1 -0
  32. package/dist/esm/main.js +3 -2
  33. package/dist/esm/objects/ClassComponent.js +1 -1
  34. package/dist/esm/objects/ExecutionScope.js +1 -1
  35. package/dist/esm/objects/NumericValue.js +15 -0
  36. package/dist/esm/objects/PinDefinition.js +1 -1
  37. package/dist/esm/objects/types.js +1 -1
  38. package/dist/esm/parser.js +2 -1
  39. package/dist/esm/pipeline.js +10 -3
  40. package/dist/esm/regenerate-tests.js +6 -6
  41. package/dist/esm/render/draw_symbols.js +15 -15
  42. package/dist/esm/render/geometry.js +6 -6
  43. package/dist/esm/render/layout.js +325 -253
  44. package/dist/esm/render/render.js +22 -19
  45. package/dist/esm/semantic-tokens/getSemanticTokens.js +1 -1
  46. package/dist/esm/sizing.js +2 -2
  47. package/dist/esm/utils.js +10 -95
  48. package/dist/esm/validate/validateScript.js +1 -1
  49. package/dist/esm/visitor.js +4 -2
  50. package/dist/libs/std.cst +31 -31
  51. package/dist/types/BaseVisitor.d.ts +3 -1
  52. package/dist/types/errors.d.ts +37 -0
  53. package/dist/types/execute.d.ts +1 -1
  54. package/dist/types/helpers.d.ts +1 -1
  55. package/dist/types/index.d.ts +1 -0
  56. package/dist/types/objects/NumericValue.d.ts +5 -1
  57. package/dist/types/render/geometry.d.ts +4 -4
  58. package/dist/types/render/layout.d.ts +7 -1
  59. package/dist/types/utils.d.ts +2 -27
  60. package/dist/types/visitor.d.ts +1 -1
  61. package/libs/std.cst +31 -31
  62. package/package.json +5 -2
@@ -5,6 +5,7 @@ import { DefaultComponentUnit, defaultFrameTitleTextSize, defaultGridSizeUnits,
5
5
  import { Geometry, HorizontalAlign, VerticalAlign } from './geometry.js';
6
6
  import { FixedFrameIds, Frame, FrameParamKeys, FramePlotDirection } from '../objects/Frame.js';
7
7
  import { areasOverlap, combineMaps, getBoundsSize, printBounds, resizeBounds, resizeToNearestGrid, toNearestGrid } from '../utils.js';
8
+ import { AutoWireFailedError_ } from "../errors.js";
8
9
  import { Direction } from '../objects/types.js';
9
10
  import { PinId } from '../objects/PinDefinition.js';
10
11
  import { milsToMM, UnitDimension } from '../helpers.js';
@@ -177,6 +178,7 @@ export class LayoutEngine {
177
178
  placeFrames(graph, subgraphInfo, frameObjects) {
178
179
  const baseFrame = frameObjects[0];
179
180
  baseFrame.padding = numeric(0);
181
+ baseFrame.gap = numeric(defaultGridSizeUnits);
180
182
  baseFrame.borderWidth = numeric(0);
181
183
  if (this.showBaseFrame) {
182
184
  baseFrame.borderWidth = numeric(5);
@@ -253,51 +255,49 @@ export class LayoutEngine {
253
255
  });
254
256
  }
255
257
  placeAndSizeFrame(frame, level = 0) {
258
+ if (level > 50) {
259
+ throw 'Exceeded placeAndSizeFrame depth limit!';
260
+ }
261
+ this.printLevel(level, `placeAndSizeFrame called`);
256
262
  const innerFrames = frame.innerItems;
257
263
  const gridSize = defaultGridSizeUnits;
258
264
  const frameDirection = frame.direction;
259
- const boundPoints = [];
260
- const frameSizes = innerFrames.map(innerFrame => {
265
+ const isFrameDirectionRow = frameDirection === FramePlotDirection.Row;
266
+ this.printLevel(level, `frame info, id: ${frame.frameId}, direction: ${frameDirection}, virtual: ${frame.virtual}`);
267
+ const frameParams = frame.frame.parameters;
268
+ let hAlign = HorizontalAlign.Center;
269
+ let vAlign = VerticalAlign.Top;
270
+ if (frameParams.has(FrameParamKeys.HorizontalAlign)) {
271
+ hAlign =
272
+ frameParams.get(FrameParamKeys.HorizontalAlign);
273
+ }
274
+ if (frameParams.has(FrameParamKeys.VerticalAlign)) {
275
+ vAlign =
276
+ frameParams.get(FrameParamKeys.VerticalAlign);
277
+ }
278
+ if (frame.overwriteAlignParamsForTitleLayout) {
279
+ hAlign = HorizontalAlign.Center;
280
+ vAlign = VerticalAlign.Top;
281
+ }
282
+ this.printLevel(level, `align params: ${hAlign} ${vAlign}`);
283
+ this.printLevel(level, `size inner frames, length: ${innerFrames.length}`);
284
+ for (const innerFrame of innerFrames) {
261
285
  if (innerFrame.renderType === RenderFrameType.Elements) {
262
- innerFrame.bounds = resizeToNearestGrid(innerFrame.bounds, gridSize);
286
+ if (!innerFrame.didResize) {
287
+ innerFrame.bounds = resizeToNearestGrid(innerFrame.bounds, gridSize);
288
+ innerFrame.didResize = true;
289
+ }
263
290
  innerFrame.translateX = innerFrame.bounds.xmin;
264
291
  innerFrame.translateY = innerFrame.bounds.ymin;
292
+ this.printLevel(level, `element frame, id: ${innerFrame.frameId}, bounds: ${JSON.stringify(innerFrame.bounds)}`);
265
293
  }
266
294
  else {
267
295
  this.placeAndSizeFrame(innerFrame, level + 1);
268
296
  }
269
- return innerFrame.bounds;
270
- });
271
- const maxWidth = Math.max(...frameSizes.map(item => {
272
- const { width } = getBoundsSize(item);
273
- return width;
274
- }));
275
- const maxHeight = Math.max(...frameSizes.map(item => {
276
- const { height } = getBoundsSize(item);
277
- return height;
278
- }));
279
- let accumRowWidth = 0;
280
- let titleFrameWidth = 0;
281
- const inRowShouldCenterInnerFrames = true;
282
- if (frameDirection === FramePlotDirection.Row) {
283
- accumRowWidth = frameSizes.reduce((accum, item, index) => {
284
- const { width } = getBoundsSize(item);
285
- if (frame.innerItems[index].containsTitle) {
286
- titleFrameWidth = width;
287
- return accum;
288
- }
289
- return accum + width +
290
- ((index + 1 < frameSizes.length) ? frame.gap.toNumber() : 0);
291
- }, 0);
292
- }
293
- else {
294
- accumRowWidth = maxWidth;
295
297
  }
298
+ this.printLevel(level, 'done sizing inner frames');
296
299
  let frameWidth = numeric(0);
297
300
  let frameHeight = numeric(0);
298
- let frameXMin = numeric(0);
299
- let frameYMin = numeric(0);
300
- const frameParams = frame.frame.parameters;
301
301
  const avoidAreas = [];
302
302
  if (frameParams.has(FrameParamKeys.SheetType)) {
303
303
  const frameComponent = frameParams.get(FrameParamKeys.SheetType);
@@ -327,6 +327,9 @@ export class LayoutEngine {
327
327
  milsToMM(y2).sub(frameMinY).toNumber(),
328
328
  ]);
329
329
  });
330
+ if (!frameParams.has(FrameParamKeys.VerticalAlign)) {
331
+ vAlign = VerticalAlign.Center;
332
+ }
330
333
  }
331
334
  else {
332
335
  if (frame.width !== null) {
@@ -336,197 +339,144 @@ export class LayoutEngine {
336
339
  frameHeight = frame.height;
337
340
  }
338
341
  }
339
- const offsetX = frame.padding;
340
- const offsetY = frame.padding;
341
- let centeredOffsetX = 0;
342
- let widthForTitle;
343
- if (frameWidth.toNumber() !== 0) {
344
- widthForTitle = frameWidth.toNumber();
345
- }
346
- else if (titleFrameWidth > accumRowWidth) {
347
- widthForTitle = titleFrameWidth;
342
+ const innerFramesWithoutTitle = innerFrames.filter(item => !item.containsTitle);
343
+ this.printLevel(level, `split into lines, width: ${frameWidth.toNumber()} height: ${frameHeight.toNumber()}, padding: ${frame.padding.toNumber()}, gap: ${frame.gap.toNumber()}, direction: ${frameDirection}`);
344
+ const frameLines = SplitIntoLines(frameWidth, frameHeight, frame.padding, frame.gap, frameDirection, innerFramesWithoutTitle, avoidAreas);
345
+ this.printLevel(level, `frame lines: ${frameLines.length}`);
346
+ if (frameLines.length > 1) {
347
+ this.printLevel(level, `split lines to containers`);
348
+ const newInnerFrames = [];
349
+ for (const line of frameLines) {
350
+ const container = RenderFrame.createContainer(frame.gap);
351
+ container.innerItems = [...line];
352
+ container.direction = frameDirection;
353
+ container.frame.parameters.set(FrameParamKeys.HorizontalAlign, hAlign);
354
+ container.frame.parameters.set(FrameParamKeys.VerticalAlign, vAlign);
355
+ if (isFrameDirectionRow) {
356
+ if (frameWidth.toNumber() !== 0) {
357
+ container.width = frameWidth.sub(frame.padding.mul(2));
358
+ }
359
+ const itemHeights = container.innerItems.map(frame => {
360
+ const bounds = frame.bounds;
361
+ return (bounds.ymax - bounds.ymin);
362
+ });
363
+ const maxHeight = Math.max(...itemHeights);
364
+ container.height = numeric(maxHeight);
365
+ this.printLevel(level, `set container size w: ${container.width}, h: ${container.height}`);
366
+ }
367
+ else {
368
+ if (frameHeight.toNumber() !== 0) {
369
+ container.height = frameHeight.sub(frame.padding.mul(2));
370
+ }
371
+ }
372
+ newInnerFrames.push(container);
373
+ }
374
+ const container = RenderFrame.createContainer(frame.gap);
375
+ container.direction = isFrameDirectionRow ? FramePlotDirection.Column : FramePlotDirection.Row;
376
+ container.innerItems = newInnerFrames;
377
+ frame.innerItems = [container];
378
+ this.placeAndSizeFrame(frame, level + 1);
348
379
  }
349
380
  else {
350
- widthForTitle = accumRowWidth;
351
- }
352
- if (frameDirection === FramePlotDirection.Row &&
353
- inRowShouldCenterInnerFrames &&
354
- titleFrameWidth !== null && titleFrameWidth > accumRowWidth) {
355
- centeredOffsetX =
356
- toNearestGrid(titleFrameWidth / 2 - accumRowWidth / 2, gridSize);
357
- }
358
- let title_align = HorizontalAlign.Middle;
359
- if (frameParams.has(FrameParamKeys.TitleAlign)) {
360
- title_align = frameParams.get(FrameParamKeys.TitleAlign);
361
- }
362
- let accumX = numeric(0);
363
- let accumY = numeric(0);
364
- innerFrames.forEach((innerFrame, index) => {
365
- const { width: innerFrameWidth, height: innerFrameHeight } = getBoundsSize(innerFrame.bounds);
366
- let arrangeLineAttempts = 0;
367
- const maxAttempts = 10;
368
- let innerFrameX = numeric(0);
369
- let innerFrameY = numeric(0);
370
- if (innerFrame.containsTitle) {
371
- innerFrame.x = offsetX.add(accumX);
372
- innerFrame.y = offsetY.add(accumY);
373
- accumY = accumY.add(innerFrameHeight).add(frame.gap);
381
+ let accumValue = frame.padding.copy();
382
+ const bounds = [];
383
+ for (const innerFrame of innerFrames) {
384
+ const { width: innerFrameWidth, height: innerFrameHeight } = getBoundsSize(innerFrame.bounds);
385
+ if (isFrameDirectionRow) {
386
+ innerFrame.x = accumValue.copy();
387
+ innerFrame.y = frame.padding.copy();
388
+ accumValue = accumValue.add(innerFrameWidth).add(frame.gap);
389
+ }
390
+ else {
391
+ innerFrame.x = frame.padding.copy();
392
+ innerFrame.y = accumValue.copy();
393
+ accumValue = accumValue.add(innerFrameHeight).add(frame.gap);
394
+ }
395
+ bounds.push([innerFrame.x.toNumber(), innerFrame.y.toNumber()], [
396
+ innerFrame.x.add(innerFrameWidth).toNumber(),
397
+ innerFrame.y.add(innerFrameHeight).toNumber(),
398
+ ]);
374
399
  }
375
- else {
376
- if (frameDirection === FramePlotDirection.Column) {
377
- innerFrameX = offsetX.add(accumX);
378
- innerFrameY = offsetY.add(accumY);
379
- while (arrangeLineAttempts < maxAttempts) {
380
- const innerFrameY2 = innerFrameY.toNumber() + innerFrameHeight;
381
- const doesExceedFrameHeight = (frameHeight.toNumber() > 0
382
- && innerFrameY2 > frameHeight.toNumber());
383
- const { xmax } = getBoundsFromPoints(boundPoints);
384
- const tmpX1 = innerFrameX.toNumber();
385
- const tmpY1 = innerFrameY.toNumber();
386
- const tmpX2 = tmpX1 + innerFrameWidth;
387
- const tmpY2 = tmpY1 + innerFrameHeight;
388
- const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
389
- const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
390
- const doesOverlapAreasToAvoid = overlaps.length > 0;
391
- if (boundPoints.length > 0 && (doesExceedFrameHeight || doesOverlapAreasToAvoid)) {
392
- innerFrameY = offsetY;
393
- const nextX = numeric(xmax).sub(offsetX).add(frame.gap);
394
- innerFrameX = offsetX.add(nextX);
395
- accumY = numeric(0);
396
- accumX = nextX;
397
- }
398
- arrangeLineAttempts++;
399
- if (arrangeLineAttempts > maxAttempts) {
400
- throw "Failed to place inner frame";
401
- }
400
+ const frameInnerBounds = getBoundsFromPoints(bounds);
401
+ const contentsPaddedBounds = resizeBounds(frameInnerBounds, frame.padding.toNumber());
402
+ const contentsPaddedWidth = roundValue(contentsPaddedBounds.xmax - contentsPaddedBounds.xmin).toNumber();
403
+ const contentsPaddedHeight = roundValue(contentsPaddedBounds.ymax - contentsPaddedBounds.ymin).toNumber();
404
+ const contentsWidth = roundValue(frameInnerBounds.xmax - frameInnerBounds.xmin).toNumber();
405
+ const contentsHeight = roundValue(frameInnerBounds.ymax - frameInnerBounds.ymin).toNumber();
406
+ if (frameWidth.toNumber() === 0) {
407
+ frameWidth = numeric(contentsPaddedWidth);
408
+ }
409
+ if (frameHeight.toNumber() === 0) {
410
+ frameHeight = numeric(contentsPaddedHeight);
411
+ }
412
+ frame.bounds = {
413
+ xmin: contentsPaddedBounds.xmin,
414
+ xmax: contentsPaddedBounds.xmin + frameWidth.toNumber(),
415
+ ymin: contentsPaddedBounds.ymin,
416
+ ymax: contentsPaddedBounds.ymin + frameHeight.toNumber(),
417
+ };
418
+ this.printLevel(level, `alignment h: ${hAlign}, v: ${vAlign}`);
419
+ const tmpFrameWidth = frameWidth.sub(frame.padding.mul(2));
420
+ const tmpFrameHeight = frameHeight.sub(frame.padding.mul(2));
421
+ this.printLevel(level, `inner frame size, width: ${tmpFrameWidth}, height: ${tmpFrameHeight}`);
422
+ let offsetX = 0;
423
+ let offsetY = 0;
424
+ if (isFrameDirectionRow) {
425
+ switch (hAlign) {
426
+ case HorizontalAlign.Left:
427
+ offsetX = 0;
428
+ break;
429
+ case HorizontalAlign.Center:
430
+ offsetX = toNearestGrid(tmpFrameWidth.sub(contentsWidth).div(2).toNumber(), gridSize);
431
+ break;
432
+ case HorizontalAlign.Right:
433
+ offsetX = toNearestGrid(tmpFrameWidth.sub(contentsWidth).toNumber(), gridSize);
434
+ break;
435
+ }
436
+ offsetX = roundValue(offsetX).toNumber();
437
+ offsetY = 0;
438
+ for (const innerFrame of innerFrames) {
439
+ const { height: innerFrameHeight } = getBoundsSize(innerFrame.bounds);
440
+ if (vAlign === VerticalAlign.Center) {
441
+ offsetY = toNearestGrid(tmpFrameHeight.sub(innerFrameHeight).div(2).toNumber(), gridSize);
442
+ }
443
+ else if (vAlign === VerticalAlign.Bottom) {
444
+ offsetY = toNearestGrid(tmpFrameHeight.sub(innerFrameHeight).toNumber(), gridSize);
402
445
  }
403
- innerFrame.x = innerFrameX;
404
- innerFrame.y = innerFrameY;
405
- accumY = accumY.add(innerFrameHeight).add(frame.gap);
446
+ offsetY = roundValue(offsetY).toNumber();
447
+ innerFrame.x = innerFrame.x.add(offsetX);
448
+ innerFrame.y = innerFrame.y.add(offsetY);
406
449
  }
407
- else if (frameDirection === FramePlotDirection.Row) {
408
- innerFrameX = offsetX.add(centeredOffsetX).add(accumX);
409
- innerFrameY = offsetY.add(accumY);
410
- while (arrangeLineAttempts < maxAttempts) {
411
- const innerFrameX2 = innerFrameX.toNumber() + innerFrameWidth;
412
- const doesExceedFrameWidth = (frameWidth.toNumber() > 0
413
- && innerFrameX2 > frameWidth.toNumber());
414
- const tmpX1 = innerFrameX.toNumber();
415
- const tmpY1 = innerFrameY.toNumber();
416
- const tmpX2 = tmpX1 + innerFrameWidth;
417
- const tmpY2 = tmpY1 + innerFrameHeight;
418
- const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
419
- const overlaps = avoidAreas.filter(area => areasOverlap(frameArea, area));
420
- const doesOverlapAreasToAvoid = overlaps.length > 0;
421
- if (boundPoints.length > 0 && (doesExceedFrameWidth || doesOverlapAreasToAvoid)) {
422
- innerFrameX = offsetX.add(centeredOffsetX);
423
- const { ymax } = getBoundsFromPoints(boundPoints);
424
- const nextY = numeric(ymax).sub(offsetY).add(frame.gap);
425
- innerFrameY = offsetY.add(nextY);
426
- accumX = numeric(0);
427
- accumY = nextY;
428
- }
429
- else {
430
- break;
431
- }
432
- arrangeLineAttempts++;
433
- if (arrangeLineAttempts > maxAttempts) {
434
- throw "Failed to place inner frame";
435
- }
450
+ }
451
+ else {
452
+ switch (vAlign) {
453
+ case VerticalAlign.Top:
454
+ offsetY = 0;
455
+ break;
456
+ case VerticalAlign.Center:
457
+ offsetY = toNearestGrid(tmpFrameHeight.sub(contentsHeight).div(2).toNumber(), gridSize);
458
+ break;
459
+ case VerticalAlign.Bottom:
460
+ offsetY = toNearestGrid(tmpFrameHeight.sub(contentsHeight).toNumber(), gridSize);
461
+ break;
462
+ }
463
+ offsetX = 0;
464
+ offsetY = roundValue(offsetY).toNumber();
465
+ for (const innerFrame of innerFrames) {
466
+ const { width: innerFrameHeight } = getBoundsSize(innerFrame.bounds);
467
+ if (hAlign === HorizontalAlign.Center) {
468
+ offsetX = toNearestGrid(tmpFrameWidth.sub(innerFrameHeight).div(2).toNumber(), gridSize);
436
469
  }
437
- innerFrame.x = innerFrameX;
438
- innerFrame.y = innerFrameY;
439
- accumX = accumX.add(innerFrameWidth).add(frame.gap);
470
+ else if (hAlign === HorizontalAlign.Right) {
471
+ offsetX = toNearestGrid(tmpFrameWidth.sub(innerFrameHeight).toNumber(), gridSize);
472
+ }
473
+ offsetX = roundValue(offsetX).toNumber();
474
+ innerFrame.x = innerFrame.x.add(offsetX);
475
+ innerFrame.y = innerFrame.y.add(offsetY);
440
476
  }
441
477
  }
442
- boundPoints.push([
443
- innerFrame.x.toNumber(),
444
- innerFrame.y.toNumber()
445
- ], [
446
- innerFrame.x.add(innerFrameWidth).toNumber(),
447
- innerFrame.y.add(innerFrameHeight).toNumber()
448
- ]);
449
- });
450
- const contentsBounds = resizeBounds(getBoundsFromPoints(boundPoints), frame.padding.toNumber());
451
- const contentsWidth = contentsBounds.xmax - contentsBounds.xmin;
452
- const contentsHeight = contentsBounds.ymax - contentsBounds.ymin;
453
- let hAlign = HorizontalAlign.Middle;
454
- let vAlign = VerticalAlign.Middle;
455
- if (frameParams.has(FrameParamKeys.HorizontalAlign)) {
456
- hAlign =
457
- frameParams.get(FrameParamKeys.HorizontalAlign);
458
478
  }
459
- if (frameParams.has(FrameParamKeys.VerticalAlign)) {
460
- vAlign =
461
- frameParams.get(FrameParamKeys.VerticalAlign);
462
- }
463
- if (frameParams.has(FrameParamKeys.SheetType)) {
464
- frameXMin = numeric(0);
465
- frameYMin = numeric(0);
466
- }
467
- else {
468
- frameXMin = numeric(contentsBounds.xmin);
469
- frameYMin = numeric(contentsBounds.ymin);
470
- }
471
- if (frameWidth.toNumber() === 0) {
472
- frameWidth = numeric(contentsWidth);
473
- }
474
- if (frameHeight.toNumber() === 0) {
475
- frameHeight = numeric(contentsHeight);
476
- }
477
- const titleFrame = innerFrames.find(frame => {
478
- return frame.containsTitle;
479
- });
480
- if (titleFrame) {
481
- const { width: innerFrameWidth } = getBoundsSize(titleFrame.bounds);
482
- let titleOffset = 0;
483
- switch (title_align) {
484
- case HorizontalAlign.Left:
485
- titleOffset = 0;
486
- break;
487
- case HorizontalAlign.Middle:
488
- titleOffset = toNearestGrid(widthForTitle / 2 - innerFrameWidth / 2, gridSize);
489
- break;
490
- case HorizontalAlign.Right:
491
- titleOffset = frameWidth.toNumber() - innerFrameWidth;
492
- break;
493
- }
494
- titleFrame.x = titleFrame.x.add(titleOffset);
495
- }
496
- let frameOffsetX = 0;
497
- let frameOffsetY = 0;
498
- switch (hAlign) {
499
- case HorizontalAlign.Left:
500
- frameOffsetX = 0;
501
- break;
502
- case HorizontalAlign.Middle:
503
- frameOffsetX = toNearestGrid((frameWidth.toNumber() - contentsWidth) / 2, gridSize);
504
- break;
505
- case HorizontalAlign.Right:
506
- frameOffsetX = toNearestGrid(frameWidth.toNumber() - contentsWidth, gridSize);
507
- break;
508
- }
509
- switch (vAlign) {
510
- case VerticalAlign.Top:
511
- frameOffsetY = 0;
512
- break;
513
- case VerticalAlign.Middle:
514
- frameOffsetY = toNearestGrid((frameHeight.toNumber() - contentsHeight) / 2, gridSize);
515
- break;
516
- case VerticalAlign.Bottom:
517
- frameOffsetY = toNearestGrid(frameHeight.toNumber() - contentsHeight, gridSize);
518
- break;
519
- }
520
- innerFrames.forEach(innerFrame => {
521
- innerFrame.x = innerFrame.x.add(frameOffsetX);
522
- innerFrame.y = innerFrame.y.add(frameOffsetY);
523
- });
524
- frame.bounds = {
525
- xmin: frameXMin.toNumber(),
526
- ymin: frameYMin.toNumber(),
527
- xmax: frameXMin.toNumber() + frameWidth.toNumber(),
528
- ymax: frameYMin.toNumber() + frameHeight.toNumber(),
529
- };
479
+ return;
530
480
  }
531
481
  dumpFrame(frame, level = 0) {
532
482
  this.print(level, "".padStart(level * 4), 'frame, items:', frame.innerItems.length);
@@ -593,33 +543,80 @@ export class LayoutEngine {
593
543
  };
594
544
  }
595
545
  checkAddFrameTitle(frame, elementFrames, textObjects, level) {
596
- if (frame.renderType === RenderFrameType.Container) {
597
- const frameObject = frame.frame;
598
- const isSheetFrame = frameObject.frameType === FrameType.Sheet;
599
- if (frameObject.parameters.has(FrameParamKeys.Title) && !isSheetFrame) {
600
- const title = frameObject.parameters.get(FrameParamKeys.Title);
601
- const tmpFrame = new RenderFrame(new Frame(FixedFrameIds.FrameIdNotUsed), RenderFrameType.Elements);
602
- tmpFrame.containsTitle = true;
603
- tmpFrame.subgraphId = title.replace(/\s/g, "_");
604
- const textObject = new RenderText(title);
605
- textObject.fontSize = numeric(defaultFrameTitleTextSize);
606
- textObject.fontWeight = 'bold';
607
- textObject.symbol.refreshDrawing();
608
- tmpFrame.innerItems.push(textObject);
609
- const tmpBox = textObject.symbol.drawing.getBoundingBox();
610
- tmpFrame.bounds = {
611
- xmin: tmpBox.start[0],
612
- ymin: tmpBox.start[1],
613
- xmax: tmpBox.start[0] + tmpBox.width,
614
- ymax: tmpBox.start[1] + tmpBox.height
615
- };
616
- textObject.x = numeric(0);
617
- textObject.y = numeric(0);
618
- frame.innerItems.splice(0, 0, tmpFrame);
619
- this.printLevel(level, frame, 'added text', tmpFrame);
620
- textObjects.push(textObject);
621
- elementFrames.splice(0, 0, tmpFrame);
546
+ if (frame.renderType !== RenderFrameType.Container) {
547
+ return;
548
+ }
549
+ const frameObject = frame.frame;
550
+ const frameParams = frame.frame.parameters;
551
+ const isSheetFrame = frameObject.frameType === FrameType.Sheet;
552
+ if (frameParams.has(FrameParamKeys.Title) && !isSheetFrame) {
553
+ const title = frameParams.get(FrameParamKeys.Title);
554
+ const titleFrame = new RenderFrame(new Frame(FixedFrameIds.FrameIdNotUsed), RenderFrameType.Elements);
555
+ titleFrame.containsTitle = true;
556
+ titleFrame.subgraphId = title.replace(/\s/g, "_");
557
+ const textObject = new RenderText(title);
558
+ textObject.fontSize = numeric(defaultFrameTitleTextSize);
559
+ textObject.fontWeight = 'bold';
560
+ textObject.x = numeric(0);
561
+ textObject.y = numeric(0);
562
+ textObject.symbol.refreshDrawing();
563
+ titleFrame.innerItems = [textObject];
564
+ const tmpBox = textObject.symbol.drawing.getBoundingBox();
565
+ const tmpBounds = {
566
+ xmin: tmpBox.start[0],
567
+ ymin: tmpBox.start[1],
568
+ xmax: tmpBox.start[0] + tmpBox.width,
569
+ ymax: tmpBox.start[1] + tmpBox.height
570
+ };
571
+ titleFrame.bounds = resizeToNearestGrid(tmpBounds, defaultGridSizeUnits);
572
+ titleFrame.didResize = true;
573
+ const titleFrameContainer = RenderFrame.createContainer(numeric(0));
574
+ titleFrameContainer.innerItems = [titleFrame];
575
+ if (frameParams.has(FrameParamKeys.TitleAlign)) {
576
+ const alignValue = frameParams.get(FrameParamKeys.TitleAlign);
577
+ titleFrameContainer.frame.parameters.set(FrameParamKeys.HorizontalAlign, alignValue);
578
+ }
579
+ const container = RenderFrame.createContainer(frame.gap);
580
+ container.direction = frame.direction;
581
+ container.innerItems = [...frame.innerItems];
582
+ let hAlign = HorizontalAlign.Center;
583
+ let vAlign = VerticalAlign.Center;
584
+ if (frameParams.has(FrameParamKeys.HorizontalAlign)) {
585
+ hAlign =
586
+ frameParams.get(FrameParamKeys.HorizontalAlign);
587
+ }
588
+ if (frameParams.has(FrameParamKeys.VerticalAlign)) {
589
+ vAlign =
590
+ frameParams.get(FrameParamKeys.VerticalAlign);
591
+ }
592
+ container.frame.parameters.set(FrameParamKeys.HorizontalAlign, hAlign);
593
+ container.frame.parameters.set(FrameParamKeys.VerticalAlign, vAlign);
594
+ const columnLayoutContainer = RenderFrame.createContainer(numeric(defaultGridSizeUnits));
595
+ columnLayoutContainer.direction = FramePlotDirection.Column;
596
+ columnLayoutContainer.innerItems = [
597
+ titleFrameContainer,
598
+ container,
599
+ ];
600
+ const frameWidth = frame.width ?? numeric(0);
601
+ if (frameWidth.toNumber() !== 0) {
602
+ columnLayoutContainer.width = frameWidth.sub(frame.padding.mul(2));
603
+ container.width = columnLayoutContainer.width.copy();
604
+ titleFrameContainer.width = columnLayoutContainer.width.copy();
622
605
  }
606
+ const frameHeight = frame.height ?? numeric(0);
607
+ if (frameHeight.toNumber() !== 0) {
608
+ columnLayoutContainer.height = frameHeight.sub(frame.padding.mul(2));
609
+ const { height: titleFrameHeight } = getBoundsSize(titleFrame.bounds);
610
+ container.height = columnLayoutContainer.height
611
+ .sub(titleFrameHeight)
612
+ .sub(columnLayoutContainer.gap);
613
+ }
614
+ frame.innerItems = [columnLayoutContainer];
615
+ frame.overwriteAlignParamsForTitleLayout = true;
616
+ columnLayoutContainer.overwriteAlignParamsForTitleLayout = true;
617
+ this.printLevel(level, frame, 'added text', titleFrame);
618
+ textObjects.push(textObject);
619
+ elementFrames.splice(0, 0, titleFrame);
623
620
  }
624
621
  }
625
622
  sizeSubGraphs(graph) {
@@ -779,7 +776,7 @@ export class LayoutEngine {
779
776
  const targetOriginNode = findOriginNode(targetNode);
780
777
  const itemOriginNode = findOriginNode(item);
781
778
  if (targetOriginNode !== itemOriginNode) {
782
- throw "Wire auto length failed. Please specify a fixed wire length.";
779
+ throw new AutoWireFailedError_("Wire auto length failed. Please specify a fixed wire length.", item.wire);
783
780
  }
784
781
  const [untilX, untilY] = getNodePositionAtPin(targetNode, pin);
785
782
  item.setEndAuto(untilX, untilY);
@@ -915,17 +912,6 @@ function getNodePositionAtPin(item, pin) {
915
912
  roundValue(x), roundValue(y)
916
913
  ];
917
914
  }
918
- function getNeighbours(graph, nodeIds) {
919
- return nodeIds.reduce((accum, nodeId) => {
920
- const tmp = graph.neighbors(nodeId);
921
- if (tmp) {
922
- tmp.forEach(neighborNodeId => {
923
- accum.push([nodeId, neighborNodeId]);
924
- });
925
- }
926
- return accum;
927
- }, []);
928
- }
929
915
  export function applyComponentParamsToSymbol(componentUnit, symbol) {
930
916
  const { widthProp = null, heightProp = null } = componentUnit;
931
917
  const newMap = new Map(componentUnit.parameters);
@@ -1255,19 +1241,25 @@ export class RenderFrame extends RenderObject {
1255
1241
  padding = milsToMM(100);
1256
1242
  gap = milsToMM(100);
1257
1243
  borderWidth = numeric(5);
1244
+ borderColor = "#111";
1258
1245
  direction = FramePlotDirection.Row;
1259
1246
  width = null;
1260
1247
  height = null;
1261
1248
  subgraphId = "";
1262
1249
  renderType;
1263
1250
  containsTitle = false;
1251
+ overwriteAlignParamsForTitleLayout = false;
1252
+ virtual = false;
1253
+ didResize = false;
1254
+ lineIndex = 0;
1264
1255
  frameId;
1265
- constructor(frame, type = RenderFrameType.Container) {
1256
+ constructor(frame, type = RenderFrameType.Container, virtual = false) {
1266
1257
  super();
1267
1258
  this.frame = frame;
1268
1259
  this.renderType = type;
1269
1260
  this.frameId = RenderFrame.FrameIdCounter;
1270
1261
  RenderFrame.FrameIdCounter++;
1262
+ this.virtual = virtual;
1271
1263
  }
1272
1264
  toString() {
1273
1265
  let name = "";
@@ -1280,6 +1272,13 @@ export class RenderFrame extends RenderObject {
1280
1272
  return name + ": " + this.x + "," + this.y
1281
1273
  + " bounds:" + (this.bounds && printBounds(this.bounds));
1282
1274
  }
1275
+ static createContainer(gap) {
1276
+ const tmpFrame = new RenderFrame(new Frame(FixedFrameIds.FrameIdNotUsed), RenderFrameType.Container, true);
1277
+ tmpFrame.gap = gap.copy();
1278
+ tmpFrame.borderWidth = numeric(0);
1279
+ tmpFrame.padding = numeric(0);
1280
+ return tmpFrame;
1281
+ }
1283
1282
  }
1284
1283
  export var RenderFrameType;
1285
1284
  (function (RenderFrameType) {
@@ -1338,3 +1337,76 @@ export function ExtractDrawingRects(drawing) {
1338
1337
  function isPointOverlap(x, y, other) {
1339
1338
  return (x >= other.x && y >= other.y && x <= (other.x + other.width) && y <= (other.y + other.height));
1340
1339
  }
1340
+ function SplitIntoLines(frameWidth, frameHeight, framePadding, frameGap, frameDirection, innerFrames, avoidAreas) {
1341
+ if (frameWidth.toNumber() === 0) {
1342
+ frameWidth = numeric(1e24);
1343
+ }
1344
+ if (frameHeight.toNumber() === 0) {
1345
+ frameHeight = numeric(1e24);
1346
+ }
1347
+ const allGroups = [];
1348
+ let currentGroup = [];
1349
+ const tmpFrameWidth = frameWidth.sub(framePadding.mul(2)).toNumber();
1350
+ const tmpFrameHeight = frameHeight.sub(framePadding.mul(2)).toNumber();
1351
+ const isRowDirection = frameDirection === FramePlotDirection.Row;
1352
+ const dimensionLimit = isRowDirection ? tmpFrameWidth : tmpFrameHeight;
1353
+ let accumX = numeric(0);
1354
+ let accumY = numeric(0);
1355
+ const framePaddingValue = framePadding.toNumber();
1356
+ avoidAreas = avoidAreas.map(bounds => {
1357
+ return [
1358
+ bounds[0] - framePaddingValue,
1359
+ bounds[1] - framePaddingValue,
1360
+ bounds[2] - framePaddingValue,
1361
+ bounds[3] - framePaddingValue
1362
+ ];
1363
+ });
1364
+ for (const innerFrame of innerFrames) {
1365
+ const { width: innerFrameWidth, height: innerFrameHeight } = getBoundsSize(innerFrame.bounds);
1366
+ const tmpX1 = accumX.toNumber();
1367
+ const tmpY1 = accumY.toNumber();
1368
+ const tmpX2 = tmpX1 + innerFrameWidth;
1369
+ const tmpY2 = tmpY1 + innerFrameHeight;
1370
+ const frameArea = [tmpX1, tmpY1, tmpX2, tmpY2];
1371
+ const conditionOverlapAvoidAreas = avoidAreas.filter(area => areasOverlap(frameArea, area)).length > 0;
1372
+ if (isRowDirection) {
1373
+ const tmpX = accumX.add(innerFrameWidth).toNumber();
1374
+ const conditionExceedDimension = tmpX > dimensionLimit;
1375
+ if ((conditionExceedDimension || conditionOverlapAvoidAreas) && currentGroup.length > 0) {
1376
+ allGroups.push(currentGroup);
1377
+ const heightsInLine = currentGroup.map(item => item.height);
1378
+ const maxHeight = Math.max(...heightsInLine);
1379
+ accumX = numeric(0);
1380
+ accumY = accumY.add(frameGap).add(maxHeight);
1381
+ currentGroup = [];
1382
+ }
1383
+ accumX = accumX.add(innerFrameWidth).add(frameGap);
1384
+ }
1385
+ else {
1386
+ const tmpY = accumY.add(innerFrameHeight).toNumber();
1387
+ const conditionExistDimension = tmpY > dimensionLimit;
1388
+ if ((conditionExistDimension || conditionOverlapAvoidAreas) && currentGroup.length > 0) {
1389
+ allGroups.push(currentGroup);
1390
+ const widthsInLine = currentGroup.map(item => item.width);
1391
+ const maxWidth = Math.max(...widthsInLine);
1392
+ accumX = accumX.add(frameGap).add(maxWidth);
1393
+ accumY = numeric(0);
1394
+ currentGroup = [];
1395
+ }
1396
+ accumY = accumY.add(innerFrameHeight).add(frameGap);
1397
+ }
1398
+ currentGroup.push({
1399
+ x: accumX.toNumber(),
1400
+ y: accumY.toNumber(),
1401
+ width: innerFrameWidth,
1402
+ height: innerFrameHeight,
1403
+ frame: innerFrame
1404
+ });
1405
+ }
1406
+ if (currentGroup.length > 0) {
1407
+ allGroups.push(currentGroup);
1408
+ }
1409
+ return allGroups.map(lines => {
1410
+ return lines.map(layoutItem => layoutItem.frame);
1411
+ });
1412
+ }