From 73cb82319907b568febc5b74c5c91346e0506329 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Mon, 15 May 2017 08:30:02 -0400 Subject: [PATCH 1/6] Add delete costume and sound functions to the vm public api --- src/virtual-machine.js | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/src/virtual-machine.js b/src/virtual-machine.js index cf4d0e636..a0da9b22f 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -286,6 +286,20 @@ 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.sprite.costumes = this.editingTarget.sprite.costumes + .slice(0, costumeIndex) + .concat(this.editingTarget.sprite.costumes.slice(costumeIndex + 1)); + if (costumeIndex === this.editingTarget.currentCostume) { + this.editingTarget.setCostume(costumeIndex - 1); + } + this.emitTargetsUpdate(); + } + /** * Add a sound to the current editing target. * @param {!object} soundObject Object representing the costume. @@ -298,6 +312,17 @@ 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.sprite.sounds = this.editingTarget.sprite.sounds + .slice(0, soundIndex) + .concat(this.editingTarget.sprite.sounds.slice(soundIndex + 1)); + this.emitTargetsUpdate(); + } + /** * Add a backdrop to the stage. * @param {string} md5ext - the MD5 and extension of the backdrop to be loaded. From 71081502fe4be6fd8abdb7caadab8eeeba984d5c Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Mon, 15 May 2017 08:32:55 -0400 Subject: [PATCH 2/6] Add to the vm spec --- test/unit/spec.js | 2 ++ 1 file changed, 2 insertions(+) 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'); From a608ca4fed76e3b3f2382a22ba957bc349d9f226 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Tue, 16 May 2017 11:01:50 -0400 Subject: [PATCH 3/6] Make rendered targets in charge of deleting their own sounds and costumes --- src/sprites/rendered-target.js | 33 ++++++++++++++ src/virtual-machine.js | 13 +----- test/unit/sprites_rendered-target.js | 65 ++++++++++++++++++++++++++++ 3 files changed, 100 insertions(+), 11 deletions(-) diff --git a/src/sprites/rendered-target.js b/src/sprites/rendered-target.js index 8489b37cb..752debaf6 100644 --- a/src/sprites/rendered-target.js +++ b/src/sprites/rendered-target.js @@ -389,6 +389,39 @@ 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 === originalCostumeCount - 1) { + this.setCostume(index - 1); + } else { + this.setCostume(index); + } + + this.runtime.requestTargetsUpdate(this); + } + + /** + * Delete a sound by index. + * @param {number} index Sound index to be deleted + */ + deleteSound (index) { + if (this.sprite.sounds.length === 1) return; + 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 a0da9b22f..fef841a6a 100644 --- a/src/virtual-machine.js +++ b/src/virtual-machine.js @@ -291,13 +291,7 @@ class VirtualMachine extends EventEmitter { * @param {int} costumeIndex - the index of the costume to be removed. */ deleteCostume (costumeIndex) { - this.editingTarget.sprite.costumes = this.editingTarget.sprite.costumes - .slice(0, costumeIndex) - .concat(this.editingTarget.sprite.costumes.slice(costumeIndex + 1)); - if (costumeIndex === this.editingTarget.currentCostume) { - this.editingTarget.setCostume(costumeIndex - 1); - } - this.emitTargetsUpdate(); + this.editingTarget.deleteCostume(costumeIndex); } /** @@ -317,10 +311,7 @@ class VirtualMachine extends EventEmitter { * @param {int} soundIndex - the index of the sound to be removed. */ deleteSound (soundIndex) { - this.editingTarget.sprite.sounds = this.editingTarget.sprite.sounds - .slice(0, soundIndex) - .concat(this.editingTarget.sprite.sounds.slice(soundIndex + 1)); - this.emitTargetsUpdate(); + this.editingTarget.deleteSound(soundIndex); } /** diff --git a/test/unit/sprites_rendered-target.js b/test/unit/sprites_rendered-target.js index 3f8ee2c37..f564bfd3e 100644 --- a/test/unit/sprites_rendered-target.js +++ b/test/unit/sprites_rendered-target.js @@ -98,6 +98,71 @@ test('setCostume', t => { t.end(); }); +test('deleteCostume', t => { + const o1 = {id: 1}; + const o2 = {id: 2}; + const o3 = {id: 3}; + + 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; + + // Deleting costume keeps costume index at 0 + a.setCostume(0); + a.deleteCostume(0); + t.deepEqual(a.sprite.costumes, [o2, o3]); + t.equals(a.currentCostume, 0); + + // Deleting a costume in the middle maintains current costume index + a.sprite.costumes = [o1, o2, o3]; + a.setCostume(1); + a.deleteCostume(1); + t.deepEqual(a.sprite.costumes, [o1, o3]); + t.equals(a.currentCostume, 1); + + // Deleting last costume selects previous costume + 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); + + 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]); + + // Refuses to delete only sound + a.sprite.sounds = [o1]; + a.deleteSound(0); + t.deepEqual(a.sprite.sounds, [o1]); + + t.end(); +}); + test('setRotationStyle', t => { const s = new Sprite(); const r = new Runtime(); From 30a0c0d251a917166ff2f6d7bd6e55128daa5112 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Thu, 18 May 2017 13:29:44 -0400 Subject: [PATCH 4/6] Allow deleting the last sound --- src/sprites/rendered-target.js | 1 - test/unit/sprites_rendered-target.js | 4 ++-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/src/sprites/rendered-target.js b/src/sprites/rendered-target.js index 752debaf6..1e7ff9a2e 100644 --- a/src/sprites/rendered-target.js +++ b/src/sprites/rendered-target.js @@ -415,7 +415,6 @@ class RenderedTarget extends Target { * @param {number} index Sound index to be deleted */ deleteSound (index) { - if (this.sprite.sounds.length === 1) return; this.sprite.sounds = this.sprite.sounds .slice(0, index) .concat(this.sprite.sounds.slice(index + 1)); diff --git a/test/unit/sprites_rendered-target.js b/test/unit/sprites_rendered-target.js index f564bfd3e..5e7f881b1 100644 --- a/test/unit/sprites_rendered-target.js +++ b/test/unit/sprites_rendered-target.js @@ -155,10 +155,10 @@ test('deleteSound', t => { a.deleteSound(0); t.deepEqual(a.sprite.sounds, [o2, o3]); - // Refuses to delete only sound + // Allows deleting the only sound a.sprite.sounds = [o1]; a.deleteSound(0); - t.deepEqual(a.sprite.sounds, [o1]); + t.deepEqual(a.sprite.sounds, []); t.end(); }); From 423da12c3c2a176d2d7573d147c32f8f59b86bf4 Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Thu, 18 May 2017 13:56:14 -0400 Subject: [PATCH 5/6] Handle more cases of deleting costumes --- src/sprites/rendered-target.js | 6 ++-- test/unit/sprites_rendered-target.js | 46 ++++++++++++++++++++++++++-- 2 files changed, 46 insertions(+), 6 deletions(-) diff --git a/src/sprites/rendered-target.js b/src/sprites/rendered-target.js index 1e7ff9a2e..06528ece0 100644 --- a/src/sprites/rendered-target.js +++ b/src/sprites/rendered-target.js @@ -401,10 +401,10 @@ class RenderedTarget extends Target { .slice(0, index) .concat(this.sprite.costumes.slice(index + 1)); - if (index === originalCostumeCount - 1) { + if (index === this.currentCostume && index === originalCostumeCount - 1) { this.setCostume(index - 1); - } else { - this.setCostume(index); + } else if (index < this.currentCostume) { + this.setCostume(this.currentCostume - 1); } this.runtime.requestTargetsUpdate(this); diff --git a/test/unit/sprites_rendered-target.js b/test/unit/sprites_rendered-target.js index 5e7f881b1..ecb4a0899 100644 --- a/test/unit/sprites_rendered-target.js +++ b/test/unit/sprites_rendered-target.js @@ -102,6 +102,8 @@ 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(); @@ -110,20 +112,26 @@ test('deleteCostume', t => { const renderer = new FakeRenderer(); a.renderer = renderer; - // Deleting costume keeps costume index at 0 + // 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); - // Deleting a costume in the middle maintains current costume index + // 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); - // Deleting last costume selects previous costume + // Costume 1 Costume 1 + // Costume 2 => * Costume 2 + // x* Costume 3 a.sprite.costumes = [o1, o2, o3]; a.setCostume(2); a.deleteCostume(2); @@ -137,6 +145,38 @@ test('deleteCostume', t => { 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(); }); From 3eaec99e51fd87bad4dba2dfdeb99b293666bf3e Mon Sep 17 00:00:00 2001 From: Paul Kaplan Date: Mon, 22 May 2017 08:14:13 -0400 Subject: [PATCH 6/6] Always activate the current costume after deleting --- src/sprites/rendered-target.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/sprites/rendered-target.js b/src/sprites/rendered-target.js index 06528ece0..0bc5cff6e 100644 --- a/src/sprites/rendered-target.js +++ b/src/sprites/rendered-target.js @@ -405,6 +405,8 @@ class RenderedTarget extends Target { this.setCostume(index - 1); } else if (index < this.currentCostume) { this.setCostume(this.currentCostume - 1); + } else { + this.setCostume(this.currentCostume); } this.runtime.requestTargetsUpdate(this);