mirror of
https://github.com/microsoft/vscode.git
synced 2026-04-27 20:13:32 +01:00
panelview: dnd
This commit is contained in:
@@ -6,13 +6,14 @@
|
||||
'use strict';
|
||||
|
||||
import 'vs/css!./splitview';
|
||||
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
||||
import { IDisposable, dispose, combinedDisposable } from 'vs/base/common/lifecycle';
|
||||
import Event, { Emitter, chain } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent';
|
||||
import { KeyCode } from 'vs/base/common/keyCodes';
|
||||
import { $, append, addClass, removeClass, toggleClass } from 'vs/base/browser/dom';
|
||||
import { firstIndex } from 'vs/base/common/arrays';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { SplitView, IView } from './splitview2';
|
||||
|
||||
enum PanelState {
|
||||
@@ -36,7 +37,7 @@ export abstract class Panel implements IView {
|
||||
private _minimumBodySize: number;
|
||||
private _maximumBodySize: number;
|
||||
private ariaHeaderLabel: string;
|
||||
private header: HTMLElement;
|
||||
readonly header: HTMLElement;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
get minimumBodySize(): number {
|
||||
@@ -155,6 +156,95 @@ export abstract class Panel implements IView {
|
||||
}
|
||||
}
|
||||
|
||||
interface IDndContext {
|
||||
draggable: PanelDraggable | null;
|
||||
}
|
||||
|
||||
class PanelDraggable implements IDisposable {
|
||||
|
||||
// see https://github.com/Microsoft/vscode/issues/14470
|
||||
private dragOverCounter = 0;
|
||||
private dropBackground: Color | undefined;
|
||||
private disposables: IDisposable[] = [];
|
||||
|
||||
private _onDidDrop = new Emitter<{ from: Panel, to: Panel }>();
|
||||
readonly onDidDrop = this._onDidDrop.event;
|
||||
|
||||
constructor(private panel: Panel, private context: IDndContext) {
|
||||
domEvent(panel.header, 'dragstart')(this.onDragStart, this, this.disposables);
|
||||
domEvent(panel.header, 'dragenter')(this.onDragEnter, this, this.disposables);
|
||||
domEvent(panel.header, 'dragleave')(this.onDragLeave, this, this.disposables);
|
||||
domEvent(panel.header, 'dragend')(this.onDragEnd, this, this.disposables);
|
||||
domEvent(panel.header, 'drop')(this.onDrop, this, this.disposables);
|
||||
}
|
||||
|
||||
private onDragStart(e: DragEvent): void {
|
||||
e.dataTransfer.effectAllowed = 'move';
|
||||
|
||||
const dragImage = append(document.body, $('.monaco-panel-drag-image', {}, this.panel.header.textContent));
|
||||
e.dataTransfer.setDragImage(dragImage, -10, -10);
|
||||
setTimeout(() => document.body.removeChild(dragImage), 0);
|
||||
|
||||
this.context.draggable = this;
|
||||
}
|
||||
|
||||
private onDragEnter(e: DragEvent): void {
|
||||
if (!this.context.draggable || this.context.draggable === this) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dragOverCounter++;
|
||||
this.renderHeader();
|
||||
}
|
||||
|
||||
private onDragLeave(e: DragEvent): void {
|
||||
if (!this.context.draggable || this.context.draggable === this) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dragOverCounter--;
|
||||
|
||||
if (this.dragOverCounter === 0) {
|
||||
this.renderHeader();
|
||||
}
|
||||
}
|
||||
|
||||
private onDragEnd(e: DragEvent): void {
|
||||
if (!this.context.draggable) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dragOverCounter = 0;
|
||||
this.renderHeader();
|
||||
this.context.draggable = null;
|
||||
}
|
||||
|
||||
private onDrop(e: DragEvent): void {
|
||||
if (!this.context.draggable) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.dragOverCounter = 0;
|
||||
this.renderHeader();
|
||||
|
||||
if (this.context.draggable !== this) {
|
||||
this._onDidDrop.fire({ from: this.context.draggable.panel, to: this.panel });
|
||||
}
|
||||
|
||||
this.context.draggable = null;
|
||||
}
|
||||
|
||||
private renderHeader(): void {
|
||||
this.panel.header.style.backgroundColor = this.dragOverCounter === 0 && this.dropBackground
|
||||
? this.dropBackground.toString()
|
||||
: null;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this.disposables = dispose(this.disposables);
|
||||
}
|
||||
}
|
||||
|
||||
export class IPanelViewOptions {
|
||||
dnd?: boolean;
|
||||
}
|
||||
@@ -166,19 +256,30 @@ interface IPanelItem {
|
||||
|
||||
export class PanelView implements IDisposable {
|
||||
|
||||
private dnd: boolean;
|
||||
private dndContext: IDndContext = { draggable: null };
|
||||
private el: HTMLElement;
|
||||
private panelItems: IPanelItem[] = [];
|
||||
private splitview: SplitView;
|
||||
private animationTimer: number | null = null;
|
||||
|
||||
constructor(private container: HTMLElement, options?: IPanelViewOptions) {
|
||||
this.dnd = !!options.dnd;
|
||||
this.el = append(container, $('.monaco-panel-view'));
|
||||
this.splitview = new SplitView(container);
|
||||
}
|
||||
|
||||
addPanel(panel: Panel, size: number, index = this.splitview.length): void {
|
||||
const disposable = panel.onDidChange(this.setupAnimation, this);
|
||||
const panelItem = { panel, disposable };
|
||||
const disposables: IDisposable[] = [];
|
||||
panel.onDidChange(this.setupAnimation, this, disposables);
|
||||
|
||||
if (this.dnd) {
|
||||
const draggable = new PanelDraggable(panel, this.dndContext);
|
||||
disposables.push(draggable);
|
||||
draggable.onDidDrop(({ from, to }) => this.movePanel(from, to), null, disposables);
|
||||
}
|
||||
|
||||
const panelItem = { panel, disposable: combinedDisposable(disposables) };
|
||||
|
||||
this.panelItems.splice(index, 0, panelItem);
|
||||
this.splitview.addView(panel, size, index);
|
||||
@@ -196,6 +297,17 @@ export class PanelView implements IDisposable {
|
||||
panelItem.disposable.dispose();
|
||||
}
|
||||
|
||||
movePanel(from: Panel, to: Panel): void {
|
||||
const fromIndex = firstIndex(this.panelItems, item => item.panel === from);
|
||||
const toIndex = firstIndex(this.panelItems, item => item.panel === to);
|
||||
|
||||
if (fromIndex === -1 || toIndex === -1) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.splitview.moveView(fromIndex, toIndex);
|
||||
}
|
||||
|
||||
layout(size: number): void {
|
||||
this.splitview.layout(size);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user