@rocketshow/designer 1.42.0 → 1.44.0

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.
@@ -26,15 +26,16 @@ import * as i3$2 from '@angular/forms';
26
26
  import { FormsModule } from '@angular/forms';
27
27
  import * as i11 from 'ngx-bootstrap/popover';
28
28
  import { PopoverModule } from 'ngx-bootstrap/popover';
29
- import * as i7 from 'ngx-sortablejs-plus';
30
- import { SortablejsModule } from 'ngx-sortablejs-plus';
31
29
  import * as i10 from 'ngx-bootstrap/typeahead';
32
30
  import { TypeaheadModule } from 'ngx-bootstrap/typeahead';
33
31
  import * as i4$1 from 'ngx-bootstrap-slider';
34
32
  import { NgxBootstrapSliderModule } from 'ngx-bootstrap-slider';
35
- import * as i8 from '@angular/common';
33
+ import * as i9 from '@angular/common';
34
+ import * as i7 from 'ngx-sortablejs-plus';
35
+ import { SortablejsModule } from 'ngx-sortablejs-plus';
36
36
  import * as i5$1 from 'ngx-bootstrap/accordion';
37
37
  import { AccordionModule } from 'ngx-bootstrap/accordion';
38
+ import { KEYS, TREE_ACTIONS, TreeModule } from '@ali-hm/angular-tree-component';
38
39
  import { BrowserModule } from '@angular/platform-browser';
39
40
  import { BrowserAnimationsModule } from '@angular/platform-browser/animations';
40
41
 
@@ -1363,7 +1364,10 @@ class FixtureService {
1363
1364
  }
1364
1365
  else if (repeatFor[0] === 'eachPixelABC') {
1365
1366
  // Gets computed into an alphanumerically sorted list of all pixelKeys
1366
- if (profile.matrix.pixelCount.length === 3) {
1367
+ if (profile.matrix.pixelKeys) {
1368
+ result = result.concat(this.getAllPixelKeys(profile));
1369
+ }
1370
+ else if (profile.matrix.pixelCount.length === 3) {
1367
1371
  for (let x = 0; x < profile.matrix.pixelCount[0]; x++) {
1368
1372
  for (let y = 0; y < profile.matrix.pixelCount[1]; y++) {
1369
1373
  for (let z = 0; z < profile.matrix.pixelCount[2]; z++) {
@@ -1372,9 +1376,6 @@ class FixtureService {
1372
1376
  }
1373
1377
  }
1374
1378
  }
1375
- else {
1376
- result = result.concat(this.getAllPixelKeys(profile));
1377
- }
1378
1379
  result.sort(this.alphanumericSort);
1379
1380
  }
1380
1381
  else if (repeatFor[0] === 'eachPixelGroup') {
@@ -1382,72 +1383,138 @@ class FixtureService {
1382
1383
  result = result.concat(this.getAllPixelGroups(profile));
1383
1384
  }
1384
1385
  else if (repeatFor[0] === 'eachPixelXYZ') {
1385
- for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1386
- for (let y = 0; y < profile.matrix.pixelKeys[x].length; y++) {
1387
- for (let z = 0; z < profile.matrix.pixelKeys[x][y].length; z++) {
1388
- const pixel = profile.matrix.pixelKeys[x][y][z];
1389
- if (pixel) {
1390
- result.push(pixel);
1386
+ if (profile.matrix.pixelKeys) {
1387
+ for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1388
+ for (let y = 0; y < profile.matrix.pixelKeys[x].length; y++) {
1389
+ for (let z = 0; z < profile.matrix.pixelKeys[x][y].length; z++) {
1390
+ const pixel = profile.matrix.pixelKeys[x][y][z];
1391
+ if (pixel) {
1392
+ result.push(pixel);
1393
+ }
1394
+ }
1395
+ }
1396
+ }
1397
+ }
1398
+ else if (profile.matrix.pixelCount.length === 3) {
1399
+ for (let x = 0; x < profile.matrix.pixelCount[0]; x++) {
1400
+ for (let y = 0; y < profile.matrix.pixelCount[1]; y++) {
1401
+ for (let z = 0; z < profile.matrix.pixelCount[2]; z++) {
1402
+ result.push('Pixel ' + (x + 1) + '-' + (y + 1) + '-' + (z + 1));
1391
1403
  }
1392
1404
  }
1393
1405
  }
1394
1406
  }
1395
1407
  }
1396
1408
  else if (repeatFor[0] === 'eachPixelXZY') {
1397
- for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1398
- for (let z = 0; z < profile.matrix.pixelKeys[x][0].length; z++) {
1399
- for (let y = 0; y < profile.matrix.pixelKeys[x].length; y++) {
1400
- const pixel = profile.matrix.pixelKeys[x][y][z];
1401
- if (pixel) {
1402
- result.push(pixel);
1409
+ if (profile.matrix.pixelKeys) {
1410
+ for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1411
+ for (let z = 0; z < profile.matrix.pixelKeys[x][0].length; z++) {
1412
+ for (let y = 0; y < profile.matrix.pixelKeys[x].length; y++) {
1413
+ const pixel = profile.matrix.pixelKeys[x][y][z];
1414
+ if (pixel) {
1415
+ result.push(pixel);
1416
+ }
1417
+ }
1418
+ }
1419
+ }
1420
+ }
1421
+ else if (profile.matrix.pixelCount.length === 3) {
1422
+ for (let x = 0; x < profile.matrix.pixelCount[0]; x++) {
1423
+ for (let z = 0; z < profile.matrix.pixelCount[2]; z++) {
1424
+ for (let y = 0; y < profile.matrix.pixelCount[1]; y++) {
1425
+ result.push('Pixel ' + (x + 1) + '-' + (y + 1) + '-' + (z + 1));
1403
1426
  }
1404
1427
  }
1405
1428
  }
1406
1429
  }
1407
1430
  }
1408
1431
  else if (repeatFor[0] === 'eachPixelYXZ') {
1409
- for (let y = 0; y < profile.matrix.pixelKeys[0].length; y++) {
1410
- for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1411
- for (let z = 0; z < profile.matrix.pixelKeys[x][y].length; z++) {
1412
- const pixel = profile.matrix.pixelKeys[x][y][z];
1413
- if (pixel) {
1414
- result.push(pixel);
1432
+ if (profile.matrix.pixelKeys) {
1433
+ for (let y = 0; y < profile.matrix.pixelKeys[0].length; y++) {
1434
+ for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1435
+ for (let z = 0; z < profile.matrix.pixelKeys[x][y].length; z++) {
1436
+ const pixel = profile.matrix.pixelKeys[x][y][z];
1437
+ if (pixel) {
1438
+ result.push(pixel);
1439
+ }
1440
+ }
1441
+ }
1442
+ }
1443
+ }
1444
+ else if (profile.matrix.pixelCount.length === 3) {
1445
+ for (let y = 0; y < profile.matrix.pixelCount[1]; y++) {
1446
+ for (let x = 0; x < profile.matrix.pixelCount[0]; x++) {
1447
+ for (let z = 0; z < profile.matrix.pixelCount[2]; z++) {
1448
+ result.push('Pixel ' + (x + 1) + '-' + (y + 1) + '-' + (z + 1));
1415
1449
  }
1416
1450
  }
1417
1451
  }
1418
1452
  }
1419
1453
  }
1420
1454
  else if (repeatFor[0] === 'eachPixelYZX') {
1421
- for (let y = 0; y < profile.matrix.pixelKeys[0].length; y++) {
1422
- for (let z = 0; z < profile.matrix.pixelKeys[0][y].length; z++) {
1423
- for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1424
- const pixel = profile.matrix.pixelKeys[x][y][z];
1425
- if (pixel) {
1426
- result.push(pixel);
1455
+ if (profile.matrix.pixelKeys) {
1456
+ for (let y = 0; y < profile.matrix.pixelKeys[0].length; y++) {
1457
+ for (let z = 0; z < profile.matrix.pixelKeys[0][y].length; z++) {
1458
+ for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1459
+ const pixel = profile.matrix.pixelKeys[x][y][z];
1460
+ if (pixel) {
1461
+ result.push(pixel);
1462
+ }
1463
+ }
1464
+ }
1465
+ }
1466
+ }
1467
+ else if (profile.matrix.pixelCount.length === 3) {
1468
+ for (let y = 0; y < profile.matrix.pixelCount[1]; y++) {
1469
+ for (let z = 0; z < profile.matrix.pixelCount[2]; z++) {
1470
+ for (let x = 0; x < profile.matrix.pixelCount[0]; x++) {
1471
+ result.push('Pixel ' + (x + 1) + '-' + (y + 1) + '-' + (z + 1));
1427
1472
  }
1428
1473
  }
1429
1474
  }
1430
1475
  }
1431
1476
  }
1432
1477
  else if (repeatFor[0] === 'eachPixelZXY') {
1433
- for (let z = 0; z < profile.matrix.pixelKeys[0][0].length; z++) {
1434
- for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1435
- for (let y = 0; y < profile.matrix.pixelKeys[x].length; y++) {
1436
- const pixel = profile.matrix.pixelKeys[x][y][z];
1437
- if (pixel) {
1438
- result.push(pixel);
1478
+ if (profile.matrix.pixelKeys) {
1479
+ for (let z = 0; z < profile.matrix.pixelKeys[0][0].length; z++) {
1480
+ for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1481
+ for (let y = 0; y < profile.matrix.pixelKeys[x].length; y++) {
1482
+ const pixel = profile.matrix.pixelKeys[x][y][z];
1483
+ if (pixel) {
1484
+ result.push(pixel);
1485
+ }
1486
+ }
1487
+ }
1488
+ }
1489
+ }
1490
+ else if (profile.matrix.pixelCount.length === 3) {
1491
+ for (let z = 0; z < profile.matrix.pixelCount[2]; z++) {
1492
+ for (let x = 0; x < profile.matrix.pixelCount[0]; x++) {
1493
+ for (let y = 0; y < profile.matrix.pixelCount[1]; y++) {
1494
+ result.push('Pixel ' + (x + 1) + '-' + (y + 1) + '-' + (z + 1));
1439
1495
  }
1440
1496
  }
1441
1497
  }
1442
1498
  }
1443
1499
  }
1444
1500
  else if (repeatFor[0] === 'eachPixelZYX') {
1445
- for (let z = 0; z < profile.matrix.pixelKeys[0][0].length; z++) {
1446
- for (let y = 0; y < profile.matrix.pixelKeys[0].length; y++) {
1447
- for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1448
- const pixel = profile.matrix.pixelKeys[x][y][z];
1449
- if (pixel) {
1450
- result.push(pixel);
1501
+ if (profile.matrix.pixelKeys) {
1502
+ for (let z = 0; z < profile.matrix.pixelKeys[0][0].length; z++) {
1503
+ for (let y = 0; y < profile.matrix.pixelKeys[0].length; y++) {
1504
+ for (let x = 0; x < profile.matrix.pixelKeys.length; x++) {
1505
+ const pixel = profile.matrix.pixelKeys[x][y][z];
1506
+ if (pixel) {
1507
+ result.push(pixel);
1508
+ }
1509
+ }
1510
+ }
1511
+ }
1512
+ }
1513
+ else if (profile.matrix.pixelCount.length === 3) {
1514
+ for (let z = 0; z < profile.matrix.pixelCount[2]; z++) {
1515
+ for (let y = 0; y < profile.matrix.pixelCount[1]; y++) {
1516
+ for (let x = 0; x < profile.matrix.pixelCount[0]; x++) {
1517
+ result.push('Pixel ' + (x + 1) + '-' + (y + 1) + '-' + (z + 1));
1451
1518
  }
1452
1519
  }
1453
1520
  }
@@ -1831,7 +1898,11 @@ class ConfigService {
1831
1898
  }], () => [], null); })();
1832
1899
 
1833
1900
  class EffectService {
1834
- constructor() { }
1901
+ constructor() {
1902
+ // The effects are currently being edited
1903
+ this.effectsOpen = false;
1904
+ this.effectsOpenChanged = new Subject();
1905
+ }
1835
1906
  static { this.ɵfac = function EffectService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EffectService)(); }; }
1836
1907
  static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: EffectService, factory: EffectService.ɵfac, providedIn: 'root' }); }
1837
1908
  }
@@ -1954,13 +2025,24 @@ class PresetService {
1954
2025
  }
1955
2026
  this.selectedPreset.fixtures = [];
1956
2027
  }
2028
+ presetFixtueEquals(fixture1, fixture2) {
2029
+ return (fixture1.fixtureUuid === fixture2.fixtureUuid &&
2030
+ ((!fixture2.pixelKey && !fixture1.pixelKey) || fixture2.pixelKey === fixture1.pixelKey));
2031
+ }
1957
2032
  removeDeletedFixtures() {
1958
2033
  // after changing the configuration in the fixture pool, we might need to
1959
2034
  // delete some fixtures
1960
2035
  for (const preset of this.projectService.project.presets) {
1961
2036
  for (let i = preset.fixtures.length - 1; i >= 0; i--) {
1962
- const presetFixture = this.fixtureService.getFixtureByUuid(preset.fixtures[i].fixtureUuid);
1963
- if (!presetFixture) {
2037
+ const presetFixture = preset.fixtures[i];
2038
+ let found = false;
2039
+ for (let projectFixture of this.projectService.project.presetFixtures) {
2040
+ if (this.presetFixtueEquals(presetFixture, projectFixture)) {
2041
+ found = true;
2042
+ break;
2043
+ }
2044
+ }
2045
+ if (!found) {
1964
2046
  preset.fixtures.splice(i, 1);
1965
2047
  }
1966
2048
  }
@@ -2191,8 +2273,7 @@ class PresetService {
2191
2273
  // loop over the project fixtures to keep the order
2192
2274
  for (let projectFixture of this.projectService.project.presetFixtures) {
2193
2275
  for (const presetFixture of this.selectedPreset.fixtures) {
2194
- if (projectFixture.fixtureUuid === presetFixture.fixtureUuid &&
2195
- ((!projectFixture.pixelKey && !presetFixture.pixelKey) || projectFixture.pixelKey === presetFixture.pixelKey)) {
2276
+ if (this.presetFixtueEquals(presetFixture, projectFixture)) {
2196
2277
  const fixture = this.fixtureService.getCachedFixtureByUuid(presetFixture.fixtureUuid, presetFixture.pixelKey);
2197
2278
  if (fixture.profile.uuid === profile.uuid) {
2198
2279
  const exists = modeAndPixelKeys.some((item) => (item.mode === fixture.mode && !item.pixelKey && !fixture.pixelKey) || item.pixelKey === fixture.pixelKey);
@@ -2423,12 +2504,13 @@ class SceneService {
2423
2504
  }], () => [{ type: UuidService }, { type: EffectService }, { type: PresetService }, { type: ProjectService }], null); })();
2424
2505
 
2425
2506
  class TimelineService {
2426
- constructor(sceneService, presetService, projectService, http, configService) {
2507
+ constructor(sceneService, presetService, projectService, http, configService, ngZone) {
2427
2508
  this.sceneService = sceneService;
2428
2509
  this.presetService = presetService;
2429
2510
  this.projectService = projectService;
2430
2511
  this.http = http;
2431
2512
  this.configService = configService;
2513
+ this.ngZone = ngZone;
2432
2514
  this.playState = 'paused';
2433
2515
  this.zoom = 0;
2434
2516
  this.timelineClicking = false;
@@ -2519,9 +2601,12 @@ class TimelineService {
2519
2601
  }
2520
2602
  startTimeUpdater() {
2521
2603
  this.stopTimeUpdater();
2522
- const timeUpdater = timer(0, 40);
2523
- this.timeUpdateSubscription = timeUpdater.subscribe(() => {
2524
- this.updateCurrentTime();
2604
+ // Avoid triggering change detection with each animation frame -> run outside zone
2605
+ this.ngZone.runOutsideAngular(() => {
2606
+ const timeUpdater = timer(0, 40);
2607
+ this.timeUpdateSubscription = timeUpdater.subscribe(() => {
2608
+ this.updateCurrentTime();
2609
+ });
2525
2610
  });
2526
2611
  }
2527
2612
  stopTimeUpdater() {
@@ -3116,7 +3201,7 @@ class TimelineService {
3116
3201
  this.waveSurferReady.next();
3117
3202
  this.applyZoom(0);
3118
3203
  }
3119
- static { this.ɵfac = function TimelineService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TimelineService)(i0.ɵɵinject(SceneService), i0.ɵɵinject(PresetService), i0.ɵɵinject(ProjectService), i0.ɵɵinject(i1.HttpClient), i0.ɵɵinject(ConfigService)); }; }
3204
+ static { this.ɵfac = function TimelineService_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TimelineService)(i0.ɵɵinject(SceneService), i0.ɵɵinject(PresetService), i0.ɵɵinject(ProjectService), i0.ɵɵinject(i1.HttpClient), i0.ɵɵinject(ConfigService), i0.ɵɵinject(i0.NgZone)); }; }
3120
3205
  static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: TimelineService, factory: TimelineService.ɵfac, providedIn: 'root' }); }
3121
3206
  }
3122
3207
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(TimelineService, [{
@@ -3124,7 +3209,7 @@ class TimelineService {
3124
3209
  args: [{
3125
3210
  providedIn: 'root',
3126
3211
  }]
3127
- }], () => [{ type: SceneService }, { type: PresetService }, { type: ProjectService }, { type: i1.HttpClient }, { type: ConfigService }], null); })();
3212
+ }], () => [{ type: SceneService }, { type: PresetService }, { type: ProjectService }, { type: i1.HttpClient }, { type: ConfigService }, { type: i0.NgZone }], null); })();
3128
3213
 
3129
3214
  class PreviewService {
3130
3215
  constructor(presetService, fixtureService, sceneService, timelineService, projectService) {
@@ -4004,15 +4089,16 @@ class MovingHead3d extends Fixture3d {
4004
4089
  }
4005
4090
  }
4006
4091
 
4007
- const _c0$6 = ["canvas"];
4092
+ const _c0$7 = ["canvas"];
4008
4093
  class PreviewComponent {
4009
- constructor(fixtureService, previewMeshService, animationService, previewService, timelineService, projectService) {
4094
+ constructor(fixtureService, previewMeshService, animationService, previewService, timelineService, projectService, ngZone) {
4010
4095
  this.fixtureService = fixtureService;
4011
4096
  this.previewMeshService = previewMeshService;
4012
4097
  this.animationService = animationService;
4013
4098
  this.previewService = previewService;
4014
4099
  this.timelineService = timelineService;
4015
4100
  this.projectService = projectService;
4101
+ this.ngZone = ngZone;
4016
4102
  this.scene = new THREE.Scene();
4017
4103
  this.fixtures3d = [];
4018
4104
  this.previewService.doUpdateFixtureSetup.subscribe(() => {
@@ -4174,11 +4260,14 @@ class PreviewComponent {
4174
4260
  this.setupControls();
4175
4261
  this.setupScene();
4176
4262
  this.onResize();
4177
- this.animate(null);
4263
+ // Avoid triggering change detection with each animation frame -> run outside zone
4264
+ this.ngZone.runOutsideAngular(() => {
4265
+ this.animate(null);
4266
+ });
4178
4267
  }
4179
- static { this.ɵfac = function PreviewComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PreviewComponent)(i0.ɵɵdirectiveInject(FixtureService), i0.ɵɵdirectiveInject(PreviewMeshService), i0.ɵɵdirectiveInject(AnimationService), i0.ɵɵdirectiveInject(PreviewService), i0.ɵɵdirectiveInject(TimelineService), i0.ɵɵdirectiveInject(ProjectService)); }; }
4268
+ static { this.ɵfac = function PreviewComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PreviewComponent)(i0.ɵɵdirectiveInject(FixtureService), i0.ɵɵdirectiveInject(PreviewMeshService), i0.ɵɵdirectiveInject(AnimationService), i0.ɵɵdirectiveInject(PreviewService), i0.ɵɵdirectiveInject(TimelineService), i0.ɵɵdirectiveInject(ProjectService), i0.ɵɵdirectiveInject(i0.NgZone)); }; }
4180
4269
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PreviewComponent, selectors: [["lib-app-preview"]], viewQuery: function PreviewComponent_Query(rf, ctx) { if (rf & 1) {
4181
- i0.ɵɵviewQuery(_c0$6, 5);
4270
+ i0.ɵɵviewQuery(_c0$7, 5);
4182
4271
  } if (rf & 2) {
4183
4272
  let _t;
4184
4273
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.canvasRef = _t.first);
@@ -4191,7 +4280,7 @@ class PreviewComponent {
4191
4280
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PreviewComponent, [{
4192
4281
  type: Component,
4193
4282
  args: [{ selector: 'lib-app-preview', standalone: false, template: "<div class=\"h-100\" #canvas style=\"overflow: hidden\"></div>\n" }]
4194
- }], () => [{ type: FixtureService }, { type: PreviewMeshService }, { type: AnimationService }, { type: PreviewService }, { type: TimelineService }, { type: ProjectService }], { canvasRef: [{
4283
+ }], () => [{ type: FixtureService }, { type: PreviewMeshService }, { type: AnimationService }, { type: PreviewService }, { type: TimelineService }, { type: ProjectService }, { type: i0.NgZone }], { canvasRef: [{
4195
4284
  type: ViewChild,
4196
4285
  args: ['canvas']
4197
4286
  }], onResize: [{
@@ -5252,49 +5341,46 @@ function FixturePoolComponent_For_49_Template(rf, ctx) { if (rf & 1) {
5252
5341
  const _r5 = i0.ɵɵgetCurrentView();
5253
5342
  i0.ɵɵelementStart(0, "div", 52);
5254
5343
  i0.ɵɵlistener("click", function FixturePoolComponent_For_49_Template_div_click_0_listener() { const fixture_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.selectFixture(fixture_r6)); });
5255
- i0.ɵɵelementStart(1, "div", 5)(2, "div", 53);
5256
- i0.ɵɵelement(3, "i", 54);
5257
- i0.ɵɵelementEnd();
5258
- i0.ɵɵelementStart(4, "div", 55)(5, "p", 46);
5259
- i0.ɵɵelement(6, "span");
5260
- i0.ɵɵtext(7);
5344
+ i0.ɵɵelementStart(1, "div", 5)(2, "div", 53)(3, "p", 46);
5345
+ i0.ɵɵelement(4, "span");
5346
+ i0.ɵɵtext(5);
5261
5347
  i0.ɵɵelementEnd()();
5262
- i0.ɵɵelementStart(8, "div", 56)(9, "a", 48);
5263
- i0.ɵɵlistener("click", function FixturePoolComponent_For_49_Template_a_click_9_listener() { const fixture_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(); ctx_r2.removeFixture(fixture_r6); return i0.ɵɵresetView(false); });
5264
- i0.ɵɵelement(10, "i", 57);
5348
+ i0.ɵɵelementStart(6, "div", 54)(7, "a", 48);
5349
+ i0.ɵɵlistener("click", function FixturePoolComponent_For_49_Template_a_click_7_listener() { const fixture_r6 = i0.ɵɵrestoreView(_r5).$implicit; const ctx_r2 = i0.ɵɵnextContext(); ctx_r2.removeFixture(fixture_r6); return i0.ɵɵresetView(false); });
5350
+ i0.ɵɵelement(8, "i", 55);
5265
5351
  i0.ɵɵelementEnd()()()();
5266
5352
  } if (rf & 2) {
5267
5353
  const fixture_r6 = ctx.$implicit;
5268
5354
  const ctx_r2 = i0.ɵɵnextContext();
5269
5355
  i0.ɵɵclassProp("active", fixture_r6 == ctx_r2.selectedFixture);
5270
- i0.ɵɵadvance(6);
5356
+ i0.ɵɵadvance(4);
5271
5357
  i0.ɵɵclassMap(i0.ɵɵinterpolate1("icon-", ctx_r2.fixtureService.getFixtureIconClass(ctx_r2.fixtureService.getProfileByUuid(fixture_r6.profileUuid)), " mr-1"));
5272
5358
  i0.ɵɵadvance();
5273
5359
  i0.ɵɵtextInterpolate1("", fixture_r6.name, " ");
5274
5360
  } }
5275
5361
  function FixturePoolComponent_For_67_Template(rf, ctx) { if (rf & 1) {
5276
5362
  const _r7 = i0.ɵɵgetCurrentView();
5277
- i0.ɵɵelementStart(0, "div", 58);
5363
+ i0.ɵɵelementStart(0, "div", 56);
5278
5364
  i0.ɵɵlistener("mousedown", function FixturePoolComponent_For_67_Template_div_mousedown_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.channelMouseDown($event)); })("mouseover", function FixturePoolComponent_For_67_Template_div_mouseover_0_listener($event) { i0.ɵɵrestoreView(_r7); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.channelMouseOver($event)); });
5279
- i0.ɵɵelementStart(1, "div", 59)(2, "div", 60)(3, "small");
5365
+ i0.ɵɵelementStart(1, "div", 57)(2, "div", 58)(3, "small");
5280
5366
  i0.ɵɵtext(4, "\u00A0");
5281
5367
  i0.ɵɵelementEnd()()()();
5282
5368
  } if (rf & 2) {
5283
- const ɵ$index_161_r8 = ctx.$index;
5369
+ const ɵ$index_157_r8 = ctx.$index;
5284
5370
  const ctx_r2 = i0.ɵɵnextContext();
5285
- i0.ɵɵclassProp("dmx-channel-occupied", ctx_r2.channelOccupied(ɵ$index_161_r8))("dmx-channel-occupied-start", ctx_r2.channelOccupiedStart(ɵ$index_161_r8))("dmx-channel-occupied-end", ctx_r2.channelOccupiedEnd(ɵ$index_161_r8))("dmx-channel-selected", ctx_r2.channelSelected(ɵ$index_161_r8))("dmx-channel-overlapped", ctx_r2.channelOverlapped(ɵ$index_161_r8));
5286
- i0.ɵɵproperty("popover", i0.ɵɵinterpolate(ɵ$index_161_r8 + 1));
5287
- i0.ɵɵattribute("data-index", ɵ$index_161_r8);
5371
+ i0.ɵɵclassProp("dmx-channel-occupied", ctx_r2.channelOccupied(ɵ$index_157_r8))("dmx-channel-occupied-start", ctx_r2.channelOccupiedStart(ɵ$index_157_r8))("dmx-channel-occupied-end", ctx_r2.channelOccupiedEnd(ɵ$index_157_r8))("dmx-channel-selected", ctx_r2.channelSelected(ɵ$index_157_r8))("dmx-channel-overlapped", ctx_r2.channelOverlapped(ɵ$index_157_r8));
5372
+ i0.ɵɵproperty("popover", i0.ɵɵinterpolate(ɵ$index_157_r8 + 1));
5373
+ i0.ɵɵattribute("data-index", ɵ$index_157_r8);
5288
5374
  i0.ɵɵadvance();
5289
5375
  i0.ɵɵclassProp("dmx-channel-text-visible", ctx_r2.showChannelNumbers);
5290
- i0.ɵɵattribute("data-index", ɵ$index_161_r8);
5376
+ i0.ɵɵattribute("data-index", ɵ$index_157_r8);
5291
5377
  i0.ɵɵadvance();
5292
- i0.ɵɵattribute("data-index", ɵ$index_161_r8);
5378
+ i0.ɵɵattribute("data-index", ɵ$index_157_r8);
5293
5379
  i0.ɵɵadvance();
5294
- i0.ɵɵattribute("data-index", ɵ$index_161_r8);
5380
+ i0.ɵɵattribute("data-index", ɵ$index_157_r8);
5295
5381
  } }
5296
5382
  function FixturePoolComponent_Conditional_69_For_14_Template(rf, ctx) { if (rf & 1) {
5297
- i0.ɵɵelementStart(0, "option", 66);
5383
+ i0.ɵɵelementStart(0, "option", 64);
5298
5384
  i0.ɵɵtext(1);
5299
5385
  i0.ɵɵpipe(2, "translate");
5300
5386
  i0.ɵɵelementEnd();
@@ -5306,43 +5392,43 @@ function FixturePoolComponent_Conditional_69_For_14_Template(rf, ctx) { if (rf &
5306
5392
  i0.ɵɵtextInterpolate3(" ", mode_r10.name, " - ", ctx_r2.fixtureService.getModeChannelCount(ctx_r2.selectedFixtureProfile, mode_r10), " ", i0.ɵɵpipeBind1(2, 4, "designer.fixture-pool.channels"), " ");
5307
5393
  } }
5308
5394
  function FixturePoolComponent_Conditional_69_For_22_Template(rf, ctx) { if (rf & 1) {
5309
- i0.ɵɵelementStart(0, "option", 66);
5395
+ i0.ɵɵelementStart(0, "option", 64);
5310
5396
  i0.ɵɵtext(1);
5311
5397
  i0.ɵɵelementEnd();
5312
5398
  } if (rf & 2) {
5313
- const ɵ$index_211_r11 = ctx.$index;
5314
- i0.ɵɵproperty("ngValue", ɵ$index_211_r11);
5399
+ const ɵ$index_207_r11 = ctx.$index;
5400
+ i0.ɵɵproperty("ngValue", ɵ$index_207_r11);
5315
5401
  i0.ɵɵadvance();
5316
- i0.ɵɵtextInterpolate1(" ", ɵ$index_211_r11 + 1, " ");
5402
+ i0.ɵɵtextInterpolate1(" ", ɵ$index_207_r11 + 1, " ");
5317
5403
  } }
5318
5404
  function FixturePoolComponent_Conditional_69_Template(rf, ctx) { if (rf & 1) {
5319
5405
  const _r9 = i0.ɵɵgetCurrentView();
5320
- i0.ɵɵelementStart(0, "div")(1, "div", 20)(2, "label", 61);
5406
+ i0.ɵɵelementStart(0, "div")(1, "div", 20)(2, "label", 59);
5321
5407
  i0.ɵɵtext(3);
5322
5408
  i0.ɵɵpipe(4, "translate");
5323
5409
  i0.ɵɵelementEnd();
5324
- i0.ɵɵelementStart(5, "div", 62)(6, "input", 63);
5410
+ i0.ɵɵelementStart(5, "div", 60)(6, "input", 61);
5325
5411
  i0.ɵɵtwoWayListener("ngModelChange", function FixturePoolComponent_Conditional_69_Template_input_ngModelChange_6_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r2 = i0.ɵɵnextContext(); i0.ɵɵtwoWayBindingSet(ctx_r2.selectedFixture.name, $event) || (ctx_r2.selectedFixture.name = $event); return i0.ɵɵresetView($event); });
5326
5412
  i0.ɵɵelementEnd()()();
5327
- i0.ɵɵelementStart(7, "div", 20)(8, "label", 64);
5413
+ i0.ɵɵelementStart(7, "div", 20)(8, "label", 62);
5328
5414
  i0.ɵɵtext(9);
5329
5415
  i0.ɵɵpipe(10, "translate");
5330
5416
  i0.ɵɵelementEnd();
5331
- i0.ɵɵelementStart(11, "div", 62)(12, "select", 65);
5417
+ i0.ɵɵelementStart(11, "div", 60)(12, "select", 63);
5332
5418
  i0.ɵɵlistener("ngModelChange", function FixturePoolComponent_Conditional_69_Template_select_ngModelChange_12_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.selectedFixture.modeShortName = $event); });
5333
- i0.ɵɵrepeaterCreate(13, FixturePoolComponent_Conditional_69_For_14_Template, 3, 6, "option", 66, i0.ɵɵrepeaterTrackByIdentity);
5419
+ i0.ɵɵrepeaterCreate(13, FixturePoolComponent_Conditional_69_For_14_Template, 3, 6, "option", 64, i0.ɵɵrepeaterTrackByIdentity);
5334
5420
  i0.ɵɵelementEnd()()();
5335
- i0.ɵɵelementStart(15, "div", 20)(16, "label", 64);
5421
+ i0.ɵɵelementStart(15, "div", 20)(16, "label", 62);
5336
5422
  i0.ɵɵtext(17);
5337
5423
  i0.ɵɵpipe(18, "translate");
5338
5424
  i0.ɵɵelementEnd();
5339
- i0.ɵɵelementStart(19, "div", 62)(20, "select", 65);
5425
+ i0.ɵɵelementStart(19, "div", 60)(20, "select", 63);
5340
5426
  i0.ɵɵlistener("ngModelChange", function FixturePoolComponent_Conditional_69_Template_select_ngModelChange_20_listener($event) { i0.ɵɵrestoreView(_r9); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.selectedFixture.dmxFirstChannel = $event); });
5341
- i0.ɵɵrepeaterCreate(21, FixturePoolComponent_Conditional_69_For_22_Template, 2, 2, "option", 66, i0.ɵɵrepeaterTrackByIdentity);
5427
+ i0.ɵɵrepeaterCreate(21, FixturePoolComponent_Conditional_69_For_22_Template, 2, 2, "option", 64, i0.ɵɵrepeaterTrackByIndex);
5342
5428
  i0.ɵɵelementEnd()()();
5343
5429
  i0.ɵɵelementStart(23, "div", 20);
5344
- i0.ɵɵelement(24, "label", 64);
5345
- i0.ɵɵelementStart(25, "div", 62)(26, "button", 42);
5430
+ i0.ɵɵelement(24, "label", 62);
5431
+ i0.ɵɵelementStart(25, "div", 60)(26, "button", 42);
5346
5432
  i0.ɵɵlistener("click", function FixturePoolComponent_Conditional_69_Template_button_click_26_listener() { i0.ɵɵrestoreView(_r9); const ctx_r2 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r2.addCopy(ctx_r2.selectedFixture)); });
5347
5433
  i0.ɵɵtext(27);
5348
5434
  i0.ɵɵpipe(28, "translate");
@@ -5384,7 +5470,7 @@ class FixturePoolComponent {
5384
5470
  this.dmxChannels = [];
5385
5471
  this.showChannelNumbers = false;
5386
5472
  this.onClose = new Subject();
5387
- this.fixturePool = [...this.projectService.project.fixtures];
5473
+ this.fixturePool = structuredClone(this.projectService.project.fixtures);
5388
5474
  if (this.fixturePool.length > 0) {
5389
5475
  this.selectFixture(this.fixturePool[0]);
5390
5476
  }
@@ -5604,12 +5690,11 @@ class FixturePoolComponent {
5604
5690
  return;
5605
5691
  }
5606
5692
  }
5607
- this.projectService.project.fixtures = this.fixturePool;
5608
- // remove deleted fixtures from preset fixtures
5693
+ // remove deleted fixtures/pixel keys from preset fixtures
5609
5694
  for (let i = this.projectService.project.presetFixtures.length - 1; i >= 0; i--) {
5610
5695
  let found = false;
5611
5696
  const presetFixture = this.projectService.project.presetFixtures[i];
5612
- for (let fixture of this.projectService.project.fixtures) {
5697
+ for (let fixture of this.fixturePool) {
5613
5698
  if (presetFixture.fixtureUuid === fixture.uuid) {
5614
5699
  found = true;
5615
5700
  break;
@@ -5619,8 +5704,23 @@ class FixturePoolComponent {
5619
5704
  this.projectService.project.presetFixtures.splice(i, 1);
5620
5705
  }
5621
5706
  }
5622
- // add the new fixtures to the preset fixtures
5623
- for (let fixture of this.projectService.project.fixtures) {
5707
+ // If a mode is changed, we need to re-add the fixture to make sure, all pixel keys
5708
+ // are removed/added
5709
+ for (let projectFixture of this.projectService.project.fixtures) {
5710
+ for (let poolFixture of this.fixturePool) {
5711
+ if (poolFixture.profileUuid === projectFixture.profileUuid && poolFixture.modeShortName != projectFixture.modeShortName) {
5712
+ // the mode has changed -> remove it from the presetfixtures
5713
+ for (let i = this.projectService.project.presetFixtures.length - 1; i >= 0; i--) {
5714
+ const presetFixture = this.projectService.project.presetFixtures[i];
5715
+ if (presetFixture.fixtureUuid === poolFixture.uuid) {
5716
+ this.projectService.project.presetFixtures.splice(i, 1);
5717
+ }
5718
+ }
5719
+ }
5720
+ }
5721
+ }
5722
+ // add the new fixtures/pixel keys to the preset fixtures
5723
+ for (let fixture of this.fixturePool) {
5624
5724
  let found = false;
5625
5725
  for (let presetFixture of this.projectService.project.presetFixtures) {
5626
5726
  if (presetFixture.fixtureUuid === fixture.uuid) {
@@ -5643,6 +5743,7 @@ class FixturePoolComponent {
5643
5743
  }
5644
5744
  }
5645
5745
  }
5746
+ this.projectService.project.fixtures = this.fixturePool;
5646
5747
  this.fixtureService.updateCachedFixtures();
5647
5748
  this.presetService.removeDeletedFixtures();
5648
5749
  this.previewService.updateFixtureSetup();
@@ -5693,7 +5794,7 @@ class FixturePoolComponent {
5693
5794
  static { this.ɵfac = function FixturePoolComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || FixturePoolComponent)(i0.ɵɵdirectiveInject(i1$1.BsModalRef), i0.ɵɵdirectiveInject(FixtureService), i0.ɵɵdirectiveInject(UuidService), i0.ɵɵdirectiveInject(ProjectService), i0.ɵɵdirectiveInject(PreviewService), i0.ɵɵdirectiveInject(i4.TranslateService), i0.ɵɵdirectiveInject(i3$1.ToastrService), i0.ɵɵdirectiveInject(PresetService), i0.ɵɵdirectiveInject(ConfigService), i0.ɵɵdirectiveInject(i1$1.BsModalService)); }; }
5694
5795
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FixturePoolComponent, selectors: [["lib-app-fixture-pool"]], hostBindings: function FixturePoolComponent_HostBindings(rf, ctx) { if (rf & 1) {
5695
5796
  i0.ɵɵlistener("mouseup", function FixturePoolComponent_mouseup_HostBindingHandler($event) { return ctx.mouseUp($event); }, i0.ɵɵresolveWindow)("keydown.enter", function FixturePoolComponent_keydown_enter_HostBindingHandler($event) { return ctx.handleKeyboardEvent($event); }, i0.ɵɵresolveDocument);
5696
- } }, standalone: false, decls: 77, vars: 35, consts: [[1, "modal-header"], [1, "modal-title", "pull-left"], ["type", "button", "aria-label", "Close", 1, "close", "pull-right", 3, "click"], ["aria-hidden", "true"], [1, "modal-body"], [1, "row"], [1, "col-6"], ["type", "text", "id", "searchSet", 1, "form-control", "input-block", "mb-3", 3, "input", "placeholder"], [1, "card", "border-secondary", "w-100", 2, "height", "200px"], [1, "card-body", "p-0", "w-100"], [1, "list-group", "list-group-flush", "w-100"], [1, "list-group-item", "flex-column", "align-items-start", "d-flex"], [1, "list-group-item"], [1, "d-inline-block", "mb-0", "mt-2"], ["href", "https://open-fixture-library.org/", "target", "_blank"], ["href", "https://open-fixture-library.org/fixture-editor", "target", "_blank", "role", "button", 1, "mt-2", "btn", "btn-secondary", "btn-sm", "float-right"], ["aria-hidden", "true", 1, "fa", "fa-file-o"], ["type", "button", "role", "button", 1, "mr-2", "mt-2", "btn", "btn-secondary", "btn-sm", "float-right", 3, "disabled"], ["type", "button", "role", "button", 1, "btn", "btn-secondary", 3, "click"], ["aria-hidden", "true", 1, "fa", "fa-plus"], [1, "form-group", "row"], [1, "col-lg-4", "col-form-label"], [1, "col-lg-8"], [1, "custom-select"], [1, "card", "border-secondary", 2, "height", "235px"], [1, "card-body", "p-0"], [1, "list-group", "list-group-flush", 3, "sortablejs"], [1, "list-group-item", 2, "cursor", "pointer", 3, "active"], [1, "row", "mt-3"], [1, "col"], ["id", "myTab", "role", "tablist", 1, "nav", "nav-tabs", "mb-4"], [1, "nav-item"], ["id", "sets-tab", "data-toggle", "tab", "href", "#dmx", "role", "tab", 1, "nav-link", "active"], ["aria-hidden", "true", 1, "icon-ola"], ["id", "compositions-tab", "data-toggle", "tab", "href", "#settings", "role", "tab", 1, "nav-link"], ["aria-hidden", "true", 1, "fa", "fa-cog"], ["id", "myTabContent", 1, "tab-content"], ["id", "dmx", "role", "tabpanel", 1, "tab-pane", "show", "active"], ["placement", "top", "triggers", "mouseenter:mouseleave", 1, "dmx-channel", 3, "dmx-channel-occupied", "dmx-channel-occupied-start", "dmx-channel-occupied-end", "dmx-channel-selected", "dmx-channel-overlapped", "popover"], ["id", "settings", "role", "tabpanel", 1, "tab-pane"], [1, "modal-footer"], ["href", "#", "role", "button", 1, "mr-3", "my-auto", 3, "click"], ["type", "button", 1, "btn", "btn-primary", 3, "click"], [1, "mb-0", "mx-auto"], [1, "fa", "fa-spinner", "fa-pulse", "fa-fw"], [1, "col-10", "col-auto", "my-auto", "pl-2"], [1, "mb-0"], [1, "col-2", "my-auto"], ["href", "#", "role", "button", 1, "btn", "btn-primary", "btn-sm", "float-right", 3, "click"], ["type", "button", "role", "button", 1, "mr-2", "mt-2", "btn", "btn-secondary", "btn-sm", "float-right", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa", "fa-spinner", "fa-pulse", "fa-fw"], ["aria-hidden", "true", 1, "fa", "fa-download", "fa-fw"], [1, "list-group-item", 2, "cursor", "pointer", 3, "click"], [1, "col-auto", "list-sort-handle", "my-auto", 2, "cursor", "move", "cursor", "-webkit-grabbing"], ["aria-hidden", "true", 1, "fa", "fa-bars"], [1, "col-auto", "flex-grow", "pl-0", "my-auto"], [1, "col-auto", "my-auto"], ["aria-hidden", "true", 1, "fa", "fa-minus"], ["placement", "top", "triggers", "mouseenter:mouseleave", 1, "dmx-channel", 3, "mousedown", "mouseover", "popover"], [1, "d-flex", "w-100", "dmx-channel-text"], [1, "m-auto", 2, "font-size", "11px"], ["for", "fixtureName", 1, "col-lg-3", "col-form-label"], [1, "col-lg-9"], ["type", "text", "maxlength", "200", "id", "fixtureName", 1, "form-control", 3, "ngModelChange", "ngModel"], [1, "col-lg-3", "col-form-label"], [1, "custom-select", 3, "ngModelChange", "ngModel"], [3, "ngValue"]], template: function FixturePoolComponent_Template(rf, ctx) { if (rf & 1) {
5797
+ } }, standalone: false, decls: 77, vars: 34, consts: [[1, "modal-header"], [1, "modal-title", "pull-left"], ["type", "button", "aria-label", "Close", 1, "close", "pull-right", 3, "click"], ["aria-hidden", "true"], [1, "modal-body"], [1, "row"], [1, "col-6"], ["type", "text", "id", "searchSet", 1, "form-control", "input-block", "mb-3", 3, "input", "placeholder"], [1, "card", "border-secondary", "w-100", 2, "height", "200px"], [1, "card-body", "p-0", "w-100"], [1, "list-group", "list-group-flush", "w-100"], [1, "list-group-item", "flex-column", "align-items-start", "d-flex"], [1, "list-group-item"], [1, "d-inline-block", "mb-0", "mt-2"], ["href", "https://open-fixture-library.org/", "target", "_blank"], ["href", "https://open-fixture-library.org/fixture-editor", "target", "_blank", "role", "button", 1, "mt-2", "btn", "btn-secondary", "btn-sm", "float-right"], ["aria-hidden", "true", 1, "fa", "fa-file-o"], ["type", "button", "role", "button", 1, "mr-2", "mt-2", "btn", "btn-secondary", "btn-sm", "float-right", 3, "disabled"], ["type", "button", "role", "button", 1, "btn", "btn-secondary", 3, "click"], ["aria-hidden", "true", 1, "fa", "fa-plus"], [1, "form-group", "row"], [1, "col-lg-4", "col-form-label"], [1, "col-lg-8"], [1, "custom-select"], [1, "card", "border-secondary", 2, "height", "235px"], [1, "card-body", "p-0"], [1, "list-group", "list-group-flush"], [1, "list-group-item", 2, "cursor", "pointer", 3, "active"], [1, "row", "mt-3"], [1, "col"], ["id", "myTab", "role", "tablist", 1, "nav", "nav-tabs", "mb-4"], [1, "nav-item"], ["id", "sets-tab", "data-toggle", "tab", "href", "#dmx", "role", "tab", 1, "nav-link", "active"], ["aria-hidden", "true", 1, "icon-ola"], ["id", "compositions-tab", "data-toggle", "tab", "href", "#settings", "role", "tab", 1, "nav-link"], ["aria-hidden", "true", 1, "fa", "fa-cog"], ["id", "myTabContent", 1, "tab-content"], ["id", "dmx", "role", "tabpanel", 1, "tab-pane", "show", "active"], ["placement", "top", "triggers", "mouseenter:mouseleave", 1, "dmx-channel", 3, "dmx-channel-occupied", "dmx-channel-occupied-start", "dmx-channel-occupied-end", "dmx-channel-selected", "dmx-channel-overlapped", "popover"], ["id", "settings", "role", "tabpanel", 1, "tab-pane"], [1, "modal-footer"], ["href", "#", "role", "button", 1, "mr-3", "my-auto", 3, "click"], ["type", "button", 1, "btn", "btn-primary", 3, "click"], [1, "mb-0", "mx-auto"], [1, "fa", "fa-spinner", "fa-pulse", "fa-fw"], [1, "col-10", "col-auto", "my-auto", "pl-2"], [1, "mb-0"], [1, "col-2", "my-auto"], ["href", "#", "role", "button", 1, "btn", "btn-primary", "btn-sm", "float-right", 3, "click"], ["type", "button", "role", "button", 1, "mr-2", "mt-2", "btn", "btn-secondary", "btn-sm", "float-right", 3, "click", "disabled"], ["aria-hidden", "true", 1, "fa", "fa-spinner", "fa-pulse", "fa-fw"], ["aria-hidden", "true", 1, "fa", "fa-download", "fa-fw"], [1, "list-group-item", 2, "cursor", "pointer", 3, "click"], [1, "col-auto", "flex-grow", "pl-0", "my-auto"], [1, "col-auto", "my-auto"], ["aria-hidden", "true", 1, "fa", "fa-minus"], ["placement", "top", "triggers", "mouseenter:mouseleave", 1, "dmx-channel", 3, "mousedown", "mouseover", "popover"], [1, "d-flex", "w-100", "dmx-channel-text"], [1, "m-auto", 2, "font-size", "11px"], ["for", "fixtureName", 1, "col-lg-3", "col-form-label"], [1, "col-lg-9"], ["type", "text", "maxlength", "200", "id", "fixtureName", 1, "form-control", 3, "ngModelChange", "ngModel"], [1, "col-lg-3", "col-form-label"], [1, "custom-select", 3, "ngModelChange", "ngModel"], [3, "ngValue"]], template: function FixturePoolComponent_Template(rf, ctx) { if (rf & 1) {
5697
5798
  i0.ɵɵelementStart(0, "div", 0)(1, "h4", 1);
5698
5799
  i0.ɵɵtext(2);
5699
5800
  i0.ɵɵpipe(3, "translate");
@@ -5738,7 +5839,7 @@ class FixturePoolComponent {
5738
5839
  i0.ɵɵtext(44, "Universe 1");
5739
5840
  i0.ɵɵelementEnd()()()()()();
5740
5841
  i0.ɵɵelementStart(45, "div", 24)(46, "div", 25)(47, "div", 26);
5741
- i0.ɵɵrepeaterCreate(48, FixturePoolComponent_For_49_Template, 11, 6, "div", 27, i0.ɵɵrepeaterTrackByIdentity);
5842
+ i0.ɵɵrepeaterCreate(48, FixturePoolComponent_For_49_Template, 9, 6, "div", 27, i0.ɵɵrepeaterTrackByIdentity);
5742
5843
  i0.ɵɵelementEnd()()()()();
5743
5844
  i0.ɵɵelementStart(50, "div", 28)(51, "div", 29)(52, "ul", 30)(53, "li", 31)(54, "a", 32);
5744
5845
  i0.ɵɵelement(55, "i", 33);
@@ -5751,7 +5852,7 @@ class FixturePoolComponent {
5751
5852
  i0.ɵɵpipe(62, "translate");
5752
5853
  i0.ɵɵelementEnd()()();
5753
5854
  i0.ɵɵelementStart(63, "div", 36)(64, "div", 37)(65, "div");
5754
- i0.ɵɵrepeaterCreate(66, FixturePoolComponent_For_67_Template, 5, 18, "div", 38, i0.ɵɵrepeaterTrackByIdentity);
5855
+ i0.ɵɵrepeaterCreate(66, FixturePoolComponent_For_67_Template, 5, 18, "div", 38, i0.ɵɵrepeaterTrackByIndex);
5755
5856
  i0.ɵɵelementEnd()();
5756
5857
  i0.ɵɵelementStart(68, "div", 39);
5757
5858
  i0.ɵɵconditionalCreate(69, FixturePoolComponent_Conditional_69_Template, 29, 15, "div");
@@ -5768,42 +5869,40 @@ class FixturePoolComponent {
5768
5869
  i0.ɵɵelementEnd()();
5769
5870
  } if (rf & 2) {
5770
5871
  i0.ɵɵadvance(2);
5771
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(3, 14, "designer.fixture-pool.title"));
5872
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(3, 13, "designer.fixture-pool.title"));
5772
5873
  i0.ɵɵadvance(8);
5773
- i0.ɵɵproperty("placeholder", i0.ɵɵinterpolate(i0.ɵɵpipeBind1(11, 16, "designer.fixture-pool.search-profiles")));
5874
+ i0.ɵɵproperty("placeholder", i0.ɵɵinterpolate(i0.ɵɵpipeBind1(11, 15, "designer.fixture-pool.search-profiles")));
5774
5875
  i0.ɵɵadvance(5);
5775
5876
  i0.ɵɵconditional(ctx.loadingProfiles ? 15 : -1);
5776
5877
  i0.ɵɵadvance();
5777
- i0.ɵɵrepeater(i0.ɵɵpipeBind2(18, 18, ctx.filteredProfiles, "uuid"));
5878
+ i0.ɵɵrepeater(i0.ɵɵpipeBind2(18, 17, ctx.filteredProfiles, "uuid"));
5778
5879
  i0.ɵɵadvance(10);
5779
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(27, 21, "designer.fixture-pool.add-profile"), " ");
5880
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(27, 20, "designer.fixture-pool.add-profile"), " ");
5780
5881
  i0.ɵɵadvance(2);
5781
5882
  i0.ɵɵconditional(ctx.configService.localProfiles ? 28 : -1);
5782
5883
  i0.ɵɵadvance(6);
5783
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(35, 23, "designer.fixture-pool.create-fixture-from-profile-file"), " ");
5884
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(35, 22, "designer.fixture-pool.create-fixture-from-profile-file"), " ");
5784
5885
  i0.ɵɵadvance(5);
5785
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(40, 25, "designer.fixture-pool.universe"));
5786
- i0.ɵɵadvance(8);
5787
- i0.ɵɵproperty("sortablejs", ctx.fixturePool);
5788
- i0.ɵɵadvance();
5886
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(40, 24, "designer.fixture-pool.universe"));
5887
+ i0.ɵɵadvance(9);
5789
5888
  i0.ɵɵrepeater(ctx.fixturePool);
5790
5889
  i0.ɵɵadvance(8);
5791
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(57, 27, "designer.fixture-pool.dmx"), " ");
5890
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(57, 26, "designer.fixture-pool.dmx"), " ");
5792
5891
  i0.ɵɵadvance(5);
5793
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(62, 29, "designer.fixture-pool.settings"), " ");
5892
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(62, 28, "designer.fixture-pool.settings"), " ");
5794
5893
  i0.ɵɵadvance(5);
5795
5894
  i0.ɵɵrepeater(ctx.dmxChannels);
5796
5895
  i0.ɵɵadvance(3);
5797
5896
  i0.ɵɵconditional(ctx.selectedFixture && ctx.selectedFixtureProfile ? 69 : -1);
5798
5897
  i0.ɵɵadvance(3);
5799
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(73, 31, "designer.misc.cancel"), " ");
5898
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(73, 30, "designer.misc.cancel"), " ");
5800
5899
  i0.ɵɵadvance(3);
5801
- i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(76, 33, "designer.misc.ok"));
5802
- } }, dependencies: [i3$2.NgSelectOption, i3$2.ɵNgSelectMultipleOption, i3$2.DefaultValueAccessor, i3$2.SelectControlValueAccessor, i3$2.NgControlStatus, i3$2.MaxLengthValidator, i3$2.NgModel, i11.PopoverDirective, i7.SortablejsDirective, i4.TranslatePipe, ArraySortPipe], styles: [".list-group-item[_ngcontent-%COMP%]{padding:.3rem 1.25rem}.dmx-channel[_ngcontent-%COMP%]{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied[_ngcontent-%COMP%]{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start[_ngcontent-%COMP%]{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end[_ngcontent-%COMP%]{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected[_ngcontent-%COMP%]{background-color:#fd7e14}.dmx-channel-overlapped[_ngcontent-%COMP%]{background-color:red;border:1px solid red;cursor:move}.card[_ngcontent-%COMP%]{overflow:auto}"] }); }
5900
+ i0.ɵɵtextInterpolate(i0.ɵɵpipeBind1(76, 32, "designer.misc.ok"));
5901
+ } }, dependencies: [i3$2.NgSelectOption, i3$2.ɵNgSelectMultipleOption, i3$2.DefaultValueAccessor, i3$2.SelectControlValueAccessor, i3$2.NgControlStatus, i3$2.MaxLengthValidator, i3$2.NgModel, i11.PopoverDirective, i4.TranslatePipe, ArraySortPipe], styles: [".list-group-item[_ngcontent-%COMP%]{padding:.3rem 1.25rem}.dmx-channel[_ngcontent-%COMP%]{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied[_ngcontent-%COMP%]{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start[_ngcontent-%COMP%]{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end[_ngcontent-%COMP%]{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected[_ngcontent-%COMP%]{background-color:#fd7e14}.dmx-channel-overlapped[_ngcontent-%COMP%]{background-color:red;border:1px solid red;cursor:move}.card[_ngcontent-%COMP%]{overflow:auto}"] }); }
5803
5902
  }
5804
5903
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FixturePoolComponent, [{
5805
5904
  type: Component,
5806
- args: [{ selector: 'lib-app-fixture-pool', standalone: false, template: "<div class=\"modal-header\">\n <h4 class=\"modal-title pull-left\">{{ 'designer.fixture-pool.title' | translate }}</h4>\n <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"cancel(); (false)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n</div>\n<div class=\"modal-body\">\n <div class=\"row\">\n <div class=\"col-6\">\n <!-- Search for profiles -->\n <input\n type=\"text\"\n class=\"form-control input-block mb-3\"\n id=\"searchSet\"\n placeholder=\"{{ 'designer.fixture-pool.search-profiles' | translate }}\"\n (input)=\"searchExpression = $event.target.value; filterProfiles()\"\n />\n\n <!-- Profiles -->\n <div class=\"card border-secondary w-100\" style=\"height: 200px\">\n <div class=\"card-body p-0 w-100\">\n <div class=\"list-group list-group-flush w-100\">\n @if (loadingProfiles) {\n <a class=\"list-group-item flex-column align-items-start d-flex\">\n <p class=\"mb-0 mx-auto\">\n <i class=\"fa fa-spinner fa-pulse fa-fw\"></i>\n </p>\n </a>\n } @for (profile of filteredProfiles | sort : 'uuid'; track profile) {\n <div class=\"list-group-item\">\n <div class=\"row\">\n <div class=\"col-10 col-auto my-auto pl-2\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(profile) }} mr-1\"></span> {{ profile.manufacturerName }} -\n {{ profile.name }}\n </p>\n </div>\n <div class=\"col-2 my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"addFixture(profile); (false)\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div>\n <p class=\"d-inline-block mb-0 mt-2\">\n Powered by the <a href=\"https://open-fixture-library.org/\" target=\"_blank\">Open Fixture Library</a>\n </p>\n <a\n class=\"mt-2 btn btn-secondary btn-sm float-right\"\n href=\"https://open-fixture-library.org/fixture-editor\"\n target=\"_blank\"\n role=\"button\"\n >\n <i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.add-profile' | translate }}\n </a>\n @if (configService.localProfiles) {\n <button\n type=\"button\"\n class=\"mr-2 mt-2 btn btn-secondary btn-sm float-right\"\n (click)=\"updateProfiles(); (false)\"\n [disabled]=\"updatingProfiles\"\n role=\"button\"\n >\n @if (updatingProfiles) {\n <i class=\"fa fa-spinner fa-pulse fa-fw\" aria-hidden=\"true\"></i>\n } @if (!updatingProfiles) {\n <i class=\"fa fa-download fa-fw\" aria-hidden=\"true\"></i>\n }\n {{ 'designer.fixture-pool.update-profiles' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"col-6\">\n <div class=\"row\">\n <!-- Add fixture from local profile -->\n <div class=\"col-6\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"createFixtureFromProfileFile()\" role=\"button\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.create-fixture-from-profile-file' | translate }}\n </button>\n </div>\n\n <!-- Universe -->\n <div class=\"col-6\">\n <div class=\"form-group row\">\n <label class=\"col-lg-4 col-form-label\">{{ 'designer.fixture-pool.universe' | translate }}</label>\n <div class=\"col-lg-8\">\n <select class=\"custom-select\">\n <option>Universe 1</option>\n </select>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Fixtures -->\n <div class=\"card border-secondary\" style=\"height: 235px\">\n <div class=\"card-body p-0\">\n <div class=\"list-group list-group-flush\" [sortablejs]=\"fixturePool\">\n @for (fixture of fixturePool; track fixture) {\n <div\n class=\"list-group-item\"\n [class.active]=\"fixture == selectedFixture\"\n (click)=\"selectFixture(fixture)\"\n style=\"cursor: pointer\"\n >\n <div class=\"row\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"col-auto flex-grow pl-0 my-auto\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(fixtureService.getProfileByUuid(fixture.profileUuid)) }} mr-1\">\n </span\n >{{ fixture.name }}\n </p>\n </div>\n <div class=\"col-auto my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"removeFixture(fixture); (false)\">\n <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row mt-3\">\n <div class=\"col\">\n <!-- Tab navigation -->\n <ul class=\"nav nav-tabs mb-4\" id=\"myTab\" role=\"tablist\">\n <li class=\"nav-item\">\n <a class=\"nav-link active\" id=\"sets-tab\" data-toggle=\"tab\" href=\"#dmx\" role=\"tab\">\n <i class=\"icon-ola\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.dmx' | translate }}\n </a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link\" id=\"compositions-tab\" data-toggle=\"tab\" href=\"#settings\" role=\"tab\">\n <i class=\"fa fa-cog\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.settings' | translate }}\n </a>\n </li>\n </ul>\n\n <!-- Tab content -->\n <div class=\"tab-content\" id=\"myTabContent\">\n <!-- DMX universe overview-->\n <div class=\"tab-pane show active\" id=\"dmx\" role=\"tabpanel\">\n <!-- Show all channel numbers -->\n <!-- <div class=\"form-group row\">\n <div class=\"col-auto flex-grow\"></div>\n <div class=\"col-lg-3 d-flex\">\n <div class=\"form-check my-auto ml-auto\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"showChannelNumbers\" [ngModel]=\"showChannelNumbers\"\n (ngModelChange)=\"showChannelNumbers = $event\">\n <label class=\"form-check-label\" for=\"showChannelNumbers\">Show channels</label>\n </div>\n </div>\n </div> -->\n\n <!-- List of DMX channels -->\n <div>\n @for (channel of dmxChannels; track channel; let i = $index) {\n <div\n class=\"dmx-channel\"\n [class.dmx-channel-occupied]=\"channelOccupied(i)\"\n [class.dmx-channel-occupied-start]=\"channelOccupiedStart(i)\"\n [class.dmx-channel-occupied-end]=\"channelOccupiedEnd(i)\"\n [class.dmx-channel-selected]=\"channelSelected(i)\"\n [class.dmx-channel-overlapped]=\"channelOverlapped(i)\"\n (mousedown)=\"channelMouseDown($event)\"\n (mouseover)=\"channelMouseOver($event)\"\n [attr.data-index]=\"i\"\n popover=\"{{ i + 1 }}\"\n placement=\"top\"\n triggers=\"mouseenter:mouseleave\"\n >\n <div class=\"d-flex w-100 dmx-channel-text\" [attr.data-index]=\"i\" [class.dmx-channel-text-visible]=\"showChannelNumbers\">\n <div class=\"m-auto\" style=\"font-size: 11px\" [attr.data-index]=\"i\"><small [attr.data-index]=\"i\">&nbsp;</small></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Fixture settings -->\n <div class=\"tab-pane\" id=\"settings\" role=\"tabpanel\">\n @if (selectedFixture && selectedFixtureProfile) {\n <div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\" for=\"fixtureName\">{{ 'designer.fixture-pool.fixture-name' | translate }}</label>\n <div class=\"col-lg-9\">\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"selectedFixture.name\" maxlength=\"200\" id=\"fixtureName\" />\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.mode' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.modeShortName\"\n (ngModelChange)=\"selectedFixture.modeShortName = $event\"\n >\n @for (mode of selectedFixtureProfile.modes; track mode) {\n <option [ngValue]=\"mode.shortName || mode.name\">\n {{ mode.name }}\n - {{ fixtureService.getModeChannelCount(selectedFixtureProfile, mode) }}\n {{ 'designer.fixture-pool.channels' | translate }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.first-channel' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.dmxFirstChannel\"\n (ngModelChange)=\"selectedFixture.dmxFirstChannel = $event\"\n >\n @for (channel of dmxChannels; track channel; let i = $index) {\n <option [ngValue]=\"i\">\n {{ i + 1 }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\"></label>\n <div class=\"col-lg-9\">\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"addCopy(selectedFixture)\">\n {{ 'designer.fixture.add-copy' | translate }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n<div class=\"modal-footer\">\n <a class=\"mr-3 my-auto\" href=\"#\" role=\"button\" (click)=\"cancel(); (false)\">\n {{ 'designer.misc.cancel' | translate }}\n </a>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"ok()\">{{ 'designer.misc.ok' | translate }}</button>\n</div>\n", styles: [".list-group-item{padding:.3rem 1.25rem}.dmx-channel{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected{background-color:#fd7e14}.dmx-channel-overlapped{background-color:red;border:1px solid red;cursor:move}.card{overflow:auto}\n"] }]
5905
+ args: [{ selector: 'lib-app-fixture-pool', standalone: false, template: "<div class=\"modal-header\">\n <h4 class=\"modal-title pull-left\">{{ 'designer.fixture-pool.title' | translate }}</h4>\n <button type=\"button\" class=\"close pull-right\" aria-label=\"Close\" (click)=\"cancel(); (false)\">\n <span aria-hidden=\"true\">&times;</span>\n </button>\n</div>\n<div class=\"modal-body\">\n <div class=\"row\">\n <div class=\"col-6\">\n <!-- Search for profiles -->\n <input\n type=\"text\"\n class=\"form-control input-block mb-3\"\n id=\"searchSet\"\n placeholder=\"{{ 'designer.fixture-pool.search-profiles' | translate }}\"\n (input)=\"searchExpression = $event.target.value; filterProfiles()\"\n />\n\n <!-- Profiles -->\n <div class=\"card border-secondary w-100\" style=\"height: 200px\">\n <div class=\"card-body p-0 w-100\">\n <div class=\"list-group list-group-flush w-100\">\n @if (loadingProfiles) {\n <a class=\"list-group-item flex-column align-items-start d-flex\">\n <p class=\"mb-0 mx-auto\">\n <i class=\"fa fa-spinner fa-pulse fa-fw\"></i>\n </p>\n </a>\n } @for (profile of filteredProfiles | sort : 'uuid'; track profile) {\n <div class=\"list-group-item\">\n <div class=\"row\">\n <div class=\"col-10 col-auto my-auto pl-2\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(profile) }} mr-1\"></span> {{ profile.manufacturerName }} -\n {{ profile.name }}\n </p>\n </div>\n <div class=\"col-2 my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"addFixture(profile); (false)\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n <div>\n <p class=\"d-inline-block mb-0 mt-2\">\n Powered by the <a href=\"https://open-fixture-library.org/\" target=\"_blank\">Open Fixture Library</a>\n </p>\n <a\n class=\"mt-2 btn btn-secondary btn-sm float-right\"\n href=\"https://open-fixture-library.org/fixture-editor\"\n target=\"_blank\"\n role=\"button\"\n >\n <i class=\"fa fa-file-o\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.add-profile' | translate }}\n </a>\n @if (configService.localProfiles) {\n <button\n type=\"button\"\n class=\"mr-2 mt-2 btn btn-secondary btn-sm float-right\"\n (click)=\"updateProfiles(); (false)\"\n [disabled]=\"updatingProfiles\"\n role=\"button\"\n >\n @if (updatingProfiles) {\n <i class=\"fa fa-spinner fa-pulse fa-fw\" aria-hidden=\"true\"></i>\n } @if (!updatingProfiles) {\n <i class=\"fa fa-download fa-fw\" aria-hidden=\"true\"></i>\n }\n {{ 'designer.fixture-pool.update-profiles' | translate }}\n </button>\n }\n </div>\n </div>\n <div class=\"col-6\">\n <div class=\"row\">\n <!-- Add fixture from local profile -->\n <div class=\"col-6\">\n <button type=\"button\" class=\"btn btn-secondary\" (click)=\"createFixtureFromProfileFile()\" role=\"button\">\n <i class=\"fa fa-plus\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.create-fixture-from-profile-file' | translate }}\n </button>\n </div>\n\n <!-- Universe -->\n <div class=\"col-6\">\n <div class=\"form-group row\">\n <label class=\"col-lg-4 col-form-label\">{{ 'designer.fixture-pool.universe' | translate }}</label>\n <div class=\"col-lg-8\">\n <select class=\"custom-select\">\n <option>Universe 1</option>\n </select>\n </div>\n </div>\n </div>\n </div>\n\n <!-- Fixtures -->\n <div class=\"card border-secondary\" style=\"height: 235px\">\n <div class=\"card-body p-0\">\n <!-- TODO sortablejs breaks sortable lists in base designer view, as soon as it disappears -->\n <!-- Reproduce: select a fixture, deselect a fixture, open pool, close pool without changes, fixture is \"half\"-selected again -->\n <!-- <div class=\"list-group list-group-flush\" [sortablejs]=\"fixturePool\"> -->\n <div class=\"list-group list-group-flush\">\n @for (fixture of fixturePool; track fixture) {\n <div\n class=\"list-group-item\"\n [class.active]=\"fixture == selectedFixture\"\n (click)=\"selectFixture(fixture)\"\n style=\"cursor: pointer\"\n >\n <div class=\"row\">\n <!-- <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div> -->\n <div class=\"col-auto flex-grow pl-0 my-auto\">\n <p class=\"mb-0\">\n <span class=\"icon-{{ fixtureService.getFixtureIconClass(fixtureService.getProfileByUuid(fixture.profileUuid)) }} mr-1\">\n </span\n >{{ fixture.name }}\n </p>\n </div>\n <div class=\"col-auto my-auto\">\n <a class=\"btn btn-primary btn-sm float-right\" href=\"#\" role=\"button\" (click)=\"removeFixture(fixture); (false)\">\n <i class=\"fa fa-minus\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n </div>\n <div class=\"row mt-3\">\n <div class=\"col\">\n <!-- Tab navigation -->\n <ul class=\"nav nav-tabs mb-4\" id=\"myTab\" role=\"tablist\">\n <li class=\"nav-item\">\n <a class=\"nav-link active\" id=\"sets-tab\" data-toggle=\"tab\" href=\"#dmx\" role=\"tab\">\n <i class=\"icon-ola\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.dmx' | translate }}\n </a>\n </li>\n <li class=\"nav-item\">\n <a class=\"nav-link\" id=\"compositions-tab\" data-toggle=\"tab\" href=\"#settings\" role=\"tab\">\n <i class=\"fa fa-cog\" aria-hidden=\"true\"></i> {{ 'designer.fixture-pool.settings' | translate }}\n </a>\n </li>\n </ul>\n\n <!-- Tab content -->\n <div class=\"tab-content\" id=\"myTabContent\">\n <!-- DMX universe overview-->\n <div class=\"tab-pane show active\" id=\"dmx\" role=\"tabpanel\">\n <!-- Show all channel numbers -->\n <!-- <div class=\"form-group row\">\n <div class=\"col-auto flex-grow\"></div>\n <div class=\"col-lg-3 d-flex\">\n <div class=\"form-check my-auto ml-auto\">\n <input type=\"checkbox\" class=\"form-check-input\" id=\"showChannelNumbers\" [ngModel]=\"showChannelNumbers\"\n (ngModelChange)=\"showChannelNumbers = $event\">\n <label class=\"form-check-label\" for=\"showChannelNumbers\">Show channels</label>\n </div>\n </div>\n </div> -->\n\n <!-- List of DMX channels -->\n <div>\n @for (channel of dmxChannels; track $index; let i = $index) {\n <div\n class=\"dmx-channel\"\n [class.dmx-channel-occupied]=\"channelOccupied(i)\"\n [class.dmx-channel-occupied-start]=\"channelOccupiedStart(i)\"\n [class.dmx-channel-occupied-end]=\"channelOccupiedEnd(i)\"\n [class.dmx-channel-selected]=\"channelSelected(i)\"\n [class.dmx-channel-overlapped]=\"channelOverlapped(i)\"\n (mousedown)=\"channelMouseDown($event)\"\n (mouseover)=\"channelMouseOver($event)\"\n [attr.data-index]=\"i\"\n popover=\"{{ i + 1 }}\"\n placement=\"top\"\n triggers=\"mouseenter:mouseleave\"\n >\n <div class=\"d-flex w-100 dmx-channel-text\" [attr.data-index]=\"i\" [class.dmx-channel-text-visible]=\"showChannelNumbers\">\n <div class=\"m-auto\" style=\"font-size: 11px\" [attr.data-index]=\"i\"><small [attr.data-index]=\"i\">&nbsp;</small></div>\n </div>\n </div>\n }\n </div>\n </div>\n\n <!-- Fixture settings -->\n <div class=\"tab-pane\" id=\"settings\" role=\"tabpanel\">\n @if (selectedFixture && selectedFixtureProfile) {\n <div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\" for=\"fixtureName\">{{ 'designer.fixture-pool.fixture-name' | translate }}</label>\n <div class=\"col-lg-9\">\n <input type=\"text\" class=\"form-control\" [(ngModel)]=\"selectedFixture.name\" maxlength=\"200\" id=\"fixtureName\" />\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.mode' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.modeShortName\"\n (ngModelChange)=\"selectedFixture.modeShortName = $event\"\n >\n @for (mode of selectedFixtureProfile.modes; track mode) {\n <option [ngValue]=\"mode.shortName || mode.name\">\n {{ mode.name }}\n - {{ fixtureService.getModeChannelCount(selectedFixtureProfile, mode) }}\n {{ 'designer.fixture-pool.channels' | translate }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\">{{ 'designer.fixture-pool.first-channel' | translate }}</label>\n <div class=\"col-lg-9\">\n <select\n class=\"custom-select\"\n [ngModel]=\"selectedFixture.dmxFirstChannel\"\n (ngModelChange)=\"selectedFixture.dmxFirstChannel = $event\"\n >\n @for (channel of dmxChannels; track $index; let i = $index) {\n <option [ngValue]=\"i\">\n {{ i + 1 }}\n </option>\n }\n </select>\n </div>\n </div>\n <div class=\"form-group row\">\n <label class=\"col-lg-3 col-form-label\"></label>\n <div class=\"col-lg-9\">\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"addCopy(selectedFixture)\">\n {{ 'designer.fixture.add-copy' | translate }}\n </button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n </div>\n </div>\n</div>\n<div class=\"modal-footer\">\n <a class=\"mr-3 my-auto\" href=\"#\" role=\"button\" (click)=\"cancel(); (false)\">\n {{ 'designer.misc.cancel' | translate }}\n </a>\n <button type=\"button\" class=\"btn btn-primary\" (click)=\"ok()\">{{ 'designer.misc.ok' | translate }}</button>\n</div>\n", styles: [".list-group-item{padding:.3rem 1.25rem}.dmx-channel{display:flex;float:left;width:28px;border:1px solid white;margin-left:-1px;margin-bottom:-1px;padding-bottom:2px}.dmx-channel-occupied{background-color:#63462e;border-left:none;border-right:none;cursor:move}.dmx-channel-occupied-start{border-left:1px solid white;border-top-left-radius:8px;border-bottom-left-radius:8px}.dmx-channel-occupied-end{border-right:1px solid white;border-top-right-radius:8px;border-bottom-right-radius:8px}.dmx-channel-selected{background-color:#fd7e14}.dmx-channel-overlapped{background-color:red;border:1px solid red;cursor:move}.card{overflow:auto}\n"] }]
5807
5906
  }], () => [{ type: i1$1.BsModalRef }, { type: FixtureService }, { type: UuidService }, { type: ProjectService }, { type: PreviewService }, { type: i4.TranslateService }, { type: i3$1.ToastrService }, { type: PresetService }, { type: ConfigService }, { type: i1$1.BsModalService }], { mouseUp: [{
5808
5907
  type: HostListener,
5809
5908
  args: ['window:mouseup', ['$event']]
@@ -6940,7 +7039,7 @@ class TimelineGridComponent {
6940
7039
  }] }); })();
6941
7040
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(TimelineGridComponent, { className: "TimelineGridComponent", filePath: "lib/timeline/timeline-grid/timeline-grid.component.ts", lineNumber: 11 }); })();
6942
7041
 
6943
- const _c0$5 = ["waveWrapper"];
7042
+ const _c0$6 = ["waveWrapper"];
6944
7043
  const _c1 = ["waveElement"];
6945
7044
  function TimelineComponent_Conditional_6_For_2_Template(rf, ctx) { if (rf & 1) {
6946
7045
  i0.ɵɵelementStart(0, "option", 14);
@@ -7273,7 +7372,7 @@ class TimelineComponent {
7273
7372
  }
7274
7373
  static { this.ɵfac = function TimelineComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || TimelineComponent)(i0.ɵɵdirectiveInject(TimelineService), i0.ɵɵdirectiveInject(i0.ChangeDetectorRef), i0.ɵɵdirectiveInject(i1$1.BsModalService), i0.ɵɵdirectiveInject(UuidService), i0.ɵɵdirectiveInject(ProjectService), i0.ɵɵdirectiveInject(HotkeyTargetExcludeService), i0.ɵɵdirectiveInject(WarningDialogService), i0.ɵɵdirectiveInject(i1.HttpClient), i0.ɵɵdirectiveInject(ConfigService), i0.ɵɵdirectiveInject(PresetService), i0.ɵɵdirectiveInject(IntroService)); }; }
7275
7374
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: TimelineComponent, selectors: [["lib-app-timeline"]], viewQuery: function TimelineComponent_Query(rf, ctx) { if (rf & 1) {
7276
- i0.ɵɵviewQuery(_c0$5, 5);
7375
+ i0.ɵɵviewQuery(_c0$6, 5);
7277
7376
  i0.ɵɵviewQuery(_c1, 5);
7278
7377
  } if (rf & 2) {
7279
7378
  let _t;
@@ -8050,7 +8149,7 @@ function FixtureCapabilityColorWheelComponent_Conditional_10_For_2_Template(rf,
8050
8149
  } }
8051
8150
  function FixtureCapabilityColorWheelComponent_Conditional_10_Template(rf, ctx) { if (rf & 1) {
8052
8151
  i0.ɵɵelementStart(0, "div", 7);
8053
- i0.ɵɵrepeaterCreate(1, FixtureCapabilityColorWheelComponent_Conditional_10_For_2_Template, 2, 4, "div", 8, i0.ɵɵrepeaterTrackByIdentity);
8152
+ i0.ɵɵrepeaterCreate(1, FixtureCapabilityColorWheelComponent_Conditional_10_For_2_Template, 2, 4, "div", 8, i0.ɵɵrepeaterTrackByIndex);
8054
8153
  i0.ɵɵelementEnd();
8055
8154
  } if (rf & 2) {
8056
8155
  const ctx_r0 = i0.ɵɵnextContext();
@@ -8204,11 +8303,11 @@ class FixtureCapabilityColorWheelComponent {
8204
8303
  i0.ɵɵconditional(ctx.showContainer ? 9 : -1);
8205
8304
  i0.ɵɵadvance();
8206
8305
  i0.ɵɵconditional(ctx.wheel ? 10 : -1);
8207
- } }, dependencies: [i8.NgStyle, i3$2.CheckboxControlValueAccessor, i3$2.NgControlStatus, i3$2.NgModel, i4.TranslatePipe], styles: [".color[_ngcontent-%COMP%]{box-sizing:border-box;width:50px;height:50px;border:solid 1px #ced4da;cursor:pointer}.color-selected[_ngcontent-%COMP%]{border-width:3px;border-color:#fff}.color-selected-inner[_ngcontent-%COMP%]{border:solid 1px black;height:100%;width:100%}"] }); }
8306
+ } }, dependencies: [i9.NgStyle, i3$2.CheckboxControlValueAccessor, i3$2.NgControlStatus, i3$2.NgModel, i4.TranslatePipe], styles: [".color[_ngcontent-%COMP%]{box-sizing:border-box;width:50px;height:50px;border:solid 1px #ced4da;cursor:pointer}.color-selected[_ngcontent-%COMP%]{border-width:3px;border-color:#fff}.color-selected-inner[_ngcontent-%COMP%]{border:solid 1px black;height:100%;width:100%}"] }); }
8208
8307
  }
8209
8308
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FixtureCapabilityColorWheelComponent, [{
8210
8309
  type: Component,
8211
- args: [{ selector: 'lib-app-fixture-capability-color-wheel', standalone: false, template: "<div class=\"card border-secondary h-100\" [class.capability-deactivated]=\"getCurrentSlotNumber() == undefined\" style=\"min-height: 200px\">\n <div class=\"card-header\">\n <div class=\"my-auto\">\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"capabilityColorWheel{{ wheelIndex }}Active\"\n [ngModel]=\"getCurrentSlotNumber() != undefined\"\n (ngModelChange)=\"changeActive($event)\"\n />\n <label class=\"form-check-label\" for=\"capabilityColorWheel{{ wheelIndex }}Active\">\n {{ 'designer.fixture.capability-color' | translate }}\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"card-body h-100\">\n @if (showContainer) {\n <div>{{ _fixtureProfile.name }} - {{ _channel.name }}</div>\n } @if (wheel) {\n <div class=\"d-flex\" style=\"max-width: 240px; flex-wrap: wrap\">\n @for (slot of slotCapabilities; track slot; let i = $index) {\n <div\n (click)=\"selectSlotNumber(slot.capability.slotNumber)\"\n class=\"m-1 color\"\n [class.color-selected]=\"slotCapabilityIsSelected(slot.capability.slotNumber)\"\n [ngStyle]=\"getCapabilityColorStyle(slot)\"\n >\n @if (slotCapabilityIsSelected(slot.capability.slotNumber)) {\n <div (click)=\"selectSlotNumber(slot.capability.slotNumber)\" class=\"color-selected-inner\"></div>\n }\n </div>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".color{box-sizing:border-box;width:50px;height:50px;border:solid 1px #ced4da;cursor:pointer}.color-selected{border-width:3px;border-color:#fff}.color-selected-inner{border:solid 1px black;height:100%;width:100%}\n"] }]
8310
+ args: [{ selector: 'lib-app-fixture-capability-color-wheel', standalone: false, template: "<div class=\"card border-secondary h-100\" [class.capability-deactivated]=\"getCurrentSlotNumber() == undefined\" style=\"min-height: 200px\">\n <div class=\"card-header\">\n <div class=\"my-auto\">\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"capabilityColorWheel{{ wheelIndex }}Active\"\n [ngModel]=\"getCurrentSlotNumber() != undefined\"\n (ngModelChange)=\"changeActive($event)\"\n />\n <label class=\"form-check-label\" for=\"capabilityColorWheel{{ wheelIndex }}Active\">\n {{ 'designer.fixture.capability-color' | translate }}\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"card-body h-100\">\n @if (showContainer) {\n <div>{{ _fixtureProfile.name }} - {{ _channel.name }}</div>\n } @if (wheel) {\n <div class=\"d-flex\" style=\"max-width: 240px; flex-wrap: wrap\">\n @for (slot of slotCapabilities; track $index; let i = $index) {\n <div\n (click)=\"selectSlotNumber(slot.capability.slotNumber)\"\n class=\"m-1 color\"\n [class.color-selected]=\"slotCapabilityIsSelected(slot.capability.slotNumber)\"\n [ngStyle]=\"getCapabilityColorStyle(slot)\"\n >\n @if (slotCapabilityIsSelected(slot.capability.slotNumber)) {\n <div (click)=\"selectSlotNumber(slot.capability.slotNumber)\" class=\"color-selected-inner\"></div>\n }\n </div>\n }\n </div>\n }\n </div>\n</div>\n", styles: [".color{box-sizing:border-box;width:50px;height:50px;border:solid 1px #ced4da;cursor:pointer}.color-selected{border-width:3px;border-color:#fff}.color-selected-inner{border:solid 1px black;height:100%;width:100%}\n"] }]
8212
8311
  }], () => [{ type: PresetService }, { type: i0.ChangeDetectorRef }, { type: FixtureService }], { profile: [{
8213
8312
  type: Input
8214
8313
  }], channel: [{
@@ -8250,7 +8349,7 @@ function FixtureCapabilityComponent_Conditional_2_Template(rf, ctx) { if (rf & 1
8250
8349
  i0.ɵɵelementStart(0, "div", 4);
8251
8350
  i0.ɵɵconditionalCreate(1, FixtureCapabilityComponent_Conditional_2_Conditional_1_Template, 2, 0, "div", 5);
8252
8351
  i0.ɵɵconditionalCreate(2, FixtureCapabilityComponent_Conditional_2_Conditional_2_Template, 2, 0, "div", 5);
8253
- i0.ɵɵrepeaterCreate(3, FixtureCapabilityComponent_Conditional_2_For_4_Template, 2, 4, "div", 5, i0.ɵɵrepeaterTrackByIdentity);
8352
+ i0.ɵɵrepeaterCreate(3, FixtureCapabilityComponent_Conditional_2_For_4_Template, 2, 4, "div", 5, i0.ɵɵrepeaterTrackByIndex);
8254
8353
  i0.ɵɵpipe(5, "keyvalue");
8255
8354
  i0.ɵɵconditionalCreate(6, FixtureCapabilityComponent_Conditional_2_Conditional_6_Template, 2, 0, "div", 5);
8256
8355
  i0.ɵɵelementStart(7, "div", 6);
@@ -8391,11 +8490,11 @@ class FixtureCapabilityComponent {
8391
8490
  i0.ɵɵconditional(ctx.projectService.project.fixtures.length > 0 && ctx.presetService.selectedPreset && ctx.presetService.selectedPreset.fixtures.length == 0 ? 4 : -1);
8392
8491
  i0.ɵɵadvance();
8393
8492
  i0.ɵɵconditional(ctx.projectService.project.fixtures.length > 0 && ctx.presetService.selectedPreset && ctx.presetService.selectedPreset.fixtures.length > 0 && !ctx.hasCapabilityColorOrColorWheel && !ctx.hasCapabilityPanTilt ? 5 : -1);
8394
- } }, dependencies: [FixtureCapabilityColorComponent, FixtureCapabilityDimmerComponent, FixtureCapabilityPanTiltComponent, FixtureCapabilityColorWheelComponent, i8.KeyValuePipe, i4.TranslatePipe], encapsulation: 2, changeDetection: 0 }); }
8493
+ } }, dependencies: [FixtureCapabilityColorComponent, FixtureCapabilityDimmerComponent, FixtureCapabilityPanTiltComponent, FixtureCapabilityColorWheelComponent, i9.KeyValuePipe, i4.TranslatePipe], encapsulation: 2, changeDetection: 0 }); }
8395
8494
  }
8396
8495
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FixtureCapabilityComponent, [{
8397
8496
  type: Component,
8398
- args: [{ selector: 'lib-app-fixture-capability', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div class=\"card border-secondary panel h-100\" [class.card-intro-active]=\"introService.showStep('capabilities')\">\n <div class=\"card-body capability-container d-flex h-100\" style=\"overflow-y: hidden\">\n <!-- h-100 needs to be applied in chrome to avoid performance issues with many layouts (reflows)\n during sliding. But the class must not be applied e.g. in Safari, because the bottom margin is not correct\n anymore afterwards. -->\n @if (presetService.selectedPreset) {\n <div class=\"row m-0 pl-3\" [class.h-100]=\"isChrome()\">\n <!-- Dimmer -->\n <!-- the height attribute is required to avoid performance issues with many layouts (reflows)\n in Chrome during sliding -->\n @if (hasCapabilityDimmer) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-dimmer></lib-app-fixture-capability-dimmer>\n </div>\n }\n <!-- Color -->\n <!-- Also show for color wheel fixtures to approx. the color -->\n @if (hasCapabilityColorOrColorWheel) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-color></lib-app-fixture-capability-color>\n </div>\n }\n <!-- Color wheels -->\n @for (entry of colorWheelChannels | keyvalue; track entry; let i = $index) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-color-wheel\n [profile]=\"entry.key\"\n [channel]=\"entry.value\"\n [wheelIndex]=\"i\"\n [showContainer]=\"colorWheelChannels.size > 1\"\n ></lib-app-fixture-capability-color-wheel>\n </div>\n }\n <!-- Pan/Tilt -->\n @if (hasCapabilityPanTilt) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-pan-tilt></lib-app-fixture-capability-pan-tilt>\n </div>\n }\n <!-- Fix spacing at the end -->\n <div class=\"col col-auto p-0 my-3 mr-3\">&nbsp;</div>\n </div>\n } @if (projectService.project.fixtures.length == 0) {\n <div class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures' | translate }}</p>\n </div>\n } @if ( projectService.project.fixtures.length > 0 && presetService.selectedPreset && presetService.selectedPreset.fixtures.length == 0\n ) {\n <div class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures-selected' | translate }}</p>\n </div>\n } @if ( projectService.project.fixtures.length > 0 && presetService.selectedPreset && presetService.selectedPreset.fixtures.length > 0\n && !hasCapabilityColorOrColorWheel && !hasCapabilityPanTilt ) {\n <div class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-capabilities-available' | translate }}</p>\n </div>\n }\n </div>\n</div>\n" }]
8497
+ args: [{ selector: 'lib-app-fixture-capability', changeDetection: ChangeDetectionStrategy.OnPush, standalone: false, template: "<div class=\"card border-secondary panel h-100\" [class.card-intro-active]=\"introService.showStep('capabilities')\">\n <div class=\"card-body capability-container d-flex h-100\" style=\"overflow-y: hidden\">\n <!-- h-100 needs to be applied in chrome to avoid performance issues with many layouts (reflows)\n during sliding. But the class must not be applied e.g. in Safari, because the bottom margin is not correct\n anymore afterwards. -->\n @if (presetService.selectedPreset) {\n <div class=\"row m-0 pl-3\" [class.h-100]=\"isChrome()\">\n <!-- Dimmer -->\n <!-- the height attribute is required to avoid performance issues with many layouts (reflows)\n in Chrome during sliding -->\n @if (hasCapabilityDimmer) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-dimmer></lib-app-fixture-capability-dimmer>\n </div>\n }\n <!-- Color -->\n <!-- Also show for color wheel fixtures to approx. the color -->\n @if (hasCapabilityColorOrColorWheel) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-color></lib-app-fixture-capability-color>\n </div>\n }\n <!-- Color wheels -->\n @for (entry of colorWheelChannels | keyvalue; track $index; let i = $index) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-color-wheel\n [profile]=\"entry.key\"\n [channel]=\"entry.value\"\n [wheelIndex]=\"i\"\n [showContainer]=\"colorWheelChannels.size > 1\"\n ></lib-app-fixture-capability-color-wheel>\n </div>\n }\n <!-- Pan/Tilt -->\n @if (hasCapabilityPanTilt) {\n <div class=\"col col-auto p-0 my-3 mr-3\" style=\"height: calc(100% - 2rem)\">\n <lib-app-fixture-capability-pan-tilt></lib-app-fixture-capability-pan-tilt>\n </div>\n }\n <!-- Fix spacing at the end -->\n <div class=\"col col-auto p-0 my-3 mr-3\">&nbsp;</div>\n </div>\n } @if (projectService.project.fixtures.length == 0) {\n <div class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures' | translate }}</p>\n </div>\n } @if ( projectService.project.fixtures.length > 0 && presetService.selectedPreset && presetService.selectedPreset.fixtures.length == 0\n ) {\n <div class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures-selected' | translate }}</p>\n </div>\n } @if ( projectService.project.fixtures.length > 0 && presetService.selectedPreset && presetService.selectedPreset.fixtures.length > 0\n && !hasCapabilityColorOrColorWheel && !hasCapabilityPanTilt ) {\n <div class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-capabilities-available' | translate }}</p>\n </div>\n }\n </div>\n</div>\n" }]
8399
8498
  }], () => [{ type: PresetService }, { type: FixtureService }, { type: i0.ChangeDetectorRef }, { type: ProjectService }, { type: IntroService }], null); })();
8400
8499
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FixtureCapabilityComponent, { className: "FixtureCapabilityComponent", filePath: "lib/fixture/fixture-capability/fixture-capability.component.ts", lineNumber: 18 }); })();
8401
8500
 
@@ -8934,7 +9033,7 @@ class FixtureSettingsComponent {
8934
9033
  }], () => [{ type: FixtureService }, { type: PresetService }], null); })();
8935
9034
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FixtureSettingsComponent, { className: "FixtureSettingsComponent", filePath: "lib/fixture/fixture-settings/fixture-settings.component.ts", lineNumber: 11 }); })();
8936
9035
 
8937
- const _c0$4 = ["curveGrid"];
9036
+ const _c0$5 = ["curveGrid"];
8938
9037
  function EffectCurveComponent_For_74_Template(rf, ctx) { if (rf & 1) {
8939
9038
  const _r2 = i0.ɵɵgetCurrentView();
8940
9039
  i0.ɵɵelementStart(0, "div", 25)(1, "input", 27);
@@ -9015,26 +9114,19 @@ class EffectCurveComponent {
9015
9114
  // whether the effect is currently being edited (open) or not
9016
9115
  set isSelected(value) {
9017
9116
  if (value) {
9018
- // start the update timer
9019
- if (!this.gridUpdateSubscription) {
9020
- this.gridUpdateSubscription = timer(0, 15).subscribe(() => {
9021
- this.redraw();
9022
- });
9023
- }
9117
+ this.startUpdateTimer();
9024
9118
  }
9025
9119
  else {
9026
- // stop the update timer
9027
- if (this.gridUpdateSubscription) {
9028
- this.gridUpdateSubscription.unsubscribe();
9029
- this.gridUpdateSubscription = undefined;
9030
- }
9120
+ this.stopUpdateTimer();
9031
9121
  }
9032
9122
  }
9033
- constructor(presetService, animationService, fixtureService, translate) {
9123
+ constructor(presetService, animationService, fixtureService, translate, effectService, ngZone) {
9034
9124
  this.presetService = presetService;
9035
9125
  this.animationService = animationService;
9036
9126
  this.fixtureService = fixtureService;
9037
9127
  this.translate = translate;
9128
+ this.effectService = effectService;
9129
+ this.ngZone = ngZone;
9038
9130
  this.lengthMillisMin = 20;
9039
9131
  this.lengthMillisMax = 8000;
9040
9132
  this.amplitudeMin = 0;
@@ -9055,6 +9147,17 @@ class EffectCurveComponent {
9055
9147
  this.updateCapabilitiesAndChannels();
9056
9148
  });
9057
9149
  this.updateCapabilitiesAndChannels();
9150
+ this.effectsOpenChangedSubscription = this.effectService.effectsOpenChanged.subscribe(() => {
9151
+ if (this.effectService.effectsOpen) {
9152
+ this.startUpdateTimer();
9153
+ }
9154
+ else {
9155
+ this.stopUpdateTimer();
9156
+ }
9157
+ });
9158
+ if (this.effectService.effectsOpen) {
9159
+ this.startUpdateTimer();
9160
+ }
9058
9161
  }
9059
9162
  ngOnInit() {
9060
9163
  const canvas = this.curveGrid.nativeElement;
@@ -9063,6 +9166,26 @@ class EffectCurveComponent {
9063
9166
  this.maxHeight = canvas.height;
9064
9167
  this.redraw();
9065
9168
  }
9169
+ ngOnDestroy() {
9170
+ this.stopUpdateTimer();
9171
+ this.effectsOpenChangedSubscription.unsubscribe();
9172
+ }
9173
+ startUpdateTimer() {
9174
+ if (!this.gridUpdateSubscription) {
9175
+ // Avoid triggering change detection with each animation frame -> run outside zone
9176
+ this.ngZone.runOutsideAngular(() => {
9177
+ this.gridUpdateSubscription = timer(0, 15).subscribe(() => {
9178
+ this.redraw();
9179
+ });
9180
+ });
9181
+ }
9182
+ }
9183
+ stopUpdateTimer() {
9184
+ if (this.gridUpdateSubscription) {
9185
+ this.gridUpdateSubscription.unsubscribe();
9186
+ this.gridUpdateSubscription = undefined;
9187
+ }
9188
+ }
9066
9189
  drawCurrentValue(currMillis, radius, lineWidth, durationMillis, maxHeight) {
9067
9190
  const currVal = 1 - this.curve.getValueAtMillis(currMillis);
9068
9191
  const x = (this.maxWidth * (currMillis % durationMillis)) / durationMillis;
@@ -9300,9 +9423,9 @@ class EffectCurveComponent {
9300
9423
  this.presetService.previewLive();
9301
9424
  }
9302
9425
  }
9303
- static { this.ɵfac = function EffectCurveComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EffectCurveComponent)(i0.ɵɵdirectiveInject(PresetService), i0.ɵɵdirectiveInject(AnimationService), i0.ɵɵdirectiveInject(FixtureService), i0.ɵɵdirectiveInject(i4.TranslateService)); }; }
9426
+ static { this.ɵfac = function EffectCurveComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EffectCurveComponent)(i0.ɵɵdirectiveInject(PresetService), i0.ɵɵdirectiveInject(AnimationService), i0.ɵɵdirectiveInject(FixtureService), i0.ɵɵdirectiveInject(i4.TranslateService), i0.ɵɵdirectiveInject(EffectService), i0.ɵɵdirectiveInject(i0.NgZone)); }; }
9304
9427
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EffectCurveComponent, selectors: [["lib-app-effect-curve"]], viewQuery: function EffectCurveComponent_Query(rf, ctx) { if (rf & 1) {
9305
- i0.ɵɵviewQuery(_c0$4, 7);
9428
+ i0.ɵɵviewQuery(_c0$5, 7);
9306
9429
  } if (rf & 2) {
9307
9430
  let _t;
9308
9431
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.curveGrid = _t.first);
@@ -9397,7 +9520,7 @@ class EffectCurveComponent {
9397
9520
  i0.ɵɵelement(69, "i", 21);
9398
9521
  i0.ɵɵelementEnd()()();
9399
9522
  i0.ɵɵelementStart(70, "div", 22)(71, "div", 23)(72, "div", 24);
9400
- i0.ɵɵrepeaterCreate(73, EffectCurveComponent_For_74_Template, 5, 8, "div", 25, i0.ɵɵrepeaterTrackByIdentity);
9523
+ i0.ɵɵrepeaterCreate(73, EffectCurveComponent_For_74_Template, 5, 8, "div", 25, i0.ɵɵrepeaterTrackByIndex);
9401
9524
  i0.ɵɵelementEnd();
9402
9525
  i0.ɵɵelementStart(75, "div", 26);
9403
9526
  i0.ɵɵconditionalCreate(76, EffectCurveComponent_Conditional_76_Template, 4, 0, "div");
@@ -9470,12 +9593,12 @@ class EffectCurveComponent {
9470
9593
  i0.ɵɵconditional(ctx.availableProfiles.length > 1 ? 76 : -1);
9471
9594
  i0.ɵɵadvance();
9472
9595
  i0.ɵɵrepeater(i0.ɵɵpipeBind1(79, 81, ctx.availableChannels));
9473
- } }, dependencies: [i3$2.NgSelectOption, i3$2.ɵNgSelectMultipleOption, i3$2.DefaultValueAccessor, i3$2.CheckboxControlValueAccessor, i3$2.SelectControlValueAccessor, i3$2.NgControlStatus, i3$2.NgModel, i4$1.SliderComponent, i11.PopoverDirective, i8.AsyncPipe, i8.KeyValuePipe, i4.TranslatePipe], styles: [".curve-grid[_ngcontent-%COMP%]{background-color:#000;border:1px solid white}.applying-to[_ngcontent-%COMP%]{overflow-y:scroll;height:130px!important;background-color:#222;border:1px solid white;padding:.5rem}.applying-to[_ngcontent-%COMP%] .form-check[_ngcontent-%COMP%]:last-child{margin-bottom:.5rem}"] }); }
9596
+ } }, dependencies: [i3$2.NgSelectOption, i3$2.ɵNgSelectMultipleOption, i3$2.DefaultValueAccessor, i3$2.CheckboxControlValueAccessor, i3$2.SelectControlValueAccessor, i3$2.NgControlStatus, i3$2.NgModel, i4$1.SliderComponent, i11.PopoverDirective, i9.AsyncPipe, i9.KeyValuePipe, i4.TranslatePipe], styles: [".curve-grid[_ngcontent-%COMP%]{background-color:#000;border:1px solid white}.applying-to[_ngcontent-%COMP%]{overflow-y:scroll;height:130px!important;background-color:#222;border:1px solid white;padding:.5rem}.applying-to[_ngcontent-%COMP%] .form-check[_ngcontent-%COMP%]:last-child{margin-bottom:.5rem}"] }); }
9474
9597
  }
9475
9598
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(EffectCurveComponent, [{
9476
9599
  type: Component,
9477
- args: [{ selector: 'lib-app-effect-curve', standalone: false, template: "<div class=\"mr-3\" style=\"float: left\">\n <div class=\"mb-2\">\n <select\n [ngModel]=\"curve.curveType\"\n (ngModelChange)=\"curve.curveType = $event; presetService.previewLive()\"\n style=\"width: 200px; height: 20px\"\n >\n <option [value]=\"'sine'\">\n {{ 'designer.effect.curve-sine' | translate }}\n </option>\n <option [value]=\"'square'\">\n {{ 'designer.effect.curve-square' | translate }}\n </option>\n <!-- <option [value]=\"'triangle'\">\n {{ 'designer.effect.curve-triangle' | translate }}</option>\n <option [value]=\"'sawtooth'\">\n {{ 'designer.effect.curve-sawtooth' | translate }}</option>\n <option [value]=\"'reverse-sawtooth'\">\n {{ 'designer.effect.curve-reverse-sawtooth' | translate }}</option> -->\n </select>\n </div>\n <div>\n <canvas #curveGrid class=\"curve-grid\" width=\"200\" height=\"100\" viewBox=\"150 -75 4850 5150\" preserveAspectRatio=\"none\"></canvas>\n </div>\n</div>\n\n<div class=\"mr-4\" style=\"float: left\">\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-length' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.lengthMillis\"\n style=\"width: 80px\"\n [tooltip]=\"'hide'\"\n [value]=\"0\"\n [min]=\"lengthMillisMin\"\n [max]=\"lengthMillisMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.lengthMillis\" (ngModelChange)=\"setLengthMillis($event); redraw()\" />\n </div>\n <div class=\"my-auto ml-1\">\n {{ 'designer.misc.ms' | translate }}\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-amplitude' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.amplitude\"\n style=\"width: 80px\"\n [tooltip]=\"'hide'\"\n [min]=\"amplitudeMin\"\n [max]=\"amplitudeMax\"\n [step]=\"0.01\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.amplitude\" (ngModelChange)=\"setAmplitude($event); redraw()\" />\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-position' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.position\"\n style=\"width: 80px; height: 18px\"\n [tooltip]=\"'hide'\"\n [min]=\"percentageMin\"\n [max]=\"percentageMax\"\n [step]=\"0.01\"\n >\n </mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.position\" (ngModelChange)=\"setPosition($event); redraw()\" />\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-phase' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.phaseMillis\"\n style=\"width: 80px; height: 18px\"\n [tooltip]=\"'hide'\"\n [min]=\"phaseMillisMin\"\n [max]=\"phaseMillisMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.phaseMillis\" (ngModelChange)=\"setPhaseMillis($event); redraw()\" />\n </div>\n <div class=\"my-auto ml-1\">\n {{ 'designer.misc.ms' | translate }}\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-chase' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.phasingMillis\"\n style=\"width: 80px; height: 18px\"\n [tooltip]=\"'hide'\"\n [min]=\"phasingMillisMin\"\n [max]=\"phasingMillisMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.phasingMillis\" (ngModelChange)=\"setPhasingMillis($event); redraw()\" />\n </div>\n <div class=\"my-auto ml-1\">\n {{ 'designer.misc.ms' | translate }}\n </div>\n </div>\n</div>\n\n<!-- Menu for the capabilities and channels-->\n<div class=\"col col-auto p-0\" style=\"margin-right: 1px; width: 50px; float: left\">\n <div class=\"nav flex-column nav-pills\" id=\"v-pills-tab\" role=\"tablist\" aria-orientation=\"vertical\">\n <a\n class=\"nav-link px-3 active\"\n id=\"v-pills-effect-capabilities-tab\"\n popover=\"{{ 'designer.misc.capabilities' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-effect-capabilities-{{ curve?.uuid }}\"\n role=\"tab\"\n aria-controls=\"v-pills-capabilities\"\n aria-selected=\"true\"\n >\n <i class=\"fa fa-bolt fa-fw\" aria-hidden=\"true\"></i>\n </a>\n <a\n class=\"nav-link px-3\"\n id=\"v-pills-effect-channels-tab\"\n popover=\"{{ 'designer.misc.channels' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-effect-channels-{{ curve?.uuid }}\"\n role=\"tab\"\n aria-controls=\"v-pills-channels\"\n aria-selected=\"false\"\n >\n <i class=\"fa fa-sliders fa-fw\" aria-hidden=\"true\"></i>\n </a>\n </div>\n</div>\n\n<div class=\"h-100\" class=\"applying-to\">\n <div class=\"tab-content h-100\" id=\"v-pills-tabContent\">\n <div class=\"tab-pane h-100 show active\" id=\"v-pills-effect-capabilities-{{ curve?.uuid }}\" role=\"tabpanel\">\n <!-- Capabilities-->\n @for (capability of availableCapabilities; track capability; let i = $index) {\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"capability_{{ curve?.uuid + '_' + i }}\"\n [ngModel]=\"capabilityChecked(capability)\"\n (change)=\"toggleCapability($event, capability)\"\n />\n <label class=\"form-check-label\" for=\"capability_{{ curve?.uuid + '_' + i }}\">{{ getCapabilityName(capability) | async }}</label>\n </div>\n }\n </div>\n <div class=\"tab-pane h-100 show\" id=\"v-pills-effect-channels-{{ curve?.uuid }}\" role=\"tabpanel\">\n <!-- channels -->\n\n <!-- profile selection -->\n @if (availableProfiles.length > 1) {\n <div>\n @for (profile of availableProfiles; track profile; let i = $index) {\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"channel_profile_{{ curve?.uuid }}_{{ profile.uuid }}\"\n [ngModel]=\"selectedProfiles.indexOf(profile) >= 0\"\n (change)=\"changeProfileSelection($event, profile)\"\n />\n <label class=\"form-check-label\" for=\"channel_profile_{{ curve?.uuid }}_{{ profile.uuid }}\">{{ profile.name }}</label>\n </div>\n }\n <hr class=\"my-1\" style=\"border-color: white\" />\n </div>\n }\n\n <!-- channels -->\n @for (entry of availableChannels | keyvalue; track entry; let i = $index) { @for (channel of entry.value; track channel; let j =\n $index) {\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"channel_{{ curve?.uuid }}_{{ i }}_{{ j }}\"\n [ngModel]=\"channelChecked(entry.key, channel)\"\n (change)=\"toggleChannel($event, entry.key, channel)\"\n />\n <label class=\"form-check-label\" for=\"channel_{{ curve?.uuid }}_{{ i }}_{{ j }}\">{{\n getChannelName(entry.key.name, channel.name)\n }}</label>\n </div>\n } }\n </div>\n </div>\n</div>\n", styles: [".curve-grid{background-color:#000;border:1px solid white}.applying-to{overflow-y:scroll;height:130px!important;background-color:#222;border:1px solid white;padding:.5rem}.applying-to .form-check:last-child{margin-bottom:.5rem}\n"] }]
9478
- }], () => [{ type: PresetService }, { type: AnimationService }, { type: FixtureService }, { type: i4.TranslateService }], { curve: [{
9600
+ args: [{ selector: 'lib-app-effect-curve', standalone: false, template: "<div class=\"mr-3\" style=\"float: left\">\n <div class=\"mb-2\">\n <select\n [ngModel]=\"curve.curveType\"\n (ngModelChange)=\"curve.curveType = $event; presetService.previewLive()\"\n style=\"width: 200px; height: 20px\"\n >\n <option [value]=\"'sine'\">\n {{ 'designer.effect.curve-sine' | translate }}\n </option>\n <option [value]=\"'square'\">\n {{ 'designer.effect.curve-square' | translate }}\n </option>\n <!-- <option [value]=\"'triangle'\">\n {{ 'designer.effect.curve-triangle' | translate }}</option>\n <option [value]=\"'sawtooth'\">\n {{ 'designer.effect.curve-sawtooth' | translate }}</option>\n <option [value]=\"'reverse-sawtooth'\">\n {{ 'designer.effect.curve-reverse-sawtooth' | translate }}</option> -->\n </select>\n </div>\n <div>\n <canvas #curveGrid class=\"curve-grid\" width=\"200\" height=\"100\" viewBox=\"150 -75 4850 5150\" preserveAspectRatio=\"none\"></canvas>\n </div>\n</div>\n\n<div class=\"mr-4\" style=\"float: left\">\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-length' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.lengthMillis\"\n style=\"width: 80px\"\n [tooltip]=\"'hide'\"\n [value]=\"0\"\n [min]=\"lengthMillisMin\"\n [max]=\"lengthMillisMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.lengthMillis\" (ngModelChange)=\"setLengthMillis($event); redraw()\" />\n </div>\n <div class=\"my-auto ml-1\">\n {{ 'designer.misc.ms' | translate }}\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-amplitude' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.amplitude\"\n style=\"width: 80px\"\n [tooltip]=\"'hide'\"\n [min]=\"amplitudeMin\"\n [max]=\"amplitudeMax\"\n [step]=\"0.01\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.amplitude\" (ngModelChange)=\"setAmplitude($event); redraw()\" />\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-position' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.position\"\n style=\"width: 80px; height: 18px\"\n [tooltip]=\"'hide'\"\n [min]=\"percentageMin\"\n [max]=\"percentageMax\"\n [step]=\"0.01\"\n >\n </mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.position\" (ngModelChange)=\"setPosition($event); redraw()\" />\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-phase' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.phaseMillis\"\n style=\"width: 80px; height: 18px\"\n [tooltip]=\"'hide'\"\n [min]=\"phaseMillisMin\"\n [max]=\"phaseMillisMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.phaseMillis\" (ngModelChange)=\"setPhaseMillis($event); redraw()\" />\n </div>\n <div class=\"my-auto ml-1\">\n {{ 'designer.misc.ms' | translate }}\n </div>\n </div>\n\n <div class=\"d-flex\">\n <div class=\"my-auto\" style=\"width: 100px; float: left\">\n {{ 'designer.effect.curve-chase' | translate }}\n </div>\n <div class=\"my-auto\" style=\"float: left\">\n <mv-slider\n (change)=\"redraw(); presetService.previewLive()\"\n [(value)]=\"curve.phasingMillis\"\n style=\"width: 80px; height: 18px\"\n [tooltip]=\"'hide'\"\n [min]=\"phasingMillisMin\"\n [max]=\"phasingMillisMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n <div class=\"my-auto\">\n <input type=\"text\" class=\"slider-input\" [ngModel]=\"curve.phasingMillis\" (ngModelChange)=\"setPhasingMillis($event); redraw()\" />\n </div>\n <div class=\"my-auto ml-1\">\n {{ 'designer.misc.ms' | translate }}\n </div>\n </div>\n</div>\n\n<!-- Menu for the capabilities and channels-->\n<div class=\"col col-auto p-0\" style=\"margin-right: 1px; width: 50px; float: left\">\n <div class=\"nav flex-column nav-pills\" id=\"v-pills-tab\" role=\"tablist\" aria-orientation=\"vertical\">\n <a\n class=\"nav-link px-3 active\"\n id=\"v-pills-effect-capabilities-tab\"\n popover=\"{{ 'designer.misc.capabilities' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-effect-capabilities-{{ curve?.uuid }}\"\n role=\"tab\"\n aria-controls=\"v-pills-capabilities\"\n aria-selected=\"true\"\n >\n <i class=\"fa fa-bolt fa-fw\" aria-hidden=\"true\"></i>\n </a>\n <a\n class=\"nav-link px-3\"\n id=\"v-pills-effect-channels-tab\"\n popover=\"{{ 'designer.misc.channels' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-effect-channels-{{ curve?.uuid }}\"\n role=\"tab\"\n aria-controls=\"v-pills-channels\"\n aria-selected=\"false\"\n >\n <i class=\"fa fa-sliders fa-fw\" aria-hidden=\"true\"></i>\n </a>\n </div>\n</div>\n\n<div class=\"h-100\" class=\"applying-to\">\n <div class=\"tab-content h-100\" id=\"v-pills-tabContent\">\n <div class=\"tab-pane h-100 show active\" id=\"v-pills-effect-capabilities-{{ curve?.uuid }}\" role=\"tabpanel\">\n <!-- Capabilities-->\n @for (capability of availableCapabilities; track $index; let i = $index) {\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"capability_{{ curve?.uuid + '_' + i }}\"\n [ngModel]=\"capabilityChecked(capability)\"\n (change)=\"toggleCapability($event, capability)\"\n />\n <label class=\"form-check-label\" for=\"capability_{{ curve?.uuid + '_' + i }}\">{{ getCapabilityName(capability) | async }}</label>\n </div>\n }\n </div>\n <div class=\"tab-pane h-100 show\" id=\"v-pills-effect-channels-{{ curve?.uuid }}\" role=\"tabpanel\">\n <!-- channels -->\n\n <!-- profile selection -->\n @if (availableProfiles.length > 1) {\n <div>\n @for (profile of availableProfiles; track profile; let i = $index) {\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"channel_profile_{{ curve?.uuid }}_{{ profile.uuid }}\"\n [ngModel]=\"selectedProfiles.indexOf(profile) >= 0\"\n (change)=\"changeProfileSelection($event, profile)\"\n />\n <label class=\"form-check-label\" for=\"channel_profile_{{ curve?.uuid }}_{{ profile.uuid }}\">{{ profile.name }}</label>\n </div>\n }\n <hr class=\"my-1\" style=\"border-color: white\" />\n </div>\n }\n\n <!-- channels -->\n @for (entry of availableChannels | keyvalue; track entry; let i = $index) { @for (channel of entry.value; track channel; let j =\n $index) {\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n class=\"form-check-input\"\n id=\"channel_{{ curve?.uuid }}_{{ i }}_{{ j }}\"\n [ngModel]=\"channelChecked(entry.key, channel)\"\n (change)=\"toggleChannel($event, entry.key, channel)\"\n />\n <label class=\"form-check-label\" for=\"channel_{{ curve?.uuid }}_{{ i }}_{{ j }}\">{{\n getChannelName(entry.key.name, channel.name)\n }}</label>\n </div>\n } }\n </div>\n </div>\n</div>\n", styles: [".curve-grid{background-color:#000;border:1px solid white}.applying-to{overflow-y:scroll;height:130px!important;background-color:#222;border:1px solid white;padding:.5rem}.applying-to .form-check:last-child{margin-bottom:.5rem}\n"] }]
9601
+ }], () => [{ type: PresetService }, { type: AnimationService }, { type: FixtureService }, { type: i4.TranslateService }, { type: EffectService }, { type: i0.NgZone }], { curve: [{
9479
9602
  type: Input
9480
9603
  }], isSelected: [{
9481
9604
  type: Input
@@ -9483,9 +9606,9 @@ class EffectCurveComponent {
9483
9606
  type: ViewChild,
9484
9607
  args: ['curveGrid', { static: true }]
9485
9608
  }] }); })();
9486
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EffectCurveComponent, { className: "EffectCurveComponent", filePath: "lib/effect/effect-curve/effect-curve.component.ts", lineNumber: 20 }); })();
9609
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(EffectCurveComponent, { className: "EffectCurveComponent", filePath: "lib/effect/effect-curve/effect-curve.component.ts", lineNumber: 21 }); })();
9487
9610
 
9488
- const _c0$3 = ["panTiltGrid"];
9611
+ const _c0$4 = ["panTiltGrid"];
9489
9612
  class EffectPanTiltComponent {
9490
9613
  constructor() {
9491
9614
  this.points = [
@@ -9501,7 +9624,7 @@ class EffectPanTiltComponent {
9501
9624
  ngOnInit() { }
9502
9625
  static { this.ɵfac = function EffectPanTiltComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || EffectPanTiltComponent)(); }; }
9503
9626
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: EffectPanTiltComponent, selectors: [["lib-app-effect-pan-tilt"]], viewQuery: function EffectPanTiltComponent_Query(rf, ctx) { if (rf & 1) {
9504
- i0.ɵɵviewQuery(_c0$3, 5);
9627
+ i0.ɵɵviewQuery(_c0$4, 5);
9505
9628
  } if (rf & 2) {
9506
9629
  let _t;
9507
9630
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.panTiltGrid = _t.first);
@@ -9866,6 +9989,7 @@ class PresetSettingsComponent {
9866
9989
  }] }); })();
9867
9990
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PresetSettingsComponent, { className: "PresetSettingsComponent", filePath: "lib/preset/preset-settings/preset-settings.component.ts", lineNumber: 11 }); })();
9868
9991
 
9992
+ const _c0$3 = ["tree"];
9869
9993
  function PresetComponent_For_13_Template(rf, ctx) { if (rf & 1) {
9870
9994
  const _r1 = i0.ɵɵgetCurrentView();
9871
9995
  i0.ɵɵelementStart(0, "div", 9);
@@ -9899,8 +10023,89 @@ class PresetComponent {
9899
10023
  this.projectService = projectService;
9900
10024
  this.introService = introService;
9901
10025
  this.modalService = modalService;
10026
+ let actionMapping = {
10027
+ mouse: {
10028
+ click: (tree, node, $event) => {
10029
+ // block activation for folders (or any condition you want)
10030
+ if (node.data.isFolder) {
10031
+ // optional: make click expand/collapse instead
10032
+ TREE_ACTIONS.TOGGLE_EXPANDED(tree, node, $event);
10033
+ return;
10034
+ }
10035
+ TREE_ACTIONS.ACTIVATE(tree, node, $event);
10036
+ },
10037
+ },
10038
+ keys: {
10039
+ [KEYS.ENTER]: (tree, node, $event) => {
10040
+ if (!node.data.isFolder)
10041
+ TREE_ACTIONS.ACTIVATE(tree, node, $event);
10042
+ },
10043
+ [KEYS.SPACE]: (tree, node, $event) => {
10044
+ if (!node.data.isFolder)
10045
+ TREE_ACTIONS.ACTIVATE(tree, node, $event);
10046
+ },
10047
+ },
10048
+ };
10049
+ this.treeOptions = {
10050
+ displayField: 'name',
10051
+ isExpandedField: 'expanded',
10052
+ idField: 'uuid',
10053
+ hasChildrenField: 'nodes',
10054
+ // actionMapping: {
10055
+ // mouse: {
10056
+ // dblClick: (tree, node, $event) => {
10057
+ // if (node.hasChildren) TREE_ACTIONS.TOGGLE_EXPANDED(tree, node, $event);
10058
+ // }
10059
+ // },
10060
+ // keys: {
10061
+ // [KEYS.ENTER]: (tree, node, $event) => {
10062
+ // node.expandAll();
10063
+ // }
10064
+ // }
10065
+ // },
10066
+ actionMapping: actionMapping,
10067
+ nodeHeight: 23,
10068
+ allowDrag: (node) => {
10069
+ return true;
10070
+ },
10071
+ allowDrop: (node, target) => {
10072
+ // only allow dropping into folders or to the root level
10073
+ return !target.parent.data.id || target.parent.data.isFolder;
10074
+ },
10075
+ allowDragoverStyling: true,
10076
+ levelPadding: 10,
10077
+ useVirtualScroll: true,
10078
+ animateExpand: true,
10079
+ scrollOnActivate: true,
10080
+ animateSpeed: 10,
10081
+ animateAcceleration: 1.2,
10082
+ scrollContainer: document.documentElement,
10083
+ };
10084
+ this.treeNodes = [
10085
+ {
10086
+ id: 1,
10087
+ name: 'root1',
10088
+ isFolder: true,
10089
+ children: [
10090
+ { id: 2, name: 'child1', isFolder: false },
10091
+ { id: 3, name: 'child2', isFolder: false },
10092
+ ],
10093
+ },
10094
+ {
10095
+ id: 4,
10096
+ name: 'root1',
10097
+ isFolder: true,
10098
+ children: [
10099
+ { id: 5, name: 'child1', isFolder: false },
10100
+ { id: 6, name: 'child2', isFolder: false },
10101
+ ],
10102
+ },
10103
+ ];
9902
10104
  }
9903
10105
  ngOnInit() { }
10106
+ onActivate(event) {
10107
+ console.log(event);
10108
+ }
9904
10109
  selectPreset(index) {
9905
10110
  this.projectService.project.previewPreset = true;
9906
10111
  this.presetService.selectPreset(index);
@@ -9948,7 +10153,12 @@ class PresetComponent {
9948
10153
  });
9949
10154
  }
9950
10155
  static { this.ɵfac = function PresetComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PresetComponent)(i0.ɵɵdirectiveInject(PresetService), i0.ɵɵdirectiveInject(SceneService), i0.ɵɵdirectiveInject(ProjectService), i0.ɵɵdirectiveInject(IntroService), i0.ɵɵdirectiveInject(i1$1.BsModalService)); }; }
9951
- static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PresetComponent, selectors: [["lib-app-preset"]], standalone: false, decls: 14, vars: 6, consts: [[1, "card", "border-secondary", "h-100", "panel", "card-intro-preset", "card-intro-active"], [1, "card-header", "d-flex"], [1, "ml-auto"], ["href", "#", 1, "btn", "btn-secondary", "m-0,", "p-0", 3, "click"], ["aria-hidden", "true", 1, "fa", "fa-minus-circle", "fa-fw"], ["aria-hidden", "true", 1, "fa", "fa-plus-circle", "fa-fw"], [1, "card-body", "h-100", "p-0"], [1, "list-group", 3, "sortablejs"], [1, "list-group-item", 3, "active-light", "active", "inactive-list-item"], [1, "list-group-item", 3, "click"], [1, "row", "d-flex", 2, "cursor", "pointer"], [1, "col-auto", "list-sort-handle", "my-auto", 2, "cursor", "move", "cursor", "-webkit-grabbing"], ["aria-hidden", "true", 1, "fa", "fa-bars"], [1, "form-check"], ["type", "checkbox", "id", "active", 1, "form-check-input", 3, "ngModelChange", "click", "disabled", "ngModel"], [1, "my-auto", "ml-auto", "mr-2", "d-flex"], ["type", "button", 1, "btn", "btn-secondary", "btn-sm", "py-0", "px-1", 3, "click"]], template: function PresetComponent_Template(rf, ctx) { if (rf & 1) {
10156
+ static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PresetComponent, selectors: [["lib-app-preset"]], viewQuery: function PresetComponent_Query(rf, ctx) { if (rf & 1) {
10157
+ i0.ɵɵviewQuery(_c0$3, 5);
10158
+ } if (rf & 2) {
10159
+ let _t;
10160
+ i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.tree = _t.first);
10161
+ } }, standalone: false, decls: 14, vars: 6, consts: [[1, "card", "border-secondary", "h-100", "panel", "card-intro-preset", "card-intro-active"], [1, "card-header", "d-flex"], [1, "ml-auto"], ["href", "#", 1, "btn", "btn-secondary", "m-0,", "p-0", 3, "click"], ["aria-hidden", "true", 1, "fa", "fa-minus-circle", "fa-fw"], ["aria-hidden", "true", 1, "fa", "fa-plus-circle", "fa-fw"], [1, "card-body", "h-100", "p-0"], [1, "list-group", 3, "sortablejs"], [1, "list-group-item", 3, "active-light", "active", "inactive-list-item"], [1, "list-group-item", 3, "click"], [1, "row", "d-flex", 2, "cursor", "pointer"], [1, "col-auto", "list-sort-handle", "my-auto", 2, "cursor", "move", "cursor", "-webkit-grabbing"], ["aria-hidden", "true", 1, "fa", "fa-bars"], [1, "form-check"], ["type", "checkbox", "id", "active", 1, "form-check-input", 3, "ngModelChange", "click", "disabled", "ngModel"], [1, "my-auto", "ml-auto", "mr-2", "d-flex"], ["type", "button", 1, "btn", "btn-secondary", "btn-sm", "py-0", "px-1", 3, "click"]], template: function PresetComponent_Template(rf, ctx) { if (rf & 1) {
9952
10162
  i0.ɵɵelementStart(0, "div", 0)(1, "div", 1)(2, "div");
9953
10163
  i0.ɵɵtext(3);
9954
10164
  i0.ɵɵpipe(4, "translate");
@@ -9976,9 +10186,12 @@ class PresetComponent {
9976
10186
  }
9977
10187
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PresetComponent, [{
9978
10188
  type: Component,
9979
- args: [{ selector: 'lib-app-preset', standalone: false, template: "<div\n class=\"card border-secondary h-100 panel card-intro-preset card-intro-active\"\n [class.card-intro-active]=\"introService.showStep('presets')\"\n>\n <div class=\"card-header d-flex\">\n <div>\n {{ 'designer.preset.title' | translate }}\n </div>\n <div class=\"ml-auto\">\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"removePreset(); (false)\"\n ><i class=\"fa fa-minus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"addPreset(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n\n <div class=\"card-body h-100 p-0\">\n <!-- List of presets -->\n <div class=\"list-group\" [sortablejs]=\"projectService.project.presets\">\n @for (item of projectService.project.presets; track item; let i = $index) {\n <div\n class=\"list-group-item\"\n (click)=\"selectPreset(i)\"\n [class.active-light]=\"!projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.active]=\"projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.inactive-list-item]=\"!sceneService.presetIsSelected(item)\"\n >\n <div class=\"row d-flex\" style=\"cursor: pointer\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n [disabled]=\"!enableCheckbox()\"\n class=\"form-check-input\"\n id=\"active\"\n [ngModel]=\"sceneService.presetIsSelected(item)\"\n (ngModelChange)=\"activatePreset($event, i)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n <div>\n {{ item.name }}\n </div>\n <div class=\"my-auto ml-auto mr-2 d-flex\">\n <button type=\"button\" class=\"btn btn-secondary btn-sm py-0 px-1\" (click)=\"openSettings(item); (false)\">...</button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n" }]
9980
- }], () => [{ type: PresetService }, { type: SceneService }, { type: ProjectService }, { type: IntroService }, { type: i1$1.BsModalService }], null); })();
9981
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PresetComponent, { className: "PresetComponent", filePath: "lib/preset/preset.component.ts", lineNumber: 16 }); })();
10189
+ args: [{ selector: 'lib-app-preset', standalone: false, template: "<div\n class=\"card border-secondary h-100 panel card-intro-preset card-intro-active\"\n [class.card-intro-active]=\"introService.showStep('presets')\"\n>\n <div class=\"card-header d-flex\">\n <div>\n {{ 'designer.preset.title' | translate }}\n </div>\n <div class=\"ml-auto\">\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"removePreset(); (false)\"\n ><i class=\"fa fa-minus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n <a href=\"#\" class=\"btn btn-secondary m-0, p-0\" (click)=\"addPreset(); (false)\"\n ><i class=\"fa fa-plus-circle fa-fw\" aria-hidden=\"true\"></i\n ></a>\n </div>\n </div>\n\n <div class=\"card-body h-100 p-0\">\n <!-- List of presets -->\n <!-- <tree-root #tree [nodes]=\"treeNodes\" [options]=\"treeOptions\" (activate)=\"onActivate($event)\">\n <ng-template #treeNodeTemplate let-node let-index=\"index\">\n <span>{{ node.data.name }}</span>\n </ng-template>\n </tree-root> -->\n\n <div class=\"list-group\" [sortablejs]=\"projectService.project.presets\">\n @for (item of projectService.project.presets; track item; let i = $index) {\n <div\n class=\"list-group-item\"\n (click)=\"selectPreset(i)\"\n [class.active-light]=\"!projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.active]=\"projectService.project.previewPreset && item == presetService.selectedPreset\"\n [class.inactive-list-item]=\"!sceneService.presetIsSelected(item)\"\n >\n <div class=\"row d-flex\" style=\"cursor: pointer\">\n <div class=\"col-auto list-sort-handle my-auto\" style=\"cursor: move; cursor: -webkit-grabbing\">\n <i class=\"fa fa-bars\" aria-hidden=\"true\"></i>\n </div>\n <div class=\"form-check\">\n <input\n type=\"checkbox\"\n [disabled]=\"!enableCheckbox()\"\n class=\"form-check-input\"\n id=\"active\"\n [ngModel]=\"sceneService.presetIsSelected(item)\"\n (ngModelChange)=\"activatePreset($event, i)\"\n (click)=\"$event.stopPropagation()\"\n />\n </div>\n <div>\n {{ item.name }}\n </div>\n <div class=\"my-auto ml-auto mr-2 d-flex\">\n <button type=\"button\" class=\"btn btn-secondary btn-sm py-0 px-1\" (click)=\"openSettings(item); (false)\">...</button>\n </div>\n </div>\n </div>\n }\n </div>\n </div>\n</div>\n" }]
10190
+ }], () => [{ type: PresetService }, { type: SceneService }, { type: ProjectService }, { type: IntroService }, { type: i1$1.BsModalService }], { tree: [{
10191
+ type: ViewChild,
10192
+ args: ['tree']
10193
+ }] }); })();
10194
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PresetComponent, { className: "PresetComponent", filePath: "lib/preset/preset.component.ts", lineNumber: 17 }); })();
9982
10195
 
9983
10196
  class MasterDimmerComponent {
9984
10197
  constructor(projectService, changeDetectorRef, presetService) {
@@ -10542,7 +10755,7 @@ class FixtureChannelComponent {
10542
10755
  i0.ɵɵconditional(ctx.projectService.project.fixtures.length == 0 ? 3 : -1);
10543
10756
  i0.ɵɵadvance();
10544
10757
  i0.ɵɵconditional(ctx.projectService.project.fixtures.length > 0 && ctx.presetService.selectedPreset && ctx.presetService.selectedPreset.fixtures.length == 0 ? 4 : -1);
10545
- } }, dependencies: [i3$2.CheckboxControlValueAccessor, i3$2.NgControlStatus, i3$2.NgModel, FixtureCapabilityChannelComponent, i8.KeyValuePipe, i4.TranslatePipe], encapsulation: 2 }); }
10758
+ } }, dependencies: [i3$2.CheckboxControlValueAccessor, i3$2.NgControlStatus, i3$2.NgModel, FixtureCapabilityChannelComponent, i9.KeyValuePipe, i4.TranslatePipe], encapsulation: 2 }); }
10546
10759
  }
10547
10760
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FixtureChannelComponent, [{
10548
10761
  type: Component,
@@ -10633,7 +10846,7 @@ class IntroComponent {
10633
10846
  i0.ɵɵconditionalCreate(0, IntroComponent_Conditional_0_Template, 17, 13, "div", 0);
10634
10847
  } if (rf & 2) {
10635
10848
  i0.ɵɵconditional(ctx.introService.showIntro ? 0 : -1);
10636
- } }, dependencies: [i8.NgStyle, i4.TranslatePipe], styles: [".card[_ngcontent-%COMP%]{position:absolute;width:400px;height:350px!important;z-index:999999}"] }); }
10849
+ } }, dependencies: [i9.NgStyle, i4.TranslatePipe], styles: [".card[_ngcontent-%COMP%]{position:absolute;width:400px;height:350px!important;z-index:999999}"] }); }
10637
10850
  }
10638
10851
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(IntroComponent, [{
10639
10852
  type: Component,
@@ -10821,7 +11034,7 @@ class DesignerComponent {
10821
11034
  set dropzoneChunking(value) {
10822
11035
  this.configService.dropzoneChunking = value;
10823
11036
  }
10824
- constructor(translateService, projectService, configService, fixturePoolService, hotkeyTargetExcludeService, modalService, userService, userEnsureLoginService, projectLoadService, warningDialogService, errorDialogService, fixtureService, timelineService, introService) {
11037
+ constructor(translateService, projectService, configService, fixturePoolService, hotkeyTargetExcludeService, modalService, userService, userEnsureLoginService, projectLoadService, warningDialogService, errorDialogService, fixtureService, timelineService, introService, effectService) {
10825
11038
  this.translateService = translateService;
10826
11039
  this.projectService = projectService;
10827
11040
  this.configService = configService;
@@ -10836,6 +11049,7 @@ class DesignerComponent {
10836
11049
  this.fixtureService = fixtureService;
10837
11050
  this.timelineService = timelineService;
10838
11051
  this.introService = introService;
11052
+ this.effectService = effectService;
10839
11053
  // the size of the menu used in the designer
10840
11054
  this.designerMenuSizePx = 20;
10841
11055
  this.splitGutterSizePx = 13;
@@ -10950,6 +11164,13 @@ class DesignerComponent {
10950
11164
  else {
10951
11165
  this.fixtureService.settingsSelection = false;
10952
11166
  }
11167
+ if (tab === 'effects') {
11168
+ this.effectService.effectsOpen = true;
11169
+ }
11170
+ else {
11171
+ this.effectService.effectsOpen = false;
11172
+ }
11173
+ this.effectService.effectsOpenChanged.next();
10953
11174
  this.currentTab = tab;
10954
11175
  }
10955
11176
  openFixturePool() {
@@ -11056,7 +11277,7 @@ class DesignerComponent {
11056
11277
  this.translateService.use(language);
11057
11278
  localStorage.setItem('language', language);
11058
11279
  }
11059
- static { this.ɵfac = function DesignerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DesignerComponent)(i0.ɵɵdirectiveInject(i4.TranslateService), i0.ɵɵdirectiveInject(ProjectService), i0.ɵɵdirectiveInject(ConfigService), i0.ɵɵdirectiveInject(FixturePoolService), i0.ɵɵdirectiveInject(HotkeyTargetExcludeService), i0.ɵɵdirectiveInject(i1$1.BsModalService), i0.ɵɵdirectiveInject(UserService), i0.ɵɵdirectiveInject(UserEnsureLoginService), i0.ɵɵdirectiveInject(ProjectLoadService), i0.ɵɵdirectiveInject(WarningDialogService), i0.ɵɵdirectiveInject(ErrorDialogService), i0.ɵɵdirectiveInject(FixtureService), i0.ɵɵdirectiveInject(TimelineService), i0.ɵɵdirectiveInject(IntroService)); }; }
11280
+ static { this.ɵfac = function DesignerComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DesignerComponent)(i0.ɵɵdirectiveInject(i4.TranslateService), i0.ɵɵdirectiveInject(ProjectService), i0.ɵɵdirectiveInject(ConfigService), i0.ɵɵdirectiveInject(FixturePoolService), i0.ɵɵdirectiveInject(HotkeyTargetExcludeService), i0.ɵɵdirectiveInject(i1$1.BsModalService), i0.ɵɵdirectiveInject(UserService), i0.ɵɵdirectiveInject(UserEnsureLoginService), i0.ɵɵdirectiveInject(ProjectLoadService), i0.ɵɵdirectiveInject(WarningDialogService), i0.ɵɵdirectiveInject(ErrorDialogService), i0.ɵɵdirectiveInject(FixtureService), i0.ɵɵdirectiveInject(TimelineService), i0.ɵɵdirectiveInject(IntroService), i0.ɵɵdirectiveInject(EffectService)); }; }
11060
11281
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: DesignerComponent, selectors: [["lib-designer"]], viewQuery: function DesignerComponent_Query(rf, ctx) { if (rf & 1) {
11061
11282
  i0.ɵɵviewQuery(PreviewComponent, 5);
11062
11283
  i0.ɵɵviewQuery(TimelineComponent, 5);
@@ -11219,12 +11440,12 @@ class DesignerComponent {
11219
11440
  i0.ɵɵconditional(ctx.projectService.project ? 76 : -1);
11220
11441
  i0.ɵɵadvance(2);
11221
11442
  i0.ɵɵconditional(ctx.projectService.project ? 78 : -1);
11222
- } }, dependencies: [i3.RouterLinkActive, i8.NgStyle, i11.PopoverDirective, PreviewComponent, SceneComponent, TimelineComponent, FixtureComponent, FixtureCapabilityComponent, FixtureSettingsComponent, EffectComponent, PresetComponent, MasterDimmerComponent, FixtureChannelComponent, IntroComponent, i4.TranslatePipe], styles: [".modal-full{max-width:unset!important;margin:1.75rem!important}.modal{z-index:10001}#designer{font-size:14px}#designer .nav-link{cursor:pointer}#designer .dropdown-menu{z-index:100000}#designer .row{flex-wrap:unset}#designer .navbar-nav{flex-direction:row!important}#designer .navbar-expand-lg{flex-flow:row nowrap!important;justify-content:flex-start!important}#designer .navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem!important;padding-left:.5rem!important}#designer .list-group-item.active{color:#fff!important;background-color:#fd7e14!important;border-color:#fd7e14!important}#designer *:focus{outline:none}#designer select{font-size:.8rem;cursor:pointer}#designer input{font-size:.7rem;background-color:transparent;color:#fff;border:1px solid}#designer input,#designer select{border-color:#dee2e6}#designer .list-group-item{padding:.3rem 1.25rem;border-left:none;border-right:none}#designer .nav-pills .nav-link.active,#designer .nav-pills .show>.nav-link{background-color:#444}#designer .nav a,#designer .panel-title .btn-link{color:#fff!important}#designer .accordion-toggle .btn,#designer .accordion-toggle button{padding:0}#designer .card-body{overflow:auto;padding:.8rem}#designer .card-header{margin-bottom:0}#designer .card-header{padding:.4rem}#designer .panel-body{background-color:#303030}#designer .list-group-item.active-light{background-color:#906542;border-color:#906542}#designer .inactive-list-item{opacity:.3}#designer span.bigcheck-target{font-family:FontAwesome}#designer input[type=checkbox].bigcheck{position:relative;left:-999em}#designer input[type=checkbox].bigcheck+span.bigcheck-target:after{content:\"\\f096\"}#designer input[type=checkbox].bigcheck:checked+span.bigcheck-target:after{content:\"\\f046\"}#designer .gutter.gutter-horizontal{cursor:ew-resize}#designer .gutter.gutter-vertical{cursor:ns-resize}#designer .split-horizontal,#designer .gutter.gutter-horizontal{float:left}#designer .split-vertical,#designer .gutter.gutter-horizontal{height:100%}#designer .split{overflow-y:hidden;overflow-x:hidden}#designer .panel{background-color:transparent}#designer .slider{cursor:pointer}#designer .slider-horizontal .slider-track{height:2px!important;margin-top:-2px!important}#designer .slider-vertical .slider-track{width:2px!important;margin-left:4px!important}#designer .slider-track,#designer .slider-track-low,#designer .slider-track-high,#designer .slider-selection{background-color:#fff!important;border-radius:0!important;background-image:none!important;box-shadow:none!important}#designer .slider-handle{width:13px!important;height:13px!important;background-color:#fff!important;background-image:none!important;border:1px solid #303030}#designer .slider-vertical .slider-handle{margin-left:4px!important}#designer .slider-horizontal .slider-handle{margin-top:2px!important}#designer .slider-input{width:35px;margin-left:8px;text-align:center}#designer .slider-input-readonly{width:35px;margin-left:8px;text-align:center;color:#a9a9a9;border-color:gray}#designer .capability-container{padding:0;height:0}#designer accordion-group>div{border:none!important}#designer .popover{background-color:#fff}#designer .popover-body{color:#000}#designer .bs-popover-right .arrow:after,#designer .bs-popover-auto[x-placement^=right] .arrow:after{border-right-color:#fff}#designer .bs-popover-left .arrow:after,#designer .bs-popover-auto[x-placement^=left] .arrow:after{border-left-color:#fff}#designer .bs-popover-bottom .arrow:after,#designer .bs-popover-auto[x-placement^=bottom] .arrow:after{border-bottom-color:#fff}#designer .bs-popover-top .arrow:after,#designer .bs-popover-auto[x-placement^=top] .arrow:after{border-top-color:#fff}#designer .iro__wheel,#designer .iro__slider{cursor:pointer}#designer .pan-tilt-grid path{fill:none;stroke:#fff;stroke-width:10px}#designer .pan-tilt-grid circle{fill:#4682b4;stroke:#fff;stroke-width:3px}#designer .capability{overflow:visible}#designer .capability-deactivated{opacity:.4}#designer .wavesurfer-region{z-index:5!important}#designer .wavesurfer-region[data-region-selected=true]{z-index:6!important}#designer .wavesurfer-region[data-region-preset=true]{height:50%!important;top:50%!important}#designer .wavesurfer-region[data-region-name]:after{content:attr(data-region-name);margin-left:20px}#designer .wavesurfer-handle{width:10px!important;max-width:10px!important;border:1px solid #ddd;background:#0000001a;box-sizing:border-box;opacity:0;cursor:unset!important}#designer .wavesurfer-handle-end{margin-left:-10px}#designer .wavesurfer-region[data-region-selectable=true] .wavesurfer-handle{opacity:1;cursor:col-resize!important}#designer .wavesurfer-handle:before,#designer .wavesurfer-handle:after{content:\"\";display:block;position:absolute;z-index:1;border-top:1px solid #fff;border-bottom:1px solid #fff;height:4px;left:5%;right:5%;top:50%;transform:translateY(-50%)}#designer .wavesurfer-handle:before{margin-top:-3px}#designer timeline{overflow:scroll!important;overflow:-moz-scrollbars-none;-ms-overflow-style:none;scrollbar-width:none;cursor:s-resize}#designer timeline::-webkit-scrollbar{height:0!important}#designer cursor{top:-20px!important}#designer wave{border-right-color:#fd7e14!important;cursor:col-resize}#designer wave canvas{opacity:.2}\n"], encapsulation: 2 }); }
11443
+ } }, dependencies: [i3.RouterLinkActive, i9.NgStyle, i11.PopoverDirective, PreviewComponent, SceneComponent, TimelineComponent, FixtureComponent, FixtureCapabilityComponent, FixtureSettingsComponent, EffectComponent, PresetComponent, MasterDimmerComponent, FixtureChannelComponent, IntroComponent, i4.TranslatePipe], styles: [".modal-full{max-width:unset!important;margin:1.75rem!important}.modal{z-index:10001}#designer{font-size:14px}#designer .nav-link{cursor:pointer}#designer .dropdown-menu{z-index:100000}#designer .row{flex-wrap:unset}#designer .navbar-nav{flex-direction:row!important}#designer .navbar-expand-lg{flex-flow:row nowrap!important;justify-content:flex-start!important}#designer .navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem!important;padding-left:.5rem!important}#designer .list-group-item.active{color:#fff!important;background-color:#fd7e14!important;border-color:#fd7e14!important}#designer *:focus{outline:none}#designer select{font-size:.8rem;cursor:pointer}#designer input{font-size:.7rem;background-color:transparent;color:#fff;border:1px solid}#designer input,#designer select{border-color:#dee2e6}#designer .list-group-item{padding:.3rem 1.25rem;border-left:none;border-right:none}#designer .nav-pills .nav-link.active,#designer .nav-pills .show>.nav-link{background-color:#444}#designer .nav a,#designer .panel-title .btn-link{color:#fff!important}#designer .accordion-toggle .btn,#designer .accordion-toggle button{padding:0}#designer .card-body{overflow:auto;padding:.8rem}#designer .card-header{margin-bottom:0}#designer .card-header{padding:.4rem}#designer .panel-body{background-color:#303030}#designer .list-group-item.active-light{background-color:#906542;border-color:#906542}#designer .inactive-list-item{opacity:.3}#designer span.bigcheck-target{font-family:FontAwesome}#designer input[type=checkbox].bigcheck{position:relative;left:-999em}#designer input[type=checkbox].bigcheck+span.bigcheck-target:after{content:\"\\f096\"}#designer input[type=checkbox].bigcheck:checked+span.bigcheck-target:after{content:\"\\f046\"}#designer .gutter.gutter-horizontal{cursor:ew-resize}#designer .gutter.gutter-vertical{cursor:ns-resize}#designer .split-horizontal,#designer .gutter.gutter-horizontal{float:left}#designer .split-vertical,#designer .gutter.gutter-horizontal{height:100%}#designer .split{overflow-y:hidden;overflow-x:hidden}#designer .panel{background-color:transparent}#designer .slider{cursor:pointer}#designer .slider-horizontal .slider-track{height:2px!important;margin-top:-2px!important}#designer .slider-vertical .slider-track{width:2px!important;margin-left:4px!important}#designer .slider-track,#designer .slider-track-low,#designer .slider-track-high,#designer .slider-selection{background-color:#fff!important;border-radius:0!important;background-image:none!important;box-shadow:none!important}#designer .slider-handle{width:13px!important;height:13px!important;background-color:#fff!important;background-image:none!important;border:1px solid #303030}#designer .slider-vertical .slider-handle{margin-left:4px!important}#designer .slider-horizontal .slider-handle{margin-top:2px!important}#designer .slider-input{width:35px;margin-left:8px;text-align:center}#designer .slider-input-readonly{width:35px;margin-left:8px;text-align:center;color:#a9a9a9;border-color:gray}#designer .capability-container{padding:0;height:0}#designer accordion-group>div{border:none!important}#designer .popover{background-color:#fff}#designer .popover-body{color:#000}#designer .bs-popover-right .arrow:after,#designer .bs-popover-auto[x-placement^=right] .arrow:after{border-right-color:#fff}#designer .bs-popover-left .arrow:after,#designer .bs-popover-auto[x-placement^=left] .arrow:after{border-left-color:#fff}#designer .bs-popover-bottom .arrow:after,#designer .bs-popover-auto[x-placement^=bottom] .arrow:after{border-bottom-color:#fff}#designer .bs-popover-top .arrow:after,#designer .bs-popover-auto[x-placement^=top] .arrow:after{border-top-color:#fff}#designer .iro__wheel,#designer .iro__slider{cursor:pointer}#designer .pan-tilt-grid path{fill:none;stroke:#fff;stroke-width:10px}#designer .pan-tilt-grid circle{fill:#4682b4;stroke:#fff;stroke-width:3px}#designer .capability{overflow:visible}#designer .capability-deactivated{opacity:.4}#designer .wavesurfer-region{z-index:5!important}#designer .wavesurfer-region[data-region-selected=true]{z-index:6!important}#designer .wavesurfer-region[data-region-preset=true]{height:50%!important;top:50%!important}#designer .wavesurfer-region[data-region-name]:after{content:attr(data-region-name);margin-left:20px}#designer .wavesurfer-handle{width:10px!important;max-width:10px!important;border:1px solid #ddd;background:#0000001a;box-sizing:border-box;opacity:0;cursor:unset!important}#designer .wavesurfer-handle-end{margin-left:-10px}#designer .wavesurfer-region[data-region-selectable=true] .wavesurfer-handle{opacity:1;cursor:col-resize!important}#designer .wavesurfer-handle:before,#designer .wavesurfer-handle:after{content:\"\";display:block;position:absolute;z-index:1;border-top:1px solid #fff;border-bottom:1px solid #fff;height:4px;left:5%;right:5%;top:50%;transform:translateY(-50%)}#designer .wavesurfer-handle:before{margin-top:-3px}#designer timeline{overflow:scroll!important;overflow:-moz-scrollbars-none;-ms-overflow-style:none;scrollbar-width:none;cursor:s-resize}#designer timeline::-webkit-scrollbar{height:0!important}#designer cursor{top:-20px!important}#designer wave{border-right-color:#fd7e14!important;cursor:col-resize}#designer wave canvas{opacity:.2}\n"], encapsulation: 2 }); }
11223
11444
  }
11224
11445
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DesignerComponent, [{
11225
11446
  type: Component,
11226
11447
  args: [{ selector: 'lib-designer', encapsulation: ViewEncapsulation.None, standalone: false, template: "<!-- Wrap the whole component inside a div to encapsulate the CSS -->\n\n<!-- 100 % height minus the menu bar above and the gutter size of 13 px -->\n<!-- <div style=\"height: calc(100% - 33px)\"> -->\n<div id=\"designer\" [ngStyle]=\"{ height: 'calc(100% - ' + totalMenuHeightPx + 'px)' }\">\n <!-- Navigation -->\n <nav\n class=\"navbar navbar-expand-lg navbar-light bg-light border-secondary\"\n style=\"border-bottom: 1px solid #444; height: 20px; z-index: 9999\"\n >\n <!-- Menu buttons -->\n <ul class=\"navbar-nav mr-auto\">\n <li class=\"nav-item dropdown\">\n <a class=\"nav-link dropdown-toggle\" href=\"#\" id=\"fileDropdown\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\">\n {{ 'designer.navigation.project' | translate }}\n </a>\n <div class=\"dropdown-menu\" aria-labelledby=\"fileDropdown\">\n <a class=\"dropdown-item d-none d-md-block\" href=\"#\" (click)=\"projectNew(); (false)\"\n ><i class=\"fa fa-fw fa-file-o\" aria-hidden=\"true\"></i> {{ 'designer.navigation.project-new' | translate }}</a\n >\n <a class=\"dropdown-item\" href=\"#\" (click)=\"projectOpen(); (false)\"\n ><i class=\"fa fa-fw fa-folder-open-o\" aria-hidden=\"true\"></i> {{ 'designer.navigation.project-open' | translate }}</a\n >\n <a class=\"dropdown-item d-none d-md-block\" href=\"#\" (click)=\"projectSave(); (false)\"\n ><i class=\"fa fa-fw fa-floppy-o\" aria-hidden=\"true\"></i> {{ 'designer.navigation.project-save' | translate }}</a\n >\n <a class=\"dropdown-item d-none d-md-block\" href=\"#\" (click)=\"projectSaveAs(); (false)\"\n ><i class=\"fa fa-fw fa-floppy-o\" aria-hidden=\"true\"></i> {{ 'designer.navigation.project-save-as' | translate }}</a\n >\n <a class=\"dropdown-item d-none d-md-block\" href=\"#\" (click)=\"projectImport(); (false)\"\n ><i class=\"fa fa-fw fa-download\" aria-hidden=\"true\"></i> {{ 'designer.navigation.project-import' | translate }}</a\n >\n <a class=\"dropdown-item d-none d-md-block\" href=\"#\" (click)=\"projectExport(); (false)\"\n ><i class=\"fa fa-fw fa-external-link\" aria-hidden=\"true\"></i> {{ 'designer.navigation.project-export' | translate }}</a\n >\n </div>\n </li>\n <li class=\"nav-item dropdown d-none d-md-block\">\n <a\n class=\"nav-link dropdown-toggle\"\n href=\"#\"\n id=\"settingsDropdown\"\n data-toggle=\"dropdown\"\n aria-haspopup=\"true\"\n aria-expanded=\"false\"\n >\n {{ 'designer.navigation.settings' | translate }}\n </a>\n <div class=\"dropdown-menu\" aria-labelledby=\"settingsDropdown\">\n <a class=\"dropdown-item\" href=\"#\" (click)=\"openFixturePool(); (false)\">{{ 'designer.navigation.fixture-pool' | translate }}</a>\n <!-- <a class=\"dropdown-item\" href=\"#\">{{ 'designer.navigation.stage' | translate }}</a> -->\n </div>\n </li>\n <li class=\"nav-item dropdown d-none d-md-block\">\n <a\n class=\"nav-link dropdown-toggle\"\n href=\"#\"\n id=\"settingsDropdown\"\n data-toggle=\"dropdown\"\n aria-haspopup=\"true\"\n aria-expanded=\"false\"\n >\n {{ 'designer.navigation.help' | translate }}\n </a>\n <div class=\"dropdown-menu\" aria-labelledby=\"settingsDropdown\">\n <a class=\"dropdown-item\" href=\"#\" (click)=\"introService.reset(); (false)\">{{ 'designer.navigation.reset-intro' | translate }}</a>\n <a class=\"dropdown-item\" href=\"https://rocketshow.net/support/\" target=\"_blank\">{{\n 'designer.navigation.support' | translate\n }}</a>\n </div>\n </li>\n </ul>\n\n <ul class=\"navbar-nav\">\n @if (configService.shareAvailable) {\n <li class=\"nav-item d-none d-md-flex\" data-toggle=\"collapse\">\n <a class=\"nav-link text-primary\" (click)=\"projectShare(); (false)\" routerLinkActive=\"active\"\n ><i class=\"fa fa-share-alt\" aria-hidden=\"true\"></i> {{ 'designer.navigation.project-share' | translate }}</a\n >\n </li>\n } @if (configService.languageSwitch) {\n <li class=\"nav-item dropdown\">\n <a class=\"nav-link dropdown-toggle\" href=\"#\" id=\"settingsDropdown\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\"\n ><i class=\"fa fa-globe\" aria-hidden=\"true\"></i>\n {{ 'designer.misc.language' | translate }}\n </a>\n <div class=\"dropdown-menu dropdown-menu-right\" aria-labelledby=\"settingsDropdown\">\n <a class=\"dropdown-item\" href=\"#\" (click)=\"switchLanguage('en'); (false)\" target=\"_blank\">English</a>\n <a class=\"dropdown-item\" href=\"#\" (click)=\"switchLanguage('de'); (false)\" target=\"_blank\">Deutsch</a>\n </div>\n </li>\n } @if (configService.loginAvailable && !userService.isLoggedIn()) {\n <li class=\"nav-item\" data-toggle=\"collapse\">\n <a class=\"nav-link\" (click)=\"userRegister(); (false)\" routerLinkActive=\"active\"\n ><i class=\"fa fa-user\" aria-hidden=\"true\"></i> {{ 'designer.navigation.login' | translate }}</a\n >\n </li>\n } @if (configService.loginAvailable && userService.isLoggedIn()) {\n <li class=\"nav-item dropdown\">\n <a class=\"nav-link dropdown-toggle\" href=\"#\" id=\"settingsDropdown\" data-toggle=\"dropdown\" aria-haspopup=\"true\" aria-expanded=\"false\"\n ><i class=\"fa fa-user\" aria-hidden=\"true\"></i>\n {{ userService.username }}\n </a>\n <div class=\"dropdown-menu dropdown-menu-right\" aria-labelledby=\"settingsDropdown\">\n <a class=\"dropdown-item\" href=\"#\" (click)=\"userService.logout(); (false)\" target=\"_blank\"\n ><i class=\"fa fa-sign-out\" aria-hidden=\"true\"></i> {{ 'designer.navigation.logout' | translate }}</a\n >\n </div>\n </li>\n }\n </ul>\n </nav>\n\n <!-- The main content for larger screens -->\n <div class=\"h-100 d-none d-md-block\">\n <div id=\"row1\" class=\"split split-vertical clearfix pt-3 pl-3\">\n <!-- Scenes -->\n <div id=\"scenes\" class=\"split split-horizontal h-100\">\n @if (projectService.project) {\n <lib-app-scene></lib-app-scene>\n }\n </div>\n\n <!-- Presets -->\n <div id=\"presets\" class=\"split split-horizontal h-100\">\n @if (projectService.project) {\n <lib-app-preset></lib-app-preset>\n }\n </div>\n\n <!-- 3D preview -->\n <div id=\"preview\" class=\"split split-horizontal h-100 pr-3\">\n @if (projectService.project) {\n <div class=\"card border-secondary h-100\" [class.card-intro-active]=\"introService.showStep('preview')\">\n <div class=\"card-body p-0 h-100\">\n <lib-app-preview class=\"h-100\"></lib-app-preview>\n </div>\n </div>\n }\n </div>\n </div>\n\n <div id=\"row2\" class=\"split split-vertical clearfix px-3 d-flex\" style=\"flex-direction: row\">\n <!-- Menu for the capabilities, channels, effects and settings -->\n @if (projectService.project) {\n <div class=\"col col-auto p-0\" style=\"margin-right: -1px\">\n <div class=\"nav flex-column nav-pills\" id=\"v-pills-tab\" role=\"tablist\" aria-orientation=\"vertical\">\n <a\n class=\"nav-link px-3 active\"\n (click)=\"openTab('capabilities')\"\n id=\"v-pills-capabilities-tab\"\n popover=\"{{ 'designer.misc.capabilities' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-capabilities\"\n role=\"tab\"\n aria-controls=\"v-pills-capabilities\"\n aria-selected=\"true\"\n >\n <i class=\"fa fa-bolt fa-fw\" aria-hidden=\"true\"></i>\n </a>\n <a\n class=\"nav-link px-3\"\n (click)=\"openTab('channels')\"\n id=\"v-pills-channels-tab\"\n popover=\"{{ 'designer.misc.channels' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-channels\"\n role=\"tab\"\n aria-controls=\"v-pills-channels\"\n aria-selected=\"false\"\n >\n <i class=\"fa fa-sliders fa-fw\" aria-hidden=\"true\"></i>\n </a>\n <a\n class=\"nav-link px-3\"\n (click)=\"openTab('effects')\"\n id=\"v-pills-effects-tab\"\n popover=\"{{ 'designer.misc.effects' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-effects\"\n role=\"tab\"\n aria-controls=\"v-pills-effects\"\n aria-selected=\"false\"\n >\n <i class=\"fa fa-magic fa-fw\" aria-hidden=\"true\"></i>\n </a>\n <a\n class=\"nav-link px-3\"\n (click)=\"openTab('settings')\"\n id=\"v-pills-settings-tab\"\n popover=\"{{ 'designer.misc.settings' | translate }}\"\n container=\"body\"\n placement=\"right\"\n triggers=\"mouseenter:mouseleave\"\n data-toggle=\"pill\"\n href=\"#v-pills-settings\"\n role=\"tab\"\n aria-controls=\"v-pills-settings\"\n aria-selected=\"false\"\n style=\"border-top: 1px solid #444\"\n >\n <i class=\"fa fa-cog fa-fw\" aria-hidden=\"true\"></i>\n </a>\n </div>\n </div>\n }\n\n <div id=\"capabilities\" class=\"split split-horizontal h-100\" style=\"padding-left: 1rem\">\n @if (projectService.project) {\n <div class=\"row h-100\">\n <!-- Content for the capabilities, channels, effects and settings -->\n <div class=\"col pl-0 h-100\">\n <div class=\"tab-content h-100\" id=\"v-pills-tabContent\">\n <div class=\"tab-pane h-100 show active\" id=\"v-pills-capabilities\" role=\"tabpanel\">\n <lib-app-fixture-capability></lib-app-fixture-capability>\n </div>\n <div class=\"tab-pane h-100 show\" id=\"v-pills-channels\" role=\"tabpanel\">\n <lib-app-fixture-channel></lib-app-fixture-channel>\n </div>\n <div class=\"tab-pane h-100\" id=\"v-pills-effects\" role=\"tabpanel\" aria-labelledby=\"v-pills-profile-tab\">\n <lib-app-effect></lib-app-effect>\n </div>\n <div class=\"tab-pane h-100\" id=\"v-pills-settings\" role=\"tabpanel\" aria-labelledby=\"v-pills-home-tab\">\n <lib-app-fixture-settings></lib-app-fixture-settings>\n </div>\n </div>\n </div>\n </div>\n }\n </div>\n\n <!-- Fixtures -->\n <div id=\"fixtures\" class=\"split split-horizontal h-100\">\n @if (projectService.project) {\n <lib-app-fixture></lib-app-fixture>\n }\n </div>\n\n <!-- Master dimmer -->\n <div id=\"masterDimmer\" class=\"split split-horizontal h-100\">\n @if (projectService.project) {\n <lib-app-master-dimmer></lib-app-master-dimmer>\n }\n </div>\n </div>\n\n <!-- Timeline -->\n <div id=\"row3\" class=\"split split-vertical clearfix px-3 pb-3\" style=\"padding-bottom: 20px\">\n @if (projectService.project) {\n <lib-app-timeline></lib-app-timeline>\n }\n </div>\n </div>\n\n <!-- The components for small screens -->\n <div class=\"d-md-none p-3\">\n <div>\n @if (projectService.project) {\n <lib-app-master-dimmer></lib-app-master-dimmer>\n }\n </div>\n\n <div class=\"mt-3\">\n @if (projectService.project) {\n <lib-app-scene></lib-app-scene>\n }\n </div>\n </div>\n</div>\n\n<lib-app-intro class=\"d-none d-md-flex\"></lib-app-intro>\n", styles: [".modal-full{max-width:unset!important;margin:1.75rem!important}.modal{z-index:10001}#designer{font-size:14px}#designer .nav-link{cursor:pointer}#designer .dropdown-menu{z-index:100000}#designer .row{flex-wrap:unset}#designer .navbar-nav{flex-direction:row!important}#designer .navbar-expand-lg{flex-flow:row nowrap!important;justify-content:flex-start!important}#designer .navbar-expand-lg .navbar-nav .nav-link{padding-right:.5rem!important;padding-left:.5rem!important}#designer .list-group-item.active{color:#fff!important;background-color:#fd7e14!important;border-color:#fd7e14!important}#designer *:focus{outline:none}#designer select{font-size:.8rem;cursor:pointer}#designer input{font-size:.7rem;background-color:transparent;color:#fff;border:1px solid}#designer input,#designer select{border-color:#dee2e6}#designer .list-group-item{padding:.3rem 1.25rem;border-left:none;border-right:none}#designer .nav-pills .nav-link.active,#designer .nav-pills .show>.nav-link{background-color:#444}#designer .nav a,#designer .panel-title .btn-link{color:#fff!important}#designer .accordion-toggle .btn,#designer .accordion-toggle button{padding:0}#designer .card-body{overflow:auto;padding:.8rem}#designer .card-header{margin-bottom:0}#designer .card-header{padding:.4rem}#designer .panel-body{background-color:#303030}#designer .list-group-item.active-light{background-color:#906542;border-color:#906542}#designer .inactive-list-item{opacity:.3}#designer span.bigcheck-target{font-family:FontAwesome}#designer input[type=checkbox].bigcheck{position:relative;left:-999em}#designer input[type=checkbox].bigcheck+span.bigcheck-target:after{content:\"\\f096\"}#designer input[type=checkbox].bigcheck:checked+span.bigcheck-target:after{content:\"\\f046\"}#designer .gutter.gutter-horizontal{cursor:ew-resize}#designer .gutter.gutter-vertical{cursor:ns-resize}#designer .split-horizontal,#designer .gutter.gutter-horizontal{float:left}#designer .split-vertical,#designer .gutter.gutter-horizontal{height:100%}#designer .split{overflow-y:hidden;overflow-x:hidden}#designer .panel{background-color:transparent}#designer .slider{cursor:pointer}#designer .slider-horizontal .slider-track{height:2px!important;margin-top:-2px!important}#designer .slider-vertical .slider-track{width:2px!important;margin-left:4px!important}#designer .slider-track,#designer .slider-track-low,#designer .slider-track-high,#designer .slider-selection{background-color:#fff!important;border-radius:0!important;background-image:none!important;box-shadow:none!important}#designer .slider-handle{width:13px!important;height:13px!important;background-color:#fff!important;background-image:none!important;border:1px solid #303030}#designer .slider-vertical .slider-handle{margin-left:4px!important}#designer .slider-horizontal .slider-handle{margin-top:2px!important}#designer .slider-input{width:35px;margin-left:8px;text-align:center}#designer .slider-input-readonly{width:35px;margin-left:8px;text-align:center;color:#a9a9a9;border-color:gray}#designer .capability-container{padding:0;height:0}#designer accordion-group>div{border:none!important}#designer .popover{background-color:#fff}#designer .popover-body{color:#000}#designer .bs-popover-right .arrow:after,#designer .bs-popover-auto[x-placement^=right] .arrow:after{border-right-color:#fff}#designer .bs-popover-left .arrow:after,#designer .bs-popover-auto[x-placement^=left] .arrow:after{border-left-color:#fff}#designer .bs-popover-bottom .arrow:after,#designer .bs-popover-auto[x-placement^=bottom] .arrow:after{border-bottom-color:#fff}#designer .bs-popover-top .arrow:after,#designer .bs-popover-auto[x-placement^=top] .arrow:after{border-top-color:#fff}#designer .iro__wheel,#designer .iro__slider{cursor:pointer}#designer .pan-tilt-grid path{fill:none;stroke:#fff;stroke-width:10px}#designer .pan-tilt-grid circle{fill:#4682b4;stroke:#fff;stroke-width:3px}#designer .capability{overflow:visible}#designer .capability-deactivated{opacity:.4}#designer .wavesurfer-region{z-index:5!important}#designer .wavesurfer-region[data-region-selected=true]{z-index:6!important}#designer .wavesurfer-region[data-region-preset=true]{height:50%!important;top:50%!important}#designer .wavesurfer-region[data-region-name]:after{content:attr(data-region-name);margin-left:20px}#designer .wavesurfer-handle{width:10px!important;max-width:10px!important;border:1px solid #ddd;background:#0000001a;box-sizing:border-box;opacity:0;cursor:unset!important}#designer .wavesurfer-handle-end{margin-left:-10px}#designer .wavesurfer-region[data-region-selectable=true] .wavesurfer-handle{opacity:1;cursor:col-resize!important}#designer .wavesurfer-handle:before,#designer .wavesurfer-handle:after{content:\"\";display:block;position:absolute;z-index:1;border-top:1px solid #fff;border-bottom:1px solid #fff;height:4px;left:5%;right:5%;top:50%;transform:translateY(-50%)}#designer .wavesurfer-handle:before{margin-top:-3px}#designer timeline{overflow:scroll!important;overflow:-moz-scrollbars-none;-ms-overflow-style:none;scrollbar-width:none;cursor:s-resize}#designer timeline::-webkit-scrollbar{height:0!important}#designer cursor{top:-20px!important}#designer wave{border-right-color:#fd7e14!important;cursor:col-resize}#designer wave canvas{opacity:.2}\n"] }]
11227
- }], () => [{ type: i4.TranslateService }, { type: ProjectService }, { type: ConfigService }, { type: FixturePoolService }, { type: HotkeyTargetExcludeService }, { type: i1$1.BsModalService }, { type: UserService }, { type: UserEnsureLoginService }, { type: ProjectLoadService }, { type: WarningDialogService }, { type: ErrorDialogService }, { type: FixtureService }, { type: TimelineService }, { type: IntroService }], { menuHeightPx: [{
11448
+ }], () => [{ type: i4.TranslateService }, { type: ProjectService }, { type: ConfigService }, { type: FixturePoolService }, { type: HotkeyTargetExcludeService }, { type: i1$1.BsModalService }, { type: UserService }, { type: UserEnsureLoginService }, { type: ProjectLoadService }, { type: WarningDialogService }, { type: ErrorDialogService }, { type: FixtureService }, { type: TimelineService }, { type: IntroService }, { type: EffectService }], { menuHeightPx: [{
11228
11449
  type: Input
11229
11450
  }], externalCompositionsAvailable: [{
11230
11451
  type: Input
@@ -11260,7 +11481,7 @@ class DesignerComponent {
11260
11481
  type: HostListener,
11261
11482
  args: ['document:keydown', ['$event']]
11262
11483
  }] }); })();
11263
- (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DesignerComponent, { className: "DesignerComponent", filePath: "lib/designer.component.ts", lineNumber: 34 }); })();
11484
+ (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(DesignerComponent, { className: "DesignerComponent", filePath: "lib/designer.component.ts", lineNumber: 35 }); })();
11264
11485
 
11265
11486
  class DesignerModule {
11266
11487
  static { this.ɵfac = function DesignerModule_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || DesignerModule)(); }; }
@@ -11278,7 +11499,8 @@ class DesignerModule {
11278
11499
  DropzoneModule,
11279
11500
  ToastrModule.forRoot({
11280
11501
  newestOnTop: true,
11281
- })] }); }
11502
+ }),
11503
+ TreeModule] }); }
11282
11504
  }
11283
11505
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(DesignerModule, [{
11284
11506
  type: NgModule,
@@ -11339,6 +11561,7 @@ class DesignerModule {
11339
11561
  ToastrModule.forRoot({
11340
11562
  newestOnTop: true,
11341
11563
  }),
11564
+ TreeModule,
11342
11565
  ],
11343
11566
  providers: [provideHttpClient(withInterceptorsFromDi())],
11344
11567
  }]
@@ -11389,7 +11612,7 @@ class DesignerModule {
11389
11612
  PopoverModule,
11390
11613
  TypeaheadModule,
11391
11614
  SortablejsModule,
11392
- DropzoneModule, i3$1.ToastrModule], exports: [DesignerComponent] }); })();
11615
+ DropzoneModule, i3$1.ToastrModule, TreeModule], exports: [DesignerComponent] }); })();
11393
11616
 
11394
11617
  /*
11395
11618
  * Public API Surface of designer