123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /*---------------------------------------------------------------------------------------------
- * Copyright (c) Microsoft Corporation. All rights reserved.
- * Licensed under the MIT License. See License.txt in the project root for license information.
- *--------------------------------------------------------------------------------------------*/
- import { Disposable } from '../../../base/common/lifecycle.js';
- import { isMacintosh } from '../../../base/common/platform.js';
- import './dnd.css';
- import { registerEditorContribution } from '../../browser/editorExtensions.js';
- import { Position } from '../../common/core/position.js';
- import { Range } from '../../common/core/range.js';
- import { Selection } from '../../common/core/selection.js';
- import { ModelDecorationOptions } from '../../common/model/textModel.js';
- import { DragAndDropCommand } from './dragAndDropCommand.js';
- function hasTriggerModifier(e) {
- if (isMacintosh) {
- return e.altKey;
- }
- else {
- return e.ctrlKey;
- }
- }
- export class DragAndDropController extends Disposable {
- constructor(editor) {
- super();
- this._editor = editor;
- this._register(this._editor.onMouseDown((e) => this._onEditorMouseDown(e)));
- this._register(this._editor.onMouseUp((e) => this._onEditorMouseUp(e)));
- this._register(this._editor.onMouseDrag((e) => this._onEditorMouseDrag(e)));
- this._register(this._editor.onMouseDrop((e) => this._onEditorMouseDrop(e)));
- this._register(this._editor.onMouseDropCanceled(() => this._onEditorMouseDropCanceled()));
- this._register(this._editor.onKeyDown((e) => this.onEditorKeyDown(e)));
- this._register(this._editor.onKeyUp((e) => this.onEditorKeyUp(e)));
- this._register(this._editor.onDidBlurEditorWidget(() => this.onEditorBlur()));
- this._register(this._editor.onDidBlurEditorText(() => this.onEditorBlur()));
- this._dndDecorationIds = [];
- this._mouseDown = false;
- this._modifierPressed = false;
- this._dragSelection = null;
- }
- onEditorBlur() {
- this._removeDecoration();
- this._dragSelection = null;
- this._mouseDown = false;
- this._modifierPressed = false;
- }
- onEditorKeyDown(e) {
- if (!this._editor.getOption(31 /* dragAndDrop */) || this._editor.getOption(18 /* columnSelection */)) {
- return;
- }
- if (hasTriggerModifier(e)) {
- this._modifierPressed = true;
- }
- if (this._mouseDown && hasTriggerModifier(e)) {
- this._editor.updateOptions({
- mouseStyle: 'copy'
- });
- }
- }
- onEditorKeyUp(e) {
- if (!this._editor.getOption(31 /* dragAndDrop */) || this._editor.getOption(18 /* columnSelection */)) {
- return;
- }
- if (hasTriggerModifier(e)) {
- this._modifierPressed = false;
- }
- if (this._mouseDown && e.keyCode === DragAndDropController.TRIGGER_KEY_VALUE) {
- this._editor.updateOptions({
- mouseStyle: 'default'
- });
- }
- }
- _onEditorMouseDown(mouseEvent) {
- this._mouseDown = true;
- }
- _onEditorMouseUp(mouseEvent) {
- this._mouseDown = false;
- // Whenever users release the mouse, the drag and drop operation should finish and the cursor should revert to text.
- this._editor.updateOptions({
- mouseStyle: 'text'
- });
- }
- _onEditorMouseDrag(mouseEvent) {
- let target = mouseEvent.target;
- if (this._dragSelection === null) {
- const selections = this._editor.getSelections() || [];
- let possibleSelections = selections.filter(selection => target.position && selection.containsPosition(target.position));
- if (possibleSelections.length === 1) {
- this._dragSelection = possibleSelections[0];
- }
- else {
- return;
- }
- }
- if (hasTriggerModifier(mouseEvent.event)) {
- this._editor.updateOptions({
- mouseStyle: 'copy'
- });
- }
- else {
- this._editor.updateOptions({
- mouseStyle: 'default'
- });
- }
- if (target.position) {
- if (this._dragSelection.containsPosition(target.position)) {
- this._removeDecoration();
- }
- else {
- this.showAt(target.position);
- }
- }
- }
- _onEditorMouseDropCanceled() {
- this._editor.updateOptions({
- mouseStyle: 'text'
- });
- this._removeDecoration();
- this._dragSelection = null;
- this._mouseDown = false;
- }
- _onEditorMouseDrop(mouseEvent) {
- if (mouseEvent.target && (this._hitContent(mouseEvent.target) || this._hitMargin(mouseEvent.target)) && mouseEvent.target.position) {
- let newCursorPosition = new Position(mouseEvent.target.position.lineNumber, mouseEvent.target.position.column);
- if (this._dragSelection === null) {
- let newSelections = null;
- if (mouseEvent.event.shiftKey) {
- let primarySelection = this._editor.getSelection();
- if (primarySelection) {
- const { selectionStartLineNumber, selectionStartColumn } = primarySelection;
- newSelections = [new Selection(selectionStartLineNumber, selectionStartColumn, newCursorPosition.lineNumber, newCursorPosition.column)];
- }
- }
- else {
- newSelections = (this._editor.getSelections() || []).map(selection => {
- if (selection.containsPosition(newCursorPosition)) {
- return new Selection(newCursorPosition.lineNumber, newCursorPosition.column, newCursorPosition.lineNumber, newCursorPosition.column);
- }
- else {
- return selection;
- }
- });
- }
- // Use `mouse` as the source instead of `api` and setting the reason to explicit (to behave like any other mouse operation).
- this._editor.setSelections(newSelections || [], 'mouse', 3 /* Explicit */);
- }
- else if (!this._dragSelection.containsPosition(newCursorPosition) ||
- ((hasTriggerModifier(mouseEvent.event) ||
- this._modifierPressed) && (this._dragSelection.getEndPosition().equals(newCursorPosition) || this._dragSelection.getStartPosition().equals(newCursorPosition)) // we allow users to paste content beside the selection
- )) {
- this._editor.pushUndoStop();
- this._editor.executeCommand(DragAndDropController.ID, new DragAndDropCommand(this._dragSelection, newCursorPosition, hasTriggerModifier(mouseEvent.event) || this._modifierPressed));
- this._editor.pushUndoStop();
- }
- }
- this._editor.updateOptions({
- mouseStyle: 'text'
- });
- this._removeDecoration();
- this._dragSelection = null;
- this._mouseDown = false;
- }
- showAt(position) {
- let newDecorations = [{
- range: new Range(position.lineNumber, position.column, position.lineNumber, position.column),
- options: DragAndDropController._DECORATION_OPTIONS
- }];
- this._dndDecorationIds = this._editor.deltaDecorations(this._dndDecorationIds, newDecorations);
- this._editor.revealPosition(position, 1 /* Immediate */);
- }
- _removeDecoration() {
- this._dndDecorationIds = this._editor.deltaDecorations(this._dndDecorationIds, []);
- }
- _hitContent(target) {
- return target.type === 6 /* CONTENT_TEXT */ ||
- target.type === 7 /* CONTENT_EMPTY */;
- }
- _hitMargin(target) {
- return target.type === 2 /* GUTTER_GLYPH_MARGIN */ ||
- target.type === 3 /* GUTTER_LINE_NUMBERS */ ||
- target.type === 4 /* GUTTER_LINE_DECORATIONS */;
- }
- dispose() {
- this._removeDecoration();
- this._dragSelection = null;
- this._mouseDown = false;
- this._modifierPressed = false;
- super.dispose();
- }
- }
- DragAndDropController.ID = 'editor.contrib.dragAndDrop';
- DragAndDropController.TRIGGER_KEY_VALUE = isMacintosh ? 6 /* Alt */ : 5 /* Ctrl */;
- DragAndDropController._DECORATION_OPTIONS = ModelDecorationOptions.register({
- description: 'dnd-target',
- className: 'dnd-target'
- });
- registerEditorContribution(DragAndDropController.ID, DragAndDropController);
|