mirror of
https://github.com/piskelapp/piskel.git
synced 2023-08-10 21:12:52 +03:00
Merge pull request #203 from juliandescottes/feature-swap-color
Feature swap color
This commit is contained in:
@@ -97,11 +97,18 @@
|
||||
background-size: 23px 23px;
|
||||
}
|
||||
|
||||
.tool-icon.tool-colorswap {
|
||||
background-image: url(../img/tools/swap-colors.png);
|
||||
background-position: 6px 6px;
|
||||
background-size: 36px 36px;
|
||||
}
|
||||
|
||||
/*
|
||||
* Tool cursors:
|
||||
*/
|
||||
|
||||
.tool-paint-bucket .drawing-canvas-container:hover {
|
||||
.tool-paint-bucket .drawing-canvas-container:hover,
|
||||
.tool-colorswap .drawing-canvas-container:hover {
|
||||
cursor: url(../img/icons/paint-bucket.png) 12 12, pointer;
|
||||
}
|
||||
|
||||
@@ -228,4 +235,28 @@
|
||||
);
|
||||
}
|
||||
|
||||
.tools-tooltip-container {
|
||||
text-align: left;
|
||||
padding-bottom: 5px;
|
||||
}
|
||||
|
||||
.tools-tooltip-shortcut {
|
||||
color:gold;
|
||||
}
|
||||
|
||||
.tools-tooltip-descriptor {
|
||||
color:#999;
|
||||
}
|
||||
|
||||
.tools-tooltip-descriptor-button {
|
||||
padding:2px;
|
||||
border:1px Solid #999;
|
||||
font-size:0.8em;
|
||||
margin-right:5px;
|
||||
width:35px;
|
||||
text-align:center;
|
||||
border-radius:3px;
|
||||
display:inline-block;
|
||||
line-height: 10px;
|
||||
}
|
||||
|
||||
|
BIN
src/img/tools/swap-colors.png
Normal file
BIN
src/img/tools/swap-colors.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 6.6 KiB |
@@ -9,8 +9,9 @@
|
||||
this.tools = [
|
||||
toDescriptor('simplePen', 'P', new pskl.drawingtools.SimplePen()),
|
||||
toDescriptor('verticalMirrorPen', 'V', new pskl.drawingtools.VerticalMirrorPen()),
|
||||
toDescriptor('eraser', 'E', new pskl.drawingtools.Eraser()),
|
||||
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()),
|
||||
@@ -130,14 +131,10 @@
|
||||
return pskl.utils.Template.replace(tpl, {
|
||||
cssclass : classList.join(' '),
|
||||
toolid : toolId,
|
||||
title : this.getTooltipText_(tool)
|
||||
title : tool.instance.getTooltipText(tool.shortcut)
|
||||
});
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.getTooltipText_ = function (tool) {
|
||||
return tool.instance.helpText + ' (' + tool.shortcut + ')';
|
||||
};
|
||||
|
||||
ns.ToolController.prototype.addKeyboardShortcuts_ = function () {
|
||||
for(var i = 0 ; i < this.tools.length ; i++) {
|
||||
pskl.app.shortcutService.addShortcut(this.tools[i].shortcut, this.onKeyboardShortcut_.bind(this));
|
||||
|
@@ -43,7 +43,7 @@
|
||||
try {
|
||||
overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR);
|
||||
} catch (e) {
|
||||
console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed');
|
||||
window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed');
|
||||
}
|
||||
this.highlightedPixelRow = null;
|
||||
this.highlightedPixelCol = null;
|
||||
@@ -58,11 +58,45 @@
|
||||
});
|
||||
};
|
||||
|
||||
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) {};
|
||||
|
||||
/**
|
||||
* Bresenham line algorihtm: Get an array of pixels from
|
||||
* Bresenham line algorithm: Get an array of pixels from
|
||||
* start and end coordinates.
|
||||
*
|
||||
* http://en.wikipedia.org/wiki/Bresenham's_line_algorithm
|
||||
|
@@ -10,6 +10,7 @@
|
||||
ns.ShapeTool.call(this);
|
||||
|
||||
this.toolId = "tool-circle";
|
||||
|
||||
this.helpText = "Circle tool";
|
||||
};
|
||||
|
||||
|
58
src/js/drawingtools/ColorSwap.js
Normal file
58
src/js/drawingtools/ColorSwap.js
Normal file
@@ -0,0 +1,58 @@
|
||||
/**
|
||||
* @provide pskl.drawingtools.ColorSwap
|
||||
*
|
||||
*/
|
||||
(function() {
|
||||
var ns = $.namespace("pskl.drawingtools");
|
||||
|
||||
ns.ColorSwap = function() {
|
||||
this.toolId = "tool-colorswap";
|
||||
|
||||
this.helpText = "Paint all pixels of the same color";
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'ctrl', description : 'Apply to all layers'},
|
||||
{key : 'shift', description : 'Apply to all frames'}
|
||||
];
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ColorSwap, ns.BaseTool);
|
||||
|
||||
/**
|
||||
* @override
|
||||
*/
|
||||
ns.ColorSwap.prototype.applyToolAt = function(col, row, color, frame, overlay, event) {
|
||||
if (frame.containsPixel(col, row)) {
|
||||
var sampledColor = frame.getPixel(col, row);
|
||||
|
||||
var allLayers = pskl.utils.UserAgent.isMac ? event.metaKey : event.ctrlKey;
|
||||
var allFrames = event.shiftKey;
|
||||
|
||||
this.swapColors(sampledColor, color, allLayers, allFrames);
|
||||
|
||||
$.publish(Events.PISKEL_SAVE_STATE, {
|
||||
type : pskl.service.HistoryService.SNAPSHOT
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
ns.ColorSwap.prototype.swapColors = function(oldColor, newColor, allLayers, allFrames) {
|
||||
var swapPixelColor = function (pixelColor,x,y,frame) {
|
||||
if (pixelColor == oldColor) {
|
||||
frame.pixels[x][y] = newColor;
|
||||
}
|
||||
};
|
||||
var currentLayer = pskl.app.piskelController.getCurrentLayer();
|
||||
var currentFrameIndex = pskl.app.piskelController.getCurrentFrameIndex();
|
||||
pskl.app.piskelController.getPiskel().getLayers().forEach(function (l) {
|
||||
if (allLayers || l === currentLayer) {
|
||||
l.getFrames().forEach(function (f, frameIndex) {
|
||||
if (allFrames || frameIndex === currentFrameIndex) {
|
||||
f.forEachPixel(swapPixelColor);
|
||||
f.version++;
|
||||
}
|
||||
});
|
||||
}
|
||||
});
|
||||
};
|
||||
})();
|
@@ -11,7 +11,14 @@
|
||||
ns.Lighten = function() {
|
||||
this.superclass.constructor.call(this);
|
||||
this.toolId = "tool-lighten";
|
||||
this.helpText = "Lighten (hold ctrl for Darken)";
|
||||
|
||||
this.helpText = "Lighten";
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'ctrl', description : 'Darken'},
|
||||
{key : 'shift', description : 'Apply only once per pixel'}
|
||||
];
|
||||
|
||||
this.resetUsedPixels_();
|
||||
};
|
||||
|
||||
@@ -31,7 +38,7 @@
|
||||
var frameColor = frame.getPixel(col, row);
|
||||
var pixelColor = overlayColor === Constants.TRANSPARENT_COLOR ? frameColor : overlayColor;
|
||||
|
||||
var isDarken = event.ctrlKey || event.cmdKey;
|
||||
var isDarken = pskl.utils.UserAgent.isMac ? event.metaKey : event.ctrlKey;
|
||||
var isSinglePass = event.shiftKey;
|
||||
|
||||
var isTransparent = pixelColor === Constants.TRANSPARENT_COLOR;
|
||||
|
@@ -10,7 +10,8 @@
|
||||
ns.ShapeTool.call(this);
|
||||
|
||||
this.toolId = "tool-rectangle";
|
||||
this.helpText = "Rectangle tool";
|
||||
|
||||
this.shortHelpText = "Rectangle tool";
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.Rectangle, ns.ShapeTool);
|
||||
|
@@ -8,6 +8,10 @@
|
||||
// Shapes's first point coordinates (set in applyToolAt)
|
||||
this.startCol = null;
|
||||
this.startRow = null;
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'shift', description : 'Keep 1 to 1 ratio'}
|
||||
];
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.ShapeTool, ns.BaseTool);
|
||||
|
@@ -5,7 +5,12 @@
|
||||
this.superclass.constructor.call(this);
|
||||
|
||||
this.toolId = "tool-vertical-mirror-pen";
|
||||
this.helpText = "Vertical Mirror pen tool (hold CTRL for Horizontal, hold SHIFT for both)";
|
||||
this.helpText = "Vertical Mirror pen";
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{key : 'ctrl', description : 'Use horizontal axis'},
|
||||
{key : 'shift', description : 'Use horizontal and vertical axis'}
|
||||
];
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.VerticalMirrorPen, ns.SimplePen);
|
||||
@@ -30,11 +35,12 @@
|
||||
var mirroredCol = this.getSymmetricCol_(col, frame);
|
||||
var mirroredRow = this.getSymmetricRow_(row, frame);
|
||||
|
||||
if (!event.ctrlKey) {
|
||||
var hasCtrlKey = pskl.utils.UserAgent.isMac ? event.metaKey : event.ctrlKey;
|
||||
if (!hasCtrlKey) {
|
||||
this.superclass.applyToolAt.call(this, mirroredCol, row, color, frame, overlay);
|
||||
}
|
||||
|
||||
if (event.shiftKey || event.ctrlKey) {
|
||||
if (event.shiftKey || hasCtrlKey) {
|
||||
this.superclass.applyToolAt.call(this, col, mirroredRow, color, frame, overlay);
|
||||
}
|
||||
|
||||
|
@@ -15,6 +15,12 @@
|
||||
this.startRow = null;
|
||||
|
||||
this.selection = null;
|
||||
|
||||
this.tooltipDescriptors = [
|
||||
{description : "Drag the selection to move it. You may switch to other layers and frames."},
|
||||
{key : 'ctrl+c', description : 'Copy the selected area'},
|
||||
{key : 'ctrl+v', description : 'Paste the copied area'}
|
||||
];
|
||||
};
|
||||
|
||||
pskl.utils.inherit(ns.BaseSelect, ns.BaseTool);
|
||||
|
@@ -8,7 +8,8 @@
|
||||
|
||||
ns.RectangleSelect = function() {
|
||||
this.toolId = "tool-rectangle-select";
|
||||
this.helpText = "Rectangle selection tool";
|
||||
|
||||
this.helpText = "Rectangle selection";
|
||||
|
||||
ns.BaseSelect.call(this);
|
||||
this.hasSelection = false;
|
||||
|
@@ -8,7 +8,8 @@
|
||||
|
||||
ns.ShapeSelect = function() {
|
||||
this.toolId = "tool-shape-select";
|
||||
this.helpText = "Shape selection tool";
|
||||
|
||||
this.helpText = "Shape selection";
|
||||
|
||||
ns.BaseSelect.call(this);
|
||||
};
|
||||
|
@@ -84,28 +84,30 @@
|
||||
return [this.id, this.version].join('-');
|
||||
};
|
||||
|
||||
ns.Frame.prototype.setPixel = function (col, row, color) {
|
||||
if (this.containsPixel(col, row)) {
|
||||
var p = this.pixels[col][row];
|
||||
ns.Frame.prototype.setPixel = function (x, y, color) {
|
||||
if (this.containsPixel(x, y)) {
|
||||
var p = this.pixels[x][y];
|
||||
if (p !== color) {
|
||||
this.pixels[col][row] = color;
|
||||
this.pixels[x][y] = color;
|
||||
this.version++;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
ns.Frame.prototype.getPixel = function (col, row) {
|
||||
if (this.containsPixel(col, row)) {
|
||||
return this.pixels[col][row];
|
||||
ns.Frame.prototype.getPixel = function (x, y) {
|
||||
if (this.containsPixel(x, y)) {
|
||||
return this.pixels[x][y];
|
||||
} else {
|
||||
return null;
|
||||
}
|
||||
};
|
||||
|
||||
ns.Frame.prototype.forEachPixel = function (callback) {
|
||||
for (var col = 0 ; col < this.getWidth() ; col++) {
|
||||
for (var row = 0 ; row < this.getHeight() ; row++) {
|
||||
callback(this.getPixel(col, row), col, row);
|
||||
var width = this.getWidth();
|
||||
var height = this.getHeight();
|
||||
for (var x = 0 ; x < width ; x++) {
|
||||
for (var y = 0 ; y < height ; y++) {
|
||||
callback(this.pixels[x][y], x, y, this);
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -122,29 +124,6 @@
|
||||
return col >= 0 && row >= 0 && col < this.width && row < this.height;
|
||||
};
|
||||
|
||||
ns.Frame.prototype.saveState = function () {
|
||||
// remove all states past current state
|
||||
this.previousStates.length = this.stateIndex + 1;
|
||||
// push new state
|
||||
this.previousStates.push(this.getPixels());
|
||||
// set the stateIndex to latest saved state
|
||||
this.stateIndex = this.previousStates.length - 1;
|
||||
};
|
||||
|
||||
ns.Frame.prototype.loadPreviousState = function () {
|
||||
if (this.stateIndex > 0) {
|
||||
this.stateIndex--;
|
||||
this.setPixels(this.previousStates[this.stateIndex]);
|
||||
}
|
||||
};
|
||||
|
||||
ns.Frame.prototype.loadNextState = function () {
|
||||
if (this.stateIndex < this.previousStates.length - 1) {
|
||||
this.stateIndex++;
|
||||
this.setPixels(this.previousStates[this.stateIndex]);
|
||||
}
|
||||
};
|
||||
|
||||
ns.Frame.prototype.isSameSize = function (otherFrame) {
|
||||
return this.getHeight() == otherFrame.getHeight() && this.getWidth() == otherFrame.getWidth();
|
||||
};
|
||||
|
@@ -55,6 +55,9 @@
|
||||
};
|
||||
|
||||
ns.CheatsheetService.prototype.toDescriptor_ = function (shortcut, description, icon) {
|
||||
if (pskl.utils.UserAgent.isMac) {
|
||||
shortcut = shortcut.replace('ctrl', 'cmd');
|
||||
}
|
||||
return {
|
||||
'shortcut' : shortcut,
|
||||
'description' : description,
|
||||
@@ -84,7 +87,7 @@
|
||||
|
||||
ns.CheatsheetService.prototype.initMarkupForTools_ = function () {
|
||||
var descriptors = pskl.app.toolController.tools.map(function (tool) {
|
||||
return this.toDescriptor_(tool.shortcut, tool.instance.helpText, 'tool-icon ' + tool.instance.toolId);
|
||||
return this.toDescriptor_(tool.shortcut, tool.instance.getHelpText(), 'tool-icon ' + tool.instance.toolId);
|
||||
}.bind(this));
|
||||
|
||||
this.initMarkupAbstract_(descriptors, '.cheatsheet-tool-shortcuts');
|
||||
|
@@ -107,7 +107,7 @@
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.isCtrlKeyPressed_ = function (evt) {
|
||||
return this.isMac_() ? evt.metaKey : evt.ctrlKey;
|
||||
return pskl.utils.UserAgent.isMac ? evt.metaKey : evt.ctrlKey;
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.isShiftKeyPressed_ = function (evt) {
|
||||
@@ -117,8 +117,4 @@
|
||||
ns.ShortcutService.prototype.isAltKeyPressed_ = function (evt) {
|
||||
return evt.altKey;
|
||||
};
|
||||
|
||||
ns.ShortcutService.prototype.isMac_ = function () {
|
||||
return navigator.appVersion.indexOf("Mac") != -1;
|
||||
};
|
||||
})();
|
@@ -1,14 +1,18 @@
|
||||
(function () {
|
||||
var ns = $.namespace("pskl.utils");
|
||||
var templates = {};
|
||||
|
||||
ns.Template = {
|
||||
get : function (templateId) {
|
||||
var template = document.getElementById(templateId);
|
||||
if (template) {
|
||||
return template.innerHTML;
|
||||
} else {
|
||||
console.error("Could not find template for id :", templateId);
|
||||
if (!templates[templateId]) {
|
||||
var template = document.getElementById(templateId);
|
||||
if (template) {
|
||||
templates[templateId] = template.innerHTML;
|
||||
} else {
|
||||
console.error("Could not find template for id :", templateId);
|
||||
}
|
||||
}
|
||||
return templates[templateId];
|
||||
},
|
||||
|
||||
createFromHTML : function (html) {
|
||||
|
@@ -6,7 +6,8 @@
|
||||
isIE : /MSIE/i.test( ua ),
|
||||
isIE11 : /trident/i.test( ua ),
|
||||
isChrome : /Chrome/i.test( ua ),
|
||||
isFirefox : /Firefox/i.test( ua )
|
||||
isFirefox : /Firefox/i.test( ua ),
|
||||
isMac : /Mac/.test( ua )
|
||||
};
|
||||
|
||||
ns.UserAgent.version = (function () {
|
||||
|
@@ -131,6 +131,7 @@
|
||||
"js/drawingtools/selectiontools/RectangleSelect.js",
|
||||
"js/drawingtools/selectiontools/ShapeSelect.js",
|
||||
"js/drawingtools/ColorPicker.js",
|
||||
"js/drawingtools/ColorSwap.js",
|
||||
// Application controller and initialization
|
||||
"js/app.js"
|
||||
];
|
@@ -1,10 +1,9 @@
|
||||
<div class="sticky-section left-sticky-section" id="tool-section">
|
||||
<div class="sticky-section-wrap">
|
||||
<div class="vertical-centerer">
|
||||
<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>
|
||||
<ul id="tools-container" class="tools-wrapper"></ul>
|
||||
<ul id="tools-container" class="tools-wrapper">
|
||||
<!-- Drawing tools will be inserted here -->
|
||||
</ul>
|
||||
<div class="palette-wrapper">
|
||||
<div
|
||||
class="tool-icon tool-color-picker"
|
||||
@@ -31,4 +30,34 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- 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>
|
||||
|
||||
<!-- Drawing tool tooltip container -->
|
||||
<script type="text/template" id="drawing-tool-tooltip-container-template">
|
||||
<div class='tools-tooltip-container'>
|
||||
<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">
|
||||
<div class='tools-tooltip-descriptor'>
|
||||
<span class='tools-tooltip-descriptor-button'>{{key}}</span>
|
||||
{{description}}
|
||||
</div>
|
||||
</script>
|
||||
|
||||
<!-- Drawing tool tooltip line -->
|
||||
<script type="text/template" id="drawing-tool-tooltip-descriptor-simple-template">
|
||||
<div class='tools-tooltip-descriptor'>
|
||||
{{description}}
|
||||
</div>
|
||||
</script>
|
||||
</div>
|
Reference in New Issue
Block a user