Skip to content

Commit

Permalink
Fix eclipse-theia#9203: Drag and drop sections between views
Browse files Browse the repository at this point in the history
Signed-off-by: Esther Perelman <[email protected]>
  • Loading branch information
EstherPerelman committed Aug 23, 2021
1 parent a6422c3 commit 5a7ae69
Show file tree
Hide file tree
Showing 20 changed files with 635 additions and 83 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
- [core] registering toolbar items for commands that explicitly target a `ViewContainer` rather than a child widget may not behave as expected. Such registrations should be made in the `ViewContainer` by overriding the `updateToolbarItems` method and using the `registerToolbarItem` utility. See the modifications to the `scm` and `vsx-registry` packages in the PR for examples. [#9798](https://github.com/eclipse-theia/theia/pull/9798)
- [vsx-registry] `VSXExtensionsContribution` no longer implements `TabBarToolbarContribution` and is not bound as such. Extensions of the class that expect such behavior should reimplement it with caution. See caveats in PR. [#9798](https://github.com/eclipse-theia/theia/pull/9798)
- [core] `handleExpansionToggleDblClickEvent` in `TreeWidget` can no longer be overridden. Instead, `doHandleExpansionToggleDblClickEvent` can be overridden. [#9877](https://github.com/eclipse-theia/theia/pull/9877)
- [view-container] `ViewContainerPart` constructor takes new 2 parameters: `originalContainerId` and `originalContainerTitle`, The existing `viewContainerId` parameter has been renamed to `currentContainerId` to enable drag & drop views. [#9644](https://github.com/eclipse-theia/theia/pull/9644)

## v1.16.0 - 7/29/2021

Expand Down
3 changes: 2 additions & 1 deletion packages/core/src/browser/frontend-application-module.ts
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ import { ResourceContextKey } from './resource-context-key';
import { KeyboardLayoutService } from './keyboard/keyboard-layout-service';
import { MimeService } from './mime-service';
import { ApplicationShellMouseTracker } from './shell/application-shell-mouse-tracker';
import { ViewContainer, ViewContainerIdentifier } from './view-container';
import { ViewContainer, ViewContainerIdentifier, DraggingPartManager } from './view-container';
import { QuickViewService } from './quick-input/quick-view-service';
import { DialogOverlayService } from './dialogs';
import { ProgressLocationService } from './progress-location-service';
Expand Down Expand Up @@ -315,6 +315,7 @@ export const frontendApplicationModule = new ContainerModule((bind, unbind, isBo
bind(ApplicationShellMouseTracker).toSelf().inSingletonScope();
bind(FrontendApplicationContribution).toService(ApplicationShellMouseTracker);

bind(DraggingPartManager).toSelf().inSingletonScope();
bind(ViewContainer.Factory).toFactory(context => (options: ViewContainerIdentifier) => {
const container = context.container.createChild();
container.bind(ViewContainerIdentifier).toConstantValue(options);
Expand Down
4 changes: 3 additions & 1 deletion packages/core/src/browser/shell/application-shell.ts
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,9 @@ export type ApplicationShellLayoutVersion =
/** view containers are introduced, backward compatible to 2.0 */
3.0 |
/** git history view is replaced by a more generic scm history view, backward compatible to 3.0 */
4.0;
4.0 |
/** added the ability to drag and drop view parts between view containers */
5.0;

/**
* When a version is increased, make sure to introduce a migration (ApplicationShellLayoutMigration) to this version.
Expand Down
67 changes: 64 additions & 3 deletions packages/core/src/browser/shell/tab-bars.ts
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,10 @@ export class TabBarRenderer extends TabBar.Renderer {
onauxclick: (e: MouseEvent) => {
// If user closes the tab using mouse wheel, nothing should be pasted to an active editor
e.preventDefault();
}
},
ondragenter: this.handleDragEnterOrLeaveEvent,
ondragover: this.handleDragOverEvent,
ondragleave: this.handleDragEnterOrLeaveEvent
},
h.div(
{ className: 'theia-tab-icon-label' },
Expand Down Expand Up @@ -439,18 +442,76 @@ export class TabBarRenderer extends TabBar.Renderer {
}
};

protected getTitle(id: string): Title<Widget> | undefined {
return this.tabBar && this.tabBar.titles.find(t => this.createTabId(t) === id);
}

protected handleDblClickEvent = (event: MouseEvent) => {
if (this.tabBar && event.currentTarget instanceof HTMLElement) {
const id = event.currentTarget.id;
// eslint-disable-next-line no-null/no-null
const title = this.tabBar.titles.find(t => this.createTabId(t) === id) || null;
const title = this.getTitle(id);
const area = title && title.owner.parent;
if (area instanceof TheiaDockPanel && (area.id === BOTTOM_AREA_ID || area.id === MAIN_AREA_ID)) {
area.toggleMaximized();
}
}
};

isViewContainerDND(event: DragEvent): boolean {
const { dataTransfer } = event;
return !!dataTransfer && dataTransfer.types.indexOf('view-container-dnd') > -1;
}

isSidebarDNDEvent(event: DragEvent): boolean {
return this.tabBar instanceof SideTabBar && this.isViewContainerDND(event);
}

toCancelViewContainerDND = new DisposableCollection();
protected handleDragEnterOrLeaveEvent = (event: DragEvent) => {
if (!this.isSidebarDNDEvent(event)) {
return;
}
this.toCancelViewContainerDND.dispose();
};

protected handleDragOverEvent = (event: DragEvent) => {
if (!this.toCancelViewContainerDND.disposed) {
return;
}
if (!this.isSidebarDNDEvent(event)) {
if (event.dataTransfer) {
event.dataTransfer.dropEffect = 'none';
}
return;
}
const { currentTarget, clientX, clientY } = event;
if (currentTarget instanceof HTMLElement) {
const { top, bottom, left, right, height } = currentTarget.getBoundingClientRect();
const mouseOnTop = (clientY - top) < (height / 2);
const dropTargetClass = `drop-target-${mouseOnTop ? 'top' : 'bottom'}`;
currentTarget.classList.add(dropTargetClass);
this.toCancelViewContainerDND.push(Disposable.create(() => {
if (currentTarget) {
currentTarget.classList.remove(dropTargetClass);
}
}));
const openTabTimer = setTimeout(() => {
const title = this.getTitle(currentTarget.id);
if (title) {
const mouseStillOnTab = clientX >= left && clientX <= right && clientY >= top && clientY <= bottom;
if (mouseStillOnTab && this.tabBar) {
this.tabBar.currentTitle = title;
this.tabBar.setHidden(false);
this.tabBar.activate();
}
}
}, 800);
this.toCancelViewContainerDND.push(Disposable.create(() => {
clearTimeout(openTabTimer);
}));
}
};

}

/**
Expand Down
21 changes: 21 additions & 0 deletions packages/core/src/browser/style/tabs.css
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@
--theia-private-horizontal-tab-scrollbar-height: 5px;
--theia-tabbar-toolbar-z-index: 1001;
--theia-toolbar-active-transform-scale: 1.272019649;
--theia-dragover-tab-border-width: 2px;
}

/*-----------------------------------------------------------------------------
Expand All @@ -23,6 +24,7 @@
overflow-x: hidden;
overflow-y: hidden;
min-height: calc(var(--theia-private-horizontal-tab-height) + var(--theia-private-horizontal-tab-scrollbar-rail-height) / 2);

}

.p-TabBar .p-TabBar-content {
Expand All @@ -38,6 +40,25 @@
align-items: center;
}

.p-TabBar[data-orientation='vertical'] .p-TabBar-tab {
flex: none;
height: calc(var(--theia-private-horizontal-tab-height) + var(--theia-private-horizontal-tab-scrollbar-rail-height) / 2);
min-width: 35px;
line-height: var(--theia-private-horizontal-tab-height);
padding: 0px 8px;
align-items: center;
border-top: var(--theia-dragover-tab-border-width) solid transparent !important;
border-bottom: var(--theia-dragover-tab-border-width) solid transparent !important;
}

.p-TabBar[data-orientation='vertical'] .p-TabBar-tab.drop-target-top {
border-top-color: var(--theia-activityBar-activeBorder) !important;
}

.p-TabBar[data-orientation='vertical'] .p-TabBar-tab.drop-target-bottom {
border-bottom-color: var(--theia-activityBar-activeBorder) !important;
}

.p-TabBar[data-orientation='horizontal'] .p-TabBar-tab .theia-tab-icon-label,
.p-TabBar-tab.p-mod-drag-image .theia-tab-icon-label {
display: flex;
Expand Down
2 changes: 1 addition & 1 deletion packages/core/src/browser/style/view-container.css
Original file line number Diff line number Diff line change
Expand Up @@ -98,7 +98,7 @@
}

.theia-view-container .part.drop-target {
background: var(--theia-sideBar-dropBackground);
background: var(--theia-list-dropBackground);
border: var(--theia-border-width) dashed var(--theia-contrastActiveBorder);
transition-property: top, left, right, bottom;
transition-duration: 150ms;
Expand Down
Loading

0 comments on commit 5a7ae69

Please sign in to comment.