Issue #446: Add export tabs, move zoom controls

This commit is contained in:
Julian Descottes 2016-05-22 23:37:28 +02:00
parent 32e701aa55
commit f66c2578ab
23 changed files with 396 additions and 245 deletions

View File

@ -56,6 +56,6 @@
margin: 5px; margin: 5px;
} }
.settings-section--application-general > .settings-item > label { .settings-section-application > .settings-item > label {
display: block; display: block;
} }

View File

@ -57,17 +57,17 @@
color: white; color: white;
} }
.scaling-factor { .export-scale {
margin-bottom: 10px; margin-bottom: 10px;
} }
.scaling-factor-input { .export-scale .scale-input {
margin: 5px; margin: 5px;
vertical-align: middle; vertical-align: middle;
width: 145px; width: 150px;
} }
.scaling-factor-text { .export-scale .scale-text {
height: 31px; height: 31px;
display: inline-block; display: inline-block;
line-height: 30px; line-height: 30px;
@ -77,3 +77,62 @@
border-radius: 3px; border-radius: 3px;
text-align: center; text-align: center;
} }
.export-resize {
margin: 10px 0;
overflow: hidden;
}
.export-resize > * {
float: left;
}
.export-resize > *:not(:last-child) {
margin-right: 10px;
}
.export-resize > .resize-field {
width: 70px;
}
.export-resize > .resize-label {
height: 23px;
line-height: 23px;
}
.export-tabs {
overflow: hidden;
position: relative;
}
.export-tabs:after {
content: "";
display: block;
position: absolute;
bottom: 0;
width: 100%;
height: 1px;
z-index: 0;
background-color: gold;
}
.export-tab {
float: left;
cursor: pointer;
padding: 5px;
border: 1px solid transparent;
/* Make sure the tab and its border are positioned above the :after element; */
position: relative;
z-index: 1;
}
.export-tab.selected,
.export-tab:hover {
color: gold;
}
.export-tab.selected {
border-color: gold gold #444 gold;
border-style: solid;
border-width: 1px;
}

View File

@ -72,7 +72,6 @@
} }
.settings-title { .settings-title {
color : gold;
margin-top: 20px; margin-top: 20px;
margin-bottom: 10px; margin-bottom: 10px;
text-transform: uppercase; text-transform: uppercase;

View File

@ -101,6 +101,10 @@
@@include('templates/settings/save.html', {}) @@include('templates/settings/save.html', {})
@@include('templates/settings/import.html', {}) @@include('templates/settings/import.html', {})
@@include('templates/settings/export.html', {}) @@include('templates/settings/export.html', {})
@@include('templates/settings/export/png.html', {})
@@include('templates/settings/export/gif.html', {})
@@include('templates/settings/export/zip.html', {})
@@include('templates/settings/export/misc.html', {})
<script type="text/javascript"> <script type="text/javascript">
@@include('piskel-boot.js', {}) @@include('piskel-boot.js', {})

View File

@ -12,7 +12,7 @@
}, },
'export' : { 'export' : {
template : 'templates/settings/export.html', template : 'templates/settings/export.html',
controller : ns.exportimage.ImageExportController controller : ns.exportimage.ExportController
}, },
'import' : { 'import' : {
template : 'templates/settings/import.html', template : 'templates/settings/import.html',

View File

@ -1,48 +1,124 @@
(function () { (function () {
var ns = $.namespace('pskl.controller.settings.exportimage'); var ns = $.namespace('pskl.controller.settings.exportimage');
ns.ImageExportController = function (piskelController) { var tabs = {
this.piskelController = piskelController; 'png' : {
this.pngExportController = new ns.PngExportController(piskelController); template : 'templates/settings/export/png.html',
this.gifExportController = new ns.GifExportController(piskelController); controller : ns.PngExportController
this.cExportController = new ns.CExportController(piskelController); },
}; 'gif' : {
template : 'templates/settings/export/gif.html',
pskl.utils.inherit(ns.ImageExportController, pskl.controller.settings.AbstractSettingController); controller : ns.GifExportController
},
ns.ImageExportController.prototype.init = function () { 'zip' : {
// Output Scaling Factor template : 'templates/settings/export/zip.html',
var scalingFactorInput = document.querySelector('.scaling-factor-input'); controller : ns.ZipExportController
scalingFactorInput.value = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING); },
this.addEventListener(scalingFactorInput, 'change', this.onScalingFactorChange_); 'misc' : {
this.addEventListener(scalingFactorInput, 'input', this.onScalingFactorChange_); template : 'templates/settings/export/misc.html',
this.updateScalingFactorText_(scalingFactorInput.value); controller : ns.MiscExportController
this.pngExportController.init();
this.gifExportController.init();
this.cExportController.init();
};
ns.ImageExportController.prototype.destroy = function () {
this.pngExportController.destroy();
this.gifExportController.destroy();
this.cExportController.destroy();
this.superclass.destroy.call(this);
};
ns.ImageExportController.prototype.onScalingFactorChange_ = function (evt) {
var target = evt.target;
var value = Math.round(parseFloat(target.value));
if (!isNaN(value)) {
this.updateScalingFactorText_(value);
pskl.UserSettings.set(pskl.UserSettings.EXPORT_SCALING, value);
} else {
target.value = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING);
} }
}; };
ns.ImageExportController.prototype.updateScalingFactorText_ = function (scale) { var DEFAULT_TAB = 'png';
var scalingFactorText = document.querySelector('.scaling-factor-text');
scalingFactorText.innerHTML = scale + 'x'; ns.ExportController = function (piskelController) {
this.piskelController = piskelController;
this.onSizeInputChange_ = this.onSizeInputChange_.bind(this);
};
pskl.utils.inherit(ns.ExportController, pskl.controller.settings.AbstractSettingController);
ns.ExportController.prototype.init = function () {
// Initialize zoom controls
this.scaleInput = document.querySelector('.export-scale .scale-input');
this.addEventListener(this.scaleInput, 'change', this.onScaleChange_);
this.addEventListener(this.scaleInput, 'input', this.onScaleChange_);
this.widthInput = document.querySelector('.export-resize .resize-width');
this.heightInput = document.querySelector('.export-resize .resize-height');
var scale = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING);
this.sizeInputWidget = new pskl.widgets.SizeInput({
widthInput : this.widthInput,
heightInput : this.heightInput,
initWidth : this.piskelController.getWidth() * scale,
initHeight : this.piskelController.getHeight() * scale,
onChange : this.onSizeInputChange_
});
this.onSizeInputChange_();
// Initialize tabs and panel
this.exportPanel = document.querySelector('.export-panel');
this.exportTabs = document.querySelector('.export-tabs');
this.addEventListener(this.exportTabs, 'click', this.onTabsClicked_);
this.selectTab(DEFAULT_TAB);
};
ns.ExportController.prototype.destroy = function () {
this.sizeInputWidget.destroy();
this.currentController.destroy();
this.superclass.destroy.call(this);
};
ns.ExportController.prototype.selectTab = function (tabId) {
if (!tabs[tabId] || this.currentTab == tabId) {
return;
}
if (this.currentController) {
this.currentController.destroy();
}
this.exportPanel.innerHTML = pskl.utils.Template.get(tabs[tabId].template);
this.currentController = new tabs[tabId].controller(this.piskelController, this);
this.currentController.init();
this.currentTab = tabId;
var selectedTab = this.exportTabs.querySelector('.selected');
if (selectedTab) {
selectedTab.classList.remove('selected');
}
this.exportTabs.querySelector('[data-tab-id="' + tabId + '"]').classList.add('selected');
};
ns.ExportController.prototype.onTabsClicked_ = function (e) {
var tabId = pskl.utils.Dom.getData(e.target, 'tabId');
this.selectTab(tabId);
};
ns.ExportController.prototype.onScaleChange_ = function () {
var value = parseFloat(this.scaleInput.value);
if (!isNaN(value)) {
if (Math.round(this.getExportZoom()) != value) {
this.sizeInputWidget.setWidth(this.piskelController.getWidth() * value);
}
pskl.UserSettings.set(pskl.UserSettings.EXPORT_SCALING, value);
}
};
ns.ExportController.prototype.updateScaleText_ = function (scale) {
scale = scale.toFixed(1);
var scaleText = document.querySelector('.export-scale .scale-text');
scaleText.innerHTML = scale + 'x';
};
ns.ExportController.prototype.onSizeInputChange_ = function () {
var zoom = this.getExportZoom();
if (isNaN(zoom)) {
return;
}
this.updateScaleText_(zoom);
this.scaleInput.value = Math.round(zoom);
if (zoom >= 1 && zoom <= 32) {
this.onScaleChange_();
}
};
ns.ExportController.prototype.getExportZoom = function () {
return parseInt(this.widthInput.value, 10) / this.piskelController.getWidth();
}; };
})(); })();

View File

@ -3,51 +3,35 @@
var URL_MAX_LENGTH = 30; var URL_MAX_LENGTH = 30;
var MAX_GIF_COLORS = 256; var MAX_GIF_COLORS = 256;
var MAX_EXPORT_ZOOM = 20;
var DEFAULT_EXPORT_ZOOM = 10;
var MAGIC_PINK = '#FF00FF'; var MAGIC_PINK = '#FF00FF';
var WHITE = '#FFFFFF'; var WHITE = '#FFFFFF';
ns.GifExportController = function (piskelController) { ns.GifExportController = function (piskelController, exportController) {
this.piskelController = piskelController; this.piskelController = piskelController;
this.exportController = exportController;
}; };
pskl.utils.inherit(ns.GifExportController, pskl.controller.settings.AbstractSettingController); pskl.utils.inherit(ns.GifExportController, pskl.controller.settings.AbstractSettingController);
/**
* List of Resolutions applicable for Gif export
* @static
* @type {Array} array of Objects {zoom:{Number}, default:{Boolean}}
*/
ns.GifExportController.RESOLUTIONS = [];
for (var i = 1 ; i <= MAX_EXPORT_ZOOM ; i++) {
ns.GifExportController.RESOLUTIONS.push({
zoom : i
});
}
ns.GifExportController.prototype.init = function () { ns.GifExportController.prototype.init = function () {
this.uploadStatusContainerEl = document.querySelector('.gif-upload-status'); this.uploadStatusContainerEl = document.querySelector('.gif-upload-status');
this.previewContainerEl = document.querySelector('.gif-export-preview'); this.previewContainerEl = document.querySelector('.gif-export-preview');
this.widthInput = document.querySelector('.export-gif-resize-width');
this.heightInput = document.querySelector('.export-gif-resize-height');
this.uploadButton = document.querySelector('.gif-upload-button'); this.uploadButton = document.querySelector('.gif-upload-button');
this.downloadButton = document.querySelector('.gif-download-button'); this.downloadButton = document.querySelector('.gif-download-button');
this.sizeInputWidget = new pskl.widgets.SizeInput(
this.widthInput, this.heightInput,
this.piskelController.getWidth(), this.piskelController.getHeight());
this.addEventListener(this.uploadButton, 'click', this.onUploadButtonClick_); this.addEventListener(this.uploadButton, 'click', this.onUploadButtonClick_);
this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_); this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_);
}; };
ns.GifExportController.prototype.destroy = function () { ns.GifExportController.prototype.destroy = function () {
this.sizeInputWidget.destroy();
this.superclass.destroy.call(this); this.superclass.destroy.call(this);
}; };
ns.GifExportController.prototype.getZoom_ = function () {
return this.exportController.getExportZoom();
};
ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) { ns.GifExportController.prototype.onUploadButtonClick_ = function (evt) {
evt.preventDefault(); evt.preventDefault();
var zoom = this.getZoom_(); var zoom = this.getZoom_();
@ -98,10 +82,6 @@
this.previewContainerEl.innerHTML = '<div><img style="max-width:32px;" src="' + src + '"/></div>'; this.previewContainerEl.innerHTML = '<div><img style="max-width:32px;" src="' + src + '"/></div>';
}; };
ns.GifExportController.prototype.getZoom_ = function () {
return parseInt(this.widthInput.value, 10) / this.piskelController.getWidth();
};
ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) { ns.GifExportController.prototype.renderAsImageDataAnimatedGIF = function(zoom, fps, cb) {
var currentColors = pskl.app.currentColorsService.getCurrentColors(); var currentColors = pskl.app.currentColorsService.getCurrentColors();
@ -172,7 +152,6 @@
return transparentColor; return transparentColor;
}; };
// FIXME : JD : HORRIBLE COPY/PASTA (JD later : where???)
ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) { ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) {
if (imageUrl) { if (imageUrl) {
var linkTpl = '<a class="image-link" href="{{link}}" target="_blank">{{shortLink}}</a>'; var linkTpl = '<a class="image-link" href="{{link}}" target="_blank">{{shortLink}}</a>';

View File

@ -3,19 +3,19 @@
var BLACK = '#000000'; var BLACK = '#000000';
ns.CExportController = function (piskelController) { ns.MiscExportController = function (piskelController) {
this.piskelController = piskelController; this.piskelController = piskelController;
}; };
pskl.utils.inherit(ns.CExportController, pskl.controller.settings.AbstractSettingController); pskl.utils.inherit(ns.MiscExportController, pskl.controller.settings.AbstractSettingController);
ns.CExportController.prototype.init = function () { ns.MiscExportController.prototype.init = function () {
var downloadButton = document.querySelector('.c-download-button'); var downloadButton = document.querySelector('.c-download-button');
this.addEventListener(downloadButton, 'click', this.onCDownloadButtonClick_); this.addEventListener(downloadButton, 'click', this.onCDownloadButtonClick_);
}; };
ns.CExportController.prototype.onCDownloadButtonClick_ = function (evt) { ns.MiscExportController.prototype.onCDownloadButtonClick_ = function (evt) {
var fileName = this.getPiskelName_() + '.c'; var fileName = this.getPiskelName_() + '.c';
var cName = this.getPiskelName_().replace(' ','_'); var cName = this.getPiskelName_().replace(' ','_');
var width = this.piskelController.getWidth(); var width = this.piskelController.getWidth();
@ -62,11 +62,11 @@
}.bind(this), 'application/text'); }.bind(this), 'application/text');
}; };
ns.CExportController.prototype.getPiskelName_ = function () { ns.MiscExportController.prototype.getPiskelName_ = function () {
return this.piskelController.getPiskel().getDescriptor().name; return this.piskelController.getPiskel().getDescriptor().name;
}; };
ns.CExportController.prototype.rgbToCHex = function (r, g, b, a) { ns.MiscExportController.prototype.rgbToCHex = function (r, g, b, a) {
var hexStr = '0x'; var hexStr = '0x';
hexStr += ('00' + a.toString(16)).substr(-2); hexStr += ('00' + a.toString(16)).substr(-2);
hexStr += ('00' + b.toString(16)).substr(-2); hexStr += ('00' + b.toString(16)).substr(-2);

View File

@ -1,25 +1,16 @@
(function () { (function () {
var ns = $.namespace('pskl.controller.settings.exportimage'); var ns = $.namespace('pskl.controller.settings.exportimage');
var URL_MAX_LENGTH = 60; ns.PngExportController = function (piskelController, exportController) {
ns.PngExportController = function (piskelController) {
this.piskelController = piskelController; this.piskelController = piskelController;
this.exportController = exportController;
}; };
pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController); pskl.utils.inherit(ns.PngExportController, pskl.controller.settings.AbstractSettingController);
ns.PngExportController.prototype.init = function () { ns.PngExportController.prototype.init = function () {
this.pngFilePrefixInput = document.querySelector('.zip-prefix-name');
this.pngFilePrefixInput.value = 'sprite_';
this.splitByLayersCheckbox = document.querySelector('.zip-split-layers-checkbox');
var downloadButton = document.querySelector('.png-download-button'); var downloadButton = document.querySelector('.png-download-button');
this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_); this.addEventListener(downloadButton, 'click', this.onPngDownloadButtonClick_);
var zipButton = document.querySelector('.zip-generate-button');
this.addEventListener(zipButton, 'click', this.onZipButtonClick_);
}; };
ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) { ns.PngExportController.prototype.onPngDownloadButtonClick_ = function (evt) {
@ -27,10 +18,10 @@
var outputCanvas = this.getFramesheetAsCanvas(); var outputCanvas = this.getFramesheetAsCanvas();
var scalingFactor = pskl.UserSettings.get(pskl.UserSettings.EXPORT_SCALING); var zoom = this.exportController.getExportZoom();
if (scalingFactor > 1) { if (zoom != 1) {
var width = outputCanvas.width * scalingFactor; var width = outputCanvas.width * zoom;
var height = outputCanvas.height * scalingFactor; var height = outputCanvas.height * zoom;
outputCanvas = pskl.utils.ImageResizer.resize(outputCanvas, width, height, false); outputCanvas = pskl.utils.ImageResizer.resize(outputCanvas, width, height, false);
} }
@ -39,54 +30,6 @@
}); });
}; };
ns.PngExportController.prototype.onZipButtonClick_ = function () {
var zip = new window.JSZip();
if (this.splitByLayersCheckbox.checked) {
this.splittedExport_(zip);
} else {
this.mergedExport_(zip);
}
var fileName = this.getPiskelName_() + '.zip';
var blob = zip.generate({
type : 'blob'
});
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
};
ns.PngExportController.prototype.mergedExport_ = function (zip) {
var paddingLength = ('' + this.piskelController.getFrameCount()).length;
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
var render = this.piskelController.renderFrameAt(i, true);
var canvas = pskl.utils.CanvasUtils.createFromImage(render);
var basename = this.pngFilePrefixInput.value;
var id = pskl.utils.StringUtils.leftPad(i, paddingLength, '0');
var filename = basename + id + '.png';
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
}
};
ns.PngExportController.prototype.splittedExport_ = function (zip) {
var layers = this.piskelController.getLayers();
var framePaddingLength = ('' + this.piskelController.getFrameCount()).length;
var layerPaddingLength = ('' + layers.length).length;
for (var j = 0; this.piskelController.hasLayerAt(j); j++) {
var layer = this.piskelController.getLayerAt(j);
var layerid = pskl.utils.StringUtils.leftPad(j, layerPaddingLength, '0');
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
var render = pskl.utils.LayerUtils.renderFrameAt(layer, i, true);
var canvas = pskl.utils.CanvasUtils.createFromImage(render);
var basename = this.pngFilePrefixInput.value;
var frameid = pskl.utils.StringUtils.leftPad(i + 1, framePaddingLength, '0');
var filename = 'l' + layerid + '_' + basename + frameid + '.png';
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
}
}
};
ns.PngExportController.prototype.getPiskelName_ = function () { ns.PngExportController.prototype.getPiskelName_ = function () {
return this.piskelController.getPiskel().getDescriptor().name; return this.piskelController.getPiskel().getDescriptor().name;
}; };
@ -95,25 +38,4 @@
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController); var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
return renderer.renderAsCanvas(); return renderer.renderAsCanvas();
}; };
ns.PngExportController.prototype.updateStatus_ = function (imageUrl, error) {
if (imageUrl) {
var linkTpl = '<a class="image-link" href="{{link}}" target="_blank">{{shortLink}}</a>';
var linkHtml = pskl.utils.Template.replace(linkTpl, {
link : imageUrl,
shortLink : this.shorten_(imageUrl, URL_MAX_LENGTH, '...')
});
this.uploadStatusContainerEl.innerHTML = 'Your image is now available at : ' + linkHtml;
} else {
// FIXME : Should display error message instead
}
};
ns.PngExportController.prototype.shorten_ = function (url, maxLength, suffix) {
if (url.length > maxLength) {
url = url.substring(0, maxLength);
url += suffix;
}
return url;
};
})(); })();

View File

@ -0,0 +1,73 @@
(function () {
var ns = $.namespace('pskl.controller.settings.exportimage');
ns.ZipExportController = function (piskelController, exportController) {
this.piskelController = piskelController;
this.exportController = exportController;
};
pskl.utils.inherit(ns.ZipExportController, pskl.controller.settings.AbstractSettingController);
ns.ZipExportController.prototype.init = function () {
this.pngFilePrefixInput = document.querySelector('.zip-prefix-name');
this.pngFilePrefixInput.value = 'sprite_';
this.splitByLayersCheckbox = document.querySelector('.zip-split-layers-checkbox');
var zipButton = document.querySelector('.zip-generate-button');
this.addEventListener(zipButton, 'click', this.onZipButtonClick_);
};
ns.ZipExportController.prototype.onZipButtonClick_ = function () {
var zip = new window.JSZip();
if (this.splitByLayersCheckbox.checked) {
this.splittedExport_(zip);
} else {
this.mergedExport_(zip);
}
var fileName = this.getPiskelName_() + '.zip';
var blob = zip.generate({
type : 'blob'
});
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
};
ns.ZipExportController.prototype.mergedExport_ = function (zip) {
var paddingLength = ('' + this.piskelController.getFrameCount()).length;
var zoom = this.exportController.getExportZoom();
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
var render = this.piskelController.renderFrameAt(i, true);
var canvas = pskl.utils.ImageResizer.scale(render, zoom);
var basename = this.pngFilePrefixInput.value;
var id = pskl.utils.StringUtils.leftPad(i, paddingLength, '0');
var filename = basename + id + '.png';
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
}
};
ns.ZipExportController.prototype.splittedExport_ = function (zip) {
var layers = this.piskelController.getLayers();
var framePaddingLength = ('' + this.piskelController.getFrameCount()).length;
var layerPaddingLength = ('' + layers.length).length;
for (var j = 0; this.piskelController.hasLayerAt(j); j++) {
var layer = this.piskelController.getLayerAt(j);
var layerid = pskl.utils.StringUtils.leftPad(j, layerPaddingLength, '0');
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
var render = pskl.utils.LayerUtils.renderFrameAt(layer, i, true);
var canvas = pskl.utils.ImageResizer.scale(render, zoom);
var basename = this.pngFilePrefixInput.value;
var frameid = pskl.utils.StringUtils.leftPad(i + 1, framePaddingLength, '0');
var filename = 'l' + layerid + '_' + basename + frameid + '.png';
zip.file(filename, pskl.utils.CanvasUtils.getBase64FromCanvas(canvas) + '\n', {base64: true});
}
}
};
ns.ZipExportController.prototype.getPiskelName_ = function () {
return this.piskelController.getPiskel().getDescriptor().name;
};
})();

View File

@ -20,9 +20,12 @@
this.resizeContentCheckbox = this.container.querySelector('.resize-content-checkbox'); this.resizeContentCheckbox = this.container.querySelector('.resize-content-checkbox');
this.maintainRatioCheckbox = this.container.querySelector('.resize-ratio-checkbox'); this.maintainRatioCheckbox = this.container.querySelector('.resize-ratio-checkbox');
var initWidth = this.piskelController.getWidth(); this.sizeInputWidget = new pskl.widgets.SizeInput({
var initHeight = this.piskelController.getHeight(); widthInput: this.widthInput,
this.sizeInputWidget = new pskl.widgets.SizeInput(this.widthInput, this.heightInput, initWidth, initHeight); heightInput: this.heightInput,
initWidth: this.piskelController.getWidth(),
initHeight: this.piskelController.getHeight(),
});
var settings = pskl.UserSettings.get('RESIZE_SETTINGS'); var settings = pskl.UserSettings.get('RESIZE_SETTINGS');
var origin = ns.AnchorWidget.ORIGIN[settings.origin] || ns.AnchorWidget.ORIGIN.TOPLEFT; var origin = ns.AnchorWidget.ORIGIN[settings.origin] || ns.AnchorWidget.ORIGIN.TOPLEFT;

View File

@ -6,6 +6,7 @@
this.isRunning = false; this.isRunning = false;
this.previousTime = 0; this.previousTime = 0;
this.callbacks = []; this.callbacks = [];
this.loop_ = this.loop_.bind(this);
}; };
ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) { ns.DrawingLoop.prototype.addCallback = function (callback, scope, args) {
@ -35,7 +36,7 @@
var delta = currentTime - this.previousTime; var delta = currentTime - this.previousTime;
this.executeCallbacks_(delta); this.executeCallbacks_(delta);
this.previousTime = currentTime; this.previousTime = currentTime;
this.requestAnimationFrame.call(window, this.loop_.bind(this)); this.requestAnimationFrame.call(window, this.loop_);
}; };
ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) { ns.DrawingLoop.prototype.executeCallbacks_ = function (deltaTime) {

View File

@ -1,16 +1,29 @@
(function () { (function () {
var ns = $.namespace('pskl.widgets'); var ns = $.namespace('pskl.widgets');
ns.SizeInput = function (widthInput, heightInput, initWidth, initHeight) {
this.widthInput = widthInput; /**
this.heightInput = heightInput; * Synchronize two "number" inputs to stick to their initial ratio.
this.initWidth = initWidth; * The synchronization can be disabled/enabled on the fly.
this.initHeight = initHeight; *
* @param {Object} options
* - {Element} widthInput
* - {Element} heightInput
* - {Number} initWidth
* - {Number} initHeight
* - {Function} onChange
*/
ns.SizeInput = function (options) {
this.widthInput = options.widthInput;
this.heightInput = options.heightInput;
this.initWidth = options.initWidth;
this.initHeight = options.initHeight;
this.onChange = options.onChange;
this.syncEnabled = true; this.syncEnabled = true;
this.lastInput = this.widthInput; this.lastInput = this.widthInput;
this.widthInput.value = initWidth; this.widthInput.value = this.initWidth;
this.heightInput.value = initHeight; this.heightInput.value = this.initHeight;
pskl.utils.Event.addEventListener(this.widthInput, 'keyup', this.onSizeInputKeyUp_, this); pskl.utils.Event.addEventListener(this.widthInput, 'keyup', this.onSizeInputKeyUp_, this);
pskl.utils.Event.addEventListener(this.heightInput, 'keyup', this.onSizeInputKeyUp_, this); pskl.utils.Event.addEventListener(this.heightInput, 'keyup', this.onSizeInputKeyUp_, this);
@ -33,6 +46,16 @@
this.syncEnabled = false; this.syncEnabled = false;
}; };
ns.SizeInput.prototype.setWidth = function (width) {
this.widthInput.value = width;
this.synchronize_(this.widthInput);
};
ns.SizeInput.prototype.setHeight = function (height) {
this.heightInput.value = height;
this.synchronize_(this.heightInput);
};
ns.SizeInput.prototype.onSizeInputKeyUp_ = function (evt) { ns.SizeInput.prototype.onSizeInputKeyUp_ = function (evt) {
var target = evt.target; var target = evt.target;
if (this.syncEnabled) { if (this.syncEnabled) {
@ -57,5 +80,9 @@
} else if (sizeInput === this.heightInput) { } else if (sizeInput === this.heightInput) {
this.widthInput.value = Math.round(value * this.initWidth / this.initHeight); this.widthInput.value = Math.round(value * this.initWidth / this.initHeight);
} }
if (this.onChange) {
this.onChange();
}
}; };
})(); })();

View File

@ -114,10 +114,11 @@
// Settings sub-controllers // Settings sub-controllers
"js/controller/settings/AbstractSettingController.js", "js/controller/settings/AbstractSettingController.js",
"js/controller/settings/ApplicationSettingsController.js", "js/controller/settings/ApplicationSettingsController.js",
"js/controller/settings/exportimage/ImageExportController.js",
"js/controller/settings/exportimage/GifExportController.js", "js/controller/settings/exportimage/GifExportController.js",
"js/controller/settings/exportimage/PngExportController.js", "js/controller/settings/exportimage/PngExportController.js",
"js/controller/settings/exportimage/CExportController.js", "js/controller/settings/exportimage/ZipExportController.js",
"js/controller/settings/exportimage/MiscExportController.js",
"js/controller/settings/exportimage/ExportController.js",
"js/controller/settings/resize/AnchorWidget.js", "js/controller/settings/resize/AnchorWidget.js",
"js/controller/settings/resize/ResizeController.js", "js/controller/settings/resize/ResizeController.js",
"js/controller/settings/resize/DefaultSizeController.js", "js/controller/settings/resize/DefaultSizeController.js",

View File

@ -1,6 +1,6 @@
<script type="text/html" id="templates/settings/application.html"> <script type="text/html" id="templates/settings/application.html">
<form action="" method="POST" name="application-settings-form"> <form action="" method="POST" name="application-settings-form">
<div class="settings-section settings-section--application-general"> <div class="settings-section settings-section-application">
<div class="settings-title"> <div class="settings-title">
General General
</div> </div>

View File

@ -1,72 +1,25 @@
<script type="text/html" id="templates/settings/export.html"> <script type="text/html" id="templates/settings/export.html">
<div class="settings-section"> <div class="settings-section settings-section-export">
<div class="settings-title"> <div class="settings-title">Export</div>
Export Spritesheet <div class="settings-item export-scale" title="Scale the exported PNG spritesheet"
</div>
<div class="settings-item">
<div class="settings-description">PNG with all frames side by side.</div>
<div class="scaling-factor"
title="Scale the exported PNG spritesheet"
rel="tooltip" rel="tooltip"
data-placement="top"> data-placement="top">
<label for="scaling-factor">Scale</label> <label for="scale-input">Scale</label>
<input type="range" class="scaling-factor-input" name="scaling-factor" min="1" max="32" step="1"/> <input type="range" class="scale-input" name="scale-input" min="1" max="32" step="1"/>
<span class="scaling-factor-text"></span> <span class="scale-text"></span>
</div> </div>
<button type="button" class="button button-primary png-download-button">Download PNG</button> <div class="settings-item export-resize">
</div> <span class="resize-label">Resolution</span>
<div class="settings-title"> <input type="text" class="textfield resize-field resize-width" autocomplete="off" name="resize-width"/>
Export as ZIP <div class="resize-label">x</div>
</div> <input type="text" class="textfield resize-field resize-height" autocomplete="off" name="resize-height"/>
<div class="settings-item">
<div class="settings-description">ZIP with one PNG file per frame.</div>
<div class="settings-description">File names will start with the prefix below.</div>
<div class="settings-item">
<label>Prefix</label>
<input type="text" class="zip-prefix-name textfield" autocomplete="off" placeholder="PNG file prefix ...">
</div>
<div class="settings-item">
<label>
<input class="zip-split-layers-checkbox checkbox-fix" type="checkbox" />
Split by layers
</label>
</div>
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
</div>
<div class="settings-title">
Export as C File
</div>
<div class="settings-item">
<div class="settings-description">C file with frame rendered as array.</div>
<button type="button" class="button button-primary c-download-button">Download C file</button>
</div>
<div class="settings-title">
Export to Animated GIF
</div>
<div class="settings-item">
<form action="" method="POST" class="gif-export-form">
<div class="settings-item">
<label>Select resolution:</label>
<div class="resize-section">
<span class="resize-section-title">Width</span>
<input type="text" class="textfield export-size-field export-gif-resize-width" autocomplete="off" name="resize-width"/>
<span>px</span>
</div>
<div class="resize-section">
<span class="resize-section-title">Height</span>
<input type="text" class="textfield export-size-field export-gif-resize-height" autocomplete="off" name="resize-height"/>
<span>px</span>
</div>
</div>
<div class="settings-item">
<button type="button" class="button button-primary gif-download-button">Download GIF</button>
<button type="button" class="button button gif-upload-button">Get public URL</button>
</div>
</form>
<div class="gif-upload">
<div class="gif-export-preview"></div>
<div class="gif-upload-status"></div>
</div> </div>
<div class="export-tabs">
<div class="export-tab" data-tab-id="png">PNG</div>
<div class="export-tab" data-tab-id="gif">GIF</div>
<div class="export-tab" data-tab-id="zip">Zip</div>
<div class="export-tab" data-tab-id="misc">Others</div>
</div> </div>
<div class="export-panel"></div>
</div> </div>
</script> </script>

View File

@ -0,0 +1,17 @@
<script type="text/html" id="templates/settings/export/gif.html">
<div class="settings-title">
Export to Animated GIF
</div>
<div class="settings-item">
<form action="" method="POST" class="gif-export-form">
<div class="settings-item">
<button type="button" class="button button-primary gif-download-button">Download GIF</button>
<button type="button" class="button button gif-upload-button">Get public URL</button>
</div>
</form>
<div class="gif-upload">
<div class="gif-export-preview"></div>
<div class="gif-upload-status"></div>
</div>
</div>
</script>

View File

@ -0,0 +1,9 @@
<script type="text/html" id="templates/settings/export/misc.html">
<div class="settings-title">
Export as C File
</div>
<div class="settings-item">
<div class="settings-description">C file with frame rendered as array.</div>
<button type="button" class="button button-primary c-download-button">Download C file</button>
</div>
</script>

View File

@ -0,0 +1,9 @@
<script type="text/html" id="templates/settings/export/png.html">
<div class="settings-title">
Export Spritesheet
</div>
<div class="settings-item">
<div class="settings-description">PNG with all frames side by side.</div>
<button type="button" class="button button-primary png-download-button">Download PNG</button>
</div>
</script>

View File

@ -0,0 +1,19 @@
<script type="text/html" id="templates/settings/export/zip.html">
<div class="settings-title">
Export as ZIP
</div>
<div class="settings-item">
<div class="settings-description">ZIP with one PNG file per frame.</div>
<div class="settings-description">File names will start with the prefix below.</div>
<div class="settings-item">
<label>Prefix</label>
<input type="text" class="zip-prefix-name textfield" autocomplete="off" placeholder="PNG file prefix ...">
</div>
<div class="settings-item">
<label>
<input class="zip-split-layers-checkbox checkbox-fix" type="checkbox" />
Split by layers
</label>
</div>
<button type="button" class="button button-primary zip-generate-button"/>Download ZIP</button>
</script>

View File

@ -1,5 +1,5 @@
<script type="text/template" id="templates/settings/import.html"> <script type="text/template" id="templates/settings/import.html">
<div class="settings-section"> <div class="settings-section settings-section-import">
<div class="settings-title"> <div class="settings-title">
Load from Browser Load from Browser
</div> </div>

View File

@ -1,5 +1,5 @@
<script type="text/html" id="templates/settings/resize.html"> <script type="text/html" id="templates/settings/resize.html">
<div class="settings-section"> <div class="settings-section settings-section-resize">
<!-- RESIZE DRAWING SECTION --> <!-- RESIZE DRAWING SECTION -->
<div class="settings-title"> <div class="settings-title">
Resize Resize

View File

@ -1,5 +1,5 @@
<script type="text/template" id="templates/settings/save.html"> <script type="text/template" id="templates/settings/save.html">
<div class="settings-section setting-save-section"> <div class="settings-section settings-section-save">
<form action="" method="POST" class="save-form" name="save-form"> <form action="" method="POST" class="save-form" name="save-form">
<div class="settings-title">Sprite Information</div> <div class="settings-title">Sprite Information</div>
<div class="settings-item"> <div class="settings-item">