2017-10-12 18:35:30 -04:00
|
|
|
import paper from '@scratch/paper';
|
2017-10-11 11:32:51 -04:00
|
|
|
import {getSelectedLeafItems} from './selection';
|
2017-10-02 15:25:04 -04:00
|
|
|
import {isPGTextItem, isPointTextItem} from './item';
|
|
|
|
import {isGroup} from './group';
|
|
|
|
|
|
|
|
const MIXED = 'scratch-paint/style-path/mixed';
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when setting fill color
|
|
|
|
* @param {string} colorString New color, css format
|
2017-10-05 18:12:22 -04:00
|
|
|
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
2017-10-02 15:25:04 -04:00
|
|
|
*/
|
2017-10-05 18:12:22 -04:00
|
|
|
const applyFillColorToSelection = function (colorString, onUpdateSvg) {
|
2017-10-11 11:58:05 -04:00
|
|
|
const items = getSelectedLeafItems();
|
2017-10-05 18:12:22 -04:00
|
|
|
let changed = false;
|
2017-10-02 15:25:04 -04:00
|
|
|
for (const item of items) {
|
|
|
|
if (isPGTextItem(item)) {
|
|
|
|
for (const child of item.children) {
|
|
|
|
if (child.children) {
|
|
|
|
for (const path of child.children) {
|
|
|
|
if (!path.data.isPGGlyphRect) {
|
2017-10-05 18:12:22 -04:00
|
|
|
if ((path.fillColor === null && colorString) ||
|
|
|
|
path.fillColor.toCSS() !== new paper.Color(colorString).toCSS()) {
|
|
|
|
changed = true;
|
|
|
|
path.fillColor = colorString;
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!child.data.isPGGlyphRect) {
|
2017-10-05 18:12:22 -04:00
|
|
|
if ((child.fillColor === null && colorString) ||
|
|
|
|
child.fillColor.toCSS() !== new paper.Color(colorString).toCSS()) {
|
|
|
|
changed = true;
|
|
|
|
child.fillColor = colorString;
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (isPointTextItem(item) && !colorString) {
|
|
|
|
colorString = 'rgba(0,0,0,0)';
|
|
|
|
}
|
2017-10-05 18:12:22 -04:00
|
|
|
if ((item.fillColor === null && colorString) ||
|
|
|
|
item.fillColor.toCSS() !== new paper.Color(colorString).toCSS()) {
|
|
|
|
changed = true;
|
|
|
|
item.fillColor = colorString;
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
}
|
2017-10-05 18:12:22 -04:00
|
|
|
if (changed) {
|
|
|
|
onUpdateSvg();
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when setting stroke color
|
|
|
|
* @param {string} colorString New color, css format
|
2017-10-05 18:12:22 -04:00
|
|
|
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
2017-10-02 15:25:04 -04:00
|
|
|
*/
|
2017-10-05 18:12:22 -04:00
|
|
|
const applyStrokeColorToSelection = function (colorString, onUpdateSvg) {
|
2017-10-11 11:32:51 -04:00
|
|
|
const items = getSelectedLeafItems();
|
2017-10-05 18:12:22 -04:00
|
|
|
let changed = false;
|
2017-10-02 15:25:04 -04:00
|
|
|
for (const item of items) {
|
|
|
|
if (isPGTextItem(item)) {
|
|
|
|
if (item.children) {
|
|
|
|
for (const child of item.children) {
|
|
|
|
if (child.children) {
|
|
|
|
for (const path of child.children) {
|
|
|
|
if (!path.data.isPGGlyphRect) {
|
2017-10-05 18:12:22 -04:00
|
|
|
if ((path.strokeColor === null && colorString) ||
|
|
|
|
path.strokeColor.toCSS() !== new paper.Color(colorString).toCSS()) {
|
|
|
|
changed = true;
|
|
|
|
path.strokeColor = colorString;
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!child.data.isPGGlyphRect) {
|
2017-10-05 18:12:22 -04:00
|
|
|
if (child.strokeColor !== colorString) {
|
|
|
|
changed = true;
|
|
|
|
child.strokeColor = colorString;
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!item.data.isPGGlyphRect) {
|
2017-10-05 18:12:22 -04:00
|
|
|
if ((item.strokeColor === null && colorString) ||
|
|
|
|
item.strokeColor.toCSS() !== new paper.Color(colorString).toCSS()) {
|
|
|
|
changed = true;
|
|
|
|
item.strokeColor = colorString;
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
2017-10-05 18:12:22 -04:00
|
|
|
} else if ((item.strokeColor === null && colorString) ||
|
|
|
|
item.strokeColor.toCSS() !== new paper.Color(colorString).toCSS()) {
|
|
|
|
changed = true;
|
2017-10-02 15:25:04 -04:00
|
|
|
item.strokeColor = colorString;
|
|
|
|
}
|
|
|
|
}
|
2017-10-05 18:12:22 -04:00
|
|
|
if (changed) {
|
|
|
|
onUpdateSvg();
|
|
|
|
}
|
2017-10-02 15:25:04 -04:00
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Called when setting stroke width
|
|
|
|
* @param {number} value New stroke width
|
2017-10-05 18:12:22 -04:00
|
|
|
* @param {!function} onUpdateSvg A callback to call when the image visibly changes
|
2017-10-02 15:25:04 -04:00
|
|
|
*/
|
2017-10-05 18:12:22 -04:00
|
|
|
const applyStrokeWidthToSelection = function (value, onUpdateSvg) {
|
2017-10-11 11:32:51 -04:00
|
|
|
const items = getSelectedLeafItems();
|
2017-10-02 15:25:04 -04:00
|
|
|
for (const item of items) {
|
|
|
|
if (isGroup(item)) {
|
|
|
|
continue;
|
2017-10-05 18:12:22 -04:00
|
|
|
} else if (item.strokeWidth !== value) {
|
2017-10-02 15:25:04 -04:00
|
|
|
item.strokeWidth = value;
|
2017-10-05 18:12:22 -04:00
|
|
|
onUpdateSvg();
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
* Get state of colors and stroke width for selection
|
2017-10-03 15:04:53 -04:00
|
|
|
* @param {!Array<paper.Item>} selectedItems Selected paper items
|
2017-10-02 15:25:04 -04:00
|
|
|
* @return {object} Object of strokeColor, strokeWidth, fillColor of the selection.
|
|
|
|
* Gives MIXED when there are mixed values for a color, and null for transparent.
|
|
|
|
* Gives null when there are mixed values for stroke width.
|
|
|
|
*/
|
2017-10-03 15:04:53 -04:00
|
|
|
const getColorsFromSelection = function (selectedItems) {
|
2017-10-02 15:25:04 -04:00
|
|
|
let selectionFillColorString;
|
|
|
|
let selectionStrokeColorString;
|
|
|
|
let selectionStrokeWidth;
|
|
|
|
let firstChild = true;
|
|
|
|
|
|
|
|
for (const item of selectedItems) {
|
|
|
|
let itemFillColorString;
|
|
|
|
let itemStrokeColorString;
|
|
|
|
|
|
|
|
// handle pgTextItems differently by going through their children
|
|
|
|
if (isPGTextItem(item)) {
|
|
|
|
for (const child of item.children) {
|
|
|
|
for (const path of child.children) {
|
|
|
|
if (!path.data.isPGGlyphRect) {
|
|
|
|
if (path.fillColor) {
|
|
|
|
itemFillColorString = path.fillColor.toCSS();
|
|
|
|
}
|
|
|
|
if (path.strokeColor) {
|
|
|
|
itemStrokeColorString = path.strokeColor.toCSS();
|
|
|
|
}
|
|
|
|
// check every style against the first of the items
|
|
|
|
if (firstChild) {
|
|
|
|
firstChild = false;
|
|
|
|
selectionFillColorString = itemFillColorString;
|
|
|
|
selectionStrokeColorString = itemStrokeColorString;
|
|
|
|
selectionStrokeWidth = path.strokeWidth;
|
|
|
|
}
|
|
|
|
if (itemFillColorString !== selectionFillColorString) {
|
|
|
|
selectionFillColorString = MIXED;
|
|
|
|
}
|
|
|
|
if (itemStrokeColorString !== selectionStrokeColorString) {
|
|
|
|
selectionStrokeColorString = MIXED;
|
|
|
|
}
|
|
|
|
if (selectionStrokeWidth !== path.strokeWidth) {
|
|
|
|
selectionStrokeWidth = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} else if (!isGroup(item)) {
|
|
|
|
if (item.fillColor) {
|
|
|
|
// hack bc text items with null fill can't be detected by fill-hitTest anymore
|
|
|
|
if (isPointTextItem(item) && item.fillColor.toCSS() === 'rgba(0,0,0,0)') {
|
|
|
|
itemFillColorString = null;
|
|
|
|
} else {
|
|
|
|
itemFillColorString = item.fillColor.toCSS();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (item.strokeColor) {
|
|
|
|
itemStrokeColorString = item.strokeColor.toCSS();
|
|
|
|
}
|
|
|
|
// check every style against the first of the items
|
|
|
|
if (firstChild) {
|
|
|
|
firstChild = false;
|
|
|
|
selectionFillColorString = itemFillColorString;
|
|
|
|
selectionStrokeColorString = itemStrokeColorString;
|
|
|
|
selectionStrokeWidth = item.strokeWidth;
|
|
|
|
}
|
|
|
|
if (itemFillColorString !== selectionFillColorString) {
|
|
|
|
selectionFillColorString = MIXED;
|
|
|
|
}
|
|
|
|
if (itemStrokeColorString !== selectionStrokeColorString) {
|
|
|
|
selectionStrokeColorString = MIXED;
|
|
|
|
}
|
|
|
|
if (selectionStrokeWidth !== item.strokeWidth) {
|
|
|
|
selectionStrokeWidth = null;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return {
|
|
|
|
fillColor: selectionFillColorString ? selectionFillColorString : null,
|
|
|
|
strokeColor: selectionStrokeColorString ? selectionStrokeColorString : null,
|
2017-10-03 13:45:19 -04:00
|
|
|
strokeWidth: selectionStrokeWidth || (selectionStrokeWidth === null) ? selectionStrokeWidth : 0
|
2017-10-02 15:25:04 -04:00
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
const stylePath = function (path, options) {
|
|
|
|
if (options.isEraser) {
|
|
|
|
path.fillColor = 'white';
|
2017-10-05 18:12:22 -04:00
|
|
|
} else if (options.fillColor) {
|
|
|
|
path.fillColor = options.fillColor;
|
2017-10-02 15:25:04 -04:00
|
|
|
} else {
|
2017-10-05 18:12:22 -04:00
|
|
|
// Make sure something visible is drawn
|
|
|
|
path.fillColor = 'black';
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
const styleCursorPreview = function (path, options) {
|
|
|
|
if (options.isEraser) {
|
|
|
|
path.fillColor = 'white';
|
|
|
|
path.strokeColor = 'cornflowerblue';
|
|
|
|
path.strokeWidth = 1;
|
2017-10-05 18:12:22 -04:00
|
|
|
} else if (options.fillColor) {
|
|
|
|
path.fillColor = options.fillColor;
|
2017-10-02 15:25:04 -04:00
|
|
|
} else {
|
2017-10-05 18:12:22 -04:00
|
|
|
// Make sure something visible is drawn
|
|
|
|
path.fillColor = 'black';
|
2017-10-02 15:25:04 -04:00
|
|
|
}
|
|
|
|
};
|
|
|
|
|
|
|
|
export {
|
|
|
|
applyFillColorToSelection,
|
|
|
|
applyStrokeColorToSelection,
|
|
|
|
applyStrokeWidthToSelection,
|
|
|
|
getColorsFromSelection,
|
|
|
|
MIXED,
|
|
|
|
stylePath,
|
|
|
|
styleCursorPreview
|
|
|
|
};
|