From 073f46b0d76c4f5eafcdbe251e998a06a0c85e07 Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 30 Aug 2014 18:39:54 +0200 Subject: [PATCH 01/32] starting palette implementation using creation wizard --- src/css/dialogs-create-palette.css | 21 +++++++++++++ src/css/toolbox-palettes-list.css | 3 +- src/index.html | 2 +- src/js/controller/PalettesListController.js | 21 ++++++------- .../dialogs/CreatePaletteController.js | 12 ++++++++ .../controller/dialogs/DialogsController.js | 4 +++ src/piskel-script-list.js | 2 ++ src/piskel-style-list.js | 1 + src/templates/dialogs/create-palette.html | 30 +++++++++++++++++++ src/templates/palettes-list.html | 22 +++++++++----- 10 files changed, 95 insertions(+), 23 deletions(-) create mode 100644 src/css/dialogs-create-palette.css create mode 100644 src/js/controller/dialogs/CreatePaletteController.js create mode 100644 src/templates/dialogs/create-palette.html diff --git a/src/css/dialogs-create-palette.css b/src/css/dialogs-create-palette.css new file mode 100644 index 00000000..62e1af74 --- /dev/null +++ b/src/css/dialogs-create-palette.css @@ -0,0 +1,21 @@ +#dialog-container.create-palette { + width: 500px; + height: 200px; + top : 50%; + left : 50%; + position : absolute; + margin-left: -250px; +} + +.show #dialog-container.create-palette { + margin-top: -100px; +} + +.create-palette-method-item { + line-height : 24px; +} + +.create-palette-method-item label{ + margin-top: 3px; + margin-left: 5px; +} \ No newline at end of file diff --git a/src/css/toolbox-palettes-list.css b/src/css/toolbox-palettes-list.css index 2d8aa477..10799c35 100644 --- a/src/css/toolbox-palettes-list.css +++ b/src/css/toolbox-palettes-list.css @@ -1,6 +1,5 @@ .palettes-list-select { - float:right; - max-width:90px; + max-width:120px; margin-top: 3px; } diff --git a/src/index.html b/src/index.html index 468cb0a0..969a082e 100644 --- a/src/index.html +++ b/src/index.html @@ -67,7 +67,7 @@
- +
diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 0901d3df..f3103ae7 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -20,11 +20,12 @@ this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); this.colorListContainer_ = document.querySelector('.palettes-list-colors'); this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - this.paletteListOptGroup_ = document.querySelector('.palettes-list-select-group'); + this.createPaletteButton_ = document.querySelector('.create-palette-button'); this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); + this.createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); @@ -38,15 +39,15 @@ ns.PalettesListController.prototype.fillPaletteList = function () { var palettes = [{ - id : Constants.NO_PALETTE_ID, - name : 'No palette' + id : Constants.CURRENT_COLORS_PALETTE_ID, + name : 'Current colors' }]; palettes = palettes.concat(this.retrievePalettes()); var html = palettes.map(function (palette) { return pskl.utils.Template.replace('', palette); }).join(''); - this.paletteListOptGroup_.innerHTML = html; + this.colorPaletteSelect_.innerHTML = html; }; ns.PalettesListController.prototype.fillColorListContainer = function () { @@ -96,17 +97,13 @@ ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { var paletteId = this.colorPaletteSelect_.value; - if (paletteId === Constants.MANAGE_PALETTE_ID) { - $.publish(Events.DIALOG_DISPLAY, 'manage-palettes'); - this.selectPaletteFromUserSettings(); - } else { - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - } - + pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); this.fillColorListContainer(); }; - + ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { + $.publish(Events.DIALOG_DISPLAY, 'create-palette'); + }; ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { event.preventDefault(); diff --git a/src/js/controller/dialogs/CreatePaletteController.js b/src/js/controller/dialogs/CreatePaletteController.js new file mode 100644 index 00000000..b749aa90 --- /dev/null +++ b/src/js/controller/dialogs/CreatePaletteController.js @@ -0,0 +1,12 @@ +(function () { + var ns = $.namespace('pskl.controller.dialogs'); + + ns.CreatePaletteController = function (piskelController) { + }; + + pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); + + ns.CreatePaletteController.prototype.init = function () { + this.superclass.init.call(this); + }; +})(); \ No newline at end of file diff --git a/src/js/controller/dialogs/DialogsController.js b/src/js/controller/dialogs/DialogsController.js index 2f52a021..af6fe2a3 100644 --- a/src/js/controller/dialogs/DialogsController.js +++ b/src/js/controller/dialogs/DialogsController.js @@ -6,6 +6,10 @@ template : 'templates/dialogs/manage-palettes.html', controller : ns.PaletteManagerController }, + 'create-palette' : { + template : 'templates/dialogs/create-palette.html', + controller : ns.CreatePaletteController + }, 'browse-local' : { template : 'templates/dialogs/browse-local.html', controller : ns.BrowseLocalController diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index bd66a181..8b518242 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -100,9 +100,11 @@ // Dialogs sub-controllers "js/controller/dialogs/AbstractDialogController.js", "js/controller/dialogs/PaletteManagerController.js", + "js/controller/dialogs/CreatePaletteController.js", "js/controller/dialogs/ImportImageController.js", "js/controller/dialogs/BrowseLocalController.js", + // Dialogs controller "js/controller/dialogs/DialogsController.js", diff --git a/src/piskel-style-list.js b/src/piskel-style-list.js index ab92a308..081b9440 100644 --- a/src/piskel-style-list.js +++ b/src/piskel-style-list.js @@ -15,6 +15,7 @@ "css/dialogs-import-image.css", "css/dialogs-manage-palettes.css", "css/dialogs-browse-local.css", + "css/dialogs-create-palette.css", "css/toolbox.css", "css/toolbox-layers-list.css", "css/toolbox-palettes-list.css", diff --git a/src/templates/dialogs/create-palette.html b/src/templates/dialogs/create-palette.html new file mode 100644 index 00000000..58f1a271 --- /dev/null +++ b/src/templates/dialogs/create-palette.html @@ -0,0 +1,30 @@ +
+

+ Create palette + X +

+
+ Select your creation method : +
+
    +
  • +

  • +
  • + +
  • +
+ + +
+
+ +
\ No newline at end of file diff --git a/src/templates/palettes-list.html b/src/templates/palettes-list.html index 8cc447e5..bfffbe50 100644 --- a/src/templates/palettes-list.html +++ b/src/templates/palettes-list.html @@ -1,13 +1,19 @@
-

- Palettes - +

+ Palettes +
+

+
+ +
+
\ No newline at end of file diff --git a/src/templates/dialogs/import-image.html b/src/templates/dialogs/import-image.html index aa7ddd65..95795799 100644 --- a/src/templates/dialogs/import-image.html +++ b/src/templates/dialogs/import-image.html @@ -1,7 +1,7 @@

Import Image - X + X

diff --git a/src/templates/dialogs/manage-palettes.html b/src/templates/dialogs/manage-palettes.html index 795cbcaa..3b1dc019 100644 --- a/src/templates/dialogs/manage-palettes.html +++ b/src/templates/dialogs/manage-palettes.html @@ -1,7 +1,7 @@

Palette manager - X + X

From e8db80a0ece7645da4bf295b5df1b9a3ae27ae8f Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 4 Sep 2014 08:34:17 +0200 Subject: [PATCH 03/32] Extracted ColorPicker code to dedicated widget package (noooooooo) ; Added basic palette creation mechanism (list colors + add color) --- src/css/color-picker-slider.css | 96 ++++++++++ src/css/dialogs-create-palette-method.css | 21 +++ .../dialogs/CreatePaletteController.js | 172 +++++------------- .../dialogs/CreatePaletteMethodController.js | 63 +++++++ .../controller/widgets/HslRgbColorPicker.js | 141 ++++++++++++++ src/piskel-script-list.js | 3 + .../dialogs/create-palette-method.html | 28 +++ src/templates/dialogs/create-palette.html | 1 + 8 files changed, 400 insertions(+), 125 deletions(-) create mode 100644 src/css/color-picker-slider.css create mode 100644 src/css/dialogs-create-palette-method.css create mode 100644 src/js/controller/dialogs/CreatePaletteMethodController.js create mode 100644 src/js/controller/widgets/HslRgbColorPicker.js create mode 100644 src/templates/dialogs/create-palette-method.html diff --git a/src/css/color-picker-slider.css b/src/css/color-picker-slider.css new file mode 100644 index 00000000..05156f72 --- /dev/null +++ b/src/css/color-picker-slider.css @@ -0,0 +1,96 @@ +.color-picker-slider * { + box-sizing: border-box; +} + +.color-picker-slider input[type="range"] { + -webkit-appearance: none; + -webkit-tap-highlight-color: rgba(255, 255, 255, 0); + width: 100%; + border: none; + padding: 1px 2px; + border-radius: 3px; + background-image: linear-gradient(to right, hsl(0, 30%, 70%) 0, hsl(359, 30%, 70%) 100%); + box-shadow: inset 0 1px 0 0 #0d0e0f, inset 0 -1px 0 0 #3a3d42; + outline: none; /* no focus outline */ +} + +/* thumb */ + +.color-picker-slider input[type="range"]::-webkit-slider-thumb { + -webkit-appearance: none; + cursor:pointer; + width: 7px; + height: 18px; + border: none; + border-radius: 2px; + background-image: -webkit-gradient(linear, left top, left bottom, color-stop(0%, #529de1), color-stop(100%, #245e8f)); /* android <= 2.2 */ + background-image: -webkit-linear-gradient(top , #529de1 0, #245e8f 100%); /* older mobile safari and android > 2.2 */; + background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ +} +.color-picker-slider input[type="range"]::-moz-range-thumb { + width: 7px; + height: 18px; + border: none; + border-radius: 2px; + background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ +} + +.color-picker-slider input[type="range"]::-ms-thumb { + width: 7px; + height: 18px; + border-radius: 2px; + border: 0; + background-image: linear-gradient(to bottom, #529de1 0, #245e8f 100%); /* W3C */ +} + +/*CROSS BROWSER RESET*/ + + +.color-picker-slider input[type="range"]::-moz-range-track { + border: inherit; + background: transparent; +} + +.color-picker-slider input[type="range"]::-ms-track { + border: inherit; + color: transparent; /* don't drawn vertical reference line */ + background: transparent; +} + +.color-picker-slider input[type="range"]::-ms-fill-lower, +.color-picker-slider input[type="range"]::-ms-fill-upper { + background: transparent; +} + +.color-picker-slider input[type="range"]::-ms-tooltip { + display: none; +} + +.color-picker-slider { + padding: 0 10px; + height : 25px; + overflow: hidden; +} + +.color-picker-slider span{ + line-height : 25px; + width : 10px; + float:left; +} + +.color-picker-slider input[type="range"]{ + float:left; + height : 10px; + width : 100px; + margin: 7px 5px; +} + +.color-picker-slider input[type="text"]{ + float:left; + width : 47px; + margin-left: 5px; +} + +.color-picker-slider input[type="range"][data-dimension="h"] { + background-image:linear-gradient(to right, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%); +} \ No newline at end of file diff --git a/src/css/dialogs-create-palette-method.css b/src/css/dialogs-create-palette-method.css new file mode 100644 index 00000000..767b6c1e --- /dev/null +++ b/src/css/dialogs-create-palette-method.css @@ -0,0 +1,21 @@ +#dialog-container.create-palette-method { + width: 500px; + height: 200px; + top : 50%; + left : 50%; + position : absolute; + margin-left: -250px; +} + +.show #dialog-container.create-palette-method { + margin-top: -100px; +} + +.create-palette-method-item { + line-height : 24px; +} + +.create-palette-method-item label{ + margin-top: 3px; + margin-left: 5px; +} \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteController.js b/src/js/controller/dialogs/CreatePaletteController.js index 89d6db77..26551f7b 100644 --- a/src/js/controller/dialogs/CreatePaletteController.js +++ b/src/js/controller/dialogs/CreatePaletteController.js @@ -4,6 +4,8 @@ ns.CreatePaletteController = function (piskelController) { this.tinyColor = null; this.hsvColor = {h:0,s:0,v:0}; + this.palette = []; + this.selectedIndex = -1; }; pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); @@ -11,138 +13,58 @@ ns.CreatePaletteController.prototype.init = function () { this.superclass.init.call(this); - $(".color-picker-spectrum").spectrum({ - flat: true, - showInput: true, - showButtons: false, - change : this.setColor.bind(this) - }); - - this.tinyColorPickerContainer = document.querySelector('.color-picker-container'); - this.tinyColorPickerContainer.addEventListener('input', this.onPickerInput_.bind(this)); - + this.colorsList = document.querySelector('.colors-list'); + this.colorPickerContainer = document.querySelector('.color-picker-container'); this.colorPreviewEl = document.querySelector('.color-preview'); - this.setColor("#000000"); - }; + this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); - ns.CreatePaletteController.prototype.onPickerInput_ = function (evt) { - var target = evt.target; + this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(this.colorPickerContainer, this.onColorUpdated_.bind(this)); + this.hslRgbColorPicker.init(); - var model = target.dataset.model; - var dimension = target.dataset.dimension; - var value = parseInt(target.value, 10); - - if (dimension === 'v' || dimension === 's') { - value = value/100; - } - - var color; - if (model === 'rgb') { - color = this.tinyColor.toRgb(); - } else if (model === 'hsv') { - color = this.hsvColor; - } - - if (isNaN(value)) { - value = color[dimension]; - } else { - color[dimension] = value; - } - - this.setColor(color); - }; - - ns.CreatePaletteController.prototype.setColor = function (inputColor) { - if (!this.unplugged) { - this.unplugged = true; - - this.hsvColor = this.toHsvColor_(inputColor); - this.tinyColor = this.toTinyColor_(inputColor); - - this.updateInputs(); - $(".color-picker-spectrum").spectrum("set", this.tinyColor); - - this.onColorUpdated_(this.tinyColor); - - this.unplugged = false; - } - }; - - ns.CreatePaletteController.prototype.toTinyColor_ = function (color) { - if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { - return color; - } else { - return window.tinycolor(JSON.parse(JSON.stringify(color))); - } - }; - - ns.CreatePaletteController.prototype.toHsvColor_ = function (color) { - var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); - if (isHsvColor) { - return { - h : Math.max(0, Math.min(255, color.h)), - s : Math.max(0, Math.min(1, color.s)), - v : Math.max(0, Math.min(1, color.v)) - }; - } else { - return this.toTinyColor_(color).toHsv(); - } - }; - - ns.CreatePaletteController.prototype.updateInputs = function () { - var inputs = this.tinyColorPickerContainer.querySelectorAll('input'); - var rgb = this.tinyColor.toRgb(); - - - for (var i = 0 ; i < inputs.length ; i++) { - var input = inputs[i]; - var dimension = input.dataset.dimension; - var model = input.dataset.model; - - if (model === 'rgb') { - input.value = rgb[dimension]; - } else if (model === 'hsv') { - var value = this.hsvColor[dimension]; - if (dimension === 'v' || dimension === 's') { - value = 100 * value; - } - input.value = Math.round(value); - } - - if (input.getAttribute('type') === 'range') { - this.updateSliderBackground(input); - } - } - }; - - ns.CreatePaletteController.prototype.updateSliderBackground = function (slider) { - var dimension = slider.dataset.dimension; - var model = slider.dataset.model; - - var start, end; - var isHueSlider = dimension === 'h'; - if (!isHueSlider) { - if (model === 'hsv') { - start = JSON.parse(JSON.stringify(this.hsvColor)); - start[dimension] = 0; - - end = JSON.parse(JSON.stringify(this.hsvColor)); - end[dimension] = 1; - } else { - start = this.tinyColor.toRgb(); - start[dimension] = 0; - - end = this.tinyColor.toRgb(); - end[dimension] = 255; - } - var colorStart = window.tinycolor(start).toRgbString(); - var colorEnd = window.tinycolor(end).toRgbString(); - slider.style.backgroundImage = "linear-gradient(to right, " + colorStart + " 0, " + colorEnd + " 100%)"; - } + this.refresh_(); }; ns.CreatePaletteController.prototype.onColorUpdated_ = function (color) { this.colorPreviewEl.style.background = color.toRgbString(); + this.palette[this.selectedIndex] = color.toRgbString(); + this.refresh_(); + }; + + ns.CreatePaletteController.prototype.onColorContainerClick_ = function (evt) { + var target = evt.target; + if (target.dataset.paletteIndex) { + this.selectColor_(target.dataset.paletteIndex); + } else if (target.classList.contains('add-color-button')) { + this.palette.push(this.palette[this.selectedIndex] || "#000000"); + this.refresh_(); + this.selectColor_(this.palette.length-1); + } + }; + + ns.CreatePaletteController.prototype.selectColor_ = function (index) { + this.selectedIndex = index; + + var previous = this.colorsList.querySelector('.selectedColor'); + if (previous) { + previous.classList.remove('selected'); + } + + var next = this.colorsList.querySelector('[data-palette-index="'+index+'"]'); + next.classList.add('selected'); + + this.hslRgbColorPicker.setColor(this.palette[index]); + }; + + ns.CreatePaletteController.prototype.refresh_ = function () { + var html = ""; + var tpl = '
'; + this.palette.forEach(function (color, index) { + html += pskl.utils.Template.replace(tpl, {color:color, index:index}); + }); + + html += '
ADD
'; + + this.colorsList.innerHTML = html; }; })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteMethodController.js b/src/js/controller/dialogs/CreatePaletteMethodController.js new file mode 100644 index 00000000..7fcd17fe --- /dev/null +++ b/src/js/controller/dialogs/CreatePaletteMethodController.js @@ -0,0 +1,63 @@ +(function () { + var ns = $.namespace('pskl.controller.dialogs'); + + ns.CreatePaletteMethodController = function (piskelController) { + }; + + pskl.utils.inherit(ns.CreatePaletteMethodController, ns.AbstractDialogController); + + ns.CreatePaletteMethodController.prototype.init = function () { + this.superclass.init.call(this); + + this.createButton = document.querySelector('.create-palette-method-continue'); + this.cancelButton = document.querySelector('.create-palette-method-cancel'); + + this.createButton.addEventListener('click', this.onCreateButtonClick_.bind(this)); + + this.cancelButton.addEventListener('click', function () { + $.publish(Events.DIALOG_HIDE); + }); + }; + + ns.CreatePaletteMethodController.prototype.onCreateButtonClick_ = function (evt) { + var method = this.getSelectedMethod_(); + + var initArgs = { + method : method + }; + + if (method === 'palette') { + initArgs.paletteId = this.getSelectedPaletteId_(); + } + + this.closeDialog(); + + window.setTimeout(function () { + $.publish(Events.DIALOG_DISPLAY, { + dialogId : 'create-palette', + initArgs : initArgs + }); + },500); + }; + + ns.CreatePaletteMethodController.prototype.getSelectedMethod_ = function (evt) { + var options = document.querySelectorAll('.create-palette-method-list input[type="radio"]'); + + var method; + for (var i = 0 ; i < options.length ; i++) { + console.log(options[i]); + if (options[i].checked) { + method = options[i].value; + } + } + + return method; + }; + + ns.CreatePaletteMethodController.prototype.getSelectedPaletteId_ = function (evt) { + var select = document.querySelector('.palettes-list-select'); + return select.value; + }; + + +})(); \ No newline at end of file diff --git a/src/js/controller/widgets/HslRgbColorPicker.js b/src/js/controller/widgets/HslRgbColorPicker.js new file mode 100644 index 00000000..093d67c5 --- /dev/null +++ b/src/js/controller/widgets/HslRgbColorPicker.js @@ -0,0 +1,141 @@ +(function () { + var ns = $.namespace('pskl.controller.widgets'); + + ns.HslRgbColorPicker = function (container, colorUpdatedCallback) { + this.container = container; + this.colorUpdatedCallback = colorUpdatedCallback; + }; + + ns.HslRgbColorPicker.prototype.init = function () { + this.container.addEventListener('input', this.onPickerInput_.bind(this)); + + this.spectrumEl = this.container.querySelector('.color-picker-spectrum'); + + $(this.spectrumEl).spectrum({ + flat: true, + showInput: true, + showButtons: false, + move : this.setColor.bind(this), + change : this.setColor.bind(this) + }); + + this.setColor("#000000"); + }; + + + ns.HslRgbColorPicker.prototype.onPickerInput_ = function (evt) { + var target = evt.target; + + var model = target.dataset.model; + var dimension = target.dataset.dimension; + + var value = parseInt(target.value, 10); + if (dimension === 'v' || dimension === 's') { + value = value/100; + } + + var color; + if (model === 'rgb') { + color = this.tinyColor.toRgb(); + } else if (model === 'hsv') { + color = this.hsvColor; + } + + if (isNaN(value)) { + value = color[dimension]; + } else { + color[dimension] = value; + } + + this.setColor(color); + }; + + ns.HslRgbColorPicker.prototype.setColor = function (inputColor) { + if (!this.unplugged) { + this.unplugged = true; + + this.hsvColor = this.toHsvColor_(inputColor); + this.tinyColor = this.toTinyColor_(inputColor); + + this.updateInputs(); + $(".color-picker-spectrum").spectrum("set", this.tinyColor); + + this.colorUpdatedCallback(this.tinyColor); + + this.unplugged = false; + } + }; + + ns.HslRgbColorPicker.prototype.toTinyColor_ = function (color) { + if (typeof color == "object" && color.hasOwnProperty("_tc_id")) { + return color; + } else { + return window.tinycolor(JSON.parse(JSON.stringify(color))); + } + }; + + ns.HslRgbColorPicker.prototype.toHsvColor_ = function (color) { + var isHsvColor = ['h','s','v'].every(color.hasOwnProperty.bind(color)); + if (isHsvColor) { + return { + h : Math.max(0, Math.min(255, color.h)), + s : Math.max(0, Math.min(1, color.s)), + v : Math.max(0, Math.min(1, color.v)) + }; + } else { + return this.toTinyColor_(color).toHsv(); + } + }; + + ns.HslRgbColorPicker.prototype.updateInputs = function () { + var inputs = this.container.querySelectorAll('input'); + var rgb = this.tinyColor.toRgb(); + + + for (var i = 0 ; i < inputs.length ; i++) { + var input = inputs[i]; + var dimension = input.dataset.dimension; + var model = input.dataset.model; + + if (model === 'rgb') { + input.value = rgb[dimension]; + } else if (model === 'hsv') { + var value = this.hsvColor[dimension]; + if (dimension === 'v' || dimension === 's') { + value = 100 * value; + } + input.value = Math.round(value); + } + + if (input.getAttribute('type') === 'range') { + this.updateSliderBackground(input); + } + } + }; + + ns.HslRgbColorPicker.prototype.updateSliderBackground = function (slider) { + var dimension = slider.dataset.dimension; + var model = slider.dataset.model; + + var start, end; + var isHueSlider = dimension === 'h'; + if (!isHueSlider) { + if (model === 'hsv') { + start = JSON.parse(JSON.stringify(this.hsvColor)); + start[dimension] = 0; + + end = JSON.parse(JSON.stringify(this.hsvColor)); + end[dimension] = 1; + } else { + start = this.tinyColor.toRgb(); + start[dimension] = 0; + + end = this.tinyColor.toRgb(); + end[dimension] = 255; + } + var colorStart = window.tinycolor(start).toRgbString(); + var colorEnd = window.tinycolor(end).toRgbString(); + slider.style.backgroundImage = "linear-gradient(to right, " + colorStart + " 0, " + colorEnd + " 100%)"; + } + }; +})(); \ No newline at end of file diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 2a793268..87ecb90e 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -109,6 +109,9 @@ // Dialogs controller "js/controller/dialogs/DialogsController.js", + // Widget controller + "js/controller/widgets/HslRgbColorPicker.js", + // Services "js/service/LocalStorageService.js", "js/service/GithubStorageService.js", diff --git a/src/templates/dialogs/create-palette-method.html b/src/templates/dialogs/create-palette-method.html new file mode 100644 index 00000000..646a942a --- /dev/null +++ b/src/templates/dialogs/create-palette-method.html @@ -0,0 +1,28 @@ +
+

+ Create palette + X +

+
+ Select your creation method : +
    +
  • + + +
  • +
  • + +
    +
  • +
  • + + + +
  • +
+ + +
+
\ No newline at end of file diff --git a/src/templates/dialogs/create-palette.html b/src/templates/dialogs/create-palette.html index 679d1c4e..a5e48d51 100644 --- a/src/templates/dialogs/create-palette.html +++ b/src/templates/dialogs/create-palette.html @@ -9,6 +9,7 @@ Name :
+
From 8441f28ac14a4de58f8ea5f9421c92041b05a5da Mon Sep 17 00:00:00 2001 From: jdescottes Date: Sat, 6 Sep 2014 12:37:11 +0200 Subject: [PATCH 04/32] Palette creator can save palettes to local storage --- package.json | 2 +- src/css/dialogs-create-palette-method.css | 21 - src/css/dialogs-create-palette.css | 78 ++++ src/css/dialogs-manage-palettes.css | 212 ---------- src/css/toolbox-palettes-list.css | 22 +- src/index.html | 1 - src/js/Constants.js | 1 - src/js/app.js | 6 +- src/js/controller/PalettesListController.js | 74 ++-- .../dialogs/CreatePaletteController.js | 135 +++++-- .../dialogs/CreatePaletteMethodController.js | 63 --- .../controller/dialogs/DialogsController.js | 10 +- .../dialogs/PaletteManagerController.js | 382 ------------------ src/js/model/Palette.js | 38 ++ src/js/service/PaletteService.js | 61 +++ src/js/utils/Uuid.js | 17 + src/piskel-script-list.js | 5 +- src/piskel-style-list.js | 2 - .../dialogs/create-palette-method.html | 28 -- src/templates/dialogs/create-palette.html | 18 +- src/templates/dialogs/manage-palettes.html | 57 --- src/templates/palettes-list.html | 22 +- test/js/model/PaletteTest.js | 23 ++ test/js/service/PaletteServiceTest.js | 144 +++++++ test/js/utils/UuidTest.js | 27 ++ 25 files changed, 603 insertions(+), 846 deletions(-) delete mode 100644 src/css/dialogs-create-palette-method.css delete mode 100644 src/css/dialogs-manage-palettes.css delete mode 100644 src/js/controller/dialogs/CreatePaletteMethodController.js delete mode 100644 src/js/controller/dialogs/PaletteManagerController.js create mode 100644 src/js/model/Palette.js create mode 100644 src/js/service/PaletteService.js create mode 100644 src/js/utils/Uuid.js delete mode 100644 src/templates/dialogs/create-palette-method.html delete mode 100644 src/templates/dialogs/manage-palettes.html create mode 100644 test/js/model/PaletteTest.js create mode 100644 test/js/service/PaletteServiceTest.js create mode 100644 test/js/utils/UuidTest.js diff --git a/package.json b/package.json index 1da0caa1..679f704b 100644 --- a/package.json +++ b/package.json @@ -33,7 +33,7 @@ "karma": "0.12.17", "karma-chrome-launcher": "^0.1.4", "karma-phantomjs-launcher": "^0.1.4", - "karma-jasmine": "^0.1.5", + "karma-jasmine": "^0.2.0", "nodewebkit": "~0.10.1" }, "window": { diff --git a/src/css/dialogs-create-palette-method.css b/src/css/dialogs-create-palette-method.css deleted file mode 100644 index 767b6c1e..00000000 --- a/src/css/dialogs-create-palette-method.css +++ /dev/null @@ -1,21 +0,0 @@ -#dialog-container.create-palette-method { - width: 500px; - height: 200px; - top : 50%; - left : 50%; - position : absolute; - margin-left: -250px; -} - -.show #dialog-container.create-palette-method { - margin-top: -100px; -} - -.create-palette-method-item { - line-height : 24px; -} - -.create-palette-method-item label{ - margin-top: 3px; - margin-left: 5px; -} \ No newline at end of file diff --git a/src/css/dialogs-create-palette.css b/src/css/dialogs-create-palette.css index 4fa3b0db..ffbbab28 100644 --- a/src/css/dialogs-create-palette.css +++ b/src/css/dialogs-create-palette.css @@ -51,6 +51,84 @@ margin: 11px; } +.colors-list { + overflow : hidden; + width : 280px; +} + +.create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ + position:relative; + float : left; + + width : 44px; + height : 44px; + margin : 10px 0 0 10px; + + box-sizing : border-box; + + cursor : pointer; +} + +.create-palette-color { + border:1px solid #2c2c2c; + transition : border-color 0.2s; +} +.create-palette-color:hover { + border:1px solid gold; +} + +.colors-list-drop-proxy { + border:2px dotted #eee; +} + +.create-palette-new-color { + border:2px dotted gold; + + border-radius: 2px; + line-height: 40px; + text-align: center; + font-size: 20px; + color: gold; +} + +.create-palette-color.selected { + border:2px solid gold; +} + +.create-palette-remove-color { + position: absolute; + top: 0; + right: 0; + padding: 2px 4px; + opacity : 0.2; + + font-weight: bold; + color: rgb(255,255,255); + text-shadow : 0 0 1px rgb(0,0,0); + + transition : opacity 0.3s, color 0.1s; +} + +.light-color .create-palette-remove-color { + color: rgb(0,0,0); + text-shadow : 0 0 1px rgb(255,255,255); +} + +.selected .create-palette-remove-color { + top: -1px; + right: -1px; +} + +.create-palette-color:hover .create-palette-remove-color { + opacity: 0.6; +} + +.create-palette-color .create-palette-remove-color:hover { + opacity: 1; + color: rgb(240,80,80); + text-shadow : 0 0 1px rgb(0,0,0); +} + /*SPECTRUM OVERRIDES*/ .create-palette .sp-container{ diff --git a/src/css/dialogs-manage-palettes.css b/src/css/dialogs-manage-palettes.css deleted file mode 100644 index 0d867a09..00000000 --- a/src/css/dialogs-manage-palettes.css +++ /dev/null @@ -1,212 +0,0 @@ -.palette-manager-wrapper { - height: 100%; - position: relative; -} - -.palette-manager-body { - position: absolute; - top: 45px; - bottom: 0; - right: 0; - left: 0; -} - -.palette-manager-head { - position: absolute; - width: 100%; - background: gold; - margin: 0; - padding: 10px; - color: black; - font-size: 1.8em; - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.palette-manager-drawer { - width: 200px; - position: absolute; - top: 0; - bottom: 0; -} - -.palette-manager-list { - position: absolute; - top:40px; - right: 0; - bottom: 0; - left: 0; - overflow: auto; -} - -.palette-manager-actions { - position: absolute; - height:40px; - line-height:40px; - width: 100%; - text-align: center; -} - -.palette-manager-actions-button { - width: 80px; - margin: 5px; -} - -.palette-manager-palette-button, -.palette-manager-actions-button { - line-height: 20px; -} - -.palette-manager-list li { - height: 48px; - line-height: 48px; - padding-left:10px; - - font-size: 1.4em; - - box-sizing: border-box; - -moz-box-sizing: border-box; - - border-bottom: 1px solid #666; - cursor:pointer; -} - -.palette-manager-list li:hover { - background : #222; -} - -.palette-manager-list li.selected { - color : gold; - font-weight: bold; -} - -.palette-manager-list li:nth-child(1) { - border-top: 1px solid #666; -} - -.palette-manager-details { - position: absolute; - top: 0; - right: 0; - bottom: 0; - left: 200px; - - box-sizing: border-box; - -moz-box-sizing: border-box; - - border-left:1px solid #666; -} - -.palette-manager-details-head { - position: absolute; - height:40px; - line-height:40px; - width: 100%; - - box-sizing: border-box; - -moz-box-sizing: border-box; -} - -.palette-manager-details-head-name { - padding: 0 10px 0 20px; - font-size: 1.5em; - font-weight: bold; -} - -.palette-manager-details-head .edit-icon { - width: 24px; - display: inline-block; - background-size: 16px; -} - -.palette-manager-details-head-actions { - float: right; - line-height: 40px; - padding-right: 10px; -} - -.palette-manager-details-body { - position: absolute; - top:40px; - right: 0; - bottom: 0; - left: 0; - overflow: auto; - - box-sizing: border-box; - -moz-box-sizing: border-box; -} - - - -.palette-manager-color-card { - width: 120px; - height: 180px; - display: inline-block; - position: relative; - margin: 20px 0 20px 20px; - box-shadow: 0 0 0px 0px gold; - transition: box-shadow 0.3s; -} - -.palette-manager-color-card:hover { - box-shadow: 0 0 4px 1px gold; -} - -.palette-manager-delete-card { - position: absolute; - top: 0; - right: 0; - width: 20px; - - text-align: center; - font-size: 1.6em; - font-weight: bold; - color: rgb(255,255,255); - text-shadow : 0 0 2px rgb(0,0,0); - cursor: pointer; - - opacity : 0.2; - transition : opacity 0.3s, color 0.1s; -} - -.palette-manager-color-card:hover .palette-manager-delete-card { - opacity : 0.6; -} - -.palette-manager-color-card .palette-manager-delete-card:hover { - opacity : 1; - color: rgb(240,80,80); -} - -.palette-manager-new-color .palette-manager-color-square { - border: 3px dotted #888; - border-bottom-width: 0; - box-sizing: border-box; - -moz-box-sizing: border-box; - border-radius: 3px 3px 0 0; - cursor: pointer; - text-align: center; - font-size: 24px; - color: #888; - line-height: 120px; -} - -.palette-manager-color-square { - width: 120px; - height: 120px; - cursor: pointer; - /*background-image:url(../img/tools/eyedropper.png);*/ -} - -.palette-manager-color-details { - color : #666; - background: #eee; - height: 60px; - padding-left: 5px; -} - -.palette-manager-color-details li{ - line-height: 20px; - font-weight: bold; -} \ No newline at end of file diff --git a/src/css/toolbox-palettes-list.css b/src/css/toolbox-palettes-list.css index 10799c35..64d64218 100644 --- a/src/css/toolbox-palettes-list.css +++ b/src/css/toolbox-palettes-list.css @@ -55,8 +55,28 @@ border-right-color: transparent; } - .palettes-list-secondary-color:before { right: 1px; border-left-color: transparent; +} + +.palette-action { + width : 18px; + height : 18px; + line-height : 16px; + + text-align:center; + float : right; + font-size : 12px; + border: 1px solid gold; + border-radius : 2px; + box-sizing : border-box; + margin : 3px 3px 3px 0; + + cursor : pointer; + transition : color 0.3s; +} + +.palette-action:hover { + color : gold; } \ No newline at end of file diff --git a/src/index.html b/src/index.html index 7846b43a..969a082e 100644 --- a/src/index.html +++ b/src/index.html @@ -68,7 +68,6 @@
-
diff --git a/src/js/Constants.js b/src/js/Constants.js index f017ca5e..0ce59ab4 100644 --- a/src/js/Constants.js +++ b/src/js/Constants.js @@ -27,7 +27,6 @@ var Constants = { NO_PALETTE_ID : '__no-palette', CURRENT_COLORS_PALETTE_ID : '__current-colors', - MANAGE_PALETTE_ID : '__manage-palettes', // Used for Spectrum input PREFERRED_COLOR_FORMAT : 'rgb', diff --git a/src/js/app.js b/src/js/app.js index 0ed608b8..4932a16b 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -39,6 +39,9 @@ this.piskelController = new pskl.controller.piskel.PublicPiskelController(this.corePiskelController); this.piskelController.init(); + this.paletteService = new pskl.service.PaletteService(); + this.paletteService.init(); + this.paletteController = new pskl.controller.PaletteController(); this.paletteController.init(); @@ -129,9 +132,6 @@ if (pskl.devtools) { pskl.devtools.init(); } - - // FIXME : remove - $.publish(Events.DIALOG_DISPLAY, 'create-palette'); }, loadPiskel_ : function (serializedPiskel, descriptor, fps) { diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 7d325dd0..11522faf 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -13,19 +13,26 @@ ns.PalettesListController = function (paletteController, usedColorService) { this.usedColorService = usedColorService; + this.paletteService = pskl.app.paletteService; this.paletteController = paletteController; }; ns.PalettesListController.prototype.init = function () { this.paletteColorTemplate_ = pskl.utils.Template.get('palette-color-template'); + this.colorListContainer_ = document.querySelector('.palettes-list-colors'); this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); - this.createPaletteButton_ = document.querySelector('.create-palette-button'); + + var createPaletteButton_ = document.querySelector('.create-palette-button'); + var paletteActions = document.querySelector('.palette-actions'); this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); - this.createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); + + createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); + paletteActions.addEventListener('click', this.onPaletteActionsClick_.bind(this)); + $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); @@ -42,7 +49,7 @@ id : Constants.CURRENT_COLORS_PALETTE_ID, name : 'Current colors' }]; - palettes = palettes.concat(this.retrievePalettes()); + palettes = palettes.concat(this.paletteService.getPalettes()); var html = palettes.map(function (palette) { return pskl.utils.Template.replace('', palette); @@ -74,7 +81,7 @@ if (paletteId === Constants.CURRENT_COLORS_PALETTE_ID) { colors = this.usedColorService.getCurrentColors(); } else { - var palette = this.getPaletteById(paletteId, this.retrievePalettes()); + var palette = this.paletteService.getPaletteById(paletteId); if (palette) { colors = palette.colors; } @@ -87,14 +94,14 @@ return colors; }; - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - this.colorPaletteSelect_.value = paletteId; - }; - ns.PalettesListController.prototype.selectPaletteFromUserSettings = function () { this.selectPalette(pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE)); }; + ns.PalettesListController.prototype.selectPalette = function (paletteId) { + this.colorPaletteSelect_.value = paletteId; + }; + ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { var paletteId = this.colorPaletteSelect_.value; pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); @@ -102,7 +109,39 @@ }; ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { - $.publish(Events.DIALOG_DISPLAY, 'create-palette-method'); + $.publish(Events.DIALOG_DISPLAY, 'create-palette'); + }; + + ns.PalettesListController.prototype.onPaletteActionsClick_ = function (evt) { + var classList = evt.target.classList; + if (classList.contains('palette-action-edit')) { + this.editSelectedPalette_(); + } else if (classList.contains('palette-action-delete')) { + this.deleteSelectedPalette_(); + } else if (classList.contains('palette-action-download')) { + this.downloadSelectedPalette_(); + } + }; + + ns.PalettesListController.prototype.editSelectedPalette_ = function () { + var paletteId = this.colorPaletteSelect_.value; + $.publish(Events.DIALOG_DISPLAY, { + dialogId : 'create-palette', + initArgs : paletteId + }); + }; + + ns.PalettesListController.prototype.deleteSelectedPalette_ = function () { + var paletteId = this.colorPaletteSelect_.value; + var palette = this.paletteService.getPaletteById(paletteId); + if (window.confirm('Are you sure you want to delete palette ' + palette.name)) { + this.paletteService.deletePaletteById(palette.id); + this.selectPalette(Constants.CURRENT_COLORS_PALETTE_ID); + } + }; + + ns.PalettesListController.prototype.downloadSelectedPalette_ = function () { + window.alert('not implemented yet'); }; ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { @@ -155,21 +194,4 @@ this.selectPaletteFromUserSettings(); this.fillColorListContainer(); }; - - ns.PalettesListController.prototype.getPaletteById = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; - - ns.PalettesListController.prototype.retrievePalettes = function () { - var palettesString = window.localStorage.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; - }; })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteController.js b/src/js/controller/dialogs/CreatePaletteController.js index 26551f7b..51a6c78b 100644 --- a/src/js/controller/dialogs/CreatePaletteController.js +++ b/src/js/controller/dialogs/CreatePaletteController.js @@ -2,22 +2,34 @@ var ns = $.namespace('pskl.controller.dialogs'); ns.CreatePaletteController = function (piskelController) { - this.tinyColor = null; - this.hsvColor = {h:0,s:0,v:0}; - this.palette = []; + this.paletteService = pskl.app.paletteService; this.selectedIndex = -1; }; pskl.utils.inherit(ns.CreatePaletteController, ns.AbstractDialogController); - ns.CreatePaletteController.prototype.init = function () { + ns.CreatePaletteController.prototype.init = function (paletteId) { this.superclass.init.call(this); + console.log(paletteId); + if (paletteId) { + var palette = this.paletteService.getPaletteById(paletteId); + this.palette = pskl.model.Palette.fromObject(palette); + } else { + paletteId = pskl.utils.Uuid.generate(); + this.palette = new pskl.model.Palette(paletteId, 'New palette', []); + } this.colorsList = document.querySelector('.colors-list'); this.colorPickerContainer = document.querySelector('.color-picker-container'); this.colorPreviewEl = document.querySelector('.color-preview'); + this.submitButton = document.querySelector('.create-palette-submit'); + this.nameInput = document.querySelector('input[name="palette-name"]'); + this.nameInput.value = this.palette.name; + this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); + this.submitButton.addEventListener('click', this.onSubmitButtonClick_.bind(this)); + this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(this.colorPickerContainer, this.onColorUpdated_.bind(this)); this.hslRgbColorPicker.init(); @@ -26,45 +38,114 @@ }; ns.CreatePaletteController.prototype.onColorUpdated_ = function (color) { - this.colorPreviewEl.style.background = color.toRgbString(); - this.palette[this.selectedIndex] = color.toRgbString(); - this.refresh_(); + var rgbColor = color.toRgbString(); + this.colorPreviewEl.style.background = rgbColor; + this.palette.set(this.selectedIndex, rgbColor); + + this.refreshColorElement_(this.selectedIndex); + }; + + /** + * Lightweight refresh only changing the color of one element of the palette color list + */ + ns.CreatePaletteController.prototype.refreshColorElement_ = function (index) { + var color = this.palette.get(this.selectedIndex); + var element = document.querySelector('[data-palette-index="'+index+'"]'); + if (element) { + element.style.background = color; + element.classList.toggle('light-color', this.isLight_(color)); + } }; ns.CreatePaletteController.prototype.onColorContainerClick_ = function (evt) { var target = evt.target; - if (target.dataset.paletteIndex) { - this.selectColor_(target.dataset.paletteIndex); - } else if (target.classList.contains('add-color-button')) { - this.palette.push(this.palette[this.selectedIndex] || "#000000"); - this.refresh_(); - this.selectColor_(this.palette.length-1); + if (target.classList.contains('create-palette-color')) { + this.onPaletteColorClick_(evt, target); + } else if (target.classList.contains('create-palette-new-color')) { + this.onNewColorClick_(evt, target); + } else if (target.classList.contains('create-palette-remove-color')) { + this.onRemoveColorClick_(evt, target); } + this.refresh_(); + }; + + ns.CreatePaletteController.prototype.onPaletteColorClick_ = function (evt, target) { + var index = parseInt(target.dataset.paletteIndex,10); + this.selectColor_(index); + }; + + ns.CreatePaletteController.prototype.onRemoveColorClick_ = function (evt, target) { + var colorElement = target.parentNode; + var index = parseInt(colorElement.dataset.paletteIndex,10); + this.removeColor_(index); + }; + + ns.CreatePaletteController.prototype.onNewColorClick_ = function (evt, target) { + var newColor = this.palette.get(this.selectedIndex) || '#000000'; + this.palette.add(newColor); + this.selectColor_(this.palette.size()-1); + }; + + ns.CreatePaletteController.prototype.onSubmitButtonClick_ = function (evt) { + this.paletteService.savePalette(this.palette); + this.closeDialog(); + }; + + ns.CreatePaletteController.prototype.onNameInputChange_ = function (evt) { + this.palette.name = this.nameInput.value; }; ns.CreatePaletteController.prototype.selectColor_ = function (index) { this.selectedIndex = index; + this.hslRgbColorPicker.setColor(this.palette.get(index)); + }; - var previous = this.colorsList.querySelector('.selectedColor'); - if (previous) { - previous.classList.remove('selected'); - } - - var next = this.colorsList.querySelector('[data-palette-index="'+index+'"]'); - next.classList.add('selected'); - - this.hslRgbColorPicker.setColor(this.palette[index]); + ns.CreatePaletteController.prototype.removeColor_ = function (index) { + this.palette.removeAt(index); + this.refresh_(); }; ns.CreatePaletteController.prototype.refresh_ = function () { var html = ""; - var tpl = '
'; - this.palette.forEach(function (color, index) { - html += pskl.utils.Template.replace(tpl, {color:color, index:index}); - }); + var tpl = pskl.utils.Template.get('create-palette-color-template'); + var colors = this.palette.colors; - html += '
ADD
'; + colors.forEach(function (color, index) { + var isSelected = (index === this.selectedIndex); + + html += pskl.utils.Template.replace(tpl, { + color:color, index:index, + ':selected':isSelected, + ':light-color':this.isLight_(color) + }); + }.bind(this)); + + html += '
  • +
  • '; this.colorsList.innerHTML = html; + + $('.colors-list').sortable({ + placeholder: 'colors-list-drop-proxy', + update: this.onDrop_.bind(this), + items: '.create-palette-color' + }); + }; + + ns.CreatePaletteController.prototype.isLight_ = function (color) { + var rgb = window.tinycolor(color).toRgb(); + return rgb.r+rgb.b+rgb.g > 128*3; + }; + + + ns.CreatePaletteController.prototype.onDrop_ = function (evt, drop) { + var colorElement = drop.item.get(0); + + var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); + var newIndex = $('.create-palette-color').index(drop.item); + this.palette.move(oldIndex, newIndex); + + this.selectedIndex = newIndex; + + this.refresh_(); }; })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteMethodController.js b/src/js/controller/dialogs/CreatePaletteMethodController.js deleted file mode 100644 index 7fcd17fe..00000000 --- a/src/js/controller/dialogs/CreatePaletteMethodController.js +++ /dev/null @@ -1,63 +0,0 @@ -(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - ns.CreatePaletteMethodController = function (piskelController) { - }; - - pskl.utils.inherit(ns.CreatePaletteMethodController, ns.AbstractDialogController); - - ns.CreatePaletteMethodController.prototype.init = function () { - this.superclass.init.call(this); - - this.createButton = document.querySelector('.create-palette-method-continue'); - this.cancelButton = document.querySelector('.create-palette-method-cancel'); - - this.createButton.addEventListener('click', this.onCreateButtonClick_.bind(this)); - - this.cancelButton.addEventListener('click', function () { - $.publish(Events.DIALOG_HIDE); - }); - }; - - ns.CreatePaletteMethodController.prototype.onCreateButtonClick_ = function (evt) { - var method = this.getSelectedMethod_(); - - var initArgs = { - method : method - }; - - if (method === 'palette') { - initArgs.paletteId = this.getSelectedPaletteId_(); - } - - this.closeDialog(); - - window.setTimeout(function () { - $.publish(Events.DIALOG_DISPLAY, { - dialogId : 'create-palette', - initArgs : initArgs - }); - },500); - }; - - ns.CreatePaletteMethodController.prototype.getSelectedMethod_ = function (evt) { - var options = document.querySelectorAll('.create-palette-method-list input[type="radio"]'); - - var method; - for (var i = 0 ; i < options.length ; i++) { - console.log(options[i]); - if (options[i].checked) { - method = options[i].value; - } - } - - return method; - }; - - ns.CreatePaletteMethodController.prototype.getSelectedPaletteId_ = function (evt) { - var select = document.querySelector('.palettes-list-select'); - return select.value; - }; - - -})(); \ No newline at end of file diff --git a/src/js/controller/dialogs/DialogsController.js b/src/js/controller/dialogs/DialogsController.js index 02c99001..0d8008bf 100644 --- a/src/js/controller/dialogs/DialogsController.js +++ b/src/js/controller/dialogs/DialogsController.js @@ -2,14 +2,6 @@ var ns = $.namespace('pskl.controller.dialogs'); var dialogs = { - 'manage-palettes' : { - template : 'templates/dialogs/manage-palettes.html', - controller : ns.PaletteManagerController - }, - 'create-palette-method' : { - template : 'templates/dialogs/create-palette-method.html', - controller : ns.CreatePaletteMethodController - }, 'create-palette' : { template : 'templates/dialogs/create-palette.html', controller : ns.CreatePaletteController @@ -35,7 +27,7 @@ $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'manage-palettes')); + pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palettes')); this.dialogWrapper_.classList.add('animated'); }; diff --git a/src/js/controller/dialogs/PaletteManagerController.js b/src/js/controller/dialogs/PaletteManagerController.js deleted file mode 100644 index dc16ba4d..00000000 --- a/src/js/controller/dialogs/PaletteManagerController.js +++ /dev/null @@ -1,382 +0,0 @@ -(function () { - var ns = $.namespace('pskl.controller.dialogs'); - - var tinycolor = window.tinycolor; - - var SELECTED_CLASSNAME = 'selected'; - var NEW_COLOR_CLASS = 'palette-manager-new-color'; - var CLOSE_ICON_CLASS = 'palette-manager-delete-card'; - var EDIT_NAME_CLASS = 'edit-icon'; - - ns.PaletteManagerController = function (piskelController) { - this.piskelController = piskelController; - this.palettes = this.retrieveUserPalettes(); - this.originalPalettes = this.retrieveUserPalettes(); - this.selectedPaletteId = null; - - // Keep track of all spectrum instances created, to dispose them when closing the popup - this.spectrumContainers = []; - }; - - pskl.utils.inherit(ns.PaletteManagerController, ns.AbstractDialogController); - - ns.PaletteManagerController.prototype.init = function () { - this.superclass.init.call(this); - - this.palettesList = document.querySelector('.palette-manager-list'); - this.paletteBody = document.querySelector('.palette-manager-details-body'); - this.paletteHead = document.querySelector('.palette-manager-details-head'); - this.createButton = document.querySelector('.palette-manager-actions-button[data-action="create"]'); - this.saveAllButton = document.querySelector('.palette-manager-actions-button[data-action="save-all"]'); - - this.colorCardTemplate = pskl.utils.Template.get('palette-color-card-template'); - this.newColorTemplate = pskl.utils.Template.get('palette-new-color-template'); - this.paletteHeadTemplate = pskl.utils.Template.get('palette-details-head-template'); - - // Events - this.palettesList.addEventListener('click', this.onPaletteListClick.bind(this)); - // Delegated event listener for events repeated on all cards - this.paletteBody.addEventListener('click', this.delegatedPaletteBodyClick.bind(this)); - this.paletteHead.addEventListener('click', this.delegatedPaletteHeadClick.bind(this)); - this.createButton.addEventListener('click', this.onCreateClick_.bind(this)); - this.saveAllButton.addEventListener('click', this.saveAll.bind(this)); - - // Init markup - this.createPaletteListMarkup(); - if (this.palettes.length > 0) { - this.selectPalette(this.palettes[0].id); - } else { - this.createPalette('New palette'); - } - }; - - ns.PaletteManagerController.prototype.destroy = function () { - this.destroySpectrumPickers(); - }; - - ns.PaletteManagerController.prototype.onCreateClick_ = function (evt) { - this.createPalette(); - }; - - ns.PaletteManagerController.prototype.createPalette = function (name) { - if (!name) { - name = window.prompt('Please enter a name for your palette', 'New palette'); - } - if (name) { - var palette = this.createPaletteObject(name); - this.palettes.push(palette); - this.createPaletteListMarkup(); - this.selectPalette(palette.id); - } - }; - - ns.PaletteManagerController.prototype.createPaletteObject = function (name) { - return { - id : 'palette-' + Date.now() + '-' + Math.floor(Math.random()*1000), - name : name, - colors : [] - }; - }; - - ns.PaletteManagerController.prototype.redraw = function () { - this.createPaletteListMarkup(); - this.selectPalette(this.selectedPaletteId); - }; - - ns.PaletteManagerController.prototype.selectPalette = function (paletteId) { - this.deselectCurrentPalette(); - var paletteListItem = this.palettesList.querySelector('[data-palette-id='+paletteId+']'); - if (paletteListItem) { - this.selectedPaletteId = paletteId; - paletteListItem.classList.add(SELECTED_CLASSNAME); - this.refreshPaletteDetails(); - } - }; - - ns.PaletteManagerController.prototype.refreshPaletteDetails = function () { - this.createPaletteHeadMarkup(); - this.createPaletteBodyMarkup(); - this.initPaletteDetailsEvents(); - this.initPaletteCardsSpectrum(); - }; - - ns.PaletteManagerController.prototype.createPaletteListMarkup = function () { - var html = this.palettes.map(function (palette) { - var paletteCopy = { - id : palette.id, - name : this.isPaletteModified(palette) ? palette.name + " *" : palette.name - }; - return pskl.utils.Template.replace('
  • {{name}}
  • ', paletteCopy); - }.bind(this)).join(''); - this.palettesList.innerHTML = html; - }; - - /** - * Fill the palette body container with color cards for the selected palette - */ - ns.PaletteManagerController.prototype.createPaletteHeadMarkup = function () { - var palette = this.getSelectedPalette(); - var dict = { - 'name' : palette.name, - 'save:disabled' : !this.isPaletteModified(palette), - 'revert:disabled' : !this.isPaletteModified(palette), - 'delete:disabled' : this.palettes.length < 2 - }; - var html = pskl.utils.Template.replace(this.paletteHeadTemplate, dict); - - this.paletteHead.innerHTML = html; - }; - - ns.PaletteManagerController.prototype.isPaletteModified = function (palette) { - var isModified = false; - var originalPalette = this.getPaletteById(palette.id, this.originalPalettes); - if (originalPalette) { - var differentName = originalPalette.name !== palette.name; - var differentColors = palette.colors.join('') !== originalPalette.colors.join(''); - isModified = differentName || differentColors; - } else { - isModified = true; - } - return isModified; - }; - - /** - * Fill the palette body container with color cards for the selected palette - */ - ns.PaletteManagerController.prototype.createPaletteBodyMarkup = function () { - var palette = this.getSelectedPalette(); - - var html = this.getColorCardsMarkup(palette.colors); - html += pskl.utils.Template.replace(this.newColorTemplate, {classname : NEW_COLOR_CLASS}); - - this.paletteBody.innerHTML = html; - }; - - ns.PaletteManagerController.prototype.initPaletteDetailsEvents = function () { - // New Card click event - var newCard = this.paletteBody.querySelector('.' + NEW_COLOR_CLASS); - newCard.addEventListener('click', this.onNewCardClick.bind(this)); - - if (this.palettes.length < 2) { - var deleteButton = this.paletteHead.querySelector('.palette-manager-palette-button[data-action="delete"]'); - deleteButton.setAttribute("disabled", "disabled"); - } - }; - - ns.PaletteManagerController.prototype.onNewCardClick = function () { - var color; - var palette = this.getSelectedPalette(); - if (palette && palette.colors.length > 0) { - color = palette.colors[palette.colors.length-1]; - } else { - color = '#FFFFFF'; - } - this.addColorInSelectedPalette(color); - }; - - ns.PaletteManagerController.prototype.delegatedPaletteBodyClick = function (event) { - var target = event.target; - if (target.classList.contains(CLOSE_ICON_CLASS)) { - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - this.removeColorInSelectedPalette(colorId); - } - }; - - ns.PaletteManagerController.prototype.delegatedPaletteHeadClick = function (event) { - var target = event.target; - if (target.classList.contains(EDIT_NAME_CLASS)) { - this.renameSelectedPalette(); - } else if (target.classList.contains('palette-manager-palette-button')) { - var action = target.dataset.action; - if (action === 'save') { - this.savePalette(this.getSelectedPalette().id); - this.redraw(); - } else if (action === 'revert') { - this.revertChanges(); - } else if (action === 'delete') { - this.deleteSelectedPalette(); - } - } - }; - - ns.PaletteManagerController.prototype.getSpectrumSelector_ = function () { - return ':not(.' + NEW_COLOR_CLASS + ')>.palette-manager-color-square'; - }; - - ns.PaletteManagerController.prototype.initPaletteCardsSpectrum = function () { - var oSelf = this; - var container = $(this.getSpectrumSelector_()); - container.spectrum({ - clickoutFiresChange : true, - showInput: true, - showButtons: false, - change : function (color) { - var target = this; - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - oSelf.updateColorInSelectedPalette(colorId, color); - }, - beforeShow : function() { - var target = this; - var colorId = parseInt(target.parentNode.dataset.colorId, 10); - var palette = oSelf.getSelectedPalette(); - var color = palette.colors[colorId]; - container.spectrum("set", color); - } - }); - - this.spectrumContainers.push(container); - }; - - /** - * Destroy all spectrum instances generated by the palette manager - */ - ns.PaletteManagerController.prototype.destroySpectrumPickers = function () { - this.spectrumContainers.forEach(function (container) { - container.spectrum("destroy"); - }); - this.spectrumContainers = []; - }; - - ns.PaletteManagerController.prototype.updateColorInSelectedPalette = function (colorId, color) { - var palette = this.getSelectedPalette(); - var hexColor = '#' + (color.toHex().toUpperCase()); - palette.colors.splice(colorId, 1, hexColor); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.addColorInSelectedPalette = function (color) { - var selectedPalette = this.getSelectedPalette(); - selectedPalette.colors.push(color); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.removeColorInSelectedPalette = function (colorId) { - var palette = this.getSelectedPalette(); - palette.colors.splice(colorId, 1); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.renameSelectedPalette = function () { - var palette = this.getSelectedPalette(); - var name = window.prompt('Please enter a new name for palette "' + palette.name + '"', palette.name); - if (name) { - palette.name = name; - this.redraw(); - } - }; - - ns.PaletteManagerController.prototype.getSelectedPalette = function () { - return this.getPaletteById(this.selectedPaletteId, this.palettes); - }; - - ns.PaletteManagerController.prototype.getColorCardsMarkup = function (colors) { - var html = colors.map(function (color, index) { - var dict = { - colorId : index, - hex : color, - rgb : tinycolor(color).toRgbString(), - hsl : tinycolor(color).toHslString() - }; - return pskl.utils.Template.replace(this.colorCardTemplate, dict); - }.bind(this)).join(''); - return html; - }; - - ns.PaletteManagerController.prototype.getPaletteById = function (paletteId, palettes) { - var match = null; - - palettes.forEach(function (palette) { - if (palette.id === paletteId) { - match = palette; - } - }); - - return match; - }; - - ns.PaletteManagerController.prototype.removePaletteById = function (paletteId, palettes) { - var palette = this.getPaletteById(paletteId, palettes); - if (palette) { - var index = palettes.indexOf(palette); - palettes.splice(index, 1); - } - }; - - ns.PaletteManagerController.prototype.deselectCurrentPalette = function () { - var selectedItem = this.palettesList.querySelector('.' + SELECTED_CLASSNAME); - if (selectedItem) { - this.selectedPaletteId = null; - selectedItem.classList.remove(SELECTED_CLASSNAME); - } - }; - - ns.PaletteManagerController.prototype.revertChanges = function () { - var palette = this.getSelectedPalette(); - var originalPalette = this.getPaletteById(palette.id, this.originalPalettes); - palette.name = originalPalette.name; - palette.colors = originalPalette.colors.slice(0); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.deleteSelectedPalette = function () { - var palette = this.getSelectedPalette(); - if (this.palettes.length > 1) { - if (window.confirm('Are you sure you want to delete "' + palette.name + '" ?')) { - this.removePaletteById(palette.id, this.palettes); - this.removePaletteById(palette.id, this.originalPalettes); - - this.persistToLocalStorage(); - - this.createPaletteListMarkup(); - this.selectPalette(this.palettes[0].id); - } - } - }; - - ns.PaletteManagerController.prototype.onPaletteListClick = function (event) { - var target = event.target; - if (target.dataset.paletteId) { - this.selectPalette(target.dataset.paletteId); - } - }; - - ns.PaletteManagerController.prototype.saveAll = function () { - this.palettes.forEach(function (palette) { - this.savePalette(palette.id); - }.bind(this)); - - this.redraw(); - }; - - ns.PaletteManagerController.prototype.savePalette = function (paletteId) { - var palette = this.getPaletteById(paletteId, this.palettes); - var originalPalette = this.getPaletteById(paletteId, this.originalPalettes); - if (originalPalette) { - originalPalette.name = palette.name; - originalPalette.colors = palette.colors; - } else { - this.originalPalettes.push(palette); - } - - this.persistToLocalStorage(); - - $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); - window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); - }; - - ns.PaletteManagerController.prototype.persistToLocalStorage = function () { - window.localStorage.setItem('piskel.palettes', JSON.stringify(this.originalPalettes)); - this.originalPalettes = this.retrieveUserPalettes(); - $.publish(Events.PALETTE_LIST_UPDATED); - }; - - ns.PaletteManagerController.prototype.retrieveUserPalettes = function () { - var palettesString = window.localStorage.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; - }; - -})(); \ No newline at end of file diff --git a/src/js/model/Palette.js b/src/js/model/Palette.js new file mode 100644 index 00000000..d2bc04de --- /dev/null +++ b/src/js/model/Palette.js @@ -0,0 +1,38 @@ +(function () { + var ns = $.namespace('pskl.model'); + + ns.Palette = function (id, name, colors) { + this.id = id; + this.name = name; + this.colors = colors; + }; + + ns.Palette.fromObject = function (paletteObj) { + var colors = paletteObj.colors.slice(0 , paletteObj.colors.length); + return new ns.Palette(paletteObj.id, paletteObj.name, colors); + }; + + ns.Palette.prototype.get = function (index) { + return this.colors[index]; + }; + + ns.Palette.prototype.set = function (index, color) { + this.colors[index] = color; + }; + + ns.Palette.prototype.add = function (color) { + this.colors.push(color); + }; + + ns.Palette.prototype.size = function () { + return this.colors.length; + }; + + ns.Palette.prototype.removeAt = function (index) { + this.colors.splice(index, 1); + }; + + ns.Palette.prototype.move = function (oldIndex, newIndex) { + this.colors.splice(newIndex, 0, this.colors.splice(oldIndex, 1)[0]); + }; +})(); \ No newline at end of file diff --git a/src/js/service/PaletteService.js b/src/js/service/PaletteService.js new file mode 100644 index 00000000..7188ab55 --- /dev/null +++ b/src/js/service/PaletteService.js @@ -0,0 +1,61 @@ +(function () { + var ns = $.namespace('pskl.service'); + ns.PaletteService = function () { + this.palettes = []; + this.localStorageService = window.localStorage; + }; + + ns.PaletteService.prototype.init = function () {}; + + ns.PaletteService.prototype.getPalettes = function () { + var palettesString = this.localStorageService.getItem('piskel.palettes'); + return JSON.parse(palettesString) || []; + }; + + ns.PaletteService.prototype.getPaletteById = function (paletteId) { + var palettes = this.getPalettes(); + return this.findPaletteInArray_(paletteId, palettes); + }; + + ns.PaletteService.prototype.savePalette = function (palette) { + var palettes = this.getPalettes(); + var existingPalette = this.findPaletteInArray_(palette.id, palettes); + if (existingPalette) { + var currentIndex = palettes.indexOf(existingPalette); + palettes.splice(currentIndex, 1, palette); + } else { + palettes.push(palette); + } + + this.savePalettes_(palettes); + + $.publish(Events.SHOW_NOTIFICATION, [{"content": "Palette " + palette.name + " successfully saved !"}]); + window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); + }; + + ns.PaletteService.prototype.deletePaletteById = function (id) { + var palettes = this.getPalettes(); + var filteredPalettes = palettes.filter(function (palette) { + return palette.id !== id; + }); + + this.savePalettes_(filteredPalettes); + }; + + ns.PaletteService.prototype.savePalettes_ = function (palettes) { + this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); + $.publish(Events.PALETTE_LIST_UPDATED); + }; + + ns.PaletteService.prototype.findPaletteInArray_ = function (paletteId, palettes) { + var match = null; + + palettes.forEach(function (palette) { + if (palette.id === paletteId) { + match = palette; + } + }); + + return match; + }; +})(); \ No newline at end of file diff --git a/src/js/utils/Uuid.js b/src/js/utils/Uuid.js new file mode 100644 index 00000000..685d315c --- /dev/null +++ b/src/js/utils/Uuid.js @@ -0,0 +1,17 @@ +(function(){ + var ns = $.namespace('pskl.utils'); + + var s4 = function () { + return Math.floor((1 + Math.random()) * 0x10000) + .toString(16) + .substring(1); + }; + + ns.Uuid = { + generate : function () { + return 'ss-s-s-s-sss'.replace(/s/g, function () { + return s4(); + }); + } + }; +})(); \ No newline at end of file diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 87ecb90e..a699101a 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -25,6 +25,7 @@ "js/utils/PiskelFileUtils.js", "js/utils/Template.js", "js/utils/UserSettings.js", + "js/utils/Uuid.js", "js/utils/Xhr.js", "js/utils/serialization/Serializer.js", "js/utils/serialization/Deserializer.js", @@ -50,6 +51,7 @@ "js/model/Layer.js", "js/model/piskel/Descriptor.js", "js/model/frame/CachedFrameProcessor.js", + "js/model/Palette.js", "js/model/Piskel.js", // Selection @@ -99,9 +101,7 @@ // Dialogs sub-controllers "js/controller/dialogs/AbstractDialogController.js", - "js/controller/dialogs/PaletteManagerController.js", "js/controller/dialogs/CreatePaletteController.js", - "js/controller/dialogs/CreatePaletteMethodController.js", "js/controller/dialogs/ImportImageController.js", "js/controller/dialogs/BrowseLocalController.js", @@ -119,6 +119,7 @@ "js/service/BackupService.js", "js/service/BeforeUnloadService.js", "js/service/HistoryService.js", + "js/service/PaletteService.js", "js/service/SavedStatusService.js", "js/service/keyboard/ShortcutService.js", "js/service/keyboard/KeycodeTranslator.js", diff --git a/src/piskel-style-list.js b/src/piskel-style-list.js index 65ebdcca..e20c191d 100644 --- a/src/piskel-style-list.js +++ b/src/piskel-style-list.js @@ -14,10 +14,8 @@ "css/color-picker-slider.css", "css/dialogs.css", "css/dialogs-import-image.css", - "css/dialogs-manage-palettes.css", "css/dialogs-browse-local.css", "css/dialogs-create-palette.css", - "css/dialogs-create-palette-method.css", "css/toolbox.css", "css/toolbox-layers-list.css", "css/toolbox-palettes-list.css", diff --git a/src/templates/dialogs/create-palette-method.html b/src/templates/dialogs/create-palette-method.html deleted file mode 100644 index 646a942a..00000000 --- a/src/templates/dialogs/create-palette-method.html +++ /dev/null @@ -1,28 +0,0 @@ -
    -

    - Create palette - X -

    -
    - Select your creation method : -
      -
    • - - -
    • -
    • - -
      -
    • -
    • - - - -
    • -
    - - -
    -
    \ No newline at end of file diff --git a/src/templates/dialogs/create-palette.html b/src/templates/dialogs/create-palette.html index a5e48d51..79d783d6 100644 --- a/src/templates/dialogs/create-palette.html +++ b/src/templates/dialogs/create-palette.html @@ -4,12 +4,11 @@ X
    -
    - Name : + Name :
    -
    +
      @@ -46,8 +45,7 @@
      - - +
      + +
      \ No newline at end of file diff --git a/src/templates/dialogs/manage-palettes.html b/src/templates/dialogs/manage-palettes.html deleted file mode 100644 index 3b1dc019..00000000 --- a/src/templates/dialogs/manage-palettes.html +++ /dev/null @@ -1,57 +0,0 @@ -
      -

      - Palette manager - X -

      -
      -
      -
      - - -
      -
        -
      -
      -
      -
      -
      -
      -
      -
      - - - - - - \ No newline at end of file diff --git a/src/templates/palettes-list.html b/src/templates/palettes-list.html index bfffbe50..f103c8eb 100644 --- a/src/templates/palettes-list.html +++ b/src/templates/palettes-list.html @@ -1,18 +1,30 @@
      -

      Palettes -
      +

      -
      +
      dl
      +
      d
      +
      e
        From 9325abb924a9cb89b54b0412d90d16b3feb1c110 Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 13 Sep 2014 20:21:40 +0200 Subject: [PATCH 12/32] Enhancement : Layers merge Added drawing test + fixed drawing test runner on Mac OS X --- src/js/devtools/DrawingTestPlayer.js | 4 ++++ test/drawing/DrawingTests.browser.js | 1 + test/drawing/DrawingTests.casper.js | 1 + test/drawing/tests/layers.merge.json | 1 + 4 files changed, 7 insertions(+) create mode 100644 test/drawing/tests/layers.merge.json diff --git a/src/js/devtools/DrawingTestPlayer.js b/src/js/devtools/DrawingTestPlayer.js index 82dfbf3c..7f72ab80 100644 --- a/src/js/devtools/DrawingTestPlayer.js +++ b/src/js/devtools/DrawingTestPlayer.js @@ -101,6 +101,10 @@ var screenCoordinates = pskl.app.drawingController.getScreenCoordinates(recordEvent.coords.x, recordEvent.coords.y); event.clientX = screenCoordinates.x; event.clientY = screenCoordinates.y; + if (pskl.utils.UserAgent.isMac && event.ctrlKey) { + event.metaKey = true; + } + if (event.type == 'mousedown') { pskl.app.drawingController.onMousedown_(event); } else if (event.type == 'mouseup') { diff --git a/test/drawing/DrawingTests.browser.js b/test/drawing/DrawingTests.browser.js index fa7a32d7..7db7ef2b 100644 --- a/test/drawing/DrawingTests.browser.js +++ b/test/drawing/DrawingTests.browser.js @@ -4,6 +4,7 @@ "color.picker.json", "frames.fun.json", "layers.fun.json", + "layers.merge.json", "lighten.darken.json", "move.json", "pen.secondary.color.json", diff --git a/test/drawing/DrawingTests.casper.js b/test/drawing/DrawingTests.casper.js index 68e8b83f..6dd57335 100644 --- a/test/drawing/DrawingTests.casper.js +++ b/test/drawing/DrawingTests.casper.js @@ -3,6 +3,7 @@ "color.picker.json", "frames.fun.json", "layers.fun.json", + "layers.merge.json", "move.json", "pen.secondary.color.json", "squares.circles.json", diff --git a/test/drawing/tests/layers.merge.json b/test/drawing/tests/layers.merge.json new file mode 100644 index 00000000..5262e828 --- /dev/null +++ b/test/drawing/tests/layers.merge.json @@ -0,0 +1 @@ +{"events":[{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":0},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":0},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":0},"type":"mouse-event"},{"type":"instrumented-event","methodName":"createLayer","args":[]},{"type":"color-event","color":"#942d2d","isPrimary":true},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":1,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":1},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"type":"instrumented-event","methodName":"createLayer","args":[]},{"type":"color-event","color":"#2d9430","isPrimary":true},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":2,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":4},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":3},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":2},"type":"mouse-event"},{"event":{"type":"mousemove","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":3,"y":3},"type":"mouse-event"},{"type":"instrumented-event","methodName":"moveLayerDown","args":[]},{"type":"instrumented-event","methodName":"mergeDownLayerAt","args":["2"]},{"type":"instrumented-event","methodName":"mergeDownLayerAt","args":["1"]},{"type":"tool-event","toolId":"tool-paint-bucket"},{"type":"color-event","color":"#2d5994","isPrimary":true},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":4},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":0,"y":4},"type":"mouse-event"},{"event":{"type":"mousedown","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"},{"event":{"type":"mouseup","button":0,"shiftKey":false,"altKey":false,"ctrlKey":false},"coords":{"x":4,"y":0},"type":"mouse-event"}],"initialState":{"size":{"width":5,"height":5},"primaryColor":"#000000","secondaryColor":"rgba(0, 0, 0, 0)","selectedTool":"tool-pen"},"png":"data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAN0lEQVQIW2NkYGD4D8RgoBs5BUwzggSn6OrCxBlm6qRjEUxnZmAEavmffmUmQiVMECxiPQcuAQAoxRAISNM8EgAAAABJRU5ErkJggg=="} \ No newline at end of file From 12dcacea5a2280fc6b6430a177169875351db543 Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 13 Sep 2014 20:32:01 +0200 Subject: [PATCH 13/32] increased the timeout for Travis tests --- Gruntfile.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Gruntfile.js b/Gruntfile.js index 6872f830..ffa321b8 100644 --- a/Gruntfile.js +++ b/Gruntfile.js @@ -36,7 +36,7 @@ module.exports = function(grunt) { }, 'travis' : { suite : './test/casperjs/TravisTestSuite.js', - delay : 5000 + delay : 10000 } }; From fab9c6e8365d218eefa6f966938e616a823946bd Mon Sep 17 00:00:00 2001 From: jdescottes Date: Tue, 16 Sep 2014 00:37:24 +0200 Subject: [PATCH 14/32] select new palette after saving --- src/css/dialogs-create-palette.css | 2 +- src/js/controller/PalettesListController.js | 25 ++++++++++++------- .../dialogs/CreatePaletteController.js | 12 ++++++--- .../service/palette/PaletteImportService.js | 22 +++++++++------- 4 files changed, 39 insertions(+), 22 deletions(-) diff --git a/src/css/dialogs-create-palette.css b/src/css/dialogs-create-palette.css index 57c04941..82b2260f 100644 --- a/src/css/dialogs-create-palette.css +++ b/src/css/dialogs-create-palette.css @@ -65,7 +65,7 @@ } .colors-list { - overflow : hidden; + overflow : auto; width : 280px; } diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 11522faf..86ce65f3 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -38,9 +38,10 @@ $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); $.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); + $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); this.fillPaletteList(); - this.selectPaletteFromUserSettings(); + this.updateFromUserSettings(); this.fillColorListContainer(); }; @@ -77,7 +78,7 @@ ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { var colors = []; - var paletteId = this.colorPaletteSelect_.value; + var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); if (paletteId === Constants.CURRENT_COLORS_PALETTE_ID) { colors = this.usedColorService.getCurrentColors(); } else { @@ -94,18 +95,25 @@ return colors; }; - ns.PalettesListController.prototype.selectPaletteFromUserSettings = function () { - this.selectPalette(pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE)); + ns.PalettesListController.prototype.selectPalette = function (paletteId) { + pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); }; - ns.PalettesListController.prototype.selectPalette = function (paletteId) { + ns.PalettesListController.prototype.onUserSettingsChange_ = function (evt, name, value) { + if (name == pskl.UserSettings.SELECTED_PALETTE) { + this.updateFromUserSettings(); + } + }; + + ns.PalettesListController.prototype.updateFromUserSettings = function () { + var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); + this.fillColorListContainer(); this.colorPaletteSelect_.value = paletteId; }; ns.PalettesListController.prototype.onPaletteSelected_ = function (evt) { var paletteId = this.colorPaletteSelect_.value; - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); - this.fillColorListContainer(); + this.selectPalette(paletteId); }; ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) { @@ -191,7 +199,6 @@ ns.PalettesListController.prototype.onPaletteListUpdated = function () { this.fillPaletteList(); - this.selectPaletteFromUserSettings(); - this.fillColorListContainer(); + this.updateFromUserSettings(); }; })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteController.js b/src/js/controller/dialogs/CreatePaletteController.js index c9f7a853..1e0cde6b 100644 --- a/src/js/controller/dialogs/CreatePaletteController.js +++ b/src/js/controller/dialogs/CreatePaletteController.js @@ -120,16 +120,22 @@ }; ns.CreatePaletteController.prototype.onSubmitButtonClick_ = function (evt) { - this.paletteService.savePalette(this.palette); + this.saveAndSelectPalette_(this.palette); this.closeDialog(); }; ns.CreatePaletteController.prototype.onCloneButtonClick_ = function (evt) { - var palette = new pskl.model.Palette(pskl.utils.Uuid.generate(), this.palette.name, this.palette.colors); - this.paletteService.savePalette(palette); + var uuid = pskl.utils.Uuid.generate(); + var palette = new pskl.model.Palette(uuid, this.palette.name, this.palette.colors); + this.saveAndSelectPalette_(palette); this.closeDialog(); }; + ns.CreatePaletteController.prototype.saveAndSelectPalette_ = function (palette) { + this.paletteService.savePalette(palette); + pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, palette.id); + }; + ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () { this.hiddenFileInput.click(); }; diff --git a/src/js/service/palette/PaletteImportService.js b/src/js/service/palette/PaletteImportService.js index d0ec4e60..fe618dac 100644 --- a/src/js/service/palette/PaletteImportService.js +++ b/src/js/service/palette/PaletteImportService.js @@ -9,7 +9,7 @@ ns.PaletteImportService = function () {}; ns.PaletteImportService.prototype.read = function (file, onSuccess, onError) { - var reader = this.getFileReader_(file, onSuccess, onError); + var reader = this.getReader_(file, onSuccess, onError); if (reader) { reader.read(); } else { @@ -21,20 +21,24 @@ return file.type.indexOf('image') === 0; }; - ns.PaletteImportService.prototype.getFileReader_ = function (file, onSuccess, onError) { + ns.PaletteImportService.prototype.getReader_ = function (file, onSuccess, onError) { var readerClass = this.getReaderClass_(file); - - var reader = null; if (readerClass) { - reader = new readerClass(file, onSuccess, onError); + return new readerClass(file, onSuccess, onError); + } else { + return null; } - - return reader; }; ns.PaletteImportService.prototype.getReaderClass_ = function (file) { - var extension = this.getExtension_(file); - return fileReaders[extension]; + var readerClass; + if (this.isImage_(file)) { + readerClass = ns.PaletteImageReader; + } else { + var extension = this.getExtension_(file); + readerClass = fileReaders[extension]; + } + return readerClass; }; ns.PaletteImportService.prototype.getExtension_ = function (file) { From 8ebdc4cd41d4744cbb9926b086801f329982024f Mon Sep 17 00:00:00 2001 From: jdescottes Date: Wed, 17 Sep 2014 01:32:59 +0200 Subject: [PATCH 15/32] Enhancement palettes : Added download palette - palettes can be downloaded as GPL palettes - slightly tweaked the UI of hsl rgb picker - switched preferred format of spectrum to hex --- src/css/color-picker-slider.css | 2 +- src/js/controller/PalettesListController.js | 11 +++- .../controller/widgets/HslRgbColorPicker.js | 3 +- src/js/lib/spectrum/spectrum.js | 3 +- src/js/service/keyboard/CheatsheetService.js | 14 +++++ src/js/service/palette/PaletteGplWriter.js | 58 +++++++++++++++++++ src/piskel-script-list.js | 1 + 7 files changed, 87 insertions(+), 5 deletions(-) create mode 100644 src/js/service/palette/PaletteGplWriter.js diff --git a/src/css/color-picker-slider.css b/src/css/color-picker-slider.css index 05156f72..8c3cdda6 100644 --- a/src/css/color-picker-slider.css +++ b/src/css/color-picker-slider.css @@ -82,7 +82,7 @@ float:left; height : 10px; width : 100px; - margin: 7px 5px; + margin: 7px 1px 7px 8px; } .color-picker-slider input[type="text"]{ diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 86ce65f3..300dd2a1 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -149,7 +149,16 @@ }; ns.PalettesListController.prototype.downloadSelectedPalette_ = function () { - window.alert('not implemented yet'); + // getSelectedPalette + var paletteId = this.colorPaletteSelect_.value; + var palette = this.paletteService.getPaletteById(paletteId); + + var paletteWriter = new pskl.service.palette.PaletteGplWriter(palette); + var paletteAsString = paletteWriter.write(); + + pskl.utils.BlobUtils.stringToBlob(paletteAsString, function(blob) { + pskl.utils.FileUtils.downloadAsFile(blob, palette.name + '.gpl'); + }.bind(this), "application/json"); }; ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { diff --git a/src/js/controller/widgets/HslRgbColorPicker.js b/src/js/controller/widgets/HslRgbColorPicker.js index a046035c..a83adaec 100644 --- a/src/js/controller/widgets/HslRgbColorPicker.js +++ b/src/js/controller/widgets/HslRgbColorPicker.js @@ -20,7 +20,8 @@ showInput: true, showButtons: false, move : this.setColor.bind(this), - change : this.setColor.bind(this) + change : this.setColor.bind(this), + preferredFormat: 'hex' }); this.setColor("#000000"); diff --git a/src/js/lib/spectrum/spectrum.js b/src/js/lib/spectrum/spectrum.js index bc378df1..b60d3894 100644 --- a/src/js/lib/spectrum/spectrum.js +++ b/src/js/lib/spectrum/spectrum.js @@ -669,10 +669,9 @@ } } - // Update the text entry input as it changes happen if (opts.showInput) { - textInput.val(realColor.toString(Constants.PREFERRED_COLOR_FORMAT || format)); + textInput.val(realColor.toString(format)); } if (opts.showPalette) { diff --git a/src/js/service/keyboard/CheatsheetService.js b/src/js/service/keyboard/CheatsheetService.js index 03c085bc..56818073 100644 --- a/src/js/service/keyboard/CheatsheetService.js +++ b/src/js/service/keyboard/CheatsheetService.js @@ -14,13 +14,27 @@ pskl.app.shortcutService.addShortcut('shift+?', this.toggleCheatsheet_.bind(this)); pskl.app.shortcutService.addShortcut('?', this.toggleCheatsheet_.bind(this)); + document.body.addEventListener('click', this.onBodyClick_.bind(this)); + var link = $('.cheatsheet-link'); link.click(this.toggleCheatsheet_.bind(this)); + $.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this)); $.subscribe(Events.ESCAPE, this.onEscape_.bind(this)); }; + ns.CheatsheetService.prototype.onBodyClick_ = function (event) { + if (this.isDisplayed_) { + var target = event.target; + var cheatsheetContainerEl = document.querySelector('.cheatsheet-container'); + var isInCheatsheetContainer = pskl.utils.Dom.isParent(target, cheatsheetContainerEl); + if (!isInCheatsheetContainer) { + this.hideCheatsheet_(); + } + } + }; + ns.CheatsheetService.prototype.toggleCheatsheet_ = function () { if (this.isDisplayed_) { this.hideCheatsheet_(); diff --git a/src/js/service/palette/PaletteGplWriter.js b/src/js/service/palette/PaletteGplWriter.js new file mode 100644 index 00000000..30c9fa2a --- /dev/null +++ b/src/js/service/palette/PaletteGplWriter.js @@ -0,0 +1,58 @@ +(function () { + var ns = $.namespace('pskl.service.palette'); + + ns.PaletteGplWriter = function (palette, onSuccess, onError) { + this.palette = palette; + this.onSuccess = onSuccess; + this.onError = onError; + }; + + ns.PaletteGplWriter.prototype.write = function () { + var lines = []; + lines.push('GIMP Palette'); + lines.push('Name: ' + this.palette.name); + lines.push('Columns: 0'); + lines.push('#'); + this.palette.colors.forEach(function (color) { + lines.push(this.writeColorLine(color)); + }.bind(this)); + lines.push('\r\n'); + + return lines.join('\r\n'); + }; + + ns.PaletteGplWriter.prototype.writeColorLine = function (color) { + var tinycolor = window.tinycolor(color); + var rgb = tinycolor.toRgb(); + var strBuffer = []; + strBuffer.push(this.padString(rgb.r, 3)); + strBuffer.push(this.padString(rgb.g, 3)); + strBuffer.push(this.padString(rgb.b, 3)); + strBuffer.push('Untitled'); + + return strBuffer.join(' '); + }; + + ns.PaletteGplWriter.prototype.padString = function (str, size) { + str = str.toString(); + for (var i = 0 ; i < size-str.length ; i++) { + str = ' ' + str; + } + return str; + }; + +})(); + +// GIMP Palette +// Name: Fabric_jeans +// Columns: 0 +// # +// 194 198 201 Untitled +// 173 180 194 Untitled +// 123 126 145 Untitled +// 91 136 195 Untitled +// 41 52 74 Untitled +// 20 25 37 Untitled +// 164 156 145 Untitled +// 103 92 82 Untitled +// 87 58 107 Untitled diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 55892ca9..7d34b17d 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -122,6 +122,7 @@ "js/service/palette/PaletteService.js", "js/service/palette/PaletteTxtReader.js", "js/service/palette/PaletteGplReader.js", + "js/service/palette/PaletteGplWriter.js", "js/service/palette/PaletteImageReader.js", "js/service/palette/PaletteImportService.js", "js/service/SavedStatusService.js", From 508fb79c32cee26e3aae55cffd2a89cd9bc205ce Mon Sep 17 00:00:00 2001 From: jdescottes Date: Thu, 18 Sep 2014 07:18:07 +0200 Subject: [PATCH 16/32] Homogeneize layout, drop palette --- src/css/dialogs-create-palette.css | 7 +- src/css/icons.css | 14 ++- src/css/toolbox-layers-list.css | 42 ++++++--- src/css/toolbox-palettes-list.css | 54 ++++++++---- src/css/toolbox.css | 19 ---- src/js/app.js | 1 + src/js/controller/PalettesListController.js | 56 ++---------- .../dialogs/AbstractDialogController.js | 7 ++ .../dialogs/CreatePaletteController.js | 88 +++++++++++-------- .../widgets/ColorsListController.js | 8 ++ src/js/model/Palette.js | 4 + src/js/service/FileDropperService.js | 19 ++-- .../service/palette/CurrentColorsPalette.js | 12 +++ src/js/service/palette/PaletteGplReader.js | 2 +- src/js/service/palette/PaletteGplWriter.js | 26 +----- src/js/service/palette/PaletteService.js | 16 +++- src/piskel-script-list.js | 1 + src/templates/dialogs/create-palette.html | 11 ++- src/templates/layers-list.html | 26 ++++-- src/templates/palettes-list.html | 30 ++----- test/js/service/palette/PaletteServiceTest.js | 4 +- 21 files changed, 245 insertions(+), 202 deletions(-) create mode 100644 src/js/controller/widgets/ColorsListController.js create mode 100644 src/js/service/palette/CurrentColorsPalette.js diff --git a/src/css/dialogs-create-palette.css b/src/css/dialogs-create-palette.css index 82b2260f..3f4856ee 100644 --- a/src/css/dialogs-create-palette.css +++ b/src/css/dialogs-create-palette.css @@ -65,8 +65,11 @@ } .colors-list { - overflow : auto; - width : 280px; + overflow: auto; + width: 280px; + box-sizing: border-box; + height: 100%; + padding-bottom: 10px; } .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ diff --git a/src/css/icons.css b/src/css/icons.css index 809ce976..51e9c20d 100644 --- a/src/css/icons.css +++ b/src/css/icons.css @@ -5,10 +5,20 @@ background-position: 50%; } -.action-icon.edit-icon { +.edit-icon { background-image: url('../img/tools/pen.png'); + background-repeat: no-repeat; } -.action-icon.merge-icon { +.merge-icon { background-image: url('../img/merge-icon.png'); + background-repeat: no-repeat; +} + +.plus-icon { + font-size:15px; + text-align:center; +} + +.delete-icon { } \ No newline at end of file diff --git a/src/css/toolbox-layers-list.css b/src/css/toolbox-layers-list.css index 1b43b338..61a96d88 100644 --- a/src/css/toolbox-layers-list.css +++ b/src/css/toolbox-layers-list.css @@ -5,18 +5,21 @@ .layers-list-container { } -.layers-title { +/*.layers-title { background-image: url('../img/layers.svg'); background-size: 22px; background-repeat: no-repeat; background-position: 97%; +}*/ + +.layers-title { position: relative; } .layers-toggle-preview { position: absolute; top: 0.3em; - right: 2em; + right: 0.5em; color: #999; font-size: 1.3em; @@ -60,16 +63,6 @@ opacity : 1; } -.layer-item .edit-icon { - width: 25px; - background-size: 12px; -} - -.layer-item .merge-icon { - width: 18px; - background-size: 16px; -} - .layer-item:last-child .merge-icon { display : none; } @@ -87,4 +80,29 @@ .layers-button-arrow { font-family : 'Lucida Grande', Calibri; padding : 2px 6px 0 6px; +} + +.layers-button-container { + overflow : hidden; +} + +.layers-button { + margin: 0; + width: 16.66667%; + float : left; +} + +/* @override */ +.layers-button-container .layers-button { + border-left-width: 0; +} + +.layers-button:last-child { + border-right-width: 0; +} + +.layers-button-container .merge-icon, +.layers-button-container .edit-icon { + background-size : 15px; + background-position : 50%; } \ No newline at end of file diff --git a/src/css/toolbox-palettes-list.css b/src/css/toolbox-palettes-list.css index 64d64218..a1db618a 100644 --- a/src/css/toolbox-palettes-list.css +++ b/src/css/toolbox-palettes-list.css @@ -60,23 +60,43 @@ border-left-color: transparent; } -.palette-action { - width : 18px; - height : 18px; - line-height : 16px; - - text-align:center; - float : right; - font-size : 12px; - border: 1px solid gold; - border-radius : 2px; - box-sizing : border-box; - margin : 3px 3px 3px 0; - - cursor : pointer; - transition : color 0.3s; +.palettes-list-actions { + background-color: #3f3f3f; + border-bottom-color: #222; + height: 24px; + padding: 0; + overflow: hidden; } -.palette-action:hover { - color : gold; +.palettes-list-button { + margin: 0; + width: 36px; + float: left; +} + +.palettes-list-select { + float: left; + width: 66.66667%; + height: 100%; + + margin: 0; + padding: 0 5px 0 5px; + + background: #3f3f3f; + + border-style : solid; + border-top-color: #666; + border-bottom-color: #222; + border-width: 1px 0 1px 0; + + color: white; +} + +.palettes-list-select:focus { + outline:none; +} + +.palettes-list-actions .edit-icon { + background-size : 15px; + background-position : 50%; } \ No newline at end of file diff --git a/src/css/toolbox.css b/src/css/toolbox.css index e449eb8a..6f157486 100644 --- a/src/css/toolbox.css +++ b/src/css/toolbox.css @@ -14,23 +14,4 @@ margin: 0; font-size: 15px; background: #222; -} - -.toolbox-button-container { - overflow : hidden; -} - -.toolbox-button { - margin: 0; - width: 25%; - float : left; -} - -/* @override */ -.button.toolbox-button { - border-left-width: 0; -} - -.toolbox-button:last-child { - border-right-width: 0; } \ No newline at end of file diff --git a/src/js/app.js b/src/js/app.js index f138823f..a6fcd4a5 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -40,6 +40,7 @@ this.paletteImportService = new pskl.service.palette.PaletteImportService(); this.paletteService = new pskl.service.palette.PaletteService(); + this.paletteService.addDynamicPalette(new pskl.service.palette.CurrentColorsPalette()); this.paletteController = new pskl.controller.PaletteController(); this.paletteController.init(); diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 300dd2a1..82c50180 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -24,15 +24,14 @@ this.colorPaletteSelect_ = document.querySelector('.palettes-list-select'); var createPaletteButton_ = document.querySelector('.create-palette-button'); - var paletteActions = document.querySelector('.palette-actions'); + var editPaletteButton_ = document.querySelector('.edit-palette-button'); this.colorPaletteSelect_.addEventListener('change', this.onPaletteSelected_.bind(this)); this.colorListContainer_.addEventListener('mouseup', this.onColorContainerMouseup.bind(this)); this.colorListContainer_.addEventListener('contextmenu', this.onColorContainerContextMenu.bind(this)); createPaletteButton_.addEventListener('click', this.onCreatePaletteClick_.bind(this)); - paletteActions.addEventListener('click', this.onPaletteActionsClick_.bind(this)); - + editPaletteButton_.addEventListener('click', this.onEditPaletteClick_.bind(this)); $.subscribe(Events.PALETTE_LIST_UPDATED, this.onPaletteListUpdated.bind(this)); $.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this)); @@ -46,11 +45,7 @@ }; ns.PalettesListController.prototype.fillPaletteList = function () { - var palettes = [{ - id : Constants.CURRENT_COLORS_PALETTE_ID, - name : 'Current colors' - }]; - palettes = palettes.concat(this.paletteService.getPalettes()); + var palettes = this.paletteService.getPalettes(); var html = palettes.map(function (palette) { return pskl.utils.Template.replace('', palette); @@ -79,13 +74,9 @@ ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { var colors = []; var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - if (paletteId === Constants.CURRENT_COLORS_PALETTE_ID) { - colors = this.usedColorService.getCurrentColors(); - } else { - var palette = this.paletteService.getPaletteById(paletteId); - if (palette) { - colors = palette.colors; - } + var palette = this.paletteService.getPaletteById(paletteId); + if (palette) { + colors = palette.getColors(); } if (colors.length > Constants.MAX_CURRENT_COLORS_DISPLAYED) { @@ -120,18 +111,7 @@ $.publish(Events.DIALOG_DISPLAY, 'create-palette'); }; - ns.PalettesListController.prototype.onPaletteActionsClick_ = function (evt) { - var classList = evt.target.classList; - if (classList.contains('palette-action-edit')) { - this.editSelectedPalette_(); - } else if (classList.contains('palette-action-delete')) { - this.deleteSelectedPalette_(); - } else if (classList.contains('palette-action-download')) { - this.downloadSelectedPalette_(); - } - }; - - ns.PalettesListController.prototype.editSelectedPalette_ = function () { + ns.PalettesListController.prototype.onEditPaletteClick_ = function (evt) { var paletteId = this.colorPaletteSelect_.value; $.publish(Events.DIALOG_DISPLAY, { dialogId : 'create-palette', @@ -139,28 +119,6 @@ }); }; - ns.PalettesListController.prototype.deleteSelectedPalette_ = function () { - var paletteId = this.colorPaletteSelect_.value; - var palette = this.paletteService.getPaletteById(paletteId); - if (window.confirm('Are you sure you want to delete palette ' + palette.name)) { - this.paletteService.deletePaletteById(palette.id); - this.selectPalette(Constants.CURRENT_COLORS_PALETTE_ID); - } - }; - - ns.PalettesListController.prototype.downloadSelectedPalette_ = function () { - // getSelectedPalette - var paletteId = this.colorPaletteSelect_.value; - var palette = this.paletteService.getPaletteById(paletteId); - - var paletteWriter = new pskl.service.palette.PaletteGplWriter(palette); - var paletteAsString = paletteWriter.write(); - - pskl.utils.BlobUtils.stringToBlob(paletteAsString, function(blob) { - pskl.utils.FileUtils.downloadAsFile(blob, palette.name + '.gpl'); - }.bind(this), "application/json"); - }; - ns.PalettesListController.prototype.onColorContainerContextMenu = function (event) { event.preventDefault(); }; diff --git a/src/js/controller/dialogs/AbstractDialogController.js b/src/js/controller/dialogs/AbstractDialogController.js index 00f28ebf..130d351e 100644 --- a/src/js/controller/dialogs/AbstractDialogController.js +++ b/src/js/controller/dialogs/AbstractDialogController.js @@ -16,4 +16,11 @@ $.publish(Events.DIALOG_HIDE); }; + ns.AbstractDialogController.prototype.setTitle = function (title) { + var dialogHead = document.querySelector('.dialog-head'); + if (dialogHead) { + dialogHead.innerText = title; + } + }; + })(); \ No newline at end of file diff --git a/src/js/controller/dialogs/CreatePaletteController.js b/src/js/controller/dialogs/CreatePaletteController.js index 1e0cde6b..03ff9e3f 100644 --- a/src/js/controller/dialogs/CreatePaletteController.js +++ b/src/js/controller/dialogs/CreatePaletteController.js @@ -1,11 +1,6 @@ (function () { var ns = $.namespace('pskl.controller.dialogs'); - var MODE = { - CREATE : 'CREATE', - EDIT : 'EDIT' - }; - ns.CreatePaletteController = function (piskelController) { this.paletteService = pskl.app.paletteService; this.paletteImportService = pskl.app.paletteImportService; @@ -23,34 +18,50 @@ this.hiddenFileInput = document.querySelector('.create-palette-import-input'); this.nameInput = document.querySelector('input[name="palette-name"]'); - var submitButton = document.querySelector('.create-palette-submit'); - var cloneButton = document.querySelector('.create-palette-clone'); - var cancelButton = document.querySelector('.create-palette-cancel'); + var buttonsContainer = document.querySelector('.create-palette-actions'); + var deleteButton = document.querySelector('.create-palette-delete'); + var downloadButton = document.querySelector('.create-palette-download-button'); var importFileButton = document.querySelector('.create-palette-import-button'); this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this)); this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this)); this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this)); - submitButton.addEventListener('click', this.onSubmitButtonClick_.bind(this)); - cloneButton.addEventListener('click', this.onCloneButtonClick_.bind(this)); - cancelButton.addEventListener('click', this.closeDialog.bind(this)); + buttonsContainer.addEventListener('click', this.onButtonClick_.bind(this)); + downloadButton.addEventListener('click', this.onDownloadButtonClick_.bind(this)); importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this)); + $('.colors-list').sortable({ + placeholder: 'colors-list-drop-proxy', + update: this.onColorDrop_.bind(this), + items: '.create-palette-color' + }); + var colorPickerContainer = document.querySelector('.color-picker-container'); this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this)); this.hslRgbColorPicker.init(); var palette; - if (paletteId) { + var isCurrentColorsPalette = paletteId == Constants.CURRENT_COLORS_PALETTE_ID; + if (paletteId && !isCurrentColorsPalette) { var paletteObject = this.paletteService.getPaletteById(paletteId); palette = pskl.model.Palette.fromObject(paletteObject); importFileButton.style.display = 'none'; - this.mode = MODE.EDIT; + this.setTitle('Edit Palette'); } else { - palette = new pskl.model.Palette(pskl.utils.Uuid.generate(), 'New palette', ['#000000']); - cloneButton.style.display = 'none'; - this.mode = MODE.CREATE; + if (isCurrentColorsPalette) { + var currentColorsPalette = this.paletteService.getPaletteById(Constants.CURRENT_COLORS_PALETTE_ID); + var colors = currentColorsPalette.getColors(); + if (!colors.length) { + colors = ['#000000']; + } + palette = new pskl.model.Palette(pskl.utils.Uuid.generate(), 'Current colors clone', colors); + } else { + palette = new pskl.model.Palette(pskl.utils.Uuid.generate(), 'New palette', ['#000000']); + } + downloadButton.style.display = 'none'; + deleteButton.style.display = 'none'; + this.setTitle('Create Palette'); } this.setPalette_(palette); @@ -119,16 +130,20 @@ this.selectColor_(this.palette.size()-1); }; - ns.CreatePaletteController.prototype.onSubmitButtonClick_ = function (evt) { - this.saveAndSelectPalette_(this.palette); - this.closeDialog(); - }; - - ns.CreatePaletteController.prototype.onCloneButtonClick_ = function (evt) { - var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, this.palette.name, this.palette.colors); - this.saveAndSelectPalette_(palette); - this.closeDialog(); + ns.CreatePaletteController.prototype.onButtonClick_ = function (evt) { + var target = evt.target; + if (target.dataset.action === 'submit') { + this.saveAndSelectPalette_(this.palette); + this.closeDialog(); + } else if (target.dataset.action === 'cancel') { + this.closeDialog(); + } else if (target.dataset.action === 'delete') { + if (window.confirm('Are you sure you want to delete palette ' + this.palette.name)) { + this.paletteService.deletePaletteById(this.palette.id); + pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, Constants.CURRENT_COLORS_PALETTE_ID); + this.closeDialog(); + } + } }; ns.CreatePaletteController.prototype.saveAndSelectPalette_ = function (palette) { @@ -136,6 +151,15 @@ pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, palette.id); }; + ns.CreatePaletteController.prototype.onDownloadButtonClick_ = function () { + var paletteWriter = new pskl.service.palette.PaletteGplWriter(this.palette); + var paletteAsString = paletteWriter.write(); + + pskl.utils.BlobUtils.stringToBlob(paletteAsString, function(blob) { + pskl.utils.FileUtils.downloadAsFile(blob, this.palette.name + '.gpl'); + }.bind(this), "application/json"); + }; + ns.CreatePaletteController.prototype.onImportFileButtonClick_ = function () { this.hiddenFileInput.click(); }; @@ -164,13 +188,13 @@ ns.CreatePaletteController.prototype.refresh_ = function () { var html = ""; var tpl = pskl.utils.Template.get('create-palette-color-template'); - var colors = this.palette.colors; + var colors = this.palette.getColors(); colors.forEach(function (color, index) { var isSelected = (index === this.selectedIndex); html += pskl.utils.Template.replace(tpl, { - color:color, index:index, + 'color':color, index:index, ':selected':isSelected, ':light-color':this.isLight_(color) }); @@ -179,12 +203,6 @@ html += '
      • +
      • '; this.colorsList.innerHTML = html; - - $('.colors-list').sortable({ - placeholder: 'colors-list-drop-proxy', - update: this.onDrop_.bind(this), - items: '.create-palette-color' - }); }; ns.CreatePaletteController.prototype.isLight_ = function (color) { @@ -193,7 +211,7 @@ }; - ns.CreatePaletteController.prototype.onDrop_ = function (evt, drop) { + ns.CreatePaletteController.prototype.onColorDrop_ = function (evt, drop) { var colorElement = drop.item.get(0); var oldIndex = parseInt(colorElement.dataset.paletteIndex, 10); diff --git a/src/js/controller/widgets/ColorsListController.js b/src/js/controller/widgets/ColorsListController.js new file mode 100644 index 00000000..903ec27d --- /dev/null +++ b/src/js/controller/widgets/ColorsListController.js @@ -0,0 +1,8 @@ +(function () { + var ns = $.namespace('pskl.controller.widgets'); + + ns.ColorsListController = function (container) { + this.container = container; + this.colorsList = this.container.querySelector('.colors-list'); + }; +})(); \ No newline at end of file diff --git a/src/js/model/Palette.js b/src/js/model/Palette.js index d2bc04de..ef1709a2 100644 --- a/src/js/model/Palette.js +++ b/src/js/model/Palette.js @@ -12,6 +12,10 @@ return new ns.Palette(paletteObj.id, paletteObj.name, colors); }; + ns.Palette.prototype.getColors = function () { + return this.colors; + }; + ns.Palette.prototype.get = function (index) { return this.colors[index]; }; diff --git a/src/js/service/FileDropperService.js b/src/js/service/FileDropperService.js index bf9104ad..5bc2a3c3 100644 --- a/src/js/service/FileDropperService.js +++ b/src/js/service/FileDropperService.js @@ -31,14 +31,27 @@ for (var i = 0; i < files.length ; i++) { var file = files[i]; var isImage = file.type.indexOf('image') === 0; + var isPiskel = /\.piskel$/i.test(file.name); + var isPalette = /\.(gpl|txt)$/i.test(file.name); if (isImage) { this.readImageFile_(file); - } else if (/\.piskel$/i.test(file.name)) { + } else if (isPiskel) { pskl.utils.PiskelFileUtils.loadFromFile(file, this.onPiskelFileLoaded_); + } else if (isPalette) { + pskl.app.paletteImportService.read(file, this.onPaletteLoaded_.bind(this)); } } }; + ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { + pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); + }; + + ns.FileDropperService.prototype.onPaletteLoaded_ = function (palette) { + pskl.app.paletteService.savePalette(palette); + pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, palette.id); + }; + ns.FileDropperService.prototype.onPiskelFileLoaded_ = function (piskel, descriptor, fps) { if (window.confirm('This will replace your current animation')) { piskel.setDescriptor(descriptor); @@ -47,10 +60,6 @@ } }; - ns.FileDropperService.prototype.readImageFile_ = function (imageFile) { - pskl.utils.FileUtils.readFile(imageFile, this.processImageSource_.bind(this)); - }; - ns.FileDropperService.prototype.processImageSource_ = function (imageSource) { this.importedImage_ = new Image(); this.importedImage_.onload = this.onImageLoaded_.bind(this); diff --git a/src/js/service/palette/CurrentColorsPalette.js b/src/js/service/palette/CurrentColorsPalette.js new file mode 100644 index 00000000..2120872b --- /dev/null +++ b/src/js/service/palette/CurrentColorsPalette.js @@ -0,0 +1,12 @@ +(function () { + var ns = $.namespace('pskl.service.palette'); + + ns.CurrentColorsPalette = function () { + this.name = 'Current colors'; + this.id = Constants.CURRENT_COLORS_PALETTE_ID; + }; + + ns.CurrentColorsPalette.prototype.getColors = function () { + return pskl.app.currentColorsService.getCurrentColors(); + }; +})(); \ No newline at end of file diff --git a/src/js/service/palette/PaletteGplReader.js b/src/js/service/palette/PaletteGplReader.js index 11d10f34..76173859 100644 --- a/src/js/service/palette/PaletteGplReader.js +++ b/src/js/service/palette/PaletteGplReader.js @@ -1,7 +1,7 @@ (function () { var ns = $.namespace('pskl.service.palette'); - var RE_COLOR_LINE = /^(\d{1,3}\s+)(\d{1,3}\s+)(\d{1,3}\s+)/; + var RE_COLOR_LINE = /^(\s*\d{1,3})(\s*\d{1,3})(\s*\d{1,3})/; var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i; ns.PaletteGplReader = function (file, onSuccess, onError) { diff --git a/src/js/service/palette/PaletteGplWriter.js b/src/js/service/palette/PaletteGplWriter.js index 30c9fa2a..4d8ae0ae 100644 --- a/src/js/service/palette/PaletteGplWriter.js +++ b/src/js/service/palette/PaletteGplWriter.js @@ -1,10 +1,8 @@ (function () { var ns = $.namespace('pskl.service.palette'); - ns.PaletteGplWriter = function (palette, onSuccess, onError) { + ns.PaletteGplWriter = function (palette) { this.palette = palette; - this.onSuccess = onSuccess; - this.onError = onError; }; ns.PaletteGplWriter.prototype.write = function () { @@ -13,7 +11,7 @@ lines.push('Name: ' + this.palette.name); lines.push('Columns: 0'); lines.push('#'); - this.palette.colors.forEach(function (color) { + this.palette.getColors().forEach(function (color) { lines.push(this.writeColorLine(color)); }.bind(this)); lines.push('\r\n'); @@ -35,24 +33,8 @@ ns.PaletteGplWriter.prototype.padString = function (str, size) { str = str.toString(); - for (var i = 0 ; i < size-str.length ; i++) { - str = ' ' + str; - } - return str; + var pad = (new Array(1+size-str.length)).join(' '); + return pad + str; }; })(); - -// GIMP Palette -// Name: Fabric_jeans -// Columns: 0 -// # -// 194 198 201 Untitled -// 173 180 194 Untitled -// 123 126 145 Untitled -// 91 136 195 Untitled -// 41 52 74 Untitled -// 20 25 37 Untitled -// 164 156 145 Untitled -// 103 92 82 Untitled -// 87 58 107 Untitled diff --git a/src/js/service/palette/PaletteService.js b/src/js/service/palette/PaletteService.js index 7cfeafc4..def44a3e 100644 --- a/src/js/service/palette/PaletteService.js +++ b/src/js/service/palette/PaletteService.js @@ -2,13 +2,18 @@ var ns = $.namespace('pskl.service.palette'); ns.PaletteService = function () { - this.palettes = []; + this.dynamicPalettes = []; this.localStorageService = window.localStorage; }; ns.PaletteService.prototype.getPalettes = function () { var palettesString = this.localStorageService.getItem('piskel.palettes'); - return JSON.parse(palettesString) || []; + var palettes = JSON.parse(palettesString) || []; + palettes = palettes.map(function (palette) { + return pskl.model.Palette.fromObject(palette); + }); + + return this.dynamicPalettes.concat(palettes); }; ns.PaletteService.prototype.getPaletteById = function (paletteId) { @@ -32,6 +37,10 @@ window.setTimeout($.publish.bind($, Events.HIDE_NOTIFICATION), 2000); }; + ns.PaletteService.prototype.addDynamicPalette = function (palette) { + this.dynamicPalettes.push(palette); + }; + ns.PaletteService.prototype.deletePaletteById = function (id) { var palettes = this.getPalettes(); var filteredPalettes = palettes.filter(function (palette) { @@ -42,6 +51,9 @@ }; ns.PaletteService.prototype.savePalettes_ = function (palettes) { + palettes = palettes.filter(function (palette) { + return palette instanceof pskl.model.Palette; + }); this.localStorageService.setItem('piskel.palettes', JSON.stringify(palettes)); $.publish(Events.PALETTE_LIST_UPDATED); }; diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 7d34b17d..e2b28987 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -119,6 +119,7 @@ "js/service/BackupService.js", "js/service/BeforeUnloadService.js", "js/service/HistoryService.js", + "js/service/palette/CurrentColorsPalette.js", "js/service/palette/PaletteService.js", "js/service/palette/PaletteTxtReader.js", "js/service/palette/PaletteGplReader.js", diff --git a/src/templates/dialogs/create-palette.html b/src/templates/dialogs/create-palette.html index 2392d98e..c9908913 100644 --- a/src/templates/dialogs/create-palette.html +++ b/src/templates/dialogs/create-palette.html @@ -12,6 +12,10 @@ type="button" rel="tooltip" data-placement="right" title="Import palette from an existing Image or from a palette file" class="button button-primary create-palette-import-button">Import from file + @@ -56,9 +60,10 @@
        - - - + + + +
        diff --git a/src/templates/layers-list.html b/src/templates/layers-list.html index 35f599f7..70389fc5 100644 --- a/src/templates/layers-list.html +++ b/src/templates/layers-list.html @@ -5,17 +5,25 @@ data-placement="top" class="layers-toggle-preview piskel-icon-eye">
        -
        - - - - +
        + + + + + +
        +
          diff --git a/src/templates/palettes-list.html b/src/templates/palettes-list.html index f103c8eb..c68d03f2 100644 --- a/src/templates/palettes-list.html +++ b/src/templates/palettes-list.html @@ -2,29 +2,15 @@

          Palettes -
          +

          -
          - -
          dl
          -
          d
          -
          e
          +
          + + +
          + +
            + -
              diff --git a/src/templates/palettes-list.html b/src/templates/palettes-list.html index c68d03f2..2dc7dded 100644 --- a/src/templates/palettes-list.html +++ b/src/templates/palettes-list.html @@ -5,11 +5,11 @@
              - + class="button palettes-list-button create-palette-button piskel-icon-plus" data-action="add" + title="Create a new palette" rel="tooltip" data-placement="top" > +
              @@ -18,6 +18,13 @@
              + + +
              From 9ef46d5ec5b7109da904784a700b97fcec58151e Mon Sep 17 00:00:00 2001 From: jdescottes Date: Sun, 21 Sep 2014 21:39:54 +0200 Subject: [PATCH 19/32] added FrameUtils unit tests --- src/js/controller/piskel/PiskelController.js | 2 +- src/js/model/Layer.js | 4 +- src/js/model/Piskel.js | 2 +- src/js/utils/FrameUtils.js | 144 +++++++++--------- src/js/utils/LayerUtils.js | 16 +- src/js/utils/serialization/Deserializer.js | 2 +- test/js/utils/FrameUtilsTest.js | 145 +++++++++++++++++++ 7 files changed, 230 insertions(+), 85 deletions(-) create mode 100644 test/js/utils/FrameUtilsTest.js diff --git a/src/js/controller/piskel/PiskelController.js b/src/js/controller/piskel/PiskelController.js index ed03a303..2aa9f565 100644 --- a/src/js/controller/piskel/PiskelController.js +++ b/src/js/controller/piskel/PiskelController.js @@ -158,7 +158,7 @@ ns.PiskelController.prototype.getFrameCount = function () { var layer = this.piskel.getLayerAt(0); - return layer.length(); + return layer.size(); }; ns.PiskelController.prototype.setCurrentFrameIndex = function (index) { diff --git a/src/js/model/Layer.js b/src/js/model/Layer.js index 13d5977e..206aa565 100644 --- a/src/js/model/Layer.js +++ b/src/js/model/Layer.js @@ -56,7 +56,7 @@ if (this.frames[index]) { this.frames.splice(index, 1); } else { - throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.length() + ')'; + throw 'Invalid index in removeFrameAt : ' + index + ' (size : ' + this.size() + ')'; } }; @@ -93,7 +93,7 @@ } }; - ns.Layer.prototype.length = function () { + ns.Layer.prototype.size = function () { return this.frames.length; }; diff --git a/src/js/model/Piskel.js b/src/js/model/Piskel.js index ab28ec14..d41e8433 100644 --- a/src/js/model/Piskel.js +++ b/src/js/model/Piskel.js @@ -33,7 +33,7 @@ */ ns.Piskel.fromLayers = function (layers, descriptor) { var piskel = null; - if (layers.length > 0 && layers[0].length() > 0) { + if (layers.length > 0 && layers[0].size() > 0) { var sampleFrame = layers[0].getFrameAt(0); piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight(), descriptor); layers.forEach(piskel.addLayer.bind(piskel)); diff --git a/src/js/utils/FrameUtils.js b/src/js/utils/FrameUtils.js index b98c2f43..c550692c 100644 --- a/src/js/utils/FrameUtils.js +++ b/src/js/utils/FrameUtils.js @@ -2,6 +2,14 @@ var ns = $.namespace('pskl.utils'); var colorCache = {}; ns.FrameUtils = { + toImage : function (frame, zoom, bgColor) { + zoom = zoom || 1; + bgColor = bgColor || Constants.TRANSPARENT_COLOR; + var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); + canvasRenderer.drawTransparentAs(bgColor); + return canvasRenderer.render(); + }, + merge : function (frames) { var merged = null; if (frames.length) { @@ -28,6 +36,66 @@ return pskl.utils.FrameUtils.createFromImage(resizedImage); }, + /* + * Create a pskl.model.Frame from an Image object. + * Transparent pixels will either be converted to completely opaque or completely transparent pixels. + * @param {Image} image source image + * @return {pskl.model.Frame} corresponding frame + */ + createFromImage : function (image) { + var w = image.width, + h = image.height; + var canvas = pskl.CanvasUtils.createCanvas(w, h); + var context = canvas.getContext('2d'); + + context.drawImage(image, 0,0,w,h,0,0,w,h); + var imgData = context.getImageData(0,0,w,h).data; + return pskl.utils.FrameUtils.createFromImageData_(imgData, w, h); + }, + + createFromImageData_ : function (imageData, width, height) { + // Draw the zoomed-up pixels to a different canvas context + var grid = []; + for (var x = 0 ; x < width ; x++){ + grid[x] = []; + for (var y = 0 ; y < height ; y++){ + // Find the starting index in the one-dimensional image data + var i = (y * width + x)*4; + var r = imageData[i ]; + var g = imageData[i+1]; + var b = imageData[i+2]; + var a = imageData[i+3]; + if (a < 125) { + grid[x][y] = Constants.TRANSPARENT_COLOR; + } else { + grid[x][y] = pskl.utils.FrameUtils.rgbToHex_(r,g,b); + } + } + } + return pskl.model.Frame.fromPixelGrid(grid); + }, + + /** + * Convert a rgb(Number, Number, Number) color to hexadecimal representation + * @param {Number} r red value, between 0 and 255 + * @param {Number} g green value, between 0 and 255 + * @param {Number} b blue value, between 0 and 255 + * @return {String} hex representation of the color '#ABCDEF' + */ + rgbToHex_ : function (r, g, b) { + return "#" + this.componentToHex_(r) + this.componentToHex_(g) + this.componentToHex_(b); + }, + + /** + * Convert a color component (as a Number between 0 and 255) to its string hexa representation + * @param {Number} c component value, between 0 and 255 + * @return {String} eg. '0A' + */ + componentToHex_ : function (c) { + var hex = c.toString(16); + return hex.length == 1 ? "0" + hex : hex; + }, + /** * Alpha compositing using porter duff algorithm : * http://en.wikipedia.org/wiki/Alpha_compositing @@ -36,9 +104,9 @@ * @param {String} strColor2 color under * @return {String} the composite color */ - mergePixels : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba(strColor2); + mergePixels_ : function (strColor1, strColor2, globalOpacity1) { + var col1 = pskl.utils.FrameUtils.toRgba_(strColor1); + var col2 = pskl.utils.FrameUtils.toRgba_(strColor2); if (typeof globalOpacity1 == 'number') { col1 = JSON.parse(JSON.stringify(col1)); col1.a = globalOpacity1 * col1.a; @@ -58,7 +126,7 @@ * @param {String} c color as a string * @return {Object} {r:Number,g:Number,b:Number,a:Number} */ - toRgba : function (c) { + toRgba_ : function (c) { if (colorCache[c]) { return colorCache[c]; } @@ -97,74 +165,6 @@ } colorCache[c] = color; return color; - }, - - /* - * Create a pskl.model.Frame from an Image object. - * Transparent pixels will either be converted to completely opaque or completely transparent pixels. - * @param {Image} image source image - * @return {pskl.model.Frame} corresponding frame - */ - createFromImage : function (image) { - var w = image.width, - h = image.height; - var canvas = pskl.CanvasUtils.createCanvas(w, h); - var context = canvas.getContext('2d'); - - context.drawImage(image, 0,0,w,h,0,0,w,h); - var imgData = context.getImageData(0,0,w,h).data; - return pskl.utils.FrameUtils.createFromImageData(imgData, w, h); - }, - - createFromImageData : function (imageData, width, height) { - // Draw the zoomed-up pixels to a different canvas context - var grid = []; - for (var x = 0 ; x < width ; x++){ - grid[x] = []; - for (var y = 0 ; y < height ; y++){ - // Find the starting index in the one-dimensional image data - var i = (y * width + x)*4; - var r = imageData[i ]; - var g = imageData[i+1]; - var b = imageData[i+2]; - var a = imageData[i+3]; - if (a < 125) { - grid[x][y] = Constants.TRANSPARENT_COLOR; - } else { - grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b); - } - } - } - return pskl.model.Frame.fromPixelGrid(grid); - }, - - /** - * Convert a rgb(Number, Number, Number) color to hexadecimal representation - * @param {Number} r red value, between 0 and 255 - * @param {Number} g green value, between 0 and 255 - * @param {Number} b blue value, between 0 and 255 - * @return {String} hex representation of the color '#ABCDEF' - */ - rgbToHex : function (r, g, b) { - return "#" + this.componentToHex(r) + this.componentToHex(g) + this.componentToHex(b); - }, - - /** - * Convert a color component (as a Number between 0 and 255) to its string hexa representation - * @param {Number} c component value, between 0 and 255 - * @return {String} eg. '0A' - */ - componentToHex : function (c) { - var hex = c.toString(16); - return hex.length == 1 ? "0" + hex : hex; - }, - - toImage : function (frame, zoom, bgColor) { - zoom = zoom || 1; - bgColor = bgColor || Constants.TRANSPARENT_COLOR; - var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom); - canvasRenderer.drawTransparentAs(bgColor); - return canvasRenderer.render(); } }; })(); diff --git a/src/js/utils/LayerUtils.js b/src/js/utils/LayerUtils.js index 38a08e5a..ee709a8d 100644 --- a/src/js/utils/LayerUtils.js +++ b/src/js/utils/LayerUtils.js @@ -8,20 +8,20 @@ * @param {Image} image source image * @return {pskl.model.Frame} corresponding frame */ - createFromImage : function (image, frameCount) { - var w = image.width, - h = image.height, - frameWidth = w / frameCount; + createLayerFromSpritesheet : function (image, frameCount) { + var width = image.width, + height = image.height, + frameWidth = width / frameCount; - var canvas = pskl.CanvasUtils.createCanvas(w, h); + var canvas = pskl.CanvasUtils.createCanvas(frameWidth, height); var context = canvas.getContext('2d'); - context.drawImage(image, 0,0,w,h,0,0,w,h); // Draw the zoomed-up pixels to a different canvas context var frames = []; for (var i = 0 ; i < frameCount ; i++) { - var imgData = context.getImageData(frameWidth*i,0,frameWidth,h).data; - var frame = pskl.utils.FrameUtils.createFromImageData(imgData, frameWidth, h); + context.clearRect(0, 0 , frameWidth, height); + context.drawImage(image, frameWidth * i, 0, frameWidth, height, 0, 0, frameWidth, height); + var frame = pskl.utils.FrameUtils.createFromImage(canvas); frames.push(frame); } return frames; diff --git a/src/js/utils/serialization/Deserializer.js b/src/js/utils/serialization/Deserializer.js index 8c0b43e4..c18808e5 100644 --- a/src/js/utils/serialization/Deserializer.js +++ b/src/js/utils/serialization/Deserializer.js @@ -47,7 +47,7 @@ // 2 - attach the onload callback that will be triggered asynchronously image.onload = function () { // 5 - extract the frames from the loaded image - var frames = pskl.utils.LayerUtils.createFromImage(image, layerData.frameCount); + var frames = pskl.utils.LayerUtils.createLayerFromSpritesheet(image, layerData.frameCount); // 6 - add each image to the layer this.addFramesToLayer(frames, layer); }.bind(this); diff --git a/test/js/utils/FrameUtilsTest.js b/test/js/utils/FrameUtilsTest.js new file mode 100644 index 00000000..ca9a165c --- /dev/null +++ b/test/js/utils/FrameUtilsTest.js @@ -0,0 +1,145 @@ +describe("FrameUtils suite", function() { + var black = '#000000'; + var red = '#ff0000'; + var transparent = Constants.TRANSPARENT_COLOR; + + it("merges 2 frames", function () { + var frame1 = pskl.model.Frame.fromPixelGrid([ + [black, transparent], + [transparent, black] + ]); + + var frame2 = pskl.model.Frame.fromPixelGrid([ + [transparent, red], + [red, transparent] + ]); + + var mergedFrame = pskl.utils.FrameUtils.merge([frame1, frame2]); + expect(mergedFrame.getPixel(0,0)).toBe(black); + expect(mergedFrame.getPixel(0,1)).toBe(red); + expect(mergedFrame.getPixel(1,0)).toBe(red); + expect(mergedFrame.getPixel(1,1)).toBe(black); + }); + + it("returns same frame when merging single frame", function () { + var frame1 = pskl.model.Frame.fromPixelGrid([ + [black, transparent], + [transparent, black] + ]); + + var mergedFrame = pskl.utils.FrameUtils.merge([frame1]); + expect(mergedFrame.getPixel(0,0)).toBe(black); + expect(mergedFrame.getPixel(0,1)).toBe(transparent); + expect(mergedFrame.getPixel(1,0)).toBe(transparent); + expect(mergedFrame.getPixel(1,1)).toBe(black); + }); + + var checkPixelsColor = function (frame, pixels, color) { + pixels.forEach(function (pixel) { + var pixelColor = frame.getPixel(pixel[0], pixel[1]); + expect(pixelColor).toBe(color); + }); + }; + + it ("converts an image to a frame", function () { + var frame1 = pskl.model.Frame.fromPixelGrid([ + [black, transparent], + [transparent, black] + ]); + + var image = pskl.utils.FrameUtils.toImage(frame1); + expect(image.width).toBe(2); + expect(image.height).toBe(2); + + var biggerImage = pskl.utils.FrameUtils.toImage(frame1, 3); + expect(biggerImage.width).toBe(6); + expect(biggerImage.height).toBe(6); + + var biggerFrame = pskl.utils.FrameUtils.createFromImage(biggerImage); + + checkPixelsColor(biggerFrame, [ + [0,0],[0,1],[0,2], + [1,0],[1,1],[1,2], + [2,0],[2,1],[2,2], + [3,3],[3,4],[3,5], + [4,3],[4,4],[4,5], + [5,3],[5,4],[5,5] + ], black); + + checkPixelsColor(biggerFrame, [ + [0,3],[0,4],[0,5], + [1,3],[1,4],[1,5], + [2,3],[2,4],[2,5], + [3,0],[3,1],[3,2], + [4,0],[4,1],[4,2], + [5,0],[5,1],[5,2] + ], transparent); + }); + + it ("[LayerUtils] creates a layer from a simple spritesheet", function () { + var frame = pskl.model.Frame.fromPixelGrid([ + [black, red], + [red, black], + [black, black], + [red, red] + ]); + var spritesheet = pskl.utils.FrameUtils.toImage(frame); + + var frames = pskl.utils.LayerUtils.createLayerFromSpritesheet(spritesheet, 4); + expect(frames.length).toBe(4); + + expect(frames[0].getPixel(0,0)).toBe(black); + expect(frames[0].getPixel(0,1)).toBe(red); + + expect(frames[1].getPixel(0,0)).toBe(red); + expect(frames[1].getPixel(0,1)).toBe(black); + + expect(frames[2].getPixel(0,0)).toBe(black); + expect(frames[2].getPixel(0,1)).toBe(black); + + expect(frames[3].getPixel(0,0)).toBe(red); + expect(frames[3].getPixel(0,1)).toBe(red); + + }); + + // it("starts at -1", function() { + // historyService = createMockHistoryService(); + // expect(historyService.currentIndex).toBe(-1); + // }); + + // it("is at 0 after init", function() { + // historyService = createMockHistoryService(); + // historyService.init(); + // expect(historyService.currentIndex).toBe(0); + // }); + + // it("stores a piskel snapshot after 5 SAVE", function () { + // // BEFORE + // var SNAPSHOT_PERIOD_BACKUP = pskl.service.HistoryService.SNAPSHOT_PERIOD; + // pskl.service.HistoryService.SNAPSHOT_PERIOD = 5; + + // historyService = createMockHistoryService(); + // historyService.init(); + + // sendSaveEvents(pskl.service.HistoryService.REPLAY).times(5); + + // expect(historyService.currentIndex).toBe(5); + + // expect(getLastState().piskel).toBe(SERIALIZED_PISKEL); + + // sendSaveEvents(pskl.service.HistoryService.REPLAY).times(4); + + // sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once(); + // expect(getLastState().piskel).toBeUndefined(); + + // sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once(); + // expect(getLastState().piskel).toBeUndefined(); + + // sendSaveEvents(pskl.service.HistoryService.REPLAY).once(); + // expect(getLastState().piskel).toBe(SERIALIZED_PISKEL); + + // // AFTER + // pskl.service.HistoryService.SNAPSHOT_PERIOD = SNAPSHOT_PERIOD_BACKUP; + + // }) +}); \ No newline at end of file From 00dd6605718e63ec2388956bfe7d505cb5e30fd6 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Mon, 22 Sep 2014 23:51:28 +0200 Subject: [PATCH 20/32] Use dedicated service to display progress information --- src/css/notifications.css | 74 +++++++++++++++++++ src/css/settings-export.css | 13 +--- src/css/style.css | 36 --------- src/index.html | 1 + src/js/Events.js | 4 + src/js/app.js | 3 + src/js/controller/ProgressBarController.js | 61 +++++++++++++++ .../settings/GifExportController.js | 19 +---- src/js/service/palette/PaletteImageReader.js | 20 ++--- src/js/worker/ImageProcessor.js | 63 +++++++++------- src/piskel-script-list.js | 1 + src/piskel-style-list.js | 1 + src/templates/misc-templates.html | 9 +++ src/templates/settings/export.html | 2 - 14 files changed, 205 insertions(+), 102 deletions(-) create mode 100644 src/css/notifications.css create mode 100644 src/js/controller/ProgressBarController.js create mode 100644 src/templates/misc-templates.html diff --git a/src/css/notifications.css b/src/css/notifications.css new file mode 100644 index 00000000..b1ab2885 --- /dev/null +++ b/src/css/notifications.css @@ -0,0 +1,74 @@ +.user-message { + position: absolute; + right: 0; + bottom: 0; + padding: 10px 47px; + max-width: 300px; + + border-top-left-radius: 7px; + border: #F0C36D 1px solid; + border-right: 0; + border-bottom: 0; + + color: #222; + background-color: #F9EDBE; + + font-weight: bold; + font-size: 13px; + + z-index: 30000; +} + +.user-message .close { + position: absolute; + top: 6px; + right: 17px; + + color: gray; + + font-size: 18px; + font-weight: bold; + + cursor: pointer; +} + +.user-message .close:hover { + color: black; +} + +.progress-bar-container { + position: absolute; + left: 0; + bottom: 0; + padding: 10px; + width: 360px; + border-top-right-radius: 2px; + border: gold 2px solid; + border-left: 0; + border-bottom: 0; + background-color: #444; + font-size: 14px; + z-index: 30000; + color: #eee; +} + +.progress-bar-item { + float: left; + height:20px; +} + +.progress-bar-status { + line-height: 20px; + width : 40px; + overflow : hidden; + margin: 0 0 0 10px; +} + +.progress-bar { + border : 1px solid grey; + margin-top: 8px; + height : 4px; + width : 300px; + background : linear-gradient(to left, gold, gold) no-repeat -300px 0; + background-color : black; +} \ No newline at end of file diff --git a/src/css/settings-export.css b/src/css/settings-export.css index e6dd2fe9..e02406ca 100644 --- a/src/css/settings-export.css +++ b/src/css/settings-export.css @@ -51,15 +51,4 @@ -moz-box-sizing:border-box; background: rgba(0,0,0,0.5); color: white; -} - -.gif-export-progress-status { - margin-left: 5px; -} - -.gif-export-progress-bar { - margin-top:5px; - height:3px; - width: 0; - background:gold; -} +} \ No newline at end of file diff --git a/src/css/style.css b/src/css/style.css index c4f2312e..deaa44a7 100644 --- a/src/css/style.css +++ b/src/css/style.css @@ -162,42 +162,6 @@ body { .canvas.onion-skin-canvas {z-index: 10;} .canvas.layers-above-canvas {z-index: 11;} - - -/** - * User messages - */ -.user-message { - position: absolute; - right: 0; - bottom: 0; - background-color: #F9EDBE; - padding: 10px 47px; - border-top-left-radius: 7px; - color: #222; - border: #F0C36D 1px solid; - border-right: 0; - border-bottom: 0; - font-weight: bold; - font-size: 13px; - z-index: 30000; - max-width: 300px; -} - -.user-message .close { - position: absolute; - top: 6px; - right: 17px; - color: gray; - font-weight: bold; - cursor: pointer; - font-size: 18px; -} - -.user-message .close:hover { - color: black; -} - .image-link { color : gold; } diff --git a/src/index.html b/src/index.html index 969a082e..ad7ae0f9 100644 --- a/src/index.html +++ b/src/index.html @@ -74,6 +74,7 @@
              + diff --git a/src/js/Events.js b/src/js/Events.js index 5b9d1106..fb2203a3 100644 --- a/src/js/Events.js +++ b/src/js/Events.js @@ -47,6 +47,10 @@ var Events = { SHOW_NOTIFICATION: "SHOW_NOTIFICATION", HIDE_NOTIFICATION: "HIDE_NOTIFICATION", + SHOW_PROGRESS: "SHOW_PROGRESS", + UPDATE_PROGRESS: "UPDATE_PROGRESS", + HIDE_PROGRESS: "HIDE_PROGRESS", + ZOOM_CHANGED : "ZOOM_CHANGED", CURRENT_COLORS_UPDATED : "CURRENT_COLORS_UPDATED", diff --git a/src/js/app.js b/src/js/app.js index a6fcd4a5..fe8eb764 100644 --- a/src/js/app.js +++ b/src/js/app.js @@ -87,6 +87,9 @@ this.notificationController = new pskl.controller.NotificationController(); this.notificationController.init(); + this.progressBarController = new pskl.controller.ProgressBarController(); + this.progressBarController.init(); + this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController(); this.canvasBackgroundController.init(); diff --git a/src/js/controller/ProgressBarController.js b/src/js/controller/ProgressBarController.js new file mode 100644 index 00000000..5ddb07bd --- /dev/null +++ b/src/js/controller/ProgressBarController.js @@ -0,0 +1,61 @@ +(function () { + var ns = $.namespace('pskl.controller'); + + ns.ProgressBarController = function () { + this.template = pskl.utils.Template.get('progress-bar-template'); + this.progressBar = null; + this.progressBarStatus = null; + + this.showProgressTimer_ = 0; + }; + + ns.ProgressBarController.prototype.init = function () { + $.subscribe(Events.SHOW_PROGRESS, $.proxy(this.showProgress_, this)); + $.subscribe(Events.UPDATE_PROGRESS, $.proxy(this.updateProgress_, this)); + $.subscribe(Events.HIDE_PROGRESS, $.proxy(this.hideProgress_, this)); + }; + + ns.ProgressBarController.prototype.showProgress_ = function (event, progressInfo) { + this.removeProgressBar_(); + this.showProgressTimer_ = window.setTimeout(this.onTimerExpired_.bind(this, progressInfo), 300); + }; + + ns.ProgressBarController.prototype.onTimerExpired_ = function (progressInfo) { + var progressBarHtml = pskl.utils.Template.replace(this.template, { + name : progressInfo.name, + status : 0 + }); + + var progressBarEl = pskl.utils.Template.createFromHTML(progressBarHtml); + document.body.appendChild(progressBarEl); + + this.progressBar = document.querySelector('.progress-bar'); + this.progressBarStatus = document.querySelector('.progress-bar-status'); + }; + + ns.ProgressBarController.prototype.updateProgress_ = function (event, progressInfo) { + if (this.progressBar && this.progressBarStatus) { + var progress = progressInfo.progress; + var width = this.progressBar.offsetWidth; + var progressWidth = width - ((progress * width) / 100); + this.progressBar.style.backgroundPosition = (-progressWidth) + 'px 0'; + this.progressBarStatus.innerText = progress + '%'; + } + }; + + ns.ProgressBarController.prototype.hideProgress_ = function (event, progressInfo) { + if (this.showProgressTimer_) { + window.clearTimeout(this.showProgressTimer_); + } + this.removeProgressBar_(); + }; + + ns.ProgressBarController.prototype.removeProgressBar_ = function () { + var progressBarContainer = document.querySelector('.progress-bar-container'); + if (progressBarContainer) { + progressBarContainer.parentNode.removeChild(progressBarContainer); + this.progressBar = null; + this.progressBarStatus = null; + } + }; +})(); \ No newline at end of file diff --git a/src/js/controller/settings/GifExportController.js b/src/js/controller/settings/GifExportController.js index c0b68eaf..02618498 100644 --- a/src/js/controller/settings/GifExportController.js +++ b/src/js/controller/settings/GifExportController.js @@ -36,9 +36,6 @@ this.downloadButton = $(".gif-download-button"); this.downloadButton.click(this.onDownloadButtonClick_.bind(this)); - this.exportProgressStatusEl = document.querySelector('.gif-export-progress-status'); - this.exportProgressBarEl = document.querySelector('.gif-export-progress-bar'); - this.createOptionElements_(); }; @@ -123,29 +120,19 @@ }); } + $.publish(Events.SHOW_PROGRESS, [{"name": 'Building animated GIF ...'}]); gif.on('progress', function(percentage) { - this.updateProgressStatus_((percentage*100).toFixed(2)); + $.publish(Events.UPDATE_PROGRESS, [{"progress": (percentage*100).toFixed(1)}]); }.bind(this)); gif.on('finished', function(blob) { - this.hideProgressStatus_(); + $.publish(Events.HIDE_PROGRESS); pskl.utils.FileUtils.readFile(blob, cb); }.bind(this)); gif.render(); }; - ns.GifExportController.prototype.updateProgressStatus_ = function (percentage) { - this.exportProgressStatusEl.innerHTML = percentage + '%'; - this.exportProgressBarEl.style.width = percentage + "%"; - - }; - - ns.GifExportController.prototype.hideProgressStatus_ = function () { - this.exportProgressStatusEl.innerHTML = ''; - this.exportProgressBarEl.style.width = "0"; - }; - // FIXME : HORRIBLE COPY/PASTA ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { diff --git a/src/js/service/palette/PaletteImageReader.js b/src/js/service/palette/PaletteImageReader.js index 61945904..ff2ba5ba 100644 --- a/src/js/service/palette/PaletteImageReader.js +++ b/src/js/service/palette/PaletteImageReader.js @@ -16,6 +16,10 @@ this.onWorkerSuccess_.bind(this), this.onWorkerStep_.bind(this), this.onWorkerError_.bind(this)); + + + $.publish(Events.SHOW_PROGRESS, [{"name": 'Processing image colors ...'}]); + imageProcessor.process(); }; @@ -33,20 +37,16 @@ this.onSuccess(palette); } + $.publish(Events.HIDE_PROGRESS); }; + ns.PaletteImageReader.prototype.onWorkerStep_ = function (event) { - var data = event.data; - var step = data.step; - var total = data.total; - - var progress = ((step/total)*100).toFixed(1); - - if (this.currentProgress !== progress) { - this.currentProgress = progress; - console.log("Image processing completed at : " + progress + "%"); - } + var progress = event.data.progress; + $.publish(Events.UPDATE_PROGRESS, [{"progress": progress}]); }; + ns.PaletteImageReader.prototype.onWorkerError_ = function (event) { + $.publish(Events.HIDE_PROGRESS); this.onError('Unable to process the image : ' + event.data.message); }; })(); \ No newline at end of file diff --git a/src/js/worker/ImageProcessor.js b/src/js/worker/ImageProcessor.js index 45dc3447..0cc80209 100644 --- a/src/js/worker/ImageProcessor.js +++ b/src/js/worker/ImageProcessor.js @@ -3,12 +3,25 @@ var worker = function () { - var postStep_ = function (step, total) { - this.postMessage({ - type : 'STEP', - step : step, - total : total - }); + var currentStep, currentProgress, currentTotal; + var initStepCounter_ = function (total) { + currentStep = 0; + currentProgress = 0; + currentTotal = total; + }; + + var postStep_ = function () { + currentStep = currentStep + 1; + var progress = ((currentStep / currentTotal) *100).toFixed(1); + if (progress != currentProgress) { + currentProgress = progress; + this.postMessage({ + type : 'STEP', + progress : currentProgress, + currentStep : currentStep, + total : currentTotal + }); + } }; var rgbToHex = function(r, g, b) { @@ -20,7 +33,7 @@ var grid = []; for (var x = 0 ; x < width ; x++){ grid[x] = []; - postStep_(x, (width-1)*2); + postStep_(); for (var y = 0 ; y < height ; y++){ // Find the starting index in the one-dimensional image data var i = (y * width + x)*4; @@ -43,9 +56,7 @@ var colorsMap = {}; for (var i = 0 ; i < grid.length ; i++) { - var step = (grid.length-1) + i; - var total = (grid.length-1)*2; - postStep_(step, total); + postStep_(); for (var j = 0 ; j < grid[i].length ; j++) { var color = grid[i][j]; if (color != 'transparent') { @@ -57,22 +68,22 @@ }; this.onmessage = function(event) { - var data = event.data; - if (data.type === 'RUN_SCRIPT') { - this.importScripts(data.script); - } else { - try { - var colorsMap = getColorsMapFromImageData(data.imageData, data.width, data.height); - this.postMessage({ - type : 'SUCCESS', - colorsMap : colorsMap - }); - } catch(e) { - this.postMessage({ - type : 'ERROR', - message : e.message - }); - } + try { + var data = event.data; + + initStepCounter_(data.width * 2); + + var colorsMap = getColorsMapFromImageData(data.imageData, data.width, data.height); + + this.postMessage({ + type : 'SUCCESS', + colorsMap : colorsMap + }); + } catch(e) { + this.postMessage({ + type : 'ERROR', + message : e.message + }); } }; }; diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index fed83252..b46e240b 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -84,6 +84,7 @@ "js/controller/ToolController.js", "js/controller/PaletteController.js", "js/controller/PalettesListController.js", + "js/controller/ProgressBarController.js", "js/controller/NotificationController.js", "js/controller/CanvasBackgroundController.js", diff --git a/src/piskel-style-list.js b/src/piskel-style-list.js index e20c191d..fdb8e0c9 100644 --- a/src/piskel-style-list.js +++ b/src/piskel-style-list.js @@ -16,6 +16,7 @@ "css/dialogs-import-image.css", "css/dialogs-browse-local.css", "css/dialogs-create-palette.css", + "css/notifications.css", "css/toolbox.css", "css/toolbox-layers-list.css", "css/toolbox-palettes-list.css", diff --git a/src/templates/misc-templates.html b/src/templates/misc-templates.html new file mode 100644 index 00000000..56d5a0b7 --- /dev/null +++ b/src/templates/misc-templates.html @@ -0,0 +1,9 @@ +
              + +
              \ No newline at end of file diff --git a/src/templates/settings/export.html b/src/templates/settings/export.html index 56865939..ff640f3c 100644 --- a/src/templates/settings/export.html +++ b/src/templates/settings/export.html @@ -40,7 +40,5 @@
              - -
              From 8989e984cb612b1b5a16b947159c8ce534be62ed Mon Sep 17 00:00:00 2001 From: jdescottes Date: Tue, 23 Sep 2014 08:00:46 +0200 Subject: [PATCH 21/32] added dedicated style for colors-list for IE and FF + bug fixing on ProgressBarCOntroller for FF --- src/css/dialogs-create-palette.css | 13 +++++++++++++ src/js/controller/ProgressBarController.js | 2 +- 2 files changed, 14 insertions(+), 1 deletion(-) diff --git a/src/css/dialogs-create-palette.css b/src/css/dialogs-create-palette.css index 3f4856ee..6988b98a 100644 --- a/src/css/dialogs-create-palette.css +++ b/src/css/dialogs-create-palette.css @@ -85,6 +85,19 @@ cursor : pointer; } +@-moz-document url-prefix() { + .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ + margin : 7px 0 0 7px; + } +} + +@media screen and (-ms-high-contrast: active), (-ms-high-contrast: none) { + .create-palette-color, .create-palette-new-color, .colors-list-drop-proxy{ + margin : 7px 0 0 7px; + } +} + + .create-palette-color { border:1px solid #2c2c2c; transition : border-color 0.2s; diff --git a/src/js/controller/ProgressBarController.js b/src/js/controller/ProgressBarController.js index 5ddb07bd..2681982b 100644 --- a/src/js/controller/ProgressBarController.js +++ b/src/js/controller/ProgressBarController.js @@ -39,7 +39,7 @@ var width = this.progressBar.offsetWidth; var progressWidth = width - ((progress * width) / 100); this.progressBar.style.backgroundPosition = (-progressWidth) + 'px 0'; - this.progressBarStatus.innerText = progress + '%'; + this.progressBarStatus.innerHTML = progress + '%'; } }; From afe790e5e33da1940b17e65c7593c28635afb37c Mon Sep 17 00:00:00 2001 From: jdescottes Date: Tue, 23 Sep 2014 08:05:31 +0200 Subject: [PATCH 22/32] Removed unused CSS rules for old edit/merge layer actions --- src/css/toolbox-layers-list.css | 24 ------------------------ 1 file changed, 24 deletions(-) diff --git a/src/css/toolbox-layers-list.css b/src/css/toolbox-layers-list.css index 116644f8..eacfde75 100644 --- a/src/css/toolbox-layers-list.css +++ b/src/css/toolbox-layers-list.css @@ -49,24 +49,6 @@ cursor : pointer; } -.layer-item .edit-icon, .layer-item .merge-icon { - float: right; - opacity: 0; - transition : opacity 0.2s; -} - -.layer-item:hover .edit-icon, .layer-item:hover .merge-icon { - opacity : 0.6; -} - -.layer-item:hover .edit-icon:hover, .layer-item:hover .merge-icon:hover { - opacity : 1; -} - -.layer-item:last-child .merge-icon { - display : none; -} - .layer-item:hover { background : #222; } @@ -94,10 +76,4 @@ .layers-button:last-child { border-right-width: 0; -} - -.layers-button-container .merge-icon, -.layers-button-container .edit-icon { - background-size : 15px; - background-position : 50%; } \ No newline at end of file From 6ef99bba15d6a278d12d7789c3494a354e77365a Mon Sep 17 00:00:00 2001 From: jdescottes Date: Wed, 24 Sep 2014 00:26:31 +0200 Subject: [PATCH 23/32] improved current colors sort algorithm --- src/js/service/CurrentColorsService.js | 75 ++++++++++++++++++++++---- 1 file changed, 66 insertions(+), 9 deletions(-) diff --git a/src/js/service/CurrentColorsService.js b/src/js/service/CurrentColorsService.js index 4aed52e7..966ed608 100644 --- a/src/js/service/CurrentColorsService.js +++ b/src/js/service/CurrentColorsService.js @@ -5,7 +5,7 @@ this.piskelController = piskelController; this.currentColors = []; this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); - this.cachedFrameProcessor.setFrameProcessor(this.frameToColors_.bind(this)); + this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); this.framesColorsCache_ = {}; }; @@ -19,11 +19,12 @@ return this.currentColors; }; - ns.CurrentColorsService.prototype.frameToColors_ = function (frame) { + ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { var frameColors = {}; frame.forEachPixel(function (color, x, y) { - frameColors[color] = (frameColors[color] || 0) + 1; - }); + var hexColor = this.toHexColor_(color); + frameColors[hexColor] = true; + }.bind(this)); return frameColors; }; @@ -35,7 +36,7 @@ frames.forEach(function (f) { var frameColors = this.cachedFrameProcessor.get(f); Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { - colors[color] = (colors[color] || 0) + frameColors[color]; + colors[color] = true; }); }.bind(this)); @@ -45,12 +46,68 @@ // limit the array to the max colors to display this.currentColors = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); + this.colorsHslMap = {}; + + this.currentColors.forEach(function (color) { + this.colorsHslMap[color] = window.tinycolor(color).toHsl(); + }.bind(this)); + // sort by most frequent color - this.currentColors = this.currentColors.sort(function (c1, c2) { - return colors[c2] - colors[c1]; - }); + this.currentColors = this.currentColors.sort(); + this.currentColors = this.currentColors.sort(this.sortColors_.bind(this)); // TODO : only fire if there was a change - $.publish(Events.CURRENT_COLORS_UPDATED, colors); + $.publish(Events.CURRENT_COLORS_UPDATED); + }; + + ns.CurrentColorsService.prototype.sortColors_ = function (c1, c2) { + var hsl1 = this.colorsHslMap[c1]; + var hsl2 = this.colorsHslMap[c2]; + + if (hsl1.l < 0.1 || hsl2.l < 0.1) { + return this.compareValues_(hsl1.l, hsl2.l); + } else if (hsl1.l > 0.9 || hsl2.l > 0.9) { + return this.compareValues_(hsl2.l, hsl1.l); + } else { + var hDiff = Math.abs(hsl1.h - hsl2.h); + var sDiff = Math.abs(hsl1.s - hsl2.s); + var lDiff = Math.abs(hsl1.l - hsl2.l); + if (hDiff < 10) { + if (sDiff > lDiff) { + return this.compareValues_(hsl1.s, hsl2.s); + } else { + return this.compareValues_(hsl1.l, hsl2.l); + } + } else { + return this.compareValues_(hsl1.h, hsl2.h); + } + } + }; + + ns.CurrentColorsService.prototype.compareValues_ = function (v1, v2) { + if (v1 > v2) { + return 1; + } else if (v1 < v2) { + return -1; + } + return 0; + }; + + ns.CurrentColorsService.prototype.toHexColor_ = function (color) { + if (color === Constants.TRANSPARENT_COLOR) { + return color; + } else { + color = color.replace(/\s/g, ''); + var hexRe = (/^#([a-f0-9]{3}){1,2}$/i); + var rgbRe = (/^rgb\((\d{1,3}),(\d{1,3}),(\d{1,3})\)$/i); + if (hexRe.test(color)) { + return color.toUpperCase(); + } else if (rgbRe.test(color)) { + var exec = rgbRe.exec(color); + return pskl.utils.rgbToHex(exec[1] * 1, exec[2] * 1, exec[3] * 1); + } else { + console.error('Could not convert color to hex : ', color); + } + } }; })(); \ No newline at end of file From e3e6730b45e9369cab89ae5a97a428f7cdd10049 Mon Sep 17 00:00:00 2001 From: jdescottes Date: Wed, 24 Sep 2014 07:43:04 +0200 Subject: [PATCH 24/32] improved current colors sort algorithm --- src/js/worker/ImageProcessor.js | 16 ++++------------ src/piskel-script-list.js | 1 + 2 files changed, 5 insertions(+), 12 deletions(-) diff --git a/src/js/worker/ImageProcessor.js b/src/js/worker/ImageProcessor.js index 0cc80209..53deb72d 100644 --- a/src/js/worker/ImageProcessor.js +++ b/src/js/worker/ImageProcessor.js @@ -1,9 +1,9 @@ (function () { var ns = $.namespace('pskl.worker'); - var worker = function () { - + var imageProcessorWorker = function () { var currentStep, currentProgress, currentTotal; + var initStepCounter_ = function (total) { currentStep = 0; currentProgress = 0; @@ -88,15 +88,6 @@ }; }; - try { - // create worker from blob - var typedArray = [(worker+"").replace(/function \(\) \{/,"").replace(/\}[^}]*$/, "")]; - var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here - var blobUrl = window.URL.createObjectURL(blob); - } catch (e) { - console.error("Could not create worker", e.message); - } - ns.ImageProcessor = function (image, onSuccess, onStep, onError) { this.image = image; @@ -104,7 +95,8 @@ this.onSuccess = onSuccess; this.onError = onError; - this.worker = new Worker(blobUrl); + // var worker = pskl.utils.WorkerUtils.addPartialWorker(imageProcessorWorker, 'step-counter'); + this.worker = pskl.utils.WorkerUtils.createWorker(worker, 'image-colors-processor'); this.worker.onmessage = this.onWorkerMessage.bind(this); }; diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index b46e240b..6baecef6 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -26,6 +26,7 @@ "js/utils/Template.js", "js/utils/UserSettings.js", "js/utils/Uuid.js", + "js/utils/WorkerUtils.js", "js/utils/Xhr.js", "js/utils/serialization/Serializer.js", "js/utils/serialization/Deserializer.js", From 258d13371da3e6e96bc1e844f4e84d6ab63fc67c Mon Sep 17 00:00:00 2001 From: jdescottes Date: Wed, 24 Sep 2014 08:15:18 +0200 Subject: [PATCH 25/32] improved current colors sort algorithm --- src/js/lib/gif/libgif.js | 2 ++ src/js/service/CurrentColorsService.js | 9 +++++++-- 2 files changed, 9 insertions(+), 2 deletions(-) diff --git a/src/js/lib/gif/libgif.js b/src/js/lib/gif/libgif.js index ef1d6ab4..157f4dee 100644 --- a/src/js/lib/gif/libgif.js +++ b/src/js/lib/gif/libgif.js @@ -624,6 +624,7 @@ var SuperGif = function ( opts ) { }; var load_callback = false; + var step_callback = false; var error_callback = false; var tmpCanvas = document.createElement('canvas'); @@ -632,6 +633,7 @@ var SuperGif = function ( opts ) { load: function (callback) { load_callback = callback.success; + step_callback = callback.step; error_callback = callback.error; loading = true; diff --git a/src/js/service/CurrentColorsService.js b/src/js/service/CurrentColorsService.js index 966ed608..f5f7c94f 100644 --- a/src/js/service/CurrentColorsService.js +++ b/src/js/service/CurrentColorsService.js @@ -60,14 +60,19 @@ $.publish(Events.CURRENT_COLORS_UPDATED); }; + var LOW_SAT = 0.1; + var LOW_LUM = 0.1; + var HI_LUM = 0.9; ns.CurrentColorsService.prototype.sortColors_ = function (c1, c2) { var hsl1 = this.colorsHslMap[c1]; var hsl2 = this.colorsHslMap[c2]; - if (hsl1.l < 0.1 || hsl2.l < 0.1) { + if (hsl1.l < LOW_LUM || hsl2.l < LOW_LUM) { return this.compareValues_(hsl1.l, hsl2.l); - } else if (hsl1.l > 0.9 || hsl2.l > 0.9) { + } else if (hsl1.l > HI_LUM || hsl2.l > HI_LUM) { return this.compareValues_(hsl2.l, hsl1.l); + } else if (hsl1.s < LOW_SAT || hsl2.s < LOW_SAT) { + return this.compareValues_(hsl1.s, hsl2.s); } else { var hDiff = Math.abs(hsl1.h - hsl2.h); var sDiff = Math.abs(hsl1.s - hsl2.s); From b5465ca066916717537e44ba4f2662ee77d077fd Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Wed, 24 Sep 2014 21:50:16 +0200 Subject: [PATCH 26/32] fixed palette import bug --- src/js/utils/WorkerUtils.js | 17 +++++++++++++++++ src/js/worker/ImageProcessor.js | 11 ++++++++--- 2 files changed, 25 insertions(+), 3 deletions(-) create mode 100644 src/js/utils/WorkerUtils.js diff --git a/src/js/utils/WorkerUtils.js b/src/js/utils/WorkerUtils.js new file mode 100644 index 00000000..0cd421a5 --- /dev/null +++ b/src/js/utils/WorkerUtils.js @@ -0,0 +1,17 @@ +(function () { + var ns = $.namespace('pskl.utils'); + + var workers = {}; + + ns.WorkerUtils = { + createWorker : function (worker, workerId) { + if (!workers[workerId]) { + var typedArray = [(worker+"").replace(/function \(\)\s?\{/,"").replace(/\}[^}]*$/, "")]; + var blob = new Blob(typedArray, {type: "application/javascript"}); // pass a useful mime type here + workers[workerId] = window.URL.createObjectURL(blob); + } + + return new Worker(workers[workerId]); + } + }; +})(); \ No newline at end of file diff --git a/src/js/worker/ImageProcessor.js b/src/js/worker/ImageProcessor.js index 53deb72d..82b17695 100644 --- a/src/js/worker/ImageProcessor.js +++ b/src/js/worker/ImageProcessor.js @@ -23,9 +23,14 @@ }); } }; + + var rgbToHex = function (r, g, b) { + return "#" + componentToHex(r) + componentToHex(g) + componentToHex(b); + }; - var rgbToHex = function(r, g, b) { - return '#' + ((r << 16) | (g << 8) | b).toString(16); + var componentToHex = function (c) { + var hex = c.toString(16); + return hex.length == 1 ? "0" + hex : hex; }; var imageDataToGrid = function (imageData, width, height, transparent) { @@ -96,7 +101,7 @@ this.onError = onError; // var worker = pskl.utils.WorkerUtils.addPartialWorker(imageProcessorWorker, 'step-counter'); - this.worker = pskl.utils.WorkerUtils.createWorker(worker, 'image-colors-processor'); + this.worker = pskl.utils.WorkerUtils.createWorker(imageProcessorWorker, 'image-colors-processor'); this.worker.onmessage = this.onWorkerMessage.bind(this); }; From 6583d3d560ab8ad1950171976fe448107a20d43f Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Wed, 24 Sep 2014 21:53:41 +0200 Subject: [PATCH 27/32] moved rgbToHex correct implementation to pskl core utils --- src/js/utils/FrameUtils.js | 23 +---------------------- src/js/utils/core.js | 23 ++++++++++++++++++----- 2 files changed, 19 insertions(+), 27 deletions(-) diff --git a/src/js/utils/FrameUtils.js b/src/js/utils/FrameUtils.js index 273a08fb..ae71a1c9 100644 --- a/src/js/utils/FrameUtils.js +++ b/src/js/utils/FrameUtils.js @@ -68,34 +68,13 @@ if (a < 125) { grid[x][y] = Constants.TRANSPARENT_COLOR; } else { - grid[x][y] = pskl.utils.FrameUtils.rgbToHex_(r,g,b); + grid[x][y] = pskl.utils.rgbToHex(r,g,b); } } } return pskl.model.Frame.fromPixelGrid(grid); }, - /** - * Convert a rgb(Number, Number, Number) color to hexadecimal representation - * @param {Number} r red value, between 0 and 255 - * @param {Number} g green value, between 0 and 255 - * @param {Number} b blue value, between 0 and 255 - * @return {String} hex representation of the color '#ABCDEF' - */ - rgbToHex_ : function (r, g, b) { - return "#" + this.componentToHex_(r) + this.componentToHex_(g) + this.componentToHex_(b); - }, - - /** - * Convert a color component (as a Number between 0 and 255) to its string hexa representation - * @param {Number} c component value, between 0 and 255 - * @return {String} eg. '0A' - */ - componentToHex_ : function (c) { - var hex = c.toString(16); - return hex.length == 1 ? "0" + hex : hex; - }, - /** * Alpha compositing using porter duff algorithm : * http://en.wikipedia.org/wiki/Alpha_compositing diff --git a/src/js/utils/core.js b/src/js/utils/core.js index 59cb7e45..2fd92c14 100644 --- a/src/js/utils/core.js +++ b/src/js/utils/core.js @@ -46,12 +46,25 @@ if (!Function.prototype.bind) { var ns = $.namespace("pskl.utils"); - ns.rgbToHex = function(r, g, b) { - if (r > 255 || g > 255 || b > 255) { - throw "Invalid color component"; - } + /** + * Convert a rgb(Number, Number, Number) color to hexadecimal representation + * @param {Number} r red value, between 0 and 255 + * @param {Number} g green value, between 0 and 255 + * @param {Number} b blue value, between 0 and 255 + * @return {String} hex representation of the color '#ABCDEF' + */ + ns.rgbToHex = function (r, g, b) { + return "#" + pskl.utils.componentToHex(r) + pskl.utils.componentToHex(g) + pskl.utils.componentToHex(b); + }; - return ((r << 16) | (g << 8) | b).toString(16); + /** + * Convert a color component (as a Number between 0 and 255) to its string hexa representation + * @param {Number} c component value, between 0 and 255 + * @return {String} eg. '0A' + */ + ns.componentToHex = function (c) { + var hex = c.toString(16); + return hex.length == 1 ? "0" + hex : hex; }; ns.normalize = function (value, def) { From ac087754069a864f07770180f4f6d04bf6ffda89 Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Thu, 25 Sep 2014 00:13:23 +0200 Subject: [PATCH 28/32] improved current colors sort --- src/js/service/CurrentColorsService.js | 56 ++----------- src/js/service/color/ColorSorter.js | 105 +++++++++++++++++++++++++ src/piskel-script-list.js | 1 + 3 files changed, 112 insertions(+), 50 deletions(-) create mode 100644 src/js/service/color/ColorSorter.js diff --git a/src/js/service/CurrentColorsService.js b/src/js/service/CurrentColorsService.js index f5f7c94f..fe71c4eb 100644 --- a/src/js/service/CurrentColorsService.js +++ b/src/js/service/CurrentColorsService.js @@ -7,6 +7,8 @@ this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor(); this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); + this.colorSorter = new pskl.service.color.ColorSorter(); + this.framesColorsCache_ = {}; }; @@ -28,11 +30,11 @@ return frameColors; }; - ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { var layers = this.piskelController.getLayers(); var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); var colors = {}; + frames.forEach(function (f) { var frameColors = this.cachedFrameProcessor.get(f); Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { @@ -44,60 +46,14 @@ delete colors[Constants.TRANSPARENT_COLOR]; // limit the array to the max colors to display - this.currentColors = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - - this.colorsHslMap = {}; - - this.currentColors.forEach(function (color) { - this.colorsHslMap[color] = window.tinycolor(color).toHsl(); - }.bind(this)); - - // sort by most frequent color - this.currentColors = this.currentColors.sort(); - this.currentColors = this.currentColors.sort(this.sortColors_.bind(this)); + var colorsArray = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); + this.currentColors = this.colorSorter.sort(colorsArray); + console.log(this.currentColors); // TODO : only fire if there was a change $.publish(Events.CURRENT_COLORS_UPDATED); }; - var LOW_SAT = 0.1; - var LOW_LUM = 0.1; - var HI_LUM = 0.9; - ns.CurrentColorsService.prototype.sortColors_ = function (c1, c2) { - var hsl1 = this.colorsHslMap[c1]; - var hsl2 = this.colorsHslMap[c2]; - - if (hsl1.l < LOW_LUM || hsl2.l < LOW_LUM) { - return this.compareValues_(hsl1.l, hsl2.l); - } else if (hsl1.l > HI_LUM || hsl2.l > HI_LUM) { - return this.compareValues_(hsl2.l, hsl1.l); - } else if (hsl1.s < LOW_SAT || hsl2.s < LOW_SAT) { - return this.compareValues_(hsl1.s, hsl2.s); - } else { - var hDiff = Math.abs(hsl1.h - hsl2.h); - var sDiff = Math.abs(hsl1.s - hsl2.s); - var lDiff = Math.abs(hsl1.l - hsl2.l); - if (hDiff < 10) { - if (sDiff > lDiff) { - return this.compareValues_(hsl1.s, hsl2.s); - } else { - return this.compareValues_(hsl1.l, hsl2.l); - } - } else { - return this.compareValues_(hsl1.h, hsl2.h); - } - } - }; - - ns.CurrentColorsService.prototype.compareValues_ = function (v1, v2) { - if (v1 > v2) { - return 1; - } else if (v1 < v2) { - return -1; - } - return 0; - }; - ns.CurrentColorsService.prototype.toHexColor_ = function (color) { if (color === Constants.TRANSPARENT_COLOR) { return color; diff --git a/src/js/service/color/ColorSorter.js b/src/js/service/color/ColorSorter.js new file mode 100644 index 00000000..a2ab027f --- /dev/null +++ b/src/js/service/color/ColorSorter.js @@ -0,0 +1,105 @@ +(function () { + var ns = $.namespace('pskl.service.color'); + + var LOW_SAT = 0.3; + var LOW_LUM = 0.1; + var HI_LUM = 0.9; + + + var HUE_STEP = 36; + var HUE_BAGS = 10; + var HUE_BOUNDS = []; + for (var i = 0 ; i < HUE_BAGS ; i++) { + HUE_BOUNDS.push(i * HUE_STEP); + } + + ns.ColorSorter = function () { + this.colorsHslMap_ = {}; + }; + + ns.ColorSorter.prototype.sort = function (colors) { + this.colorsHslMap_ = {}; + + colors.forEach(function (color) { + this.colorsHslMap_[color] = window.tinycolor(color).toHsl(); + }.bind(this)); + + // sort by most frequent color + var darkColors = colors.filter(function (c) { + var hsl = this.colorsHslMap_[c]; + return hsl.l <= LOW_LUM; + }.bind(this)); + + var brightColors = colors.filter(function (c) { + var hsl = this.colorsHslMap_[c]; + return hsl.l >= HI_LUM; + }.bind(this)); + + var desaturatedColors = colors.filter(function (c) { + var hsl = this.colorsHslMap_[c]; + return hsl.s <= LOW_SAT; + }.bind(this)); + + darkColors = this.sortOnHslProperty_(darkColors, 'l'); + brightColors = this.sortOnHslProperty_(brightColors, 'l'); + desaturatedColors = this.sortOnHslProperty_(desaturatedColors, 'h'); + + var sortedColors = darkColors.concat(brightColors).concat(desaturatedColors); + + var regularColors = colors.filter(function (c) { + return sortedColors.indexOf(c) === -1; + }); + + var regularColorsBags = []; + for (var i = 0 ; i < HUE_BOUNDS.length ; i++) { + var hue = HUE_BOUNDS[i]; + var bagColors = regularColors.filter(function (color) { + var hsl = this.colorsHslMap_[color]; + return (hsl.h >= hue && hsl.h < hue + HUE_STEP); + }.bind(this)); + + regularColorsBags[i] = this.sortRegularColors_(bagColors); + } + + return Array.prototype.concat.apply(sortedColors, regularColorsBags); + }; + + ns.ColorSorter.prototype.sortRegularColors_ = function (colors) { + var sortedColors = colors.sort(function (c1, c2) { + var hsl1 = this.colorsHslMap_[c1]; + var hsl2 = this.colorsHslMap_[c2]; + var hDiff = Math.abs(hsl1.h - hsl2.h); + var sDiff = Math.abs(hsl1.s - hsl2.s); + var lDiff = Math.abs(hsl1.l - hsl2.l); + if (hDiff < 10) { + if (sDiff > lDiff) { + return this.compareValues_(hsl1.s, hsl2.s); + } else { + return this.compareValues_(hsl1.l, hsl2.l); + } + } else { + return this.compareValues_(hsl1.h, hsl2.h); + } + }.bind(this)); + + return sortedColors; + }; + + ns.ColorSorter.prototype.sortOnHslProperty_ = function (colors, property) { + return colors.sort(function (c1, c2) { + var hsl1 = this.colorsHslMap_[c1]; + var hsl2 = this.colorsHslMap_[c2]; + return this.compareValues_(hsl1[property], hsl2[property]); + }.bind(this)); + }; + + ns.ColorSorter.prototype.compareValues_ = function (v1, v2) { + if (v1 > v2) { + return 1; + } else if (v1 < v2) { + return -1; + } + return 0; + }; + +})(); \ No newline at end of file diff --git a/src/piskel-script-list.js b/src/piskel-script-list.js index 6baecef6..1e9e38cb 100644 --- a/src/piskel-script-list.js +++ b/src/piskel-script-list.js @@ -122,6 +122,7 @@ "js/service/BackupService.js", "js/service/BeforeUnloadService.js", "js/service/HistoryService.js", + "js/service/color/ColorSorter.js", "js/service/palette/CurrentColorsPalette.js", "js/service/palette/PaletteService.js", "js/service/palette/PaletteTxtReader.js", From a7ef57b6eef9e0b82e59d7217e96fb1c9539aaef Mon Sep 17 00:00:00 2001 From: jdescottes Date: Fri, 26 Sep 2014 00:03:24 +0200 Subject: [PATCH 29/32] fixed color sorting for desaturated colors --- src/js/service/CurrentColorsService.js | 4 +++- src/js/service/color/ColorSorter.js | 16 ++++++++-------- 2 files changed, 11 insertions(+), 9 deletions(-) diff --git a/src/js/service/CurrentColorsService.js b/src/js/service/CurrentColorsService.js index fe71c4eb..d32f1aa4 100644 --- a/src/js/service/CurrentColorsService.js +++ b/src/js/service/CurrentColorsService.js @@ -15,6 +15,8 @@ ns.CurrentColorsService.prototype.init = function () { $.subscribe(Events.PISKEL_RESET, this.onPiskelUpdated_.bind(this)); $.subscribe(Events.TOOL_RELEASED, this.onPiskelUpdated_.bind(this)); + + // this.updateTimer = window.setInterval(this.updateCurrentColors_.bind(this)); }; ns.CurrentColorsService.prototype.getCurrentColors = function () { @@ -34,7 +36,7 @@ var layers = this.piskelController.getLayers(); var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); var colors = {}; - + frames.forEach(function (f) { var frameColors = this.cachedFrameProcessor.get(f); Object.keys(frameColors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED).forEach(function (color) { diff --git a/src/js/service/color/ColorSorter.js b/src/js/service/color/ColorSorter.js index a2ab027f..0f8e80c1 100644 --- a/src/js/service/color/ColorSorter.js +++ b/src/js/service/color/ColorSorter.js @@ -1,7 +1,7 @@ (function () { var ns = $.namespace('pskl.service.color'); - var LOW_SAT = 0.3; + var LOW_SAT = 0.1; var LOW_LUM = 0.1; var HI_LUM = 0.9; @@ -36,6 +36,8 @@ }.bind(this)); var desaturatedColors = colors.filter(function (c) { + return brightColors.indexOf(c) === -1 && darkColors.indexOf(c) === -1; + }).filter(function (c) { var hsl = this.colorsHslMap_[c]; return hsl.s <= LOW_SAT; }.bind(this)); @@ -44,22 +46,20 @@ brightColors = this.sortOnHslProperty_(brightColors, 'l'); desaturatedColors = this.sortOnHslProperty_(desaturatedColors, 'h'); - var sortedColors = darkColors.concat(brightColors).concat(desaturatedColors); - + var sortedColors = darkColors.concat(brightColors, desaturatedColors); + var regularColors = colors.filter(function (c) { return sortedColors.indexOf(c) === -1; }); - var regularColorsBags = []; - for (var i = 0 ; i < HUE_BOUNDS.length ; i++) { - var hue = HUE_BOUNDS[i]; + var regularColorsBags = HUE_BOUNDS.map(function (hue) { var bagColors = regularColors.filter(function (color) { var hsl = this.colorsHslMap_[color]; return (hsl.h >= hue && hsl.h < hue + HUE_STEP); }.bind(this)); - regularColorsBags[i] = this.sortRegularColors_(bagColors); - } + return this.sortRegularColors_(bagColors); + }.bind(this)); return Array.prototype.concat.apply(sortedColors, regularColorsBags); }; From d805e13d57843df90d57d9305b668e901d2c1d9e Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 27 Sep 2014 01:10:54 +0200 Subject: [PATCH 30/32] sort colors on image import for palette --- src/js/service/palette/PaletteImageReader.js | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/js/service/palette/PaletteImageReader.js b/src/js/service/palette/PaletteImageReader.js index ff2ba5ba..d96b66ea 100644 --- a/src/js/service/palette/PaletteImageReader.js +++ b/src/js/service/palette/PaletteImageReader.js @@ -5,6 +5,8 @@ this.file = file; this.onSuccess = onSuccess; this.onError = onError; + + this.colorSorter_ = new pskl.service.color.ColorSorter(); }; ns.PaletteImageReader.prototype.read = function () { @@ -33,7 +35,8 @@ this.onError('Too many colors : ' + colors.length); } else { var uuid = pskl.utils.Uuid.generate(); - var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', colors); + var sortedColors = this.colorSorter_.sort(colors); + var palette = new pskl.model.Palette(uuid, this.file.name + ' palette', sortedColors); this.onSuccess(palette); } From 37aa6c3d72c80ac4af0fd56671c8488e930f23bd Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 27 Sep 2014 01:22:20 +0200 Subject: [PATCH 31/32] sort colors on image import for palette --- src/js/service/CurrentColorsService.js | 40 +++++++++++++++++++------- 1 file changed, 30 insertions(+), 10 deletions(-) diff --git a/src/js/service/CurrentColorsService.js b/src/js/service/CurrentColorsService.js index d32f1aa4..169a67bc 100644 --- a/src/js/service/CurrentColorsService.js +++ b/src/js/service/CurrentColorsService.js @@ -8,6 +8,7 @@ this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this)); this.colorSorter = new pskl.service.color.ColorSorter(); + this.paletteService = pskl.app.paletteService; this.framesColorsCache_ = {}; }; @@ -15,24 +16,35 @@ ns.CurrentColorsService.prototype.init = function () { $.subscribe(Events.PISKEL_RESET, this.onPiskelUpdated_.bind(this)); $.subscribe(Events.TOOL_RELEASED, this.onPiskelUpdated_.bind(this)); + $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); + }; - // this.updateTimer = window.setInterval(this.updateCurrentColors_.bind(this)); + ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () { + var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); + var palette = this.paletteService.getPaletteById(paletteId); + + return palette.id === Constants.CURRENT_COLORS_PALETTE_ID; + }; + + ns.CurrentColorsService.prototype.onUserSettingsChange_ = function (evt, name, value) { + if (name == pskl.UserSettings.SELECTED_PALETTE) { + if (this.isCurrentColorsPaletteSelected_()) { + this.updateCurrentColors_(); + } + } }; ns.CurrentColorsService.prototype.getCurrentColors = function () { return this.currentColors; }; - ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { - var frameColors = {}; - frame.forEachPixel(function (color, x, y) { - var hexColor = this.toHexColor_(color); - frameColors[hexColor] = true; - }.bind(this)); - return frameColors; + ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { + if (this.isCurrentColorsPaletteSelected_()) { + this.updateCurrentColors_(); + } }; - ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { + ns.CurrentColorsService.prototype.updateCurrentColors_ = function () { var layers = this.piskelController.getLayers(); var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); var colors = {}; @@ -50,12 +62,20 @@ // limit the array to the max colors to display var colorsArray = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); this.currentColors = this.colorSorter.sort(colorsArray); - console.log(this.currentColors); // TODO : only fire if there was a change $.publish(Events.CURRENT_COLORS_UPDATED); }; + ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { + var frameColors = {}; + frame.forEachPixel(function (color, x, y) { + var hexColor = this.toHexColor_(color); + frameColors[hexColor] = true; + }.bind(this)); + return frameColors; + }; + ns.CurrentColorsService.prototype.toHexColor_ = function (color) { if (color === Constants.TRANSPARENT_COLOR) { return color; From fe5e8966a53f9042b32e17f2feea1fba6ad7da58 Mon Sep 17 00:00:00 2001 From: juliandescottes Date: Sat, 27 Sep 2014 11:04:03 +0200 Subject: [PATCH 32/32] added shortcuts to select previous / next color in palette --- src/js/controller/PalettesListController.js | 45 ++++++++++++++++--- .../controller/dialogs/DialogsController.js | 3 +- src/js/service/CurrentColorsService.js | 36 ++++++++------- src/js/service/keyboard/CheatsheetService.js | 6 +-- src/js/service/keyboard/KeycodeTranslator.js | 4 +- src/js/service/keyboard/ShortcutService.js | 6 +++ src/js/utils/FrameUtils.js | 8 ++-- src/templates/dialogs/create-palette.html | 20 +++------ src/templates/palettes-list.html | 2 +- 9 files changed, 84 insertions(+), 46 deletions(-) diff --git a/src/js/controller/PalettesListController.js b/src/js/controller/PalettesListController.js index 3a848256..1f9e33ef 100644 --- a/src/js/controller/PalettesListController.js +++ b/src/js/controller/PalettesListController.js @@ -39,6 +39,10 @@ $.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this)); $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); + + pskl.app.shortcutService.addShortcuts(['>', 'shift+>'], this.selectNextColor_.bind(this)); + pskl.app.shortcutService.addShortcut('<', this.selectPreviousColor_.bind(this)); + this.fillPaletteList(); this.updateFromUserSettings(); this.fillColorListContainer(); @@ -58,8 +62,8 @@ var colors = this.getSelectedPaletteColors_(); if (colors.length > 0) { - var html = colors.map(function (color) { - return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color}); + var html = colors.map(function (color, index) { + return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color, index : index}); }.bind(this)).join(''); this.colorListContainer_.innerHTML = html; @@ -76,10 +80,13 @@ } }; + ns.PalettesListController.prototype.selectPalette = function (paletteId) { + pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); + }; + ns.PalettesListController.prototype.getSelectedPaletteColors_ = function () { var colors = []; - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - var palette = this.paletteService.getPaletteById(paletteId); + var palette = this.getSelectedPalette_(); if (palette) { colors = palette.getColors(); } @@ -91,8 +98,34 @@ return colors; }; - ns.PalettesListController.prototype.selectPalette = function (paletteId) { - pskl.UserSettings.set(pskl.UserSettings.SELECTED_PALETTE, paletteId); + ns.PalettesListController.prototype.getSelectedPalette_ = function () { + var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); + return this.paletteService.getPaletteById(paletteId); + }; + + ns.PalettesListController.prototype.selectNextColor_ = function () { + this.selectColor_(this.getCurrentColorIndex_() + 1); + }; + + ns.PalettesListController.prototype.selectPreviousColor_ = function () { + this.selectColor_(this.getCurrentColorIndex_() - 1); + }; + + ns.PalettesListController.prototype.getCurrentColorIndex_ = function () { + var currentIndex = 0; + var selectedColor = document.querySelector('.' + PRIMARY_COLOR_CLASSNAME); + if (selectedColor) { + currentIndex = parseInt(selectedColor.dataset.colorIndex, 10); + } + return currentIndex; + }; + + ns.PalettesListController.prototype.selectColor_ = function (index) { + var colors = this.getSelectedPaletteColors_(); + var color = colors[index]; + if (color) { + $.publish(Events.SELECT_PRIMARY_COLOR, [color]); + } }; ns.PalettesListController.prototype.onUserSettingsChange_ = function (evt, name, value) { diff --git a/src/js/controller/dialogs/DialogsController.js b/src/js/controller/dialogs/DialogsController.js index 0d8008bf..eac69e4d 100644 --- a/src/js/controller/dialogs/DialogsController.js +++ b/src/js/controller/dialogs/DialogsController.js @@ -27,7 +27,8 @@ $.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this)); $.subscribe(Events.DIALOG_HIDE, this.onDialogHideEvent_.bind(this)); - pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palettes')); + pskl.app.shortcutService.addShortcut('alt+P', this.onDialogDisplayEvent_.bind(this, null, 'create-palette')); + this.dialogWrapper_.classList.add('animated'); }; diff --git a/src/js/service/CurrentColorsService.js b/src/js/service/CurrentColorsService.js index 169a67bc..11a02536 100644 --- a/src/js/service/CurrentColorsService.js +++ b/src/js/service/CurrentColorsService.js @@ -9,21 +9,23 @@ this.colorSorter = new pskl.service.color.ColorSorter(); this.paletteService = pskl.app.paletteService; - - this.framesColorsCache_ = {}; }; ns.CurrentColorsService.prototype.init = function () { $.subscribe(Events.PISKEL_RESET, this.onPiskelUpdated_.bind(this)); $.subscribe(Events.TOOL_RELEASED, this.onPiskelUpdated_.bind(this)); - $.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this)); + $.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this)); }; - ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () { - var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); - var palette = this.paletteService.getPaletteById(paletteId); + ns.CurrentColorsService.prototype.getCurrentColors = function () { + return this.currentColors; + }; - return palette.id === Constants.CURRENT_COLORS_PALETTE_ID; + ns.CurrentColorsService.prototype.setCurrentColors = function (colors) { + if (colors.join('') !== this.currentColors.join('')) { + this.currentColors = colors; + $.publish(Events.CURRENT_COLORS_UPDATED); + } }; ns.CurrentColorsService.prototype.onUserSettingsChange_ = function (evt, name, value) { @@ -34,16 +36,19 @@ } }; - ns.CurrentColorsService.prototype.getCurrentColors = function () { - return this.currentColors; - }; - ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) { if (this.isCurrentColorsPaletteSelected_()) { this.updateCurrentColors_(); } }; + ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () { + var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE); + var palette = this.paletteService.getPaletteById(paletteId); + + return palette.id === Constants.CURRENT_COLORS_PALETTE_ID; + }; + ns.CurrentColorsService.prototype.updateCurrentColors_ = function () { var layers = this.piskelController.getLayers(); var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);}); @@ -61,22 +66,21 @@ // limit the array to the max colors to display var colorsArray = Object.keys(colors).slice(0, Constants.MAX_CURRENT_COLORS_DISPLAYED); - this.currentColors = this.colorSorter.sort(colorsArray); + var currentColors = this.colorSorter.sort(colorsArray); - // TODO : only fire if there was a change - $.publish(Events.CURRENT_COLORS_UPDATED); + this.setCurrentColors(currentColors); }; ns.CurrentColorsService.prototype.getFrameColors_ = function (frame) { var frameColors = {}; frame.forEachPixel(function (color, x, y) { - var hexColor = this.toHexColor_(color); + var hexColor = this.toHexString_(color); frameColors[hexColor] = true; }.bind(this)); return frameColors; }; - ns.CurrentColorsService.prototype.toHexColor_ = function (color) { + ns.CurrentColorsService.prototype.toHexString_ = function (color) { if (color === Constants.TRANSPARENT_COLOR) { return color; } else { diff --git a/src/js/service/keyboard/CheatsheetService.js b/src/js/service/keyboard/CheatsheetService.js index f2194c1e..d319784c 100644 --- a/src/js/service/keyboard/CheatsheetService.js +++ b/src/js/service/keyboard/CheatsheetService.js @@ -11,8 +11,7 @@ throw 'cheatsheetEl_ DOM element could not be retrieved'; } this.initMarkup_(); - pskl.app.shortcutService.addShortcut('shift+?', this.toggleCheatsheet_.bind(this)); - pskl.app.shortcutService.addShortcut('?', this.toggleCheatsheet_.bind(this)); + pskl.app.shortcutService.addShortcuts(['?', 'shift+?'], this.toggleCheatsheet_.bind(this)); var link = $('.cheatsheet-link'); link.click(this.toggleCheatsheet_.bind(this)); @@ -107,7 +106,8 @@ this.toDescriptor_('N', 'Create new frame'), this.toDescriptor_('shift + N', 'Duplicate selected frame'), this.toDescriptor_('shift + ?', 'Open/Close this popup'), - this.toDescriptor_('alt + P', 'Open the Palette Manager'), + this.toDescriptor_('alt + P', 'Create a Palette'), + this.toDescriptor_('</>', 'Select previous/next palette color'), this.toDescriptor_('alt + O', 'Toggle Onion Skin'), this.toDescriptor_('alt + L', 'Toggle Layer Preview') ]; diff --git a/src/js/service/keyboard/KeycodeTranslator.js b/src/js/service/keyboard/KeycodeTranslator.js index 23269a20..a9e352ad 100644 --- a/src/js/service/keyboard/KeycodeTranslator.js +++ b/src/js/service/keyboard/KeycodeTranslator.js @@ -7,7 +7,9 @@ 40 : "down", 46 : "del", 189 : "-", - 187 : "+" + 187 : "+", + 188 : "<", + 190 : ">" }; var ns = $.namespace('pskl.service.keyboard'); diff --git a/src/js/service/keyboard/ShortcutService.js b/src/js/service/keyboard/ShortcutService.js index bc0f77b3..960deb18 100644 --- a/src/js/service/keyboard/ShortcutService.js +++ b/src/js/service/keyboard/ShortcutService.js @@ -35,6 +35,12 @@ } }; + ns.ShortcutService.prototype.addShortcuts = function (keys, callback) { + keys.forEach(function (key) { + this.addShortcut(key, callback); + }.bind(this)); + }; + ns.ShortcutService.prototype.removeShortcut = function (rawKey) { var parsedKey = this.parseKey_(rawKey.toLowerCase()); diff --git a/src/js/utils/FrameUtils.js b/src/js/utils/FrameUtils.js index ae71a1c9..a2094d43 100644 --- a/src/js/utils/FrameUtils.js +++ b/src/js/utils/FrameUtils.js @@ -83,9 +83,9 @@ * @param {String} strColor2 color under * @return {String} the composite color */ - mergePixels_ : function (strColor1, strColor2, globalOpacity1) { - var col1 = pskl.utils.FrameUtils.toRgba_(strColor1); - var col2 = pskl.utils.FrameUtils.toRgba_(strColor2); + mergePixels__ : function (strColor1, strColor2, globalOpacity1) { + var col1 = pskl.utils.FrameUtils.toRgba__(strColor1); + var col2 = pskl.utils.FrameUtils.toRgba__(strColor2); if (typeof globalOpacity1 == 'number') { col1 = JSON.parse(JSON.stringify(col1)); col1.a = globalOpacity1 * col1.a; @@ -105,7 +105,7 @@ * @param {String} c color as a string * @return {Object} {r:Number,g:Number,b:Number,a:Number} */ - toRgba_ : function (c) { + toRgba__ : function (c) { if (colorCache[c]) { return colorCache[c]; } diff --git a/src/templates/dialogs/create-palette.html b/src/templates/dialogs/create-palette.html index a644f98a..eb8c26ea 100644 --- a/src/templates/dialogs/create-palette.html +++ b/src/templates/dialogs/create-palette.html @@ -28,33 +28,33 @@
              H - +
              S - +
              V - +

              R - +
              G - +
              B - +
              @@ -67,14 +67,6 @@ - -