UNPKG

@aurigma/design-atoms

Version:

Design Atoms is a part of Customer's Canvas SDK which allows for manipulating individual design elements through your code.

517 lines 26.7 kB
import { Collection } from "@aurigma/design-atoms-model/Collection"; import { LayoutItem, ManipulationPermissions } from "@aurigma/design-atoms-model/Product/Items"; import { arrayReferenceEquals, intersection } from "@aurigma/design-atoms-model/Utils/Utils"; import { RotatedRectangleF, RectangleF, EqualsOfFloatNumbers } from "@aurigma/design-atoms-model/Math"; import { EventObject } from "@aurigma/design-atoms-model/EventObject"; import { ArgumentException } from "@aurigma/design-atoms-model/Exception"; import { SelectionRectangleHandler } from "./SelectionRectangleHandler"; import { SelectionHitTestManager } from "../SelectionHitTestManager"; import { BaseRectangleItemHandler, PlaceholderItemHandler, GroupItemHandler, LineItemHandler, NewBaseTextItemHandler } from "../../ItemHandlers"; import { InputState } from "../../Input/InputManager/IInputManager"; import { SelectionProcessModifier } from "./SelectionProcessModifier"; import { FrontEndLogger, LogSource } from "../FrontEndLogger"; import { HistoryUpdateMode } from "../../Commands/ModelUpdateCommand"; import { getRotatedRectangleWithBorder } from "../../Utils/Math"; import { ItemsCommand } from "@aurigma/design-atoms-interfaces"; export class SelectionHandler { constructor(hitTestManager, _canvas, _snapLinesHandler, _interactiveZonesHandler) { this._canvas = _canvas; this._snapLinesHandler = _snapLinesHandler; this._interactiveZonesHandler = _interactiveZonesHandler; this._itemHandlers = new Collection(); this._parentSelectionRectangle = null; this._multipleSelectionEnabled = true; this._enabled = true; this._skipUpdate = false; this._locked = false; this._state = SelectionState.Idle; this._ignoreSimpleMode = false; this._manipulationPermissions = new ManipulationPermissions(); this._resizeIndex = null; this._setRectangle = (rect) => { this._rectangle = rect; }; this._updatePermissions = () => { const result = new ManipulationPermissions(); const isPlaceholderEditing = this._canvas.contentEditingPlaceholderItemHandler != null; if (isPlaceholderEditing) { this._manipulationPermissions = this._canvas.contentEditingPlaceholderItemHandler.content.item.manipulationPermissions; return; } if (!this._ignoreSimpleMode && this._canvas.simpleMode) { this._manipulationPermissions = new ManipulationPermissions(false); return; } const handlers = this._itemHandlers.selectMany(h => h instanceof GroupItemHandler ? h.getNestedItemHandlers(false, false, true) : [h]) .ofType(BaseRectangleItemHandler); handlers.forEach(handler => { var _a, _b, _c, _d; const perms = handler.item.manipulationPermissions; result.allowDelete = result.allowDelete && perms.allowDelete; result.allowDragAndDrop = result.allowDragAndDrop && perms.allowDragAndDrop; result.allowMoveHorizontal = result.allowMoveHorizontal && perms.allowMoveHorizontal; result.allowMoveVertical = result.allowMoveVertical && perms.allowMoveVertical; result.allowRotate = result.allowRotate && perms.allowRotate; result.resizeGrips.edge = result.resizeGrips.edge && perms.resizeGrips.edge; result.resizeGrips.corner = intersection([perms.resizeGrips.corner, result.resizeGrips.corner]); let selectionAngle = (_d = (_b = (_a = this._rectangle) === null || _a === void 0 ? void 0 : _a.angle) !== null && _b !== void 0 ? _b : (_c = this._parentSelectionRectangle) === null || _c === void 0 ? void 0 : _c.angle) !== null && _d !== void 0 ? _d : 0; if (EqualsOfFloatNumbers((selectionAngle - handler.angle) % 90, 0) == false) { result.resizeGrips.edge = false; result.resizeGrips.setCornerArbitrary(false); } }); this._manipulationPermissions = result; }; this._selectionChanged = new EventObject(); this._onSelectionItemHandlersChanged = () => { var _a; if (!this._itemHandlers.contains(this._currentItemHandler)) { if (this._currentItemHandler instanceof PlaceholderItemHandler) this._currentItemHandler.removeIsEditingChanged(this._updatePermissions); this._currentItemHandler = this._itemHandlers.lastOrDefault(); this._updateParentItemHandler((_a = this._currentItemHandler) === null || _a === void 0 ? void 0 : _a.parentGroupItemHandler); if (this._currentItemHandler instanceof PlaceholderItemHandler) this._currentItemHandler.addIsEditingChanged(this._updatePermissions); this._currentItemChangedEvent.notify(this._currentItemHandler); } this._update(); this._updatePermissions(); this._selectionChanged.notify(); }; this._onParentHandlerPropertyChanged = (sender, property) => { if (property == "sourceRectangle") this._updateParentSelectionRectangle(); }; this._selectionRectangleChanged = (args) => { FrontEndLogger.debugLog(`Selection changed: ${args.rectangle.toString()} is${args.finished ? "" : " not"} finished.`, LogSource.SelectionHandler); this._rectangle = args.rectangle; this._rectangleSigns = { x: args.rectangle.width < 0 ? -1 : 1, y: args.rectangle.height < 0 ? -1 : 1 }; if (args.finished) { this._rectangle.width = Math.abs(this._rectangle.width); this._rectangle.height = Math.abs(this._rectangle.height); this._canvas.updateTexts(); } this._updateParentSelectionRectangle(); this._selectionChanged.notify(); }; this._selectionStateChanged = (state) => { this._state = state; }; this._selectionAngleChanged = (args) => { const cmdArgs = Object.assign(Object.assign({}, args), { items: this._items, finished: args.finished }); this._canvas.viewer.commandManager.execute(ItemsCommand.rotateItems, cmdArgs, this._getHistoryUpdateMode(args.finished)); }; this._selectionMoved = (args) => { const cmdArgs = { delta: args.delta, items: this._items, finished: args.finished }; this._canvas.viewer.commandManager.execute(ItemsCommand.newTranslateItems, cmdArgs, this._getHistoryUpdateMode(args.finished)); }; this._selectionResized = (args) => { const cmdArgs = Object.assign({ items: this._items, finished: args.finished }, args); this._canvas.viewer.commandManager.execute(ItemsCommand.resizeItems, cmdArgs, this._getHistoryUpdateMode(args.finished)); }; this._onItemHandlersItemAdded = (data) => { data.item.addChanged(this._onSelectedItemHandlerChanged); }; this._onItemHandlersItemRemoved = (data) => { data.item.removeChanged(this._onSelectedItemHandlerChanged); }; this._onSelectedItemHandlerChanged = (handler) => { this._updatePermissions(); this._update(); }; this.addSelectedItemHandlersChanged = (handler) => { this._itemHandlers.add_collectionChanged(handler); }; this.removeSelectedItemHandlersChanged = (handler) => { this._itemHandlers.remove_collectionChanged(handler); }; this._currentItemChangedEvent = new EventObject(); this._selectionHitTestManager = new SelectionHitTestManager(this, hitTestManager); this._selectionProcessModifier = new SelectionProcessModifier(this, _canvas, _snapLinesHandler); this._selectionRectangleHandler = new SelectionRectangleHandler(this._selectionProcessModifier); this._itemHandlers.add_collectionChanged(this._onSelectionItemHandlersChanged); this._itemHandlers.add_itemAdded(this._onItemHandlersItemAdded); this._itemHandlers.add_itemRemoved(this._onItemHandlersItemRemoved); this._selectionRectangleHandler.addRectangleChanged(this._selectionRectangleChanged); this._selectionRectangleHandler.addRectangleAngleChanged(this._selectionAngleChanged); this._selectionRectangleHandler.addRectangleMoved(this._selectionMoved); this._selectionRectangleHandler.addRectangleResized(this._selectionResized); this._selectionRectangleHandler.addStateChanged(this._selectionStateChanged); } get enabled() { return this._enabled; } get selectedItemHandlers() { return this._itemHandlers; } get currentItemHandler() { return this._currentItemHandler; } get selectionHitTestManager() { return this._selectionHitTestManager; } get locked() { return this._locked; } get border() { return this._border; } get rectangle() { return this._rectangle; } get parentRectangle() { return this._parentSelectionRectangle; } get region() { return this._region; } get resizeIndex() { return this._resizeIndex; } set ignoreSimpleMode(value) { if (this._ignoreSimpleMode === value) return; this._ignoreSimpleMode = value; this._updatePermissions(); } get multipleSelectionEnabled() { return this._multipleSelectionEnabled && !this.selectedItemHandlers.any(itemHandler => itemHandler.item.parentGroupItem instanceof LayoutItem); } set multipleSelectionEnabled(value) { this._multipleSelectionEnabled = value; } lock(saveSelectedItems = false) { this._locked = true; if (!saveSelectedItems) this._itemHandlers.clear(); this._canvas.onSelectionLocked(); this._canvas.redraw(); } unlock() { this._locked = false; this._canvas.redraw(); } enable() { this._update(); this._enabled = true; } disable() { this._enabled = false; } rotateByPoint(args, state, startPoint = null) { if (!this.manipulationPermissions.allowRotate) return; if (state === InputState.Started) { if (startPoint == null) throw new ArgumentException("SelectionHandler.updateRotation: startPoint cannot be null!"); this._selectionProcessModifier.ignoreSnapLines = false; this._selectionRectangleHandler.startRotatingByPoint(startPoint, this.rectangle); } try { this._selectionRectangleHandler.updateRotatingByPoint(args); } finally { if (state === InputState.Finished) this._notifyItemHandlersChanged(); } } moveByPoint(args, state, ignoreSnapLines, startPoint = null) { var _a; const perms = this.manipulationPermissions; if (!perms.allowMove) return; if (args.allowMoveHorizontal == null) args.allowMoveHorizontal = perms.allowMoveHorizontal; if (args.allowMoveVertical == null) args.allowMoveVertical = perms.allowMoveVertical; if (state === InputState.Started) { if (startPoint == null) throw new ArgumentException("SelectionHandler.updateMoving: startPoint cannot be null!"); this._selectionProcessModifier.ignoreSnapLines = ignoreSnapLines; this._selectionRectangleHandler.startMovingByPoint(startPoint, this.rectangle); if (!ignoreSnapLines) this._fillSnapData(); } try { this._selectionRectangleHandler.updateMovingByPoint(args); } finally { if (state === InputState.Finished) { this._notifyItemHandlersChanged(); this._snapLinesHandler.clearSnapData(); (_a = this._canvas) === null || _a === void 0 ? void 0 : _a.redraw(); } } } resizeByPoint(args, state, startPoint = null) { var _a; if (!this.manipulationPermissions.allowResize) return; if (state === InputState.Started) { if (startPoint == null) throw new ArgumentException("SelectionHandler.updateResizing: startPoint cannot be null!"); this._resizeIndex = args.resizeIndex; this._selectionProcessModifier.ignoreSnapLines = false; this._selectionRectangleHandler.startResizingByPoint(startPoint, this.rectangle, args.resizeIndex, this._allowNegativeResize, this.selectedItemHandlers.toArray()); this._fillSnapData(); } try { this._selectionRectangleHandler.updateResizingByPoint(args, this._itemHandlers.toArray()); } finally { if (state === InputState.Finished) { this._resizeIndex = null; this._notifyItemHandlersChanged(); this._snapLinesHandler.clearSnapData(); (_a = this._canvas) === null || _a === void 0 ? void 0 : _a.redraw(); } } } _notifyItemHandlersChanged() { this._itemHandlers.forEach(x => x.item.getItemChangedEvent().fire()); } move(args, state) { const perms = this.manipulationPermissions; if (!perms.allowMove) return; if (args.allowMoveHorizontal == null) args.allowMoveHorizontal = perms.allowMoveHorizontal; if (args.allowMoveVertical == null) args.allowMoveVertical = perms.allowMoveVertical; if (state === InputState.Started && this._state === SelectionState.Idle) { this._selectionProcessModifier.ignoreSnapLines = true; this._selectionRectangleHandler.startMove(this.rectangle); } this._selectionRectangleHandler.move(args); } isItemHandlerSelected(itemHandler) { return this._itemHandlers.contains(itemHandler); } isOnlyThisItemHandlerSelected(itemHandler) { return this.isItemHandlerSelected(itemHandler) && this._itemHandlers.length === 1; } setSelectedItemHandlers(itemHandlers, dontClean = false) { if (!Array.isArray(itemHandlers) || this._locked || arrayReferenceEquals(itemHandlers, this._itemHandlers.toArray())) return; if (!dontClean) this.clearSelectedItemHandlers(); this._cancelEditMode(); if (!this.multipleSelectionEnabled) itemHandlers = [itemHandlers[0]]; this._itemHandlers.addRange(itemHandlers); } _cancelEditMode() { var _a; (_a = this._itemHandlers) === null || _a === void 0 ? void 0 : _a.ofType(PlaceholderItemHandler).forEach(p => p.editing = false); } clearSelectedItemHandlers() { this._cancelEditMode(); this._itemHandlers.clear(); this._updateParentSelectionRectangle(); } addSelectedItemHandler(itemHandler) { if (!this.multipleSelectionEnabled && this._itemHandlers.length > 0) this._itemHandlers.clear(); this.setSelectedItemHandlers([itemHandler], true); } removeSelectedItemHandler(itemHandler) { if (!this._itemHandlers.contains(itemHandler)) return; this._itemHandlers.remove(itemHandler); } update(force = false) { if (force || this._state === SelectionState.Idle) this._update(); } _update() { if (this._skipUpdate) return; if (this._itemHandlers.length === 0) { this._setRectangle(null); this._border = null; this._region = null; return; } var itemHandler = this._itemHandlers.getItem(0); var margin = itemHandler.getBorderMargin(); if (this._itemHandlers.length === 1) { this._setRectangle(this._itemHandlers.get(0).getSelectionRectangle()); this._border = { left: margin, top: margin, right: margin, bottom: margin }; } else { var bounds = itemHandler.getSelectionRectangle().bounds; var left = bounds.left, top = bounds.top, right = bounds.right, bottom = bounds.bottom; var border = { left: margin, top: margin, right: margin, bottom: margin }; for (var i = 1; i < this._itemHandlers.length; i++) { itemHandler = this._itemHandlers.getItem(i); margin = itemHandler.getBorderMargin(); bounds = itemHandler.getSelectionRectangle().bounds; if (bounds.left - margin < left - border.left) { left = bounds.left; border.left = margin; } if (bounds.top - margin < top - border.top) { top = bounds.top; border.top = margin; } if (bounds.right + margin > right + border.right) { right = bounds.right; border.right = margin; } if (bounds.bottom + margin > bottom + border.bottom) { bottom = bounds.bottom; border.bottom = margin; } } this._setRectangle(RotatedRectangleF.FromLTRB(left, top, right, bottom)); this._border = border; } this._updateParentSelectionRectangle(); this._region = this._getRegion(); this._canvas.redraw(); } _updateParentSelectionRectangle() { var _a; let parentGroupItem = null; let parentGroupItemHandler; if ((_a = this._itemHandlers) === null || _a === void 0 ? void 0 : _a.any()) { parentGroupItem = this._itemHandlers.getItem(0).item.parentGroupItem; parentGroupItemHandler = parentGroupItem && this._canvas.handlerFactory.get(parentGroupItem); } if (parentGroupItem == null || parentGroupItemHandler == null || parentGroupItemHandler.isEmpty()) { this._parentSelectionRectangle = null; return; } const parentGroupItemSelectionRectangle = parentGroupItemHandler.getSelectionRectangle(); this._parentSelectionRectangle = parentGroupItemSelectionRectangle; } _getRegion() { var rectangle = null; if (this._canvas.constrainedMarginEnabled && this._canvas.margin > 0) { var margin = this._canvas.margin; rectangle = new RectangleF(margin, margin, this._canvas.workspaceWidth - margin, this._canvas.workspaceHeight - margin); } this._itemHandlers .where(i => { var _a; return ((_a = i.layer) === null || _a === void 0 ? void 0 : _a.region) != null; }) .select(i => i.layer.region) .distinct() .forEach(region => { rectangle = rectangle != null ? RectangleF.intersect(rectangle, region) : region; }); return rectangle; } getSelectionDrawingParams() { var _a, _b; let isOnlyOneLine = false; let isLineInSelection = false; let isPlaceholderEditing = false; let currentItemHandler = null; let isPlaceholderInCropMode = false; if (this._itemHandlers.length === 1) { currentItemHandler = this._itemHandlers.getItem(0); isOnlyOneLine = currentItemHandler instanceof LineItemHandler; isPlaceholderEditing = currentItemHandler instanceof PlaceholderItemHandler && currentItemHandler.editing; isPlaceholderInCropMode = currentItemHandler instanceof PlaceholderItemHandler && currentItemHandler.isCropMode; } else { isLineInSelection = this._itemHandlers.any(i => i instanceof LineItemHandler); } const isPlaceholderWithCoverModeEditing = isPlaceholderEditing && currentItemHandler.item.isCoverMode; const isTextEditing = (currentItemHandler instanceof NewBaseTextItemHandler) && currentItemHandler.isInEdit; // ? currentItemHandler.content?.angle % 90 == 0 const placeholderAllowArbitrary = isPlaceholderInCropMode && currentItemHandler.content ? currentItemHandler.content.angle == 0 : true; const { resizeGrips, allowRotate } = this.manipulationPermissions; return { rotate: this.allowManipulation && allowRotate && !isPlaceholderWithCoverModeEditing && !isTextEditing, resize: this.allowManipulation && ((_b = (_a = resizeGrips.corner) === null || _a === void 0 ? void 0 : _a[0]) !== null && _b !== void 0 ? _b : false) && !isOnlyOneLine && !isTextEditing, arbitraryWidthResize: this.allowManipulation && resizeGrips.edge && !isLineInSelection && !isPlaceholderWithCoverModeEditing && !isTextEditing && placeholderAllowArbitrary, arbitraryHeightResize: this.allowManipulation && resizeGrips.edge && !isOnlyOneLine && !isLineInSelection && !isPlaceholderWithCoverModeEditing && !isTextEditing && placeholderAllowArbitrary }; } getHighlightRectangles() { var _a; const result = []; if (this._itemHandlers == null || this._itemHandlers.length == 0) return result; const highlightOpts = { includeChildren: true, includeParent: false }; if (this._itemHandlers.length > 1) { this._itemHandlers.forEach(x => result.push(...x.getHighlightRectangles(highlightOpts))); } else { const current = this._itemHandlers.get(0); const needToHighlight = current instanceof NewBaseTextItemHandler ? current.isHighlightNeeded() && ((_a = this._canvas.textEditor) === null || _a === void 0 ? void 0 : _a.highlightInEditingModeEnabled) : current.isHighlightNeeded(); if (needToHighlight) { highlightOpts.includeParent = false; result.push(...current.getHighlightRectangles(highlightOpts)); } } return result; } get visibleRectangle() { return this._getVisibleSelectionRectangle(this._rectangle); } get rectangleSigns() { return this._rectangleSigns; } _getVisibleSelectionRectangle(rectangle) { if (rectangle == null) return null; var r = rectangle.clone(); r.width = Math.abs(r.width); r.height = Math.abs(r.height); if (this._border != null) { var angle = r.angle; r = RotatedRectangleF.fromRectangleF(r.toRectangleF().getExpanded(this._border)); r.angle = angle; } return r; } get manipulationPermissions() { return this._manipulationPermissions; } get allowManipulation() { return this._canvas != null && (!this._canvas.simpleMode || this._canvas.contentEditingPlaceholderItemHandler != null); } get allowMove() { return this.manipulationPermissions.allowMove && this.allowManipulation; } get _allowNegativeResize() { return !this._itemHandlers.any(i => !i.allowNegativeResize); } addOnSelectionChanged(handler) { this._selectionChanged.add(handler); } removeOnSelectionChanged(handler) { this._selectionChanged.remove(handler); } _updateParentItemHandler(parentHandler) { if (this._parentItemHandler == parentHandler) return; if (this._parentItemHandler != null) { this._parentItemHandler.item.removePropertyChanged(this._onParentHandlerPropertyChanged); } this._parentItemHandler = parentHandler; if (this._parentItemHandler != null) { this._parentItemHandler.item.addPropertyChanged(this._onParentHandlerPropertyChanged); } } _getHistoryUpdateMode(finished) { return finished ? HistoryUpdateMode.ForceUpdate : HistoryUpdateMode.NotUpdate; } get _items() { if (this._canvas.contentEditingPlaceholderItemHandler != null) return [this._canvas.contentEditingPlaceholderItemHandler.item.content]; return this._itemHandlers.select(i => i.item).toArray(); } _fillSnapData() { const interactiveZonesBounds = this._interactiveZonesHandler.getSnapLines(); const rectWithBorder = getRotatedRectangleWithBorder(this.rectangle, this.border); this._snapLinesHandler.fillSnapData(this.rectangle, this._selectionProcessModifier.getRectWithFrames(this.rectangle), rectWithBorder != null ? rectWithBorder.bounds : null, this._region, interactiveZonesBounds, this._canvas, this._state === SelectionState.Drag); } dispose() { this._itemHandlers.remove_collectionChanged(this._onSelectionItemHandlersChanged); if (this._currentItemHandler instanceof PlaceholderItemHandler) this._currentItemHandler.removeIsEditingChanged(this._updatePermissions); } addCurrentItemChanged(listener) { this._currentItemChangedEvent.add(listener); } removeCurrentItemChanged(listener) { this._currentItemChangedEvent.remove(listener); } get isIdle() { return this._state === SelectionState.Idle; } get isResizing() { return this._state === SelectionState.Resize; } get isRotating() { return this._state === SelectionState.Rotate; } get isDragging() { return this._state === SelectionState.Drag; } } //gripses values for multipli (choosing resize strategy) SelectionHandler.cw = [0, -1, 1, 1, -1, -1, 0, 1, 0]; SelectionHandler.ch = [0, -1, -1, 1, 1, 0, -1, 0, 1]; export var SelectionState; (function (SelectionState) { SelectionState[SelectionState["Idle"] = 0] = "Idle"; SelectionState[SelectionState["Select"] = 1] = "Select"; SelectionState[SelectionState["Drag"] = 2] = "Drag"; SelectionState[SelectionState["Resize"] = 3] = "Resize"; SelectionState[SelectionState["Rotate"] = 4] = "Rotate"; })(SelectionState || (SelectionState = {})); //# sourceMappingURL=SelectionHandler.js.map