2013-05-28 01:42:53 +04:00
|
|
|
(function () {
|
2013-08-10 14:11:16 +04:00
|
|
|
var ns = $.namespace("pskl.controller");
|
2013-10-30 01:16:39 +04:00
|
|
|
ns.PreviewFilmController = function (piskelController, container) {
|
2013-08-10 14:11:16 +04:00
|
|
|
|
2013-09-22 23:02:43 +04:00
|
|
|
this.piskelController = piskelController;
|
2013-08-10 14:11:16 +04:00
|
|
|
this.container = container;
|
2013-10-30 01:16:39 +04:00
|
|
|
this.refreshZoom_();
|
2013-08-10 14:11:16 +04:00
|
|
|
|
|
|
|
this.redrawFlag = true;
|
2013-08-10 16:28:10 +04:00
|
|
|
};
|
2013-08-10 14:11:16 +04:00
|
|
|
|
2013-08-10 16:28:10 +04:00
|
|
|
ns.PreviewFilmController.prototype.init = function() {
|
2013-08-10 14:11:16 +04:00
|
|
|
$.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this));
|
2013-09-29 02:01:18 +04:00
|
|
|
$.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this));
|
2013-10-30 01:16:39 +04:00
|
|
|
$.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this));
|
2013-08-10 14:11:16 +04:00
|
|
|
|
|
|
|
$('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this));
|
|
|
|
this.updateScrollerOverflows();
|
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.addFrame = function () {
|
2013-11-21 01:58:20 +04:00
|
|
|
this.piskelController.addFrame();
|
2013-09-22 23:02:43 +04:00
|
|
|
this.piskelController.setCurrentFrameIndex(this.piskelController.getFrameCount() - 1);
|
2013-08-10 14:11:16 +04:00
|
|
|
this.updateScrollerOverflows();
|
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.flagForRedraw_ = function () {
|
|
|
|
this.redrawFlag = true;
|
|
|
|
};
|
|
|
|
|
2013-10-30 01:16:39 +04:00
|
|
|
ns.PreviewFilmController.prototype.refreshZoom_ = function () {
|
|
|
|
this.zoom = this.calculateZoom_();
|
2013-08-10 14:11:16 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.render = function () {
|
|
|
|
if (this.redrawFlag) {
|
|
|
|
// TODO(vincz): Full redraw on any drawing modification, optimize.
|
|
|
|
this.createPreviews_();
|
|
|
|
this.redrawFlag = false;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.updateScrollerOverflows = function () {
|
|
|
|
var scroller = $('#preview-list-scroller');
|
|
|
|
var scrollerHeight = scroller.height();
|
|
|
|
var scrollTop = scroller.scrollTop();
|
|
|
|
var scrollerContentHeight = $('#preview-list').height();
|
|
|
|
var treshold = $('.top-overflow').height();
|
|
|
|
var overflowTop = false,
|
|
|
|
overflowBottom = false;
|
|
|
|
if (scrollerHeight < scrollerContentHeight) {
|
|
|
|
if (scrollTop > treshold) {
|
|
|
|
overflowTop = true;
|
|
|
|
}
|
|
|
|
var scrollBottom = (scrollerContentHeight - scrollTop) - scrollerHeight;
|
|
|
|
if (scrollBottom > treshold) {
|
|
|
|
overflowBottom = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
var wrapper = $('#preview-list-wrapper');
|
|
|
|
wrapper.toggleClass('top-overflow-visible', overflowTop);
|
|
|
|
wrapper.toggleClass('bottom-overflow-visible', overflowBottom);
|
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.createPreviews_ = function () {
|
2013-09-29 01:52:51 +04:00
|
|
|
|
2013-08-10 14:11:16 +04:00
|
|
|
this.container.html("");
|
|
|
|
// Manually remove tooltips since mouseout events were shortcut by the DOM refresh:
|
|
|
|
$(".tooltip").remove();
|
|
|
|
|
2013-09-22 23:02:43 +04:00
|
|
|
var frameCount = this.piskelController.getFrameCount();
|
2013-08-10 14:11:16 +04:00
|
|
|
|
|
|
|
for (var i = 0, l = frameCount; i < l ; i++) {
|
|
|
|
this.container.append(this.createPreviewTile_(i));
|
|
|
|
}
|
|
|
|
// Append 'new empty frame' button
|
|
|
|
var newFrameButton = document.createElement("div");
|
|
|
|
newFrameButton.id = "add-frame-action";
|
|
|
|
newFrameButton.className = "add-frame-action";
|
|
|
|
newFrameButton.innerHTML = "<p class='label'>Add new frame</p>";
|
|
|
|
this.container.append(newFrameButton);
|
|
|
|
|
|
|
|
$(newFrameButton).click(this.addFrame.bind(this));
|
|
|
|
|
|
|
|
var needDragndropBehavior = (frameCount > 1);
|
|
|
|
if(needDragndropBehavior) {
|
|
|
|
this.initDragndropBehavior_();
|
|
|
|
}
|
|
|
|
this.updateScrollerOverflows();
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
ns.PreviewFilmController.prototype.initDragndropBehavior_ = function () {
|
2013-09-29 01:52:51 +04:00
|
|
|
|
2013-08-10 14:11:16 +04:00
|
|
|
$("#preview-list").sortable({
|
|
|
|
placeholder: "preview-tile-drop-proxy",
|
|
|
|
update: $.proxy(this.onUpdate_, this),
|
|
|
|
items: ".preview-tile"
|
|
|
|
});
|
|
|
|
$("#preview-list").disableSelection();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
*/
|
|
|
|
ns.PreviewFilmController.prototype.onUpdate_ = function( event, ui ) {
|
|
|
|
var originFrameId = parseInt(ui.item.data("tile-number"), 10);
|
|
|
|
var targetInsertionId = $('.preview-tile').index(ui.item);
|
|
|
|
|
2013-09-22 23:02:43 +04:00
|
|
|
this.piskelController.moveFrame(originFrameId, targetInsertionId);
|
|
|
|
this.piskelController.setCurrentFrameIndex(targetInsertionId);
|
2013-08-10 14:11:16 +04:00
|
|
|
|
|
|
|
// TODO(grosbouddha): move localstorage request to the model layer?
|
|
|
|
$.publish(Events.LOCALSTORAGE_REQUEST);
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* @private
|
|
|
|
* TODO(vincz): clean this giant rendering function & remove listeners.
|
|
|
|
*/
|
|
|
|
ns.PreviewFilmController.prototype.createPreviewTile_ = function(tileNumber) {
|
2013-09-22 23:02:43 +04:00
|
|
|
var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber);
|
2013-09-29 01:52:51 +04:00
|
|
|
|
2013-08-10 14:11:16 +04:00
|
|
|
var previewTileRoot = document.createElement("li");
|
|
|
|
var classname = "preview-tile";
|
|
|
|
previewTileRoot.setAttribute("data-tile-number", tileNumber);
|
|
|
|
|
2013-09-22 23:02:43 +04:00
|
|
|
if (this.piskelController.getCurrentFrame() == currentFrame) {
|
2013-08-10 14:11:16 +04:00
|
|
|
classname += " selected";
|
|
|
|
}
|
|
|
|
previewTileRoot.className = classname;
|
|
|
|
|
|
|
|
var canvasContainer = document.createElement("div");
|
|
|
|
canvasContainer.className = "canvas-container";
|
2013-09-29 01:52:51 +04:00
|
|
|
|
2013-08-10 14:11:16 +04:00
|
|
|
var canvasBackground = document.createElement("div");
|
|
|
|
canvasBackground.className = "canvas-background";
|
|
|
|
canvasContainer.appendChild(canvasBackground);
|
2013-09-29 01:52:51 +04:00
|
|
|
|
2013-08-10 14:11:16 +04:00
|
|
|
previewTileRoot.addEventListener('click', this.onPreviewClick_.bind(this, tileNumber));
|
|
|
|
|
|
|
|
var cloneFrameButton = document.createElement("button");
|
|
|
|
cloneFrameButton.setAttribute('rel', 'tooltip');
|
|
|
|
cloneFrameButton.setAttribute('data-placement', 'right');
|
|
|
|
cloneFrameButton.setAttribute('title', 'Duplicate this frame');
|
|
|
|
cloneFrameButton.className = "tile-overlay duplicate-frame-action";
|
|
|
|
previewTileRoot.appendChild(cloneFrameButton);
|
|
|
|
cloneFrameButton.addEventListener('click', this.onAddButtonClick_.bind(this, tileNumber));
|
|
|
|
|
|
|
|
// TODO(vincz): Eventually optimize this part by not recreating a FrameRenderer. Note that the real optim
|
|
|
|
// is to make this update function (#createPreviewTile) less aggressive.
|
2013-10-30 01:16:39 +04:00
|
|
|
var renderingOptions = {
|
|
|
|
"zoom" : this.zoom,
|
2013-11-01 18:39:42 +04:00
|
|
|
"height" : this.piskelController.getCurrentFrame().getHeight() * this.zoom,
|
|
|
|
"width" : this.piskelController.getCurrentFrame().getWidth() * this.zoom
|
2013-10-30 01:16:39 +04:00
|
|
|
};
|
2013-11-01 18:39:42 +04:00
|
|
|
var currentFrameRenderer = new pskl.rendering.frame.FrameRenderer($(canvasContainer), renderingOptions, ["tile-view"]);
|
2013-08-10 16:28:10 +04:00
|
|
|
currentFrameRenderer.render(currentFrame);
|
2013-09-29 01:52:51 +04:00
|
|
|
|
2013-08-10 14:11:16 +04:00
|
|
|
previewTileRoot.appendChild(canvasContainer);
|
|
|
|
|
2013-09-22 23:02:43 +04:00
|
|
|
if(tileNumber > 0 || this.piskelController.getFrameCount() > 1) {
|
2013-08-10 14:11:16 +04:00
|
|
|
// Add 'remove frame' button.
|
|
|
|
var deleteButton = document.createElement("button");
|
|
|
|
deleteButton.setAttribute('rel', 'tooltip');
|
|
|
|
deleteButton.setAttribute('data-placement', 'right');
|
|
|
|
deleteButton.setAttribute('title', 'Delete this frame');
|
|
|
|
deleteButton.className = "tile-overlay delete-frame-action";
|
|
|
|
deleteButton.addEventListener('click', this.onDeleteButtonClick_.bind(this, tileNumber));
|
|
|
|
previewTileRoot.appendChild(deleteButton);
|
|
|
|
|
|
|
|
// Add 'dragndrop handle'.
|
|
|
|
var dndHandle = document.createElement("div");
|
|
|
|
dndHandle.className = "tile-overlay dnd-action";
|
|
|
|
previewTileRoot.appendChild(dndHandle);
|
|
|
|
}
|
|
|
|
var tileCount = document.createElement("div");
|
|
|
|
tileCount.className = "tile-overlay tile-count";
|
|
|
|
tileCount.innerHTML = tileNumber;
|
|
|
|
previewTileRoot.appendChild(tileCount);
|
2013-09-29 01:52:51 +04:00
|
|
|
|
2013-08-10 14:11:16 +04:00
|
|
|
|
|
|
|
return previewTileRoot;
|
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.onPreviewClick_ = function (index, evt) {
|
|
|
|
// has not class tile-action:
|
|
|
|
if(!evt.target.classList.contains('tile-overlay')) {
|
2013-09-22 23:02:43 +04:00
|
|
|
this.piskelController.setCurrentFrameIndex(index);
|
2013-09-29 01:52:51 +04:00
|
|
|
}
|
2013-08-10 14:11:16 +04:00
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.onDeleteButtonClick_ = function (index, evt) {
|
2013-09-22 23:02:43 +04:00
|
|
|
this.piskelController.removeFrameAt(index);
|
2013-08-10 14:11:16 +04:00
|
|
|
$.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model
|
|
|
|
this.updateScrollerOverflows();
|
|
|
|
};
|
|
|
|
|
|
|
|
ns.PreviewFilmController.prototype.onAddButtonClick_ = function (index, evt) {
|
2013-09-22 23:02:43 +04:00
|
|
|
this.piskelController.duplicateFrameAt(index);
|
2013-08-10 14:11:16 +04:00
|
|
|
$.publish(Events.LOCALSTORAGE_REQUEST); // Should come from model
|
2013-09-22 23:02:43 +04:00
|
|
|
this.piskelController.setCurrentFrameIndex(index + 1);
|
2013-08-10 14:11:16 +04:00
|
|
|
this.updateScrollerOverflows();
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
2013-11-06 01:11:47 +04:00
|
|
|
* Calculate the preview zoom depending on the piskel size
|
2013-08-10 14:11:16 +04:00
|
|
|
*/
|
2013-10-30 01:16:39 +04:00
|
|
|
ns.PreviewFilmController.prototype.calculateZoom_ = function () {
|
2013-09-22 23:02:43 +04:00
|
|
|
var curFrame = this.piskelController.getCurrentFrame(),
|
2013-08-10 16:28:10 +04:00
|
|
|
frameHeight = curFrame.getHeight(),
|
|
|
|
frameWidth = curFrame.getWidth(),
|
|
|
|
maxFrameDim = Math.max(frameWidth, frameHeight);
|
|
|
|
|
|
|
|
var previewHeight = Constants.PREVIEW_FILM_SIZE * frameHeight / maxFrameDim;
|
|
|
|
var previewWidth = Constants.PREVIEW_FILM_SIZE * frameWidth / maxFrameDim;
|
2013-08-10 14:11:16 +04:00
|
|
|
|
2013-11-06 01:11:47 +04:00
|
|
|
return pskl.PixelUtils.calculateZoom(previewHeight, previewWidth, frameHeight, frameWidth) || 1;
|
2013-08-10 14:11:16 +04:00
|
|
|
};
|
2012-09-05 02:09:42 +04:00
|
|
|
})();
|