@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
JavaScript
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