提交 b57dffa7 编写于 作者: A Alex Dima

Refactor how the scrollbar gets its dimensions

上级 9cf8943d
......@@ -30,6 +30,7 @@ function code() {
exec ./.build/electron/Electron.app/Contents/MacOS/Electron . "$@"
else
exec ./.build/electron/electron . "$@" --no-sandbox --js-flags="--trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces"
# exec ./.build/electron/electron . "$@" --no-sandbox --js-flags="--trace-opt-verbose --trace-hydrogen --trace-phase=Z --trace-deopt --code-comments --hydrogen-track-positions --redirect-code-traces"
fi
}
......
......@@ -3,7 +3,7 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IScrollable } from 'vs/base/common/scrollable';
import { IScrollable, ScrollEvent } from 'vs/base/common/scrollable';
import { Emitter } from 'vs/base/common/event';
import { toObject, assign } from 'vs/base/common/objects';
import { IDisposable, disposeAll } from 'vs/base/common/lifecycle';
......@@ -16,11 +16,6 @@ import { IDelegate, IRenderer } from './list';
import { RowCache, IRow } from './rowCache';
import { LcsDiff, ISequence } from 'vs/base/common/diff/diff';
interface IScrollEvent {
vertical: boolean;
horizontal: boolean;
}
interface IItemRange<T> {
item: IItem<T>;
index: number;
......@@ -68,7 +63,7 @@ export class ListView<T> implements IScrollable, IDisposable {
private rowsContainer: HTMLElement;
private scrollableElement: IScrollableElement;
private _onScroll = new Emitter<IScrollEvent>();
private _onScroll = new Emitter<ScrollEvent>();
private toDispose: IDisposable[];
......@@ -94,9 +89,8 @@ export class ListView<T> implements IScrollable, IDisposable {
this.rowsContainer.className = 'monaco-list-rows';
this.gesture = new Gesture(this.rowsContainer);
this.scrollableElement = new ScrollableElement(this.rowsContainer, {
this.scrollableElement = new ScrollableElement(this.rowsContainer, this, {
forbidTranslate3dUse: true,
scrollable: this,
horizontal: 'hidden',
vertical: 'auto',
useShadows: false,
......@@ -144,7 +138,7 @@ export class ListView<T> implements IScrollable, IDisposable {
this.rowsContainer.style.height = `${ this.rangeMap.size }px`;
this.setScrollTop(this.renderTop);
this.scrollableElement.onElementInternalDimensions();
this._emitScrollEvent(false, false);
return deleted.map(i => i.element);
}
......@@ -181,7 +175,7 @@ export class ListView<T> implements IScrollable, IDisposable {
this.setRenderHeight(height || DOM.getContentHeight(this._domNode));
this.setScrollTop(this.renderTop);
this.scrollableElement.onElementDimensions();
this.scrollableElement.onElementInternalDimensions();
this._emitScrollEvent(false, false);
}
// Render
......@@ -292,10 +286,21 @@ export class ListView<T> implements IScrollable, IDisposable {
this.render(scrollTop, this._renderHeight);
this.renderTop = scrollTop;
this._onScroll.fire({ vertical: true, horizontal: false });
this._emitScrollEvent(true, false);
}
private _emitScrollEvent(vertical:boolean, horizontal:boolean): void {
this._onScroll.fire(new ScrollEvent(
this.getScrollTop(),
this.getScrollLeft(),
this.getScrollWidth(),
this.getScrollHeight(),
vertical,
horizontal
));
}
addScrollListener(callback: ()=>void): IDisposable {
addScrollListener(callback: (v:ScrollEvent)=>void): IDisposable {
return this._onScroll.event(callback);
}
......
......@@ -12,7 +12,7 @@ import URI from 'vs/base/common/uri';
import paths = require('vs/base/common/paths');
import {Builder, $} from 'vs/base/browser/builder';
import DOM = require('vs/base/browser/dom');
import {IScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElement';
import {DomNodeScrollable} from 'vs/base/browser/ui/scrollbar/domNodeScrollable';
// Known media mimes that we can handle
const mapExtToMediaMimes = {
......@@ -69,7 +69,7 @@ const mapExtToMediaMimes = {
*/
export class ResourceViewer {
public static show(name: string, resource: URI, container: Builder, scrollbar?: IScrollableElement): void {
public static show(name: string, resource: URI, container: Builder, scrollable?: DomNodeScrollable): void {
// Ensure CSS class
$(container).addClass('monaco-resource-viewer');
......@@ -93,8 +93,8 @@ export class ResourceViewer {
.img({
src: resource.toString() + '?' + new Date().getTime() // We really want to avoid the browser from caching this resource, so we add a fake query param that is unique
}).on(DOM.EventType.LOAD, () => {
if (scrollbar) {
scrollbar.onElementInternalDimensions();
if (scrollable) {
scrollable.onContentsDimensions();
}
});
}
......@@ -124,8 +124,8 @@ export class ResourceViewer {
text: nls.localize('missingAudioSupport', "Sorry but playback of audio files is not supported."),
controls: 'controls'
}).on(DOM.EventType.LOAD, () => {
if (scrollbar) {
scrollbar.onElementInternalDimensions();
if (scrollable) {
scrollable.onContentsDimensions();
}
});
}
......@@ -141,8 +141,8 @@ export class ResourceViewer {
text: nls.localize('missingVideoSupport', "Sorry but playback of video files is not supported."),
controls: 'controls'
}).on(DOM.EventType.LOAD, () => {
if (scrollbar) {
scrollbar.onElementInternalDimensions();
if (scrollable) {
scrollable.onContentsDimensions();
}
});
}
......@@ -156,8 +156,8 @@ export class ResourceViewer {
text: nls.localize('nativeBinaryError', "The file cannot be displayed in the editor because it is either binary, very large or uses an unsupported text encoding.")
});
if (scrollbar) {
scrollbar.onElementInternalDimensions();
if (scrollable) {
scrollable.onContentsDimensions();
}
}
}
......
......@@ -83,7 +83,7 @@ export class ScrollbarState {
this._computedAvailableSize = 0;
this._computedRepresentableSize = 0;
this._computedRatio = 0;
this._computedRatio = 0.1;
this._computedIsNeeded = false;
this._computedSliderSize = 0;
this._computedSliderPosition = 0;
......@@ -92,9 +92,9 @@ export class ScrollbarState {
}
public setVisibleSize(visibleSize: number): boolean {
visibleSize = Math.round(visibleSize);
if (this._visibleSize !== visibleSize) {
this._visibleSize = visibleSize;
let iVisibleSize = Math.round(visibleSize);
if (this._visibleSize !== iVisibleSize) {
this._visibleSize = iVisibleSize;
this._refreshComputedValues();
return true;
}
......@@ -102,9 +102,9 @@ export class ScrollbarState {
}
public setScrollSize(scrollSize: number): boolean {
scrollSize = Math.round(scrollSize);
if (this._scrollSize !== scrollSize) {
this._scrollSize = scrollSize;
let iScrollSize = Math.round(scrollSize);
if (this._scrollSize !== iScrollSize) {
this._scrollSize = iScrollSize;
this._refreshComputedValues();
return true;
}
......@@ -112,9 +112,9 @@ export class ScrollbarState {
}
public setScrollPosition(scrollPosition: number): boolean {
scrollPosition = Math.round(scrollPosition);
if (this._scrollPosition !== scrollPosition) {
this._scrollPosition = scrollPosition;
let iScrollPosition = Math.round(scrollPosition);
if (this._scrollPosition !== iScrollPosition) {
this._scrollPosition = iScrollPosition;
this._refreshComputedValues();
return true;
}
......@@ -122,39 +122,55 @@ export class ScrollbarState {
}
private _refreshComputedValues(): void {
this._computedAvailableSize = Math.max(0, this._visibleSize - this._oppositeScrollbarSize);
this._computedRepresentableSize = Math.max(0, this._computedAvailableSize - 2 * this._arrowSize);
this._computedRatio = this._scrollSize > 0 ? (this._computedRepresentableSize / this._scrollSize) : 0;
this._computedIsNeeded = (this._scrollSize > this._visibleSize);
if (!this._computedIsNeeded) {
this._computedSliderSize = this._computedRepresentableSize;
this._computedSliderPosition = 0;
const oppositeScrollbarSize = this._oppositeScrollbarSize;
const arrowSize = this._arrowSize;
const visibleSize = this._visibleSize;
const scrollSize = this._scrollSize;
const scrollPosition = this._scrollPosition;
let computedAvailableSize = Math.max(0, visibleSize - oppositeScrollbarSize);
let computedRepresentableSize = Math.max(0, computedAvailableSize - 2 * arrowSize);
let computedRatio = scrollSize > 0 ? (computedRepresentableSize / scrollSize) : 0;
let computedIsNeeded = (scrollSize > visibleSize);
let computedSliderSize: number;
let computedSliderPosition: number;
if (!computedIsNeeded) {
computedSliderSize = computedRepresentableSize;
computedSliderPosition = 0;
} else {
this._computedSliderSize = Math.floor(this._visibleSize * this._computedRatio);
this._computedSliderPosition = Math.floor(this._scrollPosition * this._computedRatio);
computedSliderSize = Math.floor(visibleSize * computedRatio);
computedSliderPosition = Math.floor(scrollPosition * computedRatio);
if (this._computedSliderSize < MINIMUM_SLIDER_SIZE) {
if (computedSliderSize < MINIMUM_SLIDER_SIZE) {
// We must artificially increase the size of the slider, since the slider would be too small otherwise
// The effort is to keep the slider centered around the original position, but we must take into
// account the cases when the slider is too close to the top or too close to the bottom
let sliderArtificialOffset = (MINIMUM_SLIDER_SIZE - this._computedSliderSize) / 2;
this._computedSliderSize = MINIMUM_SLIDER_SIZE;
let sliderArtificialOffset = (MINIMUM_SLIDER_SIZE - computedSliderSize) / 2;
computedSliderSize = MINIMUM_SLIDER_SIZE;
this._computedSliderPosition -= sliderArtificialOffset;
computedSliderPosition -= sliderArtificialOffset;
if (this._computedSliderPosition + this._computedSliderSize > this._computedRepresentableSize) {
if (computedSliderPosition + computedSliderSize > computedRepresentableSize) {
// Slider is too close to the bottom, so we glue it to the bottom
this._computedSliderPosition = this._computedRepresentableSize - this._computedSliderSize;
computedSliderPosition = computedRepresentableSize - computedSliderSize;
}
if (this._computedSliderPosition < 0) {
if (computedSliderPosition < 0) {
// Slider is too close to the top, so we glue it to the top
this._computedSliderPosition = 0;
computedSliderPosition = 0;
}
}
}
this._computedAvailableSize = Math.round(computedAvailableSize);
this._computedRepresentableSize = Math.round(computedRepresentableSize);
this._computedRatio = computedRatio;
this._computedIsNeeded = computedIsNeeded;
this._computedSliderSize = Math.round(computedSliderSize);
this._computedSliderPosition = Math.round(computedSliderPosition);
}
public getArrowSize(): number {
......
......@@ -7,20 +7,50 @@
import * as DomUtils from 'vs/base/browser/dom';
import {Gesture} from 'vs/base/browser/touch';
import {Disposable, IDisposable} from 'vs/base/common/lifecycle';
import {IScrollable} from 'vs/base/common/scrollable';
import {IScrollable, ScrollEvent} from 'vs/base/common/scrollable';
import {Emitter} from 'vs/base/common/event';
export class DomNodeScrollable extends Disposable implements IScrollable {
private _domNode: HTMLElement;
private _gestureHandler: Gesture;
private _onScroll = this._register(new Emitter<void>());
private _onScroll = this._register(new Emitter<ScrollEvent>());
private _lastScrollTop:number;
private _lastScrollLeft:number;
constructor(domNode: HTMLElement) {
super();
this._domNode = domNode;
this._gestureHandler = this._register(new Gesture(this._domNode));
this._register(DomUtils.addDisposableListener(this._domNode, 'scroll', (e) => this._onScroll.fire(void 0)));
this._lastScrollTop = this.getScrollTop();
this._lastScrollLeft = this.getScrollLeft();
this._register(DomUtils.addDisposableListener(this._domNode, 'scroll', (e) => {
this._emitScrollEvent();
}));
}
public onContentsDimensions(): void {
this._emitScrollEvent();
}
private _emitScrollEvent(): void {
let vertical = (this._lastScrollTop !== this.getScrollTop());
this._lastScrollTop = this.getScrollTop();
let horizontal = (this._lastScrollLeft !== this.getScrollLeft());
this._lastScrollLeft = this.getScrollLeft();
this._onScroll.fire(new ScrollEvent(
this.getScrollTop(),
this.getScrollLeft(),
this.getScrollWidth(),
this.getScrollHeight(),
vertical,
horizontal
));
}
public dispose() {
......@@ -52,7 +82,7 @@ export class DomNodeScrollable extends Disposable implements IScrollable {
this._domNode.scrollTop = scrollTop;
}
public addScrollListener(callback: () => void): IDisposable {
public addScrollListener(callback: (v:ScrollEvent) => void): IDisposable {
return this._onScroll.event(callback);
}
}
......@@ -9,13 +9,13 @@ import {ARROW_IMG_SIZE, AbstractScrollbar, ScrollbarState, IMouseMoveEventData}
import {IMouseEvent, StandardMouseWheelEvent} from 'vs/base/browser/mouseEvent';
import {IDomNodePosition} from 'vs/base/browser/dom';
import {IParent, IScrollableElementOptions, Visibility} from 'vs/base/browser/ui/scrollbar/scrollableElement';
import {IScrollable} from 'vs/base/common/scrollable';
import {DelegateScrollable} from 'vs/base/common/scrollable';
export class HorizontalScrollbar extends AbstractScrollbar {
private _scrollable: IScrollable;
private _scrollable: DelegateScrollable;
constructor(scrollable: IScrollable, parent: IParent, options: IScrollableElementOptions) {
constructor(scrollable: DelegateScrollable, parent: IParent, options: IScrollableElementOptions) {
let s = new ScrollbarState(
(options.horizontalHasArrows ? options.arrowSize : 0),
(options.horizontal === Visibility.Hidden ? 0 : options.horizontalScrollbarSize),
......
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {IScrollable} from 'vs/base/common/scrollable';
import {FastDomNode} from 'vs/base/browser/styleMutator';
export interface IScrollableElementCreationOptions {
......@@ -48,12 +47,6 @@ export interface IScrollableElementCreationOptions {
*/
arrowSize?: number;
/**
* The scrollable that will react to all the scrolling logic.
* If no scrollable is provided, a dom node scrollable will be created automatically.
*/
scrollable?: IScrollable;
/**
* The dom node events should be bound to.
* If no listenOnDomNode is provided, the dom node passed to the constructor will be used for event listening.
......@@ -145,11 +138,6 @@ export interface IScrollableElement {
*/
onElementDimensions(dimensions?: IDimensions): void;
/**
* Let the scrollable element know that the contained dom node's width / height might have changed.
*/
onElementInternalDimensions(): void;
/**
* Dispose.
*/
......@@ -230,7 +218,6 @@ export interface IScrollableElementOptions {
flipAxes: boolean;
mouseWheelScrollSensitivity: number;
arrowSize: number;
scrollable: IScrollable;
listenOnDomNode: HTMLElement;
horizontal: Visibility;
horizontalScrollbarSize: number;
......
......@@ -9,7 +9,6 @@ import 'vs/css!./media/scrollbars';
import * as DomUtils from 'vs/base/browser/dom';
import * as Platform from 'vs/base/common/platform';
import {StandardMouseWheelEvent, IMouseEvent} from 'vs/base/browser/mouseEvent';
import {DomNodeScrollable} from 'vs/base/browser/ui/scrollbar/domNodeScrollable';
import {HorizontalScrollbar} from 'vs/base/browser/ui/scrollbar/horizontalScrollbar';
import {VerticalScrollbar} from 'vs/base/browser/ui/scrollbar/verticalScrollbar';
import {
......@@ -17,7 +16,7 @@ import {
IScrollableElement, IScrollableElementCreationOptions, IOverviewRulerLayoutInfo
} from 'vs/base/browser/ui/scrollbar/scrollableElement';
import {IDisposable, disposeAll} from 'vs/base/common/lifecycle';
import {IScrollable} from 'vs/base/common/scrollable';
import {IScrollable, DelegateScrollable} from 'vs/base/common/scrollable';
import {Widget} from 'vs/base/browser/ui/widget';
import {TimeoutTimer} from 'vs/base/common/async';
......@@ -28,7 +27,7 @@ export class ScrollableElement extends Widget implements IScrollableElement {
private _originalElement: HTMLElement;
private _options: IScrollableElementOptions;
private _scrollable: IScrollable;
private _scrollable: DelegateScrollable;
public verticalScrollbarWidth: number;
public horizontalScrollbarHeight: number;
private _verticalScrollbar: IScrollbar;
......@@ -43,24 +42,19 @@ export class ScrollableElement extends Widget implements IScrollableElement {
private _mouseWheelToDispose: IDisposable[];
private _onElementDimensionsTimeout: TimeoutTimer;
private _onElementInternalDimensionsTimeout: TimeoutTimer;
private _isDragging: boolean;
private _mouseIsOver: boolean;
private _dimensions: IDimensions;
private _hideTimeout: TimeoutTimer;
constructor(element: HTMLElement, options: IScrollableElementCreationOptions, dimensions: IDimensions = null) {
constructor(element: HTMLElement, scrollable:IScrollable, options: IScrollableElementCreationOptions, dimensions: IDimensions = null) {
super();
this._originalElement = element;
this._originalElement.style.overflow = 'hidden';
this._options = this._createOptions(options);
if (this._options.scrollable) {
this._scrollable = this._options.scrollable;
} else {
this._scrollable = this._register(new DomNodeScrollable(this._originalElement));
}
this._scrollable = this._register(new DelegateScrollable(scrollable, () => this._onScroll()));
this.verticalScrollbarWidth = this._options.verticalScrollbarSize;
this.horizontalScrollbarHeight = this._options.horizontalScrollbarSize;
......@@ -95,9 +89,6 @@ export class ScrollableElement extends Widget implements IScrollableElement {
this._listenOnDomNode = this._options.listenOnDomNode || this._domNode;
this._register(this._scrollable.addScrollListener(() => this._onScroll()));
this._mouseWheelToDispose = [];
this._setListeningToMouseWheel(this._options.handleMouseWheel);
......@@ -105,13 +96,13 @@ export class ScrollableElement extends Widget implements IScrollableElement {
this.onnonbubblingmouseout(this._listenOnDomNode, (e) => this._onMouseOut(e));
this._onElementDimensionsTimeout = this._register(new TimeoutTimer());
this._onElementInternalDimensionsTimeout = this._register(new TimeoutTimer());
this._hideTimeout = this._register(new TimeoutTimer());
this._isDragging = false;
this._mouseIsOver = false;
this.onElementDimensions(dimensions, true);
this.onElementInternalDimensions(true);
this._horizontalScrollbar.onElementScrollSize(this._scrollable.getScrollWidth());
this._verticalScrollbar.onElementScrollSize(this._scrollable.getScrollHeight());
}
public dispose(): void {
......@@ -155,20 +146,6 @@ export class ScrollableElement extends Widget implements IScrollableElement {
this._horizontalScrollbar.onElementSize(this._dimensions.width);
}
public onElementInternalDimensions(synchronous: boolean = false): void {
if (synchronous) {
this._actualElementInternalDimensions();
this._onElementInternalDimensionsTimeout.cancel();
} else {
this._onElementInternalDimensionsTimeout.setIfNotSet(() => this._actualElementInternalDimensions(), 0);
}
}
private _actualElementInternalDimensions(): void {
this._horizontalScrollbar.onElementScrollSize(this._scrollable.getScrollWidth());
this._verticalScrollbar.onElementScrollSize(this._scrollable.getScrollHeight());
}
public updateClassName(newClassName: string): void {
this._options.className = newClassName;
// Defaults are different on Macs
......@@ -282,6 +259,8 @@ export class ScrollableElement extends Widget implements IScrollableElement {
let scrollWidth = this._scrollable.getScrollWidth();
let scrollLeft = this._scrollable.getScrollLeft();
this._horizontalScrollbar.onElementScrollSize(scrollWidth);
this._verticalScrollbar.onElementScrollSize(scrollHeight);
this._verticalScrollbar.onElementScrollPosition(scrollTop);
this._horizontalScrollbar.onElementScrollPosition(scrollLeft);
......@@ -378,7 +357,6 @@ export class ScrollableElement extends Widget implements IScrollableElement {
mouseWheelScrollSensitivity: ensureValue(options, 'mouseWheelScrollSensitivity', 1),
arrowSize: ensureValue(options, 'arrowSize', 11),
scrollable: ensureValue<IScrollable>(options, 'scrollable', null),
listenOnDomNode: ensureValue<HTMLElement>(options, 'listenOnDomNode', null),
horizontal: visibilityFromString(ensureValue(options, 'horizontal', 'auto')),
......
......@@ -9,13 +9,13 @@ import {ARROW_IMG_SIZE, AbstractScrollbar, ScrollbarState, IMouseMoveEventData}
import {IMouseEvent, StandardMouseWheelEvent} from 'vs/base/browser/mouseEvent';
import {IDomNodePosition} from 'vs/base/browser/dom';
import {IParent, IScrollableElementOptions, Visibility} from 'vs/base/browser/ui/scrollbar/scrollableElement';
import {IScrollable} from 'vs/base/common/scrollable';
import {DelegateScrollable} from 'vs/base/common/scrollable';
export class VerticalScrollbar extends AbstractScrollbar {
private _scrollable: IScrollable;
private _scrollable: DelegateScrollable;
constructor(scrollable: IScrollable, parent: IParent, options: IScrollableElementOptions) {
constructor(scrollable: DelegateScrollable, parent: IParent, options: IScrollableElementOptions) {
let s = new ScrollbarState(
(options.verticalHasArrows ? options.arrowSize : 0),
(options.vertical === Visibility.Hidden ? 0 : options.verticalScrollbarSize),
......
......@@ -4,7 +4,7 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import {IDisposable} from 'vs/base/common/lifecycle';
import {Disposable, IDisposable} from 'vs/base/common/lifecycle';
export interface IScrollable {
getScrollHeight():number;
......@@ -13,5 +13,94 @@ export interface IScrollable {
setScrollLeft(scrollLeft:number);
getScrollTop():number;
setScrollTop(scrollTop:number);
addScrollListener(callback:()=>void): IDisposable;
addScrollListener(callback:(newValues:ScrollEvent)=>void): IDisposable;
}
export class ScrollEvent {
_scrollEventTrait: void;
scrollTop: number;
scrollLeft: number;
scrollWidth: number;
scrollHeight: number;
vertical: boolean;
horizontal: boolean;
constructor(scrollTop:number, scrollLeft:number, scrollWidth:number, scrollHeight:number, vertical:boolean, horizontal:boolean) {
this.scrollTop = Math.round(scrollTop);
this.scrollLeft = Math.round(scrollLeft);
this.scrollWidth = Math.round(scrollWidth);
this.scrollHeight = Math.round(scrollHeight);
this.vertical = Boolean(vertical);
this.horizontal = Boolean(horizontal);
}
}
export class ScrollableValues {
_scrollableValuesTrait: void;
scrollTop: number;
scrollLeft: number;
scrollWidth: number;
scrollHeight: number;
constructor(scrollTop:number, scrollLeft:number, scrollWidth:number, scrollHeight:number) {
this.scrollTop = Math.round(scrollTop);
this.scrollLeft = Math.round(scrollLeft);
this.scrollWidth = Math.round(scrollWidth);
this.scrollHeight = Math.round(scrollHeight);
}
public equals(other:ScrollEvent): boolean {
return (
this.scrollTop === other.scrollTop
&& this.scrollLeft === other.scrollLeft
&& this.scrollWidth === other.scrollWidth
&& this.scrollHeight === other.scrollHeight
);
}
}
export class DelegateScrollable extends Disposable {
private _actual:IScrollable;
private _onChange:()=>void;
private _values: ScrollableValues;
constructor(actual:IScrollable, onChange:()=>void) {
super();
this._actual = actual;
this._onChange = onChange;
this._values = new ScrollableValues(this._actual.getScrollTop(), this._actual.getScrollLeft(), this._actual.getScrollWidth(), this._actual.getScrollHeight());
this._register(this._actual.addScrollListener((newValues) => this._update(newValues)));
}
public dispose(): void {
super.dispose();
}
private _update(e:ScrollEvent): void {
if (this._values.equals(e)) {
return;
}
this._values = new ScrollableValues(e.scrollTop, e.scrollLeft, e.scrollWidth, e.scrollHeight);
this._onChange();
}
public getScrollTop():number { return this._values.scrollTop; }
public getScrollLeft():number { return this._values.scrollLeft; }
public getScrollWidth():number { return this._values.scrollWidth; }
public getScrollHeight():number { return this._values.scrollHeight; }
public setScrollTop(scrollTop:number): void {
this._actual.setScrollTop(scrollTop);
}
public setScrollLeft(scrollLeft:number): void {
this._actual.setScrollLeft(scrollLeft);
}
}
......@@ -21,7 +21,7 @@ import ScrollableElementImpl = require('vs/base/browser/ui/scrollbar/scrollableE
import { HeightMap } from 'vs/base/parts/tree/browser/treeViewModel';
import _ = require('vs/base/parts/tree/browser/tree');
import { IViewItem } from 'vs/base/parts/tree/browser/treeViewModel';
import {IScrollable} from 'vs/base/common/scrollable';
import {IScrollable, ScrollEvent} from 'vs/base/common/scrollable';
import {KeyCode} from 'vs/base/common/keyCodes';
export interface IRow {
......@@ -489,9 +489,8 @@ export class TreeView extends HeightMap implements IScrollable {
this.wrapper = document.createElement('div');
this.wrapper.className = 'monaco-tree-wrapper';
this.scrollableElement = new ScrollableElementImpl.ScrollableElement(this.wrapper, {
this.scrollableElement = new ScrollableElementImpl.ScrollableElement(this.wrapper, this, {
forbidTranslate3dUse: true,
scrollable: this,
horizontal: 'hidden',
vertical: context.options.verticalScrollMode || 'auto',
useShadows: context.options.useShadows,
......@@ -597,7 +596,7 @@ export class TreeView extends HeightMap implements IScrollable {
this.scrollTop = this.onHiddenScrollTop;
this.onHiddenScrollTop = null;
this.scrollableElement.onElementDimensions();
this.scrollableElement.onElementInternalDimensions();
this._emitScrollEvent(false, false);
this.setupMSGesture();
}
......@@ -625,7 +624,7 @@ export class TreeView extends HeightMap implements IScrollable {
this.scrollTop = this.scrollTop; // render
this.scrollableElement.onElementDimensions();
this.scrollableElement.onElementInternalDimensions();
this._emitScrollEvent(false, false);
}
private render(scrollTop: number, viewHeight: number): void {
......@@ -750,7 +749,7 @@ export class TreeView extends HeightMap implements IScrollable {
}
this.scrollTop = scrollTop;
this.scrollableElement.onElementInternalDimensions();
this._emitScrollEvent(false, false);
}
public focusNextPage(eventPayload?:any): void {
......@@ -849,10 +848,21 @@ export class TreeView extends HeightMap implements IScrollable {
this.render(scrollTop, this.viewHeight);
this._scrollTop = scrollTop;
this.emit('scroll', { vertical: true, horizontal: false });
this._emitScrollEvent(true, false);
}
public addScrollListener(callback:()=>void): Lifecycle.IDisposable {
private _emitScrollEvent(vertical:boolean, horizontal:boolean): void {
this.emit('scroll', new ScrollEvent(
this.getScrollTop(),
this.getScrollLeft(),
this.getScrollWidth(),
this.getScrollHeight(),
vertical,
horizontal
));
}
public addScrollListener(callback:(v:ScrollEvent)=>void): Lifecycle.IDisposable {
return this.addListener2('scroll', callback);
}
......
......@@ -4,7 +4,6 @@
*--------------------------------------------------------------------------------------------*/
'use strict';
import * as dom from 'vs/base/browser/dom';
import * as editorCommon from 'vs/editor/common/editorCommon';
import {IViewContext} from 'vs/editor/browser/editorBrowser';
import {ViewPart} from 'vs/editor/browser/view/viewPart';
......@@ -47,6 +46,8 @@ export class ViewLayer extends ViewPart {
_rendLineNumberStart:number;
private _renderer: ViewLayerRenderer;
private _scrollDomNode: HTMLElement;
private _scrollDomNodeIsAbove: boolean;
constructor(context:IViewContext) {
super(context);
......@@ -56,6 +57,9 @@ export class ViewLayer extends ViewPart {
this._lines = [];
this._rendLineNumberStart = 1;
this._scrollDomNode = null;
this._scrollDomNodeIsAbove = false;
this._renderer = new ViewLayerRenderer(
() => this._createLine(),
() => this._extraDomNodeHTML()
......@@ -95,7 +99,8 @@ export class ViewLayer extends ViewPart {
public onModelFlushed(): boolean {
this._lines = [];
this._rendLineNumberStart = 1;
dom.clearNode(this.domNode);
this._scrollDomNode = null;
// No need to clear the dom node because a full .innerHTML will occur in ViewLayerRenderer._render
return true;
}
......@@ -233,8 +238,6 @@ export class ViewLayer extends ViewPart {
// ---- end view event handlers
private _scrollDomNode: HTMLElement = null;
private _scrollDomNodeIsAbove: boolean = false;
public _renderLines(linesViewportData:editorCommon.IViewLinesViewportData): void {
var ctx: IRendererContext = {
......
......@@ -42,7 +42,6 @@ export class ScrollManager implements IDisposable {
var configScrollbarOpts = this.configuration.editor.scrollbar;
var scrollbarOptions:IScrollableElementCreationOptions = {
scrollable: this.scrollable,
listenOnDomNode: viewDomNode,
vertical: configScrollbarOpts.vertical,
horizontal: configScrollbarOpts.horizontal,
......@@ -61,15 +60,12 @@ export class ScrollManager implements IDisposable {
addPropertyIfPresent(configScrollbarOpts, scrollbarOptions, 'mouseWheelScrollSensitivity');
this.scrollbar = new ScrollableElement(linesContent, scrollbarOptions, {
this.scrollbar = new ScrollableElement(linesContent, this.scrollable, scrollbarOptions, {
width: this.configuration.editor.layoutInfo.contentWidth,
height: this.configuration.editor.layoutInfo.contentHeight,
});
this.toDispose.push(this.scrollbar);
this.toDispose.push(this.scrollable.addInternalSizeChangeListener(() => {
this.scrollbar.onElementInternalDimensions();
}));
this.toDispose.push(this.configuration.onDidChange((e:IConfigurationChangedEvent) => {
this.scrollbar.updateClassName(this.configuration.editor.theme);
if (e.scrollbar) {
......
......@@ -85,6 +85,9 @@ export class ViewLines extends ViewLayer {
private _lastCursorRevealRangeHorizontallyEvent:editorCommon.IViewRevealRangeEvent;
private _lastRenderedData: LastRenderedData;
private _hasVerticalScroll:boolean;
private _hasHorizontalScroll:boolean;
constructor(context:IViewContext, layoutProvider:ILayoutProvider) {
super(context);
this._lineHeight = this._context.configuration.editor.lineHeight;
......@@ -139,6 +142,7 @@ export class ViewLines extends ViewLayer {
public onLayoutChanged(layoutInfo:editorCommon.IEditorLayoutInfo): boolean {
var shouldRender = super.onLayoutChanged(layoutInfo);
this._maxLineWidth = 0;
this._lastRenderedData.resetDomNodeClientRectLeft();
return shouldRender;
}
......@@ -180,8 +184,6 @@ export class ViewLines extends ViewLayer {
return true;
}
private _hasVerticalScroll = false;
private _hasHorizontalScroll = false;
public onScrollChanged(e:editorCommon.IScrollEvent): boolean {
this._hasVerticalScroll = this._hasVerticalScroll || e.vertical;
this._hasHorizontalScroll = this._hasHorizontalScroll || e.horizontal;
......@@ -366,8 +368,6 @@ export class ViewLines extends ViewLayer {
this._context.model.getLineMaxColumn(this._lines.length - 1 + this._rendLineNumberStart)
));
this._lastRenderedData.resetDomNodeClientRectLeft();
if (this._lastCursorRevealRangeHorizontallyEvent) {
var newScrollLeft = this._computeScrollLeftToRevealRange(this._lastCursorRevealRangeHorizontallyEvent.range);
this._lastCursorRevealRangeHorizontallyEvent = null;
......@@ -436,8 +436,9 @@ export class ViewLines extends ViewLayer {
// --- width
private _ensureMaxLineWidth(lineWidth: number): void {
if (this._maxLineWidth < lineWidth) {
this._maxLineWidth = lineWidth;
let iLineWidth = Math.ceil(lineWidth);
if (this._maxLineWidth < iLineWidth) {
this._maxLineWidth = iLineWidth;
this._layoutProvider.onMaxLineWidthChanged(this._maxLineWidth);
}
}
......
......@@ -6,7 +6,7 @@
import {EventEmitter} from 'vs/base/common/eventEmitter';
import {IDisposable} from 'vs/base/common/lifecycle';
import {IScrollable} from 'vs/base/common/scrollable';
import {IScrollable, ScrollEvent} from 'vs/base/common/scrollable';
import {IScrollEvent} from 'vs/editor/common/editorCommon';
export class EditorScrollable extends EventEmitter implements IScrollable {
......@@ -20,8 +20,7 @@ export class EditorScrollable extends EventEmitter implements IScrollable {
constructor() {
super([
EditorScrollable._SCROLL_EVENT,
EditorScrollable._INTERNAL_SIZE_CHANGED_EVENT
EditorScrollable._SCROLL_EVENT
]);
this.scrollTop = 0;
......@@ -75,7 +74,7 @@ export class EditorScrollable extends EventEmitter implements IScrollable {
// Revalidate
this.setScrollLeft(this.scrollLeft);
this._emitInternalSizeEvent();
this._emitScrollEvent(false, false);
}
}
......@@ -140,7 +139,7 @@ export class EditorScrollable extends EventEmitter implements IScrollable {
// Revalidate
this.setScrollTop(this.scrollTop);
this._emitInternalSizeEvent();
this._emitScrollEvent(false, false);
}
}
......@@ -170,24 +169,17 @@ export class EditorScrollable extends EventEmitter implements IScrollable {
static _SCROLL_EVENT = 'scroll';
private _emitScrollEvent(vertical:boolean, horizontal:boolean): void {
var e:IScrollEvent = {
vertical: vertical,
horizontal: horizontal,
scrollTop: this.scrollTop,
scrollLeft: this.scrollLeft
};
var e:IScrollEvent = new ScrollEvent(
this.getScrollTop(),
this.getScrollLeft(),
this.getScrollWidth(),
this.getScrollHeight(),
vertical,
horizontal
);
this.emit(EditorScrollable._SCROLL_EVENT, e);
}
public addScrollListener(listener: (e:IScrollEvent) => void): IDisposable {
public addScrollListener(listener: (e:ScrollEvent) => void): IDisposable {
return this.addListener2(EditorScrollable._SCROLL_EVENT, listener);
}
static _INTERNAL_SIZE_CHANGED_EVENT = 'internalSizeChanged';
private _emitInternalSizeEvent(): void {
this.emit(EditorScrollable._INTERNAL_SIZE_CHANGED_EVENT);
}
public addInternalSizeChangeListener(listener:()=>void): IDisposable {
return this.addListener2(EditorScrollable._INTERNAL_SIZE_CHANGED_EVENT, listener);
}
}
\ No newline at end of file
}
......@@ -27,6 +27,7 @@ import {CONTEXT_SUGGESTION_SUPPORTS_ACCEPT_ON_KEY, SuggestRegistry} from '../com
import {CompletionItem, CompletionModel} from './completionModel';
import {ICancelEvent, ISuggestEvent, ITriggerEvent, SuggestModel} from './suggestModel';
import {alert} from 'vs/base/browser/ui/aria/aria';
import {DomNodeScrollable} from 'vs/base/browser/ui/scrollbar/domNodeScrollable';
interface ISuggestionTemplateData {
root: HTMLElement;
......@@ -180,7 +181,8 @@ class SuggestionDetails {
private el: HTMLElement;
private title: HTMLElement;
private back: HTMLElement;
private scrollable: ScrollableElement;
private scrollable: DomNodeScrollable;
private scrollbar: ScrollableElement;
private body: HTMLElement;
private type: HTMLElement;
private docs: HTMLElement;
......@@ -193,8 +195,9 @@ class SuggestionDetails {
this.back = append(header, $('span.go-back.octicon.octicon-mail-reply'));
this.back.title = nls.localize('goback', "Go back");
this.body = $('.body');
this.scrollable = new ScrollableElement(this.body, {});
append(this.el, this.scrollable.getDomNode());
this.scrollable = new DomNodeScrollable(this.body);
this.scrollbar = new ScrollableElement(this.body, this.scrollable, {});
append(this.el, this.scrollbar.getDomNode());
this.type = append(this.body, $('p.type'));
this.docs = append(this.body, $('p.docs'));
......@@ -227,8 +230,8 @@ class SuggestionDetails {
this.widget.toggleDetails();
};
this.scrollable.onElementDimensions();
this.scrollable.onElementInternalDimensions();
this.scrollbar.onElementDimensions();
this.scrollable.onContentsDimensions();
this.ariaLabel = strings.format('{0}\n{1}\n{2}', item.suggestion.label || '', item.suggestion.typeLabel || '', item.suggestion.documentationLabel || '');
}
......@@ -254,6 +257,9 @@ class SuggestionDetails {
}
dispose(): void {
this.scrollbar.dispose();
this.scrollable.dispose();
this.el.parentElement.removeChild(this.el);
this.el = null;
}
......
......@@ -20,6 +20,7 @@ import {BinaryEditorModel} from 'vs/workbench/common/editor/binaryEditorModel';
import {DiffEditorModel} from 'vs/workbench/common/editor/diffEditorModel';
import {IWorkbenchEditorService} from 'vs/workbench/services/editor/common/editorService';
import {ITelemetryService} from 'vs/platform/telemetry/common/telemetry';
import {DomNodeScrollable} from 'vs/base/browser/ui/scrollbar/domNodeScrollable';
/**
* An implementation of editor for diffing binary files like images or videos.
......@@ -31,8 +32,10 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
private static MIN_CONTAINER_WIDTH = 100;
private leftBinaryContainer: Builder;
private leftScrollable: DomNodeScrollable;
private leftScrollbar: IScrollableElement;
private rightBinaryContainer: Builder;
private rightScrollable: DomNodeScrollable;
private rightScrollbar: IScrollableElement;
private sash: Sash;
private dimension: Dimension;
......@@ -59,7 +62,8 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
this.leftBinaryContainer.tabindex(0); // enable focus support from the editor part (do not remove)
// Left Custom Scrollbars
this.leftScrollbar = new ScrollableElement(leftBinaryContainerElement, { horizontal: 'hidden', vertical: 'hidden' });
this.leftScrollable = new DomNodeScrollable(leftBinaryContainerElement);
this.leftScrollbar = new ScrollableElement(leftBinaryContainerElement, this.leftScrollable, { horizontal: 'hidden', vertical: 'hidden' });
parent.getHTMLElement().appendChild(this.leftScrollbar.getDomNode());
$(this.leftScrollbar.getDomNode()).addClass('binarydiff-left');
......@@ -76,7 +80,8 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
this.rightBinaryContainer.tabindex(0); // enable focus support from the editor part (do not remove)
// Right Custom Scrollbars
this.rightScrollbar = new ScrollableElement(rightBinaryContainerElement, { horizontal: 'hidden', vertical: 'hidden' });
this.rightScrollable = new DomNodeScrollable(rightBinaryContainerElement);
this.rightScrollbar = new ScrollableElement(rightBinaryContainerElement, this.rightScrollable, { horizontal: 'hidden', vertical: 'hidden' });
parent.getHTMLElement().appendChild(this.rightScrollbar.getDomNode());
$(this.rightScrollbar.getDomNode()).addClass('binarydiff-right');
}
......@@ -127,9 +132,9 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
// Pass to ResourceViewer
let container = isOriginal ? this.leftBinaryContainer : this.rightBinaryContainer;
let scrollbar = isOriginal ? this.leftScrollbar : this.rightScrollbar;
let scrollable = isOriginal ? this.leftScrollable : this.rightScrollable;
ResourceViewer.show(name, resource, container, scrollbar);
ResourceViewer.show(name, resource, container, scrollable);
}
public clearInput(): void {
......@@ -165,12 +170,12 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
// Size left container
this.leftBinaryContainer.size(this.leftContainerWidth, this.dimension.height);
this.leftScrollbar.onElementDimensions();
this.leftScrollbar.onElementInternalDimensions();
this.leftScrollable.onContentsDimensions();
// Size right container
this.rightBinaryContainer.size(this.dimension.width - this.leftContainerWidth, this.dimension.height);
this.rightScrollbar.onElementDimensions();
this.rightScrollbar.onElementInternalDimensions();
this.rightScrollable.onContentsDimensions();
}
private onSashDragStart(): void {
......@@ -217,7 +222,9 @@ export class BinaryResourceDiffEditor extends BaseEditor implements IVerticalSas
// Dispose Scrollbar
this.leftScrollbar.dispose();
this.leftScrollable.dispose();
this.rightScrollbar.dispose();
this.rightScrollable.dispose();
// Destroy Container
this.leftBinaryContainer.destroy();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册