diff --git a/src/sprites/rendered-target.js b/src/sprites/rendered-target.js index 8489b37cb..0bc5cff6e 100644 --- a/src/sprites/rendered-target.js +++ b/src/sprites/rendered-target.js @@ -389,6 +389,40 @@ class RenderedTarget extends Target { this.runtime.requestTargetsUpdate(this); } + /** + * Delete a costume by index. + * @param {number} index Costume index to be deleted + */ + deleteCostume (index) { + const originalCostumeCount = this.sprite.costumes.length; + if (originalCostumeCount === 1) return; + + this.sprite.costumes = this.sprite.costumes + .slice(0, index) + .concat(this.sprite.costumes.slice(index + 1)); + + if (index === this.currentCostume && index === originalCostumeCount - 1) { + this.setCostume(index - 1); + } else if (index < this.currentCostume) { + this.setCostume(this.currentCostume - 1); + } else { + this.setCostume(this.currentCostume); + } + + this.runtime.requestTargetsUpdate(this); + } + + /** + * Delete a sound by index. + * @param {number} index Sound index to be deleted + */ + deleteSound (index) { + this.sprite.sounds = this.sprite.sounds + .slice(0, index) + .concat(this.sprite.sounds.slice(index + 1)); + this.runtime.requestTargetsUpdate(this); + } + /** * Update the rotation style. * @param {!string} rotationStyle New rotation style. diff --git a/src/virtual-machine.js b/src/virtual-machine.js index cf4d0e636..fef841a6a 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -286,6 +286,14 @@ class VirtualMachine extends EventEmitter { }); } + /** + * Delete a costume from the current editing target. + * @param {int} costumeIndex - the index of the costume to be removed. + */ + deleteCostume (costumeIndex) { + this.editingTarget.deleteCostume(costumeIndex); + } + /** * Add a sound to the current editing target. * @param {!object} soundObject Object representing the costume. @@ -298,6 +306,14 @@ class VirtualMachine extends EventEmitter { }); } + /** + * Delete a sound from the current editing target. + * @param {int} soundIndex - the index of the sound to be removed. + */ + deleteSound (soundIndex) { + this.editingTarget.deleteSound(soundIndex); + } + /** * Add a backdrop to the stage. * @param {string} md5ext - the MD5 and extension of the backdrop to be loaded. diff --git a/test/unit/spec.js b/test/unit/spec.js index 7e2115567..48b0fd6ae 100644 --- a/test/unit/spec.js +++ b/test/unit/spec.js @@ -19,6 +19,8 @@ test('interface', t => { t.type(vm.addCostume, 'function'); t.type(vm.addBackdrop, 'function'); t.type(vm.addSound, 'function'); + t.type(vm.deleteCostume, 'function'); + t.type(vm.deleteSound, 'function'); t.type(vm.renameSprite, 'function'); t.type(vm.deleteSprite, 'function'); diff --git a/test/unit/sprites_rendered-target.js b/test/unit/sprites_rendered-target.js index 3f8ee2c37..ecb4a0899 100644 --- a/test/unit/sprites_rendered-target.js +++ b/test/unit/sprites_rendered-target.js @@ -98,6 +98,111 @@ test('setCostume', t => { t.end(); }); +test('deleteCostume', t => { + const o1 = {id: 1}; + const o2 = {id: 2}; + const o3 = {id: 3}; + const o4 = {id: 4}; + const o5 = {id: 5}; + + const s = new Sprite(); + const r = new Runtime(); + s.costumes = [o1, o2, o3]; + const a = new RenderedTarget(s, r); + const renderer = new FakeRenderer(); + a.renderer = renderer; + + // x* Costume 1 * Costume 2 + // Costume 2 => Costume 3 + // Costume 3 + a.setCostume(0); + a.deleteCostume(0); + t.deepEqual(a.sprite.costumes, [o2, o3]); + t.equals(a.currentCostume, 0); + + // Costume 1 Costume 1 + // x* Costume 2 => * Costume 3 + // Costume 3 + a.sprite.costumes = [o1, o2, o3]; + a.setCostume(1); + a.deleteCostume(1); + t.deepEqual(a.sprite.costumes, [o1, o3]); + t.equals(a.currentCostume, 1); + + // Costume 1 Costume 1 + // Costume 2 => * Costume 2 + // x* Costume 3 + a.sprite.costumes = [o1, o2, o3]; + a.setCostume(2); + a.deleteCostume(2); + t.deepEqual(a.sprite.costumes, [o1, o2]); + t.equals(a.currentCostume, 1); + + // Refuses to delete only costume + a.sprite.costumes = [o1]; + a.setCostume(0); + a.deleteCostume(0); + t.deepEqual(a.sprite.costumes, [o1]); + t.equals(a.currentCostume, 0); + + // Costume 1 Costume 1 + // x Costume 2 Costume 3 + // Costume 3 => * Costume 4 + // * Costume 4 Costume 5 + // Costume 5 + a.sprite.costumes = [o1, o2, o3, o4, o5]; + a.setCostume(3); + a.deleteCostume(1); + t.deepEqual(a.sprite.costumes, [o1, o3, o4, o5]); + t.equals(a.currentCostume, 2); + + // Costume 1 Costume 1 + // * Costume 2 * Costume 2 + // Costume 3 => Costume 3 + // x Costume 4 Costume 5 + // Costume 5 + a.sprite.costumes = [o1, o2, o3, o4, o5]; + a.setCostume(1); + a.deleteCostume(3); + t.deepEqual(a.sprite.costumes, [o1, o2, o3, o5]); + t.equals(a.currentCostume, 1); + + // Costume 1 Costume 1 + // * Costume 2 * Costume 2 + // Costume 3 => Costume 3 + // Costume 4 Costume 4 + // x Costume 5 + a.sprite.costumes = [o1, o2, o3, o4, o5]; + a.setCostume(1); + a.deleteCostume(4); + t.deepEqual(a.sprite.costumes, [o1, o2, o3, o4]); + t.equals(a.currentCostume, 1); + t.end(); +}); + +test('deleteSound', t => { + const o1 = {id: 1}; + const o2 = {id: 2}; + const o3 = {id: 3}; + + const s = new Sprite(); + const r = new Runtime(); + s.sounds = [o1, o2, o3]; + const a = new RenderedTarget(s, r); + const renderer = new FakeRenderer(); + a.renderer = renderer; + + a.deleteSound(0); + t.deepEqual(a.sprite.sounds, [o2, o3]); + + // Allows deleting the only sound + a.sprite.sounds = [o1]; + a.deleteSound(0); + t.deepEqual(a.sprite.sounds, []); + + t.end(); +}); + test('setRotationStyle', t => { const s = new Sprite(); const r = new Runtime();