mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Merge from master
This commit is contained in:
commit
5bbbdf64d9
77
css/cheatsheet.css
Normal file
77
css/cheatsheet.css
Normal file
|
@ -0,0 +1,77 @@
|
||||||
|
#cheatsheet-wrapper {
|
||||||
|
position: absolute;
|
||||||
|
z-index: 10000;
|
||||||
|
|
||||||
|
top: 0;
|
||||||
|
right: 0;
|
||||||
|
bottom: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
|
padding: 50px;
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cheatsheet-container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
box-sizing: border-box;
|
||||||
|
padding: 20px 10%;
|
||||||
|
border-radius: 3px;
|
||||||
|
background: rgba(0,0,0,0.9);
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cheatsheet-container h3 {
|
||||||
|
font-size:24px;
|
||||||
|
margin-top: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cheatsheet-section {
|
||||||
|
float: left;
|
||||||
|
width : 50%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cheatsheet-shortcut {
|
||||||
|
overflow: hidden;
|
||||||
|
margin: 10px 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cheatsheet-icon.tool-icon {
|
||||||
|
float: left;
|
||||||
|
display: inline-block;
|
||||||
|
|
||||||
|
height: 30px;
|
||||||
|
width: 30px;
|
||||||
|
margin: 0 20px 0 0;
|
||||||
|
|
||||||
|
background-size: 20px 20px;
|
||||||
|
background-position: 5px 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cheatsheet-description {
|
||||||
|
font-family:Courier;
|
||||||
|
color: white;
|
||||||
|
font-size : 13px;
|
||||||
|
margin-left: 20px;
|
||||||
|
line-height : 30px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.cheatsheet-key {
|
||||||
|
display : inline-block;
|
||||||
|
height: 30px;
|
||||||
|
line-height: 30px;
|
||||||
|
padding: 0 10px;
|
||||||
|
|
||||||
|
border : 1px solid gold;
|
||||||
|
border-radius: 2px;
|
||||||
|
|
||||||
|
box-sizing: border-box;
|
||||||
|
|
||||||
|
text-align: center;
|
||||||
|
font-family:Courier;
|
||||||
|
font-weight: bold;
|
||||||
|
font-size : 18px;
|
||||||
|
color: gold;
|
||||||
|
}
|
|
@ -12,6 +12,7 @@
|
||||||
<link rel="stylesheet" type="text/css" href="css/forms.css">
|
<link rel="stylesheet" type="text/css" href="css/forms.css">
|
||||||
<link rel="stylesheet" type="text/css" href="css/settings.css">
|
<link rel="stylesheet" type="text/css" href="css/settings.css">
|
||||||
<link rel="stylesheet" type="text/css" href="css/tools.css">
|
<link rel="stylesheet" type="text/css" href="css/tools.css">
|
||||||
|
<link rel="stylesheet" type="text/css" href="css/cheatsheet.css">
|
||||||
<link rel="stylesheet" type="text/css" href="css/spectrum/spectrum.css"/>
|
<link rel="stylesheet" type="text/css" href="css/spectrum/spectrum.css"/>
|
||||||
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap.css">
|
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap.css">
|
||||||
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap-tooltip-custom.css">
|
<link rel="stylesheet" type="text/css" href="css/bootstrap/bootstrap-tooltip-custom.css">
|
||||||
|
@ -55,9 +56,8 @@
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
<iframe src="templates/cheatsheet.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
|
||||||
<script type="text/javascript" src="piskel-boot.js"></script>
|
<script type="text/javascript" src="piskel-boot.js"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -6,7 +6,7 @@ var Constants = {
|
||||||
FPS : 12
|
FPS : 12
|
||||||
},
|
},
|
||||||
|
|
||||||
MODEL_VERSION : 1,
|
MODEL_VERSION : 2,
|
||||||
|
|
||||||
MAX_HEIGHT : 1024,
|
MAX_HEIGHT : 1024,
|
||||||
MAX_WIDTH : 1024,
|
MAX_WIDTH : 1024,
|
||||||
|
|
32
js/Events.js
32
js/Events.js
|
@ -3,10 +3,8 @@ var Events = {
|
||||||
|
|
||||||
TOOL_SELECTED : "TOOL_SELECTED",
|
TOOL_SELECTED : "TOOL_SELECTED",
|
||||||
TOOL_RELEASED : "TOOL_RELEASED",
|
TOOL_RELEASED : "TOOL_RELEASED",
|
||||||
PRIMARY_COLOR_SELECTED: "PRIMARY_COLOR_SELECTED",
|
SELECT_PRIMARY_COLOR: "SELECT_PRIMARY_COLOR",
|
||||||
PRIMARY_COLOR_UPDATED: "PRIMARY_COLOR_UPDATED",
|
SELECT_SECONDARY_COLOR: "SELECT_SECONDARY_COLOR",
|
||||||
SECONDARY_COLOR_SELECTED: "SECONDARY_COLOR_SELECTED",
|
|
||||||
SECONDARY_COLOR_UPDATED: "SECONDARY_COLOR_UPDATED",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* When this event is emitted, a request is sent to the localstorage
|
* When this event is emitted, a request is sent to the localstorage
|
||||||
|
@ -15,22 +13,6 @@ var Events = {
|
||||||
*/
|
*/
|
||||||
LOCALSTORAGE_REQUEST: "LOCALSTORAGE_REQUEST",
|
LOCALSTORAGE_REQUEST: "LOCALSTORAGE_REQUEST",
|
||||||
|
|
||||||
CANVAS_RIGHT_CLICKED: "CANVAS_RIGHT_CLICKED",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Event to request a refresh of the display.
|
|
||||||
* A bit overkill but, it's just workaround in our current drawing system.
|
|
||||||
* TODO: Remove or rework when redraw system is refactored.
|
|
||||||
*/
|
|
||||||
REFRESH: "REFRESH",
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Temporary event to bind the redraw of right preview film to the canvas.
|
|
||||||
* This redraw should be driven by model updates.
|
|
||||||
* TODO(vincz): Remove.
|
|
||||||
*/
|
|
||||||
REDRAW_PREVIEWFILM: "REDRAW_PREVIEWFILM",
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Fired each time a user setting change.
|
* Fired each time a user setting change.
|
||||||
* The payload will be:
|
* The payload will be:
|
||||||
|
@ -39,7 +21,6 @@ var Events = {
|
||||||
*/
|
*/
|
||||||
USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED",
|
USER_SETTINGS_CHANGED: "USER_SETTINGS_CHANGED",
|
||||||
|
|
||||||
/* Listened to by SettingsController */
|
|
||||||
CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER",
|
CLOSE_SETTINGS_DRAWER : "CLOSE_SETTINGS_DRAWER",
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -50,8 +31,6 @@ var Events = {
|
||||||
|
|
||||||
FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED",
|
FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED",
|
||||||
|
|
||||||
CURRENT_FRAME_SET: "CURRENT_FRAME_SET",
|
|
||||||
|
|
||||||
SELECTION_CREATED: "SELECTION_CREATED",
|
SELECTION_CREATED: "SELECTION_CREATED",
|
||||||
SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST",
|
SELECTION_MOVE_REQUEST: "SELECTION_MOVE_REQUEST",
|
||||||
SELECTION_DISMISSED: "SELECTION_DISMISSED",
|
SELECTION_DISMISSED: "SELECTION_DISMISSED",
|
||||||
|
@ -59,9 +38,6 @@ var Events = {
|
||||||
SHOW_NOTIFICATION: "SHOW_NOTIFICATION",
|
SHOW_NOTIFICATION: "SHOW_NOTIFICATION",
|
||||||
HIDE_NOTIFICATION: "HIDE_NOTIFICATION",
|
HIDE_NOTIFICATION: "HIDE_NOTIFICATION",
|
||||||
|
|
||||||
UNDO: "UNDO",
|
// Events triggered by keyboard
|
||||||
REDO: "REDO",
|
SELECT_TOOL : "SELECT_TOOL"
|
||||||
CUT: "CUT",
|
|
||||||
COPY: "COPY",
|
|
||||||
PASTE: "PASTE"
|
|
||||||
};
|
};
|
42
js/app.js
42
js/app.js
|
@ -10,6 +10,9 @@
|
||||||
ns.app = {
|
ns.app = {
|
||||||
|
|
||||||
init : function () {
|
init : function () {
|
||||||
|
this.shortcutService = new pskl.service.keyboard.ShortcutService();
|
||||||
|
this.shortcutService.init();
|
||||||
|
|
||||||
var size = this.readSizeFromURL_();
|
var size = this.readSizeFromURL_();
|
||||||
var piskel = new pskl.model.Piskel(size.width, size.height);
|
var piskel = new pskl.model.Piskel(size.width, size.height);
|
||||||
|
|
||||||
|
@ -20,8 +23,12 @@
|
||||||
piskel.addLayer(layer);
|
piskel.addLayer(layer);
|
||||||
|
|
||||||
this.piskelController = new pskl.controller.PiskelController(piskel);
|
this.piskelController = new pskl.controller.PiskelController(piskel);
|
||||||
|
this.piskelController.init();
|
||||||
|
|
||||||
this.drawingController = new pskl.controller.DrawingController(this.piskelController, $('#drawing-canvas-container'));
|
this.paletteController = new pskl.controller.PaletteController();
|
||||||
|
this.paletteController.init();
|
||||||
|
|
||||||
|
this.drawingController = new pskl.controller.DrawingController(this.piskelController, this.paletteController, $('#drawing-canvas-container'));
|
||||||
this.drawingController.init();
|
this.drawingController.init();
|
||||||
|
|
||||||
this.animationController = new pskl.controller.AnimatedPreviewController(this.piskelController, $('#preview-canvas-container'));
|
this.animationController = new pskl.controller.AnimatedPreviewController(this.piskelController, $('#preview-canvas-container'));
|
||||||
|
@ -39,15 +46,15 @@
|
||||||
this.settingsController = new pskl.controller.settings.SettingsController(this.piskelController);
|
this.settingsController = new pskl.controller.settings.SettingsController(this.piskelController);
|
||||||
this.settingsController.init();
|
this.settingsController.init();
|
||||||
|
|
||||||
|
this.toolController = new pskl.controller.ToolController();
|
||||||
|
this.toolController.init();
|
||||||
|
|
||||||
this.selectionManager = new pskl.selection.SelectionManager(this.piskelController);
|
this.selectionManager = new pskl.selection.SelectionManager(this.piskelController);
|
||||||
this.selectionManager.init();
|
this.selectionManager.init();
|
||||||
|
|
||||||
this.historyService = new pskl.service.HistoryService(this.piskelController);
|
this.historyService = new pskl.service.HistoryService(this.piskelController);
|
||||||
this.historyService.init();
|
this.historyService.init();
|
||||||
|
|
||||||
this.keyboardEventService = new pskl.service.KeyboardEventService();
|
|
||||||
this.keyboardEventService.init();
|
|
||||||
|
|
||||||
this.notificationController = new pskl.controller.NotificationController();
|
this.notificationController = new pskl.controller.NotificationController();
|
||||||
this.notificationController.init();
|
this.notificationController.init();
|
||||||
|
|
||||||
|
@ -57,11 +64,10 @@
|
||||||
this.imageUploadService = new pskl.service.ImageUploadService();
|
this.imageUploadService = new pskl.service.ImageUploadService();
|
||||||
this.imageUploadService.init();
|
this.imageUploadService.init();
|
||||||
|
|
||||||
this.toolController = new pskl.controller.ToolController();
|
|
||||||
this.toolController.init();
|
|
||||||
|
|
||||||
this.paletteController = new pskl.controller.PaletteController();
|
this.cheatsheetService = new pskl.service.keyboard.CheatsheetService();
|
||||||
this.paletteController.init();
|
this.cheatsheetService.init();
|
||||||
|
|
||||||
|
|
||||||
var drawingLoop = new pskl.rendering.DrawingLoop();
|
var drawingLoop = new pskl.rendering.DrawingLoop();
|
||||||
drawingLoop.addCallback(this.render, this);
|
drawingLoop.addCallback(this.render, this);
|
||||||
|
@ -96,9 +102,10 @@
|
||||||
|
|
||||||
finishInitAppEngine_ : function () {
|
finishInitAppEngine_ : function () {
|
||||||
if (pskl.framesheetData_ && pskl.framesheetData_.content) {
|
if (pskl.framesheetData_ && pskl.framesheetData_.content) {
|
||||||
var piskel = pskl.utils.Serializer.createPiskel(pskl.framesheetData_.content);
|
pskl.utils.serialization.Deserializer.deserialize(pskl.framesheetData_.content, function (piskel) {
|
||||||
pskl.app.piskelController.setPiskel(piskel);
|
pskl.app.piskelController.setPiskel(piskel);
|
||||||
pskl.app.animationController.setFPS(pskl.framesheetData_.fps);
|
pskl.app.animationController.setFPS(pskl.framesheetData_.fps);
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
|
@ -159,10 +166,11 @@
|
||||||
xhr.responseType = 'text';
|
xhr.responseType = 'text';
|
||||||
xhr.onload = function (e) {
|
xhr.onload = function (e) {
|
||||||
var res = JSON.parse(this.responseText);
|
var res = JSON.parse(this.responseText);
|
||||||
var piskel = pskl.utils.Serializer.createPiskel(res.framesheet);
|
pskl.utils.serialization.Deserializer.deserialize(res.framesheet, function (piskel) {
|
||||||
pskl.app.piskelController.setPiskel(piskel);
|
pskl.app.piskelController.setPiskel(piskel);
|
||||||
pskl.app.animationController.setFPS(res.fps);
|
pskl.app.animationController.setFPS(res.fps);
|
||||||
$.publish(Events.HIDE_NOTIFICATION);
|
$.publish(Events.HIDE_NOTIFICATION);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
xhr.onerror = function () {
|
xhr.onerror = function () {
|
||||||
|
@ -242,8 +250,8 @@
|
||||||
},
|
},
|
||||||
|
|
||||||
getFramesheetAsPng : function () {
|
getFramesheetAsPng : function () {
|
||||||
var renderer = new pskl.rendering.SpritesheetRenderer(this.piskelController);
|
var renderer = new pskl.rendering.PiskelRenderer(this.piskelController);
|
||||||
var framesheetCanvas = renderer.render();
|
var framesheetCanvas = renderer.renderAsCanvas();
|
||||||
return framesheetCanvas.toDataURL("image/png");
|
return framesheetCanvas.toDataURL("image/png");
|
||||||
},
|
},
|
||||||
|
|
||||||
|
|
|
@ -1,11 +1,13 @@
|
||||||
(function () {
|
(function () {
|
||||||
var ns = $.namespace("pskl.controller");
|
var ns = $.namespace("pskl.controller");
|
||||||
ns.DrawingController = function (piskelController, container) {
|
ns.DrawingController = function (piskelController, paletteController,container) {
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
this.piskelController = piskelController;
|
this.piskelController = piskelController;
|
||||||
|
|
||||||
|
this.paletteController = paletteController;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
|
@ -41,34 +43,16 @@
|
||||||
this.isRightClicked = false;
|
this.isRightClicked = false;
|
||||||
this.previousMousemoveTime = 0;
|
this.previousMousemoveTime = 0;
|
||||||
this.currentToolBehavior = null;
|
this.currentToolBehavior = null;
|
||||||
this.primaryColor = Constants.DEFAULT_PEN_COLOR;
|
|
||||||
this.secondaryColor = Constants.TRANSPARENT_COLOR;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.DrawingController.prototype.init = function () {
|
ns.DrawingController.prototype.init = function () {
|
||||||
this.initMouseBehavior();
|
this.initMouseBehavior();
|
||||||
|
|
||||||
$.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) {
|
$.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) {
|
||||||
console.log("Tool selected: ", toolBehavior);
|
|
||||||
this.currentToolBehavior = toolBehavior;
|
this.currentToolBehavior = toolBehavior;
|
||||||
this.overlayFrame.clear();
|
this.overlayFrame.clear();
|
||||||
}, this));
|
}, this));
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO(grosbouddha): Primary/secondary color state are kept in this general controller.
|
|
||||||
* Find a better place to store that. Perhaps PaletteController?
|
|
||||||
*/
|
|
||||||
$.subscribe(Events.PRIMARY_COLOR_SELECTED, $.proxy(function(evt, color) {
|
|
||||||
console.log("Primary color selected: ", color);
|
|
||||||
this.primaryColor = color;
|
|
||||||
$.publish(Events.PRIMARY_COLOR_UPDATED, [color]);
|
|
||||||
}, this));
|
|
||||||
$.subscribe(Events.SECONDARY_COLOR_SELECTED, $.proxy(function(evt, color) {
|
|
||||||
console.log("Secondary color selected: ", color);
|
|
||||||
this.secondaryColor = color;
|
|
||||||
$.publish(Events.SECONDARY_COLOR_UPDATED, [color]);
|
|
||||||
}, this));
|
|
||||||
|
|
||||||
$(window).resize($.proxy(this.startResizeTimer_, this));
|
$(window).resize($.proxy(this.startResizeTimer_, this));
|
||||||
|
|
||||||
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
|
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
|
||||||
|
@ -127,7 +111,6 @@
|
||||||
|
|
||||||
if(event.button == 2) { // right click
|
if(event.button == 2) { // right click
|
||||||
this.isRightClicked = true;
|
this.isRightClicked = true;
|
||||||
$.publish(Events.CANVAS_RIGHT_CLICKED);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
var coords = this.renderer.getCoordinates(event.clientX, event.clientY);
|
var coords = this.renderer.getCoordinates(event.clientX, event.clientY);
|
||||||
|
@ -249,9 +232,9 @@
|
||||||
*/
|
*/
|
||||||
ns.DrawingController.prototype.getCurrentColor_ = function () {
|
ns.DrawingController.prototype.getCurrentColor_ = function () {
|
||||||
if(this.isRightClicked) {
|
if(this.isRightClicked) {
|
||||||
return this.secondaryColor;
|
return this.paletteController.getSecondaryColor();
|
||||||
} else {
|
} else {
|
||||||
return this.primaryColor;
|
return this.paletteController.getPrimaryColor();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -1,7 +1,10 @@
|
||||||
(function () {
|
(function () {
|
||||||
var ns = $.namespace("pskl.controller");
|
var ns = $.namespace("pskl.controller");
|
||||||
|
|
||||||
ns.PaletteController = function () {};
|
ns.PaletteController = function () {
|
||||||
|
this.primaryColor = Constants.DEFAULT_PEN_COLOR;
|
||||||
|
this.secondaryColor = Constants.TRANSPARENT_COLOR;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
|
@ -10,13 +13,11 @@
|
||||||
var transparentColorPalette = $(".palette-color[data-color=TRANSPARENT]");
|
var transparentColorPalette = $(".palette-color[data-color=TRANSPARENT]");
|
||||||
transparentColorPalette.mouseup($.proxy(this.onPaletteColorClick_, this));
|
transparentColorPalette.mouseup($.proxy(this.onPaletteColorClick_, this));
|
||||||
|
|
||||||
$.subscribe(Events.PRIMARY_COLOR_UPDATED, $.proxy(function(evt, color) {
|
$.subscribe(Events.SELECT_PRIMARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:true}));
|
||||||
this.updateColorPicker_(color, $('#color-picker'));
|
$.subscribe(Events.SELECT_SECONDARY_COLOR, this.onColorSelected_.bind(this, {isPrimary:false}));
|
||||||
}, this));
|
|
||||||
|
|
||||||
$.subscribe(Events.SECONDARY_COLOR_UPDATED, $.proxy(function(evt, color) {
|
pskl.app.shortcutService.addShortcut('X', this.swapColors.bind(this));
|
||||||
this.updateColorPicker_(color, $('#secondary-color-picker'));
|
pskl.app.shortcutService.addShortcut('D', this.resetColors.bind(this));
|
||||||
}, this));
|
|
||||||
|
|
||||||
var spectrumCfg = {
|
var spectrumCfg = {
|
||||||
showPalette: true,
|
showPalette: true,
|
||||||
|
@ -45,12 +46,53 @@
|
||||||
ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) {
|
ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) {
|
||||||
var inputPicker = $(evt.target);
|
var inputPicker = $(evt.target);
|
||||||
if(evt.data.isPrimary) {
|
if(evt.data.isPrimary) {
|
||||||
$.publish(Events.PRIMARY_COLOR_SELECTED, [inputPicker.val()]);
|
this.setPrimaryColor(inputPicker.val());
|
||||||
} else {
|
} else {
|
||||||
$.publish(Events.SECONDARY_COLOR_SELECTED, [inputPicker.val()]);
|
this.setSecondaryColor(inputPicker.val());
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) {
|
||||||
|
var inputPicker = $(evt.target);
|
||||||
|
if(args.isPrimary) {
|
||||||
|
this.setPrimaryColor(color);
|
||||||
|
} else {
|
||||||
|
this.setSecondaryColor(color);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PaletteController.prototype.setPrimaryColor = function (color) {
|
||||||
|
this.primaryColor = color;
|
||||||
|
this.updateColorPicker_(color, $('#color-picker'));
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PaletteController.prototype.setSecondaryColor = function (color) {
|
||||||
|
this.secondaryColor = color;
|
||||||
|
this.updateColorPicker_(color, $('#secondary-color-picker'));
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PaletteController.prototype.getPrimaryColor = function () {
|
||||||
|
return this.primaryColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PaletteController.prototype.getSecondaryColor = function () {
|
||||||
|
return this.secondaryColor;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PaletteController.prototype.swapColors = function () {
|
||||||
|
var primaryColor = this.getPrimaryColor();
|
||||||
|
this.setPrimaryColor(this.getSecondaryColor());
|
||||||
|
this.setSecondaryColor(primaryColor);
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PaletteController.prototype.resetColors = function () {
|
||||||
|
this.setPrimaryColor(Constants.DEFAULT_PEN_COLOR);
|
||||||
|
this.setSecondaryColor(Constants.TRANSPARENT_COLOR);
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
|
|
|
@ -20,6 +20,13 @@
|
||||||
$.publish(Events.FRAME_SIZE_CHANGED);
|
$.publish(Events.FRAME_SIZE_CHANGED);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ns.PiskelController.prototype.init = function () {
|
||||||
|
pskl.app.shortcutService.addShortcut('up', this.selectPreviousFrame.bind(this));
|
||||||
|
pskl.app.shortcutService.addShortcut('down', this.selectNextFrame.bind(this));
|
||||||
|
pskl.app.shortcutService.addShortcut('n', this.addFrameAtCurrentIndex.bind(this));
|
||||||
|
pskl.app.shortcutService.addShortcut('shift+n', this.duplicateCurrentFrame.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
ns.PiskelController.prototype.getHeight = function () {
|
ns.PiskelController.prototype.getHeight = function () {
|
||||||
return this.piskel.getHeight();
|
return this.piskel.getHeight();
|
||||||
};
|
};
|
||||||
|
@ -63,15 +70,21 @@
|
||||||
return !!this.getCurrentLayer().getFrameAt(index);
|
return !!this.getCurrentLayer().getFrameAt(index);
|
||||||
};
|
};
|
||||||
|
|
||||||
// backward from framesheet
|
ns.PiskelController.prototype.addFrame = function () {
|
||||||
ns.PiskelController.prototype.getFrameByIndex =
|
this.addFrameAt(this.getFrameCount());
|
||||||
ns.PiskelController.prototype.getMergedFrameAt;
|
};
|
||||||
|
|
||||||
ns.PiskelController.prototype.addEmptyFrame = function () {
|
ns.PiskelController.prototype.addFrameAtCurrentIndex = function () {
|
||||||
|
this.addFrameAt(this.currentFrameIndex + 1);
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PiskelController.prototype.addFrameAt = function (index) {
|
||||||
var layers = this.getLayers();
|
var layers = this.getLayers();
|
||||||
layers.forEach(function (l) {
|
layers.forEach(function (l) {
|
||||||
l.addFrame(this.createEmptyFrame_());
|
l.addFrameAt(this.createEmptyFrame_(), index);
|
||||||
}.bind(this));
|
}.bind(this));
|
||||||
|
|
||||||
|
$.publish(Events.PISKEL_RESET);
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.PiskelController.prototype.createEmptyFrame_ = function () {
|
ns.PiskelController.prototype.createEmptyFrame_ = function () {
|
||||||
|
@ -92,11 +105,17 @@
|
||||||
$.publish(Events.PISKEL_RESET);
|
$.publish(Events.PISKEL_RESET);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ns.PiskelController.prototype.duplicateCurrentFrame = function () {
|
||||||
|
this.duplicateFrameAt(this.currentFrameIndex);
|
||||||
|
};
|
||||||
|
|
||||||
ns.PiskelController.prototype.duplicateFrameAt = function (index) {
|
ns.PiskelController.prototype.duplicateFrameAt = function (index) {
|
||||||
var layers = this.getLayers();
|
var layers = this.getLayers();
|
||||||
layers.forEach(function (l) {
|
layers.forEach(function (l) {
|
||||||
l.duplicateFrameAt(index);
|
l.duplicateFrameAt(index);
|
||||||
});
|
});
|
||||||
|
|
||||||
|
$.publish(Events.PISKEL_RESET);
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) {
|
ns.PiskelController.prototype.moveFrame = function (fromIndex, toIndex) {
|
||||||
|
@ -116,6 +135,20 @@
|
||||||
$.publish(Events.PISKEL_RESET);
|
$.publish(Events.PISKEL_RESET);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
ns.PiskelController.prototype.selectNextFrame = function () {
|
||||||
|
var nextIndex = this.currentFrameIndex + 1;
|
||||||
|
if (nextIndex < this.getFrameCount()) {
|
||||||
|
this.setCurrentFrameIndex(nextIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.PiskelController.prototype.selectPreviousFrame = function () {
|
||||||
|
var nextIndex = this.currentFrameIndex - 1;
|
||||||
|
if (nextIndex >= 0) {
|
||||||
|
this.setCurrentFrameIndex(nextIndex);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
ns.PiskelController.prototype.setCurrentLayerIndex = function (index) {
|
ns.PiskelController.prototype.setCurrentLayerIndex = function (index) {
|
||||||
this.currentLayerIndex = index;
|
this.currentLayerIndex = index;
|
||||||
$.publish(Events.PISKEL_RESET);
|
$.publish(Events.PISKEL_RESET);
|
||||||
|
|
|
@ -19,7 +19,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.PreviewFilmController.prototype.addFrame = function () {
|
ns.PreviewFilmController.prototype.addFrame = function () {
|
||||||
this.piskelController.addEmptyFrame();
|
this.piskelController.addFrame();
|
||||||
this.piskelController.setCurrentFrameIndex(this.piskelController.getFrameCount() - 1);
|
this.piskelController.setCurrentFrameIndex(this.piskelController.getFrameCount() - 1);
|
||||||
this.updateScrollerOverflows();
|
this.updateScrollerOverflows();
|
||||||
};
|
};
|
||||||
|
|
|
@ -1,36 +1,40 @@
|
||||||
(function () {
|
(function () {
|
||||||
var ns = $.namespace("pskl.controller");
|
var ns = $.namespace("pskl.controller");
|
||||||
|
|
||||||
|
|
||||||
ns.ToolController = function () {
|
ns.ToolController = function () {
|
||||||
|
var toDescriptor = function (id, shortcut, instance) {
|
||||||
this.toolInstances = {
|
return {id:id, shortcut:shortcut, instance:instance};
|
||||||
"simplePen" : new pskl.drawingtools.SimplePen(),
|
|
||||||
"verticalMirrorPen" : new pskl.drawingtools.VerticalMirrorPen(),
|
|
||||||
"eraser" : new pskl.drawingtools.Eraser(),
|
|
||||||
"paintBucket" : new pskl.drawingtools.PaintBucket(),
|
|
||||||
"stroke" : new pskl.drawingtools.Stroke(),
|
|
||||||
"rectangle" : new pskl.drawingtools.Rectangle(),
|
|
||||||
"circle" : new pskl.drawingtools.Circle(),
|
|
||||||
"move" : new pskl.drawingtools.Move(),
|
|
||||||
"rectangleSelect" : new pskl.drawingtools.RectangleSelect(),
|
|
||||||
"shapeSelect" : new pskl.drawingtools.ShapeSelect(),
|
|
||||||
"colorPicker" : new pskl.drawingtools.ColorPicker()
|
|
||||||
};
|
};
|
||||||
|
|
||||||
this.currentSelectedTool = this.toolInstances.simplePen;
|
this.tools = [
|
||||||
this.previousSelectedTool = this.toolInstances.simplePen;
|
toDescriptor('simplePen', 'P', new pskl.drawingtools.SimplePen()),
|
||||||
|
toDescriptor('verticalMirrorPen', 'V', new pskl.drawingtools.VerticalMirrorPen()),
|
||||||
|
toDescriptor('eraser', 'E', new pskl.drawingtools.Eraser()),
|
||||||
|
toDescriptor('paintBucket', 'B', new pskl.drawingtools.PaintBucket()),
|
||||||
|
toDescriptor('stroke', 'L', new pskl.drawingtools.Stroke()),
|
||||||
|
toDescriptor('rectangle', 'R', new pskl.drawingtools.Rectangle()),
|
||||||
|
toDescriptor('circle', 'C', new pskl.drawingtools.Circle()),
|
||||||
|
toDescriptor('move', 'M', new pskl.drawingtools.Move()),
|
||||||
|
toDescriptor('rectangleSelect', 'S', new pskl.drawingtools.RectangleSelect()),
|
||||||
|
toDescriptor('shapeSelect', 'Z', new pskl.drawingtools.ShapeSelect()),
|
||||||
|
toDescriptor('colorPicker', 'O', new pskl.drawingtools.ColorPicker())
|
||||||
|
];
|
||||||
|
|
||||||
|
this.currentSelectedTool = this.tools[0];
|
||||||
|
this.previousSelectedTool = this.tools[0];
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @public
|
* @public
|
||||||
*/
|
*/
|
||||||
ns.ToolController.prototype.init = function() {
|
ns.ToolController.prototype.init = function() {
|
||||||
this.createToolMarkup_();
|
this.createToolsDom_();
|
||||||
|
this.addKeyboardShortcuts_();
|
||||||
|
|
||||||
// Initialize tool:
|
// Initialize tool:
|
||||||
// Set SimplePen as default selected tool:
|
// Set SimplePen as default selected tool:
|
||||||
this.selectTool_(this.toolInstances.simplePen);
|
this.selectTool_(this.tools[0]);
|
||||||
// Activate listener on tool panel:
|
// Activate listener on tool panel:
|
||||||
$("#tool-section").click($.proxy(this.onToolIconClicked_, this));
|
$("#tool-section").click($.proxy(this.onToolIconClicked_, this));
|
||||||
};
|
};
|
||||||
|
@ -44,18 +48,24 @@
|
||||||
if(previousSelectedToolClass) {
|
if(previousSelectedToolClass) {
|
||||||
stage.removeClass(previousSelectedToolClass);
|
stage.removeClass(previousSelectedToolClass);
|
||||||
}
|
}
|
||||||
stage.addClass(tool.toolId);
|
stage.addClass(tool.instance.toolId);
|
||||||
stage.data("selected-tool-class", tool.toolId);
|
stage.data("selected-tool-class", tool.instance.toolId);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ns.ToolController.prototype.selectTool_ = function(tool) {
|
ns.ToolController.prototype.selectTool_ = function(tool) {
|
||||||
console.log("Selecting Tool:" , this.currentSelectedTool);
|
|
||||||
this.currentSelectedTool = tool;
|
this.currentSelectedTool = tool;
|
||||||
this.activateToolOnStage_(this.currentSelectedTool);
|
this.activateToolOnStage_(this.currentSelectedTool);
|
||||||
$.publish(Events.TOOL_SELECTED, [tool]);
|
|
||||||
|
var selectedToolElement = $('#tool-section .tool-icon.selected');
|
||||||
|
var toolElement = $('[data-tool-id=' + tool.instance.toolId + ']');
|
||||||
|
|
||||||
|
selectedToolElement.removeClass('selected');
|
||||||
|
toolElement.addClass('selected');
|
||||||
|
|
||||||
|
$.publish(Events.TOOL_SELECTED, [tool.instance]);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -70,18 +80,24 @@
|
||||||
var tool = this.getToolById_(toolId);
|
var tool = this.getToolById_(toolId);
|
||||||
if (tool) {
|
if (tool) {
|
||||||
this.selectTool_(tool);
|
this.selectTool_(tool);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
// Show tool as selected:
|
ns.ToolController.prototype.onKeyboardShortcut_ = function(charkey) {
|
||||||
$('#tool-section .tool-icon.selected').removeClass('selected');
|
for (var i = 0 ; i < this.tools.length ; i++) {
|
||||||
clickedTool.addClass('selected');
|
var tool = this.tools[i];
|
||||||
|
if (tool.shortcut.toLowerCase() === charkey.toLowerCase()) {
|
||||||
|
this.selectTool_(tool);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.ToolController.prototype.getToolById_ = function (toolId) {
|
ns.ToolController.prototype.getToolById_ = function (toolId) {
|
||||||
for(var key in this.toolInstances) {
|
for(var i = 0 ; i < this.tools.length ; i++) {
|
||||||
if (this.toolInstances[key].toolId == toolId) {
|
var tool = this.tools[i];
|
||||||
return this.toolInstances[key];
|
if (tool.instance.toolId == toolId) {
|
||||||
|
return tool;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
|
@ -90,18 +106,32 @@
|
||||||
/**
|
/**
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ns.ToolController.prototype.createToolMarkup_ = function() {
|
ns.ToolController.prototype.createToolsDom_ = function() {
|
||||||
var currentTool, toolMarkup = '', extraClass;
|
var toolMarkup = '';
|
||||||
// TODO(vincz): Tools rendering order is not enforced by the data stucture (this.toolInstances), fix that.
|
for(var i = 0 ; i < this.tools.length ; i++) {
|
||||||
for (var toolKey in this.toolInstances) {
|
toolMarkup += this.getToolMarkup_(this.tools[i]);
|
||||||
currentTool = this.toolInstances[toolKey];
|
|
||||||
extraClass = currentTool.toolId;
|
|
||||||
if (this.currentSelectedTool == currentTool) {
|
|
||||||
extraClass = extraClass + " selected";
|
|
||||||
}
|
|
||||||
toolMarkup += '<li rel="tooltip" data-placement="right" class="tool-icon ' + extraClass + '" data-tool-id="' + currentTool.toolId +
|
|
||||||
'" title="' + currentTool.helpText + '"></li>';
|
|
||||||
}
|
}
|
||||||
$('#tools-container').html(toolMarkup);
|
$('#tools-container').html(toolMarkup);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ns.ToolController.prototype.getToolMarkup_ = function(tool) {
|
||||||
|
var instance = tool.instance;
|
||||||
|
|
||||||
|
var classList = ['tool-icon', instance.toolId];
|
||||||
|
if (this.currentSelectedTool == tool) {
|
||||||
|
classList.push('selected');
|
||||||
|
}
|
||||||
|
|
||||||
|
return '<li rel="tooltip" data-placement="right" class="' + classList.join(' ') + '" data-tool-id="' + instance.toolId +
|
||||||
|
'" title="' + instance.helpText + '"></li>';
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ToolController.prototype.addKeyboardShortcuts_ = function () {
|
||||||
|
for(var i = 0 ; i < this.tools.length ; i++) {
|
||||||
|
pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this));
|
||||||
|
}
|
||||||
|
};
|
||||||
})();
|
})();
|
|
@ -114,8 +114,9 @@
|
||||||
|
|
||||||
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
for (var i = 0; i < this.piskelController.getFrameCount(); i++) {
|
||||||
var frame = this.piskelController.getFrameAt(i);
|
var frame = this.piskelController.getFrameAt(i);
|
||||||
var renderer = new pskl.rendering.CanvasRenderer(frame, zoom);
|
var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom);
|
||||||
gif.addFrame(renderer.render(), {
|
var canvas = canvasRenderer.render();
|
||||||
|
gif.addFrame(canvas.getContext('2d'), {
|
||||||
delay: 1000 / fps
|
delay: 1000 / fps
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -153,10 +153,11 @@
|
||||||
var image = pskl.utils.ImageResizer.resize(this.importedImage_, w, h, smoothing);
|
var image = pskl.utils.ImageResizer.resize(this.importedImage_, w, h, smoothing);
|
||||||
var frame = pskl.utils.FrameUtils.createFromImage(image);
|
var frame = pskl.utils.FrameUtils.createFromImage(image);
|
||||||
|
|
||||||
var piskel = pskl.utils.Serializer.createPiskel([frame]);
|
var layer = pskl.model.Layer.fromFrames('Layer 1', [frame]);
|
||||||
|
var piskel = pskl.model.Piskel.fromLayers([layer]);
|
||||||
|
|
||||||
pskl.app.piskelController.setPiskel(piskel);
|
pskl.app.piskelController.setPiskel(piskel);
|
||||||
pskl.app.animationController.setFPS(Constants.DEFAULT.FPS);
|
pskl.app.animationController.setFPS(Constants.DEFAULT.FPS);
|
||||||
|
|
||||||
this.reset_();
|
this.reset_();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -12,7 +12,7 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
pskl.utils.inherit(ns.ColorPicker, ns.BaseTool);
|
pskl.utils.inherit(ns.ColorPicker, ns.BaseTool);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @override
|
* @override
|
||||||
*/
|
*/
|
||||||
|
@ -20,9 +20,9 @@
|
||||||
if (frame.containsPixel(col, row)) {
|
if (frame.containsPixel(col, row)) {
|
||||||
var sampledColor = frame.getPixel(col, row);
|
var sampledColor = frame.getPixel(col, row);
|
||||||
if (context.button == Constants.LEFT_BUTTON) {
|
if (context.button == Constants.LEFT_BUTTON) {
|
||||||
$.publish(Events.PRIMARY_COLOR_SELECTED, [sampledColor]);
|
$.publish(Events.SELECT_PRIMARY_COLOR, [sampledColor]);
|
||||||
} else if (context.button == Constants.RIGHT_BUTTON) {
|
} else if (context.button == Constants.RIGHT_BUTTON) {
|
||||||
$.publish(Events.SECONDARY_COLOR_SELECTED, [sampledColor]);
|
$.publish(Events.SELECT_SECONDARY_COLOR, [sampledColor]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -10,6 +10,19 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a Layer instance from an already existing set a Frames
|
||||||
|
* @static
|
||||||
|
* @param {String} name layer's name
|
||||||
|
* @param {Array<pskl.model.Frame>} frames should all have the same dimensions
|
||||||
|
* @return {pskl.model.Layer}
|
||||||
|
*/
|
||||||
|
ns.Layer.fromFrames = function (name, frames) {
|
||||||
|
var layer = new ns.Layer(name);
|
||||||
|
frames.forEach(layer.addFrame.bind(layer));
|
||||||
|
return layer;
|
||||||
|
};
|
||||||
|
|
||||||
ns.Layer.prototype.getName = function () {
|
ns.Layer.prototype.getName = function () {
|
||||||
return this.name;
|
return this.name;
|
||||||
};
|
};
|
||||||
|
|
|
@ -21,6 +21,24 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Create a piskel instance from an existing set of (non empty) layers
|
||||||
|
* Layers should all be synchronized : same number of frames, same dimensions
|
||||||
|
* @param {Array<pskl.model.Layer>} layers
|
||||||
|
* @return {pskl.model.Piskel}
|
||||||
|
*/
|
||||||
|
ns.Piskel.fromLayers = function (layers) {
|
||||||
|
var piskel = null;
|
||||||
|
if (layers.length > 0 && layers[0].length() > 0) {
|
||||||
|
var sampleFrame = layers[0].getFrameAt(0);
|
||||||
|
piskel = new pskl.model.Piskel(sampleFrame.getWidth(), sampleFrame.getHeight());
|
||||||
|
layers.forEach(piskel.addLayer.bind(piskel));
|
||||||
|
} else {
|
||||||
|
throw 'Piskel.fromLayers expects array of non empty pskl.model.Layer as first argument';
|
||||||
|
}
|
||||||
|
return piskel;
|
||||||
|
};
|
||||||
|
|
||||||
ns.Piskel.prototype.getLayers = function () {
|
ns.Piskel.prototype.getLayers = function () {
|
||||||
return this.layers;
|
return this.layers;
|
||||||
};
|
};
|
||||||
|
|
|
@ -19,24 +19,20 @@
|
||||||
ns.CanvasRenderer.prototype.render = function () {
|
ns.CanvasRenderer.prototype.render = function () {
|
||||||
var canvas = this.createCanvas_();
|
var canvas = this.createCanvas_();
|
||||||
var context = canvas.getContext('2d');
|
var context = canvas.getContext('2d');
|
||||||
for(var col = 0, width = this.frame.getWidth(); col < width; col++) {
|
|
||||||
for(var row = 0, height = this.frame.getHeight(); row < height; row++) {
|
|
||||||
var color = this.frame.getPixel(col, row);
|
|
||||||
this.renderPixel_(color, col, row, context);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return context;
|
this.frame.forEachPixel(function (color, x, y) {
|
||||||
|
this.renderPixel_(color, x, y, context);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
return canvas;
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.CanvasRenderer.prototype.renderPixel_ = function (color, col, row, context) {
|
ns.CanvasRenderer.prototype.renderPixel_ = function (color, x, y, context) {
|
||||||
|
|
||||||
if(color == Constants.TRANSPARENT_COLOR) {
|
if(color == Constants.TRANSPARENT_COLOR) {
|
||||||
color = this.transparentColor_;
|
color = this.transparentColor_;
|
||||||
}
|
}
|
||||||
context.fillStyle = color;
|
context.fillStyle = color;
|
||||||
|
context.fillRect(x * this.zoom, y * this.zoom, this.zoom, this.zoom);
|
||||||
context.fillRect(col * this.zoom, row * this.zoom, this.zoom, this.zoom);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.CanvasRenderer.prototype.createCanvas_ = function () {
|
ns.CanvasRenderer.prototype.createCanvas_ = function () {
|
||||||
|
|
43
js/rendering/FramesheetRenderer.js
Normal file
43
js/rendering/FramesheetRenderer.js
Normal file
|
@ -0,0 +1,43 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.rendering');
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Render an array of frames
|
||||||
|
* @param {Array.<pskl.model.Frame>} frames
|
||||||
|
*/
|
||||||
|
ns.FramesheetRenderer = function (frames) {
|
||||||
|
if (frames.length > 0) {
|
||||||
|
this.frames = frames;
|
||||||
|
} else {
|
||||||
|
throw 'FramesheetRenderer : Invalid argument : frames is empty';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.FramesheetRenderer.prototype.renderAsCanvas = function () {
|
||||||
|
var canvas = this.createCanvas_();
|
||||||
|
for (var i = 0 ; i < this.frames.length ; i++) {
|
||||||
|
var frame = this.frames[i];
|
||||||
|
this.drawFrameInCanvas_(frame, canvas, i * frame.getWidth(), 0);
|
||||||
|
}
|
||||||
|
return canvas;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.FramesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) {
|
||||||
|
var context = canvas.getContext('2d');
|
||||||
|
frame.forEachPixel(function (color, x, y) {
|
||||||
|
if(color != Constants.TRANSPARENT_COLOR) {
|
||||||
|
context.fillStyle = color;
|
||||||
|
context.fillRect(x + offsetWidth, y + offsetHeight, 1, 1);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.FramesheetRenderer.prototype.createCanvas_ = function () {
|
||||||
|
var sampleFrame = this.frames[0];
|
||||||
|
var count = this.frames.length;
|
||||||
|
var width = count * sampleFrame.getWidth();
|
||||||
|
var height = sampleFrame.getHeight();
|
||||||
|
return pskl.CanvasUtils.createCanvas(width, height);
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
14
js/rendering/PiskelRenderer.js
Normal file
14
js/rendering/PiskelRenderer.js
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
(function () {
|
||||||
|
|
||||||
|
var ns = $.namespace("pskl.rendering");
|
||||||
|
|
||||||
|
ns.PiskelRenderer = function (piskelController) {
|
||||||
|
var frames = [];
|
||||||
|
for (var i = 0 ; i < piskelController.getFrameCount() ; i++) {
|
||||||
|
frames.push(this.piskelController.getFrameAt(i));
|
||||||
|
}
|
||||||
|
ns.FramesheetRenderer.call(this, frames);
|
||||||
|
};
|
||||||
|
|
||||||
|
pskl.utils.inherit(ns.PiskelRenderer, ns.FramesheetRenderer);
|
||||||
|
})();
|
|
@ -1,44 +0,0 @@
|
||||||
(function () {
|
|
||||||
|
|
||||||
var ns = $.namespace("pskl.rendering");
|
|
||||||
|
|
||||||
ns.SpritesheetRenderer = function (piskelController) {
|
|
||||||
this.piskelController = piskelController;
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.SpritesheetRenderer.prototype.render = function () {
|
|
||||||
var canvas = this.createCanvas_();
|
|
||||||
for (var i = 0 ; i < this.piskelController.getFrameCount() ; i++) {
|
|
||||||
var frame = this.piskelController.getFrameAt(i);
|
|
||||||
this.drawFrameInCanvas_(frame, canvas, i * this.piskelController.getWidth(), 0);
|
|
||||||
}
|
|
||||||
return canvas;
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* TODO(juliandescottes): Mutualize with code already present in FrameRenderer
|
|
||||||
*/
|
|
||||||
ns.SpritesheetRenderer.prototype.drawFrameInCanvas_ = function (frame, canvas, offsetWidth, offsetHeight) {
|
|
||||||
var context = canvas.getContext('2d');
|
|
||||||
for(var col = 0, width = frame.getWidth(); col < width; col++) {
|
|
||||||
for(var row = 0, height = frame.getHeight(); row < height; row++) {
|
|
||||||
var color = frame.getPixel(col, row);
|
|
||||||
if(color != Constants.TRANSPARENT_COLOR) {
|
|
||||||
context.fillStyle = color;
|
|
||||||
context.fillRect(col + offsetWidth, row + offsetHeight, 1, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
ns.SpritesheetRenderer.prototype.createCanvas_ = function () {
|
|
||||||
var frameCount = this.piskelController.getFrameCount();
|
|
||||||
if (frameCount > 0){
|
|
||||||
var width = frameCount * this.piskelController.getWidth();
|
|
||||||
var height = this.piskelController.getHeight();
|
|
||||||
return pskl.CanvasUtils.createCanvas(width, height);
|
|
||||||
} else {
|
|
||||||
throw "Cannot render empty Spritesheet";
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
|
@ -13,9 +13,9 @@
|
||||||
$.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this));
|
$.subscribe(Events.SELECTION_DISMISSED, $.proxy(this.onSelectionDismissed_, this));
|
||||||
$.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this));
|
$.subscribe(Events.SELECTION_MOVE_REQUEST, $.proxy(this.onSelectionMoved_, this));
|
||||||
|
|
||||||
$.subscribe(Events.PASTE, $.proxy(this.onPaste_, this));
|
pskl.app.shortcutService.addShortcut('ctrl+V', this.paste.bind(this));
|
||||||
$.subscribe(Events.COPY, $.proxy(this.onCopy_, this));
|
pskl.app.shortcutService.addShortcut('ctrl+X', this.cut.bind(this));
|
||||||
$.subscribe(Events.CUT, $.proxy(this.onCut_, this));
|
pskl.app.shortcutService.addShortcut('ctrl+C', this.copy.bind(this));
|
||||||
|
|
||||||
$.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this));
|
$.subscribe(Events.TOOL_SELECTED, $.proxy(this.onToolSelected_, this));
|
||||||
};
|
};
|
||||||
|
@ -46,10 +46,7 @@
|
||||||
this.cleanSelection_();
|
this.cleanSelection_();
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
ns.SelectionManager.prototype.cut = function() {
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ns.SelectionManager.prototype.onCut_ = function(evt) {
|
|
||||||
if(this.currentSelection) {
|
if(this.currentSelection) {
|
||||||
// Put cut target into the selection:
|
// Put cut target into the selection:
|
||||||
this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame());
|
this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame());
|
||||||
|
@ -59,9 +56,8 @@
|
||||||
for(var i=0, l=pixels.length; i<l; i++) {
|
for(var i=0, l=pixels.length; i<l; i++) {
|
||||||
try {
|
try {
|
||||||
currentFrame.setPixel(pixels[i].col, pixels[i].row, Constants.TRANSPARENT_COLOR);
|
currentFrame.setPixel(pixels[i].col, pixels[i].row, Constants.TRANSPARENT_COLOR);
|
||||||
}
|
} catch(e) {
|
||||||
catch(e) {
|
// Catching out of frame's bound pixels without testing
|
||||||
// Catchng out of frame's bound pixels without testing
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -70,7 +66,7 @@
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.SelectionManager.prototype.onPaste_ = function(evt) {
|
ns.SelectionManager.prototype.paste = function() {
|
||||||
if(this.currentSelection && this.currentSelection.hasPastedContent) {
|
if(this.currentSelection && this.currentSelection.hasPastedContent) {
|
||||||
var pixels = this.currentSelection.pixels;
|
var pixels = this.currentSelection.pixels;
|
||||||
var currentFrame = this.piskelController.getCurrentFrame();
|
var currentFrame = this.piskelController.getCurrentFrame();
|
||||||
|
@ -79,22 +75,17 @@
|
||||||
currentFrame.setPixel(
|
currentFrame.setPixel(
|
||||||
pixels[i].col, pixels[i].row,
|
pixels[i].col, pixels[i].row,
|
||||||
pixels[i].copiedColor);
|
pixels[i].copiedColor);
|
||||||
}
|
} catch(e) {
|
||||||
catch(e) {
|
// Catching out of frame's bound pixels without testing
|
||||||
// Catchng out of frame's bound pixels without testing
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
ns.SelectionManager.prototype.copy = function() {
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ns.SelectionManager.prototype.onCopy_ = function(evt) {
|
|
||||||
if(this.currentSelection && this.piskelController.getCurrentFrame()) {
|
if(this.currentSelection && this.piskelController.getCurrentFrame()) {
|
||||||
this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame());
|
this.currentSelection.fillSelectionFromFrame(this.piskelController.getCurrentFrame());
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
throw "Bad state for CUT callback in SelectionManager";
|
throw "Bad state for CUT callback in SelectionManager";
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -7,8 +7,9 @@
|
||||||
ns.HistoryService.prototype.init = function () {
|
ns.HistoryService.prototype.init = function () {
|
||||||
|
|
||||||
$.subscribe(Events.TOOL_RELEASED, this.saveState.bind(this));
|
$.subscribe(Events.TOOL_RELEASED, this.saveState.bind(this));
|
||||||
$.subscribe(Events.UNDO, this.undo.bind(this));
|
|
||||||
$.subscribe(Events.REDO, this.redo.bind(this));
|
pskl.app.shortcutService.addShortcut('ctrl+Z', this.undo.bind(this));
|
||||||
|
pskl.app.shortcutService.addShortcut('ctrl+Y', this.redo.bind(this));
|
||||||
};
|
};
|
||||||
|
|
||||||
ns.HistoryService.prototype.saveState = function () {
|
ns.HistoryService.prototype.saveState = function () {
|
||||||
|
|
|
@ -1,64 +0,0 @@
|
||||||
(function () {
|
|
||||||
var ns = $.namespace("pskl.service");
|
|
||||||
|
|
||||||
ns.KeyboardEventService = function () {};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ns.KeyboardEventService.prototype.KeyboardActions_ = {
|
|
||||||
|
|
||||||
"ctrl" : {
|
|
||||||
"z" : Events.UNDO,
|
|
||||||
"y" : Events.REDO,
|
|
||||||
"x" : Events.CUT,
|
|
||||||
"c" : Events.COPY,
|
|
||||||
"v" : Events.PASTE
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ns.KeyboardEventService.prototype.CharCodeToKeyCodeMap_ = {
|
|
||||||
|
|
||||||
90 : "z",
|
|
||||||
89 : "y",
|
|
||||||
88 : "x",
|
|
||||||
67 : "c",
|
|
||||||
86 : "v"
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @private
|
|
||||||
*/
|
|
||||||
ns.KeyboardEventService.prototype.onKeyUp_ = function(evt) {
|
|
||||||
var isMac = false;
|
|
||||||
if (navigator.appVersion.indexOf("Mac")!=-1) {
|
|
||||||
// Welcome in mac world where vowels are consons and meta used instead of ctrl:
|
|
||||||
isMac = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (isMac ? evt.metaKey : evt.ctrlKey) {
|
|
||||||
// Get key pressed:
|
|
||||||
var letter = this.CharCodeToKeyCodeMap_[evt.which];
|
|
||||||
if(letter) {
|
|
||||||
var eventToTrigger = this.KeyboardActions_.ctrl[letter];
|
|
||||||
if(eventToTrigger) {
|
|
||||||
$.publish(eventToTrigger);
|
|
||||||
|
|
||||||
evt.preventDefault();
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @public
|
|
||||||
*/
|
|
||||||
ns.KeyboardEventService.prototype.init = function() {
|
|
||||||
$(document.body).keydown($.proxy(this.onKeyUp_, this));
|
|
||||||
};
|
|
||||||
|
|
||||||
})();
|
|
|
@ -36,7 +36,6 @@
|
||||||
* @private
|
* @private
|
||||||
*/
|
*/
|
||||||
ns.LocalStorageService.prototype.persistToLocalStorage_ = function() {
|
ns.LocalStorageService.prototype.persistToLocalStorage_ = function() {
|
||||||
|
|
||||||
console.log('[LocalStorage service]: Snapshot stored');
|
console.log('[LocalStorage service]: Snapshot stored');
|
||||||
window.localStorage.snapShot = this.piskelController.serialize();
|
window.localStorage.snapShot = this.piskelController.serialize();
|
||||||
};
|
};
|
||||||
|
@ -46,8 +45,9 @@
|
||||||
*/
|
*/
|
||||||
ns.LocalStorageService.prototype.restoreFromLocalStorage_ = function() {
|
ns.LocalStorageService.prototype.restoreFromLocalStorage_ = function() {
|
||||||
var framesheet = JSON.parse(window.localStorage.snapShot);
|
var framesheet = JSON.parse(window.localStorage.snapShot);
|
||||||
var piskel = pskl.utils.Serializer.createPiskel(framesheet);
|
pskl.utils.serialization.Deserializer.deserialize(framesheet, function (piskel) {
|
||||||
pskl.app.piskelController.setPiskel(piskel);
|
pskl.app.piskelController.setPiskel(piskel);
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
104
js/service/keyboard/CheatsheetService.js
Normal file
104
js/service/keyboard/CheatsheetService.js
Normal file
|
@ -0,0 +1,104 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.service.keyboard');
|
||||||
|
|
||||||
|
ns.CheatsheetService = function () {
|
||||||
|
this.isDisplayed_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.init = function () {
|
||||||
|
this.cheatsheetEl_ = document.getElementById('cheatsheet-wrapper');
|
||||||
|
if (!this.cheatsheetEl_) {
|
||||||
|
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));
|
||||||
|
$.subscribe(Events.TOGGLE_HELP, this.toggleCheatsheet_.bind(this));
|
||||||
|
$.subscribe(Events.ESCAPE, this.onEscape_.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.toggleCheatsheet_ = function () {
|
||||||
|
if (this.isDisplayed_) {
|
||||||
|
this.hideCheatsheet_();
|
||||||
|
} else {
|
||||||
|
this.showCheatsheet_();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.onEscape_ = function () {
|
||||||
|
if (this.isDisplayed_) {
|
||||||
|
this.hideCheatsheet_();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.showCheatsheet_ = function () {
|
||||||
|
pskl.app.shortcutService.addShortcut('ESC', this.hideCheatsheet_.bind(this));
|
||||||
|
this.cheatsheetEl_.style.display = 'block';
|
||||||
|
this.isDisplayed_ = true;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.hideCheatsheet_ = function () {
|
||||||
|
pskl.app.shortcutService.removeShortcut('ESC');
|
||||||
|
this.cheatsheetEl_.style.display = 'none';
|
||||||
|
this.isDisplayed_ = false;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.initMarkup_ = function () {
|
||||||
|
this.initMarkupForTools_();
|
||||||
|
this.initMarkupForMisc_();
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.initMarkupForTools_ = function () {
|
||||||
|
var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template');
|
||||||
|
|
||||||
|
var toolShortcutsContainer = $('.cheatsheet-tool-shortcuts', this.cheatsheetEl_).get(0);
|
||||||
|
var tools = pskl.app.toolController.tools;
|
||||||
|
for (var i = 0 ; i < tools.length ; i++) {
|
||||||
|
var tool = tools[i];
|
||||||
|
var shortcutEl = pskl.utils.Template.createFromHTML(
|
||||||
|
pskl.utils.Template.replace(shortcutTemplate, {
|
||||||
|
shortcutIcon : 'tool-icon ' + tool.instance.toolId,
|
||||||
|
shortcutDescription : tool.instance.helpText,
|
||||||
|
shortcutKey : tool.shortcut
|
||||||
|
})
|
||||||
|
);
|
||||||
|
toolShortcutsContainer.appendChild(shortcutEl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.CheatsheetService.prototype.initMarkupForMisc_ = function () {
|
||||||
|
var shortcutTemplate = pskl.utils.Template.get('cheatsheet-shortcut-template');
|
||||||
|
|
||||||
|
var miscShortcutsContainer = $('.cheatsheet-misc-shortcuts', this.cheatsheetEl_).get(0);
|
||||||
|
var toDescriptor = function (shortcut, description) {
|
||||||
|
return {shortcut:shortcut, description:description};
|
||||||
|
};
|
||||||
|
var miscKeys = [
|
||||||
|
toDescriptor('X', 'Swap primary/secondary colors'),
|
||||||
|
toDescriptor('D', 'Reset default colors'),
|
||||||
|
toDescriptor('ctrl + X', 'Cut selection'),
|
||||||
|
toDescriptor('ctrl + C', 'Copy selection'),
|
||||||
|
toDescriptor('ctrl + V', 'Paste selection'),
|
||||||
|
toDescriptor('ctrl + Z', 'Undo'),
|
||||||
|
toDescriptor('ctrl + Y', 'Redo'),
|
||||||
|
toDescriptor('↑', 'Select previous frame'), /* ASCII for up-arrow */
|
||||||
|
toDescriptor('↓', 'Select next frame'), /* ASCII for down-arrow */
|
||||||
|
toDescriptor('N', 'Create new frame'),
|
||||||
|
toDescriptor('shift + N', 'Duplicate selected frame'),
|
||||||
|
toDescriptor('shift + ?', 'Open/Close this popup')
|
||||||
|
];
|
||||||
|
for (var i = 0 ; i < miscKeys.length ; i++) {
|
||||||
|
var key = miscKeys[i];
|
||||||
|
var shortcutEl = pskl.utils.Template.createFromHTML(
|
||||||
|
pskl.utils.Template.replace(shortcutTemplate, {
|
||||||
|
shortcutIcon : '',
|
||||||
|
shortcutDescription : key.description,
|
||||||
|
shortcutKey : key.shortcut
|
||||||
|
})
|
||||||
|
);
|
||||||
|
miscShortcutsContainer.appendChild(shortcutEl);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
24
js/service/keyboard/KeycodeTranslator.js
Normal file
24
js/service/keyboard/KeycodeTranslator.js
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
(function () {
|
||||||
|
var specialKeys = {
|
||||||
|
191 : "?",
|
||||||
|
27 : "esc",
|
||||||
|
38 : "up",
|
||||||
|
40 : "down"
|
||||||
|
};
|
||||||
|
|
||||||
|
var ns = $.namespace('pskl.service.keyboard');
|
||||||
|
|
||||||
|
ns.KeycodeTranslator= {
|
||||||
|
toChar : function (keycode) {
|
||||||
|
if (keycode >= 48 && keycode <= 57) {
|
||||||
|
// key is 0-9
|
||||||
|
return (keycode - 48) + "";
|
||||||
|
} else if (keycode >= 65 && keycode <= 90) {
|
||||||
|
// key is a-z, use base 36 to get the string representation
|
||||||
|
return (keycode - 65 + 10).toString(36);
|
||||||
|
} else {
|
||||||
|
return specialKeys[keycode];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
90
js/service/keyboard/ShortcutService.js
Normal file
90
js/service/keyboard/ShortcutService.js
Normal file
|
@ -0,0 +1,90 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.service.keyboard');
|
||||||
|
|
||||||
|
ns.ShortcutService = function () {
|
||||||
|
this.shortcuts_ = {};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @public
|
||||||
|
*/
|
||||||
|
ns.ShortcutService.prototype.init = function() {
|
||||||
|
$(document.body).keydown($.proxy(this.onKeyUp_, this));
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ShortcutService.prototype.addShortcut = function (rawKey, callback) {
|
||||||
|
var parsedKey = this.parseKey_(rawKey.toLowerCase());
|
||||||
|
|
||||||
|
var key = parsedKey.key,
|
||||||
|
meta = parsedKey.meta;
|
||||||
|
|
||||||
|
this.shortcuts_[key] = this.shortcuts_[key] || {};
|
||||||
|
|
||||||
|
if (this.shortcuts_[key][meta]) {
|
||||||
|
throw 'Shortcut ' + meta + ' + ' + key + ' already registered';
|
||||||
|
} else {
|
||||||
|
this.shortcuts_[key][meta] = callback;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ShortcutService.prototype.removeShortcut = function (rawKey) {
|
||||||
|
var parsedKey = this.parseKey_(rawKey.toLowerCase());
|
||||||
|
|
||||||
|
var key = parsedKey.key,
|
||||||
|
meta = parsedKey.meta;
|
||||||
|
|
||||||
|
this.shortcuts_[key] = this.shortcuts_[key] || {};
|
||||||
|
|
||||||
|
this.shortcuts_[key][meta] = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ShortcutService.prototype.parseKey_ = function (key) {
|
||||||
|
var meta = 'normal';
|
||||||
|
if (key.indexOf('ctrl+') === 0) {
|
||||||
|
meta = 'ctrl';
|
||||||
|
key = key.replace('ctrl+', '');
|
||||||
|
} else if (key.indexOf('shift+') === 0) {
|
||||||
|
meta = 'shift';
|
||||||
|
key = key.replace('shift+', '');
|
||||||
|
}
|
||||||
|
return {meta : meta, key : key};
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @private
|
||||||
|
*/
|
||||||
|
ns.ShortcutService.prototype.onKeyUp_ = function(evt) {
|
||||||
|
// jquery names FTW ...
|
||||||
|
var keycode = evt.which;
|
||||||
|
var charkey = pskl.service.keyboard.KeycodeTranslator.toChar(keycode);
|
||||||
|
|
||||||
|
var keyShortcuts = this.shortcuts_[charkey];
|
||||||
|
if(keyShortcuts) {
|
||||||
|
var cb;
|
||||||
|
if (this.isCtrlKeyPressed_(evt)) {
|
||||||
|
cb = keyShortcuts.ctrl;
|
||||||
|
} else if (this.isShiftKeyPressed_(evt)) {
|
||||||
|
cb = keyShortcuts.shift;
|
||||||
|
} else {
|
||||||
|
cb = keyShortcuts.normal;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(cb) {
|
||||||
|
cb(charkey);
|
||||||
|
evt.preventDefault();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) {
|
||||||
|
return this.isMac_() ? evt.metaKey : evt.ctrlKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) {
|
||||||
|
return evt.shiftKey;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.ShortcutService.prototype.isMac_ = function () {
|
||||||
|
return navigator.appVersion.indexOf("Mac") != -1;
|
||||||
|
};
|
||||||
|
})();
|
|
@ -107,25 +107,29 @@
|
||||||
|
|
||||||
context.drawImage(image, 0,0,w,h,0,0,w,h);
|
context.drawImage(image, 0,0,w,h,0,0,w,h);
|
||||||
var imgData = context.getImageData(0,0,w,h).data;
|
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
|
// Draw the zoomed-up pixels to a different canvas context
|
||||||
var frame = [];
|
var grid = [];
|
||||||
for (var x=0;x<image.width;++x){
|
for (var x = 0 ; x < width ; x++){
|
||||||
frame[x] = [];
|
grid[x] = [];
|
||||||
for (var y=0;y<image.height;++y){
|
for (var y = 0 ; y < height ; y++){
|
||||||
// Find the starting index in the one-dimensional image data
|
// Find the starting index in the one-dimensional image data
|
||||||
var i = (y*image.width + x)*4;
|
var i = (y * width + x)*4;
|
||||||
var r = imgData[i ];
|
var r = imageData[i ];
|
||||||
var g = imgData[i+1];
|
var g = imageData[i+1];
|
||||||
var b = imgData[i+2];
|
var b = imageData[i+2];
|
||||||
var a = imgData[i+3];
|
var a = imageData[i+3];
|
||||||
if (a < 125) {
|
if (a < 125) {
|
||||||
frame[x][y] = Constants.TRANSPARENT_COLOR;
|
grid[x][y] = Constants.TRANSPARENT_COLOR;
|
||||||
} else {
|
} else {
|
||||||
frame[x][y] = this.rgbToHex(r,g,b);
|
grid[x][y] = pskl.utils.FrameUtils.rgbToHex(r,g,b);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return frame;
|
return pskl.model.Frame.fromPixelGrid(grid);
|
||||||
},
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
31
js/utils/LayerUtils.js
Normal file
31
js/utils/LayerUtils.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.utils');
|
||||||
|
|
||||||
|
ns.LayerUtils = {
|
||||||
|
/**
|
||||||
|
* Create a pskl.model.Layer 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, frameCount) {
|
||||||
|
var w = image.width,
|
||||||
|
h = image.height,
|
||||||
|
frameWidth = w / frameCount;
|
||||||
|
|
||||||
|
var canvas = pskl.CanvasUtils.createCanvas(w, h);
|
||||||
|
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);
|
||||||
|
frames.push(frame);
|
||||||
|
}
|
||||||
|
return frames;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
})();
|
|
@ -1,87 +0,0 @@
|
||||||
(function () {
|
|
||||||
var ns = $.namespace('pskl.utils');
|
|
||||||
ns.Serializer = {
|
|
||||||
serializePiskel : function (piskel) {
|
|
||||||
var serializedLayers = piskel.getLayers().map(function (l) {
|
|
||||||
return pskl.utils.Serializer.serializeLayer(l);
|
|
||||||
});
|
|
||||||
return JSON.stringify({
|
|
||||||
modelVersion : Constants.MODEL_VERSION,
|
|
||||||
piskel : {
|
|
||||||
height : piskel.getHeight(),
|
|
||||||
width : piskel.getWidth(),
|
|
||||||
layers : serializedLayers
|
|
||||||
}
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
serializeLayer : function (layer) {
|
|
||||||
var serializedFrames = layer.getFrames().map(function (f) {
|
|
||||||
return f.serialize();
|
|
||||||
});
|
|
||||||
return JSON.stringify({
|
|
||||||
name : layer.getName(),
|
|
||||||
frames : serializedFrames
|
|
||||||
});
|
|
||||||
},
|
|
||||||
|
|
||||||
deserializePiskel : function (piskelString) {
|
|
||||||
var piskelData = JSON.parse(piskelString);
|
|
||||||
return this.createPiskelFromData(piskelData);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Similar to deserializePiskel, but dealing directly with a parsed piskel
|
|
||||||
* @param {Object} piskelData JSON.parse of a serialized piskel
|
|
||||||
* @return {pskl.model.Piskel} a piskel
|
|
||||||
*/
|
|
||||||
createPiskel : function (piskelData) {
|
|
||||||
var piskel = null;
|
|
||||||
if (piskelData.modelVersion == Constants.MODEL_VERSION) {
|
|
||||||
var pData = piskelData.piskel;
|
|
||||||
piskel = new pskl.model.Piskel(pData.width, pData.height);
|
|
||||||
|
|
||||||
pData.layers.forEach(function (serializedLayer) {
|
|
||||||
var layer = pskl.utils.Serializer.deserializeLayer(serializedLayer);
|
|
||||||
piskel.addLayer(layer);
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
piskel = pskl.utils.Serializer.backwardDeserializer_(piskelData);
|
|
||||||
}
|
|
||||||
|
|
||||||
return piskel;
|
|
||||||
},
|
|
||||||
|
|
||||||
deserializeLayer : function (layerString) {
|
|
||||||
var lData = JSON.parse(layerString);
|
|
||||||
var layer = new pskl.model.Layer(lData.name);
|
|
||||||
|
|
||||||
lData.frames.forEach(function (serializedFrame) {
|
|
||||||
var frame = pskl.utils.Serializer.deserializeFrame(serializedFrame);
|
|
||||||
layer.addFrame(frame);
|
|
||||||
});
|
|
||||||
|
|
||||||
return layer;
|
|
||||||
},
|
|
||||||
|
|
||||||
deserializeFrame : function (frameString) {
|
|
||||||
var framePixelGrid = JSON.parse(frameString);
|
|
||||||
return pskl.model.Frame.fromPixelGrid(framePixelGrid);
|
|
||||||
},
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Deserialize old piskel framesheets. Initially piskels were stored as arrays of frames : "[[pixelGrid],[pixelGrid],[pixelGrid]]".
|
|
||||||
*/
|
|
||||||
backwardDeserializer_ : function (frames) {
|
|
||||||
var layer = new pskl.model.Layer('Layer 1');
|
|
||||||
frames.forEach(function (frame) {
|
|
||||||
layer.addFrame(pskl.model.Frame.fromPixelGrid(frame));
|
|
||||||
});
|
|
||||||
var width = layer.getFrameAt(0).getWidth(), height = layer.getFrameAt(0).getHeight();
|
|
||||||
var piskel = new pskl.model.Piskel(width, height);
|
|
||||||
piskel.addLayer(layer);
|
|
||||||
|
|
||||||
return piskel;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
})();
|
|
68
js/utils/serialization/Deserializer.js
Normal file
68
js/utils/serialization/Deserializer.js
Normal file
|
@ -0,0 +1,68 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.utils.serialization');
|
||||||
|
|
||||||
|
ns.Deserializer = function (data, callback) {
|
||||||
|
this.layersToLoad_ = 0;
|
||||||
|
this.data_ = data;
|
||||||
|
this.callback_ = callback;
|
||||||
|
this.piskel_ = null;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer.deserialize = function (data, callback) {
|
||||||
|
var deserializer;
|
||||||
|
if (data.modelVersion == Constants.MODEL_VERSION) {
|
||||||
|
deserializer = new ns.Deserializer(data, callback);
|
||||||
|
} else if (data.modelVersion == 1) {
|
||||||
|
deserializer = new ns.backward.Deserializer_v1(data, callback);
|
||||||
|
} else {
|
||||||
|
deserializer = new ns.backward.Deserializer_v0(data, callback);
|
||||||
|
}
|
||||||
|
deserializer.deserialize();
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer.prototype.deserialize = function () {
|
||||||
|
var data = this.data_;
|
||||||
|
var piskelData = data.piskel;
|
||||||
|
this.piskel_ = new pskl.model.Piskel(piskelData.width, piskelData.height);
|
||||||
|
|
||||||
|
this.layersToLoad_ = piskelData.layers.length;
|
||||||
|
|
||||||
|
piskelData.layers.forEach(function (serializedLayer) {
|
||||||
|
var layer = this.deserializeLayer(serializedLayer);
|
||||||
|
this.piskel_.addLayer(layer);
|
||||||
|
}.bind(this));
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer.prototype.deserializeLayer = function (layerString) {
|
||||||
|
var layerData = JSON.parse(layerString);
|
||||||
|
var layer = new pskl.model.Layer(layerData.name);
|
||||||
|
|
||||||
|
// 1 - create an image to load the base64PNG representing the layer
|
||||||
|
var base64PNG = layerData.base64PNG;
|
||||||
|
var image = new Image();
|
||||||
|
|
||||||
|
// 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);
|
||||||
|
|
||||||
|
// 6 - add each image to the layer
|
||||||
|
frames.forEach(layer.addFrame.bind(layer));
|
||||||
|
|
||||||
|
this.onLayerLoaded_();
|
||||||
|
}.bind(this);
|
||||||
|
|
||||||
|
// 3 - set the source of the image
|
||||||
|
image.src = base64PNG;
|
||||||
|
|
||||||
|
// 4 - return a pointer to the new layer instance
|
||||||
|
return layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer.prototype.onLayerLoaded_ = function () {
|
||||||
|
this.layersToLoad_ = this.layersToLoad_ - 1;
|
||||||
|
if (this.layersToLoad_ === 0) {
|
||||||
|
this.callback_(this.piskel_);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
31
js/utils/serialization/Serializer.js
Normal file
31
js/utils/serialization/Serializer.js
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.utils');
|
||||||
|
|
||||||
|
ns.Serializer = {
|
||||||
|
serializePiskel : function (piskel) {
|
||||||
|
var serializedLayers = piskel.getLayers().map(function (l) {
|
||||||
|
return pskl.utils.Serializer.serializeLayer(l);
|
||||||
|
});
|
||||||
|
return JSON.stringify({
|
||||||
|
modelVersion : Constants.MODEL_VERSION,
|
||||||
|
piskel : {
|
||||||
|
height : piskel.getHeight(),
|
||||||
|
width : piskel.getWidth(),
|
||||||
|
layers : serializedLayers
|
||||||
|
}
|
||||||
|
});
|
||||||
|
},
|
||||||
|
|
||||||
|
serializeLayer : function (layer) {
|
||||||
|
var frames = layer.getFrames();
|
||||||
|
var renderer = new pskl.rendering.FramesheetRenderer(frames);
|
||||||
|
var base64PNG = renderer.renderAsCanvas().toDataURL();
|
||||||
|
|
||||||
|
return JSON.stringify({
|
||||||
|
name : layer.getName(),
|
||||||
|
base64PNG : base64PNG,
|
||||||
|
frameCount : frames.length
|
||||||
|
});
|
||||||
|
}
|
||||||
|
};
|
||||||
|
})();
|
18
js/utils/serialization/backward/Deserializer_v0.js
Normal file
18
js/utils/serialization/backward/Deserializer_v0.js
Normal file
|
@ -0,0 +1,18 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.utils.serialization.backward');
|
||||||
|
|
||||||
|
ns.Deserializer_v0 = function (data, callback) {
|
||||||
|
this.data_ = data;
|
||||||
|
this.callback_ = callback;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer_v0.prototype.deserialize = function () {
|
||||||
|
var pixelGrids = this.data_;
|
||||||
|
var frames = pixelGrids.map(function (grid) {
|
||||||
|
return pskl.model.Frame.fromPixelGrid(grid);
|
||||||
|
});
|
||||||
|
var layer = pskl.model.Layer.fromFrames('Layer 1', frames);
|
||||||
|
|
||||||
|
this.callback_(pskl.model.Piskel.fromLayers([layer]));
|
||||||
|
};
|
||||||
|
})();
|
36
js/utils/serialization/backward/Deserializer_v1.js
Normal file
36
js/utils/serialization/backward/Deserializer_v1.js
Normal file
|
@ -0,0 +1,36 @@
|
||||||
|
(function () {
|
||||||
|
var ns = $.namespace('pskl.utils.serialization.backward');
|
||||||
|
|
||||||
|
ns.Deserializer_v1 = function (data, callback) {
|
||||||
|
this.callback_ = callback;
|
||||||
|
this.data_ = data;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer_v1.prototype.deserialize = function () {
|
||||||
|
var piskelData = this.data_.piskel;
|
||||||
|
var piskel = new pskl.model.Piskel(piskelData.width, piskelData.height);
|
||||||
|
|
||||||
|
piskelData.layers.forEach(function (serializedLayer) {
|
||||||
|
var layer = this.deserializeLayer(serializedLayer);
|
||||||
|
piskel.addLayer(layer);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
this.callback_(piskel);
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer_v1.prototype.deserializeLayer = function (layerString) {
|
||||||
|
var layerData = JSON.parse(layerString);
|
||||||
|
var layer = new pskl.model.Layer(layerData.name);
|
||||||
|
layerData.frames.forEach(function (serializedFrame) {
|
||||||
|
var frame = this.deserializeFrame(serializedFrame);
|
||||||
|
layer.addFrame(frame);
|
||||||
|
}.bind(this));
|
||||||
|
|
||||||
|
return layer;
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Deserializer_v1.prototype.deserializeFrame = function (frameString) {
|
||||||
|
var framePixelGrid = JSON.parse(frameString);
|
||||||
|
return pskl.model.Frame.fromPixelGrid(framePixelGrid);
|
||||||
|
};
|
||||||
|
})();
|
|
@ -19,11 +19,15 @@ exports.scripts = [
|
||||||
"js/utils/Math.js",
|
"js/utils/Math.js",
|
||||||
"js/utils/FileUtils.js",
|
"js/utils/FileUtils.js",
|
||||||
"js/utils/FrameUtils.js",
|
"js/utils/FrameUtils.js",
|
||||||
|
"js/utils/LayerUtils.js",
|
||||||
"js/utils/ImageResizer.js",
|
"js/utils/ImageResizer.js",
|
||||||
"js/utils/PixelUtils.js",
|
"js/utils/PixelUtils.js",
|
||||||
"js/utils/Serializer.js",
|
|
||||||
"js/utils/Template.js",
|
"js/utils/Template.js",
|
||||||
"js/utils/UserSettings.js",
|
"js/utils/UserSettings.js",
|
||||||
|
"js/utils/serialization/Serializer.js",
|
||||||
|
"js/utils/serialization/Deserializer.js",
|
||||||
|
"js/utils/serialization/backward/Deserializer_v0.js",
|
||||||
|
"js/utils/serialization/backward/Deserializer_v1.js",
|
||||||
|
|
||||||
// Application libraries-->
|
// Application libraries-->
|
||||||
"js/rendering/DrawingLoop.js",
|
"js/rendering/DrawingLoop.js",
|
||||||
|
@ -46,7 +50,8 @@ exports.scripts = [
|
||||||
"js/rendering/frame/FrameRenderer.js",
|
"js/rendering/frame/FrameRenderer.js",
|
||||||
"js/rendering/frame/CachedFrameRenderer.js",
|
"js/rendering/frame/CachedFrameRenderer.js",
|
||||||
"js/rendering/CanvasRenderer.js",
|
"js/rendering/CanvasRenderer.js",
|
||||||
"js/rendering/SpritesheetRenderer.js",
|
"js/rendering/FramesheetRenderer.js",
|
||||||
|
"js/rendering/PiskelRenderer.js",
|
||||||
|
|
||||||
// Controllers
|
// Controllers
|
||||||
"js/controller/PiskelController.js",
|
"js/controller/PiskelController.js",
|
||||||
|
@ -69,7 +74,9 @@ exports.scripts = [
|
||||||
// Services
|
// Services
|
||||||
"js/service/LocalStorageService.js",
|
"js/service/LocalStorageService.js",
|
||||||
"js/service/HistoryService.js",
|
"js/service/HistoryService.js",
|
||||||
"js/service/KeyboardEventService.js",
|
"js/service/keyboard/ShortcutService.js",
|
||||||
|
"js/service/keyboard/KeycodeTranslator.js",
|
||||||
|
"js/service/keyboard/CheatsheetService.js",
|
||||||
"js/service/ImageUploadService.js",
|
"js/service/ImageUploadService.js",
|
||||||
|
|
||||||
// Tools
|
// Tools
|
||||||
|
|
19
templates/cheatsheet.html
Normal file
19
templates/cheatsheet.html
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
<div id="cheatsheet-wrapper" style="display:none">
|
||||||
|
<div class="cheatsheet-container">
|
||||||
|
<div class="cheatsheet-section">
|
||||||
|
<h3>Tool shortcuts</h3>
|
||||||
|
<ul class="cheatsheet-tool-shortcuts"></ul>
|
||||||
|
</div>
|
||||||
|
<div class="cheatsheet-section">
|
||||||
|
<h3>Misc shortcuts</h3>
|
||||||
|
<ul class="cheatsheet-misc-shortcuts"></ul>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<script type="text/template" id="cheatsheet-shortcut-template">
|
||||||
|
<li class="cheatsheet-shortcut">
|
||||||
|
<div class="cheatsheet-icon {{shortcutIcon}}"></div>
|
||||||
|
<span class="cheatsheet-key">{{shortcutKey}}</span>
|
||||||
|
<span class="cheatsheet-description">{{shortcutDescription}}</span>
|
||||||
|
</li>
|
||||||
|
</script>
|
Loading…
Reference in New Issue
Block a user