diff --git a/src/components/options-panel/components/layers/layers.vue b/src/components/options-panel/components/layers/layers.vue
index ea005ac..64d16af 100644
--- a/src/components/options-panel/components/layers/layers.vue
+++ b/src/components/options-panel/components/layers/layers.vue
@@ -31,8 +31,28 @@
:class="{
'active': layer.index === activeLayerIndex
}"
- @click="setActiveLayerIndex( layer.index )"
- >{{ layer.name }}
+ >
+ {{ layer.name }}
+
+ ×
+
-
@@ -73,6 +86,7 @@ export default {
"activeDocument",
"activeLayer",
"activeLayerIndex",
+ "activeLayerMask",
"layers",
]),
reverseLayers() {
@@ -88,6 +102,7 @@ export default {
"removeLayer",
"updateLayer",
"setActiveLayerIndex",
+ "setActiveLayerMask",
"addMaskToActiveLayer",
]),
requestLayerAdd() {
@@ -101,8 +116,8 @@ export default {
}
});
},
- requestLayerRemove() {
- this.removeLayer( this.activeLayer );
+ requestLayerRemove( index ) {
+ this.removeLayer( index );
},
},
};
@@ -131,16 +146,28 @@ h3 {
padding: 0 $spacing-xsmall;
@include boxSize();
@include customFont();
+ display: flex;
&:hover,
&.active {
background-color: $color-1;
- color: #FFF;
+ color: #000;
}
&.active {
padding: $spacing-xsmall $spacing-xsmall;
border: none;
}
+
+ .name {
+ flex: 3;
+ @include truncate();
+ }
+ .mask {
+ flex: 1;
+ }
+ .highlight {
+ color: #FFF;
+ }
}
.actions {
diff --git a/src/components/options-panel/components/layers/messages.json b/src/components/options-panel/components/layers/messages.json
index a2d4038..66d3b18 100644
--- a/src/components/options-panel/components/layers/messages.json
+++ b/src/components/options-panel/components/layers/messages.json
@@ -3,6 +3,6 @@
"layers": "Layers",
"addLayer": "Add layer",
"addMask": "Add mask",
- "removeLayer": "Remove layer"
+ "mask": "Mask"
}
}
diff --git a/src/components/ui/zcanvas/layer-sprite.js b/src/components/ui/zcanvas/layer-sprite.js
index 35b7af8..a3b1d6a 100644
--- a/src/components/ui/zcanvas/layer-sprite.js
+++ b/src/components/ui/zcanvas/layer-sprite.js
@@ -22,7 +22,7 @@
*/
import { sprite } from "zcanvas";
import { createCanvas } from "@/utils/canvas-util";
-import { LAYER_GRAPHIC, LAYER_MASK } from "@/definitions/layer-types";
+import { LAYER_GRAPHIC, LAYER_MASK } from "@/definitions/layer-types";
class LayerSprite extends sprite {
constructor( layer ) {
@@ -38,7 +38,7 @@ class LayerSprite extends sprite {
super({ bitmap, x, y, width, height } );
this.setDraggable( true );
- this._layer = layer;
+ this.layer = layer;
// create brush (always as all layers can be maskable)
const brushCanvas = createCanvas();
@@ -50,11 +50,11 @@ class LayerSprite extends sprite {
}
isDrawable() {
- return this._layer.type === LAYER_GRAPHIC || this.isMaskable();
+ return this.layer.type === LAYER_GRAPHIC || this.isMaskable();
}
isMaskable() {
- return !!this._layer.mask;
+ return !!this.layer.mask;
}
cacheGradient( color, radius = 30 ) {
@@ -70,7 +70,7 @@ class LayerSprite extends sprite {
const gradient = this._brushCtx.createRadialGradient( x, y, innerRadius, x, y, outerRadius );
gradient.addColorStop( 0, color );
- gradient.addColorStop( 1, 'rgba(255,255,255,0)' );
+ gradient.addColorStop( 1, "rgba(255,255,255,0)" );
this._brushCtx.clearRect( 0, 0, this._brushCvs.width, this._brushCvs.height );
this._brushCtx.arc( x, y, radius, 0, 2 * Math.PI );
@@ -83,10 +83,11 @@ class LayerSprite extends sprite {
// overridden from zCanvas.sprite
handleMove( x, y ) {
if ( !this.isDrawable() ) {
+ // not drawable, perform default behaviour (drag)
return super.handleMove( x, y );
}
- // cache this upfront
- const ctx = this.isMaskable() ? this._layer.mask.getContext( "2d" ) : this._bitmap.getContext( "2d" );
+ // get the drawing context, cache this upfront
+ const ctx = this.isMaskable() ? this.layer.mask.getContext( "2d" ) : this._bitmap.getContext( "2d" );
// note we draw onto the layer bitmap to make this permanent
ctx.drawImage( this._brushCvs, x - this._halfRadius, y - this._halfRadius );
}
diff --git a/src/store/modules/document-module.js b/src/store/modules/document-module.js
index a2df301..0c9670f 100644
--- a/src/store/modules/document-module.js
+++ b/src/store/modules/document-module.js
@@ -31,13 +31,15 @@ export default {
documents : [], // opened documents
activeIndex: 0, // the currently active document
activeLayerIndex: 0, // the currently active layer within the currently active document
+ maskActive: false,
},
getters: {
documents: state => state.documents,
activeDocument: state => state.documents[ state.activeIndex ],
layers: ( state, getters ) => getters.activeDocument?.layers,
- activeLayer: ( state, getters ) => getters.layers?.[ state.activeLayerIndex ],
activeLayerIndex: state => state.activeLayerIndex,
+ activeLayer: ( state, getters ) => getters.layers?.[ state.activeLayerIndex ],
+ activeLayerMask: ( state, getters ) => ( state.maskActive && getters.activeLayer.mask ) || null,
},
mutations: {
setActiveDocument( state, index ) {
@@ -76,9 +78,9 @@ export default {
layers.push( LayerFactory.create( opts ) );
state.activeLayerIndex = layers.length - 1;
},
- removeLayer( state, layer ) {
- const index = state.documents[ state.activeIndex ]?.layers.indexOf( layer );
- if ( index < 0 ) {
+ removeLayer( state, index ) {
+ const layer = state.documents[ state.activeIndex ]?.layers[ index ];
+ if ( !layer ) {
return;
}
flushLayerSprites( layer );
@@ -87,8 +89,13 @@ export default {
state.activeLayerIndex = Math.max( 0, index - 1 );
}
},
- setActiveLayerIndex( state, index ) {
- state.activeLayerIndex = index;
+ setActiveLayerIndex( state, layerIndex ) {
+ state.activeLayerIndex = layerIndex;
+ state.maskActive = false;
+ },
+ setActiveLayerMask( state, layerIndex ) {
+ state.activeLayerIndex = layerIndex;
+ state.maskActive = !!state.documents[ state.activeIndex ].layers[ layerIndex ].mask;
},
updateLayer( state, { index, opts = {} }) {
const layer = state.documents[ state.activeIndex ].layers[ index ];
diff --git a/tests/unit/store/modules/document-module.spec.js b/tests/unit/store/modules/document-module.spec.js
index 3a6e22e..cc2f724 100644
--- a/tests/unit/store/modules/document-module.spec.js
+++ b/tests/unit/store/modules/document-module.spec.js
@@ -37,6 +37,11 @@ describe( "Vuex document module", () => {
expect( getters.layers( state, mockedGetters )).toEqual( mockedGetters.activeDocument.layers );
});
+ it( "should be able to retrieve the active Layer index", () => {
+ const state = { activeLayerIndex: 2 };
+ expect( getters.activeLayerIndex( state )).toEqual( 2 );
+ });
+
it( "should be able to retrieve the active Layer for the active Document", () => {
const state = { activeLayerIndex: 1 };
const mockedGetters = {
@@ -45,9 +50,16 @@ describe( "Vuex document module", () => {
expect( getters.activeLayer( state, mockedGetters )).toEqual( mockedGetters.layers[ 1 ]);
});
- it( "should be able to retrieve the active Layer index", () => {
- const state = { activeLayerIndex: 2 };
- expect( getters.activeLayerIndex( state )).toEqual( 2 );
+ it( "should be able to retrieve the active Layer mask, when set", () => {
+ const state = { maskActive: false };
+ const mockedGetters = { activeLayer: { name: "layer1" } };
+ // null because mask is not active
+ expect( getters.activeLayerMask( state, mockedGetters )).toBeNull();
+ state.maskActive = true;
+ // null because layer has no mask drawable
+ expect( getters.activeLayerMask( state, mockedGetters )).toBeNull();
+ mockedGetters.activeLayer.mask = { src: "mask" };
+ expect( getters.activeLayerMask( state, mockedGetters )).toEqual( mockedGetters.activeLayer.mask );
});
});
@@ -151,7 +163,7 @@ describe( "Vuex document module", () => {
};
mockUpdateFn = jest.fn();
const layer = state.documents[ 0 ].layers[ 1 ];
- mutations.removeLayer( state, layer );
+ mutations.removeLayer( state, 1 );
expect( state.documents[ 0 ].layers ).toEqual([
{ name: "layer1" }, { name: "layer3" }
]);
@@ -160,13 +172,40 @@ describe( "Vuex document module", () => {
});
});
- it( "should be able to set the active layer index", () => {
- const state = {
- documents: [ { name: "foo", layers: [{ name: "layer1" }, { name: "layer2" }] }],
- activeLayerIndex: 0
- };
- mutations.setActiveLayerIndex( state, 1 );
- expect( state.activeLayerIndex ).toEqual( 1 );
+ describe( "when setting the active layer content", () => {
+ it( "should be able to set the active layer index", () => {
+ const state = {
+ documents: [ { name: "foo", layers: [{ name: "layer1" }, { name: "layer2" }] }],
+ activeLayerIndex: 0
+ };
+ mutations.setActiveLayerIndex( state, 1 );
+ expect( state.activeLayerIndex ).toEqual( 1 );
+ });
+
+ it( "should unset the active layer mask when setting the active layer index", () => {
+ const state = {
+ documents: [ { name: "foo", layers: [{ name: "layer1" }, { name: "layer2" }] }],
+ activeLayerIndex: 0,
+ maskActive: true,
+ };
+ mutations.setActiveLayerIndex( state, 1 );
+ expect( state.maskActive ).toBe( false );
+ });
+
+ it( "should be able to set the active layer mask", () => {
+ const state = {
+ documents: [{
+ name: "foo",
+ layers: [ { name: "layer1" }, { name: "layer2", mask: { src: "mask" } } ]
+ }],
+ activeIndex: 0,
+ activeLayerIndex: 0,
+ maskActive: false,
+ };
+ mutations.setActiveLayerMask( state, 1 );
+ expect( state.activeLayerIndex ).toEqual( 1 );
+ expect( state.maskActive ).toBe( true );
+ });
});
it( "should be able to update the options of a specific layer within the active Document", () => {