diff --git a/src/vs/editor/browser/controller/mouseHandler.ts b/src/vs/editor/browser/controller/mouseHandler.ts index be698a7550b30f11dc0f767dcbb11ba7517832f3..6d2a455fbee2fab31ec8ba300e05234c895944dd 100644 --- a/src/vs/editor/browser/controller/mouseHandler.ts +++ b/src/vs/editor/browser/controller/mouseHandler.ts @@ -418,6 +418,7 @@ class MouseDownOperation extends Disposable { private _onMouseDragThenMove(e: EditorMouseEvent): void { this._lastMouseEvent = e; this._mouseState.setModifiers(e); + this._mouseState.setMouseDownEvent('drag'); let position = this._findMousePosition(e, true); if (!position) { @@ -437,7 +438,7 @@ class MouseDownOperation extends Disposable { this._mouseState.setStartedOnLineNumbers(targetType === editorCommon.MouseTargetType.GUTTER_LINE_NUMBERS); this._mouseState.setModifiers(e); - + this._mouseState.setMouseDownEvent('down'); let position = this._findMousePosition(e, true); if (!position) { // Ignoring because position is unknown @@ -452,6 +453,7 @@ class MouseDownOperation extends Disposable { if (!this._mouseState.altKey // we don't support multiple mouse && e.detail < 2 // only single click on a selection can work && !this._isActive // the mouse is not down yet + && !this._currentSelection.isEmpty() // we don't drag single cursor && this._currentSelection.containsPosition(position.position) // single click on a selection ) { this._isActive = true; @@ -461,7 +463,16 @@ class MouseDownOperation extends Disposable { createMouseMoveEventMerger(null), this._mouseDragThenMoveEventHandler.handler, () => { - this._viewController.dragTo('mouse', this._dragTargetPosition); + if (this._mouseState.lastMouseDownEvent !== 'drag') { + // the last event is mouse down which happens 16ms ago. + this._dispatchMouse(position, e.shiftKey); + } else { + this._viewController.emitMouseDrop({ + event: e, + target: this._createMouseTarget(e, true) + }); + } + this._stop(); } ); @@ -602,6 +613,7 @@ class MouseDownState { private _lastMouseDownPositionEqualCount: number; private _lastMouseDownCount: number; private _lastSetMouseDownCountTime: number; + private _lastMouseDownEvent: 'down' | 'drag' | 'move'; constructor() { this._altKey = false; @@ -613,12 +625,17 @@ class MouseDownState { this._lastMouseDownPositionEqualCount = 0; this._lastMouseDownCount = 0; this._lastSetMouseDownCountTime = 0; + this._lastMouseDownEvent = 'down'; } public get count(): number { return this._lastMouseDownCount; } + public get lastMouseDownEvent(): 'down' | 'drag' | 'move' { + return this._lastMouseDownEvent; + } + public setModifiers(source: EditorMouseEvent) { this._altKey = source.altKey; this._ctrlKey = source.ctrlKey; @@ -626,6 +643,10 @@ class MouseDownState { this._shiftKey = source.shiftKey; } + public setMouseDownEvent(event: 'down' | 'drag' | 'move') { + this._lastMouseDownEvent = event; + } + public setStartedOnLineNumbers(startedOnLineNumbers: boolean): void { this._startedOnLineNumbers = startedOnLineNumbers; } diff --git a/src/vs/editor/browser/editorBrowser.ts b/src/vs/editor/browser/editorBrowser.ts index 7f822e7b61214107e3526330d7390d54d61cb762..2ea3474e83d4ffa2f56b858931eaab6ef8cda067 100644 --- a/src/vs/editor/browser/editorBrowser.ts +++ b/src/vs/editor/browser/editorBrowser.ts @@ -120,7 +120,6 @@ export interface IMouseDispatchData { export interface IViewController { dispatchMouse(data: IMouseDispatchData); - dragTo(source: string, position: Position): void; moveTo(source: string, position: Position): void; paste(source: string, text: string, pasteOnNewLine: boolean): void; @@ -138,6 +137,7 @@ export interface IViewController { emitMouseUp(e: IEditorMouseEvent): void; emitMouseDown(e: IEditorMouseEvent): void; emitMouseDrag(e: IEditorMouseEvent): void; + emitMouseDrop(e: IEditorMouseEvent): void; } /** @@ -422,6 +422,11 @@ export interface ICodeEditor extends editorCommon.ICommonCodeEditor { * @event */ onMouseDrag(listener: (e: IEditorMouseEvent) => void): IDisposable; + /** + * An event emitted on a "mousedrop". + * @event + */ + onMouseDrop(listener: (e: IEditorMouseEvent) => void): IDisposable; /** * An event emitted on a "contextmenu". * @event diff --git a/src/vs/editor/browser/view/viewController.ts b/src/vs/editor/browser/view/viewController.ts index 0b70991c44e91c8df2f357cc669911d20ede4e46..1477b2465c8e218750bba4395373eb89bfd6833f 100644 --- a/src/vs/editor/browser/view/viewController.ts +++ b/src/vs/editor/browser/view/viewController.ts @@ -143,14 +143,6 @@ export class ViewController implements IViewController { } } - public dragTo(source: string, viewPosition: Position): void { - viewPosition = this._validateViewColumn(viewPosition); - this.triggerCursorHandler(source, editorCommon.Handler.DragTo, { - position: this.convertViewToModelPosition(viewPosition), - viewPosition: viewPosition - }); - } - public moveTo(source: string, viewPosition: Position): void { viewPosition = this._validateViewColumn(viewPosition); this.triggerCursorHandler(source, editorCommon.Handler.MoveTo, { @@ -277,14 +269,22 @@ export class ViewController implements IViewController { } public emitMouseUp(e: IEditorMouseEvent): void { + console.log('up'); this.outgoingEvents.emitMouseUp(e); } public emitMouseDown(e: IEditorMouseEvent): void { + console.log('down'); this.outgoingEvents.emitMouseDown(e); } public emitMouseDrag(e: IEditorMouseEvent): void { + console.log('drag'); this.outgoingEvents.emitMouseDrag(e); } + + public emitMouseDrop(e: IEditorMouseEvent): void { + console.log('drop'); + this.outgoingEvents.emitMouseDrop(e); + } } diff --git a/src/vs/editor/browser/view/viewOutgoingEvents.ts b/src/vs/editor/browser/view/viewOutgoingEvents.ts index cc2e4985c8e70c0ef9235d9a47b05ba90a6d119c..566259205c0021194c91b924ecd95cb58cb2ec85 100644 --- a/src/vs/editor/browser/view/viewOutgoingEvents.ts +++ b/src/vs/editor/browser/view/viewOutgoingEvents.ts @@ -78,6 +78,10 @@ export class ViewOutgoingEvents extends Disposable { this._actual.emit(EventType.MouseDrag, this._convertViewToModelMouseEvent(e)); } + public emitMouseDrop(e: IEditorMouseEvent): void { + this._actual.emit(EventType.MouseDrop, this._convertViewToModelMouseEvent(e)); + } + private _convertViewToModelMouseEvent(e: IEditorMouseEvent): IEditorMouseEvent { if (e.target) { return { diff --git a/src/vs/editor/browser/widget/codeEditorWidget.ts b/src/vs/editor/browser/widget/codeEditorWidget.ts index 81bb0357e1bf9cad649b47a4de4bddf79bc2031f..3e1e4b2043db99ae7832c71c8c14c1a7cf2945ca 100644 --- a/src/vs/editor/browser/widget/codeEditorWidget.ts +++ b/src/vs/editor/browser/widget/codeEditorWidget.ts @@ -34,6 +34,7 @@ export abstract class CodeEditorWidget extends CommonCodeEditor implements edito public readonly onMouseUp: Event = fromEventEmitter(this, editorCommon.EventType.MouseUp); public readonly onMouseDown: Event = fromEventEmitter(this, editorCommon.EventType.MouseDown); public readonly onMouseDrag: Event = fromEventEmitter(this, editorCommon.EventType.MouseDrag); + public readonly onMouseDrop: Event = fromEventEmitter(this, editorCommon.EventType.MouseDrop); public readonly onContextMenu: Event = fromEventEmitter(this, editorCommon.EventType.ContextMenu); public readonly onMouseMove: Event = fromEventEmitter(this, editorCommon.EventType.MouseMove); public readonly onMouseLeave: Event = fromEventEmitter(this, editorCommon.EventType.MouseLeave); diff --git a/src/vs/editor/common/commonCodeEditor.ts b/src/vs/editor/common/commonCodeEditor.ts index ffa8cc6311df11f39b46ad787b573ee91acfbd4e..f3d58cf0277c51ddf626f7016b68d042d55e2535 100644 --- a/src/vs/editor/common/commonCodeEditor.ts +++ b/src/vs/editor/common/commonCodeEditor.ts @@ -874,6 +874,10 @@ export abstract class CommonCodeEditor extends EventEmitter implements editorCom this.emit(editorCommon.EventType.MouseDrag, e); break; + case editorCommon.EventType.MouseDrop: + this.emit(editorCommon.EventType.MouseDrop, e); + break; + case editorCommon.EventType.KeyUp: this.emit(editorCommon.EventType.KeyUp, e); break; diff --git a/src/vs/editor/common/controller/cursor.ts b/src/vs/editor/common/controller/cursor.ts index b80a96e2e9854faa4711c0bbbaffa3fcfd6f963e..76bff2078a1f8a60114949ade057515823ddfeb0 100644 --- a/src/vs/editor/common/controller/cursor.ts +++ b/src/vs/editor/common/controller/cursor.ts @@ -9,7 +9,6 @@ import * as strings from 'vs/base/common/strings'; import { onUnexpectedError } from 'vs/base/common/errors'; import { EventEmitter } from 'vs/base/common/eventEmitter'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; -import { DragAndDropCommand } from 'vs/editor/common/commands/dragAndDropCommand'; import { ReplaceCommand } from 'vs/editor/common/commands/replaceCommand'; import { CursorCollection, ICursorCollectionState } from 'vs/editor/common/controller/cursorCollection'; import { IOneCursorOperationContext, IViewModelHelper, OneCursor, OneCursorOp } from 'vs/editor/common/controller/oneCursor'; @@ -926,7 +925,6 @@ export class Cursor extends EventEmitter { this._handlers[H.WordSelect] = (ctx) => this._word(false, ctx); this._handlers[H.WordSelectDrag] = (ctx) => this._word(true, ctx); this._handlers[H.LastCursorWordSelect] = (ctx) => this._lastCursorWord(ctx); - this._handlers[H.DragTo] = (ctx) => this._dragTo(ctx); this._handlers[H.CancelSelection] = (ctx) => this._cancelSelection(ctx); this._handlers[H.RemoveSecondaryCursors] = (ctx) => this._removeSecondaryCursors(ctx); @@ -1308,42 +1306,6 @@ export class Cursor extends EventEmitter { return true; } - private _dragTo(ctx: IMultipleCursorOperationContext): boolean { - if (this.configuration.editor.readOnly || this.model.hasEditableRange()) { - return false; - } - - let selections = this.getSelections().filter(selection => !selection.isEmpty()); - - if (selections.length !== 1) { - return false; - } - - let dragTargetPosition = ctx.eventData.position; - if (selections[0].containsPosition(dragTargetPosition)) { - this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => { - if (oneCursor.modelState.selection.containsPosition(dragTargetPosition)) { - return OneCursorOp.moveTo(oneCursor, false, ctx.eventData.position, ctx.eventData.viewPosition, ctx.eventSource, oneCtx); - } - return false; - }); - - return true; - } else { - this._invokeForAll(ctx, (cursorIndex: number, oneCursor: OneCursor, oneCtx: IOneCursorOperationContext) => { - if (!oneCursor.modelState.selection.isEmpty()) { - return this._doApplyEdit(cursorIndex, oneCursor, oneCtx, () => new EditOperationResult(new DragAndDropCommand(oneCursor.modelState.selection, dragTargetPosition), { - shouldPushStackElementBefore: false, - shouldPushStackElementAfter: false - })); - } - return true; - }); - } - - return true; - } - private _removeSecondaryCursors(ctx: IMultipleCursorOperationContext): boolean { this.cursors.killSecondaryCursors(); return true; diff --git a/src/vs/editor/common/editorCommon.ts b/src/vs/editor/common/editorCommon.ts index e76b9fb723fd1f9f793d1d82747f5f8bc83cdfe7..e893c2209b7c345312ebc0787dcd7b1a3f69d431 100644 --- a/src/vs/editor/common/editorCommon.ts +++ b/src/vs/editor/common/editorCommon.ts @@ -4137,6 +4137,7 @@ export var EventType = { MouseMove: 'mousemove', MouseLeave: 'mouseleave', MouseDrag: 'mousedrag', + MouseDrop: 'mousedrop', KeyDown: 'keydown', KeyUp: 'keyup', diff --git a/src/vs/editor/contrib/dragAndDrop/browser/dragAndDrop.ts b/src/vs/editor/contrib/dragAndDrop/browser/dragAndDrop.ts index 3dbb72cb6f25934a9a3496b567ccee7a546e3aca..07e10cd4d6a5c7b61d53773b821930d07ea7a38d 100644 --- a/src/vs/editor/contrib/dragAndDrop/browser/dragAndDrop.ts +++ b/src/vs/editor/contrib/dragAndDrop/browser/dragAndDrop.ts @@ -11,7 +11,9 @@ import { ICodeEditor, IEditorMouseEvent } from 'vs/editor/browser/editorBrowser' import { editorContribution } from 'vs/editor/browser/editorBrowserExtensions'; import { IDisposable, dispose } from 'vs/base/common/lifecycle'; import { DragContentHintWidget } from './dragContentHintWidget'; - +import { Selection } from 'vs/editor/common/core/selection'; +import { DragAndDropCommand } from '../common/dragAndDropCommand'; +import { Position } from 'vs/editor/common/core/position'; @editorContribution export class DragAndDropController implements editorCommon.IEditorContribution { @@ -21,6 +23,8 @@ export class DragAndDropController implements editorCommon.IEditorContribution { private _editor: ICodeEditor; private _toUnhook: IDisposable[]; private _contentWidget: DragContentHintWidget; + private _active: boolean; + private _dragSelection: Selection; static get(editor: editorCommon.ICommonCodeEditor): DragAndDropController { return editor.getContribution(DragAndDropController.ID); @@ -32,13 +36,37 @@ export class DragAndDropController implements editorCommon.IEditorContribution { this._toUnhook = []; this._toUnhook.push(this._editor.onMouseDrag((e: IEditorMouseEvent) => this._onEditorMouseDrag(e))); - this._toUnhook.push(this._editor.onMouseUp((e: IEditorMouseEvent) => this._hideWidgets())); + this._toUnhook.push(this._editor.onMouseDrop((e: IEditorMouseEvent) => this._onEditorMouseDrop(e))); this._contentWidget = new DragContentHintWidget(editor); + this._active = false; } private _onEditorMouseDrag(mouseEvent: IEditorMouseEvent): void { let target = mouseEvent.target; - this._contentWidget.showAt(target.position); + + if (this._active) { + this._contentWidget.showAt(target.position); + } else { + let possibleSelections = this._editor.getSelections().filter(selection => selection.containsPosition(target.position)); + + if (possibleSelections.length === 1) { + this._active = true; + this._dragSelection = possibleSelections[0]; + this._contentWidget.showAt(target.position); + } + } + } + + private _onEditorMouseDrop(mouseEvent: IEditorMouseEvent): void { + let targetPosition = this._contentWidget.getPosition().position; + + if (targetPosition) { + let newCursorPosition = new Position(targetPosition.lineNumber, targetPosition.column); + this._editor.executeCommand(DragAndDropController.ID, new DragAndDropCommand(this._dragSelection, newCursorPosition)); + } + + this._hideWidgets(); + this._active = false; } private _hideWidgets(): void { diff --git a/src/vs/editor/common/commands/dragAndDropCommand.ts b/src/vs/editor/contrib/dragAndDrop/common/dragAndDropCommand.ts similarity index 99% rename from src/vs/editor/common/commands/dragAndDropCommand.ts rename to src/vs/editor/contrib/dragAndDrop/common/dragAndDropCommand.ts index 2502af6e5952240e6c91d83d1baa3e7cde0cb5d2..98eca36375a68858bf8dd9f4eee59b6824ba0b3a 100644 --- a/src/vs/editor/common/commands/dragAndDropCommand.ts +++ b/src/vs/editor/contrib/dragAndDrop/common/dragAndDropCommand.ts @@ -9,6 +9,7 @@ import { Position } from 'vs/editor/common/core/position'; import * as editorCommon from 'vs/editor/common/editorCommon'; import { Selection } from 'vs/editor/common/core/selection'; + export class DragAndDropCommand implements editorCommon.ICommand { private selection: Selection; diff --git a/src/vs/monaco.d.ts b/src/vs/monaco.d.ts index 6ee7f450184cac83ac398ee00220537690c6d305..a24df4889f33f63a04770dc3bbae297eda570244 100644 --- a/src/vs/monaco.d.ts +++ b/src/vs/monaco.d.ts @@ -3762,6 +3762,11 @@ declare module monaco.editor { * @event */ onMouseDrag(listener: (e: IEditorMouseEvent) => void): IDisposable; + /** + * An event emitted on a "mousedrop". + * @event + */ + onMouseDrop(listener: (e: IEditorMouseEvent) => void): IDisposable; /** * An event emitted on a "contextmenu". * @event