UNPKG

@eclipse-glsp/client

Version:

A sprotty-based client for GLSP

193 lines 8.86 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.FeedbackMoveMouseListener = void 0; /******************************************************************************** * Copyright (c) 2019-2024 EclipseSource and others. * * This program and the accompanying materials are made available under the * terms of the Eclipse Public License v. 2.0 which is available at * http://www.eclipse.org/legal/epl-2.0. * * This Source Code may also be made available under the following Secondary * Licenses when the conditions for such availability set forth in the Eclipse * Public License v. 2.0 are satisfied: GNU General Public License, version 2 * with the GNU Classpath Exception which is available at * https://www.gnu.org/software/classpath/license.html. * * SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 ********************************************************************************/ const sprotty_1 = require("@eclipse-glsp/sprotty"); const lodash_1 = require("lodash"); const drag_aware_mouse_listener_1 = require("../../../base/drag-aware-mouse-listener"); const css_feedback_1 = require("../../../base/feedback/css-feedback"); const gmodel_util_1 = require("../../../utils/gmodel-util"); const model_1 = require("../../change-bounds/model"); const change_bounds_tool_feedback_1 = require("./change-bounds-tool-feedback"); /** * This mouse listener provides visual feedback for moving by sending client-side * `MoveAction`s while elements are selected and dragged. This will also update * their bounds, which is important, as it is not only required for rendering * the visual feedback but also the basis for sending the change to the server * (see also `tools/MoveTool`). */ class FeedbackMoveMouseListener extends drag_aware_mouse_listener_1.DragAwareMouseListener { constructor(tool) { super(); this.tool = tool; this.elementId2startPos = new Map(); this.tracker = tool.createChangeBoundsTracker(); this.moveInitializedFeedback = tool.createFeedbackEmitter(); this.moveFeedback = tool.createFeedbackEmitter(); } mouseDown(target, event) { super.mouseDown(target, event); if (event.button === 0) { if (this.tracker.isTracking()) { // we have a move in progress that was not resolved yet (e.g., user may have triggered a mouse up outside the window) this.draggingMouseUp(target, event); return []; } this.initializeMove(target, event); return []; } this.tracker.stopTracking(); return []; } initializeMove(target, event) { if (target instanceof model_1.GResizeHandle) { // avoid conflict with resize tool return; } const moveable = (0, sprotty_1.findParentByFeature)(target, this.isValidMoveable); if (moveable !== undefined) { this.tracker.startTracking(); this.scheduleMoveInitialized(); } else { this.tracker.stopTracking(); } } scheduleMoveInitialized() { var _a; (_a = this.pendingMoveInitialized) === null || _a === void 0 ? void 0 : _a.cancel(); this.pendingMoveInitialized = (0, lodash_1.debounce)(() => { this.moveInitialized(); this.pendingMoveInitialized = undefined; }, 750); this.pendingMoveInitialized(); } moveInitializationTimeout() { return 750; } moveInitialized() { if (this.isMouseDown) { this.moveInitializedFeedback .add(change_bounds_tool_feedback_1.MoveInitializedEventAction.create(), change_bounds_tool_feedback_1.MoveFinishedEventAction.create()) .add((0, css_feedback_1.cursorFeedbackAction)(css_feedback_1.CursorCSS.MOVE), (0, css_feedback_1.cursorFeedbackAction)(css_feedback_1.CursorCSS.DEFAULT)) .submit(); } } isValidMoveable(element) { return !!element && (0, gmodel_util_1.isNonRoutableSelectedMovableBoundsAware)(element) && !(element instanceof model_1.GResizeHandle); } isValidRevertable(element) { return !!element && (0, gmodel_util_1.isNonRoutableMovableBoundsAware)(element) && !(element instanceof model_1.GResizeHandle); } nonDraggingMouseUp(element, event) { // should reset everything that may have happend on mouse down this.moveInitializedFeedback.dispose(); this.tracker.stopTracking(); return []; } draggingMouseMove(target, event) { super.draggingMouseMove(target, event); if (this.tracker.isTracking()) { return this.moveElements(target, event); } return []; } moveElements(target, event) { var _a; if (this.elementId2startPos.size === 0) { this.initializeElementsToMove(target.root); } const elementsToMove = this.getElementsToMove(target); const move = this.tracker.moveElements(elementsToMove, { snap: event, restrict: event }); if (move.elementMoves.length === 0) { return []; } // cancel any pending move (_a = this.pendingMoveInitialized) === null || _a === void 0 ? void 0 : _a.cancel(); this.moveFeedback.add(this.createMoveAction(move), () => this.resetElementPositions(target)); this.addMoveFeedback(move, target, event); this.tracker.updateTrackingPosition(move); this.moveFeedback.submit(); return []; } createMoveAction(trackedMove) { // we never want to animate the move action as this interferes with the move feedback return sprotty_1.MoveAction.create(trackedMove.elementMoves.map(move => ({ elementId: move.element.id, toPosition: move.toPosition })), { animate: false }); } addMoveFeedback(trackedMove, ctx, event) { this.tool.changeBoundsManager.addMoveFeedback(this.moveFeedback, trackedMove, ctx, event); } initializeElementsToMove(root) { const elementsToMove = this.collectElementsToMove(root); elementsToMove.forEach(element => this.elementId2startPos.set(element.id, element.position)); } collectElementsToMove(root) { const moveableElements = (0, gmodel_util_1.filter)(root.index, this.isValidMoveable); const topLevelElements = (0, gmodel_util_1.removeDescendants)(moveableElements); return Array.from(topLevelElements); } getElementsToMove(context, moveable = this.isValidMoveable) { return (0, gmodel_util_1.getElements)(context.root.index, Array.from(this.elementId2startPos.keys()), moveable); } resetElementPositions(context) { const elementMoves = this.revertElementMoves(context); return sprotty_1.MoveAction.create(elementMoves, { animate: false, finished: true }); } revertElementMoves(context) { var _a; const elementMoves = []; if ((_a = context === null || context === void 0 ? void 0 : context.root) === null || _a === void 0 ? void 0 : _a.index) { const movableElements = this.getElementsToMove(context, this.isValidRevertable); movableElements.forEach(element => elementMoves.push({ elementId: element.id, toPosition: this.elementId2startPos.get(element.id) })); } return elementMoves; } draggingMouseUp(target, event) { if (!this.tracker.isTracking()) { return []; } const elementsToMove = this.getElementsToMove(target); if (!this.tool.movementOptions.allElementsNeedToBeValid) { // only reset the move of invalid elements, the others will be handled by the change bounds tool itself elementsToMove .filter(element => this.tool.changeBoundsManager.isValid(element)) .forEach(element => this.elementId2startPos.delete(element.id)); } else { if (elementsToMove.length > 0 && elementsToMove.every(element => this.tool.changeBoundsManager.isValid(element))) { // do not reset any element as all are valid this.elementId2startPos.clear(); } } this.dispose(); return []; } selectionChanged(root, selectedElements, deselectedElements) { this.dispose(); } dispose() { var _a; (_a = this.pendingMoveInitialized) === null || _a === void 0 ? void 0 : _a.cancel(); this.moveInitializedFeedback.dispose(); this.moveFeedback.dispose(); this.tracker.dispose(); this.elementId2startPos.clear(); super.dispose(); } } exports.FeedbackMoveMouseListener = FeedbackMoveMouseListener; //# sourceMappingURL=change-bounds-tool-move-feedback.js.map