mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Add outliner tool.
This commit is contained in:
parent
cb41a72b5b
commit
0f5501bc3b
BIN
misc/proto-ui-1/img/outliner-icon-dark.png
Normal file
BIN
misc/proto-ui-1/img/outliner-icon-dark.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 4.0 KiB |
BIN
misc/proto-ui-1/img/outliner-icon.png
Normal file
BIN
misc/proto-ui-1/img/outliner-icon.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.2 KiB |
@ -46,6 +46,7 @@ body {
|
|||||||
.tool.bucket { background-image: url(img/paintbucket-icon.png); }
|
.tool.bucket { background-image: url(img/paintbucket-icon.png); }
|
||||||
.tool.pen { background-image: url(img/pen-icon.png); }
|
.tool.pen { background-image: url(img/pen-icon.png); }
|
||||||
.tool.eyedropper { background-image: url(img/eyedropper-icon.png);}
|
.tool.eyedropper { background-image: url(img/eyedropper-icon.png);}
|
||||||
|
.tool.outliner { background-image: url(img/outliner-icon.png);} /* TODO!!! replace */
|
||||||
|
|
||||||
.tool:hover {
|
.tool:hover {
|
||||||
cursor: pointer;
|
cursor: pointer;
|
||||||
|
@ -202,6 +202,10 @@
|
|||||||
background-image: url(../img/icons/tools/tool-paint-bucket.png);
|
background-image: url(../img/icons/tools/tool-paint-bucket.png);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cheatsheet-icon-tool-outliner {
|
||||||
|
background-image: url(../img/icons/tools/tool-outliner.png);
|
||||||
|
}
|
||||||
|
|
||||||
.cheatsheet-icon-tool-pen {
|
.cheatsheet-icon-tool-pen {
|
||||||
background-image: url(../img/icons/tools/tool-pen.png);
|
background-image: url(../img/icons/tools/tool-pen.png);
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@
|
|||||||
*/
|
*/
|
||||||
|
|
||||||
.tool-paint-bucket .drawing-canvas-container:hover,
|
.tool-paint-bucket .drawing-canvas-container:hover,
|
||||||
|
.tool-outliner .drawing-canvas-container:hover,
|
||||||
.tool-colorswap .drawing-canvas-container:hover {
|
.tool-colorswap .drawing-canvas-container:hover {
|
||||||
cursor: url(../img/cursors/paint-bucket.png) 14 14, pointer;
|
cursor: url(../img/cursors/paint-bucket.png) 14 14, pointer;
|
||||||
}
|
}
|
||||||
|
@ -18,7 +18,8 @@
|
|||||||
new pskl.tools.drawing.selection.LassoSelect(),
|
new pskl.tools.drawing.selection.LassoSelect(),
|
||||||
new pskl.tools.drawing.Lighten(),
|
new pskl.tools.drawing.Lighten(),
|
||||||
new pskl.tools.drawing.DitheringTool(),
|
new pskl.tools.drawing.DitheringTool(),
|
||||||
new pskl.tools.drawing.ColorPicker()
|
new pskl.tools.drawing.ColorPicker(),
|
||||||
|
new pskl.tools.drawing.Outliner()
|
||||||
];
|
];
|
||||||
|
|
||||||
this.toolIconBuilder = new pskl.tools.ToolIconBuilder();
|
this.toolIconBuilder = new pskl.tools.ToolIconBuilder();
|
||||||
|
@ -31,7 +31,8 @@
|
|||||||
LASSO_SELECT : createShortcut('tool-lasso-select', 'Lasso selection', 'H'),
|
LASSO_SELECT : createShortcut('tool-lasso-select', 'Lasso selection', 'H'),
|
||||||
LIGHTEN : createShortcut('tool-lighten', 'Lighten tool', 'U'),
|
LIGHTEN : createShortcut('tool-lighten', 'Lighten tool', 'U'),
|
||||||
DITHERING : createShortcut('tool-dithering', 'Dithering tool', 'T'),
|
DITHERING : createShortcut('tool-dithering', 'Dithering tool', 'T'),
|
||||||
COLORPICKER : createShortcut('tool-colorpicker', 'Color picker', 'O')
|
COLORPICKER : createShortcut('tool-colorpicker', 'Color picker', 'O'),
|
||||||
|
OUTLINER : createShortcut('tool-outliner', 'Outliner', 'Q')
|
||||||
},
|
},
|
||||||
|
|
||||||
SELECTION : {
|
SELECTION : {
|
||||||
|
39
src/js/tools/drawing/Outliner.js
Normal file
39
src/js/tools/drawing/Outliner.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
/**
|
||||||
|
* @provide pskl.tools.drawing.Outliner
|
||||||
|
*
|
||||||
|
* @require pskl.utils
|
||||||
|
*/
|
||||||
|
(function() {
|
||||||
|
var ns = $.namespace('pskl.tools.drawing');
|
||||||
|
|
||||||
|
ns.Outliner = function() {
|
||||||
|
this.toolId = 'tool-outliner';
|
||||||
|
this.helpText = 'Outliner tool';
|
||||||
|
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.OUTLINER;
|
||||||
|
this.tooltipDescriptors = [
|
||||||
|
{key : 'ctrl', description : 'Fill corners'}
|
||||||
|
];
|
||||||
|
};
|
||||||
|
|
||||||
|
pskl.utils.inherit(ns.Outliner, ns.BaseTool);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @override
|
||||||
|
*/
|
||||||
|
ns.Outliner.prototype.applyToolAt = function(col, row, frame, overlay, event) {
|
||||||
|
var fillCorners = pskl.utils.UserAgent.isMac ? event.metaKey : event.ctrlKey;
|
||||||
|
var color = this.getToolColor();
|
||||||
|
pskl.PixelUtils.outlineSimilarConnectedPixelsFromFrame(frame, col, row, color, fillCorners);
|
||||||
|
|
||||||
|
this.raiseSaveStateEvent({
|
||||||
|
col : col,
|
||||||
|
row : row,
|
||||||
|
color : color,
|
||||||
|
fillCorners: fillCorners
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
ns.Outliner.prototype.replay = function (frame, replayData) {
|
||||||
|
pskl.PixelUtils.outlineSimilarConnectedPixelsFromFrame(frame, replayData.col, replayData.row, replayData.color, replayData.fillCorners);
|
||||||
|
};
|
||||||
|
})();
|
@ -154,6 +154,76 @@
|
|||||||
return paintedPixels;
|
return paintedPixels;
|
||||||
},
|
},
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Apply the outliner tool in a frame at the (col, row) initial position
|
||||||
|
* with the replacement color.
|
||||||
|
*
|
||||||
|
* @param frame pskl.model.Frame The frame target in which we want to paintbucket
|
||||||
|
* @param col number Column coordinate in the frame
|
||||||
|
* @param row number Row coordinate in the frame
|
||||||
|
* @param replacementColor string Hexadecimal color used to fill the area
|
||||||
|
* @param fillCorners boolean If true, also paint corner pixels
|
||||||
|
*
|
||||||
|
* @return an array of the pixel coordinates paint with the replacement color
|
||||||
|
*/
|
||||||
|
outlineSimilarConnectedPixelsFromFrame: function(frame, col, row, replacementColor, fillCorners) {
|
||||||
|
/**
|
||||||
|
* Acts like floodfill, except that a given pixel is only painted if it has at
|
||||||
|
* least one non-filled-color neighbor.
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
if (typeof replacementColor == 'string') {
|
||||||
|
replacementColor = pskl.utils.colorToInt(replacementColor);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (fillCorners===undefined) {
|
||||||
|
fillCorners = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
var targetColor;
|
||||||
|
try {
|
||||||
|
targetColor = frame.getPixel(col, row);
|
||||||
|
} catch (e) {
|
||||||
|
// Frame out of bound exception.
|
||||||
|
}
|
||||||
|
|
||||||
|
if (targetColor === null || targetColor == replacementColor) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
var atLeastOneNeighborHasNonTargetColor = function(pixel) {
|
||||||
|
for (var y = -1; y <= 1; y++ ) {
|
||||||
|
for (var x = -1; x <= 1; x++ ) {
|
||||||
|
if (x != 0 || y != 0) {
|
||||||
|
if (fillCorners || (x == 0 || y == 0)) {
|
||||||
|
try {
|
||||||
|
var pixelColor = frame.getPixel(pixel.col + x, pixel.row + y);
|
||||||
|
if ( pixelColor !== null && pixelColor !== targetColor) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
// Frame out of bound exception.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
|
||||||
|
var pixels = pskl.PixelUtils.getSimilarConnectedPixelsFromFrame(frame, col, row);
|
||||||
|
pixels = pixels.filter(pixel => atLeastOneNeighborHasNonTargetColor(pixel));
|
||||||
|
|
||||||
|
var paintedPixels = [];
|
||||||
|
|
||||||
|
for (var pixel of pixels) {
|
||||||
|
frame.setPixel(pixel.col, pixel.row, replacementColor);
|
||||||
|
paintedPixels.push(pixel);
|
||||||
|
}
|
||||||
|
|
||||||
|
return paintedPixels;
|
||||||
|
},
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Starting from a provided origin, visit connected pixels using a visitor function.
|
* Starting from a provided origin, visit connected pixels using a visitor function.
|
||||||
* After visiting a pixel, select the 4 connected pixels (up, right, down, left).
|
* After visiting a pixel, select the 4 connected pixels (up, right, down, left).
|
||||||
@ -167,9 +237,6 @@
|
|||||||
* @return {Array} the array of visited pixels {col, row}
|
* @return {Array} the array of visited pixels {col, row}
|
||||||
*/
|
*/
|
||||||
visitConnectedPixels : function (pixel, frame, pixelVisitor) {
|
visitConnectedPixels : function (pixel, frame, pixelVisitor) {
|
||||||
var col = pixel.col;
|
|
||||||
var row = pixel.row;
|
|
||||||
|
|
||||||
var queue = [];
|
var queue = [];
|
||||||
var visitedPixels = [];
|
var visitedPixels = [];
|
||||||
var dy = [-1, 0, 1, 0];
|
var dy = [-1, 0, 1, 0];
|
||||||
|
@ -225,6 +225,7 @@
|
|||||||
"js/tools/drawing/Eraser.js",
|
"js/tools/drawing/Eraser.js",
|
||||||
"js/tools/drawing/Stroke.js",
|
"js/tools/drawing/Stroke.js",
|
||||||
"js/tools/drawing/PaintBucket.js",
|
"js/tools/drawing/PaintBucket.js",
|
||||||
|
"js/tools/drawing/Outliner.js",
|
||||||
"js/tools/drawing/Rectangle.js",
|
"js/tools/drawing/Rectangle.js",
|
||||||
"js/tools/drawing/Circle.js",
|
"js/tools/drawing/Circle.js",
|
||||||
"js/tools/drawing/Move.js",
|
"js/tools/drawing/Move.js",
|
||||||
|
Loading…
Reference in New Issue
Block a user