Compare commits
456 Commits
Author | SHA1 | Date | |
---|---|---|---|
ef945ef8a6 | |||
c5c8184ae3 | |||
66452de1e5 | |||
fa62ae511e | |||
f106909150 | |||
b54efbde21 | |||
5ebf83badf | |||
3804afbeb5 | |||
0a64d62b84 | |||
af9095b934 | |||
65f4fd0f27 | |||
5e364e984c | |||
5a0b6b90e4 | |||
717e8dd52a | |||
bd0478fb35 | |||
2bbbfd1219 | |||
da4156912e | |||
99c060f4a7 | |||
52e49a1ed6 | |||
6acfa2256c | |||
89629d2939 | |||
e5d89104a1 | |||
6e84f0a2b5 | |||
ba0e86dc7e | |||
27497313ff | |||
8662ab65ad | |||
594d748146 | |||
379c61a11d | |||
230a38bf07 | |||
0e5d74e1d8 | |||
f462cd3b70 | |||
45d2245346 | |||
e5e85f67c2 | |||
4836251bd3 | |||
e3182504dd | |||
34a88b79a0 | |||
7b8978da7a | |||
1c3b359b5c | |||
5c4cbbbba1 | |||
b9cc2eb4f8 | |||
ac13cf13c1 | |||
32600f9e66 | |||
39eb0d3143 | |||
6e53bce2cf | |||
090acee11a | |||
a1bb5f3b97 | |||
f69e502639 | |||
027cd2e2a6 | |||
2726af2d81 | |||
22cec2e8c7 | |||
57ee8e4365 | |||
a9cdf98281 | |||
0a9e7dcffb | |||
fe3f6996f1 | |||
9d32a8c3aa | |||
64cd724139 | |||
dae08107e2 | |||
779761628e | |||
3e450c3d77 | |||
5c7070b01b | |||
7c215ebcbe | |||
bcee24609f | |||
f420c6f1fd | |||
76429dfd86 | |||
4ebf43fda4 | |||
2f2b4cd9ba | |||
dfb049bbf0 | |||
8c54108a9b | |||
3dd72f9781 | |||
80001eab0e | |||
5ecf351e0f | |||
407b432227 | |||
69cc27557e | |||
cfd3773a2b | |||
0eface45f1 | |||
87893bb4ac | |||
77d26bffa9 | |||
652027bd3f | |||
bf4cc3302a | |||
95c8df1224 | |||
7445357368 | |||
a2369cac0c | |||
51538dff48 | |||
da739e78da | |||
dd8217e21b | |||
d502d3416b | |||
d1156954ca | |||
dc5209628c | |||
8568663949 | |||
fd3d828067 | |||
e1797b2008 | |||
0a43f6bbec | |||
b9423bc831 | |||
5e6280301d | |||
5671eb4782 | |||
35788b54ba | |||
629ecf83b4 | |||
c037b07693 | |||
c31b7a351c | |||
7de03f1e73 | |||
eab21e0839 | |||
2b3bd02479 | |||
4e86fa1570 | |||
170a7e4731 | |||
6b7f04b63e | |||
da2e9f99e4 | |||
530a949e54 | |||
4377c9e601 | |||
e0bbb88d47 | |||
9ff2ecbb45 | |||
8beba2088b | |||
ee45cdcc45 | |||
30ea7fa079 | |||
e9b39a5c61 | |||
d0a32b18c5 | |||
372ad1f513 | |||
c6e106fe2d | |||
f9570ea3c5 | |||
f9cb631acb | |||
ed749a747f | |||
30ecd41452 | |||
af65344c23 | |||
183133496e | |||
8a2c0191f9 | |||
a096dcabfd | |||
96d326ef12 | |||
7c37372b13 | |||
b21ea30fa8 | |||
c2dbddcf9f | |||
09ce6ff88f | |||
2c4a8efb44 | |||
02a25d3f84 | |||
d159de2e65 | |||
726a8f74c1 | |||
89a65ab032 | |||
d8ec58b42c | |||
1168870ee0 | |||
d3a37c74e9 | |||
5d2ca7e70c | |||
2976fd09ea | |||
317fda83c3 | |||
94160d8fc4 | |||
b977a146e9 | |||
aea4e4d6a6 | |||
5456ea973a | |||
a299d9aed0 | |||
cc2fc48107 | |||
799c9fbf5a | |||
a9e22535d6 | |||
4b4cbe47c8 | |||
e7d07c5353 | |||
cf3383722a | |||
6566ca07a5 | |||
9fafa8b7a7 | |||
4a9f7cc74b | |||
319060beb6 | |||
729c9f4732 | |||
cd560012e1 | |||
e819503cc5 | |||
6512c3dcc0 | |||
3535dfb25e | |||
a69554f6c9 | |||
1040cb4d8c | |||
d18b85df16 | |||
76563bfc41 | |||
2ba95667b2 | |||
3949051ba7 | |||
df6780a3e7 | |||
b768a22b1c | |||
8f4f9d9b0a | |||
14e969a3bb | |||
0ef69bae58 | |||
b40c1c4744 | |||
261259b38f | |||
799bf76a86 | |||
42f329980c | |||
80a1edf027 | |||
92934502e8 | |||
4d07a4eb90 | |||
41ef0cd460 | |||
d77889d265 | |||
4f15b14b58 | |||
00d4a1614b | |||
a72b0c69e5 | |||
c6733cdad4 | |||
30274ad1f8 | |||
b7fe8c1a5e | |||
a68dccfce0 | |||
78bbc71e6c | |||
b5a8eb9f96 | |||
af3d0fa48b | |||
e6a65c0db4 | |||
f2b733c91e | |||
4506fdbdf2 | |||
5d6f354443 | |||
a6d3aff9f1 | |||
a707170fa2 | |||
8c815f320d | |||
f74b081fad | |||
b8fed60fa6 | |||
d841ad10f6 | |||
f6e16e7b4b | |||
6fb8a6859c | |||
866553b2ca | |||
5aad87471e | |||
942aacbb94 | |||
88da91bde3 | |||
ce94dbeeeb | |||
a8c85b8a29 | |||
89199f2d6a | |||
98768b2e5b | |||
62b1b8baf0 | |||
11a063de12 | |||
6f4413f353 | |||
974450837e | |||
c6c64af2fd | |||
c68b82339c | |||
099ff80155 | |||
f30e16386d | |||
08b97cb6f0 | |||
b6fa769ba1 | |||
47b09b10c5 | |||
f039a89572 | |||
e74329f04e | |||
8959b201e9 | |||
f5491dc557 | |||
9ce3d44cc6 | |||
8928f3e626 | |||
e04fde7084 | |||
a25648f8e2 | |||
1918227c81 | |||
8b1b21368c | |||
d781df3290 | |||
35bfcb5f00 | |||
cce4cde98b | |||
4706587abb | |||
c0182952c9 | |||
ba779a97a6 | |||
dc149f88d6 | |||
ac08ff8b82 | |||
9be332fad3 | |||
11db5ca45c | |||
37445202f3 | |||
f8b77403cd | |||
74d8aa8c9c | |||
acad4df49e | |||
af92ee6bd7 | |||
a740699775 | |||
6ce2c00acf | |||
93db679dd7 | |||
5bde3c471d | |||
94b1a1df4a | |||
8806c41892 | |||
8cad3bb607 | |||
552d4fa710 | |||
b11f7a430d | |||
a4952d0db2 | |||
42f4812b46 | |||
bf91c4ef62 | |||
03f37d46ac | |||
0abd779348 | |||
33259e5522 | |||
e8207aba57 | |||
b03b4a7c60 | |||
2f47bc433c | |||
9cd3fa03a0 | |||
d4b4192d45 | |||
d5199d38aa | |||
ab082b9f4a | |||
2ec6c4b848 | |||
2cdc999875 | |||
4c6d2c1e48 | |||
95256071e1 | |||
b86ec72a4e | |||
70085bc056 | |||
a328e4d20e | |||
569b508fd5 | |||
d30f6a05d1 | |||
76ae797a9e | |||
61c76f980a | |||
5bd113b38f | |||
aa5d4d4090 | |||
398d93557a | |||
0733a5a142 | |||
835cee37aa | |||
2dea7faea0 | |||
809737908c | |||
e43cee3c94 | |||
b869d63211 | |||
c0f7e7be52 | |||
98527c6ded | |||
9518d570e6 | |||
01b9898181 | |||
184b2e48aa | |||
e97a641e95 | |||
7eea5d672a | |||
537234b1d1 | |||
57936d90b1 | |||
ef8060c07d | |||
8551a8546a | |||
eb84e87a13 | |||
ca3b789747 | |||
22dd474799 | |||
16151e8e95 | |||
2f62be4927 | |||
fbaccb03f2 | |||
dd9b1e0189 | |||
dda566a218 | |||
2bcd354342 | |||
6cc41ee07b | |||
eca9191f29 | |||
83c7e950f0 | |||
32070efcc1 | |||
c743334a31 | |||
84419a1550 | |||
66c941dd25 | |||
dba62d2b0d | |||
156161f7c8 | |||
58bfe16b27 | |||
57b37971f6 | |||
8dab74ceea | |||
d0cca52f47 | |||
58cf9f8390 | |||
49109e51c9 | |||
27b26fe4f3 | |||
b21fc0490d | |||
25ede9ffff | |||
37d2861352 | |||
2fe0b842a5 | |||
dd7ab574b9 | |||
c2fdb65e37 | |||
aef88c8713 | |||
b3c13f1630 | |||
6b0eda2998 | |||
16cfffa898 | |||
732c3c2d76 | |||
21c7425cbc | |||
9ac9583455 | |||
9608995d9c | |||
5faa985dea | |||
5544f734cf | |||
9d0d38e081 | |||
ad5c8182e4 | |||
9dd403a54e | |||
f2424ed16e | |||
da0e8dec84 | |||
a5fc491e92 | |||
e53ee0604c | |||
e1671202af | |||
5e3bb9d79c | |||
c5c336e12c | |||
85b141df52 | |||
a65eeee2e0 | |||
39dba2b70f | |||
0cb4a7831b | |||
696d18748a | |||
e328b4c7b8 | |||
5996216ae7 | |||
8cb7a4aaf6 | |||
136506da40 | |||
d08c101b11 | |||
4b50dfdb5b | |||
e3b363d757 | |||
440c28d0fd | |||
a560872df7 | |||
aca6c28b4b | |||
4a01f5625c | |||
8f493a8147 | |||
73986c4e61 | |||
2a7957bce2 | |||
0586756b92 | |||
2b78456314 | |||
4b378d48a2 | |||
5faf4af7c9 | |||
d947fe1c05 | |||
85336f9b9a | |||
91f637d2fd | |||
eb69c91d43 | |||
7ae40d8794 | |||
5a39d6850e | |||
f342b72e1b | |||
1624792f61 | |||
dd58af30b9 | |||
4e515f4820 | |||
71ec809aea | |||
9538e03928 | |||
e647826095 | |||
5fe9081df1 | |||
d4f038f97b | |||
23a0768f8d | |||
4cc434edd6 | |||
26b3cf3a23 | |||
7e9c632efd | |||
6c50816830 | |||
38cbfe4fce | |||
d775609183 | |||
74f36daa7c | |||
ffca6aa44c | |||
6ea9c248d8 | |||
9c96c7eaf2 | |||
c97ce34e6e | |||
43f989919c | |||
0ec8036670 | |||
3a2d837f5a | |||
0f404d2b25 | |||
5577c3ab5a | |||
baf8049ea6 | |||
74b7f93ddb | |||
fb97533cc9 | |||
ebab5ecb3f | |||
37443ecdc2 | |||
91f0d98d63 | |||
fa716d7a6c | |||
ac3e43bf61 | |||
502eb1aac4 | |||
218c0b511b | |||
a3fd2f0d89 | |||
c522d48c8f | |||
c2b283be67 | |||
dbbd57ae28 | |||
fefc635e25 | |||
8910bf0dbd | |||
f607c65789 | |||
2962a838d3 | |||
7eab386122 | |||
0c0aa5f2c9 | |||
bb7d5c862f | |||
f0f79754f1 | |||
a097d0b897 | |||
a1ab693fb5 | |||
7707aca03e | |||
f829d589d5 | |||
712262b82a | |||
0bbb4ff2d5 | |||
6ee23e22df | |||
f5c98cf0b3 | |||
06abdca62e | |||
2ca97b48e7 | |||
132487704b | |||
f6be33d5bf | |||
8a031d771a | |||
3be2b3d3bc | |||
7b512f6412 | |||
b1058c452e | |||
7bc5d20b2e | |||
e9ef6eb5b3 | |||
a2d5e6ff04 | |||
4d12908363 | |||
682ef9cf91 | |||
cbacd68414 | |||
3b65b90de1 | |||
e7ed2f9b24 | |||
0238dffe71 | |||
52eaa8b170 | |||
53d728cf3a | |||
d01f4ef83e |
25
.codeclimate.yml
Normal file
@ -0,0 +1,25 @@
|
||||
engines:
|
||||
csslint:
|
||||
enabled: true
|
||||
duplication:
|
||||
enabled: true
|
||||
config:
|
||||
languages:
|
||||
- javascript
|
||||
eslint:
|
||||
enabled: true
|
||||
checks:
|
||||
wrap-iife:
|
||||
enabled: false
|
||||
fixme:
|
||||
enabled: true
|
||||
ratings:
|
||||
paths:
|
||||
- "**.css"
|
||||
- "**.js"
|
||||
exclude_paths:
|
||||
- .github/
|
||||
- bin/
|
||||
- misc/
|
||||
- src/js/lib/
|
||||
- test/
|
2
.eslintignore
Normal file
@ -0,0 +1,2 @@
|
||||
# Exclude libs.
|
||||
**/lib/**/*.js
|
19
.github/ISSUE_TEMPLATE
vendored
Normal file
@ -0,0 +1,19 @@
|
||||
Bug description
|
||||
|
||||
(this template is intended for bug reports, erase it when requesting features/enhancements)
|
||||
|
||||
### Steps to reproduce the bug
|
||||
1. go to piskelapp.com
|
||||
2. select a tool
|
||||
3. ...
|
||||
|
||||
### Environment details
|
||||
* operating system:
|
||||
* browser (or offline application version):
|
||||
|
||||
### Sprite details
|
||||
* number of frames:
|
||||
* sprite resolution:
|
||||
* session duration:
|
||||
|
||||
Feel free to include a screenshot of the bug, a .piskel file of the sprite or anything else that can help us investigate.
|
7
.gitignore
vendored
@ -1,4 +1,4 @@
|
||||
# mac artefacts
|
||||
# mac artifacts
|
||||
*.DS_Store
|
||||
|
||||
# nodejs local installs
|
||||
@ -15,10 +15,12 @@ cache
|
||||
# netbeans project folder
|
||||
nbproject
|
||||
|
||||
# vscode workspace folder
|
||||
.vscode
|
||||
|
||||
# git stackdumps
|
||||
*.stackdump
|
||||
|
||||
|
||||
# diffs
|
||||
diff.txt
|
||||
|
||||
@ -28,6 +30,7 @@ build/closure/closure_compiled_binary.js
|
||||
|
||||
# spriting artifacts
|
||||
src/img/icons.png
|
||||
src/img/icons@2x.png
|
||||
src/css/icons.css
|
||||
|
||||
# plato report directory
|
||||
|
75
.jscsrc
@ -1,75 +0,0 @@
|
||||
{
|
||||
"requireCurlyBraces": [
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"try",
|
||||
"catch"
|
||||
],
|
||||
"requireOperatorBeforeLineBreak": true,
|
||||
"requireCamelCaseOrUpperCaseIdentifiers": true,
|
||||
"maximumLineLength": {
|
||||
"value": 80,
|
||||
"allExcept": ["comments", "regex"]
|
||||
},
|
||||
"validateIndentation": 2,
|
||||
"validateQuoteMarks": "'",
|
||||
|
||||
"disallowMultipleLineStrings": true,
|
||||
"disallowMixedSpacesAndTabs": true,
|
||||
"disallowTrailingWhitespace": true,
|
||||
"disallowSpaceAfterPrefixUnaryOperators": true,
|
||||
"disallowMultipleVarDecl": true,
|
||||
"disallowKeywordsOnNewLine": ["else"],
|
||||
|
||||
"requireSpaceAfterKeywords": [
|
||||
"if",
|
||||
"else",
|
||||
"for",
|
||||
"while",
|
||||
"do",
|
||||
"switch",
|
||||
"return",
|
||||
"try",
|
||||
"catch"
|
||||
],
|
||||
"requireSpaceBeforeBinaryOperators": [
|
||||
"=", "+=", "-=", "*=", "/=", "%=", "<<=", ">>=", ">>>=",
|
||||
"&=", "|=", "^=", "+=",
|
||||
|
||||
"+", "-", "*", "/", "%", "<<", ">>", ">>>", "&",
|
||||
"|", "^", "&&", "||", "===", "==", ">=",
|
||||
"<=", "<", ">", "!=", "!=="
|
||||
],
|
||||
"requireSpaceAfterBinaryOperators": true,
|
||||
"requireSpacesInConditionalExpression": true,
|
||||
"requireSpaceBeforeBlockStatements": true,
|
||||
"requireSpacesInForStatement": true,
|
||||
"requireLineFeedAtFileEnd": true,
|
||||
"requireSpacesInFunctionExpression": {
|
||||
"beforeOpeningCurlyBrace": true
|
||||
},
|
||||
"disallowSpacesInAnonymousFunctionExpression": {
|
||||
"beforeOpeningRoundBrace": false
|
||||
},
|
||||
"disallowSpacesInsideObjectBrackets": "all",
|
||||
"disallowSpacesInsideArrayBrackets": "all",
|
||||
"disallowSpacesInsideParentheses": true,
|
||||
|
||||
"disallowMultipleLineBreaks": true,
|
||||
"disallowNewlineBeforeBlockStatements": true,
|
||||
"disallowKeywords": ["with"],
|
||||
"disallowSpacesInFunctionExpression": null,
|
||||
"disallowSpacesInFunctionDeclaration": null,
|
||||
"disallowSpacesInCallExpression": true,
|
||||
"disallowSpaceAfterObjectKeys": false,
|
||||
"requireSpaceBeforeObjectValues": true,
|
||||
"requireCapitalizedConstructors": true,
|
||||
"requireDotNotation": true,
|
||||
"requireSemicolons": true,
|
||||
"validateParameterSeparator": ", ",
|
||||
|
||||
"jsDoc": null
|
||||
}
|
@ -1,14 +1,9 @@
|
||||
language: node_js
|
||||
node_js:
|
||||
- "4.1"
|
||||
- "7.4.0"
|
||||
before_install:
|
||||
- npm update -g npm
|
||||
- npm install -g grunt-cli
|
||||
- git clone git://github.com/n1k0/casperjs.git ~/casperjs
|
||||
- cd ~/casperjs
|
||||
- git checkout tags/1.0.2
|
||||
- export PATH=$PATH:`pwd`/bin
|
||||
- cd -
|
||||
before_script:
|
||||
- phantomjs --version
|
||||
- casperjs --version
|
||||
|
206
Gruntfile.js
@ -9,11 +9,10 @@ module.exports = function(grunt) {
|
||||
TEST : 9991
|
||||
};
|
||||
|
||||
var DEV_MODE = '?debug';
|
||||
|
||||
// create a version based on the build timestamp
|
||||
var dateFormat = require('dateformat');
|
||||
var version = '-' + dateFormat(new Date(), "yyyy-mm-dd-hh-MM");
|
||||
var releaseVersion = require('./package.json').version;
|
||||
|
||||
/**
|
||||
* Helper to prefix all strings in provided array with the provided path
|
||||
@ -34,37 +33,27 @@ module.exports = function(grunt) {
|
||||
var stylePaths = require('./src/piskel-style-list.js').styles;
|
||||
var piskelStyles = prefixPaths(stylePaths, "src/");
|
||||
|
||||
var getCasperConfig = function (suiteName, delay, host) {
|
||||
var testPaths = require('./test/casperjs/' + suiteName).tests;
|
||||
var tests = prefixPaths(testPaths, "test/casperjs/");
|
||||
// Casper JS tests
|
||||
var casperjsOptions = [
|
||||
'--baseUrl=http://' + hostname + ':' + PORT.TEST,
|
||||
'--mode=?debug',
|
||||
'--verbose=false',
|
||||
'--includes=test/casperjs/integration/include.js',
|
||||
'--log-level=info',
|
||||
'--print-command=false',
|
||||
'--print-file-paths=true',
|
||||
];
|
||||
|
||||
return {
|
||||
filesSrc : tests,
|
||||
options : {
|
||||
args : {
|
||||
baseUrl : 'http://' + host + ':' + PORT.TEST,
|
||||
mode : DEV_MODE,
|
||||
delay : delay
|
||||
},
|
||||
async : false,
|
||||
direct : false,
|
||||
logLevel : 'info',
|
||||
printCommand : false,
|
||||
printFilePaths : true
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
var getConnectConfig = function (base, port, host) {
|
||||
if (typeof base === 'string') {
|
||||
base = [base];
|
||||
}
|
||||
var integrationTestPaths = require('./test/casperjs/integration/IntegrationSuite.js').tests;
|
||||
var integrationTests = prefixPaths(integrationTestPaths, "test/casperjs/integration/");
|
||||
|
||||
var getConnectConfig = function (base, port, host, open) {
|
||||
return {
|
||||
options: {
|
||||
port: port,
|
||||
hostname : host,
|
||||
base: base
|
||||
base: base,
|
||||
open: open
|
||||
}
|
||||
};
|
||||
};
|
||||
@ -91,32 +80,13 @@ module.exports = function(grunt) {
|
||||
css : ['src/css/**/*.css']
|
||||
},
|
||||
|
||||
jscs : {
|
||||
options : {
|
||||
"config": ".jscsrc",
|
||||
"maximumLineLength": 120,
|
||||
"requireCamelCaseOrUpperCaseIdentifiers": "ignoreProperties",
|
||||
"validateQuoteMarks": { "mark": "'", "escape": true },
|
||||
"disallowMultipleVarDecl": "exceptUndefined",
|
||||
"disallowSpacesInAnonymousFunctionExpression": null
|
||||
},
|
||||
js : [ 'src/js/**/*.js' , '!src/js/**/lib/**/*.js' ]
|
||||
},
|
||||
|
||||
jshint: {
|
||||
options: {
|
||||
undef : true,
|
||||
latedef : true,
|
||||
browser : true,
|
||||
trailing : true,
|
||||
curly : true,
|
||||
globals : {'$':true, 'jQuery' : true, 'pskl':true, 'Events':true, 'Constants':true, 'console' : true, 'module':true, 'require':true, 'Q':true}
|
||||
},
|
||||
eslint: {
|
||||
files: [
|
||||
'Gruntfile.js',
|
||||
'package.json',
|
||||
// Includes
|
||||
'src/js/**/*.js',
|
||||
'!src/js/**/lib/**/*.js' // Exclude lib folder (note the leading !)
|
||||
// Exludes
|
||||
// TODO: remove this (for now we still get warnings from the lib folder)
|
||||
'!src/js/**/lib/**/*.js'
|
||||
]
|
||||
},
|
||||
|
||||
@ -125,18 +95,9 @@ module.exports = function(grunt) {
|
||||
*/
|
||||
|
||||
connect: {
|
||||
prod: getConnectConfig('dest/prod', PORT.PROD, hostname),
|
||||
test: getConnectConfig(['dest/dev', 'test'], PORT.TEST, hostname),
|
||||
dev: getConnectConfig(['dest/dev', 'test'], PORT.DEV, hostname)
|
||||
},
|
||||
|
||||
open : {
|
||||
prod : {
|
||||
path : 'http://' + hostname + ':' + PORT.PROD + '/'
|
||||
},
|
||||
dev : {
|
||||
path : 'http://' + hostname + ':' + PORT.DEV + '/' + DEV_MODE
|
||||
}
|
||||
prod: getConnectConfig('dest/prod', PORT.PROD, hostname, true),
|
||||
test: getConnectConfig(['dest/dev', 'test'], PORT.TEST, hostname, false),
|
||||
dev: getConnectConfig(['dest/dev', 'test'], PORT.DEV, hostname, 'http://' + hostname + ':' + PORT.DEV + '/?debug')
|
||||
},
|
||||
|
||||
watch: {
|
||||
@ -180,7 +141,7 @@ module.exports = function(grunt) {
|
||||
},
|
||||
css : {
|
||||
src : piskelStyles,
|
||||
dest : 'dest/prod/css/piskel-style-packaged' + version + '.css'
|
||||
dest : 'dest/tmp/css/piskel-style-packaged' + version + '.css'
|
||||
}
|
||||
},
|
||||
|
||||
@ -201,7 +162,8 @@ module.exports = function(grunt) {
|
||||
dest: 'dest/tmp/index.html',
|
||||
options : {
|
||||
globals : {
|
||||
'version' : version
|
||||
'version' : version,
|
||||
'releaseVersion' : releaseVersion
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -231,19 +193,18 @@ module.exports = function(grunt) {
|
||||
{src: ['dest/tmp/index.html'], dest: 'dest/prod/piskelapp-partials/main-partial.html'}
|
||||
]
|
||||
},
|
||||
// remove the fake header from the desktop build
|
||||
desktop: {
|
||||
|
||||
css: {
|
||||
options: {
|
||||
patterns: [{
|
||||
match: /<!--standalone-start-->(?:.|[\r\n])*<!--standalone-end-->/,
|
||||
replacement: "",
|
||||
description : "Remove everything between standalone-start & standalone-end"
|
||||
}
|
||||
]
|
||||
match: /var\(--highlight-color\)/g,
|
||||
replacement: "gold",
|
||||
}]
|
||||
},
|
||||
files: [
|
||||
{src: ['dest/prod/index.html'], dest: 'dest/prod/index.html'}
|
||||
]
|
||||
files: [{
|
||||
src: ['dest/tmp/css/piskel-style-packaged' + version + '.css'],
|
||||
dest: 'dest/prod/css/piskel-style-packaged' + version + '.css'
|
||||
}]
|
||||
}
|
||||
},
|
||||
|
||||
@ -282,9 +243,23 @@ module.exports = function(grunt) {
|
||||
}
|
||||
},
|
||||
|
||||
ghost : {
|
||||
'travis' : getCasperConfig('TravisTestSuite.js', 10000, hostname),
|
||||
'local' : getCasperConfig('LocalTestSuite.js', 50, hostname)
|
||||
casperjs : {
|
||||
drawing : {
|
||||
files : {
|
||||
src: ['test/casperjs/DrawingTest.js']
|
||||
},
|
||||
options : {
|
||||
casperjsOptions: casperjsOptions
|
||||
}
|
||||
},
|
||||
integration : {
|
||||
files : {
|
||||
src: integrationTests
|
||||
},
|
||||
options : {
|
||||
casperjsOptions: casperjsOptions
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
/**
|
||||
@ -294,57 +269,78 @@ module.exports = function(grunt) {
|
||||
nwjs: {
|
||||
windows : {
|
||||
options: {
|
||||
version : "0.15.4",
|
||||
downloadUrl: 'https://dl.nwjs.io/',
|
||||
version : "0.19.4",
|
||||
build_dir: './dest/desktop/', // destination folder of releases.
|
||||
win: true,
|
||||
linux32: true,
|
||||
linux64: true
|
||||
linux64: true,
|
||||
flavor: "normal",
|
||||
},
|
||||
src: ['./dest/prod/**/*', "./package.json", "!./dest/desktop/"]
|
||||
},
|
||||
macos : {
|
||||
options: {
|
||||
downloadUrl: 'https://dl.nwjs.io/',
|
||||
osx64: true,
|
||||
version : "0.15.4",
|
||||
build_dir: './dest/desktop/'
|
||||
version : "0.19.4",
|
||||
build_dir: './dest/desktop/',
|
||||
flavor: "normal",
|
||||
},
|
||||
src: ['./dest/prod/**/*', "./package.json", "!./dest/desktop/"]
|
||||
},
|
||||
macos_old : {
|
||||
options: {
|
||||
downloadUrl: 'https://dl.nwjs.io/',
|
||||
osx64: true,
|
||||
version : "0.12.3",
|
||||
build_dir: './dest/desktop/old',
|
||||
flavor: "normal",
|
||||
},
|
||||
src: ['./dest/prod/**/*', "./package.json", "!./dest/desktop/"]
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
// Validate
|
||||
grunt.registerTask('lint', ['jscs:js', 'leadingIndent:css', 'jshint']);
|
||||
|
||||
// karma/unit-tests task
|
||||
// TEST TASKS
|
||||
// Run linting
|
||||
grunt.registerTask('lint', ['eslint', 'leadingIndent:css']);
|
||||
// Run unit-tests
|
||||
grunt.registerTask('unit-test', ['karma']);
|
||||
// Run integration tests
|
||||
grunt.registerTask('integration-test', ['build-dev', 'connect:test', 'casperjs:integration']);
|
||||
// Run drawing tests
|
||||
grunt.registerTask('drawing-test', ['build-dev', 'connect:test', 'casperjs:drawing']);
|
||||
// Run linting, unit tests, drawing tests and integration tests
|
||||
grunt.registerTask('test', ['lint', 'unit-test', 'build-dev', 'connect:test', 'casperjs:drawing', 'casperjs:integration']);
|
||||
|
||||
// Validate & Test
|
||||
grunt.registerTask('test-travis', ['lint', 'unit-test', 'build-dev', 'connect:test', 'ghost:travis']);
|
||||
// Validate & Test (faster version) will NOT work on travis !!
|
||||
grunt.registerTask('test-local', ['lint', 'unit-test', 'build-dev', 'connect:test', 'ghost:local']);
|
||||
grunt.registerTask('test-local-nolint', ['unit-test', 'build-dev', 'connect:test', 'ghost:local']);
|
||||
// Run the tests, even if the linting fails
|
||||
grunt.registerTask('test-nolint', ['unit-test', 'build-dev', 'connect:test', 'casperjs:drawing', 'casperjs:integration']);
|
||||
|
||||
grunt.registerTask('test', ['test-travis']);
|
||||
grunt.registerTask('precommit', ['test-local']);
|
||||
// Used by optional precommit hook
|
||||
grunt.registerTask('precommit', ['test']);
|
||||
|
||||
// BUILD TASKS
|
||||
grunt.registerTask('build-index.html', ['includereplace']);
|
||||
grunt.registerTask('merge-statics', ['concat:js', 'concat:css', 'uglify']);
|
||||
grunt.registerTask('build', ['clean:prod', 'sprite', 'merge-statics', 'build-index.html', 'replace:mainPartial', 'copy:prod']);
|
||||
grunt.registerTask('build', ['clean:prod', 'sprite', 'merge-statics', 'build-index.html', 'replace:mainPartial', 'replace:css', 'copy:prod']);
|
||||
grunt.registerTask('build-dev', ['clean:dev', 'sprite', 'build-index.html', 'copy:dev']);
|
||||
grunt.registerTask('desktop', ['clean:desktop', 'default', 'nwjs:windows']);
|
||||
grunt.registerTask('desktop-mac', ['clean:desktop', 'default', 'nwjs:macos']);
|
||||
grunt.registerTask('desktop-mac-old', ['clean:desktop', 'default', 'replace:desktop', 'nwjs:macos_old']);
|
||||
|
||||
// Validate & Build
|
||||
grunt.registerTask('default', ['lint', 'build']);
|
||||
|
||||
// Build stand alone app with nodewebkit
|
||||
grunt.registerTask('desktop', ['clean:desktop', 'default', 'replace:desktop', 'nwjs:windows']);
|
||||
grunt.registerTask('desktop-mac', ['clean:desktop', 'default', 'replace:desktop', 'nwjs:macos']);
|
||||
|
||||
// SERVER TASKS
|
||||
// Start webserver and watch for changes
|
||||
grunt.registerTask('serve', ['build', 'connect:prod', 'open:prod', 'watch:prod']);
|
||||
grunt.registerTask('serve', ['build', 'connect:prod', 'watch:prod']);
|
||||
// Start webserver on src folder, in debug mode
|
||||
grunt.registerTask('serve-dev', ['build-dev', 'connect:dev', 'open:dev', 'watch:dev']);
|
||||
grunt.registerTask('play', ['build-dev', 'connect:dev', 'watch:dev']);
|
||||
|
||||
grunt.registerTask('serve-debug', ['serve-dev']);
|
||||
grunt.registerTask('play', ['serve-dev']);
|
||||
// ALIASES, kept for backward compatibility
|
||||
grunt.registerTask('serve-debug', ['play']);
|
||||
grunt.registerTask('serve-dev', ['play']);
|
||||
grunt.registerTask('test-travis', ['test']);
|
||||
grunt.registerTask('test-local', ['test']);
|
||||
|
||||
// Default task
|
||||
grunt.registerTask('default', ['lint', 'build']);
|
||||
};
|
||||
|
82
README.md
@ -1,75 +1,61 @@
|
||||
Piskel
|
||||
======
|
||||
|
||||
[](https://travis-ci.org/juliandescottes/piskel) [](http://gruntjs.com/)
|
||||
[](https://travis-ci.org/piskelapp/piskel) [](https://gruntjs.com/)
|
||||
|
||||
A simple web-based tool for Spriting and Pixel art.
|
||||
Piskel is an easy-to-use sprite editor. It can be used to create game sprites, animations, pixel-art...
|
||||
It is the editor used in **[piskelapp.com](https://www.piskelapp.com)**.
|
||||
|
||||

|
||||
<img
|
||||
src="https://screenletstore.appspot.com/img/95aaa0f0-37a4-11e7-a652-7b8128ce3e3b.png"
|
||||
title="Piskel editor screenshot"
|
||||
width="500">
|
||||
|
||||
You can try the standalone editor at **http://juliandescottes.github.io/piskel** or see it integrated in **http://piskelapp.com**.
|
||||
## About Piskel
|
||||
|
||||
Piskel is mainly developped by :
|
||||
### Built with
|
||||
|
||||
* **[@juliandescottes](https://github.com/juliandescottes)**
|
||||
* **[@grosbouddha](https://github.com/grosbouddha)**
|
||||
|
||||
## What's the point ?
|
||||
|
||||
You can use Piskel to do two things :
|
||||
* **spriting** : create retro-style sprites for games
|
||||
|
||||

|
||||
|
||||
* **pixelart** : create crazy/pretty pixelart animations for fun !
|
||||
|
||||

|
||||
|
||||
Integrated in **[piskelapp.com](http://piskelapp.com)**, you can share everything you work on with others as easily as you share a link.
|
||||
|
||||
## Requirements
|
||||
|
||||
Piskel supports the following browsers :
|
||||
* **Chrome** (latest)
|
||||
* **Firefox** (latest)
|
||||
* **Internet Explorer** 11+
|
||||
|
||||
... and a fairly recent computer.
|
||||
|
||||
We don't plan/want/could be forced into supporting older IEs. For Opera and Safari, we've never tested them but the gap shouldn't be huge.
|
||||
|
||||
## Offline version
|
||||
|
||||
Offline builds are available. More details in the [dedicated wiki page](https://github.com/juliandescottes/piskel/wiki/Desktop-applications).
|
||||
|
||||
## Built with
|
||||
|
||||
The Piskel editor is purely built in **JavaScript, HTML and CSS**. It uses Canvas extensively for displaying all them pretty sprites.
|
||||
The Piskel editor is purely built in **JavaScript, HTML and CSS**.
|
||||
|
||||
We also use the following **libraries** :
|
||||
* [spectrum](https://github.com/bgrins/spectrum) : awesome standalone colorpicker
|
||||
* [gifjs](http://jnordberg.github.io/gif.js/) : generate animated GIFs in javascript, using webworkers
|
||||
* [gifjs](https://jnordberg.github.io/gif.js/) : generate animated GIFs in javascript, using webworkers
|
||||
* [supergif](https://github.com/buzzfeed/libgif-js) : modified version of SuperGif to parse and import GIFs
|
||||
* [jszip](https://github.com/Stuk/jszip) : create, read and edit .zip files with Javascript
|
||||
* [canvas-toBlob](https://github.com/eligrey/canvas-toBlob.js/) : shim for canvas toBlob
|
||||
* [jquery](http://jquery.com/) : used sporadically in the application
|
||||
* [bootstrap-tooltip](http://getbootstrap.com/javascript/#tooltips) : nice tooltips
|
||||
* [jquery](https://jquery.com/) : used sporadically in the application
|
||||
* [bootstrap-tooltip](https://getbootstrap.com/javascript/#tooltips) : nice tooltips
|
||||
|
||||
As well as some **icons** from the [Noun Project](http://thenounproject.com/) :
|
||||
As well as some **icons** from the [Noun Project](https://thenounproject.com/) :
|
||||
* Folder by Simple Icons from The Noun Project
|
||||
* (and probably one or two others)
|
||||
|
||||
### Browser Support
|
||||
|
||||
Piskel supports the following browsers:
|
||||
* **Chrome** (latest)
|
||||
* **Firefox** (latest)
|
||||
* **Edge** (latest)
|
||||
* **Internet Explorer** 11
|
||||
|
||||
### Mobile/Tablets
|
||||
|
||||
There is no support for mobile.
|
||||
|
||||
### Offline builds
|
||||
|
||||
Offline builds are available. More details in the [dedicated wiki page](https://github.com/piskelapp/piskel/wiki/Desktop-applications).
|
||||
|
||||
## Contributing ?
|
||||
|
||||
Help is always welcome !
|
||||
|
||||
* **Issues** : Found a problem when using the application, want to request a feature, [open an issue](https://github.com/juliandescottes/piskel/issues).
|
||||
* **Participate** : Have a look at the [wiki](https://github.com/juliandescottes/piskel/wiki) to set up the development environment
|
||||
* **Issues** : Found a problem when using the application, want to request a feature, [open an issue](https://github.com/piskelapp/piskel/issues).
|
||||
* **Development** : Have a look at the [wiki](https://github.com/piskelapp/piskel/wiki) to set up the development environment
|
||||
|
||||
## License
|
||||
|
||||
Copyright 2016 Julian Descottes
|
||||
Copyright 2017 Julian Descottes
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
@ -83,7 +69,3 @@ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
See the License for the specific language governing permissions and
|
||||
limitations under the License.
|
||||
|
||||
## Mobile/Tablets
|
||||
|
||||
There is no support for mobile for now.
|
||||
|
||||
|
84
bin/copy-to-piskel-website.js
Normal file
@ -0,0 +1,84 @@
|
||||
const rmdir = require('rmdir');
|
||||
const path = require('path');
|
||||
const fs = require('fs');
|
||||
const fse = require('fs-extra');
|
||||
|
||||
const PISKEL_PATH = path.resolve(__dirname, '..');
|
||||
const PISKELAPP_PATH = path.resolve(__dirname, '../../piskel-website');
|
||||
|
||||
var pjson = require('../package.json');
|
||||
|
||||
// Callbacks sorted by call sequence.
|
||||
function onCopy(err) {
|
||||
if (err) {
|
||||
console.error('Failed to copy static files...');
|
||||
return console.error(err);
|
||||
}
|
||||
|
||||
console.log('Copied static files to piskel-website...');
|
||||
let previousPartialPath = path.resolve(PISKELAPP_PATH, 'templates/editor/main-partial.html');
|
||||
fs.access(previousPartialPath, fs.constants.F_OK, function (err) {
|
||||
if (err) {
|
||||
// File does not exit, call next step directly.
|
||||
console.error('Previous main partial doesn\'t exist yet.');
|
||||
onDeletePreviousPartial();
|
||||
} else {
|
||||
// File exists, try to delete it before moving on.
|
||||
fs.unlink(previousPartialPath, onDeletePreviousPartial);
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
function onDeletePreviousPartial(err) {
|
||||
if (err) {
|
||||
console.error('Failed to delete previous main partial...');
|
||||
return console.error(err);
|
||||
}
|
||||
|
||||
console.log('Previous main partial deleted...');
|
||||
fse.copy(
|
||||
path.resolve(PISKELAPP_PATH, "static/editor/piskelapp-partials/main-partial.html"),
|
||||
path.resolve(PISKELAPP_PATH, "templates/editor/main-partial.html"),
|
||||
onCopyNewPartial
|
||||
);
|
||||
}
|
||||
|
||||
function onCopyNewPartial(err) {
|
||||
if (err) {
|
||||
console.error('Failed to delete previous main partial...');
|
||||
return console.error(err);
|
||||
}
|
||||
|
||||
console.log('Main partial copied...');
|
||||
rmdir(
|
||||
path.resolve(PISKELAPP_PATH, "static/editor/piskelapp-partials/"),
|
||||
onDeleteTempPartial
|
||||
);
|
||||
}
|
||||
|
||||
function onDeleteTempPartial(err) {
|
||||
if (err) {
|
||||
console.error('Failed to delete temporary main partial...');
|
||||
return console.error(err);
|
||||
}
|
||||
|
||||
console.log('Temporary main partial deleted...');
|
||||
|
||||
fs.writeFile(path.resolve(PISKELAPP_PATH, "static/editor/VERSION"), pjson.version, onVersionFileCreated);
|
||||
}
|
||||
|
||||
function onVersionFileCreated(err) {
|
||||
if (err) {
|
||||
console.error('Failed to create temporary main partial...');
|
||||
return console.error(err);
|
||||
}
|
||||
|
||||
console.log('Version file created...');
|
||||
console.log('Finished!');
|
||||
}
|
||||
|
||||
fse.copy(
|
||||
path.resolve(PISKEL_PATH, "dest/prod"),
|
||||
path.resolve(PISKELAPP_PATH, "static/editor"),
|
||||
onCopy
|
||||
);
|
64
cli/README.md
Normal file
@ -0,0 +1,64 @@
|
||||
# Piskel CLI
|
||||
|
||||
Wraps the Piskel pixel editing application to enable similar export options via the command line.
|
||||
|
||||
## Installation
|
||||
|
||||
Option 1: Globally install Piskel
|
||||
```
|
||||
npm install -g https://github.com/piskelapp/piskel/tarball/master
|
||||
```
|
||||
|
||||
Option 2: Clone and install Piskel normally and then run npm link inside the installation root
|
||||
|
||||
## Usage
|
||||
|
||||
**Export provided .piskel file as a png sprite sheet using app defaults**
|
||||
```
|
||||
piskel-cli snow-monster.piskel
|
||||
```
|
||||
|
||||
**Export scaled sprite sheet**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --scale 5
|
||||
```
|
||||
|
||||
**Export scaled to specific (single frame) width value**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --scaledWidth 435
|
||||
```
|
||||
|
||||
**Export scaled to specific (single frame) height value**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --scaledHeight 435
|
||||
```
|
||||
|
||||
**Export sprite sheet as a single column**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --columns 1
|
||||
```
|
||||
|
||||
**Export sprite sheet as a single row**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --rows 1
|
||||
```
|
||||
|
||||
**Export a single frame (0 is first frame)**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --frame 3
|
||||
```
|
||||
|
||||
**Export a second file containing the data-uri for the exported png**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --dataUri
|
||||
```
|
||||
|
||||
**Export cropped**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --crop
|
||||
```
|
||||
|
||||
**Custom output path and/or filename**
|
||||
```
|
||||
piskel-cli snow-monster.piskel --dest ./output-folder/snah-monstah.png
|
||||
```
|
130
cli/export-png.js
Normal file
@ -0,0 +1,130 @@
|
||||
const fs = require('fs');
|
||||
|
||||
function onPageEvaluate(window, options, piskel) {
|
||||
console.log("\nPiskel name: " + piskel.descriptor.name);
|
||||
|
||||
// Setup piskelController
|
||||
var piskelController = new pskl.controller.piskel.PiskelController(piskel);
|
||||
|
||||
pskl.app.piskelController = piskelController;
|
||||
|
||||
piskelController.init();
|
||||
|
||||
// Apply crop if enabled
|
||||
if (options.crop) {
|
||||
// Mock selection manager to avoid errors during crop
|
||||
pskl.app.selectionManager = {};
|
||||
|
||||
// Setup crop tool
|
||||
var crop = new pskl.tools.transform.Crop();
|
||||
|
||||
// Perform crop
|
||||
crop.applyTransformation();
|
||||
|
||||
// Get cropped piskel
|
||||
piskel = piskelController.getPiskel();
|
||||
}
|
||||
|
||||
// Mock exportController to provide zoom value based on cli args
|
||||
// and to avoid errors and/or unnecessary bootstrapping
|
||||
var exportController = {
|
||||
getExportZoom: function () {
|
||||
var zoom = options.zoom;
|
||||
|
||||
if (options.scaledWidth) {
|
||||
zoom = options.scaledWidth / piskel.getWidth();
|
||||
} else if (options.scaledHeight) {
|
||||
zoom = options.scaledHeight / piskel.getHeight();
|
||||
}
|
||||
|
||||
return zoom;
|
||||
}
|
||||
};
|
||||
|
||||
// Setup pngExportController
|
||||
var pngExportController = new pskl.controller.settings.exportimage.PngExportController(piskelController, exportController);
|
||||
|
||||
// Mock getColumns and getRows to use values from cli arguments
|
||||
pngExportController.getColumns_ = function () {
|
||||
if (options.columns) return options.columns;
|
||||
|
||||
if (options.rows) {
|
||||
return Math.ceil(piskelController.getFrameCount() / pngExportController.getRows_());
|
||||
} else {
|
||||
return pngExportController.getBestFit_();
|
||||
}
|
||||
};
|
||||
|
||||
pngExportController.getRows_ = function () {
|
||||
if (options.columns && !options.rows) {
|
||||
return Math.ceil(piskelController.getFrameCount() / pngExportController.getColumns_());
|
||||
}
|
||||
|
||||
return options.rows;
|
||||
};
|
||||
|
||||
// Render to output canvas
|
||||
var canvas;
|
||||
|
||||
if (options.frame > -1) {
|
||||
// Render a single frame
|
||||
canvas = piskelController.renderFrameAt(options.frame, true);
|
||||
|
||||
var zoom = exportController.getExportZoom();
|
||||
|
||||
if (zoom != 1) {
|
||||
// Scale rendered frame
|
||||
canvas = pskl.utils.ImageResizer.resize(canvas, canvas.width * zoom, canvas.height * zoom, false);
|
||||
}
|
||||
} else {
|
||||
// Render the sprite sheet
|
||||
canvas = pngExportController.createPngSpritesheet_();
|
||||
}
|
||||
|
||||
// Add output canvas to DOM
|
||||
window.document.body.appendChild(canvas);
|
||||
|
||||
// Prepare return data
|
||||
const returnData = {
|
||||
width: canvas.width,
|
||||
height: canvas.height
|
||||
};
|
||||
|
||||
// Wait a tick for things to wrap up
|
||||
setTimeout(function () {
|
||||
// Exit and pass data to parent process
|
||||
window.callPhantom(returnData);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
function onPageExit(page, options, data) {
|
||||
// Set clip for output image
|
||||
if (data.width && data.height) {
|
||||
page.clipRect = { top: 0, left: 0, width: data.width, height: data.height };
|
||||
}
|
||||
|
||||
console.log("\n" + 'Generated file(s):');
|
||||
|
||||
const dest = options.dest.replace('.png', '') + '.png';
|
||||
|
||||
// Render page to the output image
|
||||
page.render(dest);
|
||||
|
||||
console.log(" " + dest);
|
||||
|
||||
if (options.dataUri) {
|
||||
const dataUriPath = options.dest + '.datauri';
|
||||
|
||||
const dataUri = 'data:image/png;base64,' + page.renderBase64('PNG');
|
||||
|
||||
// Write data-uri to file
|
||||
fs.write(dataUriPath, dataUri, 'w');
|
||||
|
||||
console.log(" " + dataUriPath);
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
onPageEvaluate: onPageEvaluate,
|
||||
onPageExit: onPageExit
|
||||
};
|
93
cli/index.js
Normal file
@ -0,0 +1,93 @@
|
||||
#!/usr/bin/env node
|
||||
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
const minimist = require('minimist');
|
||||
const childProcess = require('child_process');
|
||||
const phantomjs = require('phantomjs');
|
||||
const binPath = phantomjs.path;
|
||||
|
||||
// Parse command args
|
||||
let args = minimist(process.argv.slice(2), {
|
||||
default: {
|
||||
crop: false,
|
||||
dataUri: false,
|
||||
debug: false,
|
||||
scale: 1
|
||||
},
|
||||
});
|
||||
|
||||
if (args.debug) console.log(args);
|
||||
|
||||
// Ensure a path for the src file was passed
|
||||
if (!args._ || (args._ && !args._.length)) {
|
||||
console.error('Path to a .piskel file is required');
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
const src = args._[0];
|
||||
|
||||
// Ensure the src file exists
|
||||
if (!fs.existsSync(src)) {
|
||||
console.error('No such file: ' + src);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Read src piskel file
|
||||
const piskelFile = fs.readFileSync(src, 'utf-8');
|
||||
|
||||
const dest = args.dest || path.basename(src, '.piskel');
|
||||
|
||||
console.log('Piskel CLI is exporting...');
|
||||
|
||||
// Get path to Piskel's app js bundle
|
||||
let piskelAppJsDir = path.resolve(__dirname +'/../dest/prod/js/');
|
||||
let minJsFiles = fs.readdirSync(piskelAppJsDir).filter(filename => filename.indexOf('min') > -1);
|
||||
let piskelAppJsFileName = minJsFiles[0];
|
||||
let piskelAppJsPath = (piskelAppJsFileName) ? path.join(piskelAppJsDir, piskelAppJsFileName) : '';
|
||||
|
||||
if (!fs.existsSync(piskelAppJsPath)) {
|
||||
console.error(`Piskel's application JS file not found in: ${piskelAppJsDir}. Run prod build and try again.`);
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Prepare args to pass to phantom script
|
||||
const options = {
|
||||
dest: dest,
|
||||
zoom: args.scale,
|
||||
crop: !!args.crop,
|
||||
rows: args.rows,
|
||||
columns: args.columns,
|
||||
frame: args.frame,
|
||||
dataUri: !!args.dataUri,
|
||||
debug: args.debug,
|
||||
piskelAppJsPath: piskelAppJsPath,
|
||||
scaledWidth: args.scaledWidth,
|
||||
scaledHeight: args.scaledHeight
|
||||
};
|
||||
|
||||
const childArgs = [
|
||||
path.join(__dirname, 'piskel-export.js'),
|
||||
piskelFile,
|
||||
JSON.stringify(options)
|
||||
];
|
||||
|
||||
if (args.debug) {
|
||||
childArgs.unshift(
|
||||
'--remote-debugger-port=9035',
|
||||
'--remote-debugger-autorun=yes'
|
||||
);
|
||||
}
|
||||
|
||||
// Run phantom script
|
||||
childProcess.execFile(binPath, childArgs, function (err, stdout, stderr) {
|
||||
// Print any output the from child process
|
||||
if (err) console.log(err);
|
||||
if (stderr) console.log(stderr);
|
||||
if (stdout) console.log(stdout);
|
||||
|
||||
console.log('Export complete');
|
||||
});
|
45
cli/piskel-export.js
Normal file
@ -0,0 +1,45 @@
|
||||
// PhantomJS system
|
||||
const system = require('system');
|
||||
|
||||
// Exporter
|
||||
const exporter = require('./export-png');
|
||||
|
||||
// Get passed args
|
||||
const args = system.args;
|
||||
|
||||
// Parse input piskel file and options
|
||||
const piskelFile = JSON.parse(args[1]);
|
||||
const options = JSON.parse(args[2]);
|
||||
|
||||
// Create page w/ canvas
|
||||
const page = require('webpage').create();
|
||||
|
||||
page.content = '<html><body></body></html>';
|
||||
|
||||
// Inject Piskel JS
|
||||
page.injectJs(options.piskelAppJsPath);
|
||||
|
||||
// Listen for page console logs
|
||||
page.onConsoleMessage = function (msg) {
|
||||
console.log(msg);
|
||||
};
|
||||
|
||||
// Run page logic
|
||||
page.evaluate(function (piskelFile, options, onPageEvaluate) {
|
||||
// Zero out default body margin
|
||||
document.body.style.margin = 0;
|
||||
|
||||
// Deserialize piskel file and run exporter's page evaluate task
|
||||
pskl.utils.serialization.Deserializer.deserialize(piskelFile, function (piskel) {
|
||||
onPageEvaluate(window, options, piskel);
|
||||
});
|
||||
}, piskelFile, options, exporter.onPageEvaluate);
|
||||
|
||||
// Wait for page to trigger exit
|
||||
page.onCallback = function (data) {
|
||||
// Run exporter page exit task
|
||||
exporter.onPageExit(page, options, data);
|
||||
|
||||
// Exit
|
||||
phantom.exit(0);
|
||||
};
|
@ -8,7 +8,10 @@ module.exports = function(config) {
|
||||
var piskelScripts = require('./src/piskel-script-list.js').scripts.map(mapToSrcFolder);
|
||||
piskelScripts.push('test/js/testutils/**/*.js');
|
||||
piskelScripts.push('test/js/**/*.js');
|
||||
|
||||
|
||||
// Polyfill for Object.assign (missing in PhantomJS)
|
||||
piskelScripts.push('./node_modules/phantomjs-polyfill-object-assign/object-assign-polyfill.js');
|
||||
|
||||
config.set({
|
||||
|
||||
// base path that will be used to resolve all patterns (eg. files, exclude)
|
||||
@ -21,7 +24,9 @@ module.exports = function(config) {
|
||||
|
||||
|
||||
// list of files / patterns to load in the browser
|
||||
files: piskelScripts,
|
||||
files: piskelScripts.concat([
|
||||
'./node_modules/promise-polyfill/promise.js'
|
||||
]),
|
||||
|
||||
|
||||
// list of files to exclude
|
||||
|
80
misc/icons/source/common-backup.svg
Normal file
@ -0,0 +1,80 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="90"
|
||||
height="90"
|
||||
viewBox="0 0 89.999997 90"
|
||||
enable-background="new 0 0 89.231 100"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.92.1 r15371"
|
||||
sodipodi:docname="common-backup.svg"
|
||||
inkscape:export-filename="C:\Development\git\piskel\misc\icons\source\tool-rotate.png"
|
||||
inkscape:export-xdpi="45"
|
||||
inkscape:export-ydpi="45"><metadata
|
||||
id="metadata15"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs13" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1148"
|
||||
id="namedview11"
|
||||
showgrid="false"
|
||||
inkscape:zoom="7.75"
|
||||
inkscape:cx="13.031976"
|
||||
inkscape:cy="43.272537"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" /><g
|
||||
id="g3760"
|
||||
transform="matrix(0,-0.97677741,0.97203982,0,-2.1261998,91.355253)"
|
||||
style="fill:#ff00ff;fill-opacity:1"><path
|
||||
style="fill:#ff00ff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path3"
|
||||
d="m 29.229405,55.37008 c -0.387431,-1.333059 -0.642506,-2.72161 -0.738881,-4.152895 h -8.675106 c 0.115651,2.460738 0.552554,4.838559 1.260594,7.099021 z" /><path
|
||||
style="fill:#ff00ff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path5"
|
||||
d="m 29.023802,70.783821 5.579515,-6.601516 c -1.862622,-1.780814 -3.387929,-3.907969 -4.44999,-6.287065 l -8.152106,2.946124 c 1.604978,3.800815 4.017584,7.185766 7.022581,9.942457 z" /><path
|
||||
style="fill:#ff00ff;fill-opacity:1"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path7"
|
||||
d="m 47.110967,69.703978 c -3.887799,-0.260871 -7.469766,-1.6322 -10.437498,-3.790608 l -5.577588,6.598963 c 4.487901,3.403448 10.011517,5.524225 16.015086,5.803594 z" /><path
|
||||
style="fill:#ff00ff;fill-opacity:1;stroke:none"
|
||||
inkscape:connector-curvature="0"
|
||||
id="path9"
|
||||
d="M 48.464084,21.400659 V 14.532532 L 28.981398,25.698341 48.464084,36.86415 v -6.867489 c 11.042093,0 20.024317,8.91683 20.024317,19.877897 0,10.509484 -8.258763,19.134189 -18.671845,19.828145 v 8.611948 c 15.190751,-0.703524 27.330245,-13.189635 27.330245,-28.440093 0,-15.700763 -12.86681,-28.473899 -28.682717,-28.473899 z" /></g><g
|
||||
id="g4513"
|
||||
transform="translate(0,-2)"><rect
|
||||
y="32.516129"
|
||||
x="42"
|
||||
height="15.612903"
|
||||
width="7.9999986"
|
||||
id="rect4494"
|
||||
style="fill:#ff00f7;fill-opacity:1;stroke:#ffffed;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:6.04534006;stroke-opacity:1" /><rect
|
||||
transform="rotate(120)"
|
||||
y="-76.050484"
|
||||
x="12.680965"
|
||||
height="15.612903"
|
||||
width="7.9999986"
|
||||
id="rect4494-7"
|
||||
style="fill:#ff00f7;fill-opacity:1;stroke:#ffffed;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:6.04534006;stroke-opacity:1" /></g></svg>
|
After Width: | Height: | Size: 3.7 KiB |
64
misc/icons/source/common-warning-red.svg
Normal file
@ -0,0 +1,64 @@
|
||||
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
|
||||
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
|
||||
|
||||
<svg
|
||||
xmlns:dc="http://purl.org/dc/elements/1.1/"
|
||||
xmlns:cc="http://creativecommons.org/ns#"
|
||||
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
|
||||
xmlns:svg="http://www.w3.org/2000/svg"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
|
||||
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
|
||||
version="1.1"
|
||||
id="Layer_1"
|
||||
x="0px"
|
||||
y="0px"
|
||||
width="42"
|
||||
height="42"
|
||||
viewBox="0 0 41.999999 41.999999"
|
||||
enable-background="new 0 0 99.997 69.373"
|
||||
xml:space="preserve"
|
||||
inkscape:version="0.48.4 r9939"
|
||||
sodipodi:docname="common-warning-red.svg"
|
||||
inkscape:export-filename="C:\Development\git\piskel\misc\icons\source\tool-move.png"
|
||||
inkscape:export-xdpi="45"
|
||||
inkscape:export-ydpi="45"><metadata
|
||||
id="metadata9"><rdf:RDF><cc:Work
|
||||
rdf:about=""><dc:format>image/svg+xml</dc:format><dc:type
|
||||
rdf:resource="http://purl.org/dc/dcmitype/StillImage" /><dc:title></dc:title></cc:Work></rdf:RDF></metadata><defs
|
||||
id="defs7" /><sodipodi:namedview
|
||||
pagecolor="#ffffff"
|
||||
bordercolor="#666666"
|
||||
borderopacity="1"
|
||||
objecttolerance="10"
|
||||
gridtolerance="10"
|
||||
guidetolerance="10"
|
||||
inkscape:pageopacity="0"
|
||||
inkscape:pageshadow="2"
|
||||
inkscape:window-width="1920"
|
||||
inkscape:window-height="1148"
|
||||
id="namedview5"
|
||||
showgrid="false"
|
||||
inkscape:zoom="4"
|
||||
inkscape:cx="85.612634"
|
||||
inkscape:cy="3.0742543"
|
||||
inkscape:window-x="-8"
|
||||
inkscape:window-y="-8"
|
||||
inkscape:window-maximized="1"
|
||||
inkscape:current-layer="Layer_1" />
|
||||
|
||||
<path
|
||||
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
d="m 21,4.2499995 c -0.868171,0 -1.517453,0.2705716 -2,1.03125 L 3.9999999,34.999999 c -0.6703157,1.211185 0.6156981,2.999959 2,3 l 29.9999991,0 c 1.377219,0.0098 2.645421,-1.78334 2,-3 l -15,-29.6874995 C 22.632848,4.6114627 21.868171,4.2499995 21,4.2499995 z m 0,6.2187495 11.999999,23.53125 -23.9999992,0 z"
|
||||
id="rect3765"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="zcccccczcccc" /><path
|
||||
style="font-size:medium;font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;text-indent:0;text-align:start;text-decoration:none;line-height:normal;letter-spacing:normal;word-spacing:normal;text-transform:none;direction:ltr;block-progression:tb;writing-mode:lr-tb;text-anchor:start;baseline-shift:baseline;color:#000000;fill:#ff0000;fill-opacity:1;fill-rule:nonzero;stroke:none;stroke-width:4;marker:none;visibility:visible;display:inline;overflow:visible;enable-background:accumulate;font-family:Sans;-inkscape-font-specification:Sans"
|
||||
d="m 20.572432,16.003047 c -0.858253,0.109012 -1.577503,1.040604 -1.572402,2.036618 L 20,25.963381 c 9.2e-5,1.066342 -0.158856,2.036512 0.765534,2.036618 l 0.468961,0 c 0.92439,-1.06e-4 0.765412,-0.970276 0.765504,-2.036618 l 1,-7.923716 c -9.2e-5,-1.066342 -0.841114,-2.036512 -1.765504,-2.036618 l -0.468961,0 c -0.0643,-0.0041 -0.128799,-0.0041 -0.193102,0 z"
|
||||
id="rect3772"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="cccccccccc" /><path
|
||||
style="fill:#ff0000;fill-opacity:1;stroke:#00ffff;stroke-width:0;stroke-linecap:butt;stroke-linejoin:round;stroke-miterlimit:4;stroke-opacity:1;stroke-dashoffset:1.60000000000000010"
|
||||
d="m 20.999298,29.000086 c 0.620953,-0.006 0.971639,0.298697 0.999273,1.499911 0.02763,1.201212 -0.347092,1.493936 -0.999273,1.499909 -0.65218,0.006 -1.002864,-0.275261 -0.999271,-1.499909 0.0036,-1.22465 0.378318,-1.493938 0.999271,-1.499911 z"
|
||||
inkscape:connector-curvature="0"
|
||||
sodipodi:nodetypes="zzzzz" /></svg>
|
After Width: | Height: | Size: 4.1 KiB |
@ -1,21 +0,0 @@
|
||||
@ECHO off
|
||||
|
||||
SETLOCAL
|
||||
|
||||
SET PISKEL_PATH="C:\Development\git\piskel"
|
||||
SET PISKELAPP_PATH="C:\Development\git\piskel-website"
|
||||
|
||||
ECHO "Copying files to piskelapp"
|
||||
XCOPY "%PISKEL_PATH%\dest\prod" "%PISKELAPP_PATH%\static\editor" /e /i /h /y
|
||||
|
||||
ECHO "Delete previous partial"
|
||||
DEL "%PISKELAPP_PATH%\templates\editor\main-partial.html"
|
||||
ECHO "Copy new partial"
|
||||
MOVE "%PISKELAPP_PATH%\static\editor\piskelapp-partials\main-partial.html" "%PISKELAPP_PATH%\templates\editor"
|
||||
ECHO "Delete temp partial"
|
||||
RMDIR "%PISKELAPP_PATH%\static\editor\piskelapp-partials\" /S /Q
|
||||
|
||||
PAUSE
|
||||
explorer "%PISKELAPP_PATH%\"
|
||||
|
||||
ENDLOCAL
|
52
package.json
@ -1,63 +1,71 @@
|
||||
{
|
||||
"name": "piskel",
|
||||
"version": "0.8.3",
|
||||
"version": "0.15.0",
|
||||
"description": "Pixel art editor",
|
||||
"author": "Julian Descottes <julian.descottes@gmail.com>",
|
||||
"contributors": [
|
||||
"Vincent Renaudin"
|
||||
],
|
||||
"homepage": "http://github.com/juliandescottes/piskel",
|
||||
"homepage": "http://github.com/piskelapp/piskel",
|
||||
"license": "Apache-2.0",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "http://github.com/juliandescottes/piskel.git"
|
||||
"url": "http://github.com/piskelapp/piskel.git"
|
||||
},
|
||||
"files": [
|
||||
"dest/prod",
|
||||
"misc/scripts/piskel-root"
|
||||
],
|
||||
"bin": {
|
||||
"piskel-root": "./misc/scripts/piskel-root"
|
||||
"piskel-root": "./misc/scripts/piskel-root",
|
||||
"piskel-cli": "./cli/index.js"
|
||||
},
|
||||
"main": "./dest/prod/index.html",
|
||||
"scripts": {
|
||||
"test": "grunt test",
|
||||
"start": "nodewebkit",
|
||||
"preversion": "grunt test-local build",
|
||||
"postversion": "git push && git push --tags && npm publish"
|
||||
"preversion": "grunt test build",
|
||||
"postversion": "git push && git push --tags && npm publish",
|
||||
"release": "grunt && node ./bin/copy-to-piskel-website"
|
||||
},
|
||||
"devDependencies": {
|
||||
"dateformat": "1.0.11",
|
||||
"grunt": "^0.4.5",
|
||||
"grunt-contrib-clean": "1.0.0",
|
||||
"dateformat": "2.0.0",
|
||||
"fs-extra": "3.0.1",
|
||||
"grunt": "0.4.5",
|
||||
"grunt-casperjs": "^2.2.1",
|
||||
"grunt-contrib-clean": "1.1.0",
|
||||
"grunt-contrib-concat": "1.0.1",
|
||||
"grunt-contrib-connect": "1.0.2",
|
||||
"grunt-contrib-copy": "1.0.0",
|
||||
"grunt-contrib-jshint": "1.0.0",
|
||||
"grunt-contrib-uglify": "1.0.1",
|
||||
"grunt-contrib-jshint": "1.1.0",
|
||||
"grunt-contrib-uglify": "2.3.0",
|
||||
"grunt-contrib-watch": "1.0.0",
|
||||
"grunt-ghost": "1.1.0",
|
||||
"grunt-eslint": "^19.0.0",
|
||||
"grunt-include-replace": "4.0.1",
|
||||
"grunt-jscs": "2.8.0",
|
||||
"grunt-karma": "1.0.0",
|
||||
"grunt-leading-indent": "0.2.0",
|
||||
"grunt-nw-builder": "2.0.3",
|
||||
"grunt-open": "0.2.3",
|
||||
"grunt-nw-builder": "3.1.0",
|
||||
"grunt-replace": "1.0.1",
|
||||
"grunt-spritesmith": "6.3.0",
|
||||
"jasmine-core": "2.1.0",
|
||||
"karma": "0.13.21",
|
||||
"karma-chrome-launcher": "1.0.1",
|
||||
"karma-jasmine": "1.0.2",
|
||||
"karma-phantomjs-launcher": "0.2.3",
|
||||
"grunt-spritesmith": "6.4.0",
|
||||
"jasmine-core": "2.6.1",
|
||||
"karma": "1.7.0",
|
||||
"karma-jasmine": "1.1.0",
|
||||
"karma-phantomjs-launcher": "1.0.4",
|
||||
"load-grunt-tasks": "3.5.0",
|
||||
"phantomjs": "1.9.19"
|
||||
"phantomjs": "2.1.7",
|
||||
"phantomjs-polyfill-object-assign": "0.0.2",
|
||||
"promise-polyfill": "6.0.2",
|
||||
"rmdir": "1.2.0"
|
||||
},
|
||||
"window": {
|
||||
"title": "Piskel",
|
||||
"icon": "dest/prod/logo.png",
|
||||
"toolbar": false,
|
||||
"width": 1000,
|
||||
"height": 500
|
||||
"height": 700
|
||||
},
|
||||
"dependencies": {
|
||||
"minimist": "^1.2.0"
|
||||
}
|
||||
}
|
||||
|
@ -1,3 +1,9 @@
|
||||
@keyframes fade {
|
||||
50% { opacity: 0.5; }
|
||||
}
|
||||
|
||||
@keyframes glow {
|
||||
0% { opacity: 0.66; }
|
||||
50% { opacity: 1; }
|
||||
100% { opacity: 0.66; }
|
||||
}
|
||||
|
152
src/css/dialogs-browse-backups.css
Normal file
@ -0,0 +1,152 @@
|
||||
#dialog-container.browse-backups {
|
||||
width: 700px;
|
||||
height: 500px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
margin-left: -350px;
|
||||
}
|
||||
|
||||
.backups-step-container {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.backups-step-content {
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
flex-grow: 1;
|
||||
background: #444;
|
||||
|
||||
padding: 20px;
|
||||
overflow: auto;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.backups-step-actions {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
height: 60px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
padding: 0 20px;
|
||||
}
|
||||
|
||||
.show #dialog-container.browse-backups {
|
||||
margin-top: -250px;
|
||||
}
|
||||
|
||||
.browse-backups .browse-backups-disclaimer {
|
||||
display: flex;
|
||||
margin-bottom: 20px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.browse-backups .browse-backups-disclaimer-content {
|
||||
padding: 0 20px;
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.browse-backups .browse-backups-disclaimer .backups-icon {
|
||||
border: 1px solid gold;
|
||||
flex-shrink: 0;
|
||||
width: 90px;
|
||||
height: 90px;
|
||||
}
|
||||
|
||||
.browse-backups .centered-message {
|
||||
position: absolute;
|
||||
left: 50%;
|
||||
width: 200px;
|
||||
margin-top: 100px;
|
||||
margin-left: -130px;
|
||||
padding: 30px;
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
/* Hide and slide up next sessions when deleting an item */
|
||||
.browse-backups .session-item.deleting {
|
||||
opacity: 0;
|
||||
margin-bottom: -60px;
|
||||
}
|
||||
|
||||
.browse-backups .session-item,
|
||||
.browse-backups .snapshot-item {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
width: 100%;
|
||||
height: 80px;
|
||||
|
||||
margin-bottom: 10px;
|
||||
padding: 0 20px;
|
||||
|
||||
border: 1px solid #666;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.browse-backups .snapshot-preview {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
/* Keep synced with SessionDetails.PREVIEW_SIZE */
|
||||
height: 60px;
|
||||
width: 60px;
|
||||
margin-right: 20px;
|
||||
}
|
||||
|
||||
.browse-backups .session-details,
|
||||
.browse-backups .snapshot-details {
|
||||
flex-grow: 1;
|
||||
flex-shrink: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
.browse-backups .session-details-title,
|
||||
.browse-backups .snapshot-details-title {
|
||||
font-size: 13px;
|
||||
}
|
||||
|
||||
.browse-backups .session-details-info,
|
||||
.browse-backups .snapshot-details-info {
|
||||
font-size: 11px;
|
||||
color: #bbb;
|
||||
line-height: 1.5em;
|
||||
}
|
||||
|
||||
.browse-backups .session-actions,
|
||||
.browse-backups .snapshot-actions {
|
||||
flex-grow: 0;
|
||||
flex-shrink: 1;
|
||||
display: flex;
|
||||
}
|
||||
|
||||
.browse-backups .session-actions button,
|
||||
.browse-backups .snapshot-actions button {
|
||||
margin-left: 10px;
|
||||
}
|
||||
|
||||
.browse-backups .session-item:last-child,
|
||||
.browse-backups .snapshot-item:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
@ -3,6 +3,19 @@
|
||||
/* Browse local piskels panel */
|
||||
/************************************************************************************************/
|
||||
|
||||
#dialog-container.browse-local {
|
||||
width: 700px;
|
||||
height: 500px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
margin-left: -350px;
|
||||
}
|
||||
|
||||
.show #dialog-container.browse-local {
|
||||
margin-top: -250px;
|
||||
}
|
||||
|
||||
.local-piskel-list {
|
||||
width: 100%;
|
||||
}
|
||||
@ -29,7 +42,7 @@
|
||||
|
||||
.local-piskel-list-head {
|
||||
font-weight: bold;
|
||||
color: gold;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.local-piskel-load-button,
|
||||
|
@ -3,7 +3,7 @@
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
|
||||
color : gold;
|
||||
color : var(--highlight-color);
|
||||
font-weight: bold;
|
||||
font-size : 1.25em;
|
||||
line-height: 20px;
|
||||
@ -97,7 +97,7 @@
|
||||
border-radius: 2px;
|
||||
|
||||
text-align: center;
|
||||
font-family:Courier;
|
||||
font-family: monospace;
|
||||
font-weight: bold;
|
||||
font-size : 18px;
|
||||
color: white;
|
||||
@ -113,8 +113,8 @@
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut-editable .cheatsheet-key {
|
||||
border-color: gold;
|
||||
color: gold;
|
||||
border-color: var(--highlight-color);
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.cheatsheet-shortcut-editing .cheatsheet-key {
|
||||
@ -140,7 +140,7 @@
|
||||
padding : 10px;
|
||||
overflow: hidden;
|
||||
|
||||
background-color : gold;
|
||||
background-color : var(--highlight-color);
|
||||
}
|
||||
|
||||
.cheatsheet-helptext {
|
||||
|
@ -103,7 +103,7 @@
|
||||
transition : border-color 0.2s;
|
||||
}
|
||||
.create-palette-color:hover {
|
||||
border:1px solid gold;
|
||||
border:1px solid var(--highlight-color);
|
||||
}
|
||||
|
||||
.colors-list-drop-proxy {
|
||||
@ -111,17 +111,17 @@
|
||||
}
|
||||
|
||||
.create-palette-new-color {
|
||||
border:2px dotted gold;
|
||||
border:2px dotted var(--highlight-color);
|
||||
|
||||
border-radius: 2px;
|
||||
line-height: 40px;
|
||||
text-align: center;
|
||||
font-size: 20px;
|
||||
color: gold;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.create-palette-color.selected {
|
||||
border:2px solid gold;
|
||||
border:2px solid var(--highlight-color);
|
||||
}
|
||||
|
||||
.create-palette-remove-color {
|
||||
|
@ -1,101 +0,0 @@
|
||||
/************************************************************************************************/
|
||||
/* Import dialog */
|
||||
/************************************************************************************************/
|
||||
|
||||
#dialog-container.import-image {
|
||||
width: 550px;
|
||||
height: 360px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
margin-left: -250px;
|
||||
}
|
||||
|
||||
.show #dialog-container.import-image {
|
||||
margin-top: -150px;
|
||||
}
|
||||
|
||||
.import-subsection {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.import-section:not(.import-subsection) > .dialog-section-title {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.import-section-preview-title {
|
||||
position: absolute;
|
||||
margin-left: 50%;
|
||||
margin-top: -28px;
|
||||
}
|
||||
|
||||
.import-section-preview {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border: 1px dashed #999;
|
||||
border-radius: 3px;
|
||||
margin-left: 50%;
|
||||
}
|
||||
|
||||
.import-section-preview img {
|
||||
max-width: 220px;
|
||||
max-height: 220px;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.import-section-preview.no-border {
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.import-section-preview canvas {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
.dialog-section-title {
|
||||
display : inline-block;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.dialog-section-radio {
|
||||
margin-top: 15px;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.import-size-field:nth-of-type(2) {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.import-image-file-name {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
|
||||
width: 200px;
|
||||
vertical-align: middle;
|
||||
|
||||
word-break : break-all;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
text-shadow: none;
|
||||
color: gold;
|
||||
}
|
||||
|
||||
[name=smooth-resize-checkbox] {
|
||||
margin : 0 8px;
|
||||
}
|
||||
|
||||
.dialog-import-body {
|
||||
padding: 10px 20px;
|
||||
font-size:1.3em
|
||||
}
|
||||
|
||||
.import-button {
|
||||
font-size: 1em;
|
||||
height: 28px;
|
||||
padding: 0px 10px;
|
||||
margin-top: 15px;
|
||||
}
|
288
src/css/dialogs-import.css
vendored
Normal file
@ -0,0 +1,288 @@
|
||||
#dialog-container.import {
|
||||
width: 500px;
|
||||
height: 350px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
margin-left: -250px;
|
||||
margin-top: -175px;
|
||||
}
|
||||
|
||||
.import .dialog-content {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
.import-step-container {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
box-sizing: border-box;
|
||||
box-shadow: 0 0 2px 0 rgba(0, 0, 0, 0.5);
|
||||
background: #444;
|
||||
}
|
||||
|
||||
.import-step-content {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.import-step-buttons {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.import-first-step .import-back-button {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* IMAGE IMPORT STEP
|
||||
*/
|
||||
|
||||
.import-image-container {
|
||||
padding: 10px;
|
||||
}
|
||||
|
||||
.import-image-loading {
|
||||
opacity: 0.3;
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.import-image-loading::after {
|
||||
content: 'loading image';
|
||||
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
top: 0;
|
||||
left: 0;
|
||||
margin-top: 110px;
|
||||
|
||||
text-align: center;
|
||||
font-size: 3em;
|
||||
color: white;
|
||||
text-shadow: 0 0 60px black;
|
||||
}
|
||||
|
||||
.import-subsection {
|
||||
margin-left: 25px;
|
||||
}
|
||||
|
||||
.import-section:not(.import-subsection) > .dialog-section-title {
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.import-section-preview-title {
|
||||
position: absolute;
|
||||
margin-left: 50%;
|
||||
margin-top: -28px;
|
||||
}
|
||||
|
||||
.import-section-preview {
|
||||
position: absolute;
|
||||
display: inline-block;
|
||||
border: 1px dashed #999;
|
||||
border-radius: 3px;
|
||||
margin-left: 50%;
|
||||
top: 10px;
|
||||
|
||||
width: 220px;
|
||||
height: 220px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.import-section-preview img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.import-section-preview canvas {
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.dialog-section-title {
|
||||
display : inline-block;
|
||||
width: 80px;
|
||||
}
|
||||
|
||||
.dialog-section-radio {
|
||||
margin-top: 15px;
|
||||
vertical-align: sub;
|
||||
}
|
||||
|
||||
.import-size-field:nth-of-type(2) {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
.import-image-file-name {
|
||||
display: inline-block;
|
||||
overflow: hidden;
|
||||
|
||||
width: 200px;
|
||||
vertical-align: middle;
|
||||
|
||||
word-break : break-all;
|
||||
white-space: nowrap;
|
||||
text-overflow: ellipsis;
|
||||
|
||||
font-style: italic;
|
||||
font-weight: normal;
|
||||
text-shadow: none;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
[name=smooth-resize-checkbox] {
|
||||
margin : 0 8px;
|
||||
}
|
||||
|
||||
.dialog-import-body {
|
||||
padding: 10px 20px;
|
||||
font-size:1.3em
|
||||
}
|
||||
|
||||
/**
|
||||
* SELECT MODE
|
||||
*/
|
||||
|
||||
.import-info {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
|
||||
height: 100%;
|
||||
max-width: 178px;
|
||||
box-sizing: border-box;
|
||||
|
||||
padding: 10px;
|
||||
border-right: 3px solid gold;
|
||||
}
|
||||
|
||||
.import-preview canvas {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.import-meta {
|
||||
margin-top: 10px;
|
||||
box-sizing: border-box;
|
||||
|
||||
/*center meta information horizontally*/
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
justify-content: center;
|
||||
}
|
||||
|
||||
.import-meta > div {
|
||||
height: 22px;
|
||||
display: flex;
|
||||
margin-bottom: 5px;
|
||||
}
|
||||
|
||||
.import-meta-value,
|
||||
.import-meta-label {
|
||||
padding: 2px 4px;
|
||||
}
|
||||
|
||||
.import-meta-label {
|
||||
border-radius: 2px 0 0 2px;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.import-meta-value {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.import-missing {
|
||||
text-align: center;
|
||||
line-height: 70px;
|
||||
font-style: italic;
|
||||
color: #aaa;
|
||||
}
|
||||
|
||||
.import-mode-title {
|
||||
margin-bottom: 10px
|
||||
}
|
||||
|
||||
.import-mode-section {
|
||||
display: flex;
|
||||
border: 3px solid #666;
|
||||
border-radius: 3px;
|
||||
padding: 10px;
|
||||
margin-bottom: 10px;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.import-mode-section .button {
|
||||
width: 75px;
|
||||
height: 30px;
|
||||
font-size: 14px;
|
||||
margin-left: 10px;
|
||||
|
||||
flex-grow: 0;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.import-mode-section-description {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
.import-resize-option,
|
||||
.insert-mode-option {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.import-resize-option :checked + span,
|
||||
.insert-mode-option :checked + span {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.import-resize-option input,
|
||||
.insert-mode-option input {
|
||||
margin: 5px;
|
||||
}
|
||||
|
||||
/**
|
||||
* ADJUST SIZE
|
||||
*/
|
||||
.import-resize-anchor-info {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.import-resize-section {
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.import-resize-anchor {
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.import-resize-option :checked + span {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.import-resize-warning {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* INSERT LOCATION
|
||||
*/
|
||||
|
||||
.insert-mode-container {
|
||||
margin-top: 20px;
|
||||
margin-bottom: 10px;
|
||||
}
|
||||
|
||||
.insert-frame-preview {
|
||||
margin: 10px 0;
|
||||
}
|
||||
|
||||
.insert-frame-preview .frame-picker-wrapper {
|
||||
height: 120px;
|
||||
}
|
68
src/css/dialogs-performance-info.css
Normal file
@ -0,0 +1,68 @@
|
||||
.performance-link {
|
||||
display: none;
|
||||
position: fixed;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
z-index: 11000;
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
transition : opacity 0.3s;
|
||||
}
|
||||
|
||||
.performance-link.visible {
|
||||
display: block;
|
||||
opacity: 0.66;
|
||||
animation: glow 2s infinite;
|
||||
}
|
||||
|
||||
.performance-link.visible:hover {
|
||||
opacity: 1;
|
||||
animation: none;
|
||||
}
|
||||
|
||||
#dialog-container.performance-info {
|
||||
width: 500px;
|
||||
height: 525px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
margin-left: -250px;
|
||||
margin-top: -260px;
|
||||
|
||||
}
|
||||
|
||||
.dialog-performance-info-body {
|
||||
font-size: 13px;
|
||||
letter-spacing: 1px;
|
||||
padding: 10px 20px;
|
||||
}
|
||||
|
||||
.dialog-performance-info-body ul {
|
||||
border: 1px solid #666;
|
||||
padding: 5px;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.dialog-performance-info-body li {
|
||||
list-style-type: initial;
|
||||
margin: 0 20px;
|
||||
}
|
||||
|
||||
.dialog-performance-info-body sup {
|
||||
color: var(--highlight-color);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.show #dialog-container.performance-info {
|
||||
margin-top: -300px;
|
||||
}
|
||||
|
||||
.dialog-performance-info-body .warning-icon {
|
||||
float: left;
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.dialog-performance-info-body .warning-icon-info {
|
||||
overflow: hidden;
|
||||
margin-left: 30px;
|
||||
}
|
32
src/css/dialogs-unsupported-browser.css
Normal file
@ -0,0 +1,32 @@
|
||||
/************************************************************************************************/
|
||||
/* Unsupported browser dialog */
|
||||
/************************************************************************************************/
|
||||
|
||||
#dialog-container.unsupported-browser {
|
||||
width: 600px;
|
||||
height: 260px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
margin-top: -130px;
|
||||
margin-left: -300px;
|
||||
}
|
||||
|
||||
.unsupported-browser .dialog-content {
|
||||
font-size:1.2em;
|
||||
letter-spacing: 1px;
|
||||
padding:10px 20px;
|
||||
overflow: auto;
|
||||
}
|
||||
|
||||
.unsupported-browser .supported-browser-list {
|
||||
padding: 5px 20px;
|
||||
}
|
||||
|
||||
.unsupported-browser .supported-browser-list li {
|
||||
list-style-type: square;
|
||||
}
|
||||
|
||||
#current-user-agent {
|
||||
color: var(--highlight-color);
|
||||
}
|
@ -39,7 +39,7 @@
|
||||
-moz-box-sizing : border-box;
|
||||
|
||||
border-radius: 3px;
|
||||
border : 3px solid gold;
|
||||
border : 3px solid var(--highlight-color);
|
||||
background: #444;
|
||||
overflow: auto;
|
||||
}
|
||||
@ -48,19 +48,6 @@
|
||||
margin-top: 0;
|
||||
}
|
||||
|
||||
#dialog-container.browse-local {
|
||||
width: 700px;
|
||||
height: 500px;
|
||||
top : 50%;
|
||||
left : 50%;
|
||||
position : absolute;
|
||||
margin-left: -350px;
|
||||
}
|
||||
|
||||
.show #dialog-container.browse-local {
|
||||
margin-top: -250px;
|
||||
}
|
||||
|
||||
.dialog-wrapper {
|
||||
height: 100%;
|
||||
position : relative;
|
||||
@ -76,7 +63,7 @@
|
||||
|
||||
.dialog-head {
|
||||
width: 100%;
|
||||
background: gold;
|
||||
background: var(--highlight-color);
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
color: black;
|
||||
|
@ -22,6 +22,11 @@
|
||||
background : #3a3a3a;
|
||||
}
|
||||
|
||||
.textfield:focus {
|
||||
border-color: var(--highlight-color);
|
||||
outline: none;
|
||||
}
|
||||
|
||||
.textfield-small {
|
||||
width : 50px;
|
||||
}
|
||||
@ -29,17 +34,13 @@
|
||||
.button {
|
||||
box-sizing: border-box;
|
||||
height: 24px;
|
||||
|
||||
background-color: #3f3f3f;
|
||||
border: 1px solid #333;
|
||||
border-top-color: #666;
|
||||
border-bottom-color: #222;
|
||||
|
||||
background-color: #666;
|
||||
border-style: none;
|
||||
border-radius: 2px;
|
||||
cursor: pointer;
|
||||
text-decoration: none;
|
||||
|
||||
color: white;
|
||||
text-shadow: 0 -1px 0 black;
|
||||
font-weight: bold;
|
||||
font-size: 1rem;
|
||||
text-align: center;
|
||||
@ -48,25 +49,17 @@
|
||||
}
|
||||
|
||||
.button:hover {
|
||||
text-decoration: none;
|
||||
background-color: #484848;
|
||||
color: gold;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.button-primary {
|
||||
background-color: rgb(255,215,0); /* gold */
|
||||
|
||||
border-color: rgb(179, 164, 0);
|
||||
border-top-color: white;
|
||||
border-bottom-color: rgb(151, 133, 0);
|
||||
|
||||
background-color: var(--highlight-color);
|
||||
color: black;
|
||||
text-shadow: 0 1px 0 #fff;
|
||||
}
|
||||
|
||||
.button-primary:hover {
|
||||
background-color: rgb(255,235,20);
|
||||
color: #333;
|
||||
background-color: white;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.button[disabled],
|
||||
@ -74,10 +67,6 @@
|
||||
cursor:default;
|
||||
background-color: #aaa;
|
||||
color: #777;
|
||||
text-shadow: 0 1px 0 #bbb;
|
||||
border-color: #666;
|
||||
border-top-color: #999;
|
||||
border-bottom-color: #555;
|
||||
}
|
||||
|
||||
.import-size-field,
|
||||
|
@ -54,6 +54,9 @@
|
||||
}
|
||||
|
||||
.add-frame-action {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
|
||||
margin-top: 8px;
|
||||
padding: 6px 0;
|
||||
overflow: hidden;
|
||||
@ -71,6 +74,7 @@
|
||||
.add-frame-action-icon {
|
||||
margin: 3px;
|
||||
float: left;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.add-frame-action .label {
|
||||
@ -79,7 +83,7 @@
|
||||
}
|
||||
|
||||
.add-frame-action:hover {
|
||||
border-color: gold;
|
||||
border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.preview-tile {
|
||||
@ -131,6 +135,11 @@
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.preview-tile .tile-overlay.tile-count.toggled {
|
||||
background-color: gold;
|
||||
color: black;
|
||||
}
|
||||
|
||||
.preview-tile .tile-overlay.delete-frame-action {
|
||||
top: 0;
|
||||
right: 0;
|
||||
@ -153,7 +162,7 @@
|
||||
}
|
||||
|
||||
.preview-tile.selected {
|
||||
border-color: gold;
|
||||
border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.preview-tile.selected:after {
|
||||
@ -162,7 +171,7 @@
|
||||
top: 38px;
|
||||
right: -9px;
|
||||
border: transparent 4px solid;
|
||||
border-left-color: gold;
|
||||
border-left-color: var(--highlight-color);
|
||||
border-width: 6px 0 6px 6px;
|
||||
border-style: solid;
|
||||
}
|
||||
@ -173,6 +182,6 @@
|
||||
*/
|
||||
|
||||
.preview-tile-drop-proxy {
|
||||
border: 3px dashed gold;
|
||||
border: 3px dashed var(--highlight-color);
|
||||
background-color: rgba(255, 215,0, 0.2);
|
||||
}
|
||||
|
@ -25,7 +25,7 @@
|
||||
.left-column {
|
||||
vertical-align: top;
|
||||
height: 100%;
|
||||
margin-right: 7px;
|
||||
padding-right: 7px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
@ -44,7 +44,8 @@
|
||||
flex-direction: column;
|
||||
position: relative;
|
||||
|
||||
margin-left: 10px;
|
||||
/* Keep in sync with Constants.RIGHT_COLUMN_PADDING_LEFT */
|
||||
padding-left: 10px;
|
||||
/* Add some padding for the absolutely positioned .cursor-coordinates */
|
||||
padding-bottom: 20px;
|
||||
}
|
||||
@ -80,10 +81,21 @@
|
||||
}
|
||||
|
||||
.cursor-coordinates {
|
||||
color:#888;
|
||||
font-size:12px;
|
||||
font-weight:bold;
|
||||
font-family:Courier;
|
||||
color: var(--highlight-color);
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
font-family: monospace;
|
||||
}
|
||||
|
||||
.cursor-coordinates .drawing-zoom {
|
||||
position: absolute;
|
||||
top: -20px;
|
||||
left: 1px;
|
||||
}
|
||||
|
||||
.cursor-coordinates .frame-info {
|
||||
line-height: 1.5;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -157,4 +169,4 @@
|
||||
.canvas.drawing-canvas {z-index: 8;}
|
||||
.canvas.canvas-overlay {z-index: 9;}
|
||||
.canvas.onion-skin-canvas {z-index: 10;}
|
||||
.canvas.layers-above-canvas {z-index: 11;}
|
||||
.canvas.layers-above-canvas {z-index: 11;}
|
||||
|
@ -1,8 +1,8 @@
|
||||
.minimap-crop-frame {
|
||||
position:absolute;
|
||||
border:1px solid rgba(255,255,255,0.5);
|
||||
z-index:100;
|
||||
box-sizing : border-box;
|
||||
-moz-box-sizing : border-box;
|
||||
cursor : pointer;
|
||||
position: absolute;
|
||||
border: 2px solid gold;
|
||||
z-index: 100;
|
||||
box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
cursor: pointer;
|
||||
}
|
@ -6,12 +6,12 @@
|
||||
max-width: 300px;
|
||||
|
||||
border-top-left-radius: 7px;
|
||||
border: #F0C36D 1px solid;
|
||||
border: #e1a325 2px solid;
|
||||
border-right: 0;
|
||||
border-bottom: 0;
|
||||
|
||||
color: #222;
|
||||
background-color: #F9EDBE;
|
||||
background-color: var(--highlight-color);
|
||||
|
||||
font-weight: bold;
|
||||
font-size: 13px;
|
||||
@ -24,8 +24,6 @@
|
||||
top: 6px;
|
||||
right: 17px;
|
||||
|
||||
color: gray;
|
||||
|
||||
font-size: 18px;
|
||||
font-weight: bold;
|
||||
|
||||
@ -43,7 +41,7 @@
|
||||
padding: 10px;
|
||||
width: 360px;
|
||||
border-top-right-radius: 2px;
|
||||
border: gold 2px solid;
|
||||
border: var(--highlight-color) 2px solid;
|
||||
border-left: 0;
|
||||
border-bottom: 0;
|
||||
background-color: #444;
|
||||
@ -69,6 +67,6 @@
|
||||
margin-top: 8px;
|
||||
height : 4px;
|
||||
width : 300px;
|
||||
background : linear-gradient(to left, gold, gold) no-repeat -300px 0;
|
||||
background : linear-gradient(to left, var(--highlight-color), var(--highlight-color)) no-repeat -300px 0;
|
||||
background-color : black;
|
||||
}
|
@ -1,49 +0,0 @@
|
||||
.pen-size-container {
|
||||
overflow: hidden;
|
||||
padding: 5px 5px;
|
||||
}
|
||||
|
||||
.pen-size-option {
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 2px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
border-color: #444;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.pen-size-option[data-size='1'] {
|
||||
padding: 6px;
|
||||
}
|
||||
.pen-size-option[data-size='2'] {
|
||||
padding: 5px;
|
||||
}
|
||||
.pen-size-option[data-size='3'] {
|
||||
padding: 4px;
|
||||
}
|
||||
.pen-size-option[data-size='4'] {
|
||||
padding: 3px;
|
||||
}
|
||||
|
||||
.pen-size-option:before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.pen-size-option:hover {
|
||||
border-color: #888;
|
||||
}
|
||||
|
||||
.pen-size-option.selected:before {
|
||||
background-color: gold;
|
||||
}
|
||||
|
||||
.pen-size-option.selected {
|
||||
border-color: gold;
|
||||
}
|
@ -5,6 +5,7 @@ html, body {
|
||||
cursor : default;
|
||||
font-family: Arial;
|
||||
font-size: 11px;
|
||||
line-height: 1.1;
|
||||
-webkit-touch-callout: none;
|
||||
-webkit-user-select: none;
|
||||
-khtml-user-select: none;
|
||||
@ -47,5 +48,5 @@ input[type="range"] {
|
||||
}
|
||||
|
||||
a, a:visited {
|
||||
color:gold;
|
||||
color: var(--highlight-color);
|
||||
}
|
@ -1,6 +1,14 @@
|
||||
/*******************************/
|
||||
/* Application Setting panel */
|
||||
/*******************************/
|
||||
/********************************/
|
||||
/* Preferences Settings panel */
|
||||
/********************************/
|
||||
|
||||
.settings-section-preferences {
|
||||
height: 100%;
|
||||
position: relative;
|
||||
overflow: hidden;
|
||||
margin: 0 20px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.background-picker-wrapper {
|
||||
display: inline-block;
|
||||
@ -27,16 +35,20 @@
|
||||
}
|
||||
|
||||
.background-picker.selected {
|
||||
border-color: gold;
|
||||
border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.layer-opacity-input {
|
||||
.settings-opacity-input {
|
||||
margin: 5px;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.layer-opacity-input,
|
||||
.tile-mask-opacity-input {
|
||||
width: 100px;
|
||||
}
|
||||
|
||||
.layer-opacity-text {
|
||||
.settings-opacity-text {
|
||||
height: 31px;
|
||||
display: inline-block;
|
||||
line-height: 30px;
|
||||
@ -47,11 +59,102 @@
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.grid-width-select {
|
||||
.settings-item-grid-size,
|
||||
.settings-item-grid-spacing,
|
||||
.settings-item-grid-color {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.settings-item-grid-size > label,
|
||||
.settings-item-grid-spacing > label,
|
||||
.settings-item-grid-color > label {
|
||||
width: 65px;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.grid-spacing-container .size-picker-option[data-size='1'] {
|
||||
padding: 7px;
|
||||
}
|
||||
.grid-spacing-container .size-picker-option[data-size='2'] {
|
||||
padding: 6px;
|
||||
}
|
||||
.grid-spacing-container .size-picker-option[data-size='4'] {
|
||||
padding: 5px;
|
||||
}
|
||||
.grid-spacing-container .size-picker-option[data-size='8'] {
|
||||
padding: 4px;
|
||||
}
|
||||
.grid-spacing-container .size-picker-option[data-size='16'] {
|
||||
padding: 3px;
|
||||
}
|
||||
.grid-spacing-container .size-picker-option[data-size='32'] {
|
||||
padding: 2px;
|
||||
}
|
||||
.grid-spacing-container .size-picker-option[data-size='64'] {
|
||||
padding: 1px;
|
||||
}
|
||||
|
||||
.settings-item-grid-size .size-picker-option,
|
||||
.settings-item-grid-spacing .size-picker-option {
|
||||
border-color: #888;
|
||||
}
|
||||
|
||||
.settings-item-grid-size .size-picker-option:not(.selected):hover,
|
||||
.settings-item-grid-spacing .size-picker-option:not(.selected):hover {
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.grid-width-select,
|
||||
.color-format-select {
|
||||
margin: 5px 5px 0 5px;
|
||||
}
|
||||
|
||||
.settings-section-application > .settings-title {
|
||||
|
||||
.grid-colors-list {
|
||||
overflow: hidden;
|
||||
padding: 0 5px;
|
||||
}
|
||||
|
||||
.grid-colors-item {
|
||||
float: left;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
cursor: pointer;
|
||||
border: 2px solid #888;
|
||||
margin-right: 2px;
|
||||
margin-bottom: 2px;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.grid-colors-item:hover {
|
||||
border-color: white;
|
||||
}
|
||||
|
||||
.grid-colors-item.selected {
|
||||
border-color: gold;
|
||||
}
|
||||
|
||||
.settings-section-preferences > .settings-title {
|
||||
/* Override the default 10px margin bottom for this panel */
|
||||
margin-bottom: 15px;
|
||||
}
|
||||
|
||||
.settings-section-preferences .button-primary {
|
||||
margin-top: 10px;
|
||||
}
|
||||
|
||||
.settings-version-info {
|
||||
position: absolute;
|
||||
bottom: 10px;
|
||||
right: 10px;
|
||||
color: #888;
|
||||
}
|
||||
|
||||
/* Override default link styles for the release notes link
|
||||
It doesn't need to popout too much */
|
||||
.settings-version,
|
||||
.settings-version:hover {
|
||||
color: white !important;
|
||||
text-decoration: none !important;
|
||||
}
|
||||
|
@ -43,8 +43,29 @@
|
||||
float : left;
|
||||
}
|
||||
|
||||
.gif-export-warning {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.gif-export-warning.visible {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
border: 1px solid red;
|
||||
padding: 5px;
|
||||
margin: 5px 0;
|
||||
}
|
||||
|
||||
.gif-export-warning-icon {
|
||||
flex-shrink: 0;
|
||||
margin-right: 5px;
|
||||
}
|
||||
|
||||
.gif-export-warning-message {
|
||||
font-weight: normal;
|
||||
}
|
||||
|
||||
.preview-upload-ongoing:before{
|
||||
content: "Upload ongoing ...";
|
||||
content: "Upload in progress...";
|
||||
position: absolute;
|
||||
display: block;
|
||||
height: 100%;
|
||||
@ -100,43 +121,6 @@
|
||||
line-height: 23px;
|
||||
}
|
||||
|
||||
.export-tabs {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.export-tabs:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
z-index: 0;
|
||||
background-color: gold;
|
||||
}
|
||||
|
||||
.export-tab {
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
border: 1px solid transparent;
|
||||
/* Make sure the tab and its border are positioned above the :after element; */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.export-tab.selected,
|
||||
.export-tab:hover {
|
||||
color: gold;
|
||||
}
|
||||
|
||||
.export-tab.selected {
|
||||
border-color: gold gold #444 gold;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
||||
|
||||
.export-panel-header {
|
||||
padding: 10px 5px 0px;
|
||||
}
|
||||
@ -160,7 +144,8 @@
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.export-panel-gif .button {
|
||||
.export-panel-gif .button,
|
||||
.export-panel-png .button {
|
||||
margin-right: 5px;
|
||||
width: 75px;
|
||||
flex-shrink: 0;
|
||||
@ -170,11 +155,6 @@
|
||||
width: 50px;
|
||||
}
|
||||
|
||||
.png-export-dimension-info,
|
||||
.png-export-datauri-info {
|
||||
margin-left: 5px;
|
||||
}
|
||||
|
||||
#png-export-columns,
|
||||
#png-export-rows {
|
||||
/* Override default textfield padding-right to keep the number spinners
|
||||
|
@ -5,103 +5,8 @@
|
||||
width: 25%;
|
||||
}
|
||||
|
||||
/*****************/
|
||||
/* ANCHOR WIDGET */
|
||||
/*****************/
|
||||
|
||||
.resize-origin-container {
|
||||
overflow: hidden;
|
||||
.resize-anchor-container {
|
||||
position: relative;
|
||||
width: 70px;
|
||||
margin-top: 5px;
|
||||
display: inline-block;
|
||||
}
|
||||
|
||||
.transition .resize-origin-option,
|
||||
.transition .resize-origin-option:before {
|
||||
transition: background-color 0.2s, border-color 0.2s;
|
||||
}
|
||||
|
||||
.resize-origin-option {
|
||||
float: left;
|
||||
position: relative;
|
||||
|
||||
box-sizing: border-box;
|
||||
margin: 0 1px 1px 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
background : #888;
|
||||
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.disabled .resize-origin-option {
|
||||
cursor: default;
|
||||
background : #555;
|
||||
border-color: #555 !important;
|
||||
}
|
||||
|
||||
.resize-origin-option:hover {
|
||||
border : 3px solid white;
|
||||
}
|
||||
|
||||
.resize-origin-option.selected {
|
||||
border : 3px solid gold;
|
||||
}
|
||||
|
||||
.resize-origin-option:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -2px;
|
||||
}
|
||||
|
||||
.resize-origin-option.selected:before {
|
||||
content: '';
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: gold;
|
||||
}
|
||||
|
||||
.disabled .resize-origin-option.selected:before {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.disabled .resize-origin-option[data-neighbor]:before {
|
||||
border-color: #555 !important;
|
||||
}
|
||||
|
||||
.resize-origin-option[data-neighbor]:before {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-width: 4px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.resize-origin-option[data-neighbor="bottom"]:before {
|
||||
border-top-color: gold;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.resize-origin-option[data-neighbor="left"]:before {
|
||||
border-right-color: gold;
|
||||
margin-top: -4px;
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.resize-origin-option[data-neighbor="top"]:before {
|
||||
border-bottom-color: gold;
|
||||
margin-top: -6px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.resize-origin-option[data-neighbor="right"]:before {
|
||||
border-left-color: gold;
|
||||
margin-top: -4px;
|
||||
}
|
@ -24,3 +24,13 @@
|
||||
color: white;
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.save-status-warning-icon {
|
||||
float: left;
|
||||
margin-top: 5px;
|
||||
}
|
||||
|
||||
.save-status-warning-icon {
|
||||
overflow: hidden;
|
||||
padding-left: 10px;
|
||||
}
|
||||
|
@ -52,7 +52,7 @@
|
||||
background-color: #444;
|
||||
margin-right: 0;
|
||||
padding-right: 2px;
|
||||
border-left : 3px solid gold;
|
||||
border-left : 3px solid var(--highlight-color);
|
||||
}
|
||||
|
||||
/************************************************************************************************/
|
||||
@ -64,7 +64,6 @@
|
||||
font-size: 12px;
|
||||
font-weight: bold;
|
||||
color: #ccc;
|
||||
text-shadow: 1px 1px #000;
|
||||
}
|
||||
|
||||
.settings-section .button {
|
||||
@ -77,7 +76,7 @@
|
||||
text-transform: uppercase;
|
||||
border-bottom: 1px #aaa solid;
|
||||
padding-bottom: 5px;
|
||||
color: gold;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.settings-description {
|
||||
|
@ -100,8 +100,8 @@
|
||||
}
|
||||
|
||||
.sp-palette .sp-thumb-el.sp-thumb-active {
|
||||
border-color: gold;
|
||||
box-shadow: 0 0 0px 1px gold;
|
||||
border-color: var(--highlight-color);
|
||||
box-shadow: 0 0 0px 1px var(--highlight-color);
|
||||
}
|
||||
|
||||
.sp-input {
|
||||
@ -110,7 +110,7 @@
|
||||
background: #111;
|
||||
border-radius: 2px;
|
||||
color: #D3D3D3;
|
||||
font-family: Courier!important;
|
||||
font-family: monospace!important;
|
||||
}
|
||||
|
||||
.sp-input.sp-validation-error {
|
||||
|
@ -1,113 +0,0 @@
|
||||
/*
|
||||
Icon classes can be used entirely standalone. They are named after their original file names.
|
||||
|
||||
```html
|
||||
<!-- `display: block` sprite -->
|
||||
<div class="icon-home"></div>
|
||||
|
||||
<!-- `display: inline-block` sprite -->
|
||||
<img class="icon-home" />
|
||||
```
|
||||
*/
|
||||
.icon-cloud_export {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px -276px;
|
||||
width: 50px;
|
||||
height: 47px;
|
||||
}
|
||||
.icon-dragndrop {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -564px -173px;
|
||||
width: 48px;
|
||||
height: 48px;
|
||||
}
|
||||
.icon-duplicate {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px -369px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.icon-export {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -564px -225px;
|
||||
width: 43px;
|
||||
height: 42px;
|
||||
}
|
||||
.icon-favicon {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -582px -151px;
|
||||
width: 16px;
|
||||
height: 16px;
|
||||
}
|
||||
.icon-gallery {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px -225px;
|
||||
width: 52px;
|
||||
height: 51px;
|
||||
}
|
||||
.icon-garbage {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: 0px 0px;
|
||||
width: 512px;
|
||||
height: 512px;
|
||||
}
|
||||
.icon-gear {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -563px -323px;
|
||||
width: 38px;
|
||||
height: 37px;
|
||||
}
|
||||
.icon-import-icon {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -576px -69px;
|
||||
width: 28px;
|
||||
height: 36px;
|
||||
}
|
||||
.icon-keyboard {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px -133px;
|
||||
width: 70px;
|
||||
height: 40px;
|
||||
}
|
||||
.icon-local-storage-icon {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px 0px;
|
||||
width: 100px;
|
||||
height: 69px;
|
||||
}
|
||||
.icon-merge-icon {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px -69px;
|
||||
width: 64px;
|
||||
height: 64px;
|
||||
}
|
||||
.icon-plus {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px -323px;
|
||||
width: 51px;
|
||||
height: 46px;
|
||||
}
|
||||
.icon-popup-preview-arrow-gold {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -576px -105px;
|
||||
width: 24px;
|
||||
height: 18px;
|
||||
}
|
||||
.icon-popup-preview-arrow-white {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -582px -133px;
|
||||
width: 24px;
|
||||
height: 18px;
|
||||
}
|
||||
.icon-resize-icon {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -512px -173px;
|
||||
width: 52px;
|
||||
height: 52px;
|
||||
}
|
||||
.icon-save {
|
||||
background-image: url(../img/spritesheet.png);
|
||||
background-position: -562px -276px;
|
||||
width: 43px;
|
||||
height: 42px;
|
||||
}
|
@ -17,11 +17,11 @@ body {
|
||||
}
|
||||
|
||||
.no-overflow {
|
||||
overflow : hidden;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.image-link {
|
||||
color : gold;
|
||||
.highlight {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.pull-top,
|
||||
@ -52,14 +52,23 @@ body {
|
||||
}
|
||||
|
||||
.checkbox-fix {
|
||||
margin-left: 0;
|
||||
margin: 3px 3px 3px 0;
|
||||
}
|
||||
|
||||
.checkbox-container {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
/**
|
||||
* TOOLTIPS
|
||||
*/
|
||||
.tooltip-shortcut {
|
||||
color:gold;
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.tooltip-container {
|
||||
|
@ -79,7 +79,7 @@
|
||||
|
||||
.preview-toggle-onion-skin-enabled,
|
||||
.preview-toggle-onion-skin-enabled:hover {
|
||||
color : gold;
|
||||
color : var(--highlight-color);
|
||||
}
|
||||
|
||||
.preview-contextual-actions {
|
||||
@ -98,7 +98,9 @@
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.original-size-button {
|
||||
.preview-contextual-action {
|
||||
float: left;
|
||||
|
||||
width : 18px;
|
||||
height: 18px;
|
||||
line-height: 18px;
|
||||
@ -113,28 +115,95 @@
|
||||
font-family: Tahoma;
|
||||
}
|
||||
|
||||
.original-size-button-enabled {
|
||||
color: gold;
|
||||
border-color: gold;
|
||||
.preview-contextual-action-hidden {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preview-contextual-action {
|
||||
float: left;
|
||||
.preview-contextual-action:hover {
|
||||
color: var(--highlight-color);
|
||||
border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* If the icon represents an enabled state, the border should always be gold.
|
||||
*/
|
||||
.preview-contextual-action-enabled {
|
||||
color: var(--highlight-color);
|
||||
border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* Drop-down in preview size selection
|
||||
*/
|
||||
.preview-drop-down {
|
||||
float: left;
|
||||
position: relative;
|
||||
width : 22px;
|
||||
min-height: 22px;
|
||||
margin: 0 5px;
|
||||
}
|
||||
|
||||
.preview-drop-down.preview-drop-down-disabled {
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.preview-disable-overlay{
|
||||
position: absolute;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: none;
|
||||
}
|
||||
|
||||
.preview-drop-down.preview-drop-down-disabled .preview-disable-overlay {
|
||||
display: block;
|
||||
z-index: 10;
|
||||
}
|
||||
|
||||
.preview-drop-down .preview-contextual-action {
|
||||
position: relative;
|
||||
margin: 0 0 -100% 0;
|
||||
opacity: 0;
|
||||
transition: opacity linear .2s,
|
||||
margin linear .2s;
|
||||
transition-delay: 0s, .2s;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.preview-drop-down:hover .preview-contextual-action {
|
||||
margin: 0 0 5px 0;
|
||||
opacity: 1;
|
||||
transition-delay: 0s, 0s;
|
||||
}
|
||||
|
||||
.preview-drop-down .size-button-selected {
|
||||
opacity: 1;
|
||||
color: gold;
|
||||
border-color: gold;
|
||||
z-index: 5;
|
||||
}
|
||||
|
||||
|
||||
.open-popup-preview-button {
|
||||
border : 2px solid white;
|
||||
background-color : rgba(0,0,0,0.3);
|
||||
}
|
||||
|
||||
.open-popup-preview-button:hover {
|
||||
border-color: gold;
|
||||
border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
* The regular image is provided bby the sprite icons.png+icons.css
|
||||
* The regular image is provided by the sprite icons.png+icons.css
|
||||
*/
|
||||
.icon-minimap-popup-preview-arrow-white:hover {
|
||||
background-image: url(../img/icons/minimap/minimap-popup-preview-arrow-gold.png);
|
||||
background-position: 0 0;
|
||||
background-size: 18px 18px;
|
||||
}
|
||||
|
||||
@media (-webkit-min-device-pixel-ratio: 2),
|
||||
(min-resolution: 192dpi) {
|
||||
.icon-minimap-popup-preview-arrow-white:hover {
|
||||
background-image: url(../img/icons/minimap/minimap-popup-preview-arrow-gold@2x.png);
|
||||
}
|
||||
}
|
||||
|
@ -35,7 +35,7 @@
|
||||
|
||||
.layers-toggle-preview-enabled,
|
||||
.layers-toggle-preview-enabled:hover {
|
||||
color : gold;
|
||||
color : var(--highlight-color);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -59,24 +59,40 @@
|
||||
|
||||
.layer-item {
|
||||
position: relative;
|
||||
display: flex;
|
||||
height:24px;
|
||||
line-height: 24px;
|
||||
padding: 0 0 0 10px;
|
||||
border-top: 1px solid #444;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.layer-item .layer-name,
|
||||
.layer-item .layer-name-input {
|
||||
padding: 0 0 0 10px;
|
||||
flex: 1 auto;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.layer-item .layer-name-input {
|
||||
width: 80%;
|
||||
}
|
||||
|
||||
.layer-item .layer-name.overflowing-name {
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.layer-item:hover {
|
||||
background : #222;
|
||||
}
|
||||
|
||||
.layer-item-opacity {
|
||||
position: absolute;
|
||||
right: 8px;
|
||||
padding: 0 8px 0 8px;
|
||||
flex: 0 auto;
|
||||
}
|
||||
|
||||
.current-layer-item,
|
||||
.current-layer-item:hover {
|
||||
background : #333;
|
||||
color: gold;
|
||||
color: var(--highlight-color);
|
||||
}
|
@ -76,6 +76,11 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.palettes-list-colors.tiny > .palettes-list-color {
|
||||
width: calc((100% - 35px) / 10);
|
||||
height: 16px;
|
||||
}
|
||||
|
||||
.palettes-list-color div {
|
||||
height: 100%;
|
||||
}
|
||||
@ -89,7 +94,7 @@
|
||||
line-height: 35px;
|
||||
width: 100%;
|
||||
color: gray;
|
||||
font-size: 0.7em;
|
||||
font-size: 0.8em;
|
||||
font-style: italic;
|
||||
text-align: center
|
||||
}
|
||||
@ -121,13 +126,14 @@
|
||||
* Color index for the 9 first colors
|
||||
*/
|
||||
|
||||
.palettes-list-color:nth-child(-n+10):after {
|
||||
:not(.tiny) > .palettes-list-color:nth-child(-n+10):after {
|
||||
content: attr(data-color-index);
|
||||
position: absolute;
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
background-color: black;
|
||||
color: gold;
|
||||
color: var(--highlight-color);
|
||||
|
||||
font-family: Tahoma;
|
||||
font-size: 0.5em;
|
||||
@ -136,39 +142,3 @@
|
||||
padding: 2px 3px 2px 3px;
|
||||
border-radius: 0 0 0 2px;
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(1):after {
|
||||
content: "1";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(2):after {
|
||||
content: "2";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(3):after {
|
||||
content: "3";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(4):after {
|
||||
content: "4";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(5):after {
|
||||
content: "5";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(6):after {
|
||||
content: "6";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(7):after {
|
||||
content: "7";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(8):after {
|
||||
content: "8";
|
||||
}
|
||||
|
||||
.palettes-list-color:nth-child(9):after {
|
||||
content: "9";
|
||||
}
|
||||
|
@ -26,7 +26,17 @@
|
||||
|
||||
.toolbox-buttons .button {
|
||||
/* Override border propery on .button elements from form.css */
|
||||
border-style: solid;
|
||||
border-color: #333;
|
||||
border-width: 0 1px 0 0;
|
||||
border-radius: 0;
|
||||
|
||||
background-color: #3f3f3f;
|
||||
}
|
||||
|
||||
.toolbox-buttons .button[disabled],
|
||||
.toolbox-buttons .button[disabled]:hover {
|
||||
background-color: #aaa;
|
||||
}
|
||||
|
||||
.toolbox-buttons button:last-child {
|
||||
|
@ -17,7 +17,7 @@
|
||||
position : absolute;
|
||||
height : 100%;
|
||||
width : 100%;
|
||||
border: 3px solid gold;
|
||||
border: 3px solid var(--highlight-color);
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
|
@ -3,5 +3,38 @@
|
||||
}
|
||||
|
||||
.transformations-container .tool-icon {
|
||||
float:left;
|
||||
margin: 0 0 5px 0;
|
||||
}
|
||||
|
||||
.transformations-container .tools-wrapper {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
height: 46px;
|
||||
|
||||
/* Override the float:left set on tools-wrapper in layout.css; */
|
||||
float: initial;
|
||||
}
|
||||
|
||||
.transformations-container.show-more .tools-wrapper {
|
||||
height: auto;
|
||||
/* Compensate the 5px bottom-margin coming from the tool-icon */
|
||||
margin-bottom: -5px;
|
||||
}
|
||||
|
||||
.transformations-show-more-link {
|
||||
position: absolute;
|
||||
color: #999;
|
||||
right: 10px;
|
||||
font-weight: normal;
|
||||
cursor: pointer;
|
||||
transition: 0.2s linear;
|
||||
}
|
||||
|
||||
.transformations-show-more-link:hover {
|
||||
color: white;
|
||||
}
|
||||
|
||||
.show-more .transformations-show-more-link {
|
||||
color: gold;
|
||||
}
|
3
src/css/variables.css
Normal file
@ -0,0 +1,3 @@
|
||||
html, body {
|
||||
--highlight-color: gold;
|
||||
}
|
98
src/css/widgets-anchor.css
Normal file
@ -0,0 +1,98 @@
|
||||
/*****************/
|
||||
/* ANCHOR WIDGET */
|
||||
/*****************/
|
||||
|
||||
.anchor-wrapper {
|
||||
overflow: hidden;
|
||||
width: 70px;
|
||||
}
|
||||
|
||||
/* When transitioning between enabled and disabled states */
|
||||
.transition .anchor-option,
|
||||
.transition .anchor-option:before {
|
||||
transition: background-color 0.2s, border-color 0.2s;
|
||||
}
|
||||
|
||||
.anchor-option {
|
||||
float: left;
|
||||
position: relative;
|
||||
|
||||
box-sizing: border-box;
|
||||
margin: 0 1px 1px 0;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
|
||||
background : #888;
|
||||
|
||||
font-size: 8px;
|
||||
text-align: center;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.disabled .anchor-option {
|
||||
cursor: default;
|
||||
background : #555;
|
||||
border-color: #555 !important;
|
||||
}
|
||||
|
||||
.anchor-option:hover {
|
||||
border : 3px solid white;
|
||||
}
|
||||
|
||||
.anchor-option.selected {
|
||||
border : 3px solid var(--highlight-color);
|
||||
}
|
||||
|
||||
.anchor-option:before {
|
||||
content: '';
|
||||
position: absolute;
|
||||
display: block;
|
||||
top: 50%;
|
||||
left: 50%;
|
||||
margin: -2px;
|
||||
}
|
||||
|
||||
.anchor-option.selected:before {
|
||||
content: '';
|
||||
width: 4px;
|
||||
height: 4px;
|
||||
background: var(--highlight-color);
|
||||
}
|
||||
|
||||
.disabled .anchor-option.selected:before {
|
||||
background: #555;
|
||||
}
|
||||
|
||||
.disabled .anchor-option[data-neighbor]:before {
|
||||
border-color: #555 !important;
|
||||
}
|
||||
|
||||
.anchor-option[data-neighbor]:before {
|
||||
width: 0;
|
||||
height: 0;
|
||||
border-width: 4px;
|
||||
border-style: solid;
|
||||
border-color: transparent;
|
||||
}
|
||||
|
||||
.anchor-option[data-neighbor="bottom"]:before {
|
||||
border-top-color: var(--highlight-color);
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.anchor-option[data-neighbor="left"]:before {
|
||||
border-right-color: var(--highlight-color);
|
||||
margin-top: -4px;
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
.anchor-option[data-neighbor="top"]:before {
|
||||
border-bottom-color: var(--highlight-color);
|
||||
margin-top: -6px;
|
||||
margin-left: -4px;
|
||||
}
|
||||
|
||||
.anchor-option[data-neighbor="right"]:before {
|
||||
border-left-color: var(--highlight-color);
|
||||
margin-top: -4px;
|
||||
}
|
55
src/css/widgets-frame-picker.css
Normal file
@ -0,0 +1,55 @@
|
||||
/***********************/
|
||||
/* FRAME PICKER WIDGET */
|
||||
/***********************/
|
||||
|
||||
.frame-picker-wrapper {
|
||||
width: 150px;
|
||||
height: 150px;
|
||||
border: 3px solid #666;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.frame-viewer {
|
||||
width: 100%;
|
||||
height: calc(100% - 25px);
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
|
||||
}
|
||||
|
||||
.frame-viewer > canvas,
|
||||
.frame-viewer > img {
|
||||
max-width: 100%;
|
||||
max-height: 100%;
|
||||
}
|
||||
|
||||
.frame-nav {
|
||||
display: flex;
|
||||
width: 100%;
|
||||
height: 24px;
|
||||
border-top: 1px solid #666;
|
||||
}
|
||||
|
||||
.frame-nav .button {
|
||||
flex-shrink: 0;
|
||||
border-radius: 0;
|
||||
height: 24px;
|
||||
background-color: #3f3f3f;
|
||||
}
|
||||
|
||||
.frame-nav .button[disabled],
|
||||
.frame-nav .button[disabled]:hover {
|
||||
background-color: #aaa;
|
||||
}
|
||||
|
||||
.frame-nav .button + .button {
|
||||
border-left: 1px solid #333;
|
||||
}
|
||||
|
||||
.frame-nav-input {
|
||||
min-width: 1px;
|
||||
border-style: none;
|
||||
height: 24px;
|
||||
text-align: center;
|
||||
}
|
61
src/css/widgets-size-picker.css
Normal file
@ -0,0 +1,61 @@
|
||||
/***********************/
|
||||
/* SIZE PICKER WIDGET */
|
||||
/***********************/
|
||||
|
||||
.size-picker-container {
|
||||
overflow: hidden;
|
||||
padding: 5px 5px;
|
||||
}
|
||||
|
||||
.size-picker-option {
|
||||
float: left;
|
||||
box-sizing: border-box;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
margin-right: 2px;
|
||||
border-style: solid;
|
||||
border-width: 2px;
|
||||
border-color: #444;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.size-picker-option[data-size='1'] {
|
||||
padding: 5px;
|
||||
}
|
||||
.size-picker-option[data-size='2'] {
|
||||
padding: 4px;
|
||||
}
|
||||
.size-picker-option[data-size='3'] {
|
||||
padding: 3px;
|
||||
}
|
||||
.size-picker-option[data-size='4'] {
|
||||
padding: 2px;
|
||||
}
|
||||
|
||||
.size-picker-option:before {
|
||||
content: '';
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background-color: white;
|
||||
display: block;
|
||||
text-align: center;
|
||||
line-height: 12px;
|
||||
font-size: 90%;
|
||||
}
|
||||
|
||||
.size-picker-option:hover {
|
||||
border-color: #888;
|
||||
}
|
||||
|
||||
.size-picker-option.selected:before {
|
||||
background-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.size-picker-option.selected {
|
||||
border-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.size-picker-option.labeled:before {
|
||||
content: attr(real-size);
|
||||
color: black;
|
||||
}
|
42
src/css/widgets-tabs.css
Normal file
@ -0,0 +1,42 @@
|
||||
/*****************/
|
||||
/* TABS WIDGET */
|
||||
/*****************/
|
||||
|
||||
.tab-list {
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.tab-list:after {
|
||||
content: "";
|
||||
display: block;
|
||||
position: absolute;
|
||||
bottom: 0;
|
||||
width: 100%;
|
||||
height: 1px;
|
||||
z-index: 0;
|
||||
background-color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.tab-item {
|
||||
float: left;
|
||||
cursor: pointer;
|
||||
padding: 5px;
|
||||
border: 1px solid transparent;
|
||||
border-radius: 2px 2px 0 0;
|
||||
/* Make sure the tab and its border are positioned above the :after element; */
|
||||
position: relative;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.tab-item.selected,
|
||||
.tab-item:hover {
|
||||
color: var(--highlight-color);
|
||||
}
|
||||
|
||||
.tab-item.selected {
|
||||
border-color: var(--highlight-color);
|
||||
border-bottom-color: #444;
|
||||
border-style: solid;
|
||||
border-width: 1px;
|
||||
}
|
32
src/css/widgets-wizard.css
Normal file
@ -0,0 +1,32 @@
|
||||
.wizard-wrapper {
|
||||
z-index: 1;
|
||||
position: relative;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.wizard-step {
|
||||
z-index: -1;
|
||||
margin-left: calc(100% + 5px);
|
||||
position: absolute;
|
||||
}
|
||||
|
||||
.current-step {
|
||||
z-index: 1;
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.current-step-in,
|
||||
.current-step-out {
|
||||
z-index: 10;
|
||||
transition: margin-left 200ms;
|
||||
}
|
||||
|
||||
.current-step-in {
|
||||
margin-left: 0;
|
||||
}
|
||||
|
||||
.current-step-out {
|
||||
margin-left: 100%;
|
||||
}
|
BIN
src/img/icons/common/common-backup-white.png
Normal file
After Width: | Height: | Size: 1.9 KiB |
BIN
src/img/icons/common/common-backup-white@2x.png
Normal file
After Width: | Height: | Size: 4.1 KiB |
BIN
src/img/icons/common/common-warning-red.png
Normal file
After Width: | Height: | Size: 446 B |
BIN
src/img/icons/common/common-warning-red@2x.png
Normal file
After Width: | Height: | Size: 851 B |
BIN
src/img/icons/minimap/minimap-grid-gold.png
Normal file
After Width: | Height: | Size: 135 B |
BIN
src/img/icons/minimap/minimap-grid-gold@2x.png
Normal file
After Width: | Height: | Size: 192 B |
BIN
src/img/icons/minimap/minimap-grid-white.png
Normal file
After Width: | Height: | Size: 135 B |
BIN
src/img/icons/minimap/minimap-grid-white@2x.png
Normal file
After Width: | Height: | Size: 186 B |
BIN
src/img/icons/transform/tool-crop.png
Normal file
After Width: | Height: | Size: 393 B |
BIN
src/img/icons/transform/tool-crop@2x.png
Normal file
After Width: | Height: | Size: 693 B |
Before Width: | Height: | Size: 24 KiB |
@ -22,9 +22,7 @@
|
||||
color:white;">
|
||||
<span style="top:45%">Loading Piskel ...</span>
|
||||
</div>
|
||||
<!--standalone-start-->
|
||||
@@include('templates/debug-header.html', {})
|
||||
<!--standalone-end-->
|
||||
|
||||
<!-- the comment below indicates the beginning of markup reused by the editor integrated in piskelapp.com -->
|
||||
<!-- do not delete, do not move :) -->
|
||||
@ -69,18 +67,28 @@
|
||||
</div>
|
||||
|
||||
@@include('templates/misc-templates.html', {})
|
||||
@@include('templates/data-uri-export.html', {})
|
||||
@@include('templates/popup-preview.html', {})
|
||||
|
||||
<span class="cheatsheet-link icon-common-keyboard-gold" rel="tooltip" data-placement="right" title="Keyboard shortcuts"> </span>
|
||||
<span class="cheatsheet-link icon-common-keyboard-gold"
|
||||
rel="tooltip" data-placement="right" title="Keyboard shortcuts"> </span>
|
||||
<div class="performance-link icon-common-warning-red"
|
||||
rel="tooltip" data-placement="left" title="Performance problem detected, learn more."> </div>
|
||||
|
||||
<!-- dialogs partials -->
|
||||
@@include('templates/dialogs/create-palette.html', {})
|
||||
@@include('templates/dialogs/import-image.html', {})
|
||||
@@include('templates/dialogs/browse-backups.html', {})
|
||||
@@include('templates/dialogs/browse-local.html', {})
|
||||
@@include('templates/dialogs/cheatsheet.html', {})
|
||||
@@include('templates/dialogs/create-palette.html', {})
|
||||
@@include('templates/dialogs/import.html', {})
|
||||
@@include('templates/dialogs/performance-info.html', {})
|
||||
@@include('templates/dialogs/unsupported-browser.html', {})
|
||||
|
||||
<!-- settings-panel partials -->
|
||||
@@include('templates/settings/application.html', {})
|
||||
@@include('templates/settings/preferences.html', {})
|
||||
@@include('templates/settings/preferences/grid.html', {})
|
||||
@@include('templates/settings/preferences/misc.html', {})
|
||||
@@include('templates/settings/preferences/tile.html', {})
|
||||
@@include('templates/settings/resize.html', {})
|
||||
@@include('templates/settings/save.html', {})
|
||||
@@include('templates/settings/import.html', {})
|
||||
|
99
src/js/.eslintrc
Normal file
@ -0,0 +1,99 @@
|
||||
{
|
||||
"env": {
|
||||
"es6": true,
|
||||
"browser": true
|
||||
},
|
||||
"globals": {
|
||||
"$": true,
|
||||
"jQuery": true,
|
||||
"pskl": true,
|
||||
"Events": true,
|
||||
"Constants": true,
|
||||
"console": true,
|
||||
"module": true,
|
||||
"require": true,
|
||||
"Q": true,
|
||||
"Promise": true
|
||||
},
|
||||
"rules": {
|
||||
"no-undef": 2,
|
||||
"no-use-before-define": [
|
||||
2,
|
||||
{
|
||||
"functions": false
|
||||
}
|
||||
],
|
||||
"curly": [
|
||||
2,
|
||||
"all"
|
||||
],
|
||||
"operator-linebreak": [
|
||||
2,
|
||||
"after"
|
||||
],
|
||||
"camelcase": [
|
||||
2,
|
||||
{
|
||||
"properties": "never"
|
||||
}
|
||||
],
|
||||
"max-len": [
|
||||
2,
|
||||
120
|
||||
],
|
||||
"indent": [
|
||||
2,
|
||||
2,
|
||||
{
|
||||
"SwitchCase": 1
|
||||
}
|
||||
],
|
||||
"quotes": [
|
||||
2,
|
||||
"single"
|
||||
],
|
||||
"no-multi-str": 2,
|
||||
"no-mixed-spaces-and-tabs": 2,
|
||||
"no-trailing-spaces": 2,
|
||||
"space-unary-ops": [
|
||||
2,
|
||||
{
|
||||
"nonwords": false,
|
||||
"overrides": {}
|
||||
}
|
||||
],
|
||||
"one-var": [
|
||||
2,
|
||||
"never"
|
||||
],
|
||||
"brace-style": [
|
||||
2,
|
||||
"1tbs",
|
||||
{
|
||||
"allowSingleLine": true
|
||||
}
|
||||
],
|
||||
"keyword-spacing": [
|
||||
2,
|
||||
{}
|
||||
],
|
||||
"space-infix-ops": 2,
|
||||
"space-before-blocks": [
|
||||
2,
|
||||
"always"
|
||||
],
|
||||
"eol-last": 2,
|
||||
"space-in-parens": [
|
||||
2,
|
||||
"never"
|
||||
],
|
||||
"no-multiple-empty-lines": 2,
|
||||
"no-with": 2,
|
||||
"no-spaced-func": 2,
|
||||
"dot-notation": 2,
|
||||
"semi": [
|
||||
2,
|
||||
"always"
|
||||
]
|
||||
}
|
||||
}
|
@ -12,14 +12,19 @@ var Constants = {
|
||||
MAX_HEIGHT : 1024,
|
||||
MAX_WIDTH : 1024,
|
||||
|
||||
MAX_PALETTE_COLORS : 100,
|
||||
MAX_PALETTE_COLORS : 256,
|
||||
// allow current colors service to get up to 256 colors.
|
||||
// GIF generation is different if the color count goes over 256.
|
||||
MAX_WORKER_COLORS : 256,
|
||||
|
||||
PREVIEW_FILM_SIZE : 96,
|
||||
ANIMATED_PREVIEW_WIDTH : 200,
|
||||
// Keep in sync with padding-left: 10px in layout.css
|
||||
RIGHT_COLUMN_PADDING_LEFT : 10,
|
||||
|
||||
DEFAULT_PEN_COLOR : '#000000',
|
||||
TRANSPARENT_COLOR : 'rgba(0, 0, 0, 0)',
|
||||
SEAMLESS_MODE_OVERLAY_COLOR : 'rgba(255, 255, 255, 0.5)',
|
||||
SEAMLESS_MODE_OVERLAY_COLOR : 'rgba(255, 255, 255, 0)',
|
||||
|
||||
CURRENT_COLORS_PALETTE_ID : '__current-colors',
|
||||
|
||||
@ -49,8 +54,17 @@ var Constants = {
|
||||
// TESTS
|
||||
DRAWING_TEST_FOLDER : 'drawing',
|
||||
|
||||
// Maximum size of a sprite that can be saved on piskelapp datastore.
|
||||
// This size will be compared to the length of the stringified serialization of the sprite.
|
||||
// This is an approximation at best but gives correct results in most cases.
|
||||
// The datastore limit is 1 MiB, which we roughly approximate to 1 million characters.
|
||||
APPENGINE_SAVE_LIMIT : 1 * 1024 * 1024,
|
||||
|
||||
// Message displayed when an action will lead to erase the current animation.
|
||||
CONFIRM_OVERWRITE: 'This will replace your current animation, are you sure you want to continue?',
|
||||
|
||||
// SERVICE URLS
|
||||
APPENGINE_SAVE_URL : 'save',
|
||||
IMAGE_SERVICE_UPLOAD_URL : 'http://piskel-imgstore-b.appspot.com/__/upload',
|
||||
IMAGE_SERVICE_GET_URL : 'http://piskel-imgstore-b.appspot.com/img/'
|
||||
IMAGE_SERVICE_UPLOAD_URL : '{{protocol}}://piskel-imgstore-b.appspot.com/__/upload',
|
||||
IMAGE_SERVICE_GET_URL : '{{protocol}}://piskel-imgstore-b.appspot.com/img/'
|
||||
};
|
||||
|
@ -15,7 +15,7 @@ var Events = {
|
||||
DRAG_START : 'DRAG_START',
|
||||
DRAG_END : 'DRAG_END',
|
||||
|
||||
DIALOG_DISPLAY : 'DIALOG_DISPLAY',
|
||||
DIALOG_SHOW : 'DIALOG_SHOW',
|
||||
DIALOG_HIDE : 'DIALOG_HIDE',
|
||||
|
||||
PALETTE_LIST_UPDATED : 'PALETTE_LIST_UPDATED',
|
||||
@ -59,13 +59,15 @@ var Events = {
|
||||
AFTER_SAVING_PISKEL: 'AFTER_SAVING_PISKEL',
|
||||
|
||||
FRAME_SIZE_CHANGED : 'FRAME_SIZE_CHANGED',
|
||||
FPS_CHANGED : 'FPS_CHANGED',
|
||||
|
||||
SELECTION_CREATED: 'SELECTION_CREATED',
|
||||
SELECTION_MOVE_REQUEST: 'SELECTION_MOVE_REQUEST',
|
||||
SELECTION_DISMISSED: 'SELECTION_DISMISSED',
|
||||
SELECTION_COPY: 'SELECTION_COPY',
|
||||
SELECTION_CUT: 'SELECTION_CUT',
|
||||
SELECTION_PASTE: 'SELECTION_PASTE',
|
||||
|
||||
CLIPBOARD_COPY: 'CLIPBOARD_COPY',
|
||||
CLIPBOARD_CUT: 'CLIPBOARD_CUT',
|
||||
CLIPBOARD_PASTE: 'CLIPBOARD_PASTE',
|
||||
|
||||
SHOW_NOTIFICATION: 'SHOW_NOTIFICATION',
|
||||
HIDE_NOTIFICATION: 'HIDE_NOTIFICATION',
|
||||
@ -79,6 +81,10 @@ var Events = {
|
||||
|
||||
CURRENT_COLORS_UPDATED : 'CURRENT_COLORS_UPDATED',
|
||||
|
||||
PERFORMANCE_REPORT_CHANGED : 'PERFORMANCE_REPORT_CHANGED',
|
||||
|
||||
PISKEL_FILE_IMPORT_FAILED : 'PISKEL_FILE_IMPORT_FAILED',
|
||||
|
||||
// Tests
|
||||
MOUSE_EVENT : 'MOUSE_EVENT',
|
||||
KEYBOARD_EVENT : 'KEYBOARD_EVENT',
|
||||
|
@ -15,12 +15,16 @@
|
||||
*/
|
||||
this.isAppEngineVersion = !!pskl.appEngineToken_;
|
||||
|
||||
// This id is used to keep track of sessions in the BackupService.
|
||||
this.sessionId = pskl.utils.Uuid.generate();
|
||||
|
||||
this.shortcutService = new pskl.service.keyboard.ShortcutService();
|
||||
this.shortcutService.init();
|
||||
|
||||
var size = pskl.UserSettings.get(pskl.UserSettings.DEFAULT_SIZE);
|
||||
var fps = Constants.DEFAULT.FPS;
|
||||
var descriptor = new pskl.model.piskel.Descriptor('New Piskel', '');
|
||||
var piskel = new pskl.model.Piskel(size.width, size.height, descriptor);
|
||||
var piskel = new pskl.model.Piskel(size.width, size.height, fps, descriptor);
|
||||
|
||||
var layer = new pskl.model.Layer('Layer 1');
|
||||
var frame = new pskl.model.Frame(size.width, size.height);
|
||||
@ -35,6 +39,8 @@
|
||||
this.piskelController.init();
|
||||
|
||||
this.paletteImportService = new pskl.service.palette.PaletteImportService();
|
||||
this.paletteImportService.init();
|
||||
|
||||
this.paletteService = new pskl.service.palette.PaletteService();
|
||||
this.paletteService.addDynamicPalette(new pskl.service.palette.CurrentColorsPalette());
|
||||
|
||||
@ -58,25 +64,24 @@
|
||||
|
||||
this.drawingController = new pskl.controller.DrawingController(
|
||||
this.piskelController,
|
||||
this.paletteController,
|
||||
$('#drawing-canvas-container'));
|
||||
document.querySelector('#drawing-canvas-container'));
|
||||
this.drawingController.init();
|
||||
|
||||
this.previewController = new pskl.controller.preview.PreviewController(
|
||||
this.piskelController,
|
||||
$('#animated-preview-canvas-container'));
|
||||
document.querySelector('#animated-preview-canvas-container'));
|
||||
this.previewController.init();
|
||||
|
||||
this.minimapController = new pskl.controller.MinimapController(
|
||||
this.piskelController,
|
||||
this.previewController,
|
||||
this.drawingController,
|
||||
$('.minimap-container'));
|
||||
document.querySelector('.minimap-container'));
|
||||
this.minimapController.init();
|
||||
|
||||
this.framesListController = new pskl.controller.FramesListController(
|
||||
this.piskelController,
|
||||
$('#preview-list'));
|
||||
document.querySelector('#preview-list-wrapper'));
|
||||
this.framesListController.init();
|
||||
|
||||
this.layersListController = new pskl.controller.LayersListController(this.piskelController);
|
||||
@ -94,7 +99,7 @@
|
||||
this.selectionManager = new pskl.selection.SelectionManager(this.piskelController);
|
||||
this.selectionManager.init();
|
||||
|
||||
this.historyService = new pskl.service.HistoryService(this.corePiskelController);
|
||||
this.historyService = new pskl.service.HistoryService(this.piskelController);
|
||||
this.historyService.init();
|
||||
|
||||
this.notificationController = new pskl.controller.NotificationController();
|
||||
@ -109,6 +114,9 @@
|
||||
this.canvasBackgroundController = new pskl.controller.CanvasBackgroundController();
|
||||
this.canvasBackgroundController.init();
|
||||
|
||||
this.indexedDbStorageService = new pskl.service.storage.IndexedDbStorageService(this.piskelController);
|
||||
this.indexedDbStorageService.init();
|
||||
|
||||
this.localStorageService = new pskl.service.storage.LocalStorageService(this.piskelController);
|
||||
this.localStorageService.init();
|
||||
|
||||
@ -124,12 +132,15 @@
|
||||
this.storageService = new pskl.service.storage.StorageService(this.piskelController);
|
||||
this.storageService.init();
|
||||
|
||||
this.importService = new pskl.service.ImportService(this.piskelController, this.previewController);
|
||||
this.importService = new pskl.service.ImportService(this.piskelController);
|
||||
this.importService.init();
|
||||
|
||||
this.imageUploadService = new pskl.service.ImageUploadService();
|
||||
this.imageUploadService.init();
|
||||
|
||||
this.savedStatusService = new pskl.service.SavedStatusService(this.piskelController, this.historyService);
|
||||
this.savedStatusService = new pskl.service.SavedStatusService(
|
||||
this.piskelController,
|
||||
this.historyService);
|
||||
this.savedStatusService.init();
|
||||
|
||||
this.backupService = new pskl.service.BackupService(this.piskelController);
|
||||
@ -138,7 +149,9 @@
|
||||
this.beforeUnloadService = new pskl.service.BeforeUnloadService(this.piskelController);
|
||||
this.beforeUnloadService.init();
|
||||
|
||||
this.headerController = new pskl.controller.HeaderController(this.piskelController, this.savedStatusService);
|
||||
this.headerController = new pskl.controller.HeaderController(
|
||||
this.piskelController,
|
||||
this.savedStatusService);
|
||||
this.headerController.init();
|
||||
|
||||
this.penSizeService = new pskl.service.pensize.PenSizeService();
|
||||
@ -147,20 +160,29 @@
|
||||
this.penSizeController = new pskl.controller.PenSizeController();
|
||||
this.penSizeController.init();
|
||||
|
||||
this.fileDropperService = new pskl.service.FileDropperService(
|
||||
this.piskelController,
|
||||
document.querySelector('#drawing-canvas-container'));
|
||||
this.fileDropperService = new pskl.service.FileDropperService(this.piskelController);
|
||||
this.fileDropperService.init();
|
||||
|
||||
var drawingLoop = new pskl.rendering.DrawingLoop();
|
||||
drawingLoop.addCallback(this.render, this);
|
||||
drawingLoop.start();
|
||||
this.userWarningController = new pskl.controller.UserWarningController(this.piskelController);
|
||||
this.userWarningController.init();
|
||||
|
||||
this.performanceReportService = new pskl.service.performance.PerformanceReportService(
|
||||
this.piskelController,
|
||||
this.currentColorsService);
|
||||
this.performanceReportService.init();
|
||||
|
||||
this.clipboardService = new pskl.service.ClipboardService(this.piskelController);
|
||||
this.clipboardService.init();
|
||||
|
||||
this.drawingLoop = new pskl.rendering.DrawingLoop();
|
||||
this.drawingLoop.addCallback(this.render, this);
|
||||
this.drawingLoop.start();
|
||||
|
||||
this.initTooltips_();
|
||||
|
||||
var piskelData = this.getPiskelInitData_();
|
||||
if (piskelData && piskelData.piskel) {
|
||||
this.loadPiskel_(piskelData.piskel, piskelData.descriptor, piskelData.fps);
|
||||
this.loadPiskel_(piskelData);
|
||||
}
|
||||
|
||||
if (pskl.devtools) {
|
||||
@ -173,13 +195,28 @@
|
||||
mb.createMacBuiltin('Piskel');
|
||||
gui.Window.get().menu = mb;
|
||||
}
|
||||
|
||||
if (!pskl.utils.Environment.isIntegrationTest() && pskl.utils.UserAgent.isUnsupported()) {
|
||||
$.publish(Events.DIALOG_SHOW, {
|
||||
dialogId : 'unsupported-browser'
|
||||
});
|
||||
}
|
||||
|
||||
if (pskl.utils.Environment.isDebug()) {
|
||||
pskl.app.shortcutService.registerShortcut(pskl.service.keyboard.Shortcuts.DEBUG.RELOAD_STYLES,
|
||||
window.reloadStyles);
|
||||
}
|
||||
},
|
||||
|
||||
loadPiskel_ : function (serializedPiskel, descriptor, fps) {
|
||||
loadPiskel_ : function (piskelData) {
|
||||
var serializedPiskel = piskelData.piskel;
|
||||
pskl.utils.serialization.Deserializer.deserialize(serializedPiskel, function (piskel) {
|
||||
piskel.setDescriptor(descriptor);
|
||||
pskl.app.piskelController.setPiskel(piskel);
|
||||
pskl.app.previewController.setFPS(fps);
|
||||
$.publish(Events.PISKEL_SAVED);
|
||||
if (piskelData.descriptor) {
|
||||
// Backward compatibility for v2 or older
|
||||
piskel.setDescriptor(piskelData.descriptor);
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
|
@ -17,6 +17,8 @@
|
||||
$.subscribe(Events.DRAG_START, this.onDragStart_.bind(this));
|
||||
$.subscribe(Events.DRAG_END, this.onDragEnd_.bind(this));
|
||||
$.subscribe(Events.FRAME_SIZE_CHANGED, this.redraw.bind(this));
|
||||
$.subscribe(Events.ZOOM_CHANGED, this.redraw.bind(this));
|
||||
$.subscribe(Events.PISKEL_RESET, this.redraw.bind(this));
|
||||
|
||||
this.redraw();
|
||||
};
|
||||
@ -39,7 +41,18 @@
|
||||
}
|
||||
}
|
||||
|
||||
this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html;
|
||||
if (pskl.app.drawingController) {
|
||||
var zoom = pskl.app.drawingController.compositeRenderer.getZoom().toFixed(2);
|
||||
html += '<div class="drawing-zoom">x' + zoom + '</div>';
|
||||
}
|
||||
|
||||
this.coordinatesContainer.innerHTML = this.getFrameSizeHTML_() + html + this.getCurrentFrameIndexHTML_();
|
||||
};
|
||||
|
||||
ns.CursorCoordinatesController.prototype.getCurrentFrameIndexHTML_ = function () {
|
||||
var currentFrameIndex = this.piskelController.getCurrentFrameIndex() + 1;
|
||||
var frameCount = this.piskelController.getFrameCount();
|
||||
return '<div class="frame-info">' + currentFrameIndex + '/' + frameCount + '</div>';
|
||||
};
|
||||
|
||||
ns.CursorCoordinatesController.prototype.getFrameSizeHTML_ = function () {
|
||||
|
@ -2,14 +2,12 @@
|
||||
|
||||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
ns.DrawingController = function (piskelController, paletteController, container) {
|
||||
ns.DrawingController = function (piskelController, container) {
|
||||
/**
|
||||
* @public
|
||||
*/
|
||||
this.piskelController = piskelController;
|
||||
|
||||
this.paletteController = paletteController;
|
||||
|
||||
this.dragHandler = new ns.drawing.DragHandler(this);
|
||||
|
||||
/**
|
||||
@ -24,7 +22,7 @@
|
||||
|
||||
var cfg = {
|
||||
'zoom': this.calculateZoom_(),
|
||||
'supportGridRendering' : true,
|
||||
'supportGridRendering' : false,
|
||||
'height' : this.getContainerHeight_(),
|
||||
'width' : this.getContainerWidth_(),
|
||||
'xOffset' : 0,
|
||||
@ -32,9 +30,10 @@
|
||||
};
|
||||
|
||||
this.overlayRenderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, cfg, ['canvas-overlay']);
|
||||
this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, cfg, ['drawing-canvas']);
|
||||
this.onionSkinRenderer = pskl.rendering.OnionSkinRenderer.createInContainer(this.container, cfg, piskelController);
|
||||
this.layersRenderer = new pskl.rendering.layer.LayersRenderer(this.container, cfg, piskelController);
|
||||
cfg.supportGridRendering = true;
|
||||
this.renderer = new pskl.rendering.frame.CachedFrameRenderer(this.container, cfg, ['drawing-canvas']);
|
||||
|
||||
this.compositeRenderer = new pskl.rendering.CompositeRenderer();
|
||||
this.compositeRenderer
|
||||
@ -52,12 +51,12 @@
|
||||
ns.DrawingController.prototype.init = function () {
|
||||
this.initMouseBehavior();
|
||||
|
||||
$.subscribe(Events.TOOL_SELECTED, $.proxy(function(evt, toolBehavior) {
|
||||
$.subscribe(Events.TOOL_SELECTED, (function(evt, toolBehavior) {
|
||||
this.currentToolBehavior = toolBehavior;
|
||||
this.overlayFrame.clear();
|
||||
}, this));
|
||||
}).bind(this));
|
||||
|
||||
$(window).resize($.proxy(this.startResizeTimer_, this));
|
||||
window.addEventListener('resize', this.startResizeTimer_.bind(this));
|
||||
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this));
|
||||
$.subscribe(Events.FRAME_SIZE_CHANGED, this.onFrameSizeChange_.bind(this));
|
||||
@ -66,6 +65,10 @@
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.RESET_ZOOM, this.resetZoom_.bind(this));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.INCREASE_ZOOM, this.updateZoom_.bind(this, 1));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.DECREASE_ZOOM, this.updateZoom_.bind(this, -1));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.OFFSET_UP, this.updateOffset_.bind(this, 'up'));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.OFFSET_RIGHT, this.updateOffset_.bind(this, 'right'));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.OFFSET_DOWN, this.updateOffset_.bind(this, 'down'));
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.MISC.OFFSET_LEFT, this.updateOffset_.bind(this, 'left'));
|
||||
|
||||
window.setTimeout(function () {
|
||||
this.afterWindowResize_();
|
||||
@ -74,13 +77,12 @@
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.initMouseBehavior = function() {
|
||||
var body = $('body');
|
||||
this.container.mousedown($.proxy(this.onMousedown_, this));
|
||||
this.container.addEventListener('mousedown', this.onMousedown_.bind(this));
|
||||
|
||||
if (pskl.utils.UserAgent.isChrome || pskl.utils.UserAgent.isIE11) {
|
||||
this.container.on('mousewheel', $.proxy(this.onMousewheel_, this));
|
||||
this.container.addEventListener('mousewheel', this.onMousewheel_.bind(this));
|
||||
} else {
|
||||
this.container.on('wheel', $.proxy(this.onMousewheel_, this));
|
||||
this.container.addEventListener('wheel', this.onMousewheel_.bind(this));
|
||||
}
|
||||
|
||||
window.addEventListener('mouseup', this.onMouseup_.bind(this));
|
||||
@ -91,22 +93,20 @@
|
||||
window.addEventListener('touchend', this.onTouchend_.bind(this));
|
||||
|
||||
// Deactivate right click:
|
||||
body.contextmenu(this.onCanvasContextMenu_);
|
||||
|
||||
document.body.addEventListener('contextmenu', this.onCanvasContextMenu_.bind(this));
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.startResizeTimer_ = function () {
|
||||
if (this.resizeTimer) {
|
||||
window.clearInterval(this.resizeTimer);
|
||||
}
|
||||
this.resizeTimer = window.setTimeout($.proxy(this.afterWindowResize_, this), 200);
|
||||
this.resizeTimer = window.setTimeout(this.afterWindowResize_.bind(this), 200);
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.afterWindowResize_ = function () {
|
||||
var initialWidth = this.compositeRenderer.getDisplaySize().width;
|
||||
|
||||
this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_());
|
||||
this.centerColumnWrapperHorizontally_();
|
||||
var ratio = this.compositeRenderer.getDisplaySize().width / initialWidth;
|
||||
var newZoom = ratio * this.compositeRenderer.getZoom();
|
||||
this.compositeRenderer.setZoom(newZoom);
|
||||
@ -131,7 +131,6 @@
|
||||
|
||||
ns.DrawingController.prototype.onFrameSizeChange_ = function () {
|
||||
this.compositeRenderer.setDisplaySize(this.getContainerWidth_(), this.getContainerHeight_());
|
||||
this.centerColumnWrapperHorizontally_();
|
||||
this.compositeRenderer.setZoom(this.calculateZoom_());
|
||||
this.compositeRenderer.setOffset(0, 0);
|
||||
$.publish(Events.ZOOM_CHANGED);
|
||||
@ -165,6 +164,9 @@
|
||||
|
||||
if (event.button === Constants.MIDDLE_BUTTON) {
|
||||
this.dragHandler.startDrag(event.clientX, event.clientY);
|
||||
} else if (event.altKey && !this.currentToolBehavior.supportsAlt()) {
|
||||
this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame);
|
||||
this.isPickingColor = true;
|
||||
} else {
|
||||
this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame);
|
||||
$.publish(Events.TOOL_PRESSED);
|
||||
@ -212,6 +214,8 @@
|
||||
if (this.isClicked) {
|
||||
if (pskl.app.mouseStateService.isMiddleButtonPressed()) {
|
||||
this.dragHandler.updateDrag(x, y);
|
||||
} else if (this.isPickingColor) {
|
||||
// Nothing to do on mousemove when picking a color with ALT+click.
|
||||
} else {
|
||||
$.publish(Events.MOUSE_EVENT, [event, this]);
|
||||
this.currentToolBehavior.moveToolAt(
|
||||
@ -234,8 +238,7 @@
|
||||
$.publish(Events.CURSOR_MOVED, [coords.x, coords.y]);
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) {
|
||||
var evt = jQueryEvent.originalEvent;
|
||||
ns.DrawingController.prototype.onMousewheel_ = function (evt) {
|
||||
// Ratio between wheelDeltaY (mousewheel event) and deltaY (wheel event) is -40
|
||||
var delta;
|
||||
if (pskl.utils.UserAgent.isIE11) {
|
||||
@ -259,6 +262,29 @@
|
||||
this.updateZoom_(modifier, coords);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the current viewport offset of 1 pixel in the provided direction.
|
||||
* Direction can be one of 'up', 'right', 'down', 'left'.
|
||||
* Callback for the OFFSET_${DIR} shortcuts.
|
||||
*/
|
||||
ns.DrawingController.prototype.updateOffset_ = function (direction) {
|
||||
var off = this.getOffset();
|
||||
if (direction === 'up') {
|
||||
off.y -= 1;
|
||||
} else if (direction === 'right') {
|
||||
off.x += 1;
|
||||
} else if (direction === 'down') {
|
||||
off.y += 1;
|
||||
} else if (direction === 'left') {
|
||||
off.x -= 1;
|
||||
}
|
||||
|
||||
this.setOffset(
|
||||
off.x,
|
||||
off.y
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Update the current zoom level by a given multiplier.
|
||||
*
|
||||
@ -296,38 +322,75 @@
|
||||
* @private
|
||||
*/
|
||||
ns.DrawingController.prototype.onMouseup_ = function (event) {
|
||||
var frame = this.piskelController.getCurrentFrame();
|
||||
if (!this.isClicked) {
|
||||
return;
|
||||
}
|
||||
|
||||
var coords = this.getSpriteCoordinates(event.clientX, event.clientY);
|
||||
if (event.changedTouches && event.changedTouches[0]) {
|
||||
coords = this.getSpriteCoordinates(event.changedTouches[0].clientX, event.changedTouches[0].clientY);
|
||||
}
|
||||
if (this.isClicked) {
|
||||
// A mouse button was clicked on the drawing canvas before this mouseup event,
|
||||
// the user was probably drawing on the canvas.
|
||||
// Note: The mousemove movement (and the mouseup) may end up outside
|
||||
// of the drawing canvas.
|
||||
|
||||
this.isClicked = false;
|
||||
// A mouse button was clicked on the drawing canvas before this mouseup event,
|
||||
// the user was probably drawing on the canvas.
|
||||
// Note: The mousemove movement (and the mouseup) may end up outside
|
||||
// of the drawing canvas.
|
||||
|
||||
if (pskl.app.mouseStateService.isMiddleButtonPressed()) {
|
||||
if (this.dragHandler.isDragging()) {
|
||||
this.dragHandler.stopDrag();
|
||||
} else if (frame.containsPixel(coords.x, coords.y)) {
|
||||
$.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]);
|
||||
}
|
||||
} else {
|
||||
this.currentToolBehavior.releaseToolAt(
|
||||
coords.x,
|
||||
coords.y,
|
||||
this.piskelController.getCurrentFrame(),
|
||||
this.overlayFrame,
|
||||
event
|
||||
);
|
||||
this.isClicked = false;
|
||||
|
||||
$.publish(Events.TOOL_RELEASED);
|
||||
}
|
||||
$.publish(Events.MOUSE_EVENT, [event, this]);
|
||||
var isMiddleButton = pskl.app.mouseStateService.isMiddleButtonPressed();
|
||||
var isMiddleClick = isMiddleButton && !this.dragHandler.isDragging();
|
||||
var isMiddleDrag = isMiddleButton && this.dragHandler.isDragging();
|
||||
|
||||
if (this.isPickingColor || isMiddleClick) {
|
||||
// Picking color after ALT+click or middle mouse button click.
|
||||
this.pickColorAt_(coords);
|
||||
this.isPickingColor = false;
|
||||
// Flash the cursor to briefly show the colorpicker cursor.
|
||||
this.flashColorPicker_();
|
||||
} else if (isMiddleDrag) {
|
||||
// Stop the drag handler after a middle button drag action.
|
||||
this.dragHandler.stopDrag();
|
||||
} else {
|
||||
// Regular tool click, release the current tool.
|
||||
this.currentToolBehavior.releaseToolAt(
|
||||
coords.x,
|
||||
coords.y,
|
||||
this.piskelController.getCurrentFrame(),
|
||||
this.overlayFrame,
|
||||
event
|
||||
);
|
||||
$.publish(Events.TOOL_RELEASED);
|
||||
}
|
||||
|
||||
$.publish(Events.MOUSE_EVENT, [event, this]);
|
||||
};
|
||||
|
||||
/**
|
||||
* Send a COLOR selection event for the color contained at the provided coordinates.
|
||||
* No-op if the coordinate is outside of the drawing canvas.
|
||||
* @param {Object} coords {x: Number, y: Number}
|
||||
*/
|
||||
ns.DrawingController.prototype.pickColorAt_ = function (coords) {
|
||||
var frame = this.piskelController.getCurrentFrame();
|
||||
if (!frame.containsPixel(coords.x, coords.y)) {
|
||||
return;
|
||||
}
|
||||
|
||||
var color = pskl.utils.intToColor(frame.getPixel(coords.x, coords.y));
|
||||
var isRightButton = pskl.app.mouseStateService.isRightButtonPressed();
|
||||
var evt = isRightButton ? Events.SELECT_SECONDARY_COLOR : Events.SELECT_PRIMARY_COLOR;
|
||||
$.publish(evt, [color]);
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.flashColorPicker_ = function () {
|
||||
document.body.classList.add('tool-colorpicker');
|
||||
document.body.classList.remove(this.currentToolBehavior.toolId);
|
||||
window.clearTimeout(this.flashColorPickerTimer);
|
||||
this.flashColorPickerTimer = window.setTimeout(function () {
|
||||
document.body.classList.remove('tool-colorpicker');
|
||||
document.body.classList.add(this.currentToolBehavior.toolId);
|
||||
}.bind(this), 200);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -348,7 +411,8 @@
|
||||
* @private
|
||||
*/
|
||||
ns.DrawingController.prototype.onCanvasContextMenu_ = function (event) {
|
||||
if ($(event.target).closest('#drawing-canvas-container').length) {
|
||||
// closest() not really available everywhere yet, just skip if missing.
|
||||
if (event.target.closest && event.target.closest('#drawing-canvas-container')) {
|
||||
// Deactivate right click on drawing canvas only.
|
||||
event.preventDefault();
|
||||
event.stopPropagation();
|
||||
@ -386,17 +450,21 @@
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.getAvailableHeight_ = function () {
|
||||
return $('#main-wrapper').height();
|
||||
return document.querySelector('#main-wrapper').getBoundingClientRect().height;
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.getSelectorWidth_ = function (selector) {
|
||||
return document.querySelector(selector).getBoundingClientRect().width;
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.getAvailableWidth_ = function () {
|
||||
var leftSectionWidth = $('.left-column').outerWidth(true);
|
||||
var rightSectionWidth = $('.right-column').outerWidth(true);
|
||||
var toolsContainerWidth = $('#tool-section').outerWidth(true);
|
||||
var settingsContainerWidth = $('#application-action-section').outerWidth(true);
|
||||
var leftSectionWidth = this.getSelectorWidth_('.left-column');
|
||||
var rightSectionWidth = this.getSelectorWidth_('.right-column');
|
||||
var toolsContainerWidth = this.getSelectorWidth_('#tool-section');
|
||||
var settingsContainerWidth = this.getSelectorWidth_('#application-action-section');
|
||||
|
||||
var usedWidth = leftSectionWidth + rightSectionWidth + toolsContainerWidth + settingsContainerWidth;
|
||||
var availableWidth = $('#main-wrapper').width() - usedWidth;
|
||||
var availableWidth = this.getSelectorWidth_('#main-wrapper') - usedWidth;
|
||||
|
||||
var comfortMargin = 10;
|
||||
return availableWidth - comfortMargin;
|
||||
@ -410,17 +478,6 @@
|
||||
return this.getAvailableWidth_();
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ns.DrawingController.prototype.centerColumnWrapperHorizontally_ = function() {
|
||||
var containerHeight = this.getContainerHeight_();
|
||||
var verticalGapInPixel = Math.floor(($('#main-wrapper').height() - containerHeight) / 2);
|
||||
$('#column-wrapper').css({
|
||||
'top': verticalGapInPixel + 'px'
|
||||
});
|
||||
};
|
||||
|
||||
ns.DrawingController.prototype.getRenderer = function () {
|
||||
return this.compositeRenderer;
|
||||
};
|
||||
|
@ -5,35 +5,46 @@
|
||||
SELECT : 'select',
|
||||
CLONE : 'clone',
|
||||
DELETE : 'delete',
|
||||
NEW_FRAME : 'newframe'
|
||||
NEW_FRAME : 'newframe',
|
||||
TOGGLE: 'toggle'
|
||||
};
|
||||
|
||||
ns.FramesListController = function (piskelController, container) {
|
||||
this.piskelController = piskelController;
|
||||
this.container = container;
|
||||
this.previewList = container.querySelector('#preview-list');
|
||||
this.refreshZoom_();
|
||||
|
||||
this.redrawFlag = true;
|
||||
this.regenerateDomFlag = true;
|
||||
this.justDropped = false;
|
||||
|
||||
this.cachedFrameProcessor = new pskl.model.frame.CachedFrameProcessor();
|
||||
this.cachedFrameProcessor.setFrameProcessor(this.frameToPreviewCanvas_.bind(this));
|
||||
this.cachedFrameProcessor.setOutputCloner(this.clonePreviewCanvas_.bind(this));
|
||||
|
||||
this.initDragndropBehavior_();
|
||||
};
|
||||
|
||||
ns.FramesListController.prototype.init = function() {
|
||||
$.subscribe(Events.TOOL_RELEASED, this.flagForRedraw_.bind(this));
|
||||
$.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this));
|
||||
$.subscribe(Events.PISKEL_RESET, this.flagForRedraw_.bind(this, true));
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, this.flagForRedraw_.bind(this));
|
||||
|
||||
$.subscribe(Events.PISKEL_RESET, this.refreshZoom_.bind(this));
|
||||
|
||||
$('#preview-list-scroller').scroll(this.updateScrollerOverflows.bind(this));
|
||||
this.container.get(0).addEventListener('click', this.onContainerClick_.bind(this));
|
||||
this.previewListScroller = document.querySelector('#preview-list-scroller');
|
||||
this.previewListScroller.addEventListener('scroll', this.updateScrollerOverflows.bind(this));
|
||||
this.container.addEventListener('click', this.onContainerClick_.bind(this));
|
||||
this.updateScrollerOverflows();
|
||||
};
|
||||
|
||||
ns.FramesListController.prototype.flagForRedraw_ = function () {
|
||||
ns.FramesListController.prototype.flagForRedraw_ = function (regenerateDom) {
|
||||
this.redrawFlag = true;
|
||||
|
||||
if (regenerateDom) {
|
||||
this.regenerateDomFlag = true;
|
||||
}
|
||||
};
|
||||
|
||||
ns.FramesListController.prototype.refreshZoom_ = function () {
|
||||
@ -42,17 +53,25 @@
|
||||
|
||||
ns.FramesListController.prototype.render = function () {
|
||||
if (this.redrawFlag) {
|
||||
this.createPreviews_();
|
||||
if (this.regenerateDomFlag) {
|
||||
this.tiles = [];
|
||||
this.addFrameTile = null;
|
||||
this.createPreviews_();
|
||||
|
||||
this.regenerateDomFlag = false;
|
||||
}
|
||||
|
||||
this.updatePreviews_();
|
||||
this.redrawFlag = false;
|
||||
}
|
||||
};
|
||||
|
||||
ns.FramesListController.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 scroller = this.previewListScroller;
|
||||
var scrollerHeight = scroller.offsetHeight;
|
||||
var scrollTop = scroller.scrollTop;
|
||||
var scrollerContentHeight = this.previewList.offsetHeight;
|
||||
var treshold = this.container.querySelector('.top-overflow').offsetHeight;
|
||||
var overflowTop = false;
|
||||
var overflowBottom = false;
|
||||
|
||||
@ -65,9 +84,8 @@
|
||||
overflowBottom = true;
|
||||
}
|
||||
}
|
||||
var wrapper = $('#preview-list-wrapper');
|
||||
wrapper.toggleClass('top-overflow-visible', overflowTop);
|
||||
wrapper.toggleClass('bottom-overflow-visible', overflowBottom);
|
||||
this.container.classList.toggle('top-overflow-visible', overflowTop);
|
||||
this.container.classList.toggle('bottom-overflow-visible', overflowBottom);
|
||||
};
|
||||
|
||||
ns.FramesListController.prototype.onContainerClick_ = function (event) {
|
||||
@ -80,27 +98,92 @@
|
||||
|
||||
if (action === ACTION.CLONE) {
|
||||
this.piskelController.duplicateFrameAt(index);
|
||||
var clonedTile = this.createPreviewTile_(index + 1);
|
||||
this.previewList.insertBefore(clonedTile, this.tiles[index].nextSibling);
|
||||
this.tiles.splice(index, 0, clonedTile);
|
||||
this.updateScrollerOverflows();
|
||||
} else if (action === ACTION.DELETE) {
|
||||
this.piskelController.removeFrameAt(index);
|
||||
this.previewList.removeChild(this.tiles[index]);
|
||||
this.tiles.splice(index, 1);
|
||||
this.updateScrollerOverflows();
|
||||
} else if (action === ACTION.SELECT) {
|
||||
} else if (action === ACTION.SELECT && !this.justDropped) {
|
||||
this.piskelController.setCurrentFrameIndex(index);
|
||||
} else if (action === ACTION.NEW_FRAME) {
|
||||
this.piskelController.addFrame();
|
||||
var newtile = this.createPreviewTile_(this.tiles.length);
|
||||
this.tiles.push(newtile);
|
||||
this.previewList.insertBefore(newtile, this.addFrameTile);
|
||||
this.updateScrollerOverflows();
|
||||
} else if (action == ACTION.TOGGLE) {
|
||||
this.piskelController.toggleFrameVisibilityAt(index);
|
||||
}
|
||||
|
||||
this.flagForRedraw_();
|
||||
};
|
||||
|
||||
ns.FramesListController.prototype.updatePreviews_ = function () {
|
||||
var i;
|
||||
var length;
|
||||
|
||||
for (i = 0, length = this.tiles.length; i < length; i++) {
|
||||
// Remove selected class
|
||||
this.tiles[i].classList.remove('selected');
|
||||
|
||||
// Remove toggle class
|
||||
this.tiles[i].querySelector('.tile-count').classList.remove('toggled');
|
||||
|
||||
// Update tile numbers
|
||||
this.tiles[i].setAttribute('data-tile-number', i);
|
||||
this.tiles[i].querySelector('.tile-count').innerHTML = (i + 1);
|
||||
|
||||
// Update visibility
|
||||
if (this.piskelController.hasVisibleFrameAt(i)) {
|
||||
this.tiles[i].querySelector('.tile-count').classList.add('toggled');
|
||||
}
|
||||
|
||||
// Check if any tile is updated
|
||||
var hash = this.piskelController.getCurrentLayer().getFrameAt(i).getHash();
|
||||
if (this.tiles[i].getAttribute('data-tile-hash') !== hash) {
|
||||
if (this.tiles[i].querySelector('canvas')) {
|
||||
this.tiles[i].querySelector('.canvas-container').replaceChild(
|
||||
this.getCanvasForFrame(this.piskelController.getCurrentLayer().getFrameAt(i)),
|
||||
this.tiles[i].querySelector('canvas')
|
||||
);
|
||||
} else {
|
||||
this.tiles[i].querySelector('.canvas-container').appendChild(
|
||||
this.getCanvasForFrame(this.piskelController.getCurrentLayer().getFrameAt(i))
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Hide/Show buttons if needed
|
||||
var buttons = this.container.querySelectorAll('.delete-frame-action, .dnd-action');
|
||||
var display = (this.piskelController.getFrameCount() > 1) ? 'block' : 'none';
|
||||
for (i = 0, length = buttons.length; i < length; i++) {
|
||||
buttons[i].style.display = display;
|
||||
}
|
||||
|
||||
// Add selected class
|
||||
this.tiles[this.piskelController.getCurrentFrameIndex()].classList.add('selected');
|
||||
};
|
||||
|
||||
ns.FramesListController.prototype.createPreviews_ = function () {
|
||||
this.container.html('');
|
||||
this.previewList.innerHTML = '';
|
||||
|
||||
// Manually remove tooltips since mouseout events were shortcut by the DOM refresh:
|
||||
$('.tooltip').remove();
|
||||
var tooltips = document.querySelectorAll('.tooltip');
|
||||
Array.prototype.forEach.call(tooltips, function (tooltip) {
|
||||
tooltip.parentNode.removeChild(tooltip);
|
||||
});
|
||||
|
||||
var frameCount = this.piskelController.getFrameCount();
|
||||
|
||||
for (var i = 0 ; i < frameCount ; i++) {
|
||||
this.container.append(this.createPreviewTile_(i));
|
||||
var tile = this.createPreviewTile_(i);
|
||||
this.previewList.appendChild(tile);
|
||||
this.tiles[i] = tile;
|
||||
}
|
||||
// Append 'new empty frame' button
|
||||
var newFrameButton = document.createElement('div');
|
||||
@ -109,12 +192,9 @@
|
||||
newFrameButton.setAttribute('data-tile-action', ACTION.NEW_FRAME);
|
||||
newFrameButton.innerHTML = '<div class="add-frame-action-icon icon-frame-plus-white">' +
|
||||
'</div><div class="label">Add new frame</div>';
|
||||
this.container.append(newFrameButton);
|
||||
this.previewList.appendChild(newFrameButton);
|
||||
this.addFrameTile = newFrameButton;
|
||||
|
||||
var needDragndropBehavior = (frameCount > 1);
|
||||
if (needDragndropBehavior) {
|
||||
this.initDragndropBehavior_();
|
||||
}
|
||||
this.updateScrollerOverflows();
|
||||
};
|
||||
|
||||
@ -122,37 +202,54 @@
|
||||
* @private
|
||||
*/
|
||||
ns.FramesListController.prototype.initDragndropBehavior_ = function () {
|
||||
|
||||
$('#preview-list').sortable({
|
||||
$(this.previewList).sortable({
|
||||
placeholder: 'preview-tile preview-tile-drop-proxy',
|
||||
update: $.proxy(this.onUpdate_, this),
|
||||
update: this.onUpdate_.bind(this),
|
||||
stop: this.onSortableStop_.bind(this),
|
||||
items: '.preview-tile',
|
||||
axis: 'y',
|
||||
tolerance: 'pointer'
|
||||
});
|
||||
$('#preview-list').disableSelection();
|
||||
$(this.previewList).disableSelection();
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ns.FramesListController.prototype.onUpdate_ = function (event, ui) {
|
||||
var originFrameId = parseInt(ui.item.data('tile-number'), 10);
|
||||
var targetInsertionId = $('.preview-tile').index(ui.item);
|
||||
var movedItem = ui.item.get(0);
|
||||
var originFrameId = parseInt(movedItem.dataset.tileNumber, 10);
|
||||
var tiles = document.querySelectorAll('.preview-tile');
|
||||
var targetInsertionId = Array.prototype.indexOf.call(tiles, movedItem);
|
||||
|
||||
this.piskelController.moveFrame(originFrameId, targetInsertionId);
|
||||
this.piskelController.setCurrentFrameIndex(targetInsertionId);
|
||||
|
||||
var tile = this.tiles.splice(originFrameId, 1)[0];
|
||||
this.tiles.splice(targetInsertionId, 0, tile);
|
||||
this.flagForRedraw_();
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ns.FramesListController.prototype.onSortableStop_ = function (event, ui) {
|
||||
this.justDropped = true;
|
||||
|
||||
this.resizeTimer = window.setTimeout((function() {
|
||||
this.justDropped = false;
|
||||
}).bind(this), 200);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
* TODO(vincz): clean this giant rendering function & remove listeners.
|
||||
*/
|
||||
ns.FramesListController.prototype.createPreviewTile_ = function(tileNumber) {
|
||||
var currentFrame = this.piskelController.getCurrentLayer().getFrameAt(tileNumber);
|
||||
|
||||
var previewTileRoot = document.createElement('li');
|
||||
previewTileRoot.setAttribute('data-tile-number', tileNumber);
|
||||
previewTileRoot.setAttribute('data-tile-hash', currentFrame.getHash());
|
||||
previewTileRoot.setAttribute('data-tile-action', ACTION.SELECT);
|
||||
previewTileRoot.classList.add('preview-tile');
|
||||
if (this.piskelController.getCurrentFrame() == currentFrame) {
|
||||
@ -171,10 +268,14 @@
|
||||
canvasContainer.style.marginLeft = verticalMargin + 'px';
|
||||
canvasContainer.style.marginRight = verticalMargin + 'px';
|
||||
|
||||
// Add canvas background and canvas
|
||||
var canvasBackground = document.createElement('div');
|
||||
canvasBackground.className = 'canvas-background';
|
||||
canvasContainer.appendChild(canvasBackground);
|
||||
canvasContainer.appendChild(this.getCanvasForFrame(currentFrame));
|
||||
previewTileRoot.appendChild(canvasContainer);
|
||||
|
||||
// Add clone button
|
||||
var cloneFrameButton = document.createElement('button');
|
||||
cloneFrameButton.setAttribute('rel', 'tooltip');
|
||||
cloneFrameButton.setAttribute('data-placement', 'right');
|
||||
@ -184,27 +285,28 @@
|
||||
cloneFrameButton.className = 'tile-overlay duplicate-frame-action icon-frame-duplicate-white';
|
||||
previewTileRoot.appendChild(cloneFrameButton);
|
||||
|
||||
canvasContainer.appendChild(this.getCanvasForFrame(currentFrame));
|
||||
previewTileRoot.appendChild(canvasContainer);
|
||||
// Add delete button
|
||||
var deleteButton = document.createElement('button');
|
||||
deleteButton.setAttribute('rel', 'tooltip');
|
||||
deleteButton.setAttribute('data-placement', 'right');
|
||||
deleteButton.setAttribute('title', 'Delete this frame');
|
||||
deleteButton.setAttribute('data-tile-number', tileNumber);
|
||||
deleteButton.setAttribute('data-tile-action', ACTION.DELETE);
|
||||
deleteButton.className = 'tile-overlay delete-frame-action icon-frame-recyclebin-white';
|
||||
previewTileRoot.appendChild(deleteButton);
|
||||
|
||||
if (tileNumber > 0 || this.piskelController.getFrameCount() > 1) {
|
||||
// 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.setAttribute('data-tile-number', tileNumber);
|
||||
deleteButton.setAttribute('data-tile-action', ACTION.DELETE);
|
||||
deleteButton.className = 'tile-overlay delete-frame-action icon-frame-recyclebin-white';
|
||||
previewTileRoot.appendChild(deleteButton);
|
||||
// Add 'dragndrop handle'.
|
||||
var dndHandle = document.createElement('div');
|
||||
dndHandle.className = 'tile-overlay dnd-action icon-frame-dragndrop-white' ;
|
||||
previewTileRoot.appendChild(dndHandle);
|
||||
|
||||
// Add 'dragndrop handle'.
|
||||
var dndHandle = document.createElement('div');
|
||||
dndHandle.className = 'tile-overlay dnd-action icon-frame-dragndrop-white' ;
|
||||
previewTileRoot.appendChild(dndHandle);
|
||||
}
|
||||
var tileCount = document.createElement('div');
|
||||
tileCount.className = 'tile-overlay tile-count';
|
||||
// Add tile count
|
||||
var tileCount = document.createElement('button');
|
||||
tileCount.setAttribute('rel', 'tooltip');
|
||||
tileCount.setAttribute('title', 'Toggle for preview');
|
||||
tileCount.setAttribute('data-tile-number', tileNumber);
|
||||
tileCount.setAttribute('data-tile-action', ACTION.TOGGLE);
|
||||
tileCount.className = 'tile-overlay tile-count toggle-frame-action';
|
||||
tileCount.innerHTML = tileNumber + 1;
|
||||
previewTileRoot.appendChild(tileCount);
|
||||
|
||||
|
@ -31,7 +31,7 @@
|
||||
}
|
||||
|
||||
if (this.piskelName_) {
|
||||
this.piskelName_.innerHTML = name;
|
||||
this.piskelName_.textContent = name;
|
||||
}
|
||||
} catch (e) {
|
||||
console.warn('Could not update header : ' + e.message);
|
||||
|
@ -1,15 +1,18 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
var TOGGLE_LAYER_SHORTCUT = 'alt+L';
|
||||
|
||||
ns.LayersListController = function (piskelController) {
|
||||
this.piskelController = piskelController;
|
||||
this.layerPreviewShortcut = pskl.service.keyboard.Shortcuts.MISC.LAYER_PREVIEW ;
|
||||
this.layerPreviewShortcut = pskl.service.keyboard.Shortcuts.MISC.LAYER_PREVIEW;
|
||||
this.startRenamingCurrentLayer_ = this.startRenamingCurrentLayer_.bind(this);
|
||||
this.onRenameInput_ = this.onRenameInput_.bind(this);
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.init = function () {
|
||||
this.isRenaming = false;
|
||||
|
||||
this.layerItemTemplate_ = pskl.utils.Template.get('layer-item-template');
|
||||
this.layerNameInputTemplate_ = pskl.utils.Template.get('layer-name-input-template');
|
||||
this.rootEl = document.querySelector('.layers-list-container');
|
||||
this.layersListEl = document.querySelector('.layers-list');
|
||||
this.toggleLayerPreviewEl = document.querySelector('.layers-toggle-preview');
|
||||
@ -17,28 +20,55 @@
|
||||
this.rootEl.addEventListener('click', this.onClick_.bind(this));
|
||||
this.toggleLayerPreviewEl.addEventListener('click', this.toggleLayerPreview_.bind(this));
|
||||
|
||||
this.createButtonTooltips_();
|
||||
this.initToggleLayerPreview_();
|
||||
|
||||
this.renderLayerList_();
|
||||
this.updateToggleLayerPreview_();
|
||||
|
||||
$.subscribe(Events.PISKEL_RESET, this.renderLayerList_.bind(this));
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this));
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.renderLayerList_ = function () {
|
||||
// Backup scroll before refresh.
|
||||
var scrollTop = this.layersListEl.scrollTop;
|
||||
|
||||
this.layersListEl.innerHTML = '';
|
||||
var layers = this.piskelController.getLayers();
|
||||
layers.forEach(this.addLayerItem.bind(this));
|
||||
this.updateButtonStatus_();
|
||||
|
||||
// Restore scroll
|
||||
this.layersListEl.scrollTop = scrollTop;
|
||||
|
||||
// Ensure the currently the selected layer is visible.
|
||||
var currentLayerEl = this.layersListEl.querySelector('.current-layer-item');
|
||||
if (currentLayerEl) {
|
||||
currentLayerEl.scrollIntoView();
|
||||
currentLayerEl.scrollIntoViewIfNeeded(false);
|
||||
}
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.createButtonTooltips_ = function () {
|
||||
var addTooltip = pskl.utils.TooltipFormatter.format('Create a layer', null, [
|
||||
{key : 'shift', description : 'Clone current layer'}
|
||||
]);
|
||||
var addButton = this.rootEl.querySelector('[data-action="add"]');
|
||||
addButton.setAttribute('title', addTooltip);
|
||||
|
||||
var moveDownTooltip = pskl.utils.TooltipFormatter.format('Move layer down', null, [
|
||||
{key : 'shift', description : 'Move to the bottom'}
|
||||
]);
|
||||
var moveDownButton = this.rootEl.querySelector('[data-action="down"]');
|
||||
moveDownButton.setAttribute('title', moveDownTooltip);
|
||||
|
||||
var moveUpTooltip = pskl.utils.TooltipFormatter.format('Move layer up', null, [
|
||||
{key : 'shift', description : 'Move to the top'}
|
||||
]);
|
||||
var moveUpButton = this.rootEl.querySelector('[data-action="up"]');
|
||||
moveUpButton.setAttribute('title', moveUpTooltip);
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.initToggleLayerPreview_ = function () {
|
||||
var descriptors = [{description : 'Opacity defined in PREFERENCES'}];
|
||||
var helpText = 'Preview all layers';
|
||||
@ -50,7 +80,6 @@
|
||||
|
||||
ns.LayersListController.prototype.updateButtonStatus_ = function () {
|
||||
var layers = this.piskelController.getLayers();
|
||||
var currentLayer = this.piskelController.getCurrentLayer();
|
||||
var index = this.piskelController.getCurrentLayerIndex();
|
||||
|
||||
var isLast = index === 0;
|
||||
@ -91,24 +120,62 @@
|
||||
|
||||
ns.LayersListController.prototype.addLayerItem = function (layer, index) {
|
||||
var isSelected = this.piskelController.getCurrentLayer() === layer;
|
||||
var isRenaming = isSelected && this.isRenaming;
|
||||
var layerItemHtml = pskl.utils.Template.replace(this.layerItemTemplate_, {
|
||||
'layername' : layer.getName(),
|
||||
'layerindex' : index,
|
||||
'isselected:current-layer-item' : isSelected,
|
||||
'opacity': layer.getOpacity()
|
||||
'opacity' : layer.getOpacity()
|
||||
});
|
||||
var layerItem = pskl.utils.Template.createFromHTML(layerItemHtml);
|
||||
this.layersListEl.insertBefore(layerItem, this.layersListEl.firstChild);
|
||||
if (layerItem.offsetWidth < layerItem.scrollWidth) {
|
||||
var layerNameEl = layerItem.querySelector('.layer-name');
|
||||
layerNameEl.classList.add('overflowing-name');
|
||||
layerNameEl.setAttribute('title', layer.getName());
|
||||
layerNameEl.setAttribute('rel', 'tooltip');
|
||||
}
|
||||
if (isSelected) {
|
||||
layerItem.removeEventListener('dblclick', this.startRenamingCurrentLayer_);
|
||||
layerItem.addEventListener('dblclick', this.startRenamingCurrentLayer_);
|
||||
}
|
||||
if (isRenaming) {
|
||||
var layerNameInputHtml = pskl.utils.Template.replace(this.layerNameInputTemplate_, {
|
||||
'layername' : layer.getName()
|
||||
});
|
||||
var layerNameInput = pskl.utils.Template.createFromHTML(layerNameInputHtml);
|
||||
var layerNameEl = layerItem.querySelector('.layer-name');
|
||||
layerItem.replaceChild(layerNameInput, layerNameEl);
|
||||
layerNameInput.removeEventListener('blur', this.onRenameInput_);
|
||||
layerNameInput.removeEventListener('keydown', this.onRenameInput_);
|
||||
layerNameInput.addEventListener('blur', this.onRenameInput_);
|
||||
layerNameInput.addEventListener('keydown', this.onRenameInput_);
|
||||
layerNameInput.focus();
|
||||
layerNameInput.select();
|
||||
}
|
||||
var opacity = layer.getOpacity();
|
||||
if (opacity == 1) {
|
||||
layerItem.querySelector('.layer-item-opacity').style.color = '#ffd700';
|
||||
} else if (opacity == 0) {
|
||||
layerItem.querySelector('.layer-item-opacity').style.color = '#969696';
|
||||
} else {
|
||||
layerItem.querySelector('.layer-item-opacity').style.color = '#ffffff';
|
||||
}
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.onClick_ = function (evt) {
|
||||
var el = evt.target || evt.srcElement;
|
||||
var index;
|
||||
if (el.classList.contains('button')) {
|
||||
this.onButtonClick_(el);
|
||||
} else if (el.classList.contains('layer-item')) {
|
||||
index = el.dataset.layerIndex;
|
||||
this.piskelController.setCurrentLayerIndex(parseInt(index, 10));
|
||||
this.onButtonClick_(el, evt);
|
||||
} else if (el.classList.contains('layer-name')) {
|
||||
var currentIndex = this.piskelController.getCurrentLayerIndex();
|
||||
index = pskl.utils.Dom.getData(el, 'layerIndex');
|
||||
if (index != currentIndex) {
|
||||
var currentItem = el.parentElement.parentElement.querySelector('.current-layer-item');
|
||||
currentItem.removeEventListener('dblclick', this.startRenamingCurrentLayer_);
|
||||
this.piskelController.setCurrentLayerIndex(parseInt(index, 10));
|
||||
}
|
||||
} else if (el.classList.contains('layer-item-opacity')) {
|
||||
index = pskl.utils.Dom.getData(el, 'layerIndex');
|
||||
var layer = this.piskelController.getLayerAt(parseInt(index, 10));
|
||||
@ -117,36 +184,55 @@
|
||||
}
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.renameCurrentLayer_ = function () {
|
||||
var layer = this.piskelController.getCurrentLayer();
|
||||
var name = window.prompt('Please enter the layer name', layer.getName());
|
||||
if (name) {
|
||||
var index = this.piskelController.getCurrentLayerIndex();
|
||||
this.piskelController.renameLayerAt(index, name);
|
||||
this.renderLayerList_();
|
||||
ns.LayersListController.prototype.startRenamingCurrentLayer_ = function () {
|
||||
this.isRenaming = true;
|
||||
this.renderLayerList_();
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.onRenameInput_ = function (evt) {
|
||||
var el = evt.target || evt.srcElement;
|
||||
if (evt.key === 'Enter') {
|
||||
this.finishRenamingCurrentLayer_(el, el.value);
|
||||
} else if (!evt.key || evt.key === 'Escape') {
|
||||
this.finishRenamingCurrentLayer_(el);
|
||||
}
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.finishRenamingCurrentLayer_ = function (input, newName) {
|
||||
if (newName) {
|
||||
var index = this.piskelController.getCurrentLayerIndex();
|
||||
this.piskelController.renameLayerAt(index, newName);
|
||||
}
|
||||
input.removeEventListener('blur', this.onRenameInput_);
|
||||
input.removeEventListener('keydown', this.onRenameInput_);
|
||||
this.isRenaming = false;
|
||||
this.renderLayerList_();
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.mergeDownCurrentLayer_ = function () {
|
||||
var index = this.piskelController.getCurrentLayerIndex();
|
||||
this.piskelController.mergeDownLayerAt(index);
|
||||
this.renderLayerList_();
|
||||
};
|
||||
|
||||
ns.LayersListController.prototype.onButtonClick_ = function (button) {
|
||||
ns.LayersListController.prototype.onButtonClick_ = function (button, evt) {
|
||||
var action = button.getAttribute('data-action');
|
||||
if (action == 'up') {
|
||||
this.piskelController.moveLayerUp();
|
||||
this.piskelController.moveLayerUp(evt.shiftKey);
|
||||
} else if (action == 'down') {
|
||||
this.piskelController.moveLayerDown();
|
||||
this.piskelController.moveLayerDown(evt.shiftKey);
|
||||
} else if (action == 'add') {
|
||||
this.piskelController.createLayer();
|
||||
if (evt.shiftKey) {
|
||||
this.piskelController.duplicateCurrentLayer();
|
||||
} else {
|
||||
this.piskelController.createLayer();
|
||||
}
|
||||
} else if (action == 'delete') {
|
||||
this.piskelController.removeCurrentLayer();
|
||||
} else if (action == 'merge') {
|
||||
this.mergeDownCurrentLayer_();
|
||||
} else if (action == 'edit') {
|
||||
this.renameCurrentLayer_();
|
||||
this.startRenamingCurrentLayer_();
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -16,14 +16,14 @@
|
||||
this.minimapEl = document.createElement('DIV');
|
||||
this.minimapEl.className = 'minimap-crop-frame';
|
||||
this.minimapEl.style.display = 'none';
|
||||
$(this.container).append(this.minimapEl);
|
||||
this.container.appendChild(this.minimapEl);
|
||||
|
||||
// Init mouse events
|
||||
$(this.container).mousedown(this.onMinimapMousedown_.bind(this));
|
||||
$('body').mousemove(this.onMinimapMousemove_.bind(this));
|
||||
$('body').mouseup(this.onMinimapMouseup_.bind(this));
|
||||
this.container.addEventListener('mousedown', this.onMinimapMousedown_.bind(this));
|
||||
document.body.addEventListener('mousemove', this.onMinimapMousemove_.bind(this));
|
||||
document.body.addEventListener('mouseup', this.onMinimapMouseup_.bind(this));
|
||||
|
||||
$.subscribe(Events.ZOOM_CHANGED, $.proxy(this.renderMinimap_, this));
|
||||
$.subscribe(Events.ZOOM_CHANGED, this.renderMinimap_.bind(this));
|
||||
};
|
||||
|
||||
ns.MinimapController.prototype.renderMinimap_ = function () {
|
||||
@ -40,8 +40,9 @@
|
||||
var minimapSize = this.getMinimapSize_();
|
||||
var previewSize = this.getPreviewSize_();
|
||||
|
||||
var containerHeight = this.container.height();
|
||||
var containerWidth = this.container.width();
|
||||
var containerRect = this.container.getBoundingClientRect();
|
||||
var containerHeight = containerRect.height;
|
||||
var containerWidth = containerRect.width;
|
||||
|
||||
// offset(x, y) in frame pixels
|
||||
var offset = this.drawingController.getRenderer().getOffset();
|
||||
@ -60,7 +61,7 @@
|
||||
this.minimapEl.style.display = 'block';
|
||||
this.minimapEl.style.width = Math.min(minimapSize.width, containerWidth) + 'px';
|
||||
this.minimapEl.style.height = Math.min(minimapSize.height, containerHeight) + 'px';
|
||||
this.minimapEl.style.left = Math.max(0, left) + 'px';
|
||||
this.minimapEl.style.left = (Math.max(0, left) + Constants.RIGHT_COLUMN_PADDING_LEFT) + 'px';
|
||||
this.minimapEl.style.top = Math.max(0, top) + 'px';
|
||||
|
||||
this.isVisible = true;
|
||||
|
@ -7,8 +7,8 @@
|
||||
* @public
|
||||
*/
|
||||
ns.NotificationController.prototype.init = function() {
|
||||
$.subscribe(Events.SHOW_NOTIFICATION, $.proxy(this.displayMessage_, this));
|
||||
$.subscribe(Events.HIDE_NOTIFICATION, $.proxy(this.removeMessage_, this));
|
||||
$.subscribe(Events.SHOW_NOTIFICATION, this.displayMessage_.bind(this));
|
||||
$.subscribe(Events.HIDE_NOTIFICATION, this.removeMessage_.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
@ -35,9 +35,9 @@
|
||||
* @private
|
||||
*/
|
||||
ns.NotificationController.prototype.removeMessage_ = function (evt) {
|
||||
var message = $('#user-message');
|
||||
if (message.length) {
|
||||
message.remove();
|
||||
var message = document.querySelector('#user-message');
|
||||
if (message) {
|
||||
message.parentNode.removeChild(message);
|
||||
}
|
||||
};
|
||||
})();
|
||||
|
@ -1,6 +1,10 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
/**
|
||||
* The PaletteController is responsible for handling the two color picker
|
||||
* widgets found in the left column, below the tools.
|
||||
*/
|
||||
ns.PaletteController = function () {};
|
||||
|
||||
/**
|
||||
@ -31,24 +35,24 @@
|
||||
// Initialize colorpickers:
|
||||
var colorPicker = $('#color-picker');
|
||||
colorPicker.spectrum($.extend({color: Constants.DEFAULT_PEN_COLOR}, spectrumCfg));
|
||||
colorPicker.change({isPrimary : true}, $.proxy(this.onPickerChange_, this));
|
||||
this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker);
|
||||
colorPicker.change({isPrimary : true}, this.onPickerChange_.bind(this));
|
||||
this.setTitleOnPicker_(Constants.DEFAULT_PEN_COLOR, colorPicker.get(0));
|
||||
|
||||
var secondaryColorPicker = $('#secondary-color-picker');
|
||||
secondaryColorPicker.spectrum($.extend({color: Constants.TRANSPARENT_COLOR}, spectrumCfg));
|
||||
secondaryColorPicker.change({isPrimary : false}, $.proxy(this.onPickerChange_, this));
|
||||
this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker);
|
||||
secondaryColorPicker.change({isPrimary : false}, this.onPickerChange_.bind(this));
|
||||
this.setTitleOnPicker_(Constants.TRANSPARENT_COLOR, secondaryColorPicker.get(0));
|
||||
|
||||
var swapColorsIcon = $('.swap-colors-button');
|
||||
swapColorsIcon.click(this.swapColors.bind(this));
|
||||
var swapColorsIcon = document.querySelector('.swap-colors-button');
|
||||
swapColorsIcon.addEventListener('click', this.swapColors.bind(this));
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ns.PaletteController.prototype.onPickerChange_ = function(evt, isPrimary) {
|
||||
var inputPicker = $(evt.target);
|
||||
var color = inputPicker.val();
|
||||
ns.PaletteController.prototype.onPickerChange_ = function(evt) {
|
||||
var inputPicker = evt.target;
|
||||
var color = inputPicker.value;
|
||||
|
||||
if (color != Constants.TRANSPARENT_COLOR) {
|
||||
// Unless the color is TRANSPARENT_COLOR, format it to hexstring, as
|
||||
@ -67,7 +71,6 @@
|
||||
* @private
|
||||
*/
|
||||
ns.PaletteController.prototype.onColorSelected_ = function(args, evt, color) {
|
||||
var inputPicker = $(evt.target);
|
||||
if (args.isPrimary) {
|
||||
this.setPrimaryColor_(color);
|
||||
} else {
|
||||
@ -76,12 +79,12 @@
|
||||
};
|
||||
|
||||
ns.PaletteController.prototype.setPrimaryColor_ = function (color) {
|
||||
this.updateColorPicker_(color, $('#color-picker'));
|
||||
this.updateColorPicker_(color, document.querySelector('#color-picker'));
|
||||
$.publish(Events.PRIMARY_COLOR_SELECTED, [color]);
|
||||
};
|
||||
|
||||
ns.PaletteController.prototype.setSecondaryColor_ = function (color) {
|
||||
this.updateColorPicker_(color, $('#secondary-color-picker'));
|
||||
this.updateColorPicker_(color, document.querySelector('#secondary-color-picker'));
|
||||
$.publish(Events.SECONDARY_COLOR_SELECTED, [color]);
|
||||
};
|
||||
|
||||
@ -92,13 +95,15 @@
|
||||
};
|
||||
|
||||
ns.PaletteController.prototype.resetColors = function () {
|
||||
pskl.app.selectedColorsService.reset();
|
||||
this.setPrimaryColor_(Constants.DEFAULT_PEN_COLOR);
|
||||
this.setSecondaryColor_(Constants.TRANSPARENT_COLOR);
|
||||
};
|
||||
|
||||
/**
|
||||
* @private
|
||||
*/
|
||||
ns.PaletteController.prototype.updateColorPicker_ = function (color, colorPicker) {
|
||||
var jqueryColorPicker = $(colorPicker);
|
||||
if (color == Constants.TRANSPARENT_COLOR) {
|
||||
// We can set the current palette color to transparent.
|
||||
// You can then combine this transparent color with an advanced
|
||||
@ -109,17 +114,17 @@
|
||||
// The colorpicker can't be set to a transparent state.
|
||||
// We set its background to white and insert the
|
||||
// string "TRANSPARENT" to mimic this state:
|
||||
colorPicker.spectrum('set', Constants.TRANSPARENT_COLOR);
|
||||
colorPicker.val(Constants.TRANSPARENT_COLOR);
|
||||
jqueryColorPicker.spectrum('set', Constants.TRANSPARENT_COLOR);
|
||||
colorPicker.value = Constants.TRANSPARENT_COLOR;
|
||||
} else {
|
||||
colorPicker.spectrum('set', color);
|
||||
jqueryColorPicker.spectrum('set', color);
|
||||
}
|
||||
this.setTitleOnPicker_(color, colorPicker);
|
||||
};
|
||||
|
||||
ns.PaletteController.prototype.setTitleOnPicker_ = function (title, colorPicker) {
|
||||
var parent = colorPicker.parent();
|
||||
title = parent.data('initial-title') + '<br/>' + title;
|
||||
parent.attr('data-original-title', title);
|
||||
var parent = colorPicker.parentNode;
|
||||
title = parent.dataset.initialTitle + '<br/>' + title;
|
||||
parent.dataset.originalTitle = title;
|
||||
};
|
||||
})();
|
||||
|
@ -29,7 +29,7 @@
|
||||
$.subscribe(Events.CURRENT_COLORS_UPDATED, this.fillColorListContainer.bind(this));
|
||||
$.subscribe(Events.PRIMARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this));
|
||||
$.subscribe(Events.SECONDARY_COLOR_SELECTED, this.highlightSelectedColors.bind(this));
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, $.proxy(this.onUserSettingsChange_, this));
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this));
|
||||
|
||||
var shortcuts = pskl.service.keyboard.Shortcuts;
|
||||
pskl.app.shortcutService.registerShortcut(shortcuts.COLOR.PREVIOUS_COLOR, this.selectPreviousColor_.bind(this));
|
||||
@ -51,12 +51,17 @@
|
||||
};
|
||||
|
||||
ns.PalettesListController.prototype.fillColorListContainer = function () {
|
||||
|
||||
var colors = this.getSelectedPaletteColors_();
|
||||
|
||||
if (colors.length > 0) {
|
||||
var html = colors.map(function (color, index) {
|
||||
return pskl.utils.Template.replace(this.paletteColorTemplate_, {color : color, index : index});
|
||||
var html = colors.filter(function (color) {
|
||||
return !!color;
|
||||
}).map(function (color, index) {
|
||||
return pskl.utils.Template.replace(this.paletteColorTemplate_, {
|
||||
color : color,
|
||||
index : index + 1,
|
||||
title : color.toUpperCase()
|
||||
});
|
||||
}.bind(this)).join('');
|
||||
this.colorListContainer_.innerHTML = html;
|
||||
|
||||
@ -64,6 +69,10 @@
|
||||
} else {
|
||||
this.colorListContainer_.innerHTML = pskl.utils.Template.get('palettes-list-no-colors-partial');
|
||||
}
|
||||
|
||||
// If we have more than 10 colors, use tiny mode, where 10 colors will fit on the same
|
||||
// line.
|
||||
this.colorListContainer_.classList.toggle('tiny', colors.length > 10);
|
||||
};
|
||||
|
||||
ns.PalettesListController.prototype.selectPalette = function (paletteId) {
|
||||
@ -100,8 +109,8 @@
|
||||
ns.PalettesListController.prototype.getCurrentColorIndex_ = function () {
|
||||
var currentIndex = 0;
|
||||
var selectedColor = document.querySelector('.' + PRIMARY_COLOR_CLASSNAME);
|
||||
if (selectedColor) {
|
||||
currentIndex = parseInt(selectedColor.dataset.colorIndex, 10);
|
||||
if (selectedColor) {
|
||||
currentIndex = parseInt(selectedColor.dataset.colorIndex, 10) - 1;
|
||||
}
|
||||
return currentIndex;
|
||||
};
|
||||
@ -139,14 +148,14 @@
|
||||
};
|
||||
|
||||
ns.PalettesListController.prototype.onCreatePaletteClick_ = function (evt) {
|
||||
$.publish(Events.DIALOG_DISPLAY, {
|
||||
$.publish(Events.DIALOG_SHOW, {
|
||||
dialogId : 'create-palette'
|
||||
});
|
||||
};
|
||||
|
||||
ns.PalettesListController.prototype.onEditPaletteClick_ = function (evt) {
|
||||
var paletteId = this.colorPaletteSelect_.value;
|
||||
$.publish(Events.DIALOG_DISPLAY, {
|
||||
$.publish(Events.DIALOG_SHOW, {
|
||||
dialogId : 'create-palette',
|
||||
initArgs : paletteId
|
||||
});
|
||||
|
@ -1,23 +1,19 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
ns.PenSizeController = function () {};
|
||||
ns.PenSizeController = function () {
|
||||
this.sizePicker = new pskl.widgets.SizePicker(this.onSizePickerChanged_.bind(this));
|
||||
};
|
||||
|
||||
ns.PenSizeController.prototype.init = function () {
|
||||
this.container = document.querySelector('.pen-size-container');
|
||||
pskl.utils.Event.addEventListener(this.container, 'click', this.onPenSizeOptionClick_, this);
|
||||
this.sizePicker.init(document.querySelector('.pen-size-container'));
|
||||
|
||||
$.subscribe(Events.PEN_SIZE_CHANGED, this.onPenSizeChanged_.bind(this));
|
||||
|
||||
this.updateSelectedOption_();
|
||||
};
|
||||
|
||||
ns.PenSizeController.prototype.onPenSizeOptionClick_ = function (e) {
|
||||
var size = e.target.dataset.size;
|
||||
if (!isNaN(size)) {
|
||||
size = parseInt(size, 10);
|
||||
pskl.app.penSizeService.setPenSize(size);
|
||||
}
|
||||
ns.PenSizeController.prototype.onSizePickerChanged_ = function (size) {
|
||||
pskl.app.penSizeService.setPenSize(size);
|
||||
};
|
||||
|
||||
ns.PenSizeController.prototype.onPenSizeChanged_ = function (e) {
|
||||
@ -25,11 +21,7 @@
|
||||
};
|
||||
|
||||
ns.PenSizeController.prototype.updateSelectedOption_ = function () {
|
||||
pskl.utils.Dom.removeClass('selected', this.container);
|
||||
var size = pskl.app.penSizeService.getPenSize();
|
||||
var selectedOption = this.container.querySelector('[data-size="' + size + '"]');
|
||||
if (selectedOption) {
|
||||
selectedOption.classList.add('selected');
|
||||
}
|
||||
this.sizePicker.setSize(size);
|
||||
};
|
||||
})();
|
||||
|
@ -10,9 +10,9 @@
|
||||
};
|
||||
|
||||
ns.ProgressBarController.prototype.init = function () {
|
||||
$.subscribe(Events.SHOW_PROGRESS, $.proxy(this.showProgress_, this));
|
||||
$.subscribe(Events.UPDATE_PROGRESS, $.proxy(this.updateProgress_, this));
|
||||
$.subscribe(Events.HIDE_PROGRESS, $.proxy(this.hideProgress_, this));
|
||||
$.subscribe(Events.SHOW_PROGRESS, this.showProgress_.bind(this));
|
||||
$.subscribe(Events.UPDATE_PROGRESS, this.updateProgress_.bind(this));
|
||||
$.subscribe(Events.HIDE_PROGRESS, this.hideProgress_.bind(this));
|
||||
};
|
||||
|
||||
ns.ProgressBarController.prototype.showProgress_ = function (event, progressInfo) {
|
||||
|
@ -35,7 +35,8 @@
|
||||
// Set SimplePen as default selected tool:
|
||||
this.selectTool_(this.tools[0]);
|
||||
// Activate listener on tool panel:
|
||||
$('#tool-section').mousedown($.proxy(this.onToolIconClicked_, this));
|
||||
var toolSection = document.querySelector('#tool-section');
|
||||
toolSection.addEventListener('mousedown', this.onToolIconClicked_.bind(this));
|
||||
|
||||
$.subscribe(Events.SELECT_TOOL, this.onSelectToolEvent_.bind(this));
|
||||
$.subscribe(Events.SHORTCUTS_CHANGED, this.createToolsDom_.bind(this));
|
||||
@ -45,14 +46,14 @@
|
||||
* @private
|
||||
*/
|
||||
ns.ToolController.prototype.activateToolOnStage_ = function(tool) {
|
||||
var stage = $('body');
|
||||
var previousSelectedToolClass = stage.data('selected-tool-class');
|
||||
var stage = document.body;
|
||||
var previousSelectedToolClass = stage.dataset.selectedToolClass;
|
||||
if (previousSelectedToolClass) {
|
||||
stage.removeClass(previousSelectedToolClass);
|
||||
stage.removeClass(pskl.tools.drawing.Move.TOOL_ID);
|
||||
stage.classList.remove(previousSelectedToolClass);
|
||||
stage.classList.remove(pskl.tools.drawing.Move.TOOL_ID);
|
||||
}
|
||||
stage.addClass(tool.toolId);
|
||||
stage.data('selected-tool-class', tool.toolId);
|
||||
stage.classList.add(tool.toolId);
|
||||
stage.dataset.selectedToolClass = tool.toolId;
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.onSelectToolEvent_ = function(event, toolId) {
|
||||
@ -69,11 +70,13 @@
|
||||
this.currentSelectedTool = tool;
|
||||
this.activateToolOnStage_(this.currentSelectedTool);
|
||||
|
||||
var selectedToolElement = $('#tool-section .tool-icon.selected');
|
||||
var toolElement = $('[data-tool-id=' + tool.toolId + ']');
|
||||
var selectedToolElement = document.querySelector('#tool-section .tool-icon.selected');
|
||||
if (selectedToolElement) {
|
||||
selectedToolElement.classList.remove('selected');
|
||||
}
|
||||
|
||||
selectedToolElement.removeClass('selected');
|
||||
toolElement.addClass('selected');
|
||||
var toolElement = document.querySelector('[data-tool-id=' + tool.toolId + ']');
|
||||
toolElement.classList.add('selected');
|
||||
|
||||
$.publish(Events.TOOL_SELECTED, [tool]);
|
||||
};
|
||||
@ -82,11 +85,11 @@
|
||||
* @private
|
||||
*/
|
||||
ns.ToolController.prototype.onToolIconClicked_ = function(evt) {
|
||||
var target = $(evt.target);
|
||||
var clickedTool = target.closest('.tool-icon');
|
||||
var target = evt.target;
|
||||
var clickedTool = pskl.utils.Dom.getParentWithData(target, 'toolId');
|
||||
|
||||
if (clickedTool.length) {
|
||||
var toolId = clickedTool.data().toolId;
|
||||
if (clickedTool) {
|
||||
var toolId = clickedTool.dataset.toolId;
|
||||
var tool = this.getToolById_(toolId);
|
||||
if (tool) {
|
||||
this.selectTool_(tool);
|
||||
@ -116,7 +119,7 @@
|
||||
var tool = this.tools[i];
|
||||
html += this.toolIconBuilder.createIcon(tool);
|
||||
}
|
||||
$('#tools-container').html(html);
|
||||
document.querySelector('#tools-container').innerHTML = html;
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.addKeyboardShortcuts_ = function () {
|
||||
|
@ -1,22 +1,30 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller');
|
||||
var SHOW_MORE_CLASS = 'show-more';
|
||||
|
||||
ns.TransformationsController = function () {
|
||||
this.tools = [
|
||||
new pskl.tools.transform.Flip(),
|
||||
new pskl.tools.transform.Rotate(),
|
||||
new pskl.tools.transform.Clone(),
|
||||
new pskl.tools.transform.Center()
|
||||
new pskl.tools.transform.Center(),
|
||||
new pskl.tools.transform.Crop(),
|
||||
];
|
||||
|
||||
this.toolIconBuilder = new pskl.tools.ToolIconBuilder();
|
||||
};
|
||||
|
||||
ns.TransformationsController.prototype.init = function () {
|
||||
var container = document.querySelector('.transformations-container');
|
||||
this.toolsContainer = container.querySelector('.tools-wrapper');
|
||||
container.addEventListener('click', this.onTransformationClick_.bind(this));
|
||||
this.container = document.querySelector('.transformations-container');
|
||||
this.container.addEventListener('click', this.onTransformationClick_.bind(this));
|
||||
|
||||
this.showMoreLink = this.container.querySelector('.transformations-show-more-link');
|
||||
this.showMoreLink.addEventListener('click', this.toggleShowMoreTools_.bind(this));
|
||||
|
||||
this.createToolsDom_();
|
||||
this.updateShowMoreLink_();
|
||||
|
||||
$.subscribe(Events.USER_SETTINGS_CHANGED, this.onUserSettingsChange_.bind(this));
|
||||
};
|
||||
|
||||
ns.TransformationsController.prototype.applyTool = function (toolId, evt) {
|
||||
@ -30,13 +38,35 @@
|
||||
|
||||
ns.TransformationsController.prototype.onTransformationClick_ = function (evt) {
|
||||
var toolId = evt.target.dataset.toolId;
|
||||
this.applyTool(toolId, evt);
|
||||
if (toolId) {
|
||||
this.applyTool(toolId, evt);
|
||||
}
|
||||
};
|
||||
|
||||
ns.TransformationsController.prototype.toggleShowMoreTools_ = function (evt) {
|
||||
var showMore = pskl.UserSettings.get(pskl.UserSettings.TRANSFORM_SHOW_MORE);
|
||||
pskl.UserSettings.set(pskl.UserSettings.TRANSFORM_SHOW_MORE, !showMore);
|
||||
};
|
||||
|
||||
ns.TransformationsController.prototype.onUserSettingsChange_ = function (evt, settingName) {
|
||||
if (settingName == pskl.UserSettings.TRANSFORM_SHOW_MORE) {
|
||||
this.updateShowMoreLink_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.TransformationsController.prototype.updateShowMoreLink_ = function () {
|
||||
var showMoreEnabled = pskl.UserSettings.get(pskl.UserSettings.TRANSFORM_SHOW_MORE);
|
||||
this.container.classList.toggle(SHOW_MORE_CLASS, showMoreEnabled);
|
||||
|
||||
// Hide the link in case there are 4 or less tools available.
|
||||
this.showMoreLink.classList.toggle('hidden', this.tools.length < 5);
|
||||
};
|
||||
|
||||
ns.TransformationsController.prototype.createToolsDom_ = function() {
|
||||
var html = this.tools.reduce(function (p, tool) {
|
||||
return p + this.toolIconBuilder.createIcon(tool, 'left');
|
||||
}.bind(this), '');
|
||||
this.toolsContainer.innerHTML = html;
|
||||
var toolsContainer = this.container.querySelector('.tools-wrapper');
|
||||
toolsContainer.innerHTML = html;
|
||||
};
|
||||
})();
|
||||
|
59
src/js/controller/UserWarningController.js
Normal file
@ -0,0 +1,59 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller');
|
||||
|
||||
ns.UserWarningController = function (piskelController, currentColorsService) {
|
||||
this.piskelController = piskelController;
|
||||
this.currentColorsService = currentColorsService;
|
||||
};
|
||||
|
||||
// This method is not attached to the prototype because we want to trigger it
|
||||
// from markup generated for a notification message.
|
||||
ns.UserWarningController.showPerformanceInfoDialog = function () {
|
||||
$.publish(Events.DIALOG_SHOW, {
|
||||
dialogId: 'performance-info'
|
||||
});
|
||||
};
|
||||
|
||||
ns.UserWarningController.prototype.init = function () {
|
||||
$.subscribe(Events.PERFORMANCE_REPORT_CHANGED, this.onPerformanceReportChanged_.bind(this));
|
||||
|
||||
this.performanceLinkEl = document.querySelector('.performance-link');
|
||||
pskl.utils.Event.addEventListener(
|
||||
this.performanceLinkEl,
|
||||
'click',
|
||||
ns.UserWarningController.showPerformanceInfoDialog,
|
||||
this
|
||||
);
|
||||
};
|
||||
|
||||
ns.UserWarningController.prototype.destroy = function () {
|
||||
pskl.utils.Event.removeAllEventListeners(this);
|
||||
this.performanceLinkEl = null;
|
||||
};
|
||||
|
||||
ns.UserWarningController.prototype.onPerformanceReportChanged_ = function (event, report) {
|
||||
var shouldDisplayWarning = report.hasProblem();
|
||||
|
||||
// Check if a performance warning is already displayed.
|
||||
var isWarningDisplayed = this.performanceLinkEl.classList.contains('visible');
|
||||
|
||||
// Show/hide the performance warning link depending on the received report.
|
||||
if (shouldDisplayWarning) {
|
||||
this.performanceLinkEl.classList.add('visible');
|
||||
} else {
|
||||
this.performanceLinkEl.classList.remove('visible');
|
||||
}
|
||||
|
||||
// Show a notification message if the new report indicates a performance issue
|
||||
// and we were not displaying a warning before.
|
||||
if (shouldDisplayWarning && !isWarningDisplayed) {
|
||||
$.publish(Events.SHOW_NOTIFICATION, [{
|
||||
'content': 'Performance problem detected, ' +
|
||||
'<a href="#" style="color:red;"' +
|
||||
'onclick="pskl.controller.UserWarningController.showPerformanceInfoDialog()">' +
|
||||
'learn more?</a>',
|
||||
'hideDelay' : 5000
|
||||
}]);
|
||||
}
|
||||
};
|
||||
})();
|
@ -4,14 +4,19 @@
|
||||
ns.AbstractDialogController = function () {};
|
||||
|
||||
ns.AbstractDialogController.prototype.init = function () {
|
||||
this.closeButton = document.querySelector('.dialog-close');
|
||||
this.closeButton.addEventListener('click', this.closeDialog.bind(this));
|
||||
var closeButton = document.querySelector('.dialog-close');
|
||||
this.addEventListener(closeButton, 'click', this.closeDialog);
|
||||
};
|
||||
|
||||
ns.AbstractDialogController.prototype.destroy = function () {};
|
||||
ns.AbstractDialogController.prototype.addEventListener = function (el, type, cb) {
|
||||
pskl.utils.Event.addEventListener(el, type, cb, this);
|
||||
};
|
||||
|
||||
ns.AbstractDialogController.prototype.destroy = function () {
|
||||
pskl.utils.Event.removeAllEventListeners(this);
|
||||
};
|
||||
|
||||
ns.AbstractDialogController.prototype.closeDialog = function () {
|
||||
this.destroy();
|
||||
$.publish(Events.DIALOG_HIDE);
|
||||
};
|
||||
|
||||
|
@ -1,8 +1,7 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
|
||||
ns.BrowseLocalController = function (piskelController) {
|
||||
};
|
||||
ns.BrowseLocalController = function (piskelController) {};
|
||||
|
||||
pskl.utils.inherit(ns.BrowseLocalController, ns.AbstractDialogController);
|
||||
|
||||
@ -11,13 +10,12 @@
|
||||
|
||||
this.localStorageItemTemplate_ = pskl.utils.Template.get('local-storage-item-template');
|
||||
|
||||
this.service_ = pskl.app.localStorageService;
|
||||
this.piskelList = $('.local-piskel-list');
|
||||
this.prevSessionContainer = $('.previous-session');
|
||||
this.service_ = pskl.app.indexedDbStorageService;
|
||||
this.piskelList = document.querySelector('.local-piskel-list');
|
||||
|
||||
this.fillLocalPiskelsList_();
|
||||
|
||||
this.piskelList.click(this.onPiskelsListClick_.bind(this));
|
||||
this.piskelList.addEventListener('click', this.onPiskelsListClick_.bind(this));
|
||||
};
|
||||
|
||||
ns.BrowseLocalController.prototype.onPiskelsListClick_ = function (evt) {
|
||||
@ -37,21 +35,24 @@
|
||||
};
|
||||
|
||||
ns.BrowseLocalController.prototype.fillLocalPiskelsList_ = function () {
|
||||
var html = '';
|
||||
var keys = this.service_.getKeys();
|
||||
this.service_.getKeys().then(function (keys) {
|
||||
var html = '';
|
||||
keys.sort(function (k1, k2) {
|
||||
if (k1.date < k2.date) {return 1;}
|
||||
if (k1.date > k2.date) {return -1;}
|
||||
return 0;
|
||||
});
|
||||
|
||||
keys.sort(function (k1, k2) {
|
||||
if (k1.date < k2.date) {return 1;}
|
||||
if (k1.date > k2.date) {return -1;}
|
||||
return 0;
|
||||
});
|
||||
keys.forEach((function (key) {
|
||||
var date = pskl.utils.DateUtils.format(key.date, '{{Y}}/{{M}}/{{D}} {{H}}:{{m}}');
|
||||
html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {
|
||||
name : key.name,
|
||||
date : date
|
||||
});
|
||||
}).bind(this));
|
||||
|
||||
keys.forEach((function (key) {
|
||||
var date = pskl.utils.DateUtils.format(key.date, '{{Y}}/{{M}}/{{D}} {{H}}:{{m}}');
|
||||
html += pskl.utils.Template.replace(this.localStorageItemTemplate_, {name : key.name, date : date});
|
||||
}).bind(this));
|
||||
|
||||
var tableBody_ = this.piskelList.get(0).tBodies[0];
|
||||
tableBody_.innerHTML = html;
|
||||
var tableBody_ = this.piskelList.tBodies[0];
|
||||
tableBody_.innerHTML = html;
|
||||
}.bind(this));
|
||||
};
|
||||
})();
|
||||
|
@ -13,11 +13,12 @@
|
||||
this.cheatsheetEl = document.getElementById('cheatsheetContainer');
|
||||
this.eventTrapInput = document.getElementById('cheatsheetEventTrap');
|
||||
|
||||
pskl.utils.Event.addEventListener('.cheatsheet-restore-defaults', 'click', this.onRestoreDefaultsClick_, this);
|
||||
pskl.utils.Event.addEventListener(this.cheatsheetEl, 'click', this.onCheatsheetClick_, this);
|
||||
pskl.utils.Event.addEventListener(this.eventTrapInput, 'keydown', this.onEventTrapKeydown_, this);
|
||||
this.addEventListener('.cheatsheet-restore-defaults', 'click', this.onRestoreDefaultsClick_);
|
||||
this.addEventListener(this.cheatsheetEl, 'click', this.onCheatsheetClick_);
|
||||
this.addEventListener(this.eventTrapInput, 'keydown', this.onEventTrapKeydown_);
|
||||
|
||||
$.subscribe(Events.SHORTCUTS_CHANGED, this.onShortcutsChanged_.bind(this));
|
||||
this.onShortcutsChanged_ = this.onShortcutsChanged_.bind(this);
|
||||
$.subscribe(Events.SHORTCUTS_CHANGED, this.onShortcutsChanged_);
|
||||
|
||||
this.initMarkup_();
|
||||
document.querySelector('.cheatsheet-helptext').setAttribute('title', this.getHelptextTitle_());
|
||||
@ -25,8 +26,11 @@
|
||||
|
||||
ns.CheatsheetController.prototype.destroy = function () {
|
||||
this.eventTrapInput.blur();
|
||||
pskl.utils.Event.removeAllEventListeners();
|
||||
|
||||
$.unsubscribe(Events.SHORTCUTS_CHANGED, this.onShortcutsChanged_);
|
||||
this.cheatsheetEl = null;
|
||||
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.CheatsheetController.prototype.onRestoreDefaultsClick_ = function () {
|
||||
@ -140,7 +144,8 @@
|
||||
title : title,
|
||||
icon : descriptor.iconClass,
|
||||
description : description,
|
||||
key : this.formatKey_(shortcut.getDisplayKey()),
|
||||
// Avoid sanitization
|
||||
'!key!' : this.formatKey_(shortcut.getDisplayKey()),
|
||||
className : shortcutClasses.join(' ')
|
||||
});
|
||||
|
||||
@ -152,10 +157,10 @@
|
||||
key = key.replace('ctrl', 'cmd');
|
||||
key = key.replace('alt', 'option');
|
||||
}
|
||||
key = key.replace(/left/i, '←');
|
||||
key = key.replace(/up/i, '↑');
|
||||
key = key.replace(/right/i, '→');
|
||||
key = key.replace(/down/i, '↓');
|
||||
key = key.replace(/left/i, '←');
|
||||
key = key.replace(/up/i, '↑');
|
||||
key = key.replace(/right/i, '→');
|
||||
key = key.replace(/down/i, '↓');
|
||||
key = key.replace(/>/g, '>');
|
||||
key = key.replace(/</g, '<');
|
||||
// add spaces around '+' delimiters
|
||||
|
@ -19,12 +19,12 @@
|
||||
var downloadButton = document.querySelector('.create-palette-download-button');
|
||||
var importFileButton = document.querySelector('.create-palette-import-button');
|
||||
|
||||
this.nameInput.addEventListener('input', this.onNameInputChange_.bind(this));
|
||||
this.hiddenFileInput.addEventListener('change', this.onFileInputChange_.bind(this));
|
||||
this.addEventListener(this.nameInput, 'input', this.onNameInputChange_);
|
||||
this.addEventListener(this.hiddenFileInput, 'change', this.onFileInputChange_);
|
||||
|
||||
buttonsContainer.addEventListener('click', this.onButtonClick_.bind(this));
|
||||
downloadButton.addEventListener('click', this.onDownloadButtonClick_.bind(this));
|
||||
importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this));
|
||||
this.addEventListener(buttonsContainer, 'click', this.onButtonClick_);
|
||||
this.addEventListener(downloadButton, 'click', this.onDownloadButtonClick_);
|
||||
this.addEventListener(importFileButton, 'click', this.onImportFileButtonClick_);
|
||||
|
||||
var colorsListContainer = document.querySelector('.colors-container');
|
||||
this.colorsListWidget = new pskl.widgets.ColorsList(colorsListContainer);
|
||||
@ -66,7 +66,10 @@
|
||||
|
||||
ns.CreatePaletteController.prototype.destroy = function () {
|
||||
this.colorsListWidget.destroy();
|
||||
this.superclass.destroy.call(this);
|
||||
|
||||
this.nameInput = null;
|
||||
this.hiddenFileInput = null;
|
||||
};
|
||||
|
||||
ns.CreatePaletteController.prototype.onButtonClick_ = function (evt) {
|
||||
|
@ -14,9 +14,21 @@
|
||||
template : 'templates/dialogs/browse-local.html',
|
||||
controller : ns.BrowseLocalController
|
||||
},
|
||||
'import-image' : {
|
||||
template : 'templates/dialogs/import-image.html',
|
||||
controller : ns.ImportImageController
|
||||
'import' : {
|
||||
template : 'templates/dialogs/import.html',
|
||||
controller : ns.importwizard.ImportWizard
|
||||
},
|
||||
'performance-info' : {
|
||||
template : 'templates/dialogs/performance-info.html',
|
||||
controller : ns.PerformanceInfoController
|
||||
},
|
||||
'unsupported-browser' : {
|
||||
template : 'templates/dialogs/unsupported-browser.html',
|
||||
controller : ns.UnsupportedBrowserController
|
||||
},
|
||||
'browse-backups' : {
|
||||
template : 'templates/dialogs/browse-backups.html',
|
||||
controller : ns.backups.BrowseBackups
|
||||
}
|
||||
};
|
||||
|
||||
@ -30,7 +42,7 @@
|
||||
this.dialogContainer_ = document.getElementById('dialog-container');
|
||||
this.dialogWrapper_ = document.getElementById('dialog-container-wrapper');
|
||||
|
||||
$.subscribe(Events.DIALOG_DISPLAY, this.onDialogDisplayEvent_.bind(this));
|
||||
$.subscribe(Events.DIALOG_SHOW, this.onDialogDisplayEvent_.bind(this));
|
||||
$.subscribe(Events.DIALOG_HIDE, this.hideDialog.bind(this));
|
||||
|
||||
var createPaletteShortcut = pskl.service.keyboard.Shortcuts.COLOR.CREATE_PALETTE;
|
||||
@ -42,6 +54,7 @@
|
||||
|
||||
// adding the .animated class here instead of in the markup to avoid an animation during app startup
|
||||
this.dialogWrapper_.classList.add('animated');
|
||||
pskl.utils.Event.addEventListener(this.dialogWrapper_, 'click', this.onWrapperClicked_, this);
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.onCreatePaletteShortcut_ = function () {
|
||||
@ -69,6 +82,12 @@
|
||||
this.showDialog(args.dialogId, args.initArgs);
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.onWrapperClicked_ = function (evt) {
|
||||
if (evt.target === this.dialogWrapper_) {
|
||||
this.hideDialog();
|
||||
}
|
||||
};
|
||||
|
||||
ns.DialogsController.prototype.showDialog = function (dialogId, initArgs) {
|
||||
if (this.isDisplayingDialog_()) {
|
||||
return;
|
||||
|
@ -1,261 +0,0 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
|
||||
ns.ImportImageController = function (piskelController) {
|
||||
this.importedImage_ = null;
|
||||
this.file_ = null;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ImportImageController, ns.AbstractDialogController);
|
||||
|
||||
ns.ImportImageController.prototype.init = function (file) {
|
||||
this.superclass.init.call(this);
|
||||
|
||||
this.file_ = file;
|
||||
|
||||
this.importPreview = $('.import-section-preview');
|
||||
|
||||
this.fileNameContainer = $('.import-image-file-name');
|
||||
|
||||
this.importType = $('[name=import-type]');
|
||||
|
||||
this.resizeWidth = $('[name=resize-width]');
|
||||
this.resizeHeight = $('[name=resize-height]');
|
||||
this.smoothResize = $('[name=smooth-resize-checkbox]');
|
||||
|
||||
this.frameSizeX = $('[name=frame-size-x]');
|
||||
this.frameSizeY = $('[name=frame-size-y]');
|
||||
this.frameOffsetX = $('[name=frame-offset-x]');
|
||||
this.frameOffsetY = $('[name=frame-offset-y]');
|
||||
|
||||
this.importType.change(this.onImportTypeChange_.bind(this));
|
||||
|
||||
this.resizeWidth.keyup(this.onResizeInputKeyUp_.bind(this, 'width'));
|
||||
this.resizeHeight.keyup(this.onResizeInputKeyUp_.bind(this, 'height'));
|
||||
this.frameSizeX.keyup(this.onFrameInputKeyUp_.bind(this, 'frameSizeX'));
|
||||
this.frameSizeY.keyup(this.onFrameInputKeyUp_.bind(this, 'frameSizeY'));
|
||||
this.frameOffsetX.keyup(this.onFrameInputKeyUp_.bind(this, 'frameOffsetX'));
|
||||
this.frameOffsetY.keyup(this.onFrameInputKeyUp_.bind(this, 'frameOffsetY'));
|
||||
|
||||
this.importImageForm = $('[name=import-image-form]');
|
||||
this.importImageForm.submit(this.onImportFormSubmit_.bind(this));
|
||||
|
||||
pskl.utils.FileUtils.readImageFile(this.file_, this.onImageLoaded_.bind(this));
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onImportTypeChange_ = function (evt) {
|
||||
if (this.getImportType_() === 'single') {
|
||||
// Using single image, so remove the frame grid
|
||||
this.hideFrameGrid_();
|
||||
} else {
|
||||
// Using spritesheet import, so draw the frame grid in the preview
|
||||
var x = this.sanitizeInputValue_(this.frameOffsetX, 0);
|
||||
var y = this.sanitizeInputValue_(this.frameOffsetY, 0);
|
||||
var w = this.sanitizeInputValue_(this.frameSizeX, 1);
|
||||
var h = this.sanitizeInputValue_(this.frameSizeY, 1);
|
||||
this.drawFrameGrid_(x, y, w, h);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onImportFormSubmit_ = function (evt) {
|
||||
evt.originalEvent.preventDefault();
|
||||
this.importImageToPiskel_();
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onResizeInputKeyUp_ = function (from, evt) {
|
||||
if (this.importedImage_) {
|
||||
this.synchronizeResizeFields_(evt.target.value, from);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onFrameInputKeyUp_ = function (from, evt) {
|
||||
if (this.importedImage_) {
|
||||
this.synchronizeFrameFields_(evt.target.value, from);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.synchronizeResizeFields_ = function (value, from) {
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
}
|
||||
var height = this.importedImage_.height;
|
||||
var width = this.importedImage_.width;
|
||||
|
||||
// Select single image import type since the user changed a value here
|
||||
this.importType.filter('[value="single"]').attr('checked', 'checked');
|
||||
|
||||
if (from === 'width') {
|
||||
this.resizeHeight.val(Math.round(value * height / width));
|
||||
} else {
|
||||
this.resizeWidth.val(Math.round(value * width / height));
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.synchronizeFrameFields_ = function (value, from) {
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
// Parse the frame input values
|
||||
var frameSizeX = this.sanitizeInputValue_(this.frameSizeX, 1);
|
||||
var frameSizeY = this.sanitizeInputValue_(this.frameSizeY, 1);
|
||||
var frameOffsetX = this.sanitizeInputValue_(this.frameOffsetX, 0);
|
||||
var frameOffsetY = this.sanitizeInputValue_(this.frameOffsetY, 0);
|
||||
|
||||
// Select spritesheet import type since the user changed a value here
|
||||
this.importType.filter('[value="sheet"]').attr('checked', 'checked');
|
||||
|
||||
// Draw the grid
|
||||
this.drawFrameGrid_(frameOffsetX, frameOffsetY, frameSizeX, frameSizeY);
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.sanitizeInputValue_ = function(input, minValue) {
|
||||
var value = parseInt(input.val(), 10);
|
||||
if (value <= minValue || isNaN(value)) {
|
||||
input.val(minValue);
|
||||
value = minValue;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.getImportType_ = function () {
|
||||
return this.importType.filter(':checked').val();
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.onImageLoaded_ = function (image) {
|
||||
this.importedImage_ = image;
|
||||
|
||||
var w = this.importedImage_.width;
|
||||
var h = this.importedImage_.height;
|
||||
|
||||
// FIXME : We remove the onload callback here because JsGif will insert
|
||||
// the image again and we want to avoid retriggering the image onload
|
||||
this.importedImage_.onload = function () {};
|
||||
|
||||
var fileName = this.extractFileNameFromPath_(this.file_.name);
|
||||
this.fileNameContainer.html(fileName);
|
||||
this.fileNameContainer.attr('title', fileName);
|
||||
|
||||
this.resizeWidth.val(w);
|
||||
this.resizeHeight.val(h);
|
||||
|
||||
this.frameSizeX.val(w);
|
||||
this.frameSizeY.val(h);
|
||||
this.frameOffsetX.val(0);
|
||||
this.frameOffsetY.val(0);
|
||||
|
||||
this.importPreview.width('auto');
|
||||
this.importPreview.height('auto');
|
||||
this.importPreview.html('');
|
||||
this.importPreview.append(this.createImagePreview_());
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.createImagePreview_ = function () {
|
||||
var image = document.createElement('IMG');
|
||||
image.src = this.importedImage_.src;
|
||||
return image;
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.extractFileNameFromPath_ = function (path) {
|
||||
var parts = [];
|
||||
if (path.indexOf('/') !== -1) {
|
||||
parts = path.split('/');
|
||||
} else if (path.indexOf('\\') !== -1) {
|
||||
parts = path.split('\\');
|
||||
} else {
|
||||
parts = [path];
|
||||
}
|
||||
return parts[parts.length - 1];
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.importImageToPiskel_ = function () {
|
||||
if (this.importedImage_) {
|
||||
if (window.confirm('You are about to create a new Piskel, unsaved changes will be lost.')) {
|
||||
pskl.app.importService.newPiskelFromImage(
|
||||
this.importedImage_,
|
||||
{
|
||||
importType: this.getImportType_(),
|
||||
frameSizeX: this.getImportType_() === 'single' ?
|
||||
this.resizeWidth.val() : this.sanitizeInputValue_(this.frameSizeX, 1),
|
||||
frameSizeY: this.getImportType_() === 'single' ?
|
||||
this.resizeHeight.val() : this.sanitizeInputValue_(this.frameSizeY, 1),
|
||||
frameOffsetX: this.sanitizeInputValue_(this.frameOffsetX, 0),
|
||||
frameOffsetY: this.sanitizeInputValue_(this.frameOffsetY, 0),
|
||||
smoothing: !!this.smoothResize.prop('checked')
|
||||
},
|
||||
this.closeDialog.bind(this)
|
||||
);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.drawFrameGrid_ = function (frameX, frameY, frameW, frameH) {
|
||||
if (!this.importedImage_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the sizes of the source and preview images
|
||||
var width = this.importedImage_.width;
|
||||
var height = this.importedImage_.height;
|
||||
var previewWidth = this.importPreview.width();
|
||||
var previewHeight = this.importPreview.height();
|
||||
|
||||
var canvasWrapper = this.importPreview.children('canvas');
|
||||
var canvas = canvasWrapper.get(0);
|
||||
if (!canvasWrapper.length) {
|
||||
// Create a new canvas for the grid
|
||||
canvas = pskl.utils.CanvasUtils.createCanvas(
|
||||
previewWidth + 1,
|
||||
previewHeight + 1);
|
||||
this.importPreview.append(canvas);
|
||||
canvasWrapper = $(canvas);
|
||||
}
|
||||
|
||||
var context = canvas.getContext('2d');
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.beginPath();
|
||||
|
||||
// Calculate the number of whole frames
|
||||
var countX = Math.floor((width - frameX) / frameW);
|
||||
var countY = Math.floor((height - frameY) / frameH);
|
||||
|
||||
if (countX > 0 && countY > 0) {
|
||||
var scaleX = previewWidth / width;
|
||||
var scaleY = previewHeight / height;
|
||||
var maxWidth = countX * frameW + frameX;
|
||||
var maxHeight = countY * frameH + frameY;
|
||||
|
||||
// Draw the vertical lines
|
||||
for (var x = frameX + 0.5; x < maxWidth + 1 && x < width + 1; x += frameW) {
|
||||
context.moveTo(x * scaleX, frameY * scaleY);
|
||||
context.lineTo(x * scaleX, maxHeight * scaleY);
|
||||
}
|
||||
|
||||
// Draw the horizontal lines
|
||||
for (var y = frameY + 0.5; y < maxHeight + 1 && y < height + 1; y += frameH) {
|
||||
context.moveTo(frameX * scaleX, y * scaleY);
|
||||
context.lineTo(maxWidth * scaleX, y * scaleY);
|
||||
}
|
||||
|
||||
// Set the line style to dashed
|
||||
context.lineWidth = 1;
|
||||
context.setLineDash([2, 1]);
|
||||
context.strokeStyle = '#000000';
|
||||
context.stroke();
|
||||
|
||||
// Show the canvas
|
||||
canvasWrapper.show();
|
||||
this.importPreview.addClass('no-border');
|
||||
} else {
|
||||
this.hideFrameGrid_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportImageController.prototype.hideFrameGrid_ = function() {
|
||||
this.importPreview.children('canvas').hide();
|
||||
this.importPreview.removeClass('no-border');
|
||||
};
|
||||
|
||||
})();
|
11
src/js/controller/dialogs/PerformanceInfoController.js
Normal file
@ -0,0 +1,11 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
|
||||
ns.PerformanceInfoController = function () {};
|
||||
|
||||
pskl.utils.inherit(ns.PerformanceInfoController, ns.AbstractDialogController);
|
||||
|
||||
ns.PerformanceInfoController.prototype.init = function () {
|
||||
this.superclass.init.call(this);
|
||||
};
|
||||
})();
|
13
src/js/controller/dialogs/UnsupportedBrowserController.js
Normal file
@ -0,0 +1,13 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs');
|
||||
|
||||
ns.UnsupportedBrowserController = function () {};
|
||||
|
||||
pskl.utils.inherit(ns.UnsupportedBrowserController, ns.AbstractDialogController);
|
||||
|
||||
ns.UnsupportedBrowserController.prototype.init = function () {
|
||||
this.superclass.init.call(this);
|
||||
var currentUserAgentElement = document.querySelector('#current-user-agent');
|
||||
currentUserAgentElement.innerText = pskl.utils.UserAgent.getDisplayName();
|
||||
};
|
||||
})();
|
81
src/js/controller/dialogs/backups/BrowseBackups.js
Normal file
@ -0,0 +1,81 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs.backups');
|
||||
|
||||
var stepDefinitions = {
|
||||
'SELECT_SESSION' : {
|
||||
controller : ns.steps.SelectSession,
|
||||
template : 'backups-select-session'
|
||||
},
|
||||
'SESSION_DETAILS' : {
|
||||
controller : ns.steps.SessionDetails,
|
||||
template : 'backups-session-details'
|
||||
},
|
||||
};
|
||||
|
||||
ns.BrowseBackups = function (piskelController, args) {
|
||||
this.piskelController = piskelController;
|
||||
|
||||
// Backups data object used by steps to communicate and share their
|
||||
// results.
|
||||
this.backupsData = {
|
||||
sessions: [],
|
||||
selectedSession : null
|
||||
};
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.BrowseBackups, pskl.controller.dialogs.AbstractDialogController);
|
||||
|
||||
ns.BrowseBackups.prototype.init = function () {
|
||||
this.superclass.init.call(this);
|
||||
|
||||
// Prepare wizard steps.
|
||||
this.steps = this.createSteps_();
|
||||
|
||||
// Start wizard widget.
|
||||
var wizardContainer = document.querySelector('.backups-wizard-container');
|
||||
this.wizard = new pskl.widgets.Wizard(this.steps, wizardContainer);
|
||||
this.wizard.init();
|
||||
|
||||
this.wizard.goTo('SELECT_SESSION');
|
||||
};
|
||||
|
||||
ns.BrowseBackups.prototype.back = function () {
|
||||
this.wizard.back();
|
||||
this.wizard.getCurrentStep().instance.onShow();
|
||||
};
|
||||
|
||||
ns.BrowseBackups.prototype.next = function () {
|
||||
var step = this.wizard.getCurrentStep();
|
||||
if (step.name === 'SELECT_SESSION') {
|
||||
this.wizard.goTo('SESSION_DETAILS');
|
||||
}
|
||||
};
|
||||
|
||||
ns.BrowseBackups.prototype.destroy = function (file) {
|
||||
Object.keys(this.steps).forEach(function (stepName) {
|
||||
var step = this.steps[stepName];
|
||||
step.instance.destroy();
|
||||
step.instance = null;
|
||||
step.el = null;
|
||||
}.bind(this));
|
||||
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.BrowseBackups.prototype.createSteps_ = function () {
|
||||
var steps = {};
|
||||
Object.keys(stepDefinitions).forEach(function (stepName) {
|
||||
var definition = stepDefinitions[stepName];
|
||||
var el = pskl.utils.Template.getAsHTML(definition.template);
|
||||
var instance = new definition.controller(this.piskelController, this, el);
|
||||
instance.init();
|
||||
steps[stepName] = {
|
||||
name: stepName,
|
||||
el: el,
|
||||
instance: instance
|
||||
};
|
||||
}.bind(this));
|
||||
|
||||
return steps;
|
||||
};
|
||||
})();
|
101
src/js/controller/dialogs/backups/steps/SelectSession.js
Normal file
@ -0,0 +1,101 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs.backups.steps');
|
||||
|
||||
// Should match the transition duration for.session-item defined in dialogs-browse-backups.css
|
||||
var DELETE_TRANSITION_DURATION = 500;
|
||||
/**
|
||||
* Helper that returns a promise that will resolve after waiting for a
|
||||
* given time (in ms).
|
||||
*
|
||||
* @param {Number} time
|
||||
* The time to wait.
|
||||
* @return {Promise} promise that resolves after time.
|
||||
*/
|
||||
var wait = function (time) {
|
||||
var deferred = Q.defer();
|
||||
setTimeout(function () {
|
||||
deferred.resolve();
|
||||
}, time);
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ns.SelectSession = function (piskelController, backupsController, container) {
|
||||
this.piskelController = piskelController;
|
||||
this.backupsController = backupsController;
|
||||
this.container = container;
|
||||
};
|
||||
|
||||
ns.SelectSession.prototype.addEventListener = function (el, type, cb) {
|
||||
pskl.utils.Event.addEventListener(el, type, cb, this);
|
||||
};
|
||||
|
||||
ns.SelectSession.prototype.init = function () {
|
||||
this.addEventListener(this.container, 'click', this.onContainerClick_);
|
||||
};
|
||||
|
||||
ns.SelectSession.prototype.onShow = function () {
|
||||
this.update();
|
||||
};
|
||||
|
||||
ns.SelectSession.prototype.update = function () {
|
||||
pskl.app.backupService.list().then(function (sessions) {
|
||||
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);
|
||||
};
|
||||
|
||||
ns.SelectSession.prototype.onContainerClick_ = function (evt) {
|
||||
var sessionId = evt.target.dataset.sessionId;
|
||||
if (!sessionId) {
|
||||
return;
|
||||
}
|
||||
|
||||
var action = evt.target.dataset.action;
|
||||
if (action == 'view') {
|
||||
this.backupsController.backupsData.selectedSession = sessionId;
|
||||
this.backupsController.next();
|
||||
} else if (action == 'delete') {
|
||||
if (window.confirm('Are you sure you want to delete this session?')) {
|
||||
evt.target.closest('.session-item').classList.add('deleting');
|
||||
Q.all([
|
||||
pskl.app.backupService.deleteSession(sessionId),
|
||||
// Wait for 500ms for the .hide opacity transition.
|
||||
wait(DELETE_TRANSITION_DURATION)
|
||||
]).then(function () {
|
||||
// Refresh the list of sessions
|
||||
this.update();
|
||||
}.bind(this));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
})();
|
102
src/js/controller/dialogs/backups/steps/SessionDetails.js
Normal file
@ -0,0 +1,102 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs.backups.steps');
|
||||
|
||||
// Should match the preview dimensions defined in dialogs-browse-backups.css
|
||||
var PREVIEW_SIZE = 60;
|
||||
|
||||
ns.SessionDetails = function (piskelController, backupsController, container) {
|
||||
this.piskelController = piskelController;
|
||||
this.backupsController = backupsController;
|
||||
this.container = container;
|
||||
};
|
||||
|
||||
ns.SessionDetails.prototype.init = function () {
|
||||
this.backButton = this.container.querySelector('.back-button');
|
||||
this.addEventListener(this.backButton, 'click', this.onBackClick_);
|
||||
this.addEventListener(this.container, 'click', this.onContainerClick_);
|
||||
};
|
||||
|
||||
ns.SessionDetails.prototype.destroy = function () {
|
||||
pskl.utils.Event.removeAllEventListeners(this);
|
||||
};
|
||||
|
||||
ns.SessionDetails.prototype.addEventListener = function (el, type, cb) {
|
||||
pskl.utils.Event.addEventListener(el, type, cb, this);
|
||||
};
|
||||
|
||||
ns.SessionDetails.prototype.onShow = function () {
|
||||
var sessionId = this.backupsController.backupsData.selectedSession;
|
||||
pskl.app.backupService.getSnapshotsBySessionId(sessionId).then(function (snapshots) {
|
||||
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),
|
||||
function (piskel) {
|
||||
var selector = '.snapshot-item[data-snapshot-id="' + snapshot.id + '"] .snapshot-preview';
|
||||
var previewContainer = this.container.querySelector(selector);
|
||||
if (!previewContainer) {
|
||||
return;
|
||||
}
|
||||
var image = this.getFirstFrameAsImage_(piskel);
|
||||
previewContainer.appendChild(image);
|
||||
}.bind(this)
|
||||
);
|
||||
};
|
||||
|
||||
ns.SessionDetails.prototype.getFirstFrameAsImage_ = function (piskel) {
|
||||
var frame = pskl.utils.LayerUtils.mergeFrameAt(piskel.getLayers(), 0);
|
||||
var wZoom = PREVIEW_SIZE / piskel.width;
|
||||
var hZoom = PREVIEW_SIZE / piskel.height;
|
||||
var zoom = Math.min(hZoom, wZoom);
|
||||
return pskl.utils.FrameUtils.toImage(frame, zoom);
|
||||
};
|
||||
|
||||
ns.SessionDetails.prototype.onBackClick_ = function () {
|
||||
this.backupsController.back(this);
|
||||
};
|
||||
|
||||
ns.SessionDetails.prototype.onContainerClick_ = function (evt) {
|
||||
var action = evt.target.dataset.action;
|
||||
if (action == 'load' && window.confirm(Constants.CONFIRM_OVERWRITE)) {
|
||||
var snapshotId = evt.target.dataset.snapshotId * 1;
|
||||
pskl.app.backupService.loadSnapshotById(snapshotId).then(function () {
|
||||
$.publish(Events.DIALOG_HIDE);
|
||||
});
|
||||
}
|
||||
};
|
||||
})();
|
202
src/js/controller/dialogs/importwizard/ImportWizard.js
Normal file
@ -0,0 +1,202 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs.importwizard');
|
||||
|
||||
var stepDefinitions = {
|
||||
'IMAGE_IMPORT' : {
|
||||
controller : ns.steps.ImageImport,
|
||||
template : 'import-image-import'
|
||||
},
|
||||
'ADJUST_SIZE' : {
|
||||
controller : ns.steps.AdjustSize,
|
||||
template : 'import-adjust-size'
|
||||
},
|
||||
'INSERT_LOCATION' : {
|
||||
controller : ns.steps.InsertLocation,
|
||||
template : 'import-insert-location'
|
||||
},
|
||||
'SELECT_MODE' : {
|
||||
controller : ns.steps.SelectMode,
|
||||
template : 'import-select-mode'
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportWizard = function (piskelController, args) {
|
||||
this.piskelController = piskelController;
|
||||
|
||||
// Merge data object used by steps to communicate and share their
|
||||
// results.
|
||||
this.mergeData = {
|
||||
rawFiles : [],
|
||||
mergePiskel: null,
|
||||
origin: null,
|
||||
resize: null,
|
||||
insertIndex: null,
|
||||
insertMode: null
|
||||
};
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ImportWizard, pskl.controller.dialogs.AbstractDialogController);
|
||||
|
||||
ns.ImportWizard.prototype.init = function (initArgs) {
|
||||
this.superclass.init.call(this);
|
||||
|
||||
// Prepare mergeData object and wizard steps.
|
||||
this.mergeData.rawFiles = initArgs.rawFiles;
|
||||
this.steps = this.createSteps_();
|
||||
|
||||
// Start wizard widget.
|
||||
var wizardContainer = document.querySelector('.import-wizard-container');
|
||||
this.wizard = new pskl.widgets.Wizard(this.steps, wizardContainer);
|
||||
this.wizard.init();
|
||||
|
||||
if (this.hasSingleImage_()) {
|
||||
this.wizard.goTo('IMAGE_IMPORT');
|
||||
} else if (this.hasSinglePiskelFile_()) {
|
||||
// If a piskel file was provided we can directly go to
|
||||
pskl.utils.PiskelFileUtils.loadFromFile(this.mergeData.rawFiles[0],
|
||||
// onSuccess
|
||||
function (piskel) {
|
||||
this.mergeData.mergePiskel = piskel;
|
||||
this.wizard.goTo('SELECT_MODE');
|
||||
}.bind(this),
|
||||
// onError
|
||||
function (reason) {
|
||||
this.closeDialog();
|
||||
$.publish(Events.PISKEL_FILE_IMPORT_FAILED, [reason]);
|
||||
}.bind(this)
|
||||
);
|
||||
} else {
|
||||
console.error('Unsupported import. Only single piskel or single image are supported at the moment.');
|
||||
this.closeDialog();
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.back = function () {
|
||||
this.wizard.back();
|
||||
this.wizard.getCurrentStep().instance.onShow();
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.next = function () {
|
||||
var step = this.wizard.getCurrentStep();
|
||||
|
||||
if (step.name === 'IMAGE_IMPORT') {
|
||||
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_();
|
||||
} else if (this.hasSameSize_()) {
|
||||
this.wizard.goTo('INSERT_LOCATION');
|
||||
} else {
|
||||
this.wizard.goTo('ADJUST_SIZE');
|
||||
}
|
||||
} else if (step.name === 'ADJUST_SIZE') {
|
||||
this.wizard.goTo('INSERT_LOCATION');
|
||||
} else if (step.name === 'INSERT_LOCATION') {
|
||||
this.finalizeImport_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.destroy = function (file) {
|
||||
Object.keys(this.steps).forEach(function (stepName) {
|
||||
var step = this.steps[stepName];
|
||||
step.instance.destroy();
|
||||
step.instance = null;
|
||||
step.el = null;
|
||||
}.bind(this));
|
||||
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.createSteps_ = function () {
|
||||
// The IMAGE_IMPORT step is used only if there is a single image file
|
||||
// being imported.
|
||||
var hasSingleImage = this.hasSingleImage_();
|
||||
|
||||
var steps = {};
|
||||
Object.keys(stepDefinitions).forEach(function (stepName) {
|
||||
if (stepName === 'IMAGE_IMPORT' && !hasSingleImage) {
|
||||
return;
|
||||
}
|
||||
|
||||
var definition = stepDefinitions[stepName];
|
||||
var el = pskl.utils.Template.getAsHTML(definition.template);
|
||||
var instance = new definition.controller(this.piskelController, this, el);
|
||||
instance.init();
|
||||
steps[stepName] = {
|
||||
name: stepName,
|
||||
el: el,
|
||||
instance: instance
|
||||
};
|
||||
}.bind(this));
|
||||
|
||||
if (hasSingleImage) {
|
||||
steps.IMAGE_IMPORT.el.classList.add('import-first-step');
|
||||
} else {
|
||||
steps.SELECT_MODE.el.classList.add('import-first-step');
|
||||
}
|
||||
|
||||
return steps;
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.finalizeImport_ = function () {
|
||||
var piskel = this.mergeData.mergePiskel;
|
||||
var mode = this.mergeData.importMode;
|
||||
|
||||
if (mode === ns.steps.SelectMode.MODES.REPLACE) {
|
||||
// Replace the current piskel and close the dialog.
|
||||
if (window.confirm(Constants.CONFIRM_OVERWRITE)) {
|
||||
this.piskelController.setPiskel(piskel);
|
||||
this.closeDialog();
|
||||
}
|
||||
} else if (mode === ns.steps.SelectMode.MODES.MERGE) {
|
||||
var merge = pskl.utils.MergeUtils.merge(this.piskelController.getPiskel(), piskel, {
|
||||
insertIndex: this.mergeData.insertIndex,
|
||||
insertMode: this.mergeData.insertMode,
|
||||
origin: this.mergeData.origin,
|
||||
resize: this.mergeData.resize
|
||||
});
|
||||
this.piskelController.setPiskel(merge);
|
||||
|
||||
// Set the first imported layer as selected.
|
||||
var importedLayers = piskel.getLayers().length;
|
||||
var currentLayers = this.piskelController.getLayers().length;
|
||||
this.piskelController.setCurrentLayerIndex(currentLayers - importedLayers);
|
||||
|
||||
this.closeDialog();
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.hasSameSize_ = function () {
|
||||
var piskel = this.mergeData.mergePiskel;
|
||||
if (!piskel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return piskel.width === this.piskelController.getWidth() &&
|
||||
piskel.height === this.piskelController.getHeight();
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.hasSingleImage_ = function () {
|
||||
if (this.mergeData.rawFiles.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var file = this.mergeData.rawFiles[0];
|
||||
return file.type.indexOf('image') === 0;
|
||||
};
|
||||
|
||||
ns.ImportWizard.prototype.hasSinglePiskelFile_ = function () {
|
||||
if (this.mergeData.rawFiles.length !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
var file = this.mergeData.rawFiles[0];
|
||||
return (/\.piskel$/).test(file.name);
|
||||
};
|
||||
})();
|
@ -0,0 +1,65 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs.importwizard.steps');
|
||||
|
||||
ns.AbstractImportStep = function (piskelController, importController, container) {
|
||||
this.piskelController = piskelController;
|
||||
this.container = container;
|
||||
this.importController = importController;
|
||||
this.mergeData = this.importController.mergeData;
|
||||
};
|
||||
|
||||
ns.AbstractImportStep.prototype.init = function () {
|
||||
this.nextButton = this.container.querySelector('.import-next-button');
|
||||
this.backButton = this.container.querySelector('.import-back-button');
|
||||
|
||||
this.addEventListener(this.nextButton, 'click', this.onNextClick);
|
||||
this.addEventListener(this.backButton, 'click', this.onBackClick);
|
||||
};
|
||||
|
||||
ns.AbstractImportStep.prototype.addEventListener = function (el, type, cb) {
|
||||
pskl.utils.Event.addEventListener(el, type, cb, this);
|
||||
};
|
||||
|
||||
ns.AbstractImportStep.prototype.destroy = function () {
|
||||
if (this.framePickerWidget) {
|
||||
this.framePickerWidget.destroy();
|
||||
}
|
||||
|
||||
pskl.utils.Event.removeAllEventListeners(this);
|
||||
};
|
||||
|
||||
ns.AbstractImportStep.prototype.onNextClick = function () {
|
||||
this.importController.next(this);
|
||||
};
|
||||
|
||||
ns.AbstractImportStep.prototype.onBackClick = function () {
|
||||
this.importController.back(this);
|
||||
};
|
||||
|
||||
ns.AbstractImportStep.prototype.onShow = function () {
|
||||
var mergePiskel = this.mergeData.mergePiskel;
|
||||
if (!mergePiskel) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!this.framePickerWidget) {
|
||||
var framePickerContainer = this.container.querySelector('.import-preview');
|
||||
this.framePickerWidget = new pskl.widgets.FramePicker(mergePiskel, framePickerContainer);
|
||||
this.framePickerWidget.init();
|
||||
} else if (this.framePickerWidget.piskel != mergePiskel) {
|
||||
// If the piskel displayed by the frame picker is different from the previous one,
|
||||
// refresh the widget.
|
||||
this.framePickerWidget.piskel = mergePiskel;
|
||||
this.framePickerWidget.setFrameIndex(1);
|
||||
}
|
||||
|
||||
var metaHtml = pskl.utils.Template.getAndReplace('import-meta-content', {
|
||||
name : mergePiskel.getDescriptor().name,
|
||||
dimensions : pskl.utils.StringUtils.formatSize(mergePiskel.getWidth(), mergePiskel.getHeight()),
|
||||
frames : mergePiskel.getFrameCount(),
|
||||
layers : mergePiskel.getLayers().length
|
||||
});
|
||||
this.container.querySelector('.import-meta').innerHTML = metaHtml;
|
||||
};
|
||||
|
||||
})();
|
109
src/js/controller/dialogs/importwizard/steps/AdjustSize.js
Normal file
@ -0,0 +1,109 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs.importwizard.steps');
|
||||
|
||||
ns.AdjustSize = function (piskelController, importController, container) {
|
||||
this.superclass.constructor.apply(this, arguments);
|
||||
};
|
||||
|
||||
ns.AdjustSize.OPTIONS = {
|
||||
KEEP: 'keep',
|
||||
EXPAND: 'expand'
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.AdjustSize, ns.AbstractImportStep);
|
||||
|
||||
ns.AdjustSize.prototype.init = function () {
|
||||
this.superclass.init.call(this);
|
||||
|
||||
// Create anchor widget
|
||||
var anchorContainer = this.container.querySelector('.import-resize-anchor-container');
|
||||
this.anchorWidget = new pskl.widgets.AnchorWidget(anchorContainer, this.onAnchorChange_.bind(this));
|
||||
this.anchorWidget.setOrigin('TOPLEFT');
|
||||
|
||||
this.resizeInfoContainer = this.container.querySelector('.import-resize-info');
|
||||
this.addEventListener(this.resizeInfoContainer, 'change', this.onResizeOptionChange_);
|
||||
|
||||
// By default, set the mode to expand to avoid losing any image content.
|
||||
this.mergeData.resize = ns.AdjustSize.OPTIONS.EXPAND;
|
||||
};
|
||||
|
||||
ns.AdjustSize.prototype.destroy = function () {
|
||||
this.anchorWidget.destroy();
|
||||
this.superclass.destroy.call(this);
|
||||
};
|
||||
|
||||
ns.AdjustSize.prototype.onShow = function () {
|
||||
this.refresh_();
|
||||
this.superclass.onShow.call(this);
|
||||
};
|
||||
|
||||
ns.AdjustSize.prototype.refresh_ = function () {
|
||||
var isBigger = this.isImportedPiskelBigger_();
|
||||
var keep = this.mergeData.resize === ns.AdjustSize.OPTIONS.KEEP;
|
||||
|
||||
// Refresh resize partial
|
||||
var size = this.formatPiskelSize_(this.piskelController.getPiskel());
|
||||
var newSize = this.formatPiskelSize_(this.mergeData.mergePiskel);
|
||||
var markup;
|
||||
if (isBigger) {
|
||||
markup = pskl.utils.Template.getAndReplace('import-resize-bigger-partial', {
|
||||
size : size,
|
||||
newSize : newSize,
|
||||
keepChecked : keep ? 'checked="checked"' : '',
|
||||
expandChecked : keep ? '' : 'checked="checked"'
|
||||
});
|
||||
} else {
|
||||
markup = pskl.utils.Template.getAndReplace('import-resize-smaller-partial', {
|
||||
size : size,
|
||||
newSize : newSize
|
||||
});
|
||||
}
|
||||
this.resizeInfoContainer.innerHTML = markup;
|
||||
|
||||
// Update anchor widget
|
||||
if (this.mergeData.origin) {
|
||||
this.anchorWidget.setOrigin(this.mergeData.origin);
|
||||
}
|
||||
|
||||
// Update anchor widget info
|
||||
var anchorInfo = this.container.querySelector('.import-resize-anchor-info');
|
||||
if (isBigger && keep) {
|
||||
anchorInfo.innerHTML = [
|
||||
'<div class="import-resize-warning">',
|
||||
' Imported content will be cropped!',
|
||||
'</div>',
|
||||
'Select crop anchor:'
|
||||
].join('');
|
||||
} else if (isBigger) {
|
||||
anchorInfo.innerHTML = 'Select resize anchor:';
|
||||
} else {
|
||||
anchorInfo.innerHTML = 'Select position anchor:';
|
||||
}
|
||||
};
|
||||
|
||||
ns.AdjustSize.prototype.onAnchorChange_ = function (origin) {
|
||||
this.mergeData.origin = origin;
|
||||
};
|
||||
|
||||
ns.AdjustSize.prototype.onResizeOptionChange_ = function () {
|
||||
var value = this.resizeInfoContainer.querySelector(':checked').value;
|
||||
if (this.mergeData.resize != value) {
|
||||
this.mergeData.resize = value;
|
||||
this.refresh_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.AdjustSize.prototype.isImportedPiskelBigger_ = function () {
|
||||
var piskel = this.mergeData.mergePiskel;
|
||||
if (!piskel) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return piskel.width > this.piskelController.getWidth() ||
|
||||
piskel.height > this.piskelController.getHeight();
|
||||
};
|
||||
|
||||
ns.AdjustSize.prototype.formatPiskelSize_ = function (piskel) {
|
||||
return pskl.utils.StringUtils.formatSize(piskel.width, piskel.height);
|
||||
};
|
||||
})();
|
282
src/js/controller/dialogs/importwizard/steps/ImageImport.js
Normal file
@ -0,0 +1,282 @@
|
||||
(function () {
|
||||
var ns = $.namespace('pskl.controller.dialogs.importwizard.steps');
|
||||
|
||||
ns.ImageImport = function (piskelController, importController, container) {
|
||||
this.superclass.constructor.apply(this, arguments);
|
||||
this.importedImage_ = null;
|
||||
this.file_ = null;
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ImageImport, ns.AbstractImportStep);
|
||||
|
||||
ns.ImageImport.prototype.init = function (file) {
|
||||
this.superclass.init.call(this);
|
||||
|
||||
// This step is only used if rawFiles contains a single image.
|
||||
this.file_ = this.mergeData.rawFiles[0];
|
||||
|
||||
this.importPreview = this.container.querySelector('.import-section-preview');
|
||||
|
||||
this.fileNameContainer = this.container.querySelector('.import-image-file-name');
|
||||
|
||||
this.singleImportType = this.container.querySelector('[name=import-type][value=single]');
|
||||
this.sheetImportType = this.container.querySelector('[name=import-type][value=sheet]');
|
||||
|
||||
this.resizeWidth = this.container.querySelector('[name=resize-width]');
|
||||
this.resizeHeight = this.container.querySelector('[name=resize-height]');
|
||||
this.smoothResize = this.container.querySelector('[name=smooth-resize-checkbox]');
|
||||
|
||||
this.frameSizeX = this.container.querySelector('[name=frame-size-x]');
|
||||
this.frameSizeY = this.container.querySelector('[name=frame-size-y]');
|
||||
this.frameOffsetX = this.container.querySelector('[name=frame-offset-x]');
|
||||
this.frameOffsetY = this.container.querySelector('[name=frame-offset-y]');
|
||||
|
||||
this.addEventListener(this.singleImportType, 'change', this.onImportTypeChange_);
|
||||
this.addEventListener(this.sheetImportType, 'change', this.onImportTypeChange_);
|
||||
|
||||
this.addEventListener(this.resizeWidth, 'keyup', this.onResizeInputKeyUp_);
|
||||
this.addEventListener(this.resizeHeight, 'keyup', this.onResizeInputKeyUp_);
|
||||
this.addEventListener(this.frameSizeX, 'keyup', this.onFrameInputKeyUp_);
|
||||
this.addEventListener(this.frameSizeY, 'keyup', this.onFrameInputKeyUp_);
|
||||
this.addEventListener(this.frameOffsetX, 'keyup', this.onFrameInputKeyUp_);
|
||||
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);
|
||||
});
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.onShow = function () {
|
||||
this.container.classList.remove('import-image-loading');
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.createPiskelFromImage = function () {
|
||||
var name = this.extractFileNameFromPath_(this.file_.name);
|
||||
// Remove extension from filename.
|
||||
name = name.replace(/\.[a-zA-Z]+$/, '');
|
||||
|
||||
var deferred = Q.defer();
|
||||
pskl.app.importService.newPiskelFromImage(
|
||||
this.importedImage_,
|
||||
{
|
||||
importType: this.getImportType_(),
|
||||
frameSizeX: this.getImportType_() === 'single' ?
|
||||
this.resizeWidth.value : this.sanitizeInputValue_(this.frameSizeX, 1),
|
||||
frameSizeY: this.getImportType_() === 'single' ?
|
||||
this.resizeHeight.value : this.sanitizeInputValue_(this.frameSizeY, 1),
|
||||
frameOffsetX: this.sanitizeInputValue_(this.frameOffsetX, 0),
|
||||
frameOffsetY: this.sanitizeInputValue_(this.frameOffsetY, 0),
|
||||
smoothing: !!this.smoothResize.checked,
|
||||
name: name
|
||||
},
|
||||
deferred.resolve
|
||||
);
|
||||
return deferred.promise;
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.onImportTypeChange_ = function (evt) {
|
||||
if (this.getImportType_() === 'single') {
|
||||
// Using single image, so remove the frame grid
|
||||
this.hideFrameGrid_();
|
||||
} else {
|
||||
// Using spritesheet import, so draw the frame grid in the preview
|
||||
var x = this.sanitizeInputValue_(this.frameOffsetX, 0);
|
||||
var y = this.sanitizeInputValue_(this.frameOffsetY, 0);
|
||||
var w = this.sanitizeInputValue_(this.frameSizeX, 1);
|
||||
var h = this.sanitizeInputValue_(this.frameSizeY, 1);
|
||||
this.drawFrameGrid_(x, y, w, h);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.onResizeInputKeyUp_ = function (evt) {
|
||||
var from = evt.target.getAttribute('name');
|
||||
if (this.importedImage_) {
|
||||
this.synchronizeResizeFields_(evt.target.value, from);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.onFrameInputKeyUp_ = function (evt) {
|
||||
if (this.importedImage_) {
|
||||
this.synchronizeFrameFields_(evt.target.value);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.synchronizeResizeFields_ = function (value, from) {
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
}
|
||||
var height = this.importedImage_.height;
|
||||
var width = this.importedImage_.width;
|
||||
|
||||
// Select single image import type since the user changed a value here
|
||||
this.singleImportType.checked = true;
|
||||
|
||||
if (from === 'resize-width') {
|
||||
this.resizeHeight.value = Math.round(value * height / width);
|
||||
} else {
|
||||
this.resizeWidth.value = Math.round(value * width / height);
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.synchronizeFrameFields_ = function (value) {
|
||||
value = parseInt(value, 10);
|
||||
if (isNaN(value)) {
|
||||
value = 0;
|
||||
}
|
||||
|
||||
// Parse the frame input values
|
||||
var frameSizeX = this.sanitizeInputValue_(this.frameSizeX, 1);
|
||||
var frameSizeY = this.sanitizeInputValue_(this.frameSizeY, 1);
|
||||
var frameOffsetX = this.sanitizeInputValue_(this.frameOffsetX, 0);
|
||||
var frameOffsetY = this.sanitizeInputValue_(this.frameOffsetY, 0);
|
||||
|
||||
// Select spritesheet import type since the user changed a value here
|
||||
this.sheetImportType.checked = true;
|
||||
|
||||
// Draw the grid
|
||||
this.drawFrameGrid_(frameOffsetX, frameOffsetY, frameSizeX, frameSizeY);
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.sanitizeInputValue_ = function(input, minValue) {
|
||||
var value = parseInt(input.value, 10);
|
||||
if (value <= minValue || isNaN(value)) {
|
||||
input.value = minValue;
|
||||
value = minValue;
|
||||
}
|
||||
return value;
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.getImportType_ = function () {
|
||||
if (this.singleImportType.checked) {
|
||||
return this.singleImportType.value;
|
||||
} else if (this.sheetImportType.checked) {
|
||||
return this.sheetImportType.value;
|
||||
} else {
|
||||
throw 'Could not find the currently selected import type';
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.onImageLoaded_ = function (image) {
|
||||
this.importedImage_ = image;
|
||||
|
||||
var w = this.importedImage_.width;
|
||||
var h = this.importedImage_.height;
|
||||
|
||||
// FIXME : We remove the onload callback here because JsGif will insert
|
||||
// the image again and we want to avoid retriggering the image onload
|
||||
this.importedImage_.onload = function () {};
|
||||
|
||||
var fileName = this.extractFileNameFromPath_(this.file_.name);
|
||||
this.fileNameContainer.textContent = fileName;
|
||||
this.fileNameContainer.setAttribute('title', fileName);
|
||||
|
||||
this.resizeWidth.value = w;
|
||||
this.resizeHeight.value = h;
|
||||
|
||||
this.frameSizeX.value = w;
|
||||
this.frameSizeY.value = h;
|
||||
this.frameOffsetX.value = 0;
|
||||
this.frameOffsetY.value = 0;
|
||||
|
||||
this.importPreview.innerHTML = '';
|
||||
this.importPreview.appendChild(this.createImagePreview_());
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.createImagePreview_ = function () {
|
||||
var image = document.createElement('IMG');
|
||||
image.src = this.importedImage_.src;
|
||||
return image;
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.extractFileNameFromPath_ = function (path) {
|
||||
var parts = [];
|
||||
if (path.indexOf('/') !== -1) {
|
||||
parts = path.split('/');
|
||||
} else if (path.indexOf('\\') !== -1) {
|
||||
parts = path.split('\\');
|
||||
} else {
|
||||
parts = [path];
|
||||
}
|
||||
return parts[parts.length - 1];
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.drawFrameGrid_ = function (frameX, frameY, frameW, frameH) {
|
||||
if (!this.importedImage_) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Grab the sizes of the source and preview images
|
||||
var width = this.importedImage_.width;
|
||||
var height = this.importedImage_.height;
|
||||
|
||||
var image = this.importPreview.querySelector('img');
|
||||
var previewWidth = image.offsetWidth;
|
||||
var previewHeight = image.offsetHeight;
|
||||
|
||||
var canvas = this.importPreview.querySelector('canvas');
|
||||
if (!canvas) {
|
||||
// Create a new canvas for the grid
|
||||
canvas = pskl.utils.CanvasUtils.createCanvas(
|
||||
previewWidth + 1,
|
||||
previewHeight + 1);
|
||||
this.importPreview.appendChild(canvas);
|
||||
}
|
||||
|
||||
var context = canvas.getContext('2d');
|
||||
context.clearRect(0, 0, canvas.width, canvas.height);
|
||||
context.beginPath();
|
||||
|
||||
// Calculate the number of whole frames
|
||||
var countX = Math.floor((width - frameX) / frameW);
|
||||
var countY = Math.floor((height - frameY) / frameH);
|
||||
|
||||
if (countX > 0 && countY > 0) {
|
||||
var scaleX = previewWidth / width;
|
||||
var scaleY = previewHeight / height;
|
||||
var maxWidth = countX * frameW + frameX;
|
||||
var maxHeight = countY * frameH + frameY;
|
||||
|
||||
// Draw the vertical lines
|
||||
for (var x = frameX + 0.5; x < maxWidth + 1 && x < width + 1; x += frameW) {
|
||||
context.moveTo(x * scaleX, frameY * scaleY);
|
||||
context.lineTo(x * scaleX, maxHeight * scaleY);
|
||||
}
|
||||
|
||||
// Draw the horizontal lines
|
||||
for (var y = frameY + 0.5; y < maxHeight + 1 && y < height + 1; y += frameH) {
|
||||
context.moveTo(frameX * scaleX, y * scaleY);
|
||||
context.lineTo(maxWidth * scaleX, y * scaleY);
|
||||
}
|
||||
|
||||
context.lineWidth = 1;
|
||||
context.strokeStyle = 'gold';
|
||||
context.stroke();
|
||||
|
||||
// Show the canvas
|
||||
canvas.style.display = 'block';
|
||||
} else {
|
||||
this.hideFrameGrid_();
|
||||
}
|
||||
};
|
||||
|
||||
ns.ImageImport.prototype.hideFrameGrid_ = function() {
|
||||
var canvas = this.importPreview.querySelector('canvas');
|
||||
if (canvas) {
|
||||
canvas.style.display = 'none';
|
||||
}
|
||||
};
|
||||
})();
|