Merge pull request #235 from juliandescottes/feature-add-effects

Feature add effects
This commit is contained in:
Julian Descottes 2014-11-25 22:43:12 +01:00
commit 62a7755407
54 changed files with 1091 additions and 398 deletions

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.

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>

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

@ -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

@ -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

@ -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

@ -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",
@ -88,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
@ -112,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",
@ -142,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

@ -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;
// })
});