20 Commits

Author SHA1 Message Date
dc61be27f0 Update README.md 2014-11-26 08:55:53 +01:00
7fd49aaccb Removed localhost url ... 2014-11-26 07:48:15 +01:00
cffaec09b2 Prepare release 0.4.0 2014-11-25 22:54:18 +01:00
62a7755407 Merge pull request #235 from juliandescottes/feature-add-effects
Feature add effects
2014-11-25 22:43:12 +01:00
2ab1e29365 Merge branch 'master' into feature-add-effects 2014-11-23 21:54:31 +01:00
fe110a3d8e Merge pull request #233 from juliandescottes/enhancement-move-viewport
Enhancement move viewport
2014-11-23 21:53:34 +01:00
5afec16258 Cleanup of console.log in MinimapController.js-n 2014-11-23 21:48:32 +01:00
fad483ce7a Increased movement speed 2014-11-23 21:44:51 +01:00
b10e87d2b7 Fix for issue #189 : user can move the viewport via click n drag of middle mouse button 2014-11-23 21:37:34 +01:00
61ee1d9b32 Added clone tool + icon 2014-11-23 16:27:12 +01:00
ce1a5c4918 Rotate non square sprites, added rotate icon, unit tests for transforms 2014-11-23 15:03:35 +01:00
796cd4466e Added Rotate tool + abstract Transform tool 2014-11-22 00:07:11 +01:00
0f49c884f2 Mutualize HTML generation for drawing tools and transform 2014-11-21 01:15:55 +01:00
c8dae1cb79 Added mirror transformation 2014-11-19 23:00:25 +01:00
54837d0e21 Issue #228 : Zoom is very slow on Firefox 2014-11-01 14:00:35 +01:00
001e35cf7b Merge pull request #229 from etumyan/fps-oninput
Combining oninput and onchange events for the FPS counter. Close #225
2014-11-01 13:57:49 +01:00
ac5083633b Combining oninput and onchange events for the FPS counter. 2014-10-31 22:38:11 +04:00
c32af500dc add notification if image upload fails 2014-10-01 01:21:49 +02:00
dc4de32162 Added support for .PAL palettes 2014-09-30 00:58:15 +02:00
243990a90f Fixed : cache issue coming from piskel-boot file 2014-09-30 00:19:54 +02:00
74 changed files with 1396 additions and 568 deletions

View File

@ -161,7 +161,7 @@ module.exports = function(grunt) {
]
},
files: [
{expand: true, flatten: true, src: ['src/piskel-boot-0.1.0.js'], dest: 'dest/'}
{src: ['src/piskel-boot.js'], dest: 'dest/piskel-boot.js'}
]
},
editor: {
@ -170,6 +170,9 @@ module.exports = function(grunt) {
{
match: /templates\//g,
replacement: "../templates"+version+"/"
},{
match: /piskel-boot.js/g,
replacement: "../piskel-boot"+version+".js"
},{
match: /^(.|[\r\n])*<!--body-main-start-->/,
replacement: "",
@ -194,6 +197,7 @@ module.exports = function(grunt) {
main: {
files: [
{src: ['dest/js/piskel-packaged-min.js'], dest: 'dest/js/piskel-packaged-min' + version + '.js'},
{src: ['dest/piskel-boot.js'], dest: 'dest/piskel-boot' + version + '.js'},
{src: ['src/logo.png'], dest: 'dest/logo.png'},
{src: ['src/js/lib/iframeLoader-0.1.0.js'], dest: 'dest/js/lib/iframeLoader-0.1.0.js'},
{src: ['src/js/lib/gif/gif.ie.worker.js'], dest: 'dest/js/lib/gif/gif.ie.worker.js'},
@ -246,7 +250,7 @@ module.exports = function(grunt) {
},
src: [
'src/js/**/*.js',
'src/piskel-boot-0.1.0.js',
'src/piskel-boot.js',
'src/piskel-script-list.js',
'!src/js/lib/**/*.js'
],

View File

@ -32,7 +32,7 @@ Integrated in **[piskelapp.com](http://piskelapp.com)**, you can share everythin
Piskel supports the following browsers :
* **Chrome** (latest)
* **Firefox** (latest)
* **Internet Explorer** 10+
* **Internet Explorer** 11+
... and a fairly recent computer.

88
misc/icons/SVG/flip.svg Normal file
View File

@ -0,0 +1,88 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<!-- Created with Inkscape (http://www.inkscape.org/) -->
<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"
width="770.71875"
height="581.4375"
id="svg2"
version="1.1"
inkscape:version="0.48.4 r9939"
sodipodi:docname="mirror.svg"
inkscape:export-filename="C:\Development\git\piskel\src\img\tools\flip.png"
inkscape:export-xdpi="35.446629"
inkscape:export-ydpi="35.446629">
<defs
id="defs4" />
<sodipodi:namedview
id="base"
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1.0"
inkscape:pageopacity="0.0"
inkscape:pageshadow="2"
inkscape:zoom="0.7"
inkscape:cx="612.40785"
inkscape:cy="222.08964"
inkscape:document-units="px"
inkscape:current-layer="layer1"
showgrid="false"
fit-margin-top="0"
fit-margin-left="0"
fit-margin-right="0"
fit-margin-bottom="0"
inkscape:window-width="1920"
inkscape:window-height="1148"
inkscape:window-x="-8"
inkscape:window-y="-8"
inkscape:window-maximized="1" />
<metadata
id="metadata7">
<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>
<g
inkscape:label="Layer 1"
inkscape:groupmode="layer"
id="layer1"
transform="translate(-63.5625,-233.7818)">
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 359.2768,233.7907 -295.7143,581.4286 295.7143,0 z"
id="rect2987"
inkscape:connector-curvature="0"
sodipodi:nodetypes="cccc"
inkscape:export-filename="C:\Development\git\piskel\src\img\tools\flip.png"
inkscape:export-xdpi="35.446629"
inkscape:export-ydpi="35.446629" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 538.5625,233.7818 295.71875,581.4375 -295.71875,0 0,-581.4375 z m 29.125,117.4375 0,434.28125 218.59375,0 L 567.6875,351.2193 z"
id="rect2987-1"
inkscape:connector-curvature="0"
inkscape:export-filename="C:\Development\git\piskel\src\img\tools\flip.png"
inkscape:export-xdpi="35.446629"
inkscape:export-ydpi="35.446629" />
<path
style="fill:#ffffff;fill-opacity:1;stroke:none"
d="m 435.5625,233.93805 0,41.28125 25.71875,0 0,-41.28125 -25.71875,0 z m 0,91.28125 0,40 25.71875,0 0,-40 -25.71875,0 z m 0,90 0,40 25.71875,0 0,-40 -25.71875,0 z m 0,90 0,40 25.71875,0 0,-40 -25.71875,0 z m 0,90 0,40 25.71875,0 0,-40 -25.71875,0 z m 0,90 0,40 25.71875,0 0,-40 -25.71875,0 z m 0,90 0,40 25.71875,0 0,-40 -25.71875,0 z"
id="rect3796"
inkscape:export-filename="C:\Development\git\piskel\src\img\tools\flip.png"
inkscape:export-xdpi="35.446629"
inkscape:export-ydpi="35.446629"
inkscape:connector-curvature="0" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 52 KiB

View File

@ -0,0 +1,41 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 15.1.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
width="99.997px" height="69.373px" viewBox="0 0 99.997 69.373" enable-background="new 0 0 99.997 69.373" xml:space="preserve">
<path fill="#010101" d="M81.635,0.222c0.553-0.327,1.242-0.219,1.85-0.133c1.502,0.296,2.658,1.426,3.533,2.62
c0.608-0.379,1.252-0.777,1.983-0.842c0.595-0.015,1.09,0.416,1.394,0.889c0.568,0.909,0.76,2.02,1.442,2.864
C92,5.829,92.246,5.941,92.482,6.044c0.968,0.409,1.846,0.996,2.688,1.615c0.361,0.223,0.396,0.691,0.529,1.056
c0.478,1.579,0.306,3.241,0.149,4.853c-0.035,0.812-0.104,1.659,0.172,2.438c0.42,0.954,1.229,1.655,1.746,2.547
c1.191,2.13,2.146,4.467,2.229,6.937v0.088c-0.071,1.268-0.203,2.647-1.062,3.653c-0.707,0.846-1.85,1.101-2.896,1.223
c-0.747,0.104-1.508,0.127-2.258,0.077c-1.912-0.275-3.812-0.628-5.724-0.911c-0.34-0.052-0.719-0.055-1,0.167
c-0.391,0.281-0.494,0.786-0.537,1.235c-0.068,1.177,0.133,2.405-0.312,3.532c-0.227,0.604-0.768,0.999-1.266,1.371
c-1.092,0.753-2.313,1.291-3.441,1.981c-0.164,0.115-0.125,0.348-0.125,0.521c0.075,0.916,0.332,1.821,0.253,2.747
c-0.021,0.597-0.271,1.188-0.72,1.587c-0.768,0.709-1.434,1.519-2.068,2.346c-0.104,0.142-0.222,0.283-0.256,0.461
c-0.264,1.272-0.385,2.576-0.74,3.83c-0.201,0.641-0.416,1.34-0.943,1.793c-0.633,0.492-1.456-0.342-2.098,0.164
c-1.191,0.882-1.558,2.412-2.379,3.582c-0.469,0.595-1.104,1.039-1.805,1.319c-0.331,4.37-0.625,8.741-0.896,13.115h-5.166
c0.16-2.783,0.32-5.567,0.486-8.351c0.203-1.728-0.097-3.444-0.312-5.152c-0.017-0.364-0.43-0.709-0.785-0.543
c-1.037,0.3-2.131,0.459-3.204,0.289c-0.87-0.227-1.536-0.877-2.11-1.533c-1.765,1.695-4.326,2.275-6.712,2.025
c-0.471-0.726-0.792-1.629-1.603-2.049c-0.539-0.324-1.198-0.155-1.729,0.098c-1.214,0.558-1.945,1.805-3.197,2.305
c-1.1,0.51-2.359,0.188-3.41-0.291c-1.127-0.54-2.176-1.242-3.186-1.975c-0.52,0.236-0.837,0.728-1.123,1.195
c-0.968,0.117-1.964,0.449-2.923,0.103c-1.548-0.399-2.625-1.652-3.94-2.472c-0.886,0.66-1.608,1.58-2.68,1.957
c-0.698,0.24-1.468,0.399-2.196,0.207c-0.825-0.181-1.609-0.5-2.425-0.705c-0.27-0.078-0.558-0.037-0.807,0.082
c-1.433,0.646-2.197,2.23-3.688,2.779c-0.307,0.148-0.632,0.043-0.936-0.047c-0.346,3.812-0.79,7.618-1.159,11.43
c-1.811,0.006-3.623-0.002-5.434,0.004c-0.078-0.656-0.297-1.312-0.188-1.978c0.27-2.282,0.637-4.551,0.9-6.833
c0.181-1.895-0.835-3.648-2.096-4.977c0.154-0.737-0.056-1.502-0.528-2.078c-1.24-1.65-3.362-2.342-4.546-4.043
c-0.357-0.53-0.698-1.256-0.328-1.864c0.285-0.724,0.94-1.381,0.769-2.21c-0.04-0.262-0.165-0.502-0.347-0.691
c-1.07-1.188-1.971-2.514-2.849-3.844c-0.403-0.59-0.372-1.338-0.438-2.02c-0.141-1.194,0.732-2.201,0.798-3.364
c-0.196-0.665-0.84-1.073-1.192-1.654C0.638,31.785,0.077,30.231,0,28.62v-0.446c0.086-0.751,0.078-1.537,0.396-2.239
c0.522-1.006,1.566-1.623,2.075-2.636c-0.222-0.968-0.747-1.833-0.966-2.799c-0.097-1.466,0.425-2.955,1.404-4.049
c0.664-0.035,1.319-0.157,1.968-0.296c0.633-0.125,1.1-0.631,1.448-1.145c0.703-1.045,0.832-2.351,1.479-3.422
c0.255-0.444,0.607-0.855,1.08-1.074c0.692-0.327,1.395-0.631,2.119-0.88c0.38-0.117,0.779-0.237,1.18-0.167
c0.894,0.134,1.771,0.361,2.665,0.5c0.624,0.088,1.321-0.085,1.74-0.58c0.379-0.424,0.483-1.003,0.574-1.544
c0.926-0.306,1.929-0.646,2.907-0.389c1.367,0.311,2.72,0.672,4.091,0.96c0.748-0.367,1.104-1.208,1.849-1.582
c0.884-0.481,1.947-0.333,2.873-0.064c1.13,0.322,1.991,1.168,3.041,1.655c0.735-0.438,1.304-1.316,2.246-1.275
c1.698,0.444,3.091,1.803,4.899,1.868c1.229,0.001,1.779-1.354,2.912-1.594c0.744-0.228,1.496,0.125,2.104,0.54
c0.745,0.517,1.432,1.11,2.132,1.684c1.052-0.622,2.251-1.085,3.492-1.026c1.448,0.261,2.847,0.754,4.294,1.011
c0.615-0.026,0.967-0.649,1.489-0.902c1.062-0.497,2.237-0.755,3.409-0.756c1.316,0.169,2.543,0.712,3.82,1.042
c0.623-0.171,1.135-0.659,1.803-0.686c1.026-0.025,2.055-0.006,3.08-0.008c0.401-0.321,0.769-0.709,1.26-0.9
c0.869-0.37,1.744-0.836,2.703-0.898c0.994,0.08,1.975,0.287,2.964,0.402c0.235-1.401,0.842-2.703,1.481-3.958
c1.241-0.227,2.463-0.58,3.66-0.973C80.409,1.51,80.956,0.784,81.635,0.222z"/>
</svg>

After

Width:  |  Height:  |  Size: 4.2 KiB

View File

@ -0,0 +1,8 @@
Thank you for using The Noun Project. This icon is licensed under Creative
Commons Attribution and must be attributed as:
Sheep by Unrecognized MJ from The Noun Project
If you have a Premium Account or have purchased a license for this icon, you
don't need to worry about attribution! We will share the profits from your
purchase with this icon's designer.

View File

@ -0,0 +1,6 @@
<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" id="Layer_1" x="0px" y="0px" width="89.231px" height="100px" viewBox="0 0 89.231 100" enable-background="new 0 0 89.231 100" xml:space="preserve">
<path d="M14.652,64.026c-0.603-2.09-1-4.267-1.15-6.511H0c0.18,3.858,0.86,7.586,1.962,11.13L14.652,64.026z"/>
<path d="M14.332,88.192l8.684-10.35c-2.899-2.792-5.273-6.127-6.926-9.857L3.402,72.604C5.9,78.563,9.655,83.87,14.332,88.192z"/>
<path d="M42.483,86.499c-6.051-0.409-11.626-2.559-16.245-5.943l-8.681,10.346c6.985,5.336,15.582,8.661,24.926,9.099V86.499z"/>
<path d="M44.589,10.768V0L14.266,17.506l30.323,17.506V24.245c17.186,0,31.166,13.98,31.166,31.165 c0,16.477-12.854,29.999-29.061,31.087v13.502C70.337,98.896,89.231,79.32,89.231,55.41C89.231,30.794,69.205,10.768,44.589,10.768z "/>
</svg>

After

Width:  |  Height:  |  Size: 843 B

View File

@ -0,0 +1,8 @@
Thank you for using The Noun Project. This icon is licensed under Creative
Commons Attribution and must be attributed as:
Undo by Kyle Levi Fox from The Noun Project
If you have a Premium Account or have purchased a license for this icon, you
don't need to worry about attribution! We will share the profits from your
purchase with this icon's designer.

View File

@ -3,7 +3,7 @@
"name": "piskel",
"main": "./dest/index.html",
"description": "Web based 2d animations editor",
"version": "0.3.0",
"version": "0.4.0",
"homepage": "http://github.com/juliandescottes/piskel",
"repository": {
"type": "git",

154
src/css/layout.css Normal file
View File

@ -0,0 +1,154 @@
/**
* Application layout
*/
.main-wrapper {
position: absolute;
top: 5px;
right: 0;
bottom: 5px;
left: 0;
}
.column-wrapper {
text-align: center;
font-size: 0;
position: absolute;
left: 100px; /* Reserve room for tools on the left edge of the screen. */
top: 0;
right: 50px; /* Reserve room for actions on the right edge of the screen. */
bottom: 0;
}
.column {
display: inline-block;
}
.left-column {
vertical-align: top;
height: 100%;
margin-right: 7px;
}
.main-column {
height: 100%;
position: relative;
}
.right-column {
vertical-align: top;
margin-left: 10px;
height: 100%;
position: relative;
}
.drawing-canvas-container {
font-size: 0;
}
.sticky-section {
position: fixed;
top: 0;
bottom: 0;
z-index: 1000;
}
.sticky-section .sticky-section-wrap {
display: table;
height: 100%;
}
.sticky-section .vertical-centerer {
display: table-cell;
vertical-align: middle;
}
.left-sticky-section.sticky-section {
left: 0;
max-width: 100px;
}
.left-sticky-section .tool-icon {
float: left;
}
.cursor-coordinates {
color:#888;
font-size:12px;
font-weight:bold;
font-family:Courier;
}
/**
* Canvases layout
*/
.canvas {
position: relative;
z-index: 1;
}
.canvas-container {
position: relative;
display: block;
}
.canvas-container .canvas-background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.light-picker-background,
.light-canvas-background .canvas-background {
background: url(../img/canvas_background/light_canvas_background.png) repeat;
}
.medium-picker-background,
.medium-canvas-background .canvas-background {
background: url(../img/canvas_background/medium_canvas_background.png) repeat;
}
.lowcont-medium-picker-background,
.lowcont-medium-canvas-background .canvas-background {
background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat;
}
.lowcont-dark-picker-background,
.lowcont-dark-canvas-background .canvas-background {
background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat;
}
.layers-canvas,
.canvas.onion-skin-canvas {
opacity: 0.2;
}
.canvas.canvas-overlay,
.canvas.layers-canvas,
.canvas.onion-skin-canvas {
position: absolute;
top: 0;
left: 0;
}
.tools-wrapper,
.options-wrapper,
.palette-wrapper {
float : left;
}
/**
* Z-indexes should match the drawing area canvas superposition order :
* - 1 : draw layers below current layer
* - 2 : draw current layer
* - 3 : draw layers above current layer
* - 4 : draw the tools overlay
*/
.canvas.layers-below-canvas {z-index: 7;}
.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;}

View File

@ -20,148 +20,10 @@ body {
user-select: initial;
}
/**
* Application layout
*/
.main-wrapper {
position: absolute;
top: 5px;
right: 0;
bottom: 5px;
left: 0;
.no-overflow {
overflow : hidden;
}
.column-wrapper {
text-align: center;
font-size: 0;
position: absolute;
left: 100px; /* Reserve room for tools on the left edge of the screen. */
top: 0;
right: 50px; /* Reserve room for actions on the right edge of the screen. */
bottom: 0;
}
.column {
display: inline-block;
}
.left-column {
vertical-align: top;
height: 100%;
margin-right: 7px;
}
.main-column {
height: 100%;
position: relative;
}
.right-column {
vertical-align: top;
margin-left: 10px;
height: 100%;
position: relative;
}
.drawing-canvas-container {
font-size: 0;
}
.sticky-section {
position: fixed;
top: 0;
bottom: 0;
z-index: 1000;
}
.sticky-section .sticky-section-wrap {
display: table;
height: 100%;
}
.sticky-section .vertical-centerer {
display: table-cell;
vertical-align: middle;
}
.left-sticky-section.sticky-section {
left: 0;
max-width: 100px;
}
.left-sticky-section .tool-icon {
float: left;
}
/**
* Canvases layout
*/
.canvas {
position: relative;
z-index: 1;
}
.canvas-container {
position: relative;
display: block;
}
.canvas-container .canvas-background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
}
.light-picker-background,
.light-canvas-background .canvas-background {
background: url(../img/canvas_background/light_canvas_background.png) repeat;
}
.medium-picker-background,
.medium-canvas-background .canvas-background {
background: url(../img/canvas_background/medium_canvas_background.png) repeat;
}
.lowcont-medium-picker-background,
.lowcont-medium-canvas-background .canvas-background {
background: url(../img/canvas_background/lowcont_medium_canvas_background.png) repeat;
}
.lowcont-dark-picker-background,
.lowcont-dark-canvas-background .canvas-background {
background: url(../img/canvas_background/lowcont_dark_canvas_background.png) repeat;
}
.layers-canvas,
.canvas.onion-skin-canvas {
opacity: 0.2;
}
.canvas.canvas-overlay,
.canvas.layers-canvas,
.canvas.onion-skin-canvas {
position: absolute;
top: 0;
left: 0;
}
/**
* Z-indexes should match the drawing area canvas superposition order :
* - 1 : draw layers below current layer
* - 2 : draw current layer
* - 3 : draw layers above current layer
* - 4 : draw the tools overlay
*/
.canvas.layers-below-canvas {z-index: 7;}
.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;}
.image-link {
color : gold;
}
@ -188,10 +50,3 @@ body {
.pull-left {
left:0;
}
.cursor-coordinates {
color:#888;
font-size:12px;
font-weight:bold;
font-family:Courier;
}

View File

@ -1,10 +1,3 @@
.tools-wrapper,
.options-wrapper,
.palette-wrapper {
float: left;
}
.tool-icon {
position : relative;
cursor : pointer;
@ -88,8 +81,8 @@
.tool-icon.tool-lighten {
background-image: url(../img/tools/lighten.png);
background-size: 30px 30px;
background-position: 8px 8px;
background-size: 30px 30px;
}
.tool-icon.tool-colorpicker {
@ -103,6 +96,24 @@
background-size: 36px 36px;
}
.tool-icon.tool-flip {
background-image: url(../img/tools/flip.png);
background-position: 7px 11px;
background-size: 32px;
}
.tool-icon.tool-rotate {
background-image: url(../img/tools/rotate.png);
background-position: 10px 9px;
background-size: 26px;
}
.tool-icon.tool-clone {
background-image: url(../img/tools/clone.png);
background-position: 9px 15px;
background-size: 30px;
}
/*
* Tool cursors:
*/

View File

@ -0,0 +1,3 @@
.transformations-container .tool-icon {
float:left;
}

BIN
src/img/tools/clone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

BIN
src/img/tools/flip.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

BIN
src/img/tools/rotate.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

View File

@ -44,6 +44,7 @@
<div class="column right-column">
<iframe src="templates/preview.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
<iframe src="templates/layers-list.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
<iframe src="templates/transformations.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
<iframe src="templates/palettes-list.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
<div class="pull-bottom cursor-coordinates"></div>
</div>
@ -75,10 +76,11 @@
<iframe src="templates/cheatsheet.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
<iframe src="templates/misc-templates.html" onload="iframeloader.onLoad(event)" data-iframe-loader="display"></iframe>
<script type="text/javascript" src="piskel-boot.js"></script>
<!--body-main-end-->
<!-- the comment above indicates the end of the markup reused by the editor integrated in piskelapp.com -->
<!-- do not delete, do not move :) -->
<script type="text/javascript" src="piskel-boot-0.1.0.js"></script>
</body>
</html>

View File

@ -87,6 +87,9 @@
this.notificationController = new pskl.controller.NotificationController();
this.notificationController.init();
this.transformationsController = new pskl.controller.TransformationsController();
this.transformationsController.init();
this.progressBarController = new pskl.controller.ProgressBarController();
this.progressBarController.init();

View File

@ -22,7 +22,7 @@
// the oninput event won't work on IE10 unfortunately, but at least will provide a
// consistent behavior across all other browsers that support the input type range
// see https://bugzilla.mozilla.org/show_bug.cgi?id=853670
$("#preview-fps")[0].addEventListener('change', this.onFPSSliderChange.bind(this));
$("#preview-fps").on('input change', this.onFPSSliderChange.bind(this));
document.querySelector(".right-column").style.width = Constants.ANIMATED_PREVIEW_WIDTH + 'px';
this.toggleOnionSkinEl = document.querySelector(".preview-toggle-onion-skin");

View File

@ -10,6 +10,8 @@
this.paletteController = paletteController;
this.dragHandler = new ns.drawing.DragHandler(this);
/**
* @public
*/
@ -138,13 +140,12 @@
var frame = this.piskelController.getCurrentFrame();
var coords = this.getSpriteCoordinates(event.clientX, event.clientY);
this.isClicked = true;
this.setCurrentButton(event);
if (event.button === Constants.MIDDLE_BUTTON) {
if (frame.containsPixel(coords.x, coords.y)) {
$.publish(Events.SELECT_PRIMARY_COLOR, [frame.getPixel(coords.x, coords.y)]);
}
this.dragHandler.startDrag(event.clientX, event.clientY);
} else {
this.isClicked = true;
this.setCurrentButton(event);
this.currentToolBehavior.hideHighlightedPixel(this.overlayFrame);
this.currentToolBehavior.applyToolAt(
@ -174,29 +175,6 @@
}
};
ns.DrawingController.prototype.resetZoom_ = function () {
this.setZoom_(this.calculateZoom_());
};
ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) {
var step = (zoomMultiplier || 1) * this.getZoomStep_();
this.setZoom_(this.renderer.getZoom() + step);
};
ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) {
var step = (zoomMultiplier || 1) * this.getZoomStep_();
this.setZoom_(this.renderer.getZoom() - step);
};
ns.DrawingController.prototype.getZoomStep_ = function () {
return this.calculateZoom_() / 10;
};
ns.DrawingController.prototype.setZoom_ = function (zoom) {
this.compositeRenderer.setZoom(zoom);
$.publish(Events.ZOOM_CHANGED);
};
/**
* @private
*/
@ -209,19 +187,22 @@
var currentFrame = this.piskelController.getCurrentFrame();
if (this.isClicked) {
$.publish(Events.MOUSE_EVENT, [event, this]);
// Warning : do not call setCurrentButton here
// mousemove do not have the correct mouse button information on all browsers
this.currentToolBehavior.moveToolAt(
coords.x | 0,
coords.y | 0,
this.getCurrentColor_(),
currentFrame,
this.overlayFrame,
event
);
if(this.currentMouseButton_ == Constants.MIDDLE_BUTTON) {
this.dragHandler.updateDrag(x, y);
} else {
$.publish(Events.MOUSE_EVENT, [event, this]);
// Warning : do not call setCurrentButton here
// mousemove do not have the correct mouse button information on all browsers
this.currentToolBehavior.moveToolAt(
coords.x | 0,
coords.y | 0,
this.getCurrentColor_(),
currentFrame,
this.overlayFrame,
event
);
}
} else {
this.currentToolBehavior.moveUnactiveToolAt(
coords.x,
coords.y,
@ -236,7 +217,8 @@
ns.DrawingController.prototype.onMousewheel_ = function (jQueryEvent) {
var event = jQueryEvent.originalEvent;
var delta = event.wheelDeltaY || (-2 * event.deltaY);
// Ratio between wheelDeltaY (mousewheel event) and deltaY (wheel event) is -40
var delta = event.wheelDeltaY || (-40 * event.deltaY);
var modifier = Math.abs(delta/120);
if (delta > 0) {
this.increaseZoom_(modifier);
@ -249,6 +231,8 @@
* @private
*/
ns.DrawingController.prototype.onMouseup_ = function (event) {
var frame = this.piskelController.getCurrentFrame();
var coords = this.getSpriteCoordinates(event.clientX, event.clientY);
if(this.isClicked) {
$.publish(Events.MOUSE_EVENT, [event, this]);
// A mouse button was clicked on the drawing canvas before this mouseup event,
@ -259,17 +243,24 @@
this.isClicked = false;
this.setCurrentButton(event);
var coords = this.getSpriteCoordinates(event.clientX, event.clientY);
this.currentToolBehavior.releaseToolAt(
coords.x,
coords.y,
this.getCurrentColor_(),
this.piskelController.getCurrentFrame(),
this.overlayFrame,
event
);
if (event.button === Constants.MIDDLE_BUTTON) {
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.getCurrentColor_(),
this.piskelController.getCurrentFrame(),
this.overlayFrame,
event
);
$.publish(Events.TOOL_RELEASED);
$.publish(Events.TOOL_RELEASED);
}
}
};
@ -389,8 +380,36 @@
return this.compositeRenderer;
};
ns.DrawingController.prototype.getOffset = function () {
return this.compositeRenderer.getOffset();
};
ns.DrawingController.prototype.setOffset = function (x, y) {
this.compositeRenderer.setOffset(x, y);
$.publish(Events.ZOOM_CHANGED);
};
ns.DrawingController.prototype.resetZoom_ = function () {
this.setZoom_(this.calculateZoom_());
};
ns.DrawingController.prototype.increaseZoom_ = function (zoomMultiplier) {
var step = (zoomMultiplier || 1) * this.getZoomStep_();
this.setZoom_(this.renderer.getZoom() + step);
};
ns.DrawingController.prototype.decreaseZoom_ = function (zoomMultiplier) {
var step = (zoomMultiplier || 1) * this.getZoomStep_();
this.setZoom_(this.renderer.getZoom() - step);
};
ns.DrawingController.prototype.getZoomStep_ = function () {
return this.calculateZoom_() / 10;
};
ns.DrawingController.prototype.setZoom_ = function (zoom) {
this.compositeRenderer.setZoom(zoom);
$.publish(Events.ZOOM_CHANGED);
};
})();

View File

@ -23,10 +23,15 @@
message.innerHTML = messageInfo.content;
message.innerHTML = message.innerHTML + "<div title='Close message' class='close'>x</div>";
document.body.appendChild(message);
$(message).find(".close").click($.proxy(this.removeMessage_, this));
if(messageInfo.behavior) {
message.querySelector('.close').addEventListener('click', this.removeMessage_.bind(this));
if (messageInfo.behavior) {
messageInfo.behavior(message);
}
if (messageInfo.hideDelay) {
window.setTimeout(this.removeMessage_.bind(this), messageInfo.hideDelay);
}
};
/**

View File

@ -7,23 +7,22 @@
};
this.tools = [
toDescriptor('simplePen', 'P', new pskl.drawingtools.SimplePen()),
toDescriptor('verticalMirrorPen', 'V', new pskl.drawingtools.VerticalMirrorPen()),
toDescriptor('paintBucket', 'B', new pskl.drawingtools.PaintBucket()),
toDescriptor('colorSwap', 'A', new pskl.drawingtools.ColorSwap()),
toDescriptor('eraser', 'E', new pskl.drawingtools.Eraser()),
toDescriptor('stroke', 'L', new pskl.drawingtools.Stroke()),
toDescriptor('rectangle', 'R', new pskl.drawingtools.Rectangle()),
toDescriptor('circle', 'C', new pskl.drawingtools.Circle()),
toDescriptor('move', 'M', new pskl.drawingtools.Move()),
toDescriptor('rectangleSelect', 'S', new pskl.drawingtools.RectangleSelect()),
toDescriptor('shapeSelect', 'Z', new pskl.drawingtools.ShapeSelect()),
toDescriptor('lighten', 'U', new pskl.drawingtools.Lighten()),
toDescriptor('colorPicker', 'O', new pskl.drawingtools.ColorPicker())
toDescriptor('simplePen', 'P', new pskl.tools.drawing.SimplePen()),
toDescriptor('verticalMirrorPen', 'V', new pskl.tools.drawing.VerticalMirrorPen()),
toDescriptor('paintBucket', 'B', new pskl.tools.drawing.PaintBucket()),
toDescriptor('colorSwap', 'A', new pskl.tools.drawing.ColorSwap()),
toDescriptor('eraser', 'E', new pskl.tools.drawing.Eraser()),
toDescriptor('stroke', 'L', new pskl.tools.drawing.Stroke()),
toDescriptor('rectangle', 'R', new pskl.tools.drawing.Rectangle()),
toDescriptor('circle', 'C', new pskl.tools.drawing.Circle()),
toDescriptor('move', 'M', new pskl.tools.drawing.Move()),
toDescriptor('rectangleSelect', 'S', new pskl.tools.drawing.RectangleSelect()),
toDescriptor('shapeSelect', 'Z', new pskl.tools.drawing.ShapeSelect()),
toDescriptor('lighten', 'U', new pskl.tools.drawing.Lighten()),
toDescriptor('colorPicker', 'O', new pskl.tools.drawing.ColorPicker())
];
this.currentSelectedTool = this.tools[0];
this.previousSelectedTool = this.tools[0];
this.toolIconRenderer = new pskl.tools.IconMarkupRenderer();
};
/**
@ -50,7 +49,7 @@
var previousSelectedToolClass = stage.data("selected-tool-class");
if(previousSelectedToolClass) {
stage.removeClass(previousSelectedToolClass);
stage.removeClass(pskl.drawingtools.Move.TOOL_ID);
stage.removeClass(pskl.tools.drawing.Move.TOOL_ID);
}
stage.addClass(tool.instance.toolId);
stage.data("selected-tool-class", tool.instance.toolId);
@ -105,43 +104,21 @@
};
ns.ToolController.prototype.getToolById_ = function (toolId) {
for(var i = 0 ; i < this.tools.length ; i++) {
var tool = this.tools[i];
if (tool.instance.toolId == toolId) {
return tool;
}
}
return null;
return pskl.utils.Array.find(this.tools, function (tool) {
return tool.instance.toolId == toolId;
});
};
/**
* @private
*/
ns.ToolController.prototype.createToolsDom_ = function() {
var toolMarkup = '';
var html = '';
for(var i = 0 ; i < this.tools.length ; i++) {
toolMarkup += this.getToolMarkup_(this.tools[i]);
var tool = this.tools[i];
html += this.toolIconRenderer.render(tool.instance, tool.shortcut);
}
$('#tools-container').html(toolMarkup);
};
/**
* @private
*/
ns.ToolController.prototype.getToolMarkup_ = function(tool) {
var toolId = tool.instance.toolId;
var classList = ['tool-icon', toolId];
if (this.currentSelectedTool == tool) {
classList.push('selected');
}
var tpl = pskl.utils.Template.get('drawing-tool-item-template');
return pskl.utils.Template.replace(tpl, {
cssclass : classList.join(' '),
toolid : toolId,
title : tool.instance.getTooltipText(tool.shortcut)
});
$('#tools-container').html(html);
};
ns.ToolController.prototype.addKeyboardShortcuts_ = function () {

View File

@ -0,0 +1,42 @@
(function () {
var ns = $.namespace('pskl.controller');
ns.TransformationsController = function () {
var toDescriptor = function (id, shortcut, instance) {
return {id:id, shortcut:shortcut, instance:instance};
};
this.tools = [
toDescriptor('flip', '', new pskl.tools.transform.Flip()),
toDescriptor('rotate', '', new pskl.tools.transform.Rotate()),
toDescriptor('clone', '', new pskl.tools.transform.Clone())
];
this.toolIconRenderer = new pskl.tools.IconMarkupRenderer();
};
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.createToolsDom_();
};
ns.TransformationsController.prototype.onTransformationClick = function (evt) {
var toolId = evt.target.dataset.toolId;
this.tools.forEach(function (tool) {
if (tool.instance.toolId === toolId) {
tool.instance.apply(evt);
}
}.bind(this));
};
ns.TransformationsController.prototype.createToolsDom_ = function() {
var html = this.tools.reduce(function (p, tool) {
return p + this.toolIconRenderer.render(tool.instance, tool.shortcut, 'left');
}.bind(this), '');
this.toolsContainer.innerHTML = html;
};
})();

View File

@ -27,7 +27,7 @@
importFileButton.addEventListener('click', this.onImportFileButtonClick_.bind(this));
var colorsListContainer = document.querySelector('.colors-container');
this.colorsListWidget = new pskl.controller.widgets.ColorsList(colorsListContainer);
this.colorsListWidget = new pskl.widgets.ColorsList(colorsListContainer);
var palette;
var isCurrentColorsPalette = paletteId == Constants.CURRENT_COLORS_PALETTE_ID;

View File

@ -0,0 +1,84 @@
(function () {
var ns = $.namespace('pskl.controller.drawing');
/**
* Multiplier applied between the mouse movement and viewport movement
* @type {Number}
*/
var MULTIPLIER = 2;
/**
* Dedicated handler to drag the drawing canvas using the mouse
* Will store the initial coordinates as well as the status of the drag
* @param {DrawingController} drawingController
*/
ns.DragHandler = function (drawingController) {
this.drawingController = drawingController;
this.isDragging_ = false;
this.updateOrigin_(-1, -1);
};
/**
* Initialize a drag session.
* @param {Number} x : x coordinate of the mouse event that initiated the drag
* @param {Number} y : y coordinate of the mouse event that initiated the drag
*/
ns.DragHandler.prototype.startDrag = function (x, y) {
var coords = this.drawingController.getSpriteCoordinates(x, y);
this.updateOrigin_(coords.x, coords.y);
};
/**
* Update the drag status
* @param {Number} x : x coordinate of the mouse event that triggered the update
* @param {Number} y : y coordinate of the mouse event that triggered the update
*/
ns.DragHandler.prototype.updateDrag = function (x, y) {
var currentOffset = this.drawingController.getOffset();
var offset = this.calculateOffset_(x, y);
if (currentOffset.y !== offset.y || currentOffset.x !== offset.x) {
this.isDragging_ = true;
this.drawingController.setOffset(offset.x, offset.y);
// retrieve the updated coordinates after moving the sprite
// and store them as the new drag origin
var coords = this.drawingController.getSpriteCoordinates(x, y);
this.updateOrigin_(coords.x, coords.y);
}
};
/**
* Stop the drag session
*/
ns.DragHandler.prototype.stopDrag = function () {
this.isDragging_ = false;
this.origin = null;
};
/**
* Will return true if the drag handler effectively MOVED the offset
* during the current drag session
*/
ns.DragHandler.prototype.isDragging = function () {
return this.isDragging_;
};
ns.DragHandler.prototype.calculateOffset_ = function (x, y) {
var coords = this.drawingController.getSpriteCoordinates(x, y);
var currentOffset = this.drawingController.getOffset();
var offset = {
x : currentOffset.x - MULTIPLIER * (coords.x - this.origin.x),
y : currentOffset.y - MULTIPLIER * (coords.y - this.origin.y)
};
return offset;
};
ns.DragHandler.prototype.updateOrigin_ = function (x, y) {
this.origin = this.origin || {};
this.origin.x = x;
this.origin.y = y;
};
})();

View File

@ -44,25 +44,30 @@
var zoom = this.getSelectedZoom_(),
fps = this.piskelController.getFPS();
this.renderAsImageDataAnimatedGIF(zoom, fps, this.onGifRenderingCompleted_.bind(this));
this.renderAsImageDataAnimatedGIF(zoom, fps, this.uploadImageData_.bind(this));
};
ns.GifExportController.prototype.onDownloadButtonClick_ = function (evt) {
var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif';
var zoom = this.getSelectedZoom_(),
fps = this.piskelController.getFPS();
this.renderAsImageDataAnimatedGIF(zoom, fps, function (imageData) {
pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) {
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
});
}.bind(this));
this.renderAsImageDataAnimatedGIF(zoom, fps, this.downloadImageData_.bind(this));
};
ns.GifExportController.prototype.onGifRenderingCompleted_ = function (imageData) {
ns.GifExportController.prototype.downloadImageData_ = function (imageData) {
var fileName = this.piskelController.getPiskel().getDescriptor().name + '.gif';
pskl.utils.BlobUtils.dataToBlob(imageData, "image/gif", function(blob) {
pskl.utils.FileUtils.downloadAsFile(blob, fileName);
});
};
ns.GifExportController.prototype.uploadImageData_ = function (imageData) {
this.updatePreview_(imageData);
this.previewContainerEl.classList.add("preview-upload-ongoing");
pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this));
console.log(imageData.length);
pskl.app.imageUploadService.upload(imageData, this.onImageUploadCompleted_.bind(this), this.onImageUploadFailed_.bind(this));
};
ns.GifExportController.prototype.onImageUploadCompleted_ = function (imageUrl) {
@ -71,6 +76,15 @@
this.previewContainerEl.classList.remove("preview-upload-ongoing");
};
ns.GifExportController.prototype.onImageUploadFailed_ = function (event, xhr) {
if (xhr.status === 500) {
$.publish(Events.SHOW_NOTIFICATION, [{
"content": "Upload failed : " + xhr.responseText,
"hideDelay" : 5000
}]);
}
};
ns.GifExportController.prototype.updatePreview_ = function (src) {
this.previewContainerEl.innerHTML = "<div><img style='max-width:32px;' src='"+src+"'/></div>";
};
@ -104,10 +118,10 @@
var colorCount = pskl.app.currentColorsService.getCurrentColors().length;
var preserveColors = colorCount < MAX_GIF_COLORS;
var gif = new window.GIF({
workers: 2,
workers: 5,
quality: 1,
width: this.piskelController.getWidth()*zoom,
height: this.piskelController.getHeight()*zoom,
width: this.piskelController.getWidth() * zoom,
height: this.piskelController.getHeight() * zoom,
preserveColors : preserveColors
});

View File

@ -41,7 +41,7 @@
* @private
*/
ns.SelectionManager.prototype.onToolSelected_ = function(evt, tool) {
var isSelectionTool = tool instanceof pskl.drawingtools.BaseSelect;
var isSelectionTool = tool instanceof pskl.tools.drawing.BaseSelect;
if(!isSelectionTool) {
this.cleanSelection_();
}

View File

@ -32,7 +32,7 @@
var file = files[i];
var isImage = file.type.indexOf('image') === 0;
var isPiskel = /\.piskel$/i.test(file.name);
var isPalette = /\.(gpl|txt)$/i.test(file.name);
var isPalette = /\.(gpl|txt|pal)$/i.test(file.name);
if (isImage) {
this.readImageFile_(file);
} else if (isPiskel) {

View File

@ -1,50 +0,0 @@
(function () {
var ns = $.namespace('pskl.service.palette');
var RE_COLOR_LINE = /^(\s*\d{1,3})(\s*\d{1,3})(\s*\d{1,3})/;
var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i;
ns.PaletteGplReader = function (file, onSuccess, onError) {
this.file = file;
this.onSuccess = onSuccess;
this.onError = onError;
};
ns.PaletteGplReader.prototype.read = function () {
pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this));
};
ns.PaletteGplReader.prototype.onFileLoaded_ = function (content) {
var text = pskl.utils.Base64.toText(content);
var lines = text.match(/[^\r\n]+/g);
var name = lines.map(function (l) {
var matches = l.match(RE_EXTRACT_NAME);
return matches ? matches[1] : '';
}).join('');
var colorLines = lines.filter(function (l) {
return RE_COLOR_LINE.test(l);
});
var colors = colorLines.map(function (l) {
var matches = l.match(RE_COLOR_LINE);
var color = window.tinycolor({
r : parseInt(matches[1], 10),
g : parseInt(matches[2], 10),
b : parseInt(matches[3], 10)
});
return color.toRgbString();
});
if (name && colors.length) {
var uuid = pskl.utils.Uuid.generate();
var palette = new pskl.model.Palette(uuid, name, colors);
this.onSuccess(palette);
} else {
this.onError();
}
};
})();

View File

@ -2,8 +2,10 @@
var ns = $.namespace('pskl.service.palette');
var fileReaders = {
'gpl' : ns.PaletteGplReader,
'txt' : ns.PaletteTxtReader
'gpl' : ns.reader.PaletteGplReader,
'pal' : ns.reader.PalettePalReader,
'txt' : ns.reader.PaletteTxtReader,
'img' : ns.reader.PaletteImageReader
};
ns.PaletteImportService = function () {};
@ -33,7 +35,7 @@
ns.PaletteImportService.prototype.getReaderClass_ = function (file) {
var readerClass;
if (this.isImage_(file)) {
readerClass = ns.PaletteImageReader;
readerClass = fileReaders.img;
} else {
var extension = this.getExtension_(file);
readerClass = fileReaders[extension];

View File

@ -1,38 +0,0 @@
(function () {
var ns = $.namespace('pskl.service.palette');
var RE_COLOR_LINE = /^[A-F0-9]{2}([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/;
ns.PaletteTxtReader = function (file, onSuccess, onError) {
this.file = file;
this.onSuccess = onSuccess;
this.onError = onError;
};
ns.PaletteTxtReader.prototype.read = function () {
pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this));
};
ns.PaletteTxtReader.prototype.onFileLoaded_ = function (content) {
var text = pskl.utils.Base64.toText(content);
var lines = text.match(/[^\r\n]+/g);
var colorLines = lines.filter(function (l) {
return RE_COLOR_LINE.test(l);
});
var colors = colorLines.map(function (l) {
var matches = l.match(RE_COLOR_LINE);
var color = "#" + matches[1] + matches[2] + matches[3];
return color;
});
if (colors.length) {
var uuid = pskl.utils.Uuid.generate();
var palette = new pskl.model.Palette(uuid, 'Imported palette', colors);
this.onSuccess(palette);
} else {
this.onError();
}
};
})();

View File

@ -0,0 +1,35 @@
(function () {
var ns = $.namespace('pskl.service.palette.reader');
ns.AbstractPaletteFileReader = function (file, onSuccess, onError, colorLineRegexp) {
this.file = file;
this.onSuccess = onSuccess;
this.onError = onError;
this.colorLineRegexp = colorLineRegexp;
};
ns.AbstractPaletteFileReader.prototype.extractColorFromLine = Constants.ABSTRACT_FUNCTION;
ns.AbstractPaletteFileReader.prototype.read = function () {
pskl.utils.FileUtils.readFile(this.file, this.onFileLoaded_.bind(this));
};
ns.AbstractPaletteFileReader.prototype.onFileLoaded_ = function (content) {
var text = pskl.utils.Base64.toText(content);
var lines = text.match(/[^\r\n]+/g);
var colorLines = lines.filter(function (l) {
return this.colorLineRegexp.test(l);
}.bind(this));
var colors = colorLines.map(this.extractColorFromLine.bind(this));
if (colors.length) {
var uuid = pskl.utils.Uuid.generate();
var palette = new pskl.model.Palette(uuid, this.file.name, colors);
this.onSuccess(palette);
} else {
this.onError();
}
};
})();

View File

@ -0,0 +1,23 @@
(function () {
var ns = $.namespace('pskl.service.palette.reader');
var RE_COLOR_LINE = /^(\s*\d{1,3})(\s*\d{1,3})(\s*\d{1,3})/;
var RE_EXTRACT_NAME = /^name\s*\:\s*(.*)$/i;
ns.PaletteGplReader = function (file, onSuccess, onError) {
this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE);
};
pskl.utils.inherit(ns.PaletteGplReader, ns.AbstractPaletteFileReader);
ns.PaletteGplReader.prototype.extractColorFromLine = function (line) {
var matches = line.match(RE_COLOR_LINE);
var color = window.tinycolor({
r : parseInt(matches[1], 10),
g : parseInt(matches[2], 10),
b : parseInt(matches[3], 10)
});
return color.toRgbString();
};
})();

View File

@ -1,5 +1,5 @@
(function () {
var ns = $.namespace('pskl.service.palette');
var ns = $.namespace('pskl.service.palette.reader');
ns.PaletteImageReader = function (file, onSuccess, onError) {
this.file = file;
@ -19,7 +19,6 @@
this.onWorkerStep_.bind(this),
this.onWorkerError_.bind(this));
$.publish(Events.SHOW_PROGRESS, [{"name": 'Processing image colors ...'}]);
imageProcessor.process();

View File

@ -0,0 +1,17 @@
(function () {
var ns = $.namespace('pskl.service.palette.reader');
var RE_COLOR_LINE = /^(\d{1,3})\s+(\d{1,3})\s+(\d{1,3})/;
ns.PalettePalReader = function (file, onSuccess, onError) {
this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE);
};
pskl.utils.inherit(ns.PalettePalReader, ns.AbstractPaletteFileReader);
ns.PalettePalReader.prototype.extractColorFromLine = function (line) {
var matches = line.match(RE_COLOR_LINE);
var color = 'rgb(' + matches[1] + ',' + matches[2] + ',' + matches[3] + ')';
return color;
};
})();

View File

@ -0,0 +1,17 @@
(function () {
var ns = $.namespace('pskl.service.palette.reader');
var RE_COLOR_LINE = /^[A-F0-9]{2}([A-F0-9]{2})([A-F0-9]{2})([A-F0-9]{2})/;
ns.PaletteTxtReader = function (file, onSuccess, onError) {
this.superclass.constructor.call(this, file, onSuccess, onError, RE_COLOR_LINE);
};
pskl.utils.inherit(ns.PaletteTxtReader, ns.AbstractPaletteFileReader);
ns.PaletteTxtReader.prototype.extractColorFromLine = function (line) {
var matches = line.match(RE_COLOR_LINE);
var color = "#" + matches[1] + matches[2] + matches[3];
return color;
};
})();

View File

@ -0,0 +1,49 @@
(function () {
var ns = $.namespace('pskl.tools');
ns.IconMarkupRenderer = function () {};
ns.IconMarkupRenderer.prototype.render = function (tool, shortcut, tooltipPosition) {
tooltipPosition = tooltipPosition || 'right';
shortcut = shortcut ? '(' + shortcut + ')' : '';
var tpl = pskl.utils.Template.get('drawingTool-item-template');
return pskl.utils.Template.replace(tpl, {
cssclass : ['tool-icon', tool.toolId].join(' '),
toolid : tool.toolId,
title : this.getTooltipText(tool, shortcut),
tooltipposition : tooltipPosition
});
};
ns.IconMarkupRenderer.prototype.getTooltipText = function(tool, shortcut) {
var descriptors = tool.tooltipDescriptors;
var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template');
return pskl.utils.Template.replace(tpl, {
helptext : tool.getHelpText(),
shortcut : shortcut,
descriptors : this.formatToolDescriptors_(descriptors)
});
};
ns.IconMarkupRenderer.prototype.formatToolDescriptors_ = function(descriptors) {
descriptors = descriptors || [];
return descriptors.reduce(function (p, descriptor) {
return p += this.formatToolDescriptor_(descriptor);
}.bind(this), '');
};
ns.IconMarkupRenderer.prototype.formatToolDescriptor_ = function(descriptor) {
var tpl;
if (descriptor.key) {
tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template');
descriptor.key = descriptor.key.toUpperCase();
if (pskl.utils.UserAgent.isMac) {
descriptor.key = descriptor.key.replace('CTRL', 'CMD');
}
} else {
tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template');
}
return pskl.utils.Template.replace(tpl, descriptor);
};
})();

17
src/js/tools/Tool.js Normal file
View File

@ -0,0 +1,17 @@
(function () {
var ns = $.namespace('pskl.tools');
ns.Tool = function () {
this.toolId = "tool";
this.helpText = "Abstract tool";
this.tooltipDescriptors = [];
};
ns.Tool.prototype.getHelpText = function() {
return this.helpText;
};
ns.Tool.prototype.getId = function() {
return this.toolId;
};
})();

View File

@ -1,15 +1,18 @@
/**
* @provide pskl.drawingtools.BaseTool
* @provide pskl.tools.drawing.BaseTool
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.BaseTool = function() {
pskl.tool.Tool.call(this);
this.toolId = "tool-base";
};
pskl.utils.inherit(ns.BaseTool, pskl.tools.Tool);
ns.BaseTool.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {};
ns.BaseTool.prototype.moveToolAt = function(col, row, color, frame, overlay, event) {};
@ -58,41 +61,6 @@
});
};
ns.BaseTool.prototype.getHelpText = function() {
return this.shortHelpText || this.helpText;
};
ns.BaseTool.prototype.getTooltipText = function(shortcut) {
var tpl = pskl.utils.Template.get('drawing-tool-tooltip-container-template');
var descriptors = "";
if (Array.isArray(this.tooltipDescriptors)) {
this.tooltipDescriptors.forEach(function (descriptor) {
descriptors += this.getTooltipDescription(descriptor);
}.bind(this));
}
return pskl.utils.Template.replace(tpl, {
helptext : this.getHelpText(),
shortcut : shortcut,
descriptors : descriptors
});
};
ns.BaseTool.prototype.getTooltipDescription = function(descriptor) {
var tpl;
if (descriptor.key) {
tpl = pskl.utils.Template.get('drawing-tool-tooltip-descriptor-template');
descriptor.key = descriptor.key.toUpperCase();
if (pskl.utils.UserAgent.isMac) {
descriptor.key = descriptor.key.replace('CTRL', 'CMD');
}
} else {
tpl = pskl.utils.Template.get('drawing-tool-tooltip-descriptor-simple-template');
}
return pskl.utils.Template.replace(tpl, descriptor);
};
ns.BaseTool.prototype.releaseToolAt = function(col, row, color, frame, overlay, event) {};
/**

View File

@ -1,52 +1,52 @@
/**
* @provide pskl.drawingtools.Circle
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
ns.Circle = function() {
ns.ShapeTool.call(this);
this.toolId = "tool-circle";
this.helpText = "Circle tool";
};
pskl.utils.inherit(ns.Circle, ns.ShapeTool);
ns.Circle.prototype.draw_ = function (col, row, color, targetFrame) {
var circlePoints = this.getCirclePixels_(this.startCol, this.startRow, col, row);
for(var i = 0; i< circlePoints.length; i++) {
// Change model:
targetFrame.setPixel(circlePoints[i].col, circlePoints[i].row, color);
}
};
ns.Circle.prototype.getCirclePixels_ = function (x0, y0, x1, y1) {
var coords = pskl.PixelUtils.getOrderedRectangleCoordinates(x0, y0, x1, y1);
var xC = (coords.x0 + coords.x1)/2;
var yC = (coords.y0 + coords.y1)/2;
var rX = coords.x1 - xC;
var rY = coords.y1 - yC;
var pixels = [];
var x, y, angle;
for (x = coords.x0 ; x < coords.x1 ; x++) {
angle = Math.acos((x - xC)/rX);
y = Math.round(rY * Math.sin(angle) + yC);
pixels.push({"col": x, "row": y});
pixels.push({"col": 2*xC - x, "row": 2*yC - y});
}
for (y = coords.y0 ; y < coords.y1 ; y++) {
angle = Math.asin((y - yC)/rY);
x = Math.round(rX * Math.cos(angle) + xC);
pixels.push({"col": x, "row": y});
pixels.push({"col": 2*xC - x, "row": 2*yC - y});
}
return pixels;
};
})();
/**
* @provide pskl.tools.drawing.Circle
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.tools.drawing");
ns.Circle = function() {
ns.ShapeTool.call(this);
this.toolId = "tool-circle";
this.helpText = "Circle tool";
};
pskl.utils.inherit(ns.Circle, ns.ShapeTool);
ns.Circle.prototype.draw_ = function (col, row, color, targetFrame) {
var circlePoints = this.getCirclePixels_(this.startCol, this.startRow, col, row);
for(var i = 0; i< circlePoints.length; i++) {
// Change model:
targetFrame.setPixel(circlePoints[i].col, circlePoints[i].row, color);
}
};
ns.Circle.prototype.getCirclePixels_ = function (x0, y0, x1, y1) {
var coords = pskl.PixelUtils.getOrderedRectangleCoordinates(x0, y0, x1, y1);
var xC = (coords.x0 + coords.x1)/2;
var yC = (coords.y0 + coords.y1)/2;
var rX = coords.x1 - xC;
var rY = coords.y1 - yC;
var pixels = [];
var x, y, angle;
for (x = coords.x0 ; x < coords.x1 ; x++) {
angle = Math.acos((x - xC)/rX);
y = Math.round(rY * Math.sin(angle) + yC);
pixels.push({"col": x, "row": y});
pixels.push({"col": 2*xC - x, "row": 2*yC - y});
}
for (y = coords.y0 ; y < coords.y1 ; y++) {
angle = Math.asin((y - yC)/rY);
x = Math.round(rX * Math.cos(angle) + xC);
pixels.push({"col": x, "row": y});
pixels.push({"col": 2*xC - x, "row": 2*yC - y});
}
return pixels;
};
})();

View File

@ -1,10 +1,10 @@
/**
* @provide pskl.drawingtools.ColorPicker
* @provide pskl.tools.drawing.ColorPicker
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.ColorPicker = function() {
this.toolId = "tool-colorpicker";

View File

@ -1,9 +1,9 @@
/**
* @provide pskl.drawingtools.ColorSwap
* @provide pskl.tools.drawing.ColorSwap
*
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.ColorSwap = function() {
this.toolId = "tool-colorswap";

View File

@ -1,11 +1,11 @@
/**
* @provide pskl.drawingtools.Eraser
* @provide pskl.tools.drawing.Eraser
*
* @require Constants
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.Eraser = function() {
this.superclass.constructor.call(this);

View File

@ -1,11 +1,11 @@
/**
* @provide pskl.drawingtools.Eraser
* @provide pskl.tools.drawing.Eraser
*
* @require Constants
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
var DEFAULT_STEP = 3;
ns.Lighten = function() {

View File

@ -1,10 +1,10 @@
/**
* @provide pskl.drawingtools.Move
* @provide pskl.tools.drawing.Move
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.Move = function() {
this.toolId = ns.Move.TOOL_ID;

View File

@ -1,10 +1,10 @@
/**
* @provide pskl.drawingtools.PaintBucket
* @provide pskl.tools.drawing.PaintBucket
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.PaintBucket = function() {
this.toolId = "tool-paint-bucket";

View File

@ -1,17 +1,17 @@
/**
* @provide pskl.drawingtools.Rectangle
* @provide pskl.tools.drawing.Rectangle
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.Rectangle = function() {
ns.ShapeTool.call(this);
this.toolId = "tool-rectangle";
this.shortHelpText = "Rectangle tool";
this.helpText = "Rectangle tool";
};
pskl.utils.inherit(ns.Rectangle, ns.ShapeTool);

View File

@ -1,5 +1,5 @@
(function () {
var ns = $.namespace('pskl.drawingtools');
var ns = $.namespace('pskl.tools.drawing');
/**
* Abstract shape tool class, parent to all shape tools (rectangle, circle).
* Shape tools should override only the draw_ method

View File

@ -1,10 +1,10 @@
/**
* @provide pskl.drawingtools.SimplePen
* @provide pskl.tools.drawing.SimplePen
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.SimplePen = function() {
this.toolId = "tool-pen";

View File

@ -1,10 +1,10 @@
/**
* @provide pskl.drawingtools.Stroke
* @provide pskl.tools.drawing.Stroke
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.Stroke = function() {
this.toolId = "tool-stroke";

View File

@ -1,5 +1,5 @@
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.VerticalMirrorPen = function() {
this.superclass.constructor.call(this);

View File

@ -1,13 +1,13 @@
/**
* @provide pskl.drawingtools.BaseSelect
* @provide pskl.tools.drawing.BaseSelect
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.BaseSelect = function() {
this.secondaryToolId = pskl.drawingtools.Move.TOOL_ID;
this.secondaryToolId = pskl.tools.drawing.Move.TOOL_ID;
this.BodyRoot = $('body');
// Select's first point coordinates (set in applyToolAt)

View File

@ -1,10 +1,10 @@
/**
* @provide pskl.drawingtools.RectangleSelect
* @provide pskl.tools.drawing.RectangleSelect
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.RectangleSelect = function() {
this.toolId = "tool-rectangle-select";

View File

@ -1,10 +1,10 @@
/**
* @provide pskl.drawingtools.ShapeSelect
* @provide pskl.tools.drawing.ShapeSelect
*
* @require pskl.utils
*/
(function() {
var ns = $.namespace("pskl.drawingtools");
var ns = $.namespace("pskl.tools.drawing");
ns.ShapeSelect = function() {
this.toolId = "tool-shape-select";

View File

@ -0,0 +1,25 @@
(function () {
var ns = $.namespace('pskl.tools.transform');
ns.Clone = function () {
this.toolId = "tool-clone";
this.helpText = "Clone current layer to all frames";
this.tooltipDescriptors = [];
};
pskl.utils.inherit(ns.Clone, ns.Transform);
ns.Clone.prototype.apply = function (evt) {
var ref = pskl.app.piskelController.getCurrentFrame();
var layer = pskl.app.piskelController.getCurrentLayer();
layer.getFrames().forEach(function (frame) {
if (frame !== ref) {
frame.setPixels(ref.getPixels());
}
});
$.publish(Events.PISKEL_RESET);
$.publish(Events.PISKEL_SAVE_STATE, {
type : pskl.service.HistoryService.SNAPSHOT
});
};
})();

View File

@ -0,0 +1,28 @@
(function () {
var ns = $.namespace('pskl.tools.transform');
ns.Flip = function () {
this.toolId = "tool-flip";
this.helpText = "Flip vertically";
this.tooltipDescriptors = [
{key : 'alt', description : 'Flip horizontally'},
{key : 'ctrl', description : 'Apply to all layers'},
{key : 'shift', description : 'Apply to all frames'}
];
};
pskl.utils.inherit(ns.Flip, ns.Transform);
ns.Flip.prototype.applyToolOnFrame_ = function (frame, altKey) {
var axis;
if (altKey) {
axis = pskl.utils.FrameTransform.HORIZONTAL;
} else {
axis = pskl.utils.FrameTransform.VERTICAL;
}
pskl.utils.FrameTransform.flip(frame, axis);
};
})();

View File

@ -0,0 +1,27 @@
(function () {
var ns = $.namespace('pskl.tools.transform');
ns.Rotate = function () {
this.toolId = "tool-rotate";
this.helpText = "Counter-clockwise rotation";
this.tooltipDescriptors = [
{key : 'alt', description : 'Clockwise rotation'},
{key : 'ctrl', description : 'Apply to all layers'},
{key : 'shift', description : 'Apply to all frames'}];
};
pskl.utils.inherit(ns.Rotate, ns.Transform);
ns.Rotate.prototype.applyToolOnFrame_ = function (frame, altKey) {
var direction;
if (altKey) {
direction = pskl.utils.FrameTransform.CLOCKWISE;
} else {
direction = pskl.utils.FrameTransform.COUNTERCLOCKWISE;
}
pskl.utils.FrameTransform.rotate(frame, direction);
};
})();

View File

@ -0,0 +1,33 @@
(function () {
var ns = $.namespace('pskl.tools.transform');
ns.Transform = function () {
this.toolId = "tool-transform";
this.helpText = "Transform tool";
this.tooltipDescriptors = [];
};
pskl.utils.inherit(ns.Transform, pskl.tools.Tool);
ns.Transform.prototype.apply = function (evt) {
var allFrames = evt.shiftKey;
var allLayers = evt.ctrlKey;
this.applyTool_(evt.altKey, allFrames, allLayers);
};
ns.Transform.prototype.applyTool_ = function (altKey, allFrames, allLayers) {
var currentFrameIndex = pskl.app.piskelController.getCurrentFrameIndex();
var layers = allLayers ? pskl.app.piskelController.getLayers(): [pskl.app.piskelController.getCurrentLayer()];
layers.forEach(function (layer) {
var frames = allFrames ? layer.getFrames(): [layer.getFrameAt(currentFrameIndex)];
frames.forEach(function (frame) {
this.applyToolOnFrame_(frame, altKey);
}.bind(this));
}.bind(this));
$.publish(Events.PISKEL_RESET);
$.publish(Events.PISKEL_SAVE_STATE, {
type : pskl.service.HistoryService.SNAPSHOT
});
};
})();

16
src/js/utils/Array.js Normal file
View File

@ -0,0 +1,16 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.Array = {
find : function (array, filterFn) {
var match = null;
array = Array.isArray(array) ? array : [];
var filtered = array.filter(filterFn);
if (filtered.length) {
match = filtered[0];
}
return match;
}
};
})();

View File

@ -0,0 +1,65 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.FrameTransform = {
VERTICAL : 'vertical',
HORIZONTAL : 'HORIZONTAL',
flip : function (frame, axis) {
var clone = frame.clone();
var w = frame.getWidth();
var h = frame.getHeight();
clone.forEachPixel(function (color, x, y) {
if (axis === ns.FrameTransform.VERTICAL) {
x = w-x-1;
} else if (axis === ns.FrameTransform.HORIZONTAL) {
y = h-y-1;
}
frame.pixels[x][y] = color;
});
frame.version++;
return frame;
},
CLOCKWISE : 'clockwise',
COUNTERCLOCKWISE : 'counterclockwise',
rotate : function (frame, direction) {
var clone = frame.clone();
var w = frame.getWidth();
var h = frame.getHeight();
var max = Math.max(w, h);
var xDelta = Math.ceil((max - w)/2);
var yDelta = Math.ceil((max - h)/2);
frame.forEachPixel(function (color, x, y) {
var _x = x, _y = y;
// Convert to square coords
x = x + xDelta;
y = y + yDelta;
// Perform the rotation
var tmpX = x, tmpY = y;
if (direction === ns.FrameTransform.CLOCKWISE) {
x = tmpY;
y = max - 1 - tmpX;
} else if (direction === ns.FrameTransform.COUNTERCLOCKWISE) {
y = tmpX;
x = max - 1 - tmpY;
}
// Convert the coordinates back to the rectangular grid
x = x - xDelta;
y = y - yDelta;
if (clone.containsPixel(x, y)) {
frame.pixels[_x][_y] = clone.getPixel(x, y);
} else {
frame.pixels[_x][_y] = Constants.TRANSPARENT_COLOR;
}
});
frame.version++;
return frame;
}
};
})();

View File

@ -2,11 +2,17 @@
var ns = $.namespace('pskl.utils');
var colorCache = {};
ns.FrameUtils = {
toImage : function (frame, zoom, bgColor) {
/**
* Render a Frame object as an image.
* Can optionally scale it (zoom)
* @param {Frame} frame
* @param {Number} zoom
* @return {Image}
*/
toImage : function (frame, zoom) {
zoom = zoom || 1;
bgColor = bgColor || Constants.TRANSPARENT_COLOR;
var canvasRenderer = new pskl.rendering.CanvasRenderer(frame, zoom);
canvasRenderer.drawTransparentAs(bgColor);
canvasRenderer.drawTransparentAs(Constants.TRANSPARENT_COLOR);
return canvasRenderer.render();
},
@ -23,9 +29,9 @@
},
mergeFrames_ : function (frameA, frameB) {
frameB.forEachPixel(function (p, col, row) {
if (p != Constants.TRANSPARENT_COLOR) {
frameA.setPixel(col, row, p);
frameB.forEachPixel(function (color, col, row) {
if (color != Constants.TRANSPARENT_COLOR) {
frameA.setPixel(col, row, color);
}
});
},

View File

@ -0,0 +1,37 @@
(function () {
var ns = $.namespace('pskl.utils');
ns.TooltipFormatter = {};
ns.TooltipFormatter.formatForTool = function(shortcut, descriptors, helpText) {
var tpl = pskl.utils.Template.get('drawingTool-tooltipContainer-template');
return pskl.utils.Template.replace(tpl, {
helptext : helpText,
shortcut : shortcut,
descriptors : this.formatToolDescriptors_(descriptors)
});
};
ns.TooltipFormatter.formatToolDescriptors_ = function(descriptors) {
descriptors = descriptors || [];
return descriptors.reduce(function (p, descriptor) {
return p += this.formatToolDescriptor_(descriptor);
}.bind(this), '');
};
ns.TooltipFormatter.formatToolDescriptor_ = function(descriptor) {
var tpl;
if (descriptor.key) {
tpl = pskl.utils.Template.get('drawingTool-tooltipDescriptor-template');
descriptor.key = descriptor.key.toUpperCase();
if (pskl.utils.UserAgent.isMac) {
descriptor.key = descriptor.key.replace('CTRL', 'CMD');
}
} else {
tpl = pskl.utils.Template.get('drawingTool-simpleTooltipDescriptor-template');
}
return pskl.utils.Template.replace(tpl, descriptor);
};
})();

View File

@ -37,7 +37,7 @@
};
xhr.onerror = function(e) {
error(e);
error(e, this);
};
return xhr;

View File

@ -1,5 +1,5 @@
(function () {
var ns = $.namespace('pskl.controller.widgets');
var ns = $.namespace('pskl.widgets');
var DEFAULT_COLOR = '#000000';
@ -20,7 +20,7 @@
this.colorsList.addEventListener('click', this.onColorContainerClick_.bind(this));
var colorPickerContainer = container.querySelector('.color-picker-container');
this.hslRgbColorPicker = new pskl.controller.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this));
this.hslRgbColorPicker = new pskl.widgets.HslRgbColorPicker(colorPickerContainer, this.onColorUpdated_.bind(this));
this.hslRgbColorPicker.init();
};

View File

@ -1,5 +1,5 @@
(function () {
var ns = $.namespace('pskl.controller.widgets');
var ns = $.namespace('pskl.widgets');
ns.HslRgbColorPicker = function (container, colorUpdatedCallback) {
this.container = container;

View File

@ -11,6 +11,7 @@
// Libraries
"js/utils/core.js",
"js/utils/UserAgent.js",
"js/utils/Array.js",
"js/utils/Base64.js",
"js/utils/BlobUtils.js",
"js/utils/CanvasUtils.js",
@ -18,12 +19,14 @@
"js/utils/Dom.js",
"js/utils/Math.js",
"js/utils/FileUtils.js",
"js/utils/FrameTransform.js",
"js/utils/FrameUtils.js",
"js/utils/LayerUtils.js",
"js/utils/ImageResizer.js",
"js/utils/PixelUtils.js",
"js/utils/PiskelFileUtils.js",
"js/utils/Template.js",
"js/utils/TooltipFormatter.js",
"js/utils/UserSettings.js",
"js/utils/Uuid.js",
"js/utils/WorkerUtils.js",
@ -78,6 +81,7 @@
"js/controller/piskel/PublicPiskelController.js",
"js/controller/CursorCoordinatesController.js",
"js/controller/DrawingController.js",
"js/controller/drawing/DragHandler.js",
"js/controller/PreviewFilmController.js",
"js/controller/LayersListController.js",
"js/controller/AnimatedPreviewController.js",
@ -87,6 +91,7 @@
"js/controller/PalettesListController.js",
"js/controller/ProgressBarController.js",
"js/controller/NotificationController.js",
"js/controller/TransformationsController.js",
"js/controller/CanvasBackgroundController.js",
// Settings sub-controllers
@ -111,9 +116,9 @@
// Dialogs controller
"js/controller/dialogs/DialogsController.js",
// Widget controller
"js/controller/widgets/ColorsList.js",
"js/controller/widgets/HslRgbColorPicker.js",
// Widgets
"js/widgets/ColorsList.js",
"js/widgets/HslRgbColorPicker.js",
// Services
"js/service/LocalStorageService.js",
@ -125,10 +130,12 @@
"js/service/color/ColorSorter.js",
"js/service/palette/CurrentColorsPalette.js",
"js/service/palette/PaletteService.js",
"js/service/palette/PaletteTxtReader.js",
"js/service/palette/PaletteGplReader.js",
"js/service/palette/PaletteGplWriter.js",
"js/service/palette/PaletteImageReader.js",
"js/service/palette/reader/AbstractPaletteFileReader.js",
"js/service/palette/reader/PaletteGplReader.js",
"js/service/palette/reader/PaletteImageReader.js",
"js/service/palette/reader/PalettePalReader.js",
"js/service/palette/reader/PaletteTxtReader.js",
"js/service/palette/PaletteImportService.js",
"js/service/SavedStatusService.js",
"js/service/keyboard/ShortcutService.js",
@ -139,22 +146,28 @@
"js/service/FileDropperService.js",
// Tools
"js/drawingtools/BaseTool.js",
"js/drawingtools/ShapeTool.js",
"js/drawingtools/SimplePen.js",
"js/drawingtools/Lighten.js",
"js/drawingtools/VerticalMirrorPen.js",
"js/drawingtools/Eraser.js",
"js/drawingtools/Stroke.js",
"js/drawingtools/PaintBucket.js",
"js/drawingtools/Rectangle.js",
"js/drawingtools/Circle.js",
"js/drawingtools/Move.js",
"js/drawingtools/selectiontools/BaseSelect.js",
"js/drawingtools/selectiontools/RectangleSelect.js",
"js/drawingtools/selectiontools/ShapeSelect.js",
"js/drawingtools/ColorPicker.js",
"js/drawingtools/ColorSwap.js",
"js/tools/Tool.js",
"js/tools/IconMarkupRenderer.js",
"js/tools/drawing/BaseTool.js",
"js/tools/drawing/ShapeTool.js",
"js/tools/drawing/SimplePen.js",
"js/tools/drawing/Lighten.js",
"js/tools/drawing/VerticalMirrorPen.js",
"js/tools/drawing/Eraser.js",
"js/tools/drawing/Stroke.js",
"js/tools/drawing/PaintBucket.js",
"js/tools/drawing/Rectangle.js",
"js/tools/drawing/Circle.js",
"js/tools/drawing/Move.js",
"js/tools/drawing/selection/BaseSelect.js",
"js/tools/drawing/selection/RectangleSelect.js",
"js/tools/drawing/selection/ShapeSelect.js",
"js/tools/drawing/ColorPicker.js",
"js/tools/drawing/ColorSwap.js",
"js/tools/transform/Transform.js",
"js/tools/transform/Clone.js",
"js/tools/transform/Flip.js",
"js/tools/transform/Rotate.js",
// Devtools
"js/devtools/DrawingTestPlayer.js",

View File

@ -3,6 +3,7 @@
(typeof exports != "undefined" ? exports : pskl_exports).styles = [
"css/reset.css",
"css/style.css",
"css/layout.css",
"css/font-icon.css",
"css/forms.css",
"css/settings.css",
@ -21,6 +22,7 @@
"css/toolbox-layers-list.css",
"css/toolbox-palettes-list.css",
"css/toolbox-animated-preview.css",
"css/transformations.css",
"css/spectrum/spectrum.css",
"css/spectrum/spectrum-overrides.css",
"css/bootstrap/bootstrap.css",

View File

@ -34,20 +34,20 @@
<!-- Templates -->
<!-- Drawing tool icon-button -->
<script type="text/template" id="drawing-tool-item-template">
<li rel="tooltip" data-placement="right" class="{{cssclass}}" data-tool-id="{{toolid}}" title="{{title}}"></li>
<script type="text/template" id="drawingTool-item-template">
<li rel="tooltip" data-placement="{{tooltipposition}}" class="{{cssclass}}" data-tool-id="{{toolid}}" title="{{title}}"></li>
</script>
<!-- Drawing tool tooltip container -->
<script type="text/template" id="drawing-tool-tooltip-container-template">
<script type="text/template" id="drawingTool-tooltipContainer-template">
<div class='tools-tooltip-container'>
<div>{{helptext}} <span class='tools-tooltip-shortcut'>({{shortcut}})</span></div>
<div>{{helptext}} <span class='tools-tooltip-shortcut'>{{shortcut}}</span></div>
{{descriptors}}
</div>
</script>
<!-- Drawing tool tooltip line for modifier -->
<script type="text/template" id="drawing-tool-tooltip-descriptor-template">
<script type="text/template" id="drawingTool-tooltipDescriptor-template">
<div class='tools-tooltip-descriptor'>
<span class='tools-tooltip-descriptor-button'>{{key}}</span>
{{description}}
@ -55,7 +55,7 @@
</script>
<!-- Drawing tool tooltip line -->
<script type="text/template" id="drawing-tool-tooltip-descriptor-simple-template">
<script type="text/template" id="drawingTool-simpleTooltipDescriptor-template">
<div class='tools-tooltip-descriptor'>
{{description}}
</div>

View File

@ -1,8 +1,5 @@
<div class="toolbox-container palettes-list-container">
<h3 class="toolbox-title palettes-title"
style="overflow: hidden;height: 36px;box-sizing: border-box;border-bottom: 1px solid #444;">
<span style="line-height:20px ">Palettes</span>
</h3>
<h3 class="toolbox-title palettes-title">Palettes</h3>
<div class="palettes-list-actions">
<button
class="button palettes-list-button create-palette-button piskel-icon-plus" data-action="add"

View File

@ -4,7 +4,7 @@
<div class="settings-item">
<div class="settings-form-section" style="overflow:hidden">
<label class="row" style="float:left;line-height:28px;">Title : </label>
<input id="save-name" type="text" class="save-field textfield" style="float:left;width:200px;margin-left:10px;"/>
<input id="save-name" type="text" class="save-field textfield" style="float:left;width:198px;margin-left:10px;"/>
</div>
<div class="settings-form-section">
<textarea id="save-description" class="save-field textfield" placeholder="Description ..."></textarea>

View File

@ -0,0 +1,4 @@
<div class="toolbox-container transformations-container">
<h3 class="toolbox-title transformations-title">Transform</h3>
<ul class="tools-wrapper"></ul>
</div>

View File

@ -0,0 +1,253 @@
describe("FrameTransform suite", function() {
var A = '#000000';
var B = '#ff0000';
var O = Constants.TRANSPARENT_COLOR;
var HORIZONTAL = pskl.utils.FrameTransform.HORIZONTAL;
var VERTICAL = pskl.utils.FrameTransform.VERTICAL;
var CLOCKWISE = pskl.utils.FrameTransform.CLOCKWISE;
var COUNTERCLOCKWISE = pskl.utils.FrameTransform.COUNTERCLOCKWISE;
/**
* Check a frame has the pixels as a given grid
* @param {Frame} frame [description]
* @param {Array<Array<String|Color>>} grid
*/
var frameEqualsGrid = function (frame, grid) {
frame.forEachPixel(function (color, col, row) {
expect(color).toBe(grid[row][col]);
});
};
var toFrameGrid = function (normalGrid) {
var frameGrid = [];
var w = normalGrid[0].length;
var h = normalGrid.length;
for (var x = 0 ; x < w ; x++) {
frameGrid[x] = [];
for (var y = 0 ; y < h ; y++) {
frameGrid[x][y] = normalGrid[y][x];
}
}
return frameGrid;
};
/*******************************/
/************ FLIP *************/
/*******************************/
it("flips a frame vertically", function () {
// create frame
var frame = pskl.model.Frame.fromPixelGrid(toFrameGrid([
[A, O],
[O, B]
]));
// should have flipped
pskl.utils.FrameTransform.flip(frame, VERTICAL);
frameEqualsGrid(frame, [
[O, A],
[B, O]
]);
});
it("flips a frame horizontally", function () {
// create frame
var frame = pskl.model.Frame.fromPixelGrid(toFrameGrid([
[A, O],
[O, B]
]));
// should have flipped
pskl.utils.FrameTransform.flip(frame, HORIZONTAL);
frameEqualsGrid(frame, [
[O, B],
[A, O]
]);
});
it("flips rectangular frame", function () {
// create frame
var frame = pskl.model.Frame.fromPixelGrid(toFrameGrid([
[A, O],
[A, O],
[A, O]
]));
// should have flipped
pskl.utils.FrameTransform.flip(frame, VERTICAL);
frameEqualsGrid(frame, [
[O, A],
[O, A],
[O, A]
]);
// should be the same
pskl.utils.FrameTransform.flip(frame, HORIZONTAL);
frameEqualsGrid(frame, [
[O, A],
[O, A],
[O, A]
]);
});
/*******************************/
/*********** ROTATE ************/
/*******************************/
it("rotates a frame counterclockwise", function () {
// create frame
var frame = pskl.model.Frame.fromPixelGrid(toFrameGrid([
[A, O],
[O, B]
]));
// rotate once
pskl.utils.FrameTransform.rotate(frame, COUNTERCLOCKWISE);
frameEqualsGrid(frame, [
[O, B],
[A, O]
]);
// rotate twice
pskl.utils.FrameTransform.rotate(frame, COUNTERCLOCKWISE);
frameEqualsGrid(frame, [
[B, O],
[O, A]
]);
// rotate 3
pskl.utils.FrameTransform.rotate(frame, COUNTERCLOCKWISE);
frameEqualsGrid(frame, [
[O, A],
[B, O]
]);
// rotate 4 - back to initial state
pskl.utils.FrameTransform.rotate(frame, COUNTERCLOCKWISE);
frameEqualsGrid(frame, [
[A, O],
[O, B]
]);
});
it("rotates a frame clockwise", function () {
// create frame
var frame = pskl.model.Frame.fromPixelGrid(toFrameGrid([
[A, O],
[O, B]
]));
// rotate once
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, A],
[B, O]
]);
// rotate twice
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[B, O],
[O, A]
]);
// rotate 3
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, B],
[A, O]
]);
// rotate 4 - back to initial state
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[A, O],
[O, B]
]);
});
it("rotates a rectangular frame", function () {
// create frame
var frame = pskl.model.Frame.fromPixelGrid(toFrameGrid([
[A, O],
[A, O],
[B, O],
[B, O]
]));
// rotate once
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, O],
[B, A],
[O, O],
[O, O]
]);
// rotate twice
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, O],
[O, B],
[O, A],
[O, O]
]);
// rotate 3
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, O],
[O, O],
[A, B],
[O, O]
]);
// rotate 4
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, O],
[A, O],
[B, O],
[O, O]
]);
});
it("rotates a rectangular (horizontal) frame", function () {
// create frame
var frame = pskl.model.Frame.fromPixelGrid(toFrameGrid([
[O, O, O, O],
[A, A, B, B]
]));
// rotate once
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, A, O, O],
[O, B, O, O]
]);
// rotate twice
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, B, A, O],
[O, O, O, O]
]);
// rotate 3
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, O, B, O],
[O, O, A, O]
]);
// rotate 4
pskl.utils.FrameTransform.rotate(frame, CLOCKWISE);
frameEqualsGrid(frame, [
[O, O, O, O],
[O, A, B, O]
]);
});
});

View File

@ -101,45 +101,4 @@ describe("FrameUtils suite", function() {
expect(frames[3].getPixel(0,1)).toBe(red);
});
// it("starts at -1", function() {
// historyService = createMockHistoryService();
// expect(historyService.currentIndex).toBe(-1);
// });
// it("is at 0 after init", function() {
// historyService = createMockHistoryService();
// historyService.init();
// expect(historyService.currentIndex).toBe(0);
// });
// it("stores a piskel snapshot after 5 SAVE", function () {
// // BEFORE
// var SNAPSHOT_PERIOD_BACKUP = pskl.service.HistoryService.SNAPSHOT_PERIOD;
// pskl.service.HistoryService.SNAPSHOT_PERIOD = 5;
// historyService = createMockHistoryService();
// historyService.init();
// sendSaveEvents(pskl.service.HistoryService.REPLAY).times(5);
// expect(historyService.currentIndex).toBe(5);
// expect(getLastState().piskel).toBe(SERIALIZED_PISKEL);
// sendSaveEvents(pskl.service.HistoryService.REPLAY).times(4);
// sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once();
// expect(getLastState().piskel).toBeUndefined();
// sendSaveEvents(pskl.service.HistoryService.REPLAY_NO_SNAPSHOT).once();
// expect(getLastState().piskel).toBeUndefined();
// sendSaveEvents(pskl.service.HistoryService.REPLAY).once();
// expect(getLastState().piskel).toBe(SERIALIZED_PISKEL);
// // AFTER
// pskl.service.HistoryService.SNAPSHOT_PERIOD = SNAPSHOT_PERIOD_BACKUP;
// })
});