18 Commits

Author SHA1 Message Date
2f2b4cd9ba release: bump to version 0.13.0 2017-10-22 16:40:09 +02:00
dfb049bbf0 release: bump version to 0.13.0-RC2 2017-10-22 16:40:09 +02:00
8c54108a9b Remove html autocomplete fromt size input fields 2017-10-22 16:40:09 +02:00
3dd72f9781 release: fix minor ui issues for checkbox containers 2017-10-22 16:40:09 +02:00
80001eab0e release: bump version to 0.13.0-RC1 2017-10-22 16:40:09 +02:00
5ecf351e0f Return promise results from PiskelDB and IndexedDBStorageService 2017-10-21 23:48:51 +02:00
407b432227 Show error message if BackupDatabase promise rejected 2017-10-21 23:48:51 +02:00
69cc27557e Add templates for backup database errors 2017-10-21 23:48:51 +02:00
cfd3773a2b Issue #751 - add repeat checkbox to GIF export panel 2017-10-08 19:46:43 +02:00
0eface45f1 Issue #750 - drawing tests: always initialize penSize before starting test 2017-10-08 19:12:04 +02:00
87893bb4ac Issue #750 - Fix mirror pen with even pensizes 2017-10-08 19:12:04 +02:00
77d26bffa9 Issue #727 - add integration test for simple import flow 2017-10-08 18:19:52 +02:00
652027bd3f Issue #727 - update integration tests to wait for color service update 2017-10-08 18:19:52 +02:00
bf4cc3302a Issue #727 - skip import steps if current piskel is empty 2017-10-08 18:19:52 +02:00
95c8df1224 Issue #727 - simplify import: resize and insertion steps 2017-10-08 18:19:52 +02:00
7445357368 Issue #727 - simplify import mode text 2017-10-08 18:19:52 +02:00
a2369cac0c Issue #727 - remove border around meta info in import wizard 2017-10-08 18:19:52 +02:00
51538dff48 Make piskel performance warning less scary 2017-09-24 18:06:37 +02:00
31 changed files with 433 additions and 127 deletions

View File

@ -1,6 +1,6 @@
{
"name": "piskel",
"version": "0.12.1",
"version": "0.13.0",
"description": "Pixel art editor",
"author": "Julian Descottes <julian.descottes@gmail.com>",
"contributors": [

View File

@ -56,8 +56,7 @@
height: 90px;
}
.browse-backups .session-list-empty,
.browse-backups .snapshot-list-empty {
.browse-backups .centered-message {
position: absolute;
left: 50%;
width: 200px;
@ -68,9 +67,18 @@
font-size: 16px;
text-align: center;
border: 1px solid;
}
.browse-backups .session-list-empty,
.browse-backups .snapshot-list-empty {
color: #bbb;
}
.browse-backups .session-list-error,
.browse-backups .snapshot-list-error {
color: white;
}
.browse-backups .session-item {
/* Transition duration should be kept in sync with SelectSession.DELETE_TRANSITION_DURATION */
transition: all 500ms;

View File

@ -183,22 +183,14 @@
.import-meta-value,
.import-meta-label {
padding: 2px 4px;
border: 1px solid gold;
}
.import-meta-label {
border-radius: 2px 0 0 2px;
color: var(--highlight-color);
border-right-width: 0;
}
.import-meta-title .import-meta-label {
border-right-width: 1px;
border-radius: 2px;
}
.import-meta-value {
border-radius: 0 2px 2px 0;
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
@ -242,7 +234,7 @@
.insert-mode-option {
display: flex;
align-items: center;
margin-bottom: 5px;
margin: 5px 0;
}
.import-resize-option :checked + span,
@ -250,11 +242,15 @@
color: var(--highlight-color);
}
.import-resize-option input,
.insert-mode-option input {
margin: 5px;
}
/**
* ADJUST SIZE
*/
.import-resize-anchor-info,
.import-resize-option-label {
.import-resize-anchor-info {
margin-bottom: 10px;
}

View File

@ -52,7 +52,12 @@ body {
}
.checkbox-fix {
margin-left: 0;
margin: 3px 3px 3px 0;
}
.checkbox-container {
display: flex;
align-items: center;
}
.hidden {

View File

@ -39,31 +39,36 @@
ns.SelectSession.prototype.update = function () {
pskl.app.backupService.list().then(function (sessions) {
var html = '';
if (sessions.length === 0) {
html = pskl.utils.Template.get('session-list-empty');
} else {
var sessionItemTemplate = pskl.utils.Template.get('session-list-item');
var html = '';
sessions.forEach(function (session) {
if (session.id === pskl.app.sessionId) {
// Do not show backups for the current session.
return;
}
var view = {
id: session.id,
name: session.name,
description: session.description ? '- ' + session.description : '',
date: pskl.utils.DateUtils.format(session.endDate, 'the {{Y}}/{{M}}/{{D}} at {{H}}:{{m}}'),
count: session.count === 1 ? '1 snapshot' : session.count + ' snapshots'
};
html += pskl.utils.Template.replace(sessionItemTemplate, view);
});
}
var html = this.getMarkupForSessions_(sessions);
this.container.querySelector('.session-list').innerHTML = html;
}.bind(this)).catch(function () {
var html = pskl.utils.Template.get('session-list-error');
this.container.querySelector('.session-list').innerHTML = html;
}.bind(this));
};
ns.SelectSession.prototype.getMarkupForSessions_ = function (sessions) {
if (sessions.length === 0) {
return pskl.utils.Template.get('session-list-empty');
}
var sessionItemTemplate = pskl.utils.Template.get('session-list-item');
return sessions.reduce(function (previous, session) {
if (session.id === pskl.app.sessionId) {
// Do not show backups for the current session.
return previous;
}
var view = {
id: session.id,
name: session.name,
description: session.description ? '- ' + session.description : '',
date: pskl.utils.DateUtils.format(session.endDate, 'the {{Y}}/{{M}}/{{D}} at {{H}}:{{m}}'),
count: session.count === 1 ? '1 snapshot' : session.count + ' snapshots'
};
return previous + pskl.utils.Template.replace(sessionItemTemplate, view);
}, '');
};
ns.SelectSession.prototype.destroy = function () {
pskl.utils.Event.removeAllEventListeners(this);
};

View File

@ -27,33 +27,42 @@
ns.SessionDetails.prototype.onShow = function () {
var sessionId = this.backupsController.backupsData.selectedSession;
pskl.app.backupService.getSnapshotsBySessionId(sessionId).then(function (snapshots) {
var html = '';
if (snapshots.length === 0) {
// This should normally never happen, all sessions have at least one snapshot and snapshots
// can not be individually deleted.
console.warn('Could not retrieve snapshots for a session');
html = pskl.utils.Template.get('snapshot-list-empty');
} else {
var sessionItemTemplate = pskl.utils.Template.get('snapshot-list-item');
var html = '';
snapshots.forEach(function (snapshot) {
var view = {
id: snapshot.id,
name: snapshot.name,
description: snapshot.description ? '- ' + snapshot.description : '',
date: pskl.utils.DateUtils.format(snapshot.date, 'the {{Y}}/{{M}}/{{D}} at {{H}}:{{m}}'),
frames: snapshot.frames === 1 ? '1 frame' : snapshot.frames + ' frames',
resolution: pskl.utils.StringUtils.formatSize(snapshot.width, snapshot.height),
fps: snapshot.fps
};
html += pskl.utils.Template.replace(sessionItemTemplate, view);
this.updateSnapshotPreview_(snapshot);
}.bind(this));
}
var html = this.getMarkupForSnapshots_(snapshots);
this.container.querySelector('.snapshot-list').innerHTML = html;
// Load the image of the first frame for each sprite and update the list.
snapshots.forEach(function (snapshot) {
this.updateSnapshotPreview_(snapshot);
}.bind(this));
}.bind(this)).catch(function () {
var html = pskl.utils.Template.get('snapshot-list-error');
this.container.querySelector('.snapshot-list').innerHTML = html;
}.bind(this));
};
ns.SessionDetails.prototype.getMarkupForSnapshots_ = function (snapshots) {
if (snapshots.length === 0) {
// This should normally never happen, all sessions have at least one snapshot and snapshots
// can not be individually deleted.
console.warn('Could not retrieve snapshots for a session');
return pskl.utils.Template.get('snapshot-list-empty');
}
var sessionItemTemplate = pskl.utils.Template.get('snapshot-list-item');
return snapshots.reduce(function (previous, snapshot) {
var view = {
id: snapshot.id,
name: snapshot.name,
description: snapshot.description ? '- ' + snapshot.description : '',
date: pskl.utils.DateUtils.format(snapshot.date, 'the {{Y}}/{{M}}/{{D}} at {{H}}:{{m}}'),
frames: snapshot.frames === 1 ? '1 frame' : snapshot.frames + ' frames',
resolution: pskl.utils.StringUtils.formatSize(snapshot.width, snapshot.height),
fps: snapshot.fps
};
return previous + pskl.utils.Template.replace(sessionItemTemplate, view);
}, '');
};
ns.SessionDetails.prototype.updateSnapshotPreview_ = function (snapshot) {
pskl.utils.serialization.Deserializer.deserialize(
JSON.parse(snapshot.serialized),

View File

@ -80,7 +80,13 @@
var step = this.wizard.getCurrentStep();
if (step.name === 'IMAGE_IMPORT') {
this.wizard.goTo('SELECT_MODE');
if (this.piskelController.isEmpty()) {
// If the current sprite is empty finalize immediately and replace the current sprite.
this.mergeData.importMode = ns.steps.SelectMode.MODES.REPLACE;
this.finalizeImport_();
} else {
this.wizard.goTo('SELECT_MODE');
}
} else if (step.name === 'SELECT_MODE') {
if (this.mergeData.importMode === ns.steps.SelectMode.MODES.REPLACE) {
this.finalizeImport_();

View File

@ -69,16 +69,15 @@
var anchorInfo = this.container.querySelector('.import-resize-anchor-info');
if (isBigger && keep) {
anchorInfo.innerHTML = [
'<span class="import-resize-warning">',
'<div class="import-resize-warning">',
' Imported content will be cropped!',
'</span>',
' ',
'Select crop origin'
'</div>',
'Select crop anchor:'
].join('');
} else if (isBigger) {
anchorInfo.innerHTML = 'Select the anchor for resizing the canvas';
anchorInfo.innerHTML = 'Select resize anchor:';
} else {
anchorInfo.innerHTML = 'Select where the import should be positioned';
anchorInfo.innerHTML = 'Select position anchor:';
}
};

View File

@ -42,12 +42,17 @@
this.addEventListener(this.frameOffsetY, 'keyup', this.onFrameInputKeyUp_);
pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this));
if (this.piskelController.isEmpty()) {
this.nextButton.textContent = 'import';
}
};
ns.ImageImport.prototype.onNextClick = function () {
this.container.classList.add('import-image-loading');
this.createPiskelFromImage().then(function (piskel) {
this.mergeData.mergePiskel = piskel;
this.container.classList.remove('import-image-loading');
this.superclass.onNextClick.call(this);
}.bind(this)).catch(function (e) {
console.error(e);
@ -257,9 +262,7 @@
context.lineTo(maxWidth * scaleX, y * scaleY);
}
// Set the line style to dashed
context.lineWidth = 1;
// context.setLineDash([2, 1]);
context.strokeStyle = 'gold';
context.stroke();

View File

@ -297,4 +297,12 @@
ns.PiskelController.prototype.serialize = function () {
return pskl.utils.serialization.Serializer.serialize(this.piskel);
};
/**
* Check if the current sprite is empty. Emptiness here means no pixel has been filled
* on any layer or frame for the current sprite.
*/
ns.PiskelController.prototype.isEmpty = function () {
return pskl.app.currentColorsService.getCurrentColors().length === 0;
};
})();

View File

@ -18,9 +18,14 @@
this.previewContainerEl = document.querySelector('.gif-export-preview');
this.uploadButton = document.querySelector('.gif-upload-button');
this.downloadButton = document.querySelector('.gif-download-button');
this.repeatCheckbox = document.querySelector('.gif-repeat-checkbox');
// Initialize repeatCheckbox state
this.repeatCheckbox.checked = this.getRepeatSetting_();
this.addEventListener(this.uploadButton, 'click', this.onUploadButtonClick_);
this.addEventListener(this.downloadButton, 'click', this.onDownloadButtonClick_);
this.addEventListener(this.repeatCheckbox, 'change', this.onRepeatCheckboxChange_);
var currentColors = pskl.app.currentColorsService.getCurrentColors();
var tooManyColors = currentColors.length >= MAX_GIF_COLORS;
@ -108,6 +113,7 @@
width: width * zoom,
height: height * zoom,
preserveColors : preserveColors,
repeat: this.getRepeatSetting_() ? 0 : 1,
transparent : transparent
});
@ -152,6 +158,15 @@
return transparentColor;
};
ns.GifExportController.prototype.onRepeatCheckboxChange_ = function () {
var checked = this.repeatCheckbox.checked;
pskl.UserSettings.set(pskl.UserSettings.EXPORT_GIF_REPEAT, checked);
};
ns.GifExportController.prototype.getRepeatSetting_ = function () {
return pskl.UserSettings.get(pskl.UserSettings.EXPORT_GIF_REPEAT);
};
ns.GifExportController.prototype.updateStatus_ = function (imageUrl, error) {
if (imageUrl) {
var linkTpl = '<a class="highlight" href="{{link}}" target="_blank">{{shortLink}}</a>';

View File

@ -29,9 +29,7 @@
return _requestPromise(request).then(function (event) {
this.db = event.target.result;
return this.db;
}.bind(this)).catch(function (e) {
console.log('Failed to initialize IndexedDB, local browser saves will be unavailable.');
});
}.bind(this));
};
ns.PiskelDatabase.prototype.onUpgradeNeeded_ = function (event) {

View File

@ -32,6 +32,7 @@
};
ns.DrawingTestPlayer.prototype.setupInitialState_ = function () {
var size = this.initialState.size;
var piskel = this.createPiskel_(size.width, size.height);
pskl.app.piskelController.setPiskel(piskel);
@ -39,9 +40,10 @@
$.publish(Events.SELECT_PRIMARY_COLOR, [this.initialState.primaryColor]);
$.publish(Events.SELECT_SECONDARY_COLOR, [this.initialState.secondaryColor]);
$.publish(Events.SELECT_TOOL, [this.initialState.selectedTool]);
if (this.initialState.penSize) {
pskl.app.penSizeService.setPenSize(this.initialState.penSize);
}
// Old tests do not have penSize stored in initialState, fallback to 1.
var penSize = this.initialState.penSize || 1;
pskl.app.penSizeService.setPenSize(this.initialState.penSize);
};
ns.DrawingTestPlayer.prototype.createPiskel_ = function (width, height) {

View File

@ -16,7 +16,7 @@
*/
ns.PerformanceReport = function (piskel, colorsCount) {
var pixels = piskel.getWidth() * piskel.getHeight();
this.resolution = pixels > (500 * 500);
this.resolution = pixels > (512 * 512);
var layersCount = piskel.getLayers().length;
this.layers = layersCount > 25;
@ -24,10 +24,10 @@
var framesCount = piskel.getLayerAt(0).size();
this.frames = framesCount > 100;
this.colors = colorsCount > 100;
this.colors = colorsCount >= 256;
var overallScore = (pixels / 2500) + (layersCount * 4) + framesCount + colorsCount;
this.overall = overallScore > 100;
var overallScore = (pixels / 2620) + (layersCount * 4) + framesCount + (colorsCount * 100 / 256);
this.overall = overallScore > 200;
};
ns.PerformanceReport.prototype.equals = function (report) {

View File

@ -7,7 +7,9 @@
};
ns.IndexedDbStorageService.prototype.init = function () {
this.piskelDatabase.init();
this.piskelDatabase.init().catch(function (e) {
console.log('Failed to initialize PiskelDatabase, local browser saves will be unavailable.');
});
};
ns.IndexedDbStorageService.prototype.save = function (piskel) {
@ -30,7 +32,7 @@
};
ns.IndexedDbStorageService.prototype.load = function (name) {
this.piskelDatabase.get(name).then(function (piskelData) {
return this.piskelDatabase.get(name).then(function (piskelData) {
if (typeof piskelData !== 'undefined') {
var serialized = piskelData.serialized;
pskl.utils.serialization.Deserializer.deserialize(
@ -46,7 +48,7 @@
};
ns.IndexedDbStorageService.prototype.remove = function (name) {
this.piskelDatabase.delete(name);
return this.piskelDatabase.delete(name);
};
ns.IndexedDbStorageService.prototype.getKeys = function () {

View File

@ -44,10 +44,17 @@
};
ns.VerticalMirrorPen.prototype.getSymmetricCol_ = function(col, frame) {
return frame.getWidth() - col - 1;
return frame.getWidth() - col - this.getPenSizeOffset_();
};
ns.VerticalMirrorPen.prototype.getSymmetricRow_ = function(row, frame) {
return frame.getHeight() - row - 1;
return frame.getHeight() - row - this.getPenSizeOffset_();
};
/**
* Depending on the pen size, the mirrored index need to have an offset of 1 pixel.
*/
ns.VerticalMirrorPen.prototype.getPenSizeOffset_ = function(row, frame) {
return pskl.app.penSizeService.getPenSize() % 2;
};
})();

View File

@ -17,6 +17,7 @@
LAYER_OPACITY : 'LAYER_OPACITY',
EXPORT_SCALE: 'EXPORT_SCALE',
EXPORT_TAB: 'EXPORT_TAB',
EXPORT_GIF_REPEAT: 'EXPORT_GIF_REPEAT',
PEN_SIZE : 'PEN_SIZE',
RESIZE_SETTINGS: 'RESIZE_SETTINGS',
COLOR_FORMAT: 'COLOR_FORMAT',
@ -41,6 +42,7 @@
'LAYER_PREVIEW' : true,
'EXPORT_SCALE' : 1,
'EXPORT_TAB' : 'gif',
'EXPORT_GIF_REPEAT' : true,
'PEN_SIZE' : 1,
'RESIZE_SETTINGS': {
maintainRatio : true,

View File

@ -28,7 +28,11 @@
</script>
<script type="text/template" id="session-list-empty">
<div class="session-list-empty">No session found ...</div>
<div class="centered-message session-list-empty">No session found ...</div>
</script>
<script type="text/template" id="session-list-error">
<div class="centered-message session-list-error">Could not load backup sessions, something went wrong.</div>
</script>
<script type="text/template" id="session-list-item">
@ -57,7 +61,11 @@
</script>
<script type="text/template" id="snapshot-list-empty">
<div class="snapshot-list-empty">No snapshot found ...</div>
<div class="centered-message snapshot-list-empty">No snapshot found ...</div>
</script>
<script type="text/template" id="snapshot-list-error">
<div class="centered-message snapshot-list-error">Could not load snapshots, something went wrong.</div>
</script>
<script type="text/template" id="snapshot-list-item">

View File

@ -25,8 +25,8 @@
</div>
<div class="import-section import-subsection">
<span class="dialog-section-title">Resize to</span>
<input type="text" class="textfield import-size-field" name="resize-width"/>x
<input type="text" class="textfield import-size-field" name="resize-height"/>
<input type="text" class="textfield import-size-field" autocomplete="off" name="resize-width"/>x
<input type="text" class="textfield import-size-field" autocomplete="off" name="resize-height"/>
</div>
<div class="import-section import-subsection">
<span class="import-section-title">Smooth resize</span>
@ -40,13 +40,13 @@
</div>
<div class="import-section import-subsection">
<span class="dialog-section-title">Frame size</span>
<input type="text" class="textfield import-size-field" name="frame-size-x"/>x
<input type="text" class="textfield import-size-field" name="frame-size-y"/>
<input type="text" class="textfield import-size-field" autocomplete="off" name="frame-size-x"/>x
<input type="text" class="textfield import-size-field" autocomplete="off" name="frame-size-y"/>
</div>
<div class="import-section import-subsection">
<span class="dialog-section-title">Offset</span>
<input type="text" class="textfield import-size-field" name="frame-offset-x"/>x
<input type="text" class="textfield import-size-field" name="frame-offset-y"/>
<input type="text" class="textfield import-size-field" autocomplete="off" name="frame-offset-x"/>x
<input type="text" class="textfield import-size-field" autocomplete="off" name="frame-offset-y"/>
</div>
</form>
<div class="import-step-buttons">
@ -67,11 +67,11 @@
<div class="import-mode">
<div class="import-mode-title">How do you want to import the new content?</div>
<div class="import-mode-section">
<span class="import-mode-section-description">Combine the imported content and your sprite.</span>
<button class="import-mode-merge-button button-primary button">Merge</button>
<span class="import-mode-section-description">Combine with your sprite</span>
<button class="import-mode-merge-button button-primary button">Combine</button>
</div>
<div class="import-mode-section">
<span class="import-mode-section-description">Replace your current sprite by the imported content.</span>
<span class="import-mode-section-description">Replace your sprite</span>
<button class="import-mode-replace-button button-primary button">Replace</button>
</div>
</div>
@ -131,9 +131,6 @@
The imported image is bigger than the current sprite.
</div>
<div class="import-resize-section">
<div class="import-resize-option-label">
How do you want to proceed?
</div>
<label class="import-resize-option">
<input type="radio" name="resize-mode" id="resize-option-expand" value="expand" {{expandChecked}}/>
<span>Expand canvas to {{newSize}}</span>
@ -162,19 +159,19 @@
</div>
<div class="import-step-content">
<div>Select a frame in your current sprite:</div>
<div>Select the insertion frame:</div>
<div class="insert-frame-preview"></div>
<div class="insert-mode-container">
<div class="insert-mode-option-label">
How should the imported frames be inserted:
Insert imported frames:
</div>
<label class="insert-mode-option">
<input type="radio" name="insert-mode" id="insert-mode-add" value="add" checked="checked"/>
<span>Add new frames</span>
<span>as new frames</span>
</label>
<label class="insert-mode-option">
<input type="radio" name="insert-mode" id="insert-mode-insert" value="insert"/>
<span>Insert in existing frames</span>
<span>in existing frames</span>
</label>
</div>
<div class="import-step-buttons">
@ -184,13 +181,3 @@
</div>
</div>
</script>
<script type="text/template" id="import-invalid-file">
<div class="import-step-container">
<div>THIS IS AN INVALID FILEZ</div>
<div class="import-step-buttons">
<button class="import-back-button button">back</button>
<button class="import-next-button button button-primary">next</button>
</div>
</div>
</script>

View File

@ -15,10 +15,10 @@
<p>If you ignore this warning, please save often!</p>
<p>To fix the issue, try adjusting your sprite settings:</p>
<ul>
<li>sprite resolution <sup title="recommended: lower than 256x256, max: 512x512" rel="tooltip" data-placement="top">?</sup></li>
<li>number of layers <sup title="recommended: lower than 5, max: 20" rel="tooltip" data-placement="top">?</sup></li>
<li>number of frames <sup title="recommended: lower than 25, max: 100" rel="tooltip" data-placement="top">?</sup></li>
<li>number of colors <sup title="max: 100" rel="tooltip" data-placement="top">?</sup></li>
<li>sprite resolution <sup title="recommended: lower than 512x512" rel="tooltip" data-placement="top">?</sup></li>
<li>number of layers <sup title="recommended: less than 10" rel="tooltip" data-placement="top">?</sup></li>
<li>number of frames <sup title="recommended: less than 50" rel="tooltip" data-placement="top">?</sup></li>
<li>number of colors <sup title="recommended: less than 256" rel="tooltip" data-placement="top">?</sup></li>
</ul>
<p>We strive to improve Piskel, its performance and stability, but this is a personal project with limited time and resources.
We prefer to warn you early rather than having you lose your work.</p>

View File

@ -9,6 +9,13 @@
Too many colors: can not preserve original colors or transparency.
</div>
</div>
<div class="export-panel-section export-panel-row">
<input id="gif-repeat-checkbox" class="gif-repeat-checkbox checkbox-fix" type="checkbox" />
<label for="gif-repeat-checkbox"
title="Uncheck to play the animation only one time."
rel="tooltip"
data-placement="top">Loop repeatedly</label>
</div>
<div class="export-panel-section export-panel-row">
<button type="button" class="button button-primary gif-download-button">Download</button>
<div class="export-info">Download as an animated GIF.</div>

View File

@ -7,7 +7,7 @@
<input type="text" style="flex: 1;" class="zip-prefix-name textfield"
autocomplete="off" placeholder="PNG file prefix ...">
</div>
<div style="margin: 5px 0;">
<div class="checkbox-container" style="margin: 5px 0;">
<input id="zip-split-layers" class="zip-split-layers-checkbox checkbox-fix" type="checkbox" />
<label for="zip-split-layers">Split by layers</label>
</div>

View File

@ -17,13 +17,13 @@
<span>px</span>
</div>
<div class="resize-section">
<label>
<label class="checkbox-container">
<input type="checkbox" class="resize-ratio-checkbox checkbox-fix" value="true"/>
<span>Maintain aspect ratio</span>
</label>
</div>
<div class="resize-section">
<label>
<label class="checkbox-container">
<input type="checkbox" class="resize-content-checkbox checkbox-fix" value="true"/>
<span>Resize canvas content</span>
</label>

View File

@ -7,6 +7,7 @@
'settings/test-export-png.js',
'settings/test-export-png-scale.js',
'settings/test-import-image.js',
'settings/test-import-image-empty.js',
'settings/test-import-image-twice.js',
'settings/test-resize-complete.js',
'settings/test-resize-content-complete.js',

View File

@ -9,7 +9,7 @@ casper.test.begin('PNG export test', 13, function(test) {
test.assert(!isDrawerExpanded(), 'settings drawer is closed');
// Setup test Piskel
// Setup test Piskel
setPiskelFromGrid('['+
'[B, T],' +
'[T, B],' +

View File

@ -0,0 +1,105 @@
/* globals casper, setPiskelFromGrid, isDrawerExpanded, getValue, isChecked,
evalLine, waitForEvent, replaceFunction, setPiskelFromImageSrc */
casper.test.begin('Image import test with an empty current sprite', 16, function(test) {
test.timeout = test.fail.bind(test, ['Test timed out']);
// Helper to retrieve the text content of the provided selector
// in the current wizard step.
var getTextContent = function (selector) {
return evalLine('document.querySelector(".current-step ' + selector +'").textContent');
};
function onTestStart() {
test.assertExists('#drawing-canvas-container canvas', 'Piskel ready, test starting');
test.assert(!isDrawerExpanded(), 'settings drawer is closed');
waitForEvent('PISKEL_RESET', onPiskelReset, test.timeout);
// 1x1 transparent pixel
setPiskelFromGrid('['+
'[T]' +
']');
}
function onPiskelReset() {
// Check the expected piskel was correctly loaded.
test.assertEquals(evalLine('pskl.app.currentColorsService.getCurrentColors().length'), 0, 'Has no color');
test.assertEquals(evalLine('pskl.app.piskelController.isEmpty()'), true, 'Current piskel is considered as empty');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getWidth()'), 1, 'Piskel width is 1 pixel');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getHeight()'), 1, 'Piskel height is 1 pixel');
// Open export panel.
test.assertDoesntExist('.settings-section-import', 'Check if import panel is closed');
casper.click('[data-setting="import"]');
casper.waitForSelector('.settings-section-import', onImportPanelReady, test.timeout, 10000);
}
function onImportPanelReady() {
test.assert(isDrawerExpanded(), 'settings drawer is expanded');
test.assertExists('.settings-section-import', 'Check if import panel is opened');
replaceFunction(test,
'pskl.utils.FileUtils.readImageFile',
function (file, callback) {
var image = new Image();
image.onload = callback.bind(null, image);
// Source for a simple base64 encoded PNG, 2x2, with 2 different colors and 2 transparent pixels.
image.src = [
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAIAAAACCAYAAABytg0',
'kAAAAF0lEQVQYVwXBAQEAAACCIPw/uiAYi406Ig4EARK1RMAAAAAASUVORK5CYII='
].join('');
}
);
casper.echo('Clicking on Browse Images button');
test.assertExists('.file-input-button', 'The import image button is available');
// We can't really control the file picker from the test so we directly fire the event
casper.evaluate(
'function () {\
$.publish(Events.DIALOG_SHOW, {\
dialogId : "import",\
initArgs : {\
rawFiles: [{type: "image", name: "test-name.png"}]\
}\
});\
}'
);
casper.echo('Wait for .import-image-container');
casper.waitForSelector('.current-step.import-image-container', onImageImportReady, test.timeout, 10000);
}
function onImageImportReady() {
casper.echo('Found import-image-container');
// Click on export again to close the settings drawer.
test.assertEquals(getTextContent('.import-next-button'), 'import',
'Next button found, with text content \'import\'');
casper.click('.current-step .import-next-button');
// Since the current sprite is empty clicking on the button should directly finalize the import.
casper.waitForSelector('#dialog-container-wrapper:not(.show)', onPopupClosed, test.timeout, 10000);
}
function onPopupClosed() {
casper.echo('Import popup is closed, check the imported piskel content');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getWidth()'), 2, 'Piskel width is 2 pixels');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getHeight()'), 2, 'Piskel height is 2 pixels');
test.assertEquals(evalLine('pskl.app.piskelController.getLayers().length'), 1, 'Piskel has 1 layer');
test.assertEquals(evalLine('pskl.app.piskelController.getFrameCount()'), 1, 'Piskel has 1 frame');
}
casper
.start(casper.cli.get('baseUrl')+"/?debug&integration-test")
.then(function () {
casper.echo("URL loaded");
casper.waitForSelector('#drawing-canvas-container canvas', onTestStart, test.timeout, 20000);
})
.run(function () {
test.done();
});
});

View File

@ -1,7 +1,7 @@
/* globals casper, setPiskelFromGrid, isDrawerExpanded, getValue, isChecked,
evalLine, waitForEvent, replaceFunction, setPiskelFromImageSrc */
casper.test.begin('Double Image import test', 25, function(test) {
casper.test.begin('Double Image import test', 26, function(test) {
test.timeout = test.fail.bind(test, ['Test timed out']);
// Helper to retrieve the text content of the provided selector
@ -54,18 +54,21 @@ casper.test.begin('Double Image import test', 25, function(test) {
test.assert(!isDrawerExpanded(), 'settings drawer is closed');
waitForEvent('PISKEL_RESET', onPiskelReset, test.timeout);
// 1x1 black pixel
var src = [
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcS',
'JAAAADUlEQVQYV2NgYGD4DwABBAEAcCBlCwAAAABJRU5ErkJggg=='
].join('');
setPiskelFromImageSrc(src);
// For this test the most important is that the color service picked up the color from the sprite
// since it drives which flow will be used for the import.
casper.waitForSelector('.palettes-list-color:nth-child(1)', onPiskelPaletteUpdated, test.timeout, 10000);
}
function onPiskelReset() {
function onPiskelPaletteUpdated() {
// Check the expected piskel was correctly loaded.
test.assertEquals(evalLine('pskl.app.currentColorsService.getCurrentColors().length'), 1, 'Has 1 color');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getWidth()'), 1, 'Piskel width is 1 pixel');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getHeight()'), 1, 'Piskel height is 1 pixel');

View File

@ -1,7 +1,7 @@
/* globals casper, setPiskelFromGrid, isDrawerExpanded, getValue, isChecked,
evalLine, waitForEvent, replaceFunction, setPiskelFromImageSrc */
casper.test.begin('Simple Image import test', 26, function(test) {
casper.test.begin('Simple Image import test', 27, function(test) {
test.timeout = test.fail.bind(test, ['Test timed out']);
// Helper to retrieve the text content of the provided selector
@ -30,18 +30,21 @@ casper.test.begin('Simple Image import test', 26, function(test) {
test.assert(!isDrawerExpanded(), 'settings drawer is closed');
waitForEvent('PISKEL_RESET', onPiskelReset, test.timeout);
// 1x1 black pixel
var src = [
'data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAEAAAABCAYAAAAfFcS',
'JAAAADUlEQVQYV2NgYGD4DwABBAEAcCBlCwAAAABJRU5ErkJggg=='
].join('');
setPiskelFromImageSrc(src);
// For this test the most important is that the color service picked up the color from the sprite
// since it drives which flow will be used for the import.
casper.waitForSelector('.palettes-list-color:nth-child(1)', onPiskelPaletteUpdated, test.timeout, 10000);
}
function onPiskelReset() {
function onPiskelPaletteUpdated() {
// Check the expected piskel was correctly loaded.
test.assertEquals(evalLine('pskl.app.currentColorsService.getCurrentColors().length'), 1, 'Has 1 color');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getWidth()'), 1, 'Piskel width is 1 pixel');
test.assertEquals(evalLine('pskl.app.piskelController.getPiskel().getHeight()'), 1, 'Piskel height is 1 pixel');

View File

@ -12,6 +12,7 @@
"lighten.darken.json",
"move.json",
"move-alllayers-allframes.json",
"pen.mirror.pensize.json",
"pen.secondary.color.json",
"selection.rectangular.json",
"squares.circles.json",

View File

@ -10,6 +10,7 @@
"layers.top.bottom.json",
"move.json",
"move-alllayers-allframes.json",
"pen.mirror.pensize.json",
"pen.secondary.color.json",
"selection.rectangular.json",
"squares.circles.json",

View File

@ -0,0 +1,125 @@
{
"events": [
{
"type": "pensize-event",
"penSize": 2
},
{
"type": "tool-event",
"toolId": "tool-vertical-mirror-pen"
},
{
"event": {
"type": "mousedown",
"button": 0,
"shiftKey": false,
"altKey": false,
"ctrlKey": false
},
"coords": {
"x": 1,
"y": 1
},
"type": "mouse-event"
},
{
"event": {
"type": "mousemove",
"button": 0,
"shiftKey": false,
"altKey": false,
"ctrlKey": false
},
"coords": {
"x": 1,
"y": 1
},
"type": "mouse-event"
},
{
"event": {
"type": "mousemove",
"button": 0,
"shiftKey": false,
"altKey": false,
"ctrlKey": false
},
"coords": {
"x": 1,
"y": 2
},
"type": "mouse-event"
},
{
"event": {
"type": "mousemove",
"button": 0,
"shiftKey": false,
"altKey": false,
"ctrlKey": false
},
"coords": {
"x": 1,
"y": 3
},
"type": "mouse-event"
},
{
"event": {
"type": "mousemove",
"button": 0,
"shiftKey": false,
"altKey": false,
"ctrlKey": false
},
"coords": {
"x": 1,
"y": 4
},
"type": "mouse-event"
},
{
"event": {
"type": "mousemove",
"button": 0,
"shiftKey": false,
"altKey": false,
"ctrlKey": false
},
"coords": {
"x": 1,
"y": 5
},
"type": "mouse-event"
},
{
"event": {
"type": "mouseup",
"button": 0,
"shiftKey": false,
"altKey": false,
"ctrlKey": false
},
"coords": {
"x": 1,
"y": 5
},
"type": "mouse-event"
},
{
"type": "pensize-event",
"penSize": 1
}
],
"initialState": {
"size": {
"width": 6,
"height": 6
},
"primaryColor": "#000000",
"secondaryColor": "rgba(0, 0, 0, 0)",
"selectedTool": "tool-pen",
"penSize": 1
},
"png": "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAYAAAAGCAYAAADgzO9IAAAAGElEQVQYV2NkYGD4zwABjFAazAdxBkwCAIsLDAFt5z4tAAAAAElFTkSuQmCC"
}