Skip to content

Commit

Permalink
Sash double clicks (#4702)
Browse files Browse the repository at this point in the history
* Support double click on sashes

We had to implement a slight change in the sash drag "hack", by removing the
full cover transparent overlay (that was preventing clicks events from being
fired) and replacing it by a CSS `cursor` rule on the document.body.

The ideal solution for a clean dragging events implementation would be to use
the `Element.setCapture` API that is unfortunately not available in Chrome.

* Center the split editor frontier by double-clicking on it

* Reset the bottom panel size by double-clicking on it

* Implement sash reset on diff editors

* Fix a bug with DOM measurement

The calculus was plain wrong as showed in winjs/winjs#1621
This was probably unotified since this utility function wasn't used in the code base.

* Implement sidebar sash optimal resizing

Fixes #4660

* Abstract `getLargestChildWidth` into a DOM method

This commit also moves the `getOptimalWidth` method from the `Composite` to the
`Viewlet` component. This partially addresses
#4702 (comment)

* Calculate the sidebar optimal width correctly in case no folder is open
  • Loading branch information
mquandalle authored and isidorn committed Apr 15, 2016
1 parent c07668d commit 239edbf
Show file tree
Hide file tree
Showing 13 changed files with 127 additions and 52 deletions.
38 changes: 13 additions & 25 deletions src/vs/base/browser/dom.ts
Original file line number Diff line number Diff line change
Expand Up @@ -637,46 +637,34 @@ export function getTotalHeight(element: HTMLElement): number {
return element.offsetHeight + margin;
}

// Adapted from WinJS
// Gets the left coordinate of the specified element relative to the specified parent.
export function getRelativeLeft(element: HTMLElement, parent: HTMLElement): number {
if (element === null) {
return 0;
}

let left = element.offsetLeft;
let e = <HTMLElement>element.parentNode;
while (e !== null) {
left -= e.offsetLeft;

if (e === parent) {
break;
}
e = <HTMLElement>e.parentNode;
}

return left;
let elementPosition = getTopLeftOffset(element);
let parentPosition = getTopLeftOffset(parent);
return elementPosition.left - parentPosition.left;
}

// Adapted from WinJS
// Gets the top coordinate of the element relative to the specified parent.
export function getRelativeTop(element: HTMLElement, parent: HTMLElement): number {
if (element === null) {
return 0;
}

let top = element.offsetTop;
let e = <HTMLElement>element.parentNode;
while (e !== null) {
top -= e.offsetTop;

if (e === parent) {
break;
}
e = <HTMLElement>e.parentNode;
}
let elementPosition = getTopLeftOffset(element);
let parentPosition = getTopLeftOffset(parent);
return parentPosition.top - elementPosition.top;
}

return top;
export function getLargestChildWidth(parent: HTMLElement, children: HTMLElement[]): number {
let childWidths = children.map((child) => {
return getTotalWidth(child) + getRelativeLeft(child, parent) || 0;
});
let maxWidth = Math.max(...childWidths);
return maxWidth;
}

// ----------------------------------------------------------------------------------------
Expand Down
8 changes: 8 additions & 0 deletions src/vs/base/browser/ui/sash/sash.css
Original file line number Diff line number Diff line change
Expand Up @@ -23,4 +23,12 @@

.monaco-sash.disabled {
cursor: default;
}

.vertical-cursor-container * {
cursor: ew-resize !important;
}

.horizontal-cursor-container * {
cursor: ns-resize !important;
}
24 changes: 10 additions & 14 deletions src/vs/base/browser/ui/sash/sash.ts
Original file line number Diff line number Diff line change
Expand Up @@ -63,11 +63,12 @@ export class Sash extends EventEmitter {

this.gesture = new Gesture(this.$e.getHTMLElement());

this.$e.on('mousedown', (e: MouseEvent) => { this.onMouseDown(e); });
this.$e.on(DOM.EventType.MOUSE_DOWN, (e: MouseEvent) => { this.onMouseDown(e); });
this.$e.on(DOM.EventType.DBLCLICK, (e: MouseEvent) => { this.emit('reset', e); });
this.$e.on(EventType.Start, (e: GestureEvent) => { this.onTouchStart(e); });

this.orientation = options.orientation || Orientation.VERTICAL;
this.$e.addClass(this.orientation === Orientation.HORIZONTAL ? 'horizontal' : 'vertical');
this.$e.addClass(this.getOrientation());

this.size = options.baseSize || 5;

Expand All @@ -91,6 +92,10 @@ export class Sash extends EventEmitter {
return this.$e.getHTMLElement();
}

private getOrientation(): 'horizontal' | 'vertical' {
return this.orientation === Orientation.HORIZONTAL ? 'horizontal' : 'vertical';
}

private onMouseDown(e: MouseEvent): void {
DOM.EventHelper.stop(e, false);

Expand All @@ -112,17 +117,8 @@ export class Sash extends EventEmitter {
this.$e.addClass('active');
this.emit('start', startEvent);

let overlayDiv = $('div').style({
position: 'absolute',
top: 0,
left: 0,
width: '100%',
height: '100%',
zIndex: 1000000,
cursor: this.orientation === Orientation.VERTICAL ? 'ew-resize' : 'ns-resize'
});

let $window = $(window);
let containerCssClass = `${this.getOrientation()}-cursor-container`;

let lastCurrentX = startX;
let lastCurrentY = startY;
Expand All @@ -148,10 +144,10 @@ export class Sash extends EventEmitter {
this.emit('end');

$window.off('mousemove');
overlayDiv.destroy();
document.body.classList.remove(containerCssClass);
});

overlayDiv.appendTo(document.body);
document.body.classList.add(containerCssClass);
}

private onTouchStart(event: GestureEvent): void {
Expand Down
19 changes: 13 additions & 6 deletions src/vs/editor/browser/widget/diffEditorWidget.ts
Original file line number Diff line number Diff line change
Expand Up @@ -1327,9 +1327,10 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
this._sash.disable();
}

this._sash.on('start', () => this._onSashDragStart());
this._sash.on('change', (e: ISashEvent) => this._onSashDrag(e));
this._sash.on('end', () => this._onSashDragEnd());
this._sash.on('start', () => this.onSashDragStart());
this._sash.on('change', (e: ISashEvent) => this.onSashDrag(e));
this._sash.on('end', () => this.onSashDragEnd());
this._sash.on('reset', () => this.onSashReset());
}

public dispose(): void {
Expand Down Expand Up @@ -1378,11 +1379,11 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
return this._sashPosition;
}

private _onSashDragStart(): void {
private onSashDragStart(): void {
this._startSashPosition = this._sashPosition;
}

private _onSashDrag(e:ISashEvent): void {
private onSashDrag(e:ISashEvent): void {
var w = this._dataSource.getWidth();
var contentWidth = w - DiffEditorWidget.ENTIRE_DIFF_OVERVIEW_WIDTH;
var sashPosition = this.layout((this._startSashPosition + (e.currentX - e.startX)) / contentWidth);
Expand All @@ -1392,7 +1393,13 @@ class DiffEdtorWidgetSideBySide extends DiffEditorWidgetStyle implements IDiffEd
this._dataSource.relayoutEditors();
}

private _onSashDragEnd(): void {
private onSashDragEnd(): void {
this._sash.layout();
}

private onSashReset(): void {
this._sashRatio = 0.5;
this._dataSource.relayoutEditors();
this._sash.layout();
}

Expand Down
21 changes: 20 additions & 1 deletion src/vs/workbench/browser/layout.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import {Sash, ISashEvent, IVerticalSashLayoutProvider, IHorizontalSashLayoutProv
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {IPartService, Position} from 'vs/workbench/services/part/common/partService';
import {IWorkspaceContextService} from 'vs/workbench/services/workspace/common/contextService';
import {IViewletService} from 'vs/workbench/services/viewlet/common/viewletService';
import {IStorageService, StorageScope} from 'vs/platform/storage/common/storage';
import {IContextViewService} from 'vs/platform/contextview/browser/contextView';
import {IEventService} from 'vs/platform/event/common/event';
Expand Down Expand Up @@ -94,6 +95,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal
@IWorkbenchEditorService private editorService: IWorkbenchEditorService,
@IWorkspaceContextService private contextService: IWorkspaceContextService,
@IPartService private partService: IPartService,
@IViewletService private viewletService: IViewletService,
@IThemeService themeService: IThemeService
) {
this.parent = parent;
Expand Down Expand Up @@ -190,7 +192,7 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal
let dragCompensation = DEFAULT_MIN_PANEL_PART_HEIGHT - HIDE_PANEL_HEIGHT_THRESHOLD;
this.partService.setPanelHidden(true);
startY = Math.min(this.sidebarHeight - this.computedStyles.statusbar.height, e.currentY + dragCompensation);
this.panelHeight = this.startPanelHeight; // when restoring panel, restore to the panel width we started from
this.panelHeight = this.startPanelHeight; // when restoring panel, restore to the panel height we started from
}

// Otherwise size the panel accordingly
Expand All @@ -217,9 +219,26 @@ export class WorkbenchLayout implements IVerticalSashLayoutProvider, IHorizontal
this.sashX.addListener('end', () => {
this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL);
});

this.sashY.addListener('end', () => {
this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL);
});

this.sashY.addListener('reset', () => {
this.panelHeight = DEFAULT_MIN_PANEL_PART_HEIGHT;
this.storageService.store(WorkbenchLayout.sashYHeightSettingsKey, this.panelHeight, StorageScope.GLOBAL);
this.partService.setPanelHidden(false);
this.layout();
});

this.sashX.addListener('reset', () => {
let activeViewlet = this.viewletService.getActiveViewlet();
let optimalWidth = activeViewlet && activeViewlet.getOptimalWidth();
this.sidebarWidth = Math.max(DEFAULT_MIN_PART_WIDTH, optimalWidth || 0);
this.storageService.store(WorkbenchLayout.sashXWidthSettingsKey, this.sidebarWidth, StorageScope.GLOBAL);
this.partService.setSideBarHidden(false);
this.layout();
});
}

private onEditorInputChanging(e: EditorEvent): void {
Expand Down
7 changes: 7 additions & 0 deletions src/vs/workbench/browser/parts/editor/binaryDiffEditor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,6 +72,7 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
this.sash.addListener('start', () => this.onSashDragStart());
this.sash.addListener('change', (e: ISashEvent) => this.onSashDrag(e));
this.sash.addListener('end', () => this.onSashDragEnd());
this.sash.addListener('reset', () => this.onSashReset());

// Right Container for Binary
let rightBinaryContainerElement = document.createElement('div');
Expand Down Expand Up @@ -199,6 +200,12 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
this.sash.layout();
}

private onSashReset(): void {
this.leftContainerWidth = this.dimension.width / 2;
this.layoutContainers();
this.sash.layout();
}

public getVerticalSashTop(sash: Sash): number {
return 0;
}
Expand Down
20 changes: 20 additions & 0 deletions src/vs/workbench/browser/parts/editor/sideBySideEditorControl.ts
Original file line number Diff line number Diff line change
Expand Up @@ -728,6 +728,7 @@ export class SideBySideEditorControl extends EventEmitter implements IVerticalSa
this.leftSash.addListener('start', () => this.onLeftSashDragStart());
this.leftSash.addListener('change', (e: ISashEvent) => this.onLeftSashDrag(e));
this.leftSash.addListener('end', () => this.onLeftSashDragEnd());
this.leftSash.addListener('reset', () => this.onLeftSashReset());
this.leftSash.hide();

// Center Container
Expand All @@ -738,6 +739,7 @@ export class SideBySideEditorControl extends EventEmitter implements IVerticalSa
this.rightSash.addListener('start', () => this.onRightSashDragStart());
this.rightSash.addListener('change', (e: ISashEvent) => this.onRightSashDrag(e));
this.rightSash.addListener('end', () => this.onRightSashDragEnd());
this.rightSash.addListener('reset', () => this.onRightSashReset());
this.rightSash.hide();

// Right Container
Expand Down Expand Up @@ -1212,6 +1214,14 @@ export class SideBySideEditorControl extends EventEmitter implements IVerticalSa
this.editorActionsToolbar[position].setActions([], [])();
}

private centerSash(a: Position, b: Position): void {
let sumWidth = this.containerWidth[a] + this.containerWidth[b];
let meanWidth = sumWidth / 2;
this.containerWidth[a] = meanWidth;
this.containerWidth[b] = sumWidth - meanWidth;
this.layoutContainers();
}

private onLeftSashDragStart(): void {
this.startLeftContainerWidth = this.containerWidth[Position.LEFT];
}
Expand Down Expand Up @@ -1301,6 +1311,11 @@ export class SideBySideEditorControl extends EventEmitter implements IVerticalSa
this.focusNextNonMinimized();
}

private onLeftSashReset(): void {
this.centerSash(Position.LEFT, Position.CENTER);
this.leftSash.layout();
}

private onRightSashDragStart(): void {
this.startRightContainerWidth = this.containerWidth[Position.RIGHT];
}
Expand Down Expand Up @@ -1358,6 +1373,11 @@ export class SideBySideEditorControl extends EventEmitter implements IVerticalSa
this.focusNextNonMinimized();
}

private onRightSashReset(): void {
this.centerSash(Position.CENTER, Position.RIGHT);
this.rightSash.layout();
}

public getVerticalSashTop(sash: Sash): number {
return 0;
}
Expand Down
2 changes: 1 addition & 1 deletion src/vs/workbench/browser/parts/sidebar/sidebarPart.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ export class SidebarPart extends CompositePart<Viewlet> implements IViewletServi
}

public getActiveViewlet(): IViewlet {
return this.getActiveComposite();
return <IViewlet>this.getActiveComposite();
}

public getLastActiveViewletId(): string {
Expand Down
6 changes: 5 additions & 1 deletion src/vs/workbench/browser/viewlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,11 @@ import {IContextMenuService} from 'vs/platform/contextview/browser/contextView';
import {IMessageService} from 'vs/platform/message/common/message';
import {StructuredSelection} from 'vs/platform/selection/common/selection';

export abstract class Viewlet extends Composite implements IViewlet { }
export abstract class Viewlet extends Composite implements IViewlet {
public getOptimalWidth(): number {
return null;
}
}

/**
* Helper subtype of viewlet for those that use a tree inside.
Expand Down
7 changes: 6 additions & 1 deletion src/vs/workbench/common/viewlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,4 +5,9 @@

import {IComposite} from 'vs/workbench/common/composite';

export interface IViewlet extends IComposite { }
export interface IViewlet extends IComposite {
/**
* Returns the minimal width needed to avoid any content horizontal truncation
*/
getOptimalWidth(): number;
}
9 changes: 9 additions & 0 deletions src/vs/workbench/parts/files/browser/explorerViewlet.ts
Original file line number Diff line number Diff line change
Expand Up @@ -175,6 +175,15 @@ export class ExplorerViewlet extends Viewlet {
return this.actionRunner;
}

public getOptimalWidth(): number {
let additionalMargin = 16;
let workingFilesViewWidth = this.getWorkingFilesView().getOptimalWidth();
let explorerView = this.getExplorerView();
let explorerViewWidth = explorerView ? explorerView.getOptimalWidth() : 0;
let optimalWidth = Math.max(workingFilesViewWidth, explorerViewWidth);
return optimalWidth + additionalMargin;
}

public shutdown(): void {
this.views.forEach((view) => view.shutdown());

Expand Down
8 changes: 7 additions & 1 deletion src/vs/workbench/parts/files/browser/views/explorerView.ts
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ import {FileEditorInput} from 'vs/workbench/parts/files/browser/editors/fileEdit
import {FileDragAndDrop, FileFilter, FileSorter, FileController, FileRenderer, FileDataSource, FileViewletState, FileAccessibilityProvider} from 'vs/workbench/parts/files/browser/views/explorerViewer';
import lifecycle = require('vs/base/common/lifecycle');
import {IEditor} from 'vs/platform/editor/common/editor';
import DOM = require('vs/base/browser/dom');
import * as DOM from 'vs/base/browser/dom';
import {CollapseAction, CollapsibleViewletView} from 'vs/workbench/browser/viewlet';
import {FileStat} from 'vs/workbench/parts/files/common/explorerViewModel';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
Expand Down Expand Up @@ -348,6 +348,12 @@ export class ExplorerView extends CollapsibleViewletView {
return this.explorerViewer;
}

public getOptimalWidth(): number {
let parentNode = this.explorerViewer.getHTMLElement();
let childNodes = [].slice.call(parentNode.querySelectorAll('.explorer-item-label > a'));
return DOM.getLargestChildWidth(parentNode, childNodes);
}

private onLocalFileChange(e: LocalFileChangeEvent): void {
let modelElement: FileStat;
let parent: FileStat;
Expand Down
Loading

0 comments on commit 239edbf

Please sign in to comment.