Refactored HistoryService, CurrentColorsService, draft for popup preview

This commit is contained in:
jdescottes 2015-02-27 23:54:18 +01:00
parent 0f1489727c
commit 7a355b39a0
12 changed files with 150 additions and 184 deletions

View File

@ -37,6 +37,9 @@ var Events = {
PISKEL_RESET: "PISKEL_RESET",
PISKEL_SAVE_STATE: "PISKEL_SAVE_STATE",
HISTORY_STATE_SAVED: "HISTORY_STATE_SAVED",
HISTORY_STATE_LOADED: "HISTORY_STATE_LOADED",
PISKEL_SAVED: "PISKEL_SAVED",
FRAME_SIZE_CHANGED : "FRAME_SIZE_CHANGED",

View File

@ -21,13 +21,13 @@
var frame = this.piskelController.getCurrentFrame();
this.renderer = new pskl.rendering.frame.TiledFrameRenderer(this.container);
this.popupPreviewController = new pskl.controller.PopupPreviewController();
};
ns.AnimatedPreviewController.prototype.init = function () {
// the oninput event won't work on IE10 unfortunately, but at least will provide a
// consistent behavior across all other browsers that support the input type range
// see https://bugzilla.mozilla.org/show_bug.cgi?id=853670
this.fpsRangeInput.on('input change', this.onFPSSliderChange.bind(this));
document.querySelector('.right-column').style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px';
@ -39,8 +39,10 @@
$.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
$.subscribe(Events.TOOL_RELEASED, this.setRenderFlag_.bind(this, true));
$.subscribe(Events.TOOL_PRESSED, this.setRenderFlag_.bind(this, false));
$.subscribe(Events.PISKEL_SAVE_STATE, this.setRenderFlag_.bind(this, true));
$.subscribe(Events.PISKEL_RESET, this.setRenderFlag_.bind(this, true));
this.popupPreviewController.init();
this.updateZoom_();
this.updateOnionSkinPreview_();
@ -117,33 +119,27 @@
};
ns.AnimatedPreviewController.prototype.render = function (delta) {
if (this.renderFlag) {
this.elapsedTime += delta;
if (this.fps === 0) {
this._renderSelectedFrame();
} else {
this._renderCurrentAnimationFrame();
}
this.elapsedTime += delta;
var index = this.getNextIndex_(delta);
if (this.renderFlag || this.currentIndex != index) {
this.currentIndex = index;
var frame = this.piskelController.getFrameAt(this.currentIndex);
this.renderer.render(frame);
this.popupPreviewController.render(frame);
this.renderFlag = false;
}
};
ns.AnimatedPreviewController.prototype._renderSelectedFrame = function (delta) {
// the selected frame is the currentFrame from the PiskelController perspective
var selectedFrameIndex = this.piskelController.getCurrentFrameIndex();
var selectedFrame = this.piskelController.getFrameAt(selectedFrameIndex);
this.renderer.render(selectedFrame);
};
ns.AnimatedPreviewController.prototype._renderCurrentAnimationFrame = function (delta) {
var index = Math.floor(this.elapsedTime / (1000/this.fps));
if (index != this.currentIndex) {
this.currentIndex = index;
if (!this.piskelController.hasFrameAt(this.currentIndex)) {
this.currentIndex = 0;
ns.AnimatedPreviewController.prototype.getNextIndex_ = function (delta) {
if (this.fps === 0) {
return this.piskelController.getCurrentFrameIndex();
} else {
var index = Math.floor(this.elapsedTime / (1000/this.fps));
if (!this.piskelController.hasFrameAt(index)) {
this.elapsedTime = 0;
index = 0;
}
var frame = this.piskelController.getFrameAt(this.currentIndex);
this.renderer.render(frame);
return index;
}
};

View File

@ -259,6 +259,11 @@
this.selectLayer(layer);
};
ns.PiskelController.prototype.removeCurrentLayer = function () {
var currentLayerIndex = this.getCurrentLayerIndex();
this.removeLayerAt(currentLayerIndex);
};
ns.PiskelController.prototype.removeLayerAt = function (index) {
if (this.getLayers().length > 1) {
var layer = this.getLayerAt(index);

View File

@ -7,6 +7,29 @@
};
ns.PublicPiskelController.prototype.init = function () {
// DECORATED WITH RESET
this.resetWrap_('setCurrentFrameIndex');
this.resetWrap_('selectNextFrame');
this.resetWrap_('selectPreviousFrame');
this.resetWrap_('setCurrentLayerIndex');
this.resetWrap_('selectLayer');
// DECORATED WITH SAVE, NO RESET
this.saveWrap_('renameLayerAt', false);
// DECORATED WITH SAVE, WITH RESET
this.saveWrap_('removeCurrentLayer', true);
this.saveWrap_('addFrame', true);
this.saveWrap_('addFrameAtCurrentIndex', true);
this.saveWrap_('addFrameAt', true);
this.saveWrap_('removeFrameAt', true);
this.saveWrap_('duplicateCurrentFrame', true);
this.saveWrap_('duplicateFrameAt', true);
this.saveWrap_('moveFrame', true);
this.saveWrap_('createLayer', true);
this.saveWrap_('mergeDownLayerAt', true);
this.saveWrap_('moveLayerUp', true);
this.saveWrap_('moveLayerDown', true);
this.saveWrap_('removeCurrentLayer', true);
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));
@ -23,128 +46,47 @@
});
};
ns.PublicPiskelController.prototype.addFrame = function () {
this.addFrameAt(this.getFrameCount());
ns.PublicPiskelController.prototype.resetWrap_ = function (methodName) {
this[methodName] = function () {
this.piskelController[methodName].apply(this.piskelController, arguments);
$.publish(Events.PISKEL_RESET);
};
};
ns.PublicPiskelController.prototype.addFrameAtCurrentIndex = function () {
this.addFrameAt(this.getCurrentFrameIndex());
ns.PublicPiskelController.prototype.saveWrap_ = function (methodName, reset) {
this[methodName] = reset ? function () {
var stateInfo = this.getStateInfo_();
this.piskelController[methodName].apply(this.piskelController, arguments);
this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo);
$.publish(Events.PISKEL_RESET);
} : function () {
var stateInfo = this.getStateInfo_();
this.piskelController[methodName].apply(this.piskelController, arguments);
this.raiseSaveStateEvent_(this.piskelController[methodName], arguments, stateInfo);
};
};
ns.PublicPiskelController.prototype.addFrameAt = function (index) {
this.raiseSaveStateEvent_(this.piskelController.addFrameAt, [index]);
this.piskelController.addFrameAt(index);
$.publish(Events.PISKEL_RESET);
ns.PublicPiskelController.prototype.getStateInfo_ = function () {
var stateInfo = {
frameIndex : this.piskelController.currentFrameIndex,
layerIndex : this.piskelController.currentLayerIndex
};
return stateInfo;
};
ns.PublicPiskelController.prototype.removeFrameAt = function (index) {
this.raiseSaveStateEvent_(this.piskelController.removeFrameAt, [index]);
this.piskelController.removeFrameAt(index);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.duplicateCurrentFrame = function () {
this.duplicateFrameAt(this.getCurrentFrameIndex());
ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args, stateInfo) {
$.publish(Events.PISKEL_SAVE_STATE, {
type : pskl.service.HistoryService.REPLAY,
scope : this,
replay : {
fn : fn,
args : args
},
state : stateInfo
});
};
ns.PublicPiskelController.prototype.replay = function (frame, replayData) {
replayData.fn.apply(this.piskelController, replayData.args);
};
ns.PublicPiskelController.prototype.duplicateFrameAt = function (index) {
this.raiseSaveStateEvent_(this.piskelController.duplicateFrameAt, [index]);
this.piskelController.duplicateFrameAt(index);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.moveFrame = function (fromIndex, toIndex) {
this.raiseSaveStateEvent_(this.piskelController.moveFrame, [fromIndex, toIndex]);
this.piskelController.moveFrame(fromIndex, toIndex);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.setCurrentFrameIndex = function (index) {
this.piskelController.setCurrentFrameIndex(index);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.selectNextFrame = function () {
this.piskelController.selectNextFrame();
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.selectPreviousFrame = function () {
this.piskelController.selectPreviousFrame();
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.setCurrentLayerIndex = function (index) {
this.piskelController.setCurrentLayerIndex(index);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.selectLayer = function (layer) {
this.piskelController.selectLayer(layer);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.renameLayerAt = function (index, name) {
this.raiseSaveStateEvent_(this.piskelController.renameLayerAt, [index, name]);
this.piskelController.renameLayerAt(index, name);
};
ns.PublicPiskelController.prototype.createLayer = function (name) {
this.raiseSaveStateEvent_(this.piskelController.createLayer, [name]);
this.piskelController.createLayer(name);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.mergeDownLayerAt = function (index) {
this.raiseSaveStateEvent_(this.piskelController.mergeDownLayerAt, [index]);
this.piskelController.mergeDownLayerAt(index);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.moveLayerUp = function () {
this.raiseSaveStateEvent_(this.piskelController.moveLayerUp, []);
this.piskelController.moveLayerUp();
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.moveLayerDown = function () {
this.raiseSaveStateEvent_(this.piskelController.moveLayerDown, []);
this.piskelController.moveLayerDown();
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.removeCurrentLayer = function () {
var currentLayerIndex = this.getCurrentLayerIndex();
this.raiseSaveStateEvent_(this.piskelController.removeLayerAt, [currentLayerIndex]);
this.piskelController.removeLayerAt(currentLayerIndex);
$.publish(Events.PISKEL_RESET);
};
ns.PublicPiskelController.prototype.getCurrentLayerIndex = function () {
return this.piskelController.getCurrentLayerIndex();
};
ns.PublicPiskelController.prototype.getCurrentFrameIndex = function () {
return this.piskelController.currentFrameIndex;
};
ns.PublicPiskelController.prototype.getPiskel = function () {
return this.piskelController.piskel;
};
ns.PublicPiskelController.prototype.raiseSaveStateEvent_ = function (fn, args) {
$.publish(Events.PISKEL_SAVE_STATE, {
type : pskl.service.HistoryService.REPLAY_NO_SNAPSHOT,
scope : this,
replay : {
fn : fn,
args : args
}
});
};
})();

View File

@ -3,9 +3,6 @@
ns.AbstractSettingController = function () {};
ns.AbstractSettingController.prototype.addEventListener = function (el, type, callback) {
if (typeof el === 'string') {
el = document.querySelector(el);
}
pskl.utils.Event.addEventListener(el, type, callback, this);
};

View File

@ -3,7 +3,10 @@
ns.CurrentColorsService = function (piskelController) {
this.piskelController = piskelController;
// cache of current colors by history state
this.cache = {};
this.currentColors = [];
this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor();
this.cachedFrameProcessor.setFrameProcessor(this.getFrameColors_.bind(this));
@ -12,9 +15,8 @@
};
ns.CurrentColorsService.prototype.init = function () {
$.subscribe(Events.PISKEL_RESET, this.onPiskelUpdated_.bind(this));
$.subscribe(Events.TOOL_RELEASED, this.onPiskelUpdated_.bind(this));
$.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this));
$.subscribe(Events.HISTORY_STATE_SAVED, this.updateCurrentColors_.bind(this));
$.subscribe(Events.HISTORY_STATE_LOADED, this.loadColorsFromCache_.bind(this));
};
ns.CurrentColorsService.prototype.getCurrentColors = function () {
@ -22,26 +24,14 @@
};
ns.CurrentColorsService.prototype.setCurrentColors = function (colors) {
var historyIndex = pskl.app.historyService.currentIndex;
this.cache[historyIndex] = colors;
if (colors.join('') !== this.currentColors.join('')) {
this.currentColors = colors;
$.publish(Events.CURRENT_COLORS_UPDATED);
}
};
ns.CurrentColorsService.prototype.onUserSettingsChange_ = function (evt, name, value) {
if (name == pskl.UserSettings.SELECTED_PALETTE) {
if (this.isCurrentColorsPaletteSelected_()) {
this.updateCurrentColors_();
}
}
};
ns.CurrentColorsService.prototype.onPiskelUpdated_ = function (evt) {
if (this.isCurrentColorsPaletteSelected_()) {
this.updateCurrentColors_();
}
};
ns.CurrentColorsService.prototype.isCurrentColorsPaletteSelected_ = function () {
var paletteId = pskl.UserSettings.get(pskl.UserSettings.SELECTED_PALETTE);
var palette = this.paletteService.getPaletteById(paletteId);
@ -49,6 +39,14 @@
return palette.id === Constants.CURRENT_COLORS_PALETTE_ID;
};
ns.CurrentColorsService.prototype.loadColorsFromCache_ = function () {
var historyIndex = pskl.app.historyService.currentIndex;
var colors = this.cache[historyIndex];
if (colors) {
this.setCurrentColors(colors);
}
};
ns.CurrentColorsService.prototype.updateCurrentColors_ = function () {
var layers = this.piskelController.getLayers();
var frames = layers.map(function (l) {return l.getFrames();}).reduce(function (p, n) {return p.concat(n);});

View File

@ -10,19 +10,19 @@
this.currentIndex = -1;
this.lastLoadState = -1;
this.saveNextAsSnapshot = false;
};
// Force to save a state as a SNAPSHOT
ns.HistoryService.SNAPSHOT = 'SNAPSHOT';
// Default save state
ns.HistoryService.REPLAY = 'REPLAY';
// Period (in number of state saved) between two snapshots
ns.HistoryService.SNAPSHOT_PERIOD = 50;
// Interval/buffer (in milliseconds) between two state load (ctrl+z/y spamming)
ns.HistoryService.LOAD_STATE_INTERVAL = 50;
/**
* This event alters the state (frames, layers) of the piskel. The event is triggered before the execution of associated command.
* Don't store snapshots for such events.
*/
ns.HistoryService.REPLAY_NO_SNAPSHOT = 'REPLAY_NO_SNAPSHOT';
ns.HistoryService.prototype.init = function () {
$.subscribe(Events.PISKEL_SAVE_STATE, this.onSaveStateEvent.bind(this));
@ -35,31 +35,28 @@
});
};
ns.HistoryService.prototype.onSaveStateEvent = function (evt, stateInfo) {
this.saveState(stateInfo);
ns.HistoryService.prototype.onSaveStateEvent = function (evt, action) {
this.saveState(action);
};
ns.HistoryService.prototype.saveState = function (stateInfo) {
ns.HistoryService.prototype.saveState = function (action) {
this.stateQueue = this.stateQueue.slice(0, this.currentIndex + 1);
this.currentIndex = this.currentIndex + 1;
var state = {
action : stateInfo,
frameIndex : this.piskelController.currentFrameIndex,
layerIndex : this.piskelController.currentLayerIndex
action : action,
frameIndex : action.state ? action.state.frameIndex : this.piskelController.currentFrameIndex,
layerIndex : action.state ? action.state.layerIndex : this.piskelController.currentLayerIndex
};
var isSnapshot = stateInfo.type === ns.HistoryService.SNAPSHOT;
var isNoSnapshot = stateInfo.type === ns.HistoryService.REPLAY_NO_SNAPSHOT;
var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0 || this.saveNextAsSnapshot;
if (isNoSnapshot && isAtAutoSnapshotInterval) {
this.saveNextAsSnapshot = true;
} else if (isSnapshot || isAtAutoSnapshotInterval) {
var isSnapshot = action.type === ns.HistoryService.SNAPSHOT;
var isAtAutoSnapshotInterval = this.currentIndex % ns.HistoryService.SNAPSHOT_PERIOD === 0;
if (isSnapshot || isAtAutoSnapshotInterval) {
state.piskel = this.piskelController.serialize(true);
this.saveNextAsSnapshot = false;
}
this.stateQueue.push(state);
$.publish(Events.HISTORY_STATE_SAVED);
};
ns.HistoryService.prototype.undo = function () {
@ -143,6 +140,7 @@
this.currentIndex = index;
$.publish(Events.PISKEL_RESET);
$.publish(Events.HISTORY_STATE_LOADED);
if (originalSize !== this.getPiskelSize_()) {
$.publish(Events.FRAME_SIZE_CHANGED);
}

View File

@ -4,6 +4,10 @@
ns.Event = {};
ns.Event.addEventListener = function (el, type, callback, scope, args) {
if (typeof el === 'string') {
el = document.querySelector(el);
}
var listener = {
el : el,
type : type,

View File

@ -85,6 +85,7 @@
"js/controller/drawing/DragHandler.js",
"js/controller/PreviewFilmController.js",
"js/controller/LayersListController.js",
"js/controller/PopupPreviewController.js",
"js/controller/AnimatedPreviewController.js",
"js/controller/MinimapController.js",
"js/controller/ToolController.js",

View File

@ -6,4 +6,28 @@
<div class="progress-bar-item progress-bar-status">{{status}}%</div>
</div>
</script>
<script type="text/template" id="popup-preview-partial">
<style>
body {
margin: 0;
}
.preview-container {
width : 100%;
height : 100%;
}
.tiled-frame-container {
height: 100%;
width: 100%;
position: relative;
background-repeat : repeat;
}
</style>
<div class="popup-container">
<div class="preview-container"></div>
</div>
</script>
</div>

View File

@ -12,4 +12,7 @@
<span id="display-fps" class="display-fps"></span>
<input id="preview-fps" class="range-fps" type="range" min="0" max="24"/>
</div>
<div>
<button class="open-popup-preview-button">Open in popup</button>
</div>
</div>

View File

@ -69,11 +69,6 @@ describe("History Service suite", function() {
expect(getLastState().piskel).toBe(SERIALIZED_PISKEL);
sendSaveEvents(pskl.service.HistoryService.REPLAY).times(4);
sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once();
expect(getLastState().piskel).toBeUndefined();
sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once();
expect(getLastState().piskel).toBeUndefined();
sendSaveEvents(pskl.service.HistoryService.REPLAY).once();
@ -82,5 +77,5 @@ describe("History Service suite", function() {
// AFTER
pskl.service.HistoryService.SNAPSHOT_PERIOD = SNAPSHOT_PERIOD_BACKUP;
})
});
});