Issue #258 : Initial implementation : missing tests + cleanup

This commit is contained in:
jdescottes 2015-11-17 00:19:25 +01:00
parent 4196576c19
commit 222c65a8a5
18 changed files with 257 additions and 41 deletions

53
src/css/pensize.css Normal file
View File

@ -0,0 +1,53 @@
.pen-size-container {
overflow: hidden;
padding: 5px 5px;
}
.pen-size-option {
float: left;
box-sizing: border-box;
width: 20px;
height: 20px;
margin-right: 2px;
border-style: solid;
border-width: 2px;
border-color: #444;
cursor: pointer;
}
.pen-size-option[data-size='1'] {
padding: 6px;
}
.pen-size-option[data-size='2'] {
padding: 5px;
}
.pen-size-option[data-size='3'] {
padding: 4px;
}
.pen-size-option[data-size='4'] {
padding: 3px;
}
.pen-size-option:before {
content: '';
width: 100%;
height: 100%;
background-color: #444;
display: block;
}
.pen-size-option:hover:before {
background-color: #888;
}
.pen-size-option:hover {
border-color: #888;
}
.pen-size-option.selected:before {
background-color: gold;
}
.pen-size-option.selected {
border-color: gold;
}

View File

@ -43,6 +43,8 @@ var Events = {
HISTORY_STATE_SAVED: 'HISTORY_STATE_SAVED',
HISTORY_STATE_LOADED: 'HISTORY_STATE_LOADED',
PEN_SIZE_CHANGED : 'PEN_SIZE_CHANGED',
/**
* Fired when a Piskel is successfully saved
*/

View File

@ -139,6 +139,12 @@
this.headerController = new pskl.controller.HeaderController(this.piskelController, this.savedStatusService);
this.headerController.init();
this.penSizeService = new pskl.service.pensize.PenSizeService();
this.penSizeService.init();
this.penSizeController = new pskl.controller.PenSizeController();
this.penSizeController.init();
this.fileDropperService = new pskl.service.FileDropperService(
this.piskelController,
document.querySelector('#drawing-canvas-container'));

View File

@ -0,0 +1,35 @@
(function () {
var ns = $.namespace('pskl.controller');
ns.PenSizeController = function () {};
ns.PenSizeController.prototype.init = function () {
this.container = document.querySelector('.pen-size-container');
pskl.utils.Event.addEventListener(this.container, 'click', this.onPenSizeOptionClick_, this);
$.subscribe(Events.PEN_SIZE_CHANGED, this.onPenSizeChanged_.bind(this));
this.updateSelectedOption_();
};
ns.PenSizeController.prototype.onPenSizeOptionClick_ = function (e) {
var size = e.target.dataset.size;
if (!isNaN(size)) {
size = parseInt(size, 10);
pskl.app.penSizeService.setPenSize(size);
}
};
ns.PenSizeController.prototype.onPenSizeChanged_ = function (e) {
this.updateSelectedOption_();
};
ns.PenSizeController.prototype.updateSelectedOption_ = function () {
pskl.utils.Dom.removeClass('selected', this.container);
var size = pskl.app.penSizeService.getPenSize();
var selectedOption = this.container.querySelector('[data-size="' + size + '"]');
if (selectedOption) {
selectedOption.classList.add('selected');
}
};
})();

View File

@ -0,0 +1,46 @@
(function () {
var ns = $.namespace('pskl.service.pensize');
ns.PenSizeService = function () {};
ns.PenSizeService.prototype.init = function () {
this.size = pskl.UserSettings.get('PEN_SIZE');
};
ns.PenSizeService.prototype.setPenSize = function (size) {
if (size != this.size) {
this.size = size;
pskl.UserSettings.set('PEN_SIZE', size);
$.publish(Events.PEN_SIZE_CHANGED);
}
};
ns.PenSizeService.prototype.getPenSize = function () {
return this.size;
};
ns.PenSizeService.prototype.getPixelsForPenSize = function (col, row, penSize) {
var size = penSize || this.size;
if (size == 1) {
return [[col, row]];
} else if (size == 2) {
return [
[col, row], [col + 1, row],
[col, row + 1], [col + 1, row + 1]
];
} else if (size == 3) {
return [
[col - 1, row - 1], [col, row - 1], [col + 1, row - 1],
[col - 1, row + 0], [col, row + 0], [col + 1, row + 0],
[col - 1, row + 1], [col, row + 1], [col + 1, row + 1],
];
} else if (size == 4) {
return [
[col - 1, row - 1], [col, row - 1], [col + 1, row - 1], [col + 2, row - 1],
[col - 1, row + 0], [col, row + 0], [col + 1, row + 0], [col + 2, row + 0],
[col - 1, row + 1], [col, row + 1], [col + 1, row + 1], [col + 2, row + 1],
[col - 1, row + 2], [col, row + 2], [col + 1, row + 2], [col + 2, row + 2],
];
}
};
})();

View File

@ -19,6 +19,10 @@
ns.BaseTool.prototype.replay = Constants.ABSTRACT_FUNCTION;
ns.BaseTool.prototype.supportsDynamicPenSize = function() {
return false;
};
ns.BaseTool.prototype.getToolColor = function() {
if (pskl.app.mouseStateService.isRightButtonPressed()) {
return pskl.app.selectedColorsService.getSecondaryColor();
@ -45,7 +49,15 @@
}
var frameColor = frame.getPixel(col, row);
overlay.setPixel(col, row, this.getHighlightColor_(frameColor));
if (this.supportsDynamicPenSize()) {
var pixels = pskl.app.penSizeService.getPixelsForPenSize(col, row);
pixels.forEach(function (p) {
overlay.setPixel(p[0], p[1], this.getHighlightColor_(frameColor));
}.bind(this));
} else {
overlay.setPixel(col, row, this.getHighlightColor_(frameColor));
}
this.highlightedPixelCol = col;
this.highlightedPixelRow = row;
@ -66,11 +78,7 @@
ns.BaseTool.prototype.hideHighlightedPixel = function (overlay) {
if (this.highlightedPixelRow !== null && this.highlightedPixelCol !== null) {
try {
overlay.setPixel(this.highlightedPixelCol, this.highlightedPixelRow, Constants.TRANSPARENT_COLOR);
} catch (e) {
window.console.warn('ns.BaseTool.prototype.hideHighlightedPixel failed');
}
overlay.clear();
this.highlightedPixelRow = null;
this.highlightedPixelCol = null;
}

View File

@ -19,11 +19,17 @@
/**
* @override
*/
ns.Circle.prototype.draw = function (col, row, color, targetFrame) {
ns.Circle.prototype.draw = function (col, row, color, targetFrame, penSize) {
var circlePoints = this.getCirclePixels_(this.startCol, this.startRow, col, row);
var applyDraw = function (p) {
targetFrame.setPixel(p[0], p[1], color);
}.bind(this);
for (var i = 0 ; i < circlePoints.length ; i++) {
// Change model:
targetFrame.setPixel(circlePoints[i].col, circlePoints[i].row, color);
var pixels = pskl.app.penSizeService.getPixelsForPenSize(circlePoints[i].col, circlePoints[i].row, penSize);
pixels.forEach(applyDraw);
}
};

View File

@ -12,12 +12,20 @@
this.helpText = 'Dithering tool';
this.shortcut = pskl.service.keyboard.Shortcuts.TOOL.DITHERING;
};
pskl.utils.inherit(ns.DitheringTool, ns.SimplePen);
ns.DitheringTool.prototype.supportsDynamicPenSize = function() {
return false;
};
/**
* @override
*/
ns.DitheringTool.prototype.applyToolAt = function(col, row, frame, overlay, event) {
this.previousCol = col;
this.previousRow = row;
var usePrimaryColor = (col + row) % 2;
usePrimaryColor =
pskl.app.mouseStateService.isRightButtonPressed() ? !usePrimaryColor : usePrimaryColor;

View File

@ -43,8 +43,14 @@
* @Override
*/
ns.Lighten.prototype.applyToolAt = function(col, row, frame, overlay, event) {
var modifiedColor = this.getModifiedColor_(col, row, frame, overlay, event);
this.draw(modifiedColor, col, row, frame, overlay);
this.previousCol = col;
this.previousRow = row;
var pixels = pskl.app.penSizeService.getPixelsForPenSize(col, row);
pixels.forEach(function (p) {
var modifiedColor = this.getModifiedColor_(p[0], p[1], frame, overlay, event);
this.draw(modifiedColor, p[0], p[1], frame, overlay);
}.bind(this));
};
ns.Lighten.prototype.getModifiedColor_ = function(col, row, frame, overlay, event) {

View File

@ -19,11 +19,17 @@
/**
* @override
*/
ns.Rectangle.prototype.draw = function (col, row, color, targetFrame) {
ns.Rectangle.prototype.draw = function (col, row, color, targetFrame, penSize) {
var strokePoints = pskl.PixelUtils.getBoundRectanglePixels(this.startCol, this.startRow, col, row);
var applyDraw = function (p) {
targetFrame.setPixel(p[0], p[1], color);
}.bind(this);
for (var i = 0 ; i < strokePoints.length ; i++) {
// Change model:
targetFrame.setPixel(strokePoints[i].col, strokePoints[i].row, color);
var pixels = pskl.app.penSizeService.getPixelsForPenSize(strokePoints[i].col, strokePoints[i].row, penSize);
pixels.forEach(applyDraw);
}
};
})();

View File

@ -16,6 +16,10 @@
pskl.utils.inherit(ns.ShapeTool, ns.BaseTool);
ns.ShapeTool.prototype.supportsDynamicPenSize = function() {
return true;
};
/**
* @override
*/
@ -57,7 +61,8 @@
row : coords.row,
startCol : this.startCol,
startRow : this.startRow,
color : color
color : color,
penSize : pskl.app.penSizeService.getPenSize()
});
};
@ -67,7 +72,7 @@
ns.ShapeTool.prototype.replay = function(frame, replayData) {
this.startCol = replayData.startCol;
this.startRow = replayData.startRow;
this.draw(replayData.col, replayData.row, replayData.color, frame);
this.draw(replayData.col, replayData.row, replayData.color, frame, replayData.penSize);
};
/**

View File

@ -19,18 +19,30 @@
pskl.utils.inherit(ns.SimplePen, ns.BaseTool);
ns.SimplePen.prototype.supportsDynamicPenSize = function() {
return true;
};
/**
* @override
*/
ns.SimplePen.prototype.applyToolAt = function(col, row, frame, overlay, event) {
var color = this.getToolColor();
this.draw(color, col, row, frame, overlay);
};
ns.SimplePen.prototype.draw = function(color, col, row, frame, overlay) {
this.previousCol = col;
this.previousRow = row;
var color = this.getToolColor();
this.drawUsingPenSize(color, col, row, frame, overlay);
};
ns.SimplePen.prototype.drawUsingPenSize = function(color, col, row, frame, overlay) {
var pixels = pskl.app.penSizeService.getPixelsForPenSize(col, row);
pixels.forEach(function (p) {
this.draw(color, p[0], p[1], frame, overlay);
}.bind(this));
};
ns.SimplePen.prototype.draw = function(color, col, row, frame, overlay) {
overlay.setPixel(col, row, color);
if (color === Constants.TRANSPARENT_COLOR) {
frame.setPixel(col, row, color);

View File

@ -21,6 +21,10 @@
pskl.utils.inherit(ns.Stroke, ns.BaseTool);
ns.Stroke.prototype.supportsDynamicPenSize = function() {
return true;
};
/**
* @override
*/
@ -55,6 +59,11 @@
// Drawing current stroke:
var color = this.getToolColor();
var setPixel = function (p) {
overlay.setPixel(p[0], p[1], color);
}.bind(this);
for (var i = 0; i < strokePoints.length; i++) {
if (color == Constants.TRANSPARENT_COLOR) {
@ -66,7 +75,9 @@
// eg deleting the equivalent of a stroke.
color = Constants.SELECTION_TRANSPARENT_COLOR;
}
overlay.setPixel(strokePoints[i].col, strokePoints[i].row, color);
var pixels = pskl.app.penSizeService.getPixelsForPenSize(strokePoints[i].col, strokePoints[i].row);
pixels.forEach(setPixel);
}
};
@ -82,25 +93,38 @@
row = coords.row;
}
var setPixel = function (p) {
frame.setPixel(p[0], p[1], color);
}.bind(this);
// The user released the tool to draw a line. We will compute the pixel coordinate, impact
// the model and draw them in the drawing canvas (not the fake overlay anymore)
var strokePoints = this.getLinePixels_(this.startCol, col, this.startRow, row);
for (var i = 0; i < strokePoints.length; i++) {
// Change model:
frame.setPixel(strokePoints[i].col, strokePoints[i].row, color);
var pixels = pskl.app.penSizeService.getPixelsForPenSize(strokePoints[i].col, strokePoints[i].row);
pixels.forEach(setPixel);
}
// For now, we are done with the stroke tool and don't need an overlay anymore:
overlay.clear();
this.raiseSaveStateEvent({
pixels : strokePoints,
color : color
color : color,
penSize : pskl.app.penSizeService.getPenSize()
});
};
ns.Stroke.prototype.replay = function(frame, replayData) {
var color = replayData.color;
var setPixel = function (p) {
frame.setPixel(p[0], p[1], color);
}.bind(this);
replayData.pixels.forEach(function (pixel) {
frame.setPixel(pixel.col, pixel.row, replayData.color);
var pixels = pskl.app.penSizeService.getPixelsForPenSize(pixel.col, pixel.row);
pixels.forEach(setPixel);
});
};

View File

@ -16,42 +16,31 @@
pskl.utils.inherit(ns.VerticalMirrorPen, ns.SimplePen);
ns.VerticalMirrorPen.prototype.backupPreviousPositions_ = function () {
this.backupPreviousCol = this.previousCol;
this.backupPreviousRow = this.previousRow;
};
ns.VerticalMirrorPen.prototype.restorePreviousPositions_ = function () {
this.previousCol = this.backupPreviousCol;
this.previousRow = this.backupPreviousRow;
};
/**
* @override
*/
ns.VerticalMirrorPen.prototype.applyToolAt = function(col, row, frame, overlay, event) {
var color = this.getToolColor();
this.draw(color, col, row, frame, overlay);
this.backupPreviousPositions_();
this.drawUsingPenSize(color, col, row, frame, overlay);
var mirroredCol = this.getSymmetricCol_(col, frame);
var mirroredRow = this.getSymmetricRow_(row, frame);
var hasCtrlKey = pskl.utils.UserAgent.isMac ? event.metaKey : event.ctrlKey;
if (!hasCtrlKey) {
this.draw(color, mirroredCol, row, frame, overlay);
this.drawUsingPenSize(color, mirroredCol, row, frame, overlay);
}
if (event.shiftKey || hasCtrlKey) {
this.draw(color, col, mirroredRow, frame, overlay);
this.drawUsingPenSize(color, col, mirroredRow, frame, overlay);
}
if (event.shiftKey) {
this.draw(color, mirroredCol, mirroredRow, frame, overlay);
this.drawUsingPenSize(color, mirroredCol, mirroredRow, frame, overlay);
}
this.restorePreviousPositions_();
this.previousCol = col;
this.previousRow = row;
};
ns.VerticalMirrorPen.prototype.getSymmetricCol_ = function(col, frame) {

View File

@ -13,8 +13,8 @@
LAYER_PREVIEW : 'LAYER_PREVIEW',
LAYER_OPACITY : 'LAYER_OPACITY',
EXPORT_SCALING: 'EXPORT_SCALING',
PEN_SIZE : 'PEN_SIZE',
RESIZE_SETTINGS: 'RESIZE_SETTINGS',
KEY_TO_DEFAULT_VALUE_MAP_ : {
'GRID_WIDTH' : 0,
'MAX_FPS' : 24,
@ -30,6 +30,7 @@
'LAYER_OPACITY' : 0.2,
'LAYER_PREVIEW' : true,
'EXPORT_SCALING' : 1,
'PEN_SIZE' : 1,
'RESIZE_SETTINGS': {
maintainRatio : true,
resizeContent : false,

View File

@ -103,6 +103,7 @@
"js/controller/ToolController.js",
"js/controller/PaletteController.js",
"js/controller/PalettesListController.js",
"js/controller/PenSizeController.js",
"js/controller/ProgressBarController.js",
"js/controller/NotificationController.js",
"js/controller/TransformationsController.js",
@ -157,6 +158,7 @@
"js/service/palette/reader/PalettePalReader.js",
"js/service/palette/reader/PaletteTxtReader.js",
"js/service/palette/PaletteImportService.js",
"js/service/pensize/PenSizeService.js",
"js/service/SavedStatusService.js",
"js/service/keyboard/KeycodeTranslator.js",
"js/service/keyboard/KeyUtils.js",

View File

@ -14,6 +14,7 @@
"css/settings-resize.css",
"css/settings-save.css",
"css/tools.css",
"css/pensize.css",
"css/icons.css",
"css/color-picker-slider.css",
"css/dialogs.css",

View File

@ -1,6 +1,12 @@
<div class="sticky-section left-sticky-section" id="tool-section">
<div class="sticky-section-wrap">
<div class="vertical-centerer">
<div class="pen-size-container">
<div class="pen-size-option" data-size="1" title="1 pixel pen-size" rel="tooltip" data-placement="right"></div>
<div class="pen-size-option" data-size="2" title="2 pixels pen-size" rel="tooltip" data-placement="right"></div>
<div class="pen-size-option" data-size="3" title="3 pixels pen-size" rel="tooltip" data-placement="right"></div>
<div class="pen-size-option" data-size="4" title="4 pixels pen-size" rel="tooltip" data-placement="right"></div>
</div>
<ul id="tools-container" class="tools-wrapper">
<!-- Drawing tools will be inserted here -->
</ul>