diff --git a/src/helper/bit-tools/fill-tool.js b/src/helper/bit-tools/fill-tool.js deleted file mode 100644 index 9b43ff9f..00000000 --- a/src/helper/bit-tools/fill-tool.js +++ /dev/null @@ -1,177 +0,0 @@ -import paper from '@scratch/paper'; -import {getHoveredItem} from '../hover'; -import {expandBy} from '../math'; - -class FillTool extends paper.Tool { - static get TOLERANCE () { - return 2; - } - /** - * @param {function} setHoveredItem Callback to set the hovered item - * @param {function} clearHoveredItem Callback to clear the hovered item - * @param {!function} onUpdateSvg A callback to call when the image visibly changes - */ - constructor (setHoveredItem, clearHoveredItem, onUpdateSvg) { - super(); - this.setHoveredItem = setHoveredItem; - this.clearHoveredItem = clearHoveredItem; - this.onUpdateSvg = onUpdateSvg; - - // We have to set these functions instead of just declaring them because - // paper.js tools hook up the listeners in the setter functions. - this.onMouseMove = this.handleMouseMove; - this.onMouseUp = this.handleMouseUp; - - // Color to fill with - this.fillColor = null; - // The path that's being hovered over. - this.fillItem = null; - // If we're hovering over a hole in a compound path, we can't just recolor it. This is the - // added item that's the same shape as the hole that's drawn over the hole when we fill a hole. - this.addedFillItem = null; - this.fillItemOrigColor = null; - this.prevHoveredItemId = null; - } - getHitOptions () { - const isAlmostClosedPath = function (item) { - return item instanceof paper.Path && item.segments.length > 2 && - item.lastSegment.point.getDistance(item.firstSegment.point) < 8; - }; - return { - segments: true, - stroke: true, - curves: true, - fill: true, - guide: false, - match: function (hitResult) { - return (hitResult.item instanceof paper.Path || hitResult.item instanceof paper.PointText) && - (hitResult.item.hasFill() || hitResult.item.closed || isAlmostClosedPath(hitResult.item)); - }, - hitUnfilledPaths: true, - tolerance: FillTool.TOLERANCE / paper.view.zoom - }; - } - setFillColor (fillColor) { - this.fillColor = fillColor; - } - /** - * To be called when the hovered item changes. When the select tool hovers over a - * new item, it compares against this to see if a hover item change event needs to - * be fired. - * @param {paper.Item} prevHoveredItemId ID of the highlight item that indicates the mouse is - * over a given item currently - */ - setPrevHoveredItemId (prevHoveredItemId) { - this.prevHoveredItemId = prevHoveredItemId; - } - handleMouseMove (event) { - const hoveredItem = getHoveredItem(event, this.getHitOptions(), true /* subselect */); - if ((!hoveredItem && this.prevHoveredItemId) || // There is no longer a hovered item - (hoveredItem && !this.prevHoveredItemId) || // There is now a hovered item - (hoveredItem && this.prevHoveredItemId && - hoveredItem.id !== this.prevHoveredItemId)) { // hovered item changed - this.setHoveredItem(hoveredItem ? hoveredItem.id : null); - } - const hitItem = hoveredItem ? hoveredItem.data.origItem : null; - // Still hitting the same thing - if ((!hitItem && !this.fillItem) || this.fillItem === hitItem) { - return; - } - if (this.fillItem) { - if (this.addedFillItem) { - this.addedFillItem.remove(); - this.addedFillItem = null; - } else { - this._setFillItemColor(this.fillItemOrigColor); - } - this.fillItemOrigColor = null; - this.fillItem = null; - } - if (hitItem) { - this.fillItem = hitItem; - this.fillItemOrigColor = hitItem.fillColor; - if (hitItem.parent instanceof paper.CompoundPath && hitItem.area < 0) { // hole - if (!this.fillColor) { - // Hole filled with transparent is no-op - this.fillItem = null; - this.fillItemOrigColor = null; - return; - } - // Make an item to fill the hole - this.addedFillItem = hitItem.clone(); - this.addedFillItem.setClockwise(true); - this.addedFillItem.data.noHover = true; - this.addedFillItem.data.origItem = hitItem; - // This usually fixes it so there isn't a teeny tiny gap in between the fill and the outline - // when filling in a hole - expandBy(this.addedFillItem, .1); - this.addedFillItem.insertAbove(hitItem.parent); - } else if (this.fillItem.parent instanceof paper.CompoundPath) { - this.fillItemOrigColor = hitItem.parent.fillColor; - } - this._setFillItemColor(this.fillColor); - } - } - handleMouseUp (event) { - if (event.event.button > 0) return; // only first mouse button - if (this.fillItem) { - // If the hole we're filling in is the same color as the parent, and parent has no outline, remove the hole - if (this.addedFillItem && - this._noStroke(this.fillItem.parent) && - this.addedFillItem.fillColor.type !== 'gradient' && - this.fillItem.parent.fillColor.toCSS() === this.addedFillItem.fillColor.toCSS()) { - this.addedFillItem.remove(); - this.addedFillItem = null; - let parent = this.fillItem.parent; - this.fillItem.remove(); - parent = parent.reduce(); - parent.fillColor = this.fillColor; - } else if (this.addedFillItem) { - // Fill in a hole. - this.addedFillItem.data.noHover = false; - } else if (!this.fillColor && - this.fillItem.data && - this.fillItem.data.origItem) { - // Filling a hole filler with transparent returns it to being gone - // instead of making a shape that's transparent - const group = this.fillItem.parent; - this.fillItem.remove(); - if (!(group instanceof paper.Layer) && group.children.length === 1) { - group.reduce(); - } - } - - this.clearHoveredItem(); - this.fillItem = null; - this.addedFillItem = null; - this.fillItemOrigColor = null; - this.onUpdateSvg(); - } - } - _noStroke (item) { - return !item.strokeColor || - item.strokeColor.alpha === 0 || - item.strokeWidth === 0; - } - _setFillItemColor (color) { - if (this.addedFillItem) { - this.addedFillItem.fillColor = color; - } else if (this.fillItem.parent instanceof paper.CompoundPath) { - this.fillItem.parent.fillColor = color; - } else { - this.fillItem.fillColor = color; - } - } - deactivateTool () { - if (this.fillItem) { - this._setFillItemColor(this.fillItemOrigColor); - this.fillItemOrigColor = null; - this.fillItem = null; - } - this.clearHoveredItem(); - this.setHoveredItem = null; - this.clearHoveredItem = null; - } -} - -export default FillTool; diff --git a/src/helper/bit-tools/oval-tool.js b/src/helper/bit-tools/oval-tool.js deleted file mode 100644 index dc90006e..00000000 --- a/src/helper/bit-tools/oval-tool.js +++ /dev/null @@ -1,133 +0,0 @@ -import paper from '@scratch/paper'; -import Modes from '../../lib/modes'; -import {styleShape} from '../style-path'; -import {clearSelection} from '../selection'; -import BoundingBoxTool from '../selection-tools/bounding-box-tool'; -import NudgeTool from '../selection-tools/nudge-tool'; - -/** - * Tool for drawing ovals. - */ -class OvalTool extends paper.Tool { - static get TOLERANCE () { - return 6; - } - /** - * @param {function} setSelectedItems Callback to set the set of selected items in the Redux state - * @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state - * @param {!function} onUpdateSvg A callback to call when the image visibly changes - */ - constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) { - super(); - this.setSelectedItems = setSelectedItems; - this.clearSelectedItems = clearSelectedItems; - this.onUpdateSvg = onUpdateSvg; - this.boundingBoxTool = new BoundingBoxTool(Modes.OVAL, setSelectedItems, clearSelectedItems, onUpdateSvg); - const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateSvg); - - // We have to set these functions instead of just declaring them because - // paper.js tools hook up the listeners in the setter functions. - this.onMouseDown = this.handleMouseDown; - this.onMouseDrag = this.handleMouseDrag; - this.onMouseUp = this.handleMouseUp; - this.onKeyUp = nudgeTool.onKeyUp; - this.onKeyDown = nudgeTool.onKeyDown; - - this.oval = null; - this.colorState = null; - this.isBoundingBoxMode = null; - this.active = false; - } - getHitOptions () { - return { - segments: true, - stroke: true, - curves: true, - fill: true, - guide: false, - match: hitResult => - (hitResult.item.data && hitResult.item.data.isHelperItem) || - hitResult.item.selected, // Allow hits on bounding box and selected only - tolerance: OvalTool.TOLERANCE / paper.view.zoom - }; - } - /** - * Should be called if the selection changes to update the bounds of the bounding box. - * @param {Array} selectedItems Array of selected items. - */ - onSelectionChanged (selectedItems) { - this.boundingBoxTool.onSelectionChanged(selectedItems); - } - setColorState (colorState) { - this.colorState = colorState; - } - handleMouseDown (event) { - if (event.event.button > 0) return; // only first mouse button - this.active = true; - - if (this.boundingBoxTool.onMouseDown(event, false /* clone */, false /* multiselect */, this.getHitOptions())) { - this.isBoundingBoxMode = true; - } else { - this.isBoundingBoxMode = false; - clearSelection(this.clearSelectedItems); - this.oval = new paper.Shape.Ellipse({ - point: event.downPoint, - size: 0 - }); - styleShape(this.oval, this.colorState); - } - } - handleMouseDrag (event) { - if (event.event.button > 0 || !this.active) return; // only first mouse button - - if (this.isBoundingBoxMode) { - this.boundingBoxTool.onMouseDrag(event); - return; - } - - const downPoint = new paper.Point(event.downPoint.x, event.downPoint.y); - const point = new paper.Point(event.point.x, event.point.y); - if (event.modifiers.shift) { - this.oval.size = new paper.Point(event.downPoint.x - event.point.x, event.downPoint.x - event.point.x); - } else { - this.oval.size = downPoint.subtract(point); - } - if (event.modifiers.alt) { - this.oval.position = downPoint; - } else { - this.oval.position = downPoint.subtract(this.oval.size.multiply(0.5)); - } - - } - handleMouseUp (event) { - if (event.event.button > 0 || !this.active) return; // only first mouse button - - if (this.isBoundingBoxMode) { - this.boundingBoxTool.onMouseUp(event); - this.isBoundingBoxMode = null; - return; - } - - if (this.oval) { - if (Math.abs(this.oval.size.width * this.oval.size.height) < OvalTool.TOLERANCE / paper.view.zoom) { - // Tiny oval created unintentionally? - this.oval.remove(); - this.oval = null; - } else { - const ovalPath = this.oval.toPath(true /* insert */); - this.oval.remove(); - this.oval = null; - - ovalPath.selected = true; - this.setSelectedItems(); - this.onUpdateSvg(); - } - } - this.active = false; - } - deactivateTool () { - this.boundingBoxTool.removeBoundsPath(); - } -} - -export default OvalTool; diff --git a/src/helper/bit-tools/rect-tool.js b/src/helper/bit-tools/rect-tool.js deleted file mode 100644 index 8099f126..00000000 --- a/src/helper/bit-tools/rect-tool.js +++ /dev/null @@ -1,127 +0,0 @@ -import paper from '@scratch/paper'; -import Modes from '../../lib/modes'; -import {styleShape} from '../style-path'; -import {clearSelection} from '../selection'; -import BoundingBoxTool from '../selection-tools/bounding-box-tool'; -import NudgeTool from '../selection-tools/nudge-tool'; - -/** - * Tool for drawing rectangles. - */ -class RectTool extends paper.Tool { - static get TOLERANCE () { - return 6; - } - /** - * @param {function} setSelectedItems Callback to set the set of selected items in the Redux state - * @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state - * @param {!function} onUpdateSvg A callback to call when the image visibly changes - */ - constructor (setSelectedItems, clearSelectedItems, onUpdateSvg) { - super(); - this.setSelectedItems = setSelectedItems; - this.clearSelectedItems = clearSelectedItems; - this.onUpdateSvg = onUpdateSvg; - this.boundingBoxTool = new BoundingBoxTool(Modes.RECT, setSelectedItems, clearSelectedItems, onUpdateSvg); - const nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateSvg); - - // We have to set these functions instead of just declaring them because - // paper.js tools hook up the listeners in the setter functions. - this.onMouseDown = this.handleMouseDown; - this.onMouseDrag = this.handleMouseDrag; - this.onMouseUp = this.handleMouseUp; - this.onKeyUp = nudgeTool.onKeyUp; - this.onKeyDown = nudgeTool.onKeyDown; - - this.rect = null; - this.colorState = null; - this.isBoundingBoxMode = null; - this.active = false; - } - getHitOptions () { - return { - segments: true, - stroke: true, - curves: true, - fill: true, - guide: false, - match: hitResult => - (hitResult.item.data && hitResult.item.data.isHelperItem) || - hitResult.item.selected, // Allow hits on bounding box and selected only - tolerance: RectTool.TOLERANCE / paper.view.zoom - }; - } - /** - * Should be called if the selection changes to update the bounds of the bounding box. - * @param {Array} selectedItems Array of selected items. - */ - onSelectionChanged (selectedItems) { - this.boundingBoxTool.onSelectionChanged(selectedItems); - } - setColorState (colorState) { - this.colorState = colorState; - } - handleMouseDown (event) { - if (event.event.button > 0) return; // only first mouse button - this.active = true; - - if (this.boundingBoxTool.onMouseDown(event, false /* clone */, false /* multiselect */, this.getHitOptions())) { - this.isBoundingBoxMode = true; - } else { - this.isBoundingBoxMode = false; - clearSelection(this.clearSelectedItems); - } - } - handleMouseDrag (event) { - if (event.event.button > 0 || !this.active) return; // only first mouse button - - if (this.isBoundingBoxMode) { - this.boundingBoxTool.onMouseDrag(event); - return; - } - - if (this.rect) { - this.rect.remove(); - } - - const rect = new paper.Rectangle(event.downPoint, event.point); - if (event.modifiers.shift) { - rect.height = rect.width; - } - this.rect = new paper.Path.Rectangle(rect); - - if (event.modifiers.alt) { - this.rect.position = event.downPoint; - } - - styleShape(this.rect, this.colorState); - } - handleMouseUp (event) { - if (event.event.button > 0 || !this.active) return; // only first mouse button - - if (this.isBoundingBoxMode) { - this.boundingBoxTool.onMouseUp(event); - this.isBoundingBoxMode = null; - return; - } - - if (this.rect) { - if (this.rect.area < RectTool.TOLERANCE / paper.view.zoom) { - // Tiny rectangle created unintentionally? - this.rect.remove(); - this.rect = null; - } else { - this.rect.selected = true; - this.setSelectedItems(); - this.onUpdateSvg(); - this.rect = null; - } - } - this.active = false; - } - deactivateTool () { - this.boundingBoxTool.removeBoundsPath(); - } -} - -export default RectTool; diff --git a/src/helper/bit-tools/text-tool.js b/src/helper/bit-tools/text-tool.js deleted file mode 100644 index 24b3d064..00000000 --- a/src/helper/bit-tools/text-tool.js +++ /dev/null @@ -1,326 +0,0 @@ -import paper from '@scratch/paper'; -import Modes from '../../lib/modes'; -import {clearSelection} from '../selection'; -import BoundingBoxTool from '../selection-tools/bounding-box-tool'; -import NudgeTool from '../selection-tools/nudge-tool'; -import {hoverBounds} from '../guides'; - -/** - * Tool for adding text. Text elements have limited editability; they can't be reshaped, - * drawn on or erased. This way they can preserve their ability to have the text edited. - */ -class TextTool extends paper.Tool { - static get TOLERANCE () { - return 6; - } - static get TEXT_EDIT_MODE () { - return 'TEXT_EDIT_MODE'; - } - static get SELECT_MODE () { - return 'SELECT_MODE'; - } - /** Clicks registered within this amount of time are registered as double clicks */ - static get DOUBLE_CLICK_MILLIS () { - return 250; - } - /** Typing with no pauses longer than this amount of type will count as 1 action */ - static get TYPING_TIMEOUT_MILLIS () { - return 1000; - } - static get TEXT_PADDING () { - return 8; - } - /** - * @param {HTMLTextAreaElement} textAreaElement dom element for the editable text field - * @param {function} setSelectedItems Callback to set the set of selected items in the Redux state - * @param {function} clearSelectedItems Callback to clear the set of selected items in the Redux state - * @param {!function} onUpdateSvg A callback to call when the image visibly changes - * @param {!function} setTextEditTarget Call to set text editing target whenever text editing is active - */ - constructor (textAreaElement, setSelectedItems, clearSelectedItems, onUpdateSvg, setTextEditTarget) { - super(); - this.element = textAreaElement; - this.setSelectedItems = setSelectedItems; - this.clearSelectedItems = clearSelectedItems; - this.onUpdateSvg = onUpdateSvg; - this.setTextEditTarget = setTextEditTarget; - this.boundingBoxTool = new BoundingBoxTool(Modes.TEXT, setSelectedItems, clearSelectedItems, onUpdateSvg); - this.nudgeTool = new NudgeTool(this.boundingBoxTool, onUpdateSvg); - this.lastEvent = null; - - // We have to set these functions instead of just declaring them because - // paper.js tools hook up the listeners in the setter functions. - this.onMouseDown = this.handleMouseDown; - this.onMouseDrag = this.handleMouseDrag; - this.onMouseUp = this.handleMouseUp; - this.onMouseMove = this.handleMouseMove; - this.onKeyUp = this.handleKeyUp; - this.onKeyDown = this.handleKeyDown; - - this.textBox = null; - this.guide = null; - this.colorState = null; - this.mode = null; - this.active = false; - this.lastTypeEvent = null; - - // If text selected and then activate this tool, switch to text edit mode for that text - // If double click on text while in select mode, does mode change to text mode? Text fully selected by default - } - getBoundingBoxHitOptions () { - return { - segments: true, - stroke: true, - curves: true, - fill: true, - guide: false, - match: hitResult => - (hitResult.item.data && hitResult.item.data.isHelperItem) || - hitResult.item.selected, // Allow hits on bounding box and selected only - tolerance: TextTool.TOLERANCE / paper.view.zoom - }; - } - getTextEditHitOptions () { - return { - class: paper.PointText, - segments: true, - stroke: true, - curves: true, - fill: true, - guide: false, - match: hitResult => hitResult.item && !hitResult.item.selected, // Unselected only - tolerance: TextTool.TOLERANCE / paper.view.zoom - }; - } - /** - * Called when the selection changes to update the bounds of the bounding box. - * @param {Array} selectedItems Array of selected items. - */ - onSelectionChanged (selectedItems) { - this.boundingBoxTool.onSelectionChanged(selectedItems); - } - // Allow other tools to cancel text edit mode - onTextEditCancelled () { - this.endTextEdit(); - if (this.textBox) { - this.mode = TextTool.SELECT_MODE; - this.textBox.selected = true; - this.setSelectedItems(); - } - } - /** - * Called when the view matrix changes - * @param {paper.Matrix} viewMtx applied to paper.view - */ - onViewBoundsChanged (viewMtx) { - if (this.mode !== TextTool.TEXT_EDIT_MODE) { - return; - } - const matrix = this.textBox.matrix; - this.element.style.transform = - `translate(0px, ${this.textBox.internalBounds.y}px) - matrix(${viewMtx.a}, ${viewMtx.b}, ${viewMtx.c}, ${viewMtx.d}, - ${viewMtx.tx}, ${viewMtx.ty}) - matrix(${matrix.a}, ${matrix.b}, ${matrix.c}, ${matrix.d}, - ${matrix.tx}, ${matrix.ty})`; - } - setColorState (colorState) { - this.colorState = colorState; - } - handleMouseMove (event) { - const hitResults = paper.project.hitTestAll(event.point, this.getTextEditHitOptions()); - if (hitResults.length) { - document.body.style.cursor = 'text'; - } else { - document.body.style.cursor = 'auto'; - } - } - handleMouseDown (event) { - if (event.event.button > 0) return; // only first mouse button - this.active = true; - - const lastMode = this.mode; - - // Check if double clicked - let doubleClicked = false; - if (this.lastEvent) { - if ((event.event.timeStamp - this.lastEvent.event.timeStamp) < TextTool.DOUBLE_CLICK_MILLIS) { - doubleClicked = true; - } else { - doubleClicked = false; - } - } - this.lastEvent = event; - - const doubleClickHitTest = paper.project.hitTest(event.point, this.getBoundingBoxHitOptions()); - if (doubleClicked && - this.mode === TextTool.SELECT_MODE && - doubleClickHitTest) { - // Double click in select mode moves you to text edit mode - clearSelection(this.clearSelectedItems); - this.textBox = doubleClickHitTest.item; - this.beginTextEdit(this.textBox.content, this.textBox.matrix); - } else if ( - this.boundingBoxTool.onMouseDown( - event, false /* clone */, false /* multiselect */, this.getBoundingBoxHitOptions())) { - // In select mode staying in select mode - return; - } - - // We clicked away from the item, so end the current mode - if (lastMode === TextTool.SELECT_MODE) { - clearSelection(this.clearSelectedItems); - this.mode = null; - } else if (lastMode === TextTool.TEXT_EDIT_MODE) { - this.endTextEdit(); - } - - const hitResults = paper.project.hitTestAll(event.point, this.getTextEditHitOptions()); - if (hitResults.length) { - // Clicking a different text item to begin text edit mode on that item - clearSelection(this.clearSelectedItems); - this.textBox = hitResults[0].item; - this.beginTextEdit(this.textBox.content, this.textBox.matrix); - } else if (lastMode === TextTool.TEXT_EDIT_MODE) { - // In text mode clicking away to begin select mode - if (this.textBox) { - this.mode = TextTool.SELECT_MODE; - this.textBox.selected = true; - this.setSelectedItems(); - } - } else { - // In no mode or select mode clicking away to begin text edit mode - this.textBox = new paper.PointText({ - point: event.point, - content: '', - font: 'Helvetica', - fontSize: 30, - fillColor: this.colorState.fillColor, - // Default leading for both the HTML text area and paper.PointText - // is 120%, but for some reason they are slightly off from each other. - // This value was obtained experimentally. - // (Don't round to 34.6, the text area will start to scroll.) - leading: 34.61 - }); - this.beginTextEdit(this.textBox.content, this.textBox.matrix); - } - } - handleMouseDrag (event) { - if (event.event.button > 0 || !this.active) return; // only first mouse button - - if (this.mode === TextTool.SELECT_MODE) { - this.boundingBoxTool.onMouseDrag(event); - return; - } - } - handleMouseUp (event) { - if (event.event.button > 0 || !this.active) return; // only first mouse button - - if (this.mode === TextTool.SELECT_MODE) { - this.boundingBoxTool.onMouseUp(event); - this.isBoundingBoxMode = null; - return; - } - - this.active = false; - } - handleKeyUp (event) { - if (this.mode === TextTool.SELECT_MODE) { - this.nudgeTool.onKeyUp(event); - } - } - handleKeyDown (event) { - if (event.event.target instanceof HTMLInputElement) { - // Ignore nudge if a text input field is focused - return; - } - - if (this.mode === TextTool.SELECT_MODE) { - this.nudgeTool.onKeyUp(event); - } - } - handleTextInput (event) { - // Save undo state if you paused typing for long enough. - if (this.lastTypeEvent && event.timeStamp - this.lastTypeEvent.timeStamp > TextTool.TYPING_TIMEOUT_MILLIS) { - this.onUpdateSvg(); - } - this.lastTypeEvent = event; - if (this.mode === TextTool.TEXT_EDIT_MODE) { - this.textBox.content = this.element.value; - } - this.resizeGuide(); - } - resizeGuide () { - if (this.guide) this.guide.remove(); - this.guide = hoverBounds(this.textBox, TextTool.TEXT_PADDING); - this.guide.dashArray = [4, 4]; - this.element.style.width = `${this.textBox.internalBounds.width}px`; - this.element.style.height = `${this.textBox.internalBounds.height}px`; - } - /** - * @param {string} initialText Text to initialize the text area with - * @param {paper.Matrix} matrix Transform matrix for the element. Defaults - * to the identity matrix. - */ - beginTextEdit (initialText, matrix) { - this.mode = TextTool.TEXT_EDIT_MODE; - this.setTextEditTarget(this.textBox.id); - - const viewMtx = paper.view.matrix; - - this.element.style.display = 'initial'; - this.element.value = initialText ? initialText : ''; - this.element.style.transformOrigin = - `${-this.textBox.internalBounds.x}px ${-this.textBox.internalBounds.y}px`; - this.element.style.transform = - `translate(0px, ${this.textBox.internalBounds.y}px) - matrix(${viewMtx.a}, ${viewMtx.b}, ${viewMtx.c}, ${viewMtx.d}, - ${viewMtx.tx}, ${viewMtx.ty}) - matrix(${matrix.a}, ${matrix.b}, ${matrix.c}, ${matrix.d}, - ${matrix.tx}, ${matrix.ty})`; - this.element.focus({preventScroll: true}); - this.eventListener = this.handleTextInput.bind(this); - this.element.addEventListener('input', this.eventListener); - this.resizeGuide(); - } - endTextEdit () { - if (this.mode !== TextTool.TEXT_EDIT_MODE) { - return; - } - this.mode = null; - - // Remove invisible textboxes - if (this.textBox && this.textBox.content.trim() === '') { - this.textBox.remove(); - this.textBox = null; - } - - // Remove guide - if (this.guide) { - this.guide.remove(); - this.guide = null; - this.setTextEditTarget(); - } - this.element.style.display = 'none'; - if (this.eventListener) { - this.element.removeEventListener('input', this.eventListener); - this.eventListener = null; - } - this.lastTypeEvent = null; - - // If you finished editing a textbox, save undo state - if (this.textBox && this.textBox.content.trim().length) { - this.onUpdateSvg(); - } - } - deactivateTool () { - if (this.textBox && this.textBox.content.trim() === '') { - this.textBox.remove(); - this.textBox = null; - } - this.endTextEdit(); - this.boundingBoxTool.removeBoundsPath(); - } -} - -export default TextTool;