diff --git a/css/style.css b/css/style.css
index 50428da5..67954475 100644
--- a/css/style.css
+++ b/css/style.css
@@ -177,6 +177,71 @@ body {
overflow: hidden;
}
+/**
+ * Layers container
+ */
+.layers-container {
+ border : 1px solid #444;
+ font-size : medium;
+ color: white;
+ text-align: left;
+}
+
+.layers-title {
+ padding : 10px;
+ margin: 0;
+ font-size : 18px;
+}
+
+.layers-list {
+ font-size : 12px;
+ border-bottom: 1px solid #444;
+}
+
+.layer-item {
+ height:24px;
+ line-height: 24px;
+ padding : 0 10px;
+ border-top: 1px solid #444;
+ cursor : pointer;
+}
+
+.layer-item:hover {
+ background : #222;
+}
+
+.current-layer-item, .current-layer-item:hover {
+ background : #333;
+ font-weight: bold;
+}
+
+.layers-button-container {
+ padding: 10px;
+}
+
+.layers-button {
+ line-height: 24px;
+ padding: 0 10px;
+ display: inline-block;
+ border: none;
+ border-top: 1px solid #666;
+ border-bottom: 1px solid #222;
+ border-radius: 3px;
+ background-color: #3f3f3f;
+ cursor: pointer;
+ color: white;
+ font-size: 0.7em;
+ font-weight: bold;
+ text-align: center;
+ text-decoration: none;
+ text-shadow: 0px -1px 0 #000;
+ transition: background-color 0.2s linear;
+}
+
+.layers-button:hover {
+ text-decoration: none;
+ background-color: #484848;
+}
/**
* User messages
*/
diff --git a/index.html b/index.html
index 3035a2cc..f6d4b427 100644
--- a/index.html
+++ b/index.html
@@ -36,6 +36,7 @@
+
diff --git a/js/app.js b/js/app.js
index fb09f694..3919d508 100644
--- a/js/app.js
+++ b/js/app.js
@@ -29,6 +29,9 @@
this.previewsController = new pskl.controller.PreviewFilmController(this.piskelController, $('#preview-list'));
this.previewsController.init();
+
+ this.layersController = new pskl.controller.LayersController(this.piskelController);
+ this.layersController.init();
this.settingsController = new pskl.controller.SettingsController(this.piskelController);
this.settingsController.init();
diff --git a/js/controller/LayersController.js b/js/controller/LayersController.js
new file mode 100644
index 00000000..275b674c
--- /dev/null
+++ b/js/controller/LayersController.js
@@ -0,0 +1,59 @@
+(function () {
+ var ns = $.namespace('pskl.controller');
+
+ ns.LayersController = function (piskelController) {
+ this.piskelController = piskelController;
+ };
+
+ ns.LayersController.prototype.init = function () {
+ this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template');
+ this.rootEl = document.querySelectorAll('.layers-container')[0];
+ this.layersListEl = document.querySelectorAll('.layers-list')[0];
+
+ this.rootEl.addEventListener('click', this.onClick_.bind(this));
+
+ $.subscribe(Events.FRAMESHEET_RESET, this.renderLayerList_.bind(this));
+
+ this.renderLayerList_();
+ };
+
+ ns.LayersController.prototype.renderLayerList_ = function () {
+ this.layersListEl.innerHTML = '';
+ var layers = this.piskelController.getLayers();
+ layers.forEach(this.addLayerItem.bind(this));
+ };
+
+ ns.LayersController.prototype.addLayerItem = function (layer) {
+ var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, {
+ layername : layer.getName()
+ });
+ var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml);
+ if (this.piskelController.getCurrentLayer() === layer) {
+ layerItem.classList.add('current-layer-item');
+ }
+ this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild);
+ };
+
+ ns.LayersController.prototype.onClick_ = function (evt) {
+ var el = evt.target || evt.srcElement;
+ if (el.nodeName == 'BUTTON') {
+ this.onButtonClick_(el);
+ } else if (el.nodeName == 'LI') {
+ var layerName = el.getAttribute('data-layer-name');
+ this.piskelController.selectLayerByName(layerName);
+ }
+ };
+
+ ns.LayersController.prototype.onButtonClick_ = function (button) {
+ var action = button.getAttribute('data-action');
+ if (action == 'up') {
+ this.piskelController.moveLayerUp();
+ } else if (action == 'down') {
+ this.piskelController.moveLayerDown();
+ } else if (action == 'add') {
+ this.piskelController.createLayer();
+ } else if (action == 'delete') {
+ this.piskelController.removeCurrentLayer();
+ }
+ };
+})();
\ No newline at end of file
diff --git a/js/controller/PaletteController.js b/js/controller/PaletteController.js
index 813f8cb9..83e5100d 100644
--- a/js/controller/PaletteController.js
+++ b/js/controller/PaletteController.js
@@ -12,12 +12,10 @@
$.subscribe(Events.PRIMARY_COLOR_UPDATED, $.proxy(function(evt, color) {
this.updateColorPicker_(color, $('#color-picker'));
- this.addColorToPalette_(color);
}, this));
$.subscribe(Events.SECONDARY_COLOR_UPDATED, $.proxy(function(evt, color) {
this.updateColorPicker_(color, $('#secondary-color-picker'));
- this.addColorToPalette_(color);
}, this));
// Initialize colorpickers:
diff --git a/js/controller/PiskelController.js b/js/controller/PiskelController.js
index 6ad47e65..faa6fcbf 100644
--- a/js/controller/PiskelController.js
+++ b/js/controller/PiskelController.js
@@ -22,6 +22,10 @@
return this.piskel.getWidth();
};
+ ns.PiskelController.prototype.getLayers = function () {
+ return this.piskel.getLayers();
+ };
+
ns.PiskelController.prototype.getCurrentLayer = function () {
return this.piskel.getLayerAt(this.currentLayerIndex);
};
@@ -32,7 +36,7 @@
};
ns.PiskelController.prototype.getFrameAt = function (index) {
- var frames = this.piskel.getLayers().map(function (l) {
+ var frames = this.getLayers().map(function (l) {
return l.getFrameAt(index);
});
return pskl.utils.FrameUtils.merge(frames);
@@ -47,7 +51,7 @@
ns.PiskelController.prototype.getMergedFrameAt;
ns.PiskelController.prototype.addEmptyFrame = function () {
- var layers = this.piskel.getLayers();
+ var layers = this.getLayers();
layers.forEach(function (l) {
l.addFrame(this.createEmptyFrame_());
}.bind(this));
@@ -59,7 +63,7 @@
};
ns.PiskelController.prototype.removeFrameAt = function (index) {
- var layers = this.piskel.getLayers();
+ var layers = this.getLayers();
layers.forEach(function (l) {
l.removeFrameAt(index);
});
@@ -72,14 +76,14 @@
};
ns.PiskelController.prototype.duplicateFrameAt = function (index) {
- var layers = this.piskel.getLayers();
+ var layers = this.getLayers();
layers.forEach(function (l) {
l.duplicateFrameAt(index);
});
};
ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) {
- var layers = this.piskel.getLayers();
+ var layers = this.getLayers();
layers.forEach(function (l) {
l.moveFrame(fromIndex, toIndex);
});
@@ -100,13 +104,58 @@
$.publish(Events.FRAMESHEET_RESET);
};
- ns.PiskelController.prototype.createLayer = function (name) {
- var layer = new pskl.model.Layer(name);
- for (var i = 0 ; i < this.getFrameCount() ; i++) {
- layer.addFrame(this.createEmptyFrame_());
+ ns.PiskelController.prototype.selectLayer = function (layer) {
+ var index = this.getLayers().indexOf(layer);
+ if (index != -1) {
+ this.setCurrentLayerIndex(index);
+ }
+ };
+
+ ns.PiskelController.prototype.selectLayerByName = function (name) {
+ if (this.hasLayerForName_(name)) {
+ var layer = this.piskel.getLayersByName(name)[0];
+ this.selectLayer(layer);
+ }
+ };
+
+ ns.PiskelController.prototype.createLayer = function (name) {
+ if (!name) {
+ name = "Layer " + (this.getLayers().length + 1);
+ }
+ if (!this.hasLayerForName_(name)) {
+ var layer = new pskl.model.Layer(name);
+ for (var i = 0 ; i < this.getFrameCount() ; i++) {
+ layer.addFrame(this.createEmptyFrame_());
+ }
+ this.piskel.addLayer(layer);
+ this.setCurrentLayerIndex(this.piskel.getLayers().length - 1);
+ } else {
+ throw 'Layer name should be unique';
+ }
+ };
+
+ ns.PiskelController.prototype.hasLayerForName_ = function (name) {
+ return this.piskel.getLayersByName(name).length > 0;
+ };
+
+ ns.PiskelController.prototype.moveLayerUp = function () {
+ var layer = this.getCurrentLayer();
+ this.piskel.moveLayerUp(layer);
+ this.selectLayer(layer);
+ };
+
+ ns.PiskelController.prototype.moveLayerDown = function () {
+ var layer = this.getCurrentLayer();
+ this.piskel.moveLayerDown(layer);
+ this.selectLayer(layer);
+ };
+
+ ns.PiskelController.prototype.removeCurrentLayer = function () {
+ if (this.getLayers().length > 1) {
+ var layer = this.getCurrentLayer();
+ this.piskel.removeLayer(layer);
+ this.setCurrentLayerIndex(0);
}
- this.piskel.addLayer(layer);
- this.setCurrentLayerIndex(this.piskel.getLayers().length - 1);
};
ns.PiskelController.prototype.serialize = function () {
diff --git a/js/controller/SettingsController.js b/js/controller/SettingsController.js
index 853e4852..611eebf2 100644
--- a/js/controller/SettingsController.js
+++ b/js/controller/SettingsController.js
@@ -30,7 +30,7 @@
// Expand drawer when clicking 'Settings' tab.
$('[data-setting]').click(function(evt) {
var el = evt.originalEvent.currentTarget;
- var setting = el.dataset.setting;
+ var setting = el.getAttribute("data-setting");
if (this.currentSetting != setting) {
this.loadSetting(setting);
} else {
diff --git a/js/controller/settings/GifExportController.js b/js/controller/settings/GifExportController.js
index 42360c2e..8b77ad32 100644
--- a/js/controller/settings/GifExportController.js
+++ b/js/controller/settings/GifExportController.js
@@ -5,12 +5,14 @@
};
ns.GifExportController.prototype.init = function () {
- this.initRadioElements_();
+ this.radioTemplate_ = pskl.utils.Template.get("export-gif-radio-template");
this.previewContainer = document.querySelectorAll(".export-gif-preview div")[0];
- this.uploadForm = $("[name=gif-export-upload-form]");
+ this.uploadForm = $("[name=gif-export-upload-form]");
this.uploadForm.submit(this.upload.bind(this));
+
+ this.initRadioElements_();
};
ns.GifExportController.prototype.upload = function (evt) {
@@ -52,18 +54,17 @@
[10,true] //default
];
- var radioTpl = $("#export-gif-radio-template").get(0);
for (var i = 0 ; i < dpis.length ; i++) {
var dpi = dpis[i];
- var radio = this.createRadioForDpi_(dpi, radioTpl.innerHTML);
- radioTpl.parentNode.insertBefore(radio, radioTpl);
+ var radio = this.createRadioForDpi_(dpi);
+ this.uploadForm.get(0).appendChild(radio);
}
};
- ns.GifExportController.prototype.createRadioForDpi_ = function (dpi, template) {
+ ns.GifExportController.prototype.createRadioForDpi_ = function (dpi) {
var label = dpi[0]*this.piskelController.getWidth() + "x" + dpi[0]*this.piskelController.getHeight();
var value = dpi[0];
- var radioHTML = pskl.utils.Template.replace(template, {value : value, label : label});
+ var radioHTML = pskl.utils.Template.replace(this.radioTemplate_, {value : value, label : label});
var radio = pskl.utils.Template.createFromHTML(radioHTML);
if (dpi[1]) {
diff --git a/js/model/Piskel.js b/js/model/Piskel.js
index 635a6ed7..5ca4b28f 100644
--- a/js/model/Piskel.js
+++ b/js/model/Piskel.js
@@ -48,10 +48,32 @@
return this.layers[index];
};
+ ns.Piskel.prototype.getLayersByName = function (name) {
+ return this.layers.filter(function (l) {
+ return l.getName() == name;
+ });
+ };
+
ns.Piskel.prototype.addLayer = function (layer) {
this.layers.push(layer);
};
+ ns.Piskel.prototype.moveLayerUp = function (layer) {
+ var index = this.layers.indexOf(layer);
+ if (index > -1 && index < this.layers.length-1) {
+ this.layers[index] = this.layers[index+1];
+ this.layers[index+1] = layer;
+ }
+ };
+
+ ns.Piskel.prototype.moveLayerDown = function (layer) {
+ var index = this.layers.indexOf(layer);
+ if (index > 0) {
+ this.layers[index] = this.layers[index-1];
+ this.layers[index-1] = layer;
+ }
+ };
+
ns.Piskel.prototype.removeLayer = function (layer) {
var index = this.layers.indexOf(layer);
if (index != -1) {
diff --git a/piskel-script-list.js b/piskel-script-list.js
index 35eba20a..c59f13f0 100644
--- a/piskel-script-list.js
+++ b/piskel-script-list.js
@@ -44,6 +44,7 @@ exports.scripts = [
"js/controller/PiskelController.js",
"js/controller/DrawingController.js",
"js/controller/PreviewFilmController.js",
+ "js/controller/LayersController.js",
"js/controller/AnimatedPreviewController.js",
"js/controller/ToolController.js",
"js/controller/PaletteController.js",
diff --git a/templates/layers.html b/templates/layers.html
new file mode 100644
index 00000000..63ddf0a7
--- /dev/null
+++ b/templates/layers.html
@@ -0,0 +1,13 @@
+
+
Layers
+
+
+
+
+
+
+
+
+