@rocketshow/designer 1.36.0 → 1.37.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.
@@ -119,18 +119,61 @@ class FixtureCapability {
119
119
  return;
120
120
  }
121
121
  this.type = FixtureCapabilityType[data.type];
122
- this.angleStart = data.angleStart;
123
- this.angleEnd = data.angleEnd;
124
122
  this.color = data.color;
125
123
  if (data.dmxRange) {
126
124
  this.dmxRange = data.dmxRange;
127
125
  }
128
126
  this.wheel = data.wheel;
129
127
  this.slotNumber = data.slotNumber;
128
+ this.comment = data.comment;
129
+ this.soundControlled = data.soundControlled;
130
+ this.shutterEffect = data.shutterEffect;
131
+ this.randomTiming = data.randomTiming;
132
+ this.angle = data.angle;
133
+ this.angleStart = data.angleStart;
134
+ this.angleEnd = data.angleEnd;
135
+ this.speed = data.speed;
136
+ this.speedStart = data.speedStart;
137
+ this.speedEnd = data.speedEnd;
130
138
  this.brightness = data.brightness;
131
139
  this.brightnessStart = data.brightnessStart;
132
140
  this.brightnessEnd = data.brightnessEnd;
133
- this.comment = data.comment;
141
+ this.duration = data.duration;
142
+ this.durationStart = data.durationStart;
143
+ this.durationEnd = data.durationEnd;
144
+ this.colorTemperature = data.colorTemperature;
145
+ this.colorTemperatureStart = data.colorTemperatureStart;
146
+ this.colorTemperatureEnd = data.colorTemperatureEnd;
147
+ this.soundSensitivity = data.soundSensitivity;
148
+ this.soundSensitivityStart = data.soundSensitivityStart;
149
+ this.soundSensitivityEnd = data.soundSensitivityEnd;
150
+ this.horizontalAngle = data.horizontalAngle;
151
+ this.horizontalAngleStart = data.horizontalAngleStart;
152
+ this.horizontalAngleEnd = data.horizontalAngleEnd;
153
+ this.verticalAngle = data.verticalAngle;
154
+ this.verticalAngleStart = data.verticalAngleStart;
155
+ this.verticalAngleEnd = data.verticalAngleEnd;
156
+ this.distance = data.distance;
157
+ this.distanceStart = data.distanceStart;
158
+ this.distanceEnd = data.distanceEnd;
159
+ this.openPercent = data.openPercent;
160
+ this.openPercentStart = data.openPercentStart;
161
+ this.openPercentEnd = data.openPercentEnd;
162
+ this.frostIntensity = data.frostIntensity;
163
+ this.frostIntensityStart = data.frostIntensityStart;
164
+ this.frostIntensityEnd = data.frostIntensityEnd;
165
+ this.fogOutput = data.fogOutput;
166
+ this.fogOutputStart = data.fogOutputStart;
167
+ this.fogOutputEnd = data.fogOutputEnd;
168
+ this.time = data.time;
169
+ this.timeStart = data.timeStart;
170
+ this.timeEnd = data.timeEnd;
171
+ this.insertion = data.insertion;
172
+ this.insertionStart = data.insertionStart;
173
+ this.insertionEnd = data.insertionEnd;
174
+ this.colors = data.colors;
175
+ this.colorsStart = data.colorsStart;
176
+ this.colorsEnd = data.colorsEnd;
134
177
  }
135
178
  }
136
179
 
@@ -2031,8 +2074,8 @@ class PresetService {
2031
2074
  }
2032
2075
  hasCapabilityType(type) {
2033
2076
  // there is at least one channel with at least one intensity capability
2034
- for (const projectFixture of this.selectedPreset.fixtures) {
2035
- const fixture = this.fixtureService.getCachedFixtureByUuid(projectFixture.fixtureUuid, projectFixture.pixelKey);
2077
+ for (const presetFixture of this.selectedPreset.fixtures) {
2078
+ const fixture = this.fixtureService.getCachedFixtureByUuid(presetFixture.fixtureUuid, presetFixture.pixelKey);
2036
2079
  for (const channel of fixture.channels) {
2037
2080
  if (channel.channel) {
2038
2081
  for (const capability of channel.capabilities) {
@@ -3092,6 +3135,14 @@ class PreviewService {
3092
3135
  // roughness: 0.5,
3093
3136
  // metalness: 0.5,
3094
3137
  });
3138
+ this.fixtureMaterial = new THREE.MeshLambertMaterial({
3139
+ color: 0x0d0d0d,
3140
+ emissive: 0x0d0d0d,
3141
+ });
3142
+ this.fixtureSelectedMaterial = new THREE.MeshLambertMaterial({
3143
+ color: 0xff00ff,
3144
+ emissive: 0xff00ff,
3145
+ });
3095
3146
  }
3096
3147
  getAlreadyCalculatedFixture(fixtures, fixtureIndex) {
3097
3148
  // Has this fixture already been calculated (same universe and dmx start address as a fixture before)
@@ -3515,6 +3566,10 @@ class PreviewService {
3515
3566
  this.scene.add(mesh);
3516
3567
  this.stageMeshes.push(mesh);
3517
3568
  }
3569
+ ngOnDestroy() {
3570
+ this.fixtureMaterial.dispose();
3571
+ this.fixtureSelectedMaterial.dispose();
3572
+ }
3518
3573
  static { this.ɵfac = function PreviewService_Factory(t) { return new (t || PreviewService)(i0.ɵɵinject(PresetService), i0.ɵɵinject(FixtureService), i0.ɵɵinject(SceneService), i0.ɵɵinject(TimelineService), i0.ɵɵinject(ProjectService)); }; }
3519
3574
  static { this.ɵprov = /*@__PURE__*/ i0.ɵɵdefineInjectable({ token: PreviewService, factory: PreviewService.ɵfac, providedIn: 'root' }); }
3520
3575
  }
@@ -3526,8 +3581,9 @@ class PreviewService {
3526
3581
  }], () => [{ type: PresetService }, { type: FixtureService }, { type: SceneService }, { type: TimelineService }, { type: ProjectService }], null); })();
3527
3582
 
3528
3583
  class Fixture3d {
3529
- constructor(fixtureService, fixture, scene) {
3584
+ constructor(fixtureService, previewService, fixture, scene, hasSpotLight = false) {
3530
3585
  this.fixtureService = fixtureService;
3586
+ this.previewService = previewService;
3531
3587
  this.pointLightMaxIntensity = 2;
3532
3588
  this.spotLightLightMaxIntensity = 10;
3533
3589
  this.fixtureHasDimmer = false;
@@ -3536,13 +3592,10 @@ class Fixture3d {
3536
3592
  this.dimmer = 0;
3537
3593
  this.isSelected = false;
3538
3594
  this.isLoaded = false;
3595
+ this.hasSpotLight = false;
3539
3596
  this.fixture = fixture;
3540
3597
  this.scene = scene;
3541
- // TODO Don't create it for each fixture but pass it from the preview service
3542
- this.selectedMaterial = new THREE.MeshLambertMaterial({
3543
- color: 0xff00ff,
3544
- emissive: 0xff00ff,
3545
- });
3598
+ this.hasSpotLight = hasSpotLight;
3546
3599
  // evaluate, various capabilities of this fixture
3547
3600
  for (const cachedChannel of this.fixture.channels) {
3548
3601
  if (cachedChannel.channel) {
@@ -3562,28 +3615,88 @@ class Fixture3d {
3562
3615
  }
3563
3616
  }
3564
3617
  }
3618
+ createSpotlightMaterial() {
3619
+ const vertexShader = `
3620
+ varying vec3 vNormal;
3621
+ varying vec3 vWorldPosition;
3622
+
3623
+ void main(){
3624
+ vNormal = normalize(normalMatrix * normal);
3625
+
3626
+ vec4 worldPosition = modelMatrix * vec4(position, 1.0);
3627
+ vWorldPosition = worldPosition.xyz;
3628
+
3629
+ gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
3630
+ }`;
3631
+ const fragmentShader = `
3632
+ varying vec3 vNormal;
3633
+ varying vec3 vWorldPosition;
3634
+
3635
+ uniform vec3 lightColor;
3636
+ uniform float opacity;
3637
+ uniform vec3 spotPosition;
3638
+ uniform float attenuation;
3639
+ uniform float anglePower;
3640
+
3641
+ void main(){
3642
+ float intensity;
3643
+
3644
+ intensity = distance(vWorldPosition, spotPosition) / attenuation;
3645
+ intensity = 1.0 - clamp(intensity, 0.0, 1.0);
3646
+
3647
+ vec3 normal = vec3(vNormal.x, vNormal.y, abs(vNormal.z));
3648
+ float angleIntensity = pow(dot(normal, vec3(0.0, 0.0, 1.0)), anglePower);
3649
+ intensity = intensity * angleIntensity * opacity;
3650
+
3651
+ gl_FragColor = vec4(lightColor, intensity);
3652
+ }`;
3653
+ this.spotlightMaterial = new THREE.ShaderMaterial({
3654
+ uniforms: {
3655
+ attenuation: {
3656
+ type: 'f',
3657
+ value: 800.0,
3658
+ },
3659
+ anglePower: {
3660
+ type: 'f',
3661
+ value: 2,
3662
+ },
3663
+ spotPosition: {
3664
+ type: 'v3',
3665
+ value: new THREE.Vector3(0, 0, 0),
3666
+ },
3667
+ lightColor: {
3668
+ type: 'c',
3669
+ value: new THREE.Color('white'),
3670
+ },
3671
+ opacity: {
3672
+ type: 'f',
3673
+ value: 1.0,
3674
+ },
3675
+ },
3676
+ vertexShader,
3677
+ fragmentShader,
3678
+ transparent: true,
3679
+ depthWrite: false,
3680
+ });
3681
+ }
3565
3682
  createObjects() {
3566
- // Add the spotlight
3567
- this.spotLight = new THREE.SpotLight(0xffffff, 50000);
3568
- this.spotLight.angle = 2;
3569
- this.spotLight.penumbra = 1;
3570
- this.spotLight.decay = 0.01;
3571
- this.spotLight.distance = 0;
3572
- this.spotLight.intensity = 1;
3573
- this.spotLightHelper = new THREE.SpotLightHelper(this.spotLight);
3574
- this.scene.add(this.spotLightHelper);
3575
- const spotLightTarget = new THREE.Object3D();
3576
- this.spotLight.target = spotLightTarget;
3577
- this.spotlightGroup = new THREE.Object3D();
3578
- this.spotlightGroup.add(this.spotLight);
3579
- this.spotlightGroup.add(spotLightTarget);
3580
- this.spotLight.position.set(0, -1.4, 0);
3581
- spotLightTarget.position.set(0, -10, 0);
3582
- this.createSpotLightBeam();
3583
- // Add the point light for the surrounding light
3584
- this.pointLight = new THREE.PointLight(0xffffff, 500, 0, 0.1);
3585
- this.spotlightGroup.add(this.pointLight);
3586
- this.pointLight.position.set(0, -1.4, 0);
3683
+ if (this.hasSpotLight) {
3684
+ this.createSpotlightMaterial();
3685
+ this.spotLight = new THREE.SpotLight(0xffffff, 50000);
3686
+ this.spotLight.angle = 2;
3687
+ this.spotLight.penumbra = 1;
3688
+ this.spotLight.decay = 0.01;
3689
+ this.spotLight.distance = 0;
3690
+ this.spotLight.intensity = 1;
3691
+ const spotLightTarget = new THREE.Object3D();
3692
+ this.spotLight.target = spotLightTarget;
3693
+ this.spotlightGroup = new THREE.Object3D();
3694
+ this.spotlightGroup.add(this.spotLight);
3695
+ this.spotlightGroup.add(spotLightTarget);
3696
+ this.spotLight.position.set(0, -1.4, 0);
3697
+ spotLightTarget.position.set(0, -10, 0);
3698
+ this.createSpotLightBeam();
3699
+ }
3587
3700
  }
3588
3701
  getCapabilityInValue(channel, value) {
3589
3702
  for (const capability of channel.capabilities) {
@@ -3664,11 +3777,7 @@ class Fixture3d {
3664
3777
  // Take the color into account for the beam (don't show a black beam)
3665
3778
  const color = new THREE.Color('rgb(' + this.colorRed + ', ' + this.colorGreen + ', ' + this.colorBlue + ')');
3666
3779
  const intensityColor = Math.max(this.colorRed, this.colorGreen, this.colorBlue);
3667
- if (this.pointLight) {
3668
- this.pointLight.color = color;
3669
- this.pointLight.intensity = this.pointLightMaxIntensity * this.dimmer;
3670
- }
3671
- if (this.spotLight) {
3780
+ if (this.hasSpotLight) {
3672
3781
  this.spotLight.color = color;
3673
3782
  this.spotLightBeam.material.uniforms.lightColor.value = color;
3674
3783
  this.spotLightBeam.material.uniforms.opacity.value = Math.min(intensityColor, this.dimmer);
@@ -3708,82 +3817,13 @@ class Fixture3d {
3708
3817
  }
3709
3818
  }
3710
3819
  }
3711
- atmosphereMat() {
3712
- const vertexShader = `
3713
- varying vec3 vNormal;
3714
- varying vec3 vWorldPosition;
3715
-
3716
- void main(){
3717
- vNormal = normalize(normalMatrix * normal);
3718
-
3719
- vec4 worldPosition = modelMatrix * vec4(position, 1.0);
3720
- vWorldPosition = worldPosition.xyz;
3721
-
3722
- gl_Position = projectionMatrix * modelViewMatrix * vec4(position, 1.0);
3723
- }`;
3724
- const fragmentShader = `
3725
- varying vec3 vNormal;
3726
- varying vec3 vWorldPosition;
3727
-
3728
- uniform vec3 lightColor;
3729
- uniform float opacity;
3730
- uniform vec3 spotPosition;
3731
- uniform float attenuation;
3732
- uniform float anglePower;
3733
-
3734
- void main(){
3735
- float intensity;
3736
-
3737
- intensity = distance(vWorldPosition, spotPosition) / attenuation;
3738
- intensity = 1.0 - clamp(intensity, 0.0, 1.0);
3739
-
3740
- vec3 normal = vec3(vNormal.x, vNormal.y, abs(vNormal.z));
3741
- float angleIntensity = pow(dot(normal, vec3(0.0, 0.0, 1.0)), anglePower);
3742
- intensity = intensity * angleIntensity * opacity;
3743
-
3744
- gl_FragColor = vec4(lightColor, intensity);
3745
- }`;
3746
- const material = new THREE.ShaderMaterial({
3747
- uniforms: {
3748
- attenuation: {
3749
- type: 'f',
3750
- value: 800.0,
3751
- },
3752
- anglePower: {
3753
- type: 'f',
3754
- value: 2,
3755
- },
3756
- spotPosition: {
3757
- type: 'v3',
3758
- value: new THREE.Vector3(0, 0, 0),
3759
- },
3760
- lightColor: {
3761
- type: 'c',
3762
- value: new THREE.Color('white'),
3763
- },
3764
- opacity: {
3765
- type: 'f',
3766
- value: 1.0,
3767
- },
3768
- },
3769
- vertexShader,
3770
- fragmentShader,
3771
- transparent: true,
3772
- depthWrite: false,
3773
- });
3774
- return material;
3775
- }
3776
3820
  createSpotLightBeam() {
3777
- if (this.spotLightBeam) {
3778
- this.spotlightGroup.remove(this.spotLightBeam);
3779
- }
3780
3821
  // TODO set the correct angle from the profile
3781
3822
  const beamAngleDegrees = 14;
3782
3823
  const geometry = new THREE.CylinderGeometry(0.1, beamAngleDegrees * 1.2, 100, 64, 20, false);
3783
3824
  geometry.applyMatrix4(new THREE.Matrix4().makeTranslation(0, -geometry.parameters.height / 2, 0));
3784
3825
  geometry.applyMatrix4(new THREE.Matrix4().makeRotationX(-Math.PI / 2));
3785
- this.atmosphereMaterial = this.atmosphereMat();
3786
- this.spotLightBeam = new THREE.Mesh(geometry, this.atmosphereMaterial);
3826
+ this.spotLightBeam = new THREE.Mesh(geometry, this.spotlightMaterial);
3787
3827
  this.spotLightBeam.position.set(0, -0.02, 0);
3788
3828
  this.spotLightBeam.receiveShadow = false;
3789
3829
  this.spotLightBeam.castShadow = false;
@@ -3791,30 +3831,17 @@ class Fixture3d {
3791
3831
  this.spotLightBeam.rotation.x = Math.PI / 2;
3792
3832
  }
3793
3833
  destroy() {
3794
- this.selectedMaterial.dispose();
3795
- this.atmosphereMaterial.dispose();
3834
+ if (this.hasSpotLight) {
3835
+ this.spotlightMaterial.dispose();
3836
+ }
3796
3837
  }
3797
3838
  }
3798
3839
 
3799
3840
  class ColorChanger3d extends Fixture3d {
3800
- createObjects() {
3801
- super.createObjects();
3802
- this.material = new THREE.MeshLambertMaterial({
3803
- color: 0x0d0d0d,
3804
- emissive: 0x0d0d0d,
3805
- });
3806
- this.mesh.material = this.material;
3807
- this.spotLightHelper = new THREE.SpotLightHelper(this.spotLight);
3808
- // scene.add(this.spotLightHelper);
3809
- this.objectGroup.add(this.spotlightGroup);
3810
- this.objectGroup.add(this.mesh);
3811
- // A moving head has about 32 cm in width
3812
- this.objectGroup.scale.multiplyScalar(9);
3813
- this.scene.add(this.objectGroup);
3814
- this.isLoaded = true;
3815
- }
3816
- constructor(fixtureService, previewMeshService, fixture, scene) {
3817
- super(fixtureService, fixture, scene);
3841
+ constructor(fixtureService, previewService, previewMeshService, fixture, scene) {
3842
+ super(fixtureService, previewService, fixture, scene, true);
3843
+ this.fixtureService = fixtureService;
3844
+ this.previewService = previewService;
3818
3845
  this.objectGroup = new THREE.Object3D();
3819
3846
  forkJoin([previewMeshService.getMesh('color-changer')])
3820
3847
  .pipe(map(([colorChanger]) => {
@@ -3823,8 +3850,14 @@ class ColorChanger3d extends Fixture3d {
3823
3850
  }))
3824
3851
  .subscribe();
3825
3852
  }
3826
- getObject() {
3827
- return this.objectGroup;
3853
+ createObjects() {
3854
+ super.createObjects();
3855
+ this.mesh.material = this.previewService.fixtureMaterial;
3856
+ this.objectGroup.add(this.spotlightGroup);
3857
+ this.objectGroup.add(this.mesh);
3858
+ this.objectGroup.scale.multiplyScalar(9);
3859
+ this.scene.add(this.objectGroup);
3860
+ this.isLoaded = true;
3828
3861
  }
3829
3862
  updatePreview(channelValues, masterDimmerValue) {
3830
3863
  if (!this.isLoaded) {
@@ -3836,36 +3869,48 @@ class ColorChanger3d extends Fixture3d {
3836
3869
  if (this.lastSelected !== this.isSelected) {
3837
3870
  if (this.isSelected) {
3838
3871
  for (const child of this.mesh.children) {
3839
- child.material = this.selectedMaterial;
3872
+ child.material = this.previewService.fixtureSelectedMaterial;
3840
3873
  }
3841
3874
  }
3842
3875
  else {
3843
3876
  for (const child of this.mesh.children) {
3844
- child.material = this.material;
3877
+ child.material = this.previewService.fixtureMaterial;
3845
3878
  }
3846
3879
  }
3847
3880
  this.lastSelected = this.isSelected;
3848
3881
  }
3849
- // Update the light helpers
3850
- // this.spotLightHelper.update();
3851
3882
  }
3852
3883
  destroy() {
3853
3884
  this.scene.remove(this.objectGroup);
3854
- this.material.dispose();
3855
- this.spotLightHelper.dispose();
3856
3885
  }
3857
3886
  }
3858
3887
 
3859
3888
  class MovingHead3d extends Fixture3d {
3889
+ constructor(fixtureService, previewService, previewMeshService, fixture, scene) {
3890
+ super(fixtureService, previewService, fixture, scene, true);
3891
+ this.fixtureService = fixtureService;
3892
+ this.previewService = previewService;
3893
+ this.headGroup = new THREE.Object3D();
3894
+ this.armGroup = new THREE.Object3D();
3895
+ this.objectGroup = new THREE.Object3D();
3896
+ forkJoin([
3897
+ previewMeshService.getMesh('moving_head_socket'),
3898
+ previewMeshService.getMesh('moving_head_arm'),
3899
+ previewMeshService.getMesh('moving_head_head'),
3900
+ ])
3901
+ .pipe(map(([socket, arm, head]) => {
3902
+ this.socket = socket;
3903
+ this.arm = arm;
3904
+ this.head = head;
3905
+ this.createObjects();
3906
+ }))
3907
+ .subscribe();
3908
+ }
3860
3909
  createObjects() {
3861
3910
  super.createObjects();
3862
- this.material = new THREE.MeshLambertMaterial({
3863
- color: 0x0d0d0d,
3864
- emissive: 0x0d0d0d,
3865
- });
3866
- this.socket.material = this.material;
3867
- this.arm.material = this.material;
3868
- this.head.material = this.material;
3911
+ this.socket.material = this.previewService.fixtureMaterial;
3912
+ this.arm.material = this.previewService.fixtureMaterial;
3913
+ this.head.material = this.previewService.fixtureMaterial;
3869
3914
  // Add the head
3870
3915
  this.head.scale.multiplyScalar(0.9);
3871
3916
  this.head.position.set(-0.1, 0, 0);
@@ -3886,32 +3931,12 @@ class MovingHead3d extends Fixture3d {
3886
3931
  this.scene.add(this.objectGroup);
3887
3932
  this.isLoaded = true;
3888
3933
  }
3889
- constructor(fixtureService, previewMeshService, fixture, scene) {
3890
- super(fixtureService, fixture, scene);
3891
- this.headGroup = new THREE.Object3D();
3892
- this.armGroup = new THREE.Object3D();
3893
- this.objectGroup = new THREE.Object3D();
3894
- forkJoin([
3895
- previewMeshService.getMesh('moving_head_socket'),
3896
- previewMeshService.getMesh('moving_head_arm'),
3897
- previewMeshService.getMesh('moving_head_head'),
3898
- ])
3899
- .pipe(map(([socket, arm, head]) => {
3900
- this.socket = socket;
3901
- this.arm = arm;
3902
- this.head = head;
3903
- this.createObjects();
3904
- }))
3905
- .subscribe();
3906
- }
3907
- getObject() {
3908
- return this.objectGroup;
3909
- }
3910
3934
  updatePreview(channelValues, masterDimmerValue) {
3911
3935
  if (!this.isLoaded) {
3912
3936
  return;
3913
3937
  }
3914
3938
  super.updatePreview(channelValues, masterDimmerValue);
3939
+ this.updatePosition(this.objectGroup);
3915
3940
  // Apply default settings
3916
3941
  let panStart = 0;
3917
3942
  let panEnd = 255;
@@ -3940,38 +3965,33 @@ class MovingHead3d extends Fixture3d {
3940
3965
  }
3941
3966
  }
3942
3967
  }
3943
- this.updatePosition(this.objectGroup);
3944
3968
  // calculate the y/x rotation in radiants based on pan/tilt (0-1) respecting the max pan/tilt
3945
3969
  this.armGroup.rotation.y = THREE.MathUtils.degToRad(panEnd * this.pan + panStart) - THREE.MathUtils.degToRad(panEnd / 2);
3946
3970
  this.headGroup.rotation.x = THREE.MathUtils.degToRad(tiltEnd * this.tilt + tiltStart) - THREE.MathUtils.degToRad(tiltEnd / 2);
3947
- // Update the angle (only on change, because it's expensive)
3971
+ // Update the angle only on change, because it's expensive
3948
3972
  // TODO update the correct angle from the profile
3949
3973
  const beamAngleDregrees = 14;
3950
3974
  if (this.lastBeamAngleDegrees !== beamAngleDregrees) {
3951
3975
  this.spotLight.angle = THREE.MathUtils.degToRad(beamAngleDregrees);
3952
- this.createSpotLightBeam();
3953
3976
  this.lastBeamAngleDegrees = beamAngleDregrees;
3954
3977
  }
3955
3978
  // Update the material
3956
3979
  if (this.lastSelected !== this.isSelected) {
3957
3980
  if (this.isSelected) {
3958
- this.socket.material = this.selectedMaterial;
3959
- this.arm.material = this.selectedMaterial;
3960
- this.head.material = this.selectedMaterial;
3981
+ this.socket.material = this.previewService.fixtureSelectedMaterial;
3982
+ this.arm.material = this.previewService.fixtureSelectedMaterial;
3983
+ this.head.material = this.previewService.fixtureSelectedMaterial;
3961
3984
  }
3962
3985
  else {
3963
- this.socket.material = this.material;
3964
- this.arm.material = this.material;
3965
- this.head.material = this.material;
3986
+ this.socket.material = this.previewService.fixtureMaterial;
3987
+ this.arm.material = this.previewService.fixtureMaterial;
3988
+ this.head.material = this.previewService.fixtureMaterial;
3966
3989
  }
3967
3990
  this.lastSelected = this.isSelected;
3968
3991
  }
3969
- // this.spotLightHelper.update();
3970
3992
  }
3971
3993
  destroy() {
3972
3994
  this.scene.remove(this.objectGroup);
3973
- this.material.dispose();
3974
- this.spotLightHelper.dispose();
3975
3995
  }
3976
3996
  }
3977
3997
 
@@ -4004,13 +4024,13 @@ class PreviewComponent {
4004
4024
  for (const fixture of this.fixtureService.cachedFixtures) {
4005
4025
  switch (fixture.profile.categories[0]) {
4006
4026
  case FixtureCategory['Moving Head']:
4007
- this.fixtures3d.push(new MovingHead3d(this.fixtureService, this.previewMeshService, fixture, this.scene));
4027
+ this.fixtures3d.push(new MovingHead3d(this.fixtureService, this.previewService, this.previewMeshService, fixture, this.scene));
4008
4028
  break;
4009
4029
  case FixtureCategory['Color Changer']:
4010
- this.fixtures3d.push(new ColorChanger3d(this.fixtureService, this.previewMeshService, fixture, this.scene));
4030
+ this.fixtures3d.push(new ColorChanger3d(this.fixtureService, this.previewService, this.previewMeshService, fixture, this.scene));
4011
4031
  break;
4012
4032
  case FixtureCategory['Blinder']:
4013
- this.fixtures3d.push(new ColorChanger3d(this.fixtureService, this.previewMeshService, fixture, this.scene));
4033
+ this.fixtures3d.push(new ColorChanger3d(this.fixtureService, this.previewService, this.previewMeshService, fixture, this.scene));
4014
4034
  break;
4015
4035
  }
4016
4036
  }
@@ -8217,13 +8237,13 @@ function FixtureCapabilityComponent_div_2_Template(rf, ctx) { if (rf & 1) {
8217
8237
  const ctx_r2 = i0.ɵɵnextContext();
8218
8238
  i0.ɵɵclassProp("h-100", ctx_r2.isChrome());
8219
8239
  i0.ɵɵadvance();
8220
- i0.ɵɵproperty("ngIf", ctx_r2.presetService.hasCapabilityDimmer());
8240
+ i0.ɵɵproperty("ngIf", ctx_r2.hasCapabilityDimmer);
8221
8241
  i0.ɵɵadvance();
8222
- i0.ɵɵproperty("ngIf", ctx_r2.presetService.hasCapabilityColorOrColorWheel());
8242
+ i0.ɵɵproperty("ngIf", ctx_r2.hasCapabilityColorOrColorWheel);
8223
8243
  i0.ɵɵadvance();
8224
8244
  i0.ɵɵproperty("ngForOf", i0.ɵɵpipeBind1(4, 6, ctx_r2.colorWheelChannels));
8225
8245
  i0.ɵɵadvance(2);
8226
- i0.ɵɵproperty("ngIf", ctx_r2.presetService.hasCapabilityPanTilt());
8246
+ i0.ɵɵproperty("ngIf", ctx_r2.hasCapabilityPanTilt);
8227
8247
  } }
8228
8248
  function FixtureCapabilityComponent_div_3_Template(rf, ctx) { if (rf & 1) {
8229
8249
  i0.ɵɵelementStart(0, "div", 10)(1, "p", 11);
@@ -8252,6 +8272,9 @@ class FixtureCapabilityComponent {
8252
8272
  this.introService = introService;
8253
8273
  // map containing the profile and the channel name containing the wheel
8254
8274
  this.colorWheelChannels = new Map();
8275
+ this.hasCapabilityDimmer = false;
8276
+ this.hasCapabilityColorOrColorWheel = false;
8277
+ this.hasCapabilityPanTilt = false;
8255
8278
  this.fixtureSelectionChangedSubscription = this.presetService.fixtureSelectionChanged.subscribe(() => {
8256
8279
  this.update();
8257
8280
  });
@@ -8300,8 +8323,14 @@ class FixtureCapabilityComponent {
8300
8323
  }
8301
8324
  }
8302
8325
  }
8326
+ updateCapabilities() {
8327
+ this.hasCapabilityDimmer = this.presetService.hasCapabilityDimmer();
8328
+ this.hasCapabilityColorOrColorWheel = this.presetService.hasCapabilityColorOrColorWheel();
8329
+ this.hasCapabilityPanTilt = this.presetService.hasCapabilityPanTilt();
8330
+ }
8303
8331
  update() {
8304
8332
  this.updateColorWheels();
8333
+ this.updateCapabilities();
8305
8334
  this.changeDetectorRef.detectChanges();
8306
8335
  }
8307
8336
  isChrome() {
@@ -8327,7 +8356,7 @@ class FixtureCapabilityComponent {
8327
8356
  }
8328
8357
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FixtureCapabilityComponent, [{
8329
8358
  type: Component,
8330
- args: [{ selector: 'lib-app-fixture-capability', changeDetection: ChangeDetectionStrategy.OnPush, 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 <div *ngIf=\"presetService.selectedPreset\" 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 <div *ngIf=\"presetService.hasCapabilityDimmer()\" 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 <div *ngIf=\"presetService.hasCapabilityColorOrColorWheel()\" 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 <div\n *ngFor=\"let entry of colorWheelChannels | keyvalue; let i = index\"\n class=\"col col-auto p-0 my-3 mr-3\"\n style=\"height: calc(100% - 2rem)\"\n >\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 <div *ngIf=\"presetService.hasCapabilityPanTilt()\" 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\n <div *ngIf=\"projectService.project.fixtures.length == 0\" class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures' | translate }}</p>\n </div>\n\n <div\n *ngIf=\"\n projectService.project.fixtures.length > 0 && presetService.selectedPreset && presetService.selectedPreset.fixtures.length == 0\n \"\n class=\"m-auto\"\n >\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures-selected' | translate }}</p>\n </div>\n </div>\n</div>\n" }]
8359
+ args: [{ selector: 'lib-app-fixture-capability', changeDetection: ChangeDetectionStrategy.OnPush, 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 <div *ngIf=\"presetService.selectedPreset\" 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 <div *ngIf=\"hasCapabilityDimmer\" 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 <div *ngIf=\"hasCapabilityColorOrColorWheel\" 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 <div\n *ngFor=\"let entry of colorWheelChannels | keyvalue; let i = index\"\n class=\"col col-auto p-0 my-3 mr-3\"\n style=\"height: calc(100% - 2rem)\"\n >\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 <div *ngIf=\"hasCapabilityPanTilt\" 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\n <div *ngIf=\"projectService.project.fixtures.length == 0\" class=\"m-auto\">\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures' | translate }}</p>\n </div>\n\n <div\n *ngIf=\"\n projectService.project.fixtures.length > 0 && presetService.selectedPreset && presetService.selectedPreset.fixtures.length == 0\n \"\n class=\"m-auto\"\n >\n <p class=\"m-auto\" style=\"color: #717171\">{{ 'designer.fixture.no-fixtures-selected' | translate }}</p>\n </div>\n </div>\n</div>\n" }]
8331
8360
  }], () => [{ type: PresetService }, { type: FixtureService }, { type: i0.ChangeDetectorRef }, { type: ProjectService }, { type: IntroService }], null); })();
8332
8361
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(FixtureCapabilityComponent, { className: "FixtureCapabilityComponent" }); })();
8333
8362
 
@@ -9974,11 +10003,49 @@ class MasterDimmerComponent {
9974
10003
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(MasterDimmerComponent, { className: "MasterDimmerComponent" }); })();
9975
10004
 
9976
10005
  const _c0$2 = ["sliderValue"];
9977
- function FixtureCapabilityChannelComponent_div_9_div_1_span_6_Template(rf, ctx) { if (rf & 1) {
10006
+ function FixtureCapabilityChannelComponent_div_9_div_1_span_5_Template(rf, ctx) { if (rf & 1) {
10007
+ i0.ɵɵelementStart(0, "span");
10008
+ i0.ɵɵtext(1);
10009
+ i0.ɵɵelementEnd();
10010
+ } if (rf & 2) {
10011
+ const capability_r3 = i0.ɵɵnextContext().$implicit;
10012
+ const ctx_r1 = i0.ɵɵnextContext(2);
10013
+ i0.ɵɵadvance();
10014
+ i0.ɵɵtextInterpolate1(" (", ctx_r1.getDescription(capability_r3), ")");
10015
+ } }
10016
+ function FixtureCapabilityChannelComponent_div_9_div_1_div_7_Template(rf, ctx) { if (rf & 1) {
10017
+ i0.ɵɵelement(0, "div", 20);
10018
+ } if (rf & 2) {
10019
+ const color_r4 = ctx.$implicit;
10020
+ i0.ɵɵstyleProp("background-color", color_r4);
10021
+ } }
10022
+ function FixtureCapabilityChannelComponent_div_9_div_1_small_8_Template(rf, ctx) { if (rf & 1) {
10023
+ i0.ɵɵelementStart(0, "small");
10024
+ i0.ɵɵtext(1);
10025
+ i0.ɵɵelementEnd();
10026
+ } if (rf & 2) {
10027
+ const capability_r3 = i0.ɵɵnextContext().$implicit;
10028
+ const ctx_r1 = i0.ɵɵnextContext(2);
10029
+ i0.ɵɵadvance();
10030
+ i0.ɵɵtextInterpolate2(" (", ctx_r1.getDescriptionStart(capability_r3), " to ", ctx_r1.getDescriptionEnd(capability_r3), ")");
10031
+ } }
10032
+ function FixtureCapabilityChannelComponent_div_9_div_1_span_9_Template(rf, ctx) { if (rf & 1) {
9978
10033
  i0.ɵɵelementStart(0, "span");
9979
10034
  i0.ɵɵtext(1, " - ");
9980
10035
  i0.ɵɵelementEnd();
9981
10036
  } }
10037
+ function FixtureCapabilityChannelComponent_div_9_div_1_i_11_Template(rf, ctx) { if (rf & 1) {
10038
+ i0.ɵɵelement(0, "i", 21);
10039
+ i0.ɵɵpipe(1, "translate");
10040
+ } if (rf & 2) {
10041
+ i0.ɵɵpropertyInterpolate("popover", i0.ɵɵpipeBind1(1, 1, "designer.fixture.capability-sound-controlled"));
10042
+ } }
10043
+ function FixtureCapabilityChannelComponent_div_9_div_1_i_12_Template(rf, ctx) { if (rf & 1) {
10044
+ i0.ɵɵelement(0, "i", 22);
10045
+ i0.ɵɵpipe(1, "translate");
10046
+ } if (rf & 2) {
10047
+ i0.ɵɵpropertyInterpolate("popover", i0.ɵɵpipeBind1(1, 1, "designer.fixture.capability-random-timing"));
10048
+ } }
9982
10049
  function FixtureCapabilityChannelComponent_div_9_div_1_Template(rf, ctx) { if (rf & 1) {
9983
10050
  const _r1 = i0.ɵɵgetCurrentView();
9984
10051
  i0.ɵɵelementStart(0, "div", 5)(1, "input", 14);
@@ -9988,31 +10055,44 @@ function FixtureCapabilityChannelComponent_div_9_div_1_Template(rf, ctx) { if (r
9988
10055
  i0.ɵɵelementStart(2, "label", 15);
9989
10056
  i0.ɵɵtext(3);
9990
10057
  i0.ɵɵpipe(4, "translate");
9991
- i0.ɵɵelementStart(5, "small");
9992
- i0.ɵɵtemplate(6, FixtureCapabilityChannelComponent_div_9_div_1_span_6_Template, 2, 0, "span", 16);
9993
- i0.ɵɵtext(7);
9994
- i0.ɵɵelementEnd()()();
10058
+ i0.ɵɵtemplate(5, FixtureCapabilityChannelComponent_div_9_div_1_span_5_Template, 2, 1, "span", 16);
10059
+ i0.ɵɵelementStart(6, "small");
10060
+ i0.ɵɵtemplate(7, FixtureCapabilityChannelComponent_div_9_div_1_div_7_Template, 1, 2, "div", 17)(8, FixtureCapabilityChannelComponent_div_9_div_1_small_8_Template, 2, 2, "small", 16)(9, FixtureCapabilityChannelComponent_div_9_div_1_span_9_Template, 2, 0, "span", 16);
10061
+ i0.ɵɵtext(10);
10062
+ i0.ɵɵelementEnd();
10063
+ i0.ɵɵtemplate(11, FixtureCapabilityChannelComponent_div_9_div_1_i_11_Template, 2, 3, "i", 18)(12, FixtureCapabilityChannelComponent_div_9_div_1_i_12_Template, 2, 3, "i", 19);
10064
+ i0.ɵɵelementEnd()();
9995
10065
  } if (rf & 2) {
9996
10066
  const capability_r3 = ctx.$implicit;
9997
- const i_r4 = ctx.index;
10067
+ const i_r5 = ctx.index;
9998
10068
  const ctx_r1 = i0.ɵɵnextContext(2);
9999
10069
  i0.ɵɵadvance();
10000
10070
  i0.ɵɵpropertyInterpolate1("name", "capabilityGeneric", ctx_r1.capabilityIndex, "Option");
10001
- i0.ɵɵpropertyInterpolate2("id", "capabilityGeneric", ctx_r1.capabilityIndex, "Option", i_r4, "");
10071
+ i0.ɵɵpropertyInterpolate2("id", "capabilityGeneric", ctx_r1.capabilityIndex, "Option", i_r5, "");
10002
10072
  i0.ɵɵtwoWayProperty("ngModel", ctx_r1.selectedCapability);
10003
10073
  i0.ɵɵproperty("value", capability_r3);
10004
10074
  i0.ɵɵadvance();
10005
- i0.ɵɵpropertyInterpolate2("for", "capabilityGeneric", ctx_r1.capabilityIndex, "Option", i_r4, "");
10075
+ i0.ɵɵpropertyInterpolate2("for", "capabilityGeneric", ctx_r1.capabilityIndex, "Option", i_r5, "");
10076
+ i0.ɵɵadvance();
10077
+ i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(4, 18, "designer.fixtureCapabilityType." + capability_r3.capability.type), "");
10078
+ i0.ɵɵadvance(2);
10079
+ i0.ɵɵproperty("ngIf", ctx_r1.getDescription(capability_r3));
10080
+ i0.ɵɵadvance(2);
10081
+ i0.ɵɵproperty("ngForOf", capability_r3.capability.colors);
10082
+ i0.ɵɵadvance();
10083
+ i0.ɵɵproperty("ngIf", ctx_r1.getDescriptionStart(capability_r3));
10006
10084
  i0.ɵɵadvance();
10007
- i0.ɵɵtextInterpolate1(" ", i0.ɵɵpipeBind1(4, 13, "designer.fixtureCapabilityType." + capability_r3.capability.type), "");
10008
- i0.ɵɵadvance(3);
10009
10085
  i0.ɵɵproperty("ngIf", capability_r3.capability.comment);
10010
10086
  i0.ɵɵadvance();
10011
10087
  i0.ɵɵtextInterpolate1(" ", capability_r3.capability.comment, "");
10088
+ i0.ɵɵadvance();
10089
+ i0.ɵɵproperty("ngIf", capability_r3.capability.soundControlled);
10090
+ i0.ɵɵadvance();
10091
+ i0.ɵɵproperty("ngIf", capability_r3.capability.randomTiming);
10012
10092
  } }
10013
10093
  function FixtureCapabilityChannelComponent_div_9_Template(rf, ctx) { if (rf & 1) {
10014
10094
  i0.ɵɵelementStart(0, "div", 12);
10015
- i0.ɵɵtemplate(1, FixtureCapabilityChannelComponent_div_9_div_1_Template, 8, 15, "div", 13);
10095
+ i0.ɵɵtemplate(1, FixtureCapabilityChannelComponent_div_9_div_1_Template, 13, 20, "div", 13);
10016
10096
  i0.ɵɵelementEnd();
10017
10097
  } if (rf & 2) {
10018
10098
  const ctx_r1 = i0.ɵɵnextContext();
@@ -10020,20 +10100,30 @@ function FixtureCapabilityChannelComponent_div_9_Template(rf, ctx) { if (rf & 1)
10020
10100
  i0.ɵɵproperty("ngForOf", ctx_r1._channel.capabilities);
10021
10101
  } }
10022
10102
  function FixtureCapabilityChannelComponent_div_10_Template(rf, ctx) { if (rf & 1) {
10023
- const _r5 = i0.ɵɵgetCurrentView();
10024
- i0.ɵɵelementStart(0, "div", 17)(1, "div", 18)(2, "input", 19, 0);
10025
- i0.ɵɵlistener("ngModelChange", function FixtureCapabilityChannelComponent_div_10_Template_input_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setValue($event)); });
10103
+ const _r6 = i0.ɵɵgetCurrentView();
10104
+ i0.ɵɵelementStart(0, "div", 23)(1, "div", 24)(2, "input", 25, 0);
10105
+ i0.ɵɵlistener("ngModelChange", function FixtureCapabilityChannelComponent_div_10_Template_input_ngModelChange_2_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setValue($event)); });
10106
+ i0.ɵɵelementEnd()();
10107
+ i0.ɵɵelementStart(4, "div", 26);
10108
+ i0.ɵɵtext(5);
10109
+ i0.ɵɵelementEnd();
10110
+ i0.ɵɵelementStart(6, "div", 27)(7, "mv-slider", 28, 1);
10111
+ i0.ɵɵlistener("change", function FixtureCapabilityChannelComponent_div_10_Template_mv_slider_change_7_listener($event) { i0.ɵɵrestoreView(_r6); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setValue($event.newValue)); });
10112
+ i0.ɵɵelementEnd()();
10113
+ i0.ɵɵelementStart(9, "div", 29);
10114
+ i0.ɵɵtext(10);
10026
10115
  i0.ɵɵelementEnd()();
10027
- i0.ɵɵelementStart(4, "div", 20)(5, "mv-slider", 21, 1);
10028
- i0.ɵɵlistener("change", function FixtureCapabilityChannelComponent_div_10_Template_mv_slider_change_5_listener($event) { i0.ɵɵrestoreView(_r5); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.setValue($event.newValue)); });
10029
- i0.ɵɵelementEnd()()();
10030
10116
  } if (rf & 2) {
10031
10117
  const ctx_r1 = i0.ɵɵnextContext();
10032
10118
  i0.ɵɵclassProp("pl-0", (ctx_r1._channel.capabilities == null ? null : ctx_r1._channel.capabilities.length) > 1);
10033
10119
  i0.ɵɵadvance(2);
10034
10120
  i0.ɵɵproperty("ngModel", ctx_r1.templateValue);
10035
10121
  i0.ɵɵadvance(3);
10122
+ i0.ɵɵtextInterpolate(ctx_r1.descriptionEnd);
10123
+ i0.ɵɵadvance(2);
10036
10124
  i0.ɵɵproperty("value", ctx_r1.templateValue)("orientation", "vertical")("reversed", true)("tooltip", "hide")("min", ctx_r1.rangeMin)("max", ctx_r1.rangeMax)("step", 1);
10125
+ i0.ɵɵadvance(3);
10126
+ i0.ɵɵtextInterpolate(ctx_r1.descriptionStart);
10037
10127
  } }
10038
10128
  class FixtureCapabilityChannelComponent {
10039
10129
  set channel(value) {
@@ -10042,11 +10132,12 @@ class FixtureCapabilityChannelComponent {
10042
10132
  }
10043
10133
  constructor(presetService) {
10044
10134
  this.presetService = presetService;
10045
- this.rangeMin = 0;
10046
- this.rangeMax = 0;
10047
10135
  this.defaultValue = 0;
10048
10136
  this.value = 0;
10049
10137
  this.templateValue = 0;
10138
+ this.hasRange = false;
10139
+ this.rangeMin = 0;
10140
+ this.rangeMax = 0;
10050
10141
  }
10051
10142
  updateChannel() {
10052
10143
  this.selectedCapability = this._channel.capabilities[0];
@@ -10054,25 +10145,107 @@ class FixtureCapabilityChannelComponent {
10054
10145
  this.calculateTemplateValue();
10055
10146
  if (this.value >= 0) {
10056
10147
  for (const capability of this._channel.capabilities) {
10057
- if (capability.capability.dmxRange.length > 0 && capability.centerValue === this.value) {
10148
+ if (capability.capability.dmxRange.length > 0 &&
10149
+ capability.capability.dmxRange[0] <= this.value &&
10150
+ this.value <= capability.capability.dmxRange[1]) {
10058
10151
  this.selectedCapability = capability;
10059
10152
  break;
10060
10153
  }
10061
10154
  }
10062
10155
  }
10156
+ this.defaultValue = this.getDefaultValue();
10157
+ this.description = this.getDescription(this.selectedCapability);
10158
+ this.hasRange = this.capabilityHasRange();
10063
10159
  this.rangeMin = this.getRangeMin();
10064
10160
  this.rangeMax = this.getRangeMax();
10065
- this.defaultValue = this.getDefaultValue();
10161
+ this.descriptionStart = this.getDescriptionStart(this.selectedCapability);
10162
+ this.descriptionEnd = this.getDescriptionEnd(this.selectedCapability);
10066
10163
  }
10067
10164
  capabilityHasRange() {
10068
- if (this._channel.capabilities && this._channel.capabilities.length === 1) {
10165
+ if (this._channel?.capabilities?.length === 1) {
10166
+ // TODO does this work in all cases? if we have no option, it's always a range?
10069
10167
  return true;
10070
10168
  }
10071
- if (this.selectedCapability && this.selectedCapability.capability.angleStart) {
10169
+ if (this.selectedCapability?.capability.angleStart ||
10170
+ this.selectedCapability?.capability.speedStart ||
10171
+ this.selectedCapability?.capability.brightnessStart ||
10172
+ this.selectedCapability?.capability.durationStart ||
10173
+ this.selectedCapability?.capability.colorTemperatureStart ||
10174
+ this.selectedCapability?.capability.soundSensitivityStart ||
10175
+ this.selectedCapability?.capability.horizontalAngleStart ||
10176
+ this.selectedCapability?.capability.verticalAngleStart ||
10177
+ this.selectedCapability?.capability.distanceStart ||
10178
+ this.selectedCapability?.capability.openPercentStart ||
10179
+ this.selectedCapability?.capability.frostIntensityStart ||
10180
+ this.selectedCapability?.capability.fogOutputStart ||
10181
+ this.selectedCapability?.capability.timeStart ||
10182
+ this.selectedCapability?.capability.insertionStart ||
10183
+ this.selectedCapability?.capability.colorsStart) {
10072
10184
  return true;
10073
10185
  }
10074
10186
  return false;
10075
10187
  }
10188
+ getDescriptionStart(capability) {
10189
+ if (!capability || !capability.capability) {
10190
+ return '';
10191
+ }
10192
+ return (capability.capability.angleStart ||
10193
+ capability.capability.speedStart ||
10194
+ capability.capability.brightnessStart ||
10195
+ capability.capability.durationStart ||
10196
+ capability.capability.colorTemperatureStart ||
10197
+ capability.capability.soundSensitivityStart ||
10198
+ capability.capability.horizontalAngleStart ||
10199
+ capability.capability.verticalAngleStart ||
10200
+ capability.capability.distanceStart ||
10201
+ capability.capability.openPercentStart ||
10202
+ capability.capability.frostIntensityStart ||
10203
+ capability.capability.fogOutputStart ||
10204
+ capability.capability.timeStart ||
10205
+ capability.capability.insertionStart ||
10206
+ capability.capability.colorsStart)?.toString();
10207
+ }
10208
+ getDescriptionEnd(capability) {
10209
+ if (!capability || !capability.capability) {
10210
+ return '';
10211
+ }
10212
+ return (capability.capability.angleEnd ||
10213
+ capability.capability.speedEnd ||
10214
+ capability.capability.brightnessEnd ||
10215
+ capability.capability.durationEnd ||
10216
+ capability.capability.colorTemperatureEnd ||
10217
+ capability.capability.soundSensitivityEnd ||
10218
+ capability.capability.horizontalAngleEnd ||
10219
+ capability.capability.verticalAngleEnd ||
10220
+ capability.capability.distanceEnd ||
10221
+ capability.capability.openPercentEnd ||
10222
+ capability.capability.frostIntensityEnd ||
10223
+ capability.capability.fogOutputEnd ||
10224
+ capability.capability.timeEnd ||
10225
+ capability.capability.insertionEnd ||
10226
+ capability.capability.colorsEnd)?.toString();
10227
+ }
10228
+ getDescription(capability) {
10229
+ if (!capability || !capability.capability) {
10230
+ return '';
10231
+ }
10232
+ return (capability.capability.slotNumber ||
10233
+ capability.capability.shutterEffect ||
10234
+ capability.capability.angle ||
10235
+ capability.capability.speed ||
10236
+ capability.capability.brightness ||
10237
+ capability.capability.duration ||
10238
+ capability.capability.colorTemperature ||
10239
+ capability.capability.soundSensitivity ||
10240
+ capability.capability.horizontalAngle ||
10241
+ capability.capability.verticalAngle ||
10242
+ capability.capability.distance ||
10243
+ capability.capability.openPercent ||
10244
+ capability.capability.frostIntensity ||
10245
+ capability.capability.fogOutput ||
10246
+ capability.capability.time ||
10247
+ capability.capability.insertion)?.toString();
10248
+ }
10076
10249
  getRangeMin() {
10077
10250
  if (this.selectedCapability.capability.dmxRange.length > 0) {
10078
10251
  return this.selectedCapability.capability.dmxRange[0];
@@ -10090,7 +10263,7 @@ class FixtureCapabilityChannelComponent {
10090
10263
  if (isNaN(value)) {
10091
10264
  return;
10092
10265
  }
10093
- if (!ignoreCapabilityRange && (value < this.getRangeMin() || value > this.getRangeMax())) {
10266
+ if (!ignoreCapabilityRange && (value < this.rangeMin || value > this.rangeMax)) {
10094
10267
  return;
10095
10268
  }
10096
10269
  this.value = value;
@@ -10102,7 +10275,9 @@ class FixtureCapabilityChannelComponent {
10102
10275
  // TODO use the same technique in the dimmer/pan/tilt/color sliders
10103
10276
  if (!this.valueSetTimer) {
10104
10277
  this.valueSetTimer = setTimeout(() => {
10105
- this.sliderValue.nativeElement.value = this.value;
10278
+ if (this.sliderValue) {
10279
+ this.sliderValue.nativeElement.value = this.value;
10280
+ }
10106
10281
  this.valueSetTimer = undefined;
10107
10282
  }, 30);
10108
10283
  }
@@ -10132,12 +10307,13 @@ class FixtureCapabilityChannelComponent {
10132
10307
  }
10133
10308
  capabilitySelected() {
10134
10309
  // select the center value of the selected capability
10135
- if (this.capabilityHasRange) {
10310
+ if (this.capabilityHasRange()) {
10136
10311
  this.setValue(this.selectedCapability.capability.dmxRange[0], true);
10137
10312
  }
10138
10313
  else {
10139
10314
  this.setValue(this.selectedCapability.centerValue, true);
10140
10315
  }
10316
+ this.updateChannel();
10141
10317
  }
10142
10318
  static { this.ɵfac = function FixtureCapabilityChannelComponent_Factory(t) { return new (t || FixtureCapabilityChannelComponent)(i0.ɵɵdirectiveInject(PresetService)); }; }
10143
10319
  static { this.ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: FixtureCapabilityChannelComponent, selectors: [["lib-app-fixture-capability-channel"]], viewQuery: function FixtureCapabilityChannelComponent_Query(rf, ctx) { if (rf & 1) {
@@ -10145,7 +10321,7 @@ class FixtureCapabilityChannelComponent {
10145
10321
  } if (rf & 2) {
10146
10322
  let _t;
10147
10323
  i0.ɵɵqueryRefresh(_t = i0.ɵɵloadQuery()) && (ctx.sliderValue = _t.first);
10148
- } }, inputs: { profile: "profile", channel: "channel", capabilityIndex: "capabilityIndex" }, decls: 11, vars: 10, consts: [["sliderValue", ""], ["slider", ""], [1, "card", "border-secondary", "h-100", 2, "min-height", "200px"], [1, "card-header"], [1, "my-auto"], [1, "form-check"], ["type", "checkbox", 1, "form-check-input", 3, "ngModelChange", "id", "ngModel"], [1, "form-check-label", 3, "for"], [1, "card-body", "h-100", "d-flex", 2, "flex-direction", "column", "overflow", "hidden"], [1, "row", "h-100"], ["class", "col mr-3", "style", "overflow-y: auto", 4, "ngIf"], ["class", "col col-auto d-flex mx-auto", "style", "flex-direction: column", 3, "pl-0", 4, "ngIf"], [1, "col", "mr-3", 2, "overflow-y", "auto"], ["class", "form-check", 4, "ngFor", "ngForOf"], ["type", "radio", 1, "form-check-input", 3, "ngModelChange", "change", "ngModel", "name", "id", "value"], [1, "form-check-label", 2, "max-width", "200px", 3, "for"], [4, "ngIf"], [1, "col", "col-auto", "d-flex", "mx-auto", 2, "flex-direction", "column"], [1, "mb-4", "w-100", "d-flex"], ["type", "text", 1, "mx-auto", 2, "width", "45px", "height", "20px", "text-align", "center", "font-size", "12px", "font-family", "monospace", 3, "ngModelChange", "ngModel"], [1, "h-100", "w-100", "d-flex"], [1, "mx-auto", 2, "height", "100%", 3, "change", "value", "orientation", "reversed", "tooltip", "min", "max", "step"]], template: function FixtureCapabilityChannelComponent_Template(rf, ctx) { if (rf & 1) {
10324
+ } }, inputs: { profile: "profile", channel: "channel", capabilityIndex: "capabilityIndex" }, decls: 11, vars: 10, consts: [["sliderValue", ""], ["slider", ""], [1, "card", "border-secondary", "h-100", 2, "min-height", "200px"], [1, "card-header"], [1, "my-auto"], [1, "form-check"], ["type", "checkbox", 1, "form-check-input", 3, "ngModelChange", "id", "ngModel"], [1, "form-check-label", 3, "for"], [1, "card-body", "h-100", "d-flex", 2, "flex-direction", "column", "overflow", "hidden"], [1, "row", "h-100"], ["class", "col mr-3", "style", "overflow-y: auto", 4, "ngIf"], ["class", "col col-auto d-flex mx-auto", "style", "flex-direction: column", 3, "pl-0", 4, "ngIf"], [1, "col", "mr-3", 2, "overflow-y", "auto"], ["class", "form-check", 4, "ngFor", "ngForOf"], ["type", "radio", 1, "form-check-input", 3, "ngModelChange", "change", "ngModel", "name", "id", "value"], [1, "form-check-label", 2, "max-width", "200px", 3, "for"], [4, "ngIf"], ["class", "color", 3, "background-color", 4, "ngFor", "ngForOf"], ["class", "fa fa-microphone pl-1", "container", "body", "placement", "top", "triggers", "mouseenter:mouseleave", "aria-hidden", "true", 3, "popover", 4, "ngIf"], ["class", "fa fa-random pl-1", "container", "body", "placement", "top", "triggers", "mouseenter:mouseleave", "aria-hidden", "true", 3, "popover", 4, "ngIf"], [1, "color"], ["container", "body", "placement", "top", "triggers", "mouseenter:mouseleave", "aria-hidden", "true", 1, "fa", "fa-microphone", "pl-1", 3, "popover"], ["container", "body", "placement", "top", "triggers", "mouseenter:mouseleave", "aria-hidden", "true", 1, "fa", "fa-random", "pl-1", 3, "popover"], [1, "col", "col-auto", "d-flex", "mx-auto", 2, "flex-direction", "column"], [1, "mb-2", "w-100", "d-flex"], ["type", "text", 1, "mx-auto", 2, "width", "45px", "height", "20px", "text-align", "center", "font-size", "12px", "font-family", "monospace", 3, "ngModelChange", "ngModel"], [1, "mx-auto", "mb-2"], [1, "h-100", "w-100", "d-flex"], [1, "mx-auto", 2, "height", "100%", 3, "change", "value", "orientation", "reversed", "tooltip", "min", "max", "step"], [1, "mx-auto", "mt-2"]], template: function FixtureCapabilityChannelComponent_Template(rf, ctx) { if (rf & 1) {
10149
10325
  i0.ɵɵelementStart(0, "div", 2)(1, "div", 3)(2, "div", 4)(3, "div", 5)(4, "input", 6);
10150
10326
  i0.ɵɵlistener("ngModelChange", function FixtureCapabilityChannelComponent_Template_input_ngModelChange_4_listener($event) { return ctx.changeActive($event); });
10151
10327
  i0.ɵɵelementEnd();
@@ -10153,7 +10329,7 @@ class FixtureCapabilityChannelComponent {
10153
10329
  i0.ɵɵtext(6);
10154
10330
  i0.ɵɵelementEnd()()()();
10155
10331
  i0.ɵɵelementStart(7, "div", 8)(8, "div", 9);
10156
- i0.ɵɵtemplate(9, FixtureCapabilityChannelComponent_div_9_Template, 2, 1, "div", 10)(10, FixtureCapabilityChannelComponent_div_10_Template, 7, 10, "div", 11);
10332
+ i0.ɵɵtemplate(9, FixtureCapabilityChannelComponent_div_9_Template, 2, 1, "div", 10)(10, FixtureCapabilityChannelComponent_div_10_Template, 11, 12, "div", 11);
10157
10333
  i0.ɵɵelementEnd()()();
10158
10334
  } if (rf & 2) {
10159
10335
  i0.ɵɵclassProp("capability-deactivated", ctx.value == undefined);
@@ -10167,12 +10343,12 @@ class FixtureCapabilityChannelComponent {
10167
10343
  i0.ɵɵadvance(3);
10168
10344
  i0.ɵɵproperty("ngIf", (ctx._channel.capabilities == null ? null : ctx._channel.capabilities.length) > 1);
10169
10345
  i0.ɵɵadvance();
10170
- i0.ɵɵproperty("ngIf", ctx.capabilityHasRange());
10171
- } }, dependencies: [i5.NgForOf, i5.NgIf, i4.DefaultValueAccessor, i4.CheckboxControlValueAccessor, i4.RadioControlValueAccessor, i4.NgControlStatus, i4.NgModel, i4$1.SliderComponent, i2.TranslatePipe], changeDetection: 0 }); }
10346
+ i0.ɵɵproperty("ngIf", ctx.hasRange);
10347
+ } }, dependencies: [i5.NgForOf, i5.NgIf, i4.DefaultValueAccessor, i4.CheckboxControlValueAccessor, i4.RadioControlValueAccessor, i4.NgControlStatus, i4.NgModel, i4$1.SliderComponent, i12.PopoverDirective, i2.TranslatePipe], styles: [".color[_ngcontent-%COMP%]{display:inline-block;margin-left:5px;border-radius:50%;width:12px;height:12px;border:1px white solid;vertical-align:middle}"], changeDetection: 0 }); }
10172
10348
  }
10173
10349
  (() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(FixtureCapabilityChannelComponent, [{
10174
10350
  type: Component,
10175
- args: [{ selector: 'lib-app-fixture-capability-channel', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"card border-secondary h-100\" [class.capability-deactivated]=\"value == 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=\"capabilityGeneric{{ capabilityIndex }}Active\"\n [ngModel]=\"value != undefined\"\n (ngModelChange)=\"changeActive($event)\"\n />\n <label class=\"form-check-label\" for=\"capabilityGeneric{{ capabilityIndex }}Active\">\n {{ _channel?.name }}\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"card-body h-100 d-flex\" style=\"flex-direction: column; overflow: hidden\">\n <div class=\"row h-100\">\n <!-- display all options, if there is more than one -->\n <div *ngIf=\"_channel.capabilities?.length > 1\" class=\"col mr-3\" style=\"overflow-y: auto\">\n <div *ngFor=\"let capability of _channel.capabilities; let i = index\" class=\"form-check\">\n <input\n [(ngModel)]=\"selectedCapability\"\n (change)=\"capabilitySelected()\"\n class=\"form-check-input\"\n type=\"radio\"\n name=\"capabilityGeneric{{ capabilityIndex }}Option\"\n id=\"capabilityGeneric{{ capabilityIndex }}Option{{ i }}\"\n [value]=\"capability\"\n />\n <label style=\"max-width: 200px\" class=\"form-check-label\" for=\"capabilityGeneric{{ capabilityIndex }}Option{{ i }}\">\n {{ 'designer.fixtureCapabilityType.' + capability.capability.type | translate\n }}<small><span *ngIf=\"capability.capability.comment\"> - </span> {{ capability.capability.comment }}</small>\n </label>\n </div>\n </div>\n\n <!-- display a slider to select the value for the currently selected capability, if it has a range -->\n <div\n *ngIf=\"capabilityHasRange()\"\n class=\"col col-auto d-flex mx-auto\"\n [class.pl-0]=\"_channel.capabilities?.length > 1\"\n style=\"flex-direction: column\"\n >\n <div class=\"mb-4 w-100 d-flex\">\n <input\n #sliderValue\n class=\"mx-auto\"\n type=\"text\"\n [ngModel]=\"templateValue\"\n (ngModelChange)=\"setValue($event)\"\n style=\"width: 45px; height: 20px; text-align: center; font-size: 12px; font-family: monospace\"\n />\n </div>\n\n <div class=\"h-100 w-100 d-flex\">\n <mv-slider\n #slider\n class=\"mx-auto\"\n [value]=\"templateValue\"\n (change)=\"setValue($event.newValue)\"\n [orientation]=\"'vertical'\"\n [reversed]=\"true\"\n style=\"height: 100%\"\n [tooltip]=\"'hide'\"\n [min]=\"rangeMin\"\n [max]=\"rangeMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n </div>\n </div>\n </div>\n</div>\n" }]
10351
+ args: [{ selector: 'lib-app-fixture-capability-channel', changeDetection: ChangeDetectionStrategy.OnPush, template: "<div class=\"card border-secondary h-100\" [class.capability-deactivated]=\"value == 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=\"capabilityGeneric{{ capabilityIndex }}Active\"\n [ngModel]=\"value != undefined\"\n (ngModelChange)=\"changeActive($event)\"\n />\n <label class=\"form-check-label\" for=\"capabilityGeneric{{ capabilityIndex }}Active\">\n {{ _channel?.name }}\n </label>\n </div>\n </div>\n </div>\n\n <div class=\"card-body h-100 d-flex\" style=\"flex-direction: column; overflow: hidden\">\n <div class=\"row h-100\">\n <!-- display all options, if there is more than one -->\n <div *ngIf=\"_channel.capabilities?.length > 1\" class=\"col mr-3\" style=\"overflow-y: auto\">\n <div *ngFor=\"let capability of _channel.capabilities; let i = index\" class=\"form-check\">\n <input\n [(ngModel)]=\"selectedCapability\"\n (change)=\"capabilitySelected()\"\n class=\"form-check-input\"\n type=\"radio\"\n name=\"capabilityGeneric{{ capabilityIndex }}Option\"\n id=\"capabilityGeneric{{ capabilityIndex }}Option{{ i }}\"\n [value]=\"capability\"\n />\n <label style=\"max-width: 200px\" class=\"form-check-label\" for=\"capabilityGeneric{{ capabilityIndex }}Option{{ i }}\">\n {{ 'designer.fixtureCapabilityType.' + capability.capability.type | translate\n }}<span *ngIf=\"getDescription(capability)\"> ({{ getDescription(capability) }})</span\n ><small\n ><div *ngFor=\"let color of capability.capability.colors\" class=\"color\" [style.background-color]=\"color\"></div>\n <small *ngIf=\"getDescriptionStart(capability)\">\n ({{ getDescriptionStart(capability) }} to {{ getDescriptionEnd(capability) }})</small\n >\n <span *ngIf=\"capability.capability.comment\"> - </span> {{ capability.capability.comment }}</small\n >\n <i\n *ngIf=\"capability.capability.soundControlled\"\n class=\"fa fa-microphone pl-1\"\n popover=\"{{ 'designer.fixture.capability-sound-controlled' | translate }}\"\n container=\"body\"\n placement=\"top\"\n triggers=\"mouseenter:mouseleave\"\n aria-hidden=\"true\"\n ></i>\n <i\n *ngIf=\"capability.capability.randomTiming\"\n class=\"fa fa-random pl-1\"\n popover=\"{{ 'designer.fixture.capability-random-timing' | translate }}\"\n container=\"body\"\n placement=\"top\"\n triggers=\"mouseenter:mouseleave\"\n aria-hidden=\"true\"\n ></i>\n </label>\n </div>\n </div>\n\n <!-- display a slider to select the value for the currently selected capability, if it has a range -->\n <div\n *ngIf=\"hasRange\"\n class=\"col col-auto d-flex mx-auto\"\n [class.pl-0]=\"_channel.capabilities?.length > 1\"\n style=\"flex-direction: column\"\n >\n <div class=\"mb-2 w-100 d-flex\">\n <input\n #sliderValue\n class=\"mx-auto\"\n type=\"text\"\n [ngModel]=\"templateValue\"\n (ngModelChange)=\"setValue($event)\"\n style=\"width: 45px; height: 20px; text-align: center; font-size: 12px; font-family: monospace\"\n />\n </div>\n\n <div class=\"mx-auto mb-2\">{{ descriptionEnd }}</div>\n\n <div class=\"h-100 w-100 d-flex\">\n <mv-slider\n #slider\n class=\"mx-auto\"\n [value]=\"templateValue\"\n (change)=\"setValue($event.newValue)\"\n [orientation]=\"'vertical'\"\n [reversed]=\"true\"\n style=\"height: 100%\"\n [tooltip]=\"'hide'\"\n [min]=\"rangeMin\"\n [max]=\"rangeMax\"\n [step]=\"1\"\n ></mv-slider>\n </div>\n\n <div class=\"mx-auto mt-2\">{{ descriptionStart }}</div>\n </div>\n </div>\n </div>\n</div>\n", styles: [".color{display:inline-block;margin-left:5px;border-radius:50%;width:12px;height:12px;border:1px white solid;vertical-align:middle}\n"] }]
10176
10352
  }], () => [{ type: PresetService }], { sliderValue: [{
10177
10353
  type: ViewChild,
10178
10354
  args: ['sliderValue', { static: false }]