mirror of
https://github.com/microsoft/vscode.git
synced 2026-05-20 23:29:57 +01:00
More cleanup in ScrollableElement
This commit is contained in:
@@ -7,130 +7,51 @@
|
||||
import * as Browser from 'vs/base/browser/browser';
|
||||
import * as Platform from 'vs/base/common/platform';
|
||||
import * as DomUtils from 'vs/base/browser/dom';
|
||||
import {IMouseEvent, StandardMouseEvent} from 'vs/base/browser/mouseEvent';
|
||||
import {IParent, Visibility} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {Disposable} from 'vs/base/common/lifecycle';
|
||||
import {IMouseEvent, StandardMouseEvent, StandardMouseWheelEvent} from 'vs/base/browser/mouseEvent';
|
||||
import {Visibility} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger} from 'vs/base/browser/globalMouseMoveMonitor';
|
||||
import {Widget} from 'vs/base/browser/ui/widget';
|
||||
import {TimeoutTimer} from 'vs/base/common/async';
|
||||
import {FastDomNode, createFastDomNode} from 'vs/base/browser/styleMutator';
|
||||
import {ScrollbarState} from 'vs/base/browser/ui/scrollbar/scrollbarState';
|
||||
import {ScrollbarArrow, IMouseWheelEventFactory} from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
|
||||
import {ScrollbarArrow, ScrollbarArrowOptions} from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
|
||||
import {ScrollbarVisibilityController} from 'vs/base/browser/ui/scrollbar/scrollbarVisibilityController';
|
||||
import {DelegateScrollable} from 'vs/base/common/scrollable';
|
||||
|
||||
/**
|
||||
* The orthogonal distance to the slider at which dragging "resets". This implements "snapping"
|
||||
*/
|
||||
const MOUSE_DRAG_RESET_DISTANCE = 140;
|
||||
|
||||
class VisibilityController extends Disposable {
|
||||
private _visibility: Visibility;
|
||||
private _visibleClassName: string;
|
||||
private _invisibleClassName: string;
|
||||
private _domNode: FastDomNode;
|
||||
private _shouldBeVisible: boolean;
|
||||
private _isNeeded: boolean;
|
||||
private _isVisible: boolean;
|
||||
private _revealTimer: TimeoutTimer;
|
||||
|
||||
constructor(visibility: Visibility, visibleClassName: string, invisibleClassName: string) {
|
||||
super();
|
||||
this._visibility = visibility;
|
||||
this._visibleClassName = visibleClassName;
|
||||
this._invisibleClassName = invisibleClassName;
|
||||
this._domNode = null;
|
||||
this._isVisible = false;
|
||||
this._isNeeded = false;
|
||||
this._shouldBeVisible = false;
|
||||
this._revealTimer = this._register(new TimeoutTimer());
|
||||
}
|
||||
|
||||
// ----------------- Hide / Reveal
|
||||
|
||||
private applyVisibilitySetting(shouldBeVisible: boolean): boolean {
|
||||
if (this._visibility === Visibility.Hidden) {
|
||||
return false;
|
||||
}
|
||||
if (this._visibility === Visibility.Visible) {
|
||||
return true;
|
||||
}
|
||||
return shouldBeVisible;
|
||||
}
|
||||
|
||||
public setShouldBeVisible(rawShouldBeVisible: boolean): void {
|
||||
let shouldBeVisible = this.applyVisibilitySetting(rawShouldBeVisible);
|
||||
|
||||
if (this._shouldBeVisible !== shouldBeVisible) {
|
||||
this._shouldBeVisible = shouldBeVisible;
|
||||
this.ensureVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
public setIsNeeded(isNeeded: boolean): void {
|
||||
if (this._isNeeded !== isNeeded) {
|
||||
this._isNeeded = isNeeded;
|
||||
this.ensureVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
public setDomNode(domNode: FastDomNode): void {
|
||||
this._domNode = domNode;
|
||||
this._domNode.setClassName(this._invisibleClassName);
|
||||
|
||||
// Now that the flags & the dom node are in a consistent state, ensure the Hidden/Visible configuration
|
||||
this.setShouldBeVisible(false);
|
||||
}
|
||||
|
||||
public ensureVisibility(): void {
|
||||
|
||||
if (!this._isNeeded) {
|
||||
// Nothing to be rendered
|
||||
this._hide(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._shouldBeVisible) {
|
||||
this._reveal();
|
||||
} else {
|
||||
this._hide(true);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private _reveal(): void {
|
||||
if (this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._isVisible = true;
|
||||
|
||||
// The CSS animation doesn't play otherwise
|
||||
this._revealTimer.setIfNotSet(() => {
|
||||
this._domNode.setClassName(this._visibleClassName);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private _hide(withFadeAway: boolean): void {
|
||||
this._revealTimer.cancel();
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._isVisible = false;
|
||||
this._domNode.setClassName(this._invisibleClassName + (withFadeAway ? ' fade' : ''));
|
||||
}
|
||||
}
|
||||
|
||||
export interface IMouseMoveEventData {
|
||||
leftButton: boolean;
|
||||
posx: number;
|
||||
posy: number;
|
||||
}
|
||||
|
||||
export interface ScrollbarHost {
|
||||
onMouseWheel(mouseWheelEvent: StandardMouseWheelEvent): void;
|
||||
onDragStart(): void;
|
||||
onDragEnd(): void;
|
||||
}
|
||||
|
||||
export interface AbstractScrollbarOptions {
|
||||
forbidTranslate3dUse: boolean;
|
||||
lazyRender:boolean;
|
||||
host: ScrollbarHost;
|
||||
scrollbarState: ScrollbarState;
|
||||
visibility: Visibility;
|
||||
extraScrollbarClassName: string;
|
||||
scrollable: DelegateScrollable;
|
||||
}
|
||||
|
||||
export abstract class AbstractScrollbar extends Widget {
|
||||
|
||||
protected _forbidTranslate3dUse: boolean;
|
||||
protected _host: ScrollbarHost;
|
||||
protected _scrollable: DelegateScrollable;
|
||||
private _lazyRender: boolean;
|
||||
private _parent: IParent;
|
||||
private _scrollbarState: ScrollbarState;
|
||||
private _visibilityController: VisibilityController;
|
||||
private _visibilityController: ScrollbarVisibilityController;
|
||||
private _mouseMoveMonitor: GlobalMouseMoveMonitor<IStandardMouseMoveEventData>;
|
||||
|
||||
public domNode: FastDomNode;
|
||||
@@ -138,23 +59,16 @@ export abstract class AbstractScrollbar extends Widget {
|
||||
|
||||
protected _shouldRender: boolean;
|
||||
|
||||
constructor(forbidTranslate3dUse: boolean, lazyRender:boolean, parent: IParent, scrollbarState: ScrollbarState, visibility: Visibility, extraScrollbarClassName: string) {
|
||||
constructor(opts:AbstractScrollbarOptions) {
|
||||
super();
|
||||
this._forbidTranslate3dUse = forbidTranslate3dUse;
|
||||
this._lazyRender = lazyRender;
|
||||
this._parent = parent;
|
||||
this._scrollbarState = scrollbarState;
|
||||
this._visibilityController = this._register(new VisibilityController(visibility, 'visible scrollbar ' + extraScrollbarClassName, 'invisible scrollbar ' + extraScrollbarClassName));
|
||||
this._forbidTranslate3dUse = opts.forbidTranslate3dUse;
|
||||
this._lazyRender = opts.lazyRender;
|
||||
this._host = opts.host;
|
||||
this._scrollable = opts.scrollable;
|
||||
this._scrollbarState = opts.scrollbarState;
|
||||
this._visibilityController = this._register(new ScrollbarVisibilityController(opts.visibility, 'visible scrollbar ' + opts.extraScrollbarClassName, 'invisible scrollbar ' + opts.extraScrollbarClassName));
|
||||
this._mouseMoveMonitor = this._register(new GlobalMouseMoveMonitor<IStandardMouseMoveEventData>());
|
||||
this._shouldRender = true;
|
||||
}
|
||||
|
||||
// ----------------- initialize & clean-up
|
||||
|
||||
/**
|
||||
* Creates the container dom node for the scrollbar & hooks up the events
|
||||
*/
|
||||
protected _createDomNode(): void {
|
||||
this.domNode = createFastDomNode(document.createElement('div'));
|
||||
if (!this._forbidTranslate3dUse && Browser.canUseTranslate3d) {
|
||||
// Put the scrollbar in its own layer
|
||||
@@ -167,11 +81,13 @@ export abstract class AbstractScrollbar extends Widget {
|
||||
this.onmousedown(this.domNode.domNode, (e) => this._domNodeMouseDown(e));
|
||||
}
|
||||
|
||||
// ----------------- creation
|
||||
|
||||
/**
|
||||
* Creates the dom node for an arrow & adds it to the container
|
||||
*/
|
||||
protected _createArrow(className: string, top: number, left: number, bottom: number, right: number, bgWidth: number, bgHeight: number, mouseWheelEventFactory: IMouseWheelEventFactory): void {
|
||||
let arrow = this._register(new ScrollbarArrow(className, top, left, bottom, right, bgWidth, bgHeight, mouseWheelEventFactory, this._parent));
|
||||
protected _createArrow(opts:ScrollbarArrowOptions): void {
|
||||
let arrow = this._register(new ScrollbarArrow(opts));
|
||||
this.domNode.domNode.appendChild(arrow.bgDomNode);
|
||||
this.domNode.domNode.appendChild(arrow.domNode);
|
||||
}
|
||||
@@ -301,12 +217,12 @@ export abstract class AbstractScrollbar extends Widget {
|
||||
},
|
||||
() => {
|
||||
this.slider.toggleClassName('active', false);
|
||||
this._parent.onDragEnd();
|
||||
this._host.onDragEnd();
|
||||
}
|
||||
);
|
||||
|
||||
e.preventDefault();
|
||||
this._parent.onDragStart();
|
||||
this._host.onDragStart();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,43 +5,61 @@
|
||||
'use strict';
|
||||
|
||||
import * as Browser from 'vs/base/browser/browser';
|
||||
import {AbstractScrollbar, IMouseMoveEventData} from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
|
||||
import {AbstractScrollbar, ScrollbarHost, IMouseMoveEventData} from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
|
||||
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 {ScrollableElementResolvedOptions, Visibility} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {DelegateScrollable} from 'vs/base/common/scrollable';
|
||||
import {ScrollbarState} from 'vs/base/browser/ui/scrollbar/scrollbarState';
|
||||
import {ARROW_IMG_SIZE} from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
|
||||
|
||||
export class HorizontalScrollbar extends AbstractScrollbar {
|
||||
|
||||
private _scrollable: DelegateScrollable;
|
||||
constructor(scrollable: DelegateScrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {
|
||||
super({
|
||||
forbidTranslate3dUse: options.forbidTranslate3dUse,
|
||||
lazyRender: options.lazyRender,
|
||||
host: host,
|
||||
scrollbarState: new ScrollbarState(
|
||||
(options.horizontalHasArrows ? options.arrowSize : 0),
|
||||
(options.horizontal === Visibility.Hidden ? 0 : options.horizontalScrollbarSize),
|
||||
(options.vertical === Visibility.Hidden ? 0 : options.verticalScrollbarSize)
|
||||
),
|
||||
visibility: options.horizontal,
|
||||
extraScrollbarClassName: 'horizontal',
|
||||
scrollable: scrollable
|
||||
});
|
||||
|
||||
constructor(scrollable: DelegateScrollable, parent: IParent, options: IScrollableElementOptions) {
|
||||
let s = new ScrollbarState(
|
||||
(options.horizontalHasArrows ? options.arrowSize : 0),
|
||||
(options.horizontal === Visibility.Hidden ? 0 : options.horizontalScrollbarSize),
|
||||
(options.vertical === Visibility.Hidden ? 0 : options.verticalScrollbarSize)
|
||||
);
|
||||
super(options.forbidTranslate3dUse, options.lazyRender, parent, s, options.horizontal, 'horizontal');
|
||||
this._scrollable = scrollable;
|
||||
|
||||
this._createDomNode();
|
||||
if (options.horizontalHasArrows) {
|
||||
let arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;
|
||||
let scrollbarDelta = (options.horizontalScrollbarSize - ARROW_IMG_SIZE) / 2;
|
||||
|
||||
this._createArrow('left-arrow', scrollbarDelta, arrowDelta, null, null, options.arrowSize, options.horizontalScrollbarSize, () => this._createMouseWheelEvent(1));
|
||||
this._createArrow('right-arrow', scrollbarDelta, null, null, arrowDelta, options.arrowSize, options.horizontalScrollbarSize, () => this._createMouseWheelEvent(-1));
|
||||
this._createArrow({
|
||||
className: 'left-arrow',
|
||||
top: scrollbarDelta,
|
||||
left: arrowDelta,
|
||||
bottom: void 0,
|
||||
right: void 0,
|
||||
bgWidth: options.arrowSize,
|
||||
bgHeight: options.horizontalScrollbarSize,
|
||||
onActivate: () => this._host.onMouseWheel(new StandardMouseWheelEvent(null, 1, 0)),
|
||||
});
|
||||
|
||||
this._createArrow({
|
||||
className: 'right-arrow',
|
||||
top: scrollbarDelta,
|
||||
left: void 0,
|
||||
bottom: void 0,
|
||||
right: arrowDelta,
|
||||
bgWidth: options.arrowSize,
|
||||
bgHeight: options.horizontalScrollbarSize,
|
||||
onActivate: () => this._host.onMouseWheel(new StandardMouseWheelEvent(null, -1, 0)),
|
||||
});
|
||||
}
|
||||
|
||||
this._createSlider(Math.floor((options.horizontalScrollbarSize - options.horizontalSliderSize) / 2), 0, null, options.horizontalSliderSize);
|
||||
}
|
||||
|
||||
protected _createMouseWheelEvent(sign: number) {
|
||||
return new StandardMouseWheelEvent(null, sign, 0);
|
||||
}
|
||||
|
||||
protected _updateSlider(sliderSize: number, sliderPosition: number): void {
|
||||
this.slider.setWidth(sliderSize);
|
||||
if (!this._forbidTranslate3dUse && Browser.canUseTranslate3d) {
|
||||
|
||||
@@ -4,205 +4,99 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
export interface IScrollableElementCreationOptions {
|
||||
export interface ScrollableElementCreationOptions {
|
||||
/**
|
||||
* Prevent the scrollbar rendering from using translate3d. Defaults to false.
|
||||
*/
|
||||
forbidTranslate3dUse?: boolean;
|
||||
|
||||
/**
|
||||
* The scrollable element should not do any DOM mutations until renderNow() is called.
|
||||
* Defaults to false.
|
||||
*/
|
||||
lazyRender?: boolean;
|
||||
|
||||
/**
|
||||
* CSS Class name for the scrollable element.
|
||||
*/
|
||||
className?: string;
|
||||
|
||||
/**
|
||||
* Drop subtle horizontal and vertical shadows.
|
||||
* Defaults to false.
|
||||
*/
|
||||
useShadows?: boolean;
|
||||
|
||||
/**
|
||||
* Handle mouse wheel (listen to mouse wheel scrolling).
|
||||
* Defaults to true
|
||||
*/
|
||||
handleMouseWheel?: boolean;
|
||||
|
||||
/**
|
||||
* Flip axes. Treat vertical scrolling like horizontal and vice-versa.
|
||||
* Defaults to false;
|
||||
*/
|
||||
flipAxes?: boolean;
|
||||
|
||||
/**
|
||||
* A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.
|
||||
* Defaults to 1.
|
||||
*/
|
||||
mouseWheelScrollSensitivity?: number;
|
||||
|
||||
/**
|
||||
* Height for vertical arrows (top/bottom) and width for horizontal arrows (left/right).
|
||||
* Defaults to 11.
|
||||
*/
|
||||
arrowSize?: number;
|
||||
|
||||
/**
|
||||
* 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.
|
||||
*/
|
||||
listenOnDomNode?: HTMLElement;
|
||||
|
||||
/**
|
||||
* Control the visibility of the horizontal scrollbar.
|
||||
* Accepted values: 'auto' (on mouse over), 'visible' (always visible), 'hidden' (never visible)
|
||||
* Defaults to 'auto'.
|
||||
*/
|
||||
horizontal?: string;
|
||||
|
||||
/**
|
||||
* Height (in px) of the horizontal scrollbar.
|
||||
* Defaults to 10.
|
||||
*/
|
||||
horizontalScrollbarSize?: number;
|
||||
|
||||
/**
|
||||
* Height (in px) of the horizontal scrollbar slider.
|
||||
* Defaults to `horizontalScrollbarSize`
|
||||
*/
|
||||
horizontalSliderSize?: number;
|
||||
|
||||
/**
|
||||
* Render arrows (left/right) for the horizontal scrollbar.
|
||||
* Defaults to false.
|
||||
*/
|
||||
horizontalHasArrows?: boolean;
|
||||
|
||||
/**
|
||||
* Control the visibility of the vertical scrollbar.
|
||||
* Accepted values: 'auto' (on mouse over), 'visible' (always visible), 'hidden' (never visible)
|
||||
* Defaults to 'auto'.
|
||||
*/
|
||||
vertical?: string;
|
||||
|
||||
/**
|
||||
* Width (in px) of the vertical scrollbar.
|
||||
* Defaults to 10.
|
||||
*/
|
||||
verticalScrollbarSize?: number;
|
||||
|
||||
/**
|
||||
* Width (in px) of the vertical scrollbar slider.
|
||||
* Defaults to `verticalScrollbarSize`
|
||||
*/
|
||||
verticalSliderSize?: number;
|
||||
|
||||
/**
|
||||
* Render arrows (top/bottom) for the vertical scrollbar.
|
||||
* Defaults to false.
|
||||
*/
|
||||
verticalHasArrows?: boolean;
|
||||
|
||||
/**
|
||||
* Add a `last-scroll-time` attribute to scroll targets or parents of scroll targets matching the following class name
|
||||
*/
|
||||
saveLastScrollTimeOnClassName?: string;
|
||||
}
|
||||
|
||||
export interface IOverviewRulerLayoutInfo {
|
||||
parent: HTMLElement;
|
||||
insertBefore: HTMLElement;
|
||||
}
|
||||
|
||||
export interface IDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Element that uses fancy scrollbars.
|
||||
*/
|
||||
export interface IScrollableElement {
|
||||
|
||||
/**
|
||||
* Get the generated 'scrollable' dom node
|
||||
*/
|
||||
getDomNode(): HTMLElement;
|
||||
|
||||
/**
|
||||
* Let the scrollable element know that the generated dom node's width / height might have changed.
|
||||
*/
|
||||
onElementDimensions(dimensions?: IDimensions): void;
|
||||
|
||||
/**
|
||||
* Dispose.
|
||||
*/
|
||||
dispose(): void;
|
||||
|
||||
/**
|
||||
* Render / mutate the DOM now.
|
||||
* Should be used together with the ctor option `lazyRender`.
|
||||
*/
|
||||
renderNow(): void;
|
||||
|
||||
/**
|
||||
* Update the class name of the scrollable element.
|
||||
*/
|
||||
updateClassName(newClassName: string): void;
|
||||
|
||||
/**
|
||||
* Update configuration options for the scrollbar.
|
||||
* Really this is Editor.IEditorScrollbarOptions, but base shouldn't
|
||||
* depend on Editor.
|
||||
*/
|
||||
updateOptions(newOptions: IScrollableElementCreationOptions): void;
|
||||
|
||||
getOverviewRulerLayoutInfo(): IOverviewRulerLayoutInfo;
|
||||
|
||||
/**
|
||||
* Delegate a mouse down event to the vertical scrollbar.
|
||||
* This is to help with clicking somewhere else and having the scrollbar react.
|
||||
*/
|
||||
delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void;
|
||||
|
||||
}
|
||||
|
||||
export interface IMouseWheelEvent {
|
||||
browserEvent: MouseWheelEvent;
|
||||
deltaX: number;
|
||||
deltaY: number;
|
||||
preventDefault(): void;
|
||||
stopPropagation(): void;
|
||||
}
|
||||
|
||||
export interface IParent {
|
||||
onMouseWheel(mouseWheelEvent: IMouseWheelEvent): void;
|
||||
onDragStart(): void;
|
||||
onDragEnd(): void;
|
||||
}
|
||||
|
||||
export enum Visibility {
|
||||
Auto,
|
||||
Hidden,
|
||||
Visible
|
||||
}
|
||||
|
||||
export function visibilityFromString(visibility: string): Visibility {
|
||||
switch (visibility) {
|
||||
case 'hidden':
|
||||
return Visibility.Hidden;
|
||||
case 'visible':
|
||||
return Visibility.Visible;
|
||||
default:
|
||||
return Visibility.Auto;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IScrollableElementOptions {
|
||||
export interface ScrollableElementResolvedOptions {
|
||||
forbidTranslate3dUse: boolean;
|
||||
lazyRender: boolean;
|
||||
className: string;
|
||||
@@ -222,3 +116,62 @@ export interface IScrollableElementOptions {
|
||||
verticalHasArrows: boolean;
|
||||
saveLastScrollTimeOnClassName: string;
|
||||
}
|
||||
|
||||
export interface IOverviewRulerLayoutInfo {
|
||||
parent: HTMLElement;
|
||||
insertBefore: HTMLElement;
|
||||
}
|
||||
|
||||
export interface IDimensions {
|
||||
width: number;
|
||||
height: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* An Element that uses fancy scrollbars.
|
||||
*/
|
||||
export interface IScrollableElement {
|
||||
|
||||
|
||||
getDomNode(): HTMLElement;
|
||||
|
||||
|
||||
onElementDimensions(dimensions?: IDimensions): void;
|
||||
|
||||
/**
|
||||
* Dispose.
|
||||
*/
|
||||
dispose(): void;
|
||||
|
||||
|
||||
renderNow(): void;
|
||||
|
||||
|
||||
updateClassName(newClassName: string): void;
|
||||
|
||||
|
||||
updateOptions(newOptions: ScrollableElementCreationOptions): void;
|
||||
|
||||
getOverviewRulerLayoutInfo(): IOverviewRulerLayoutInfo;
|
||||
|
||||
|
||||
delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void;
|
||||
}
|
||||
|
||||
export enum Visibility {
|
||||
Auto,
|
||||
Hidden,
|
||||
Visible
|
||||
}
|
||||
|
||||
export function visibilityFromString(visibility: string): Visibility {
|
||||
switch (visibility) {
|
||||
case 'hidden':
|
||||
return Visibility.Hidden;
|
||||
case 'visible':
|
||||
return Visibility.Visible;
|
||||
default:
|
||||
return Visibility.Auto;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -12,21 +12,22 @@ import {StandardMouseWheelEvent, IMouseEvent} from 'vs/base/browser/mouseEvent';
|
||||
import {HorizontalScrollbar} from 'vs/base/browser/ui/scrollbar/horizontalScrollbar';
|
||||
import {VerticalScrollbar} from 'vs/base/browser/ui/scrollbar/verticalScrollbar';
|
||||
import {
|
||||
IScrollableElementOptions, IDimensions, IMouseWheelEvent, visibilityFromString,
|
||||
IScrollableElement, IScrollableElementCreationOptions, IOverviewRulerLayoutInfo
|
||||
ScrollableElementResolvedOptions, IDimensions, visibilityFromString,
|
||||
IScrollableElement, ScrollableElementCreationOptions, IOverviewRulerLayoutInfo
|
||||
} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
|
||||
import {IScrollable, DelegateScrollable} from 'vs/base/common/scrollable';
|
||||
import {Widget} from 'vs/base/browser/ui/widget';
|
||||
import {TimeoutTimer} from 'vs/base/common/async';
|
||||
import {FastDomNode, createFastDomNode} from 'vs/base/browser/styleMutator';
|
||||
import {ScrollbarHost} from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
|
||||
|
||||
const HIDE_TIMEOUT = 500;
|
||||
const SCROLL_WHEEL_SENSITIVITY = 50;
|
||||
|
||||
export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
|
||||
private _options: IScrollableElementOptions;
|
||||
private _options: ScrollableElementResolvedOptions;
|
||||
private _scrollable: DelegateScrollable;
|
||||
private _verticalScrollbar: VerticalScrollbar;
|
||||
private _horizontalScrollbar: HorizontalScrollbar;
|
||||
@@ -47,15 +48,20 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
private _hideTimeout: TimeoutTimer;
|
||||
private _shouldRender: boolean;
|
||||
|
||||
constructor(element: HTMLElement, scrollable:IScrollable, options: IScrollableElementCreationOptions, dimensions: IDimensions = null) {
|
||||
constructor(element: HTMLElement, scrollable:IScrollable, options: ScrollableElementCreationOptions, dimensions: IDimensions = null) {
|
||||
super();
|
||||
element.style.overflow = 'hidden';
|
||||
this._options = this._createOptions(options);
|
||||
this._options = resolveOptions(options);
|
||||
|
||||
this._scrollable = this._register(new DelegateScrollable(scrollable, () => this._onScroll()));
|
||||
|
||||
this._verticalScrollbar = this._register(new VerticalScrollbar(this._scrollable, this, this._options));
|
||||
this._horizontalScrollbar = this._register(new HorizontalScrollbar(this._scrollable, this, this._options));
|
||||
let scrollbarHost:ScrollbarHost = {
|
||||
onMouseWheel: (mouseWheelEvent: StandardMouseWheelEvent) => this._onMouseWheel(mouseWheelEvent),
|
||||
onDragStart: () => this._onDragStart(),
|
||||
onDragEnd: () => this._onDragEnd(),
|
||||
};
|
||||
this._verticalScrollbar = this._register(new VerticalScrollbar(this._scrollable, this._options, scrollbarHost));
|
||||
this._horizontalScrollbar = this._register(new HorizontalScrollbar(this._scrollable, this._options, scrollbarHost));
|
||||
|
||||
this._domNode = document.createElement('div');
|
||||
this._domNode.className = 'monaco-scrollable-element ' + this._options.className;
|
||||
@@ -105,6 +111,9 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the generated 'scrollable' dom node
|
||||
*/
|
||||
public getDomNode(): HTMLElement {
|
||||
return this._domNode;
|
||||
}
|
||||
@@ -116,10 +125,17 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Delegate a mouse down event to the vertical scrollbar.
|
||||
* This is to help with clicking somewhere else and having the scrollbar react.
|
||||
*/
|
||||
public delegateVerticalScrollbarMouseDown(browserEvent: MouseEvent): void {
|
||||
this._verticalScrollbar.delegateMouseDown(browserEvent);
|
||||
}
|
||||
|
||||
/**
|
||||
* Let the scrollable element know that the generated dom node's width / height might have changed.
|
||||
*/
|
||||
public onElementDimensions(dimensions: IDimensions = null, synchronous: boolean = false): void {
|
||||
if (synchronous) {
|
||||
this._actualElementDimensions(dimensions);
|
||||
@@ -142,6 +158,9 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
this._shouldRender = this._horizontalScrollbar.onElementSize(width) || this._shouldRender;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the class name of the scrollable element.
|
||||
*/
|
||||
public updateClassName(newClassName: string): void {
|
||||
this._options.className = newClassName;
|
||||
// Defaults are different on Macs
|
||||
@@ -151,9 +170,14 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
this._domNode.className = 'monaco-scrollable-element ' + this._options.className;
|
||||
}
|
||||
|
||||
public updateOptions(newOptions: IScrollableElementCreationOptions): void {
|
||||
/**
|
||||
* Update configuration options for the scrollbar.
|
||||
* Really this is Editor.IEditorScrollbarOptions, but base shouldn't
|
||||
* depend on Editor.
|
||||
*/
|
||||
public updateOptions(newOptions: ScrollableElementCreationOptions): void {
|
||||
// only support handleMouseWheel changes for now
|
||||
let massagedOptions = this._createOptions(newOptions);
|
||||
let massagedOptions = resolveOptions(newOptions);
|
||||
this._options.handleMouseWheel = massagedOptions.handleMouseWheel;
|
||||
this._options.mouseWheelScrollSensitivity = massagedOptions.mouseWheelScrollSensitivity;
|
||||
this._setListeningToMouseWheel(this._options.handleMouseWheel);
|
||||
@@ -176,7 +200,7 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
if (shouldListen) {
|
||||
let onMouseWheel = (browserEvent: MouseWheelEvent) => {
|
||||
let e = new StandardMouseWheelEvent(browserEvent);
|
||||
this.onMouseWheel(e);
|
||||
this._onMouseWheel(e);
|
||||
};
|
||||
|
||||
this._mouseWheelToDispose.push(DomUtils.addDisposableListener(this._listenOnDomNode, 'mousewheel', onMouseWheel));
|
||||
@@ -184,7 +208,7 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
}
|
||||
}
|
||||
|
||||
public onMouseWheel(e: IMouseWheelEvent): void {
|
||||
private _onMouseWheel(e: StandardMouseWheelEvent): void {
|
||||
if (Platform.isMacintosh && e.browserEvent && this._options.saveLastScrollTimeOnClassName) {
|
||||
// Mark dom node with timestamp of wheel event
|
||||
let target = <HTMLElement>e.browserEvent.target;
|
||||
@@ -271,6 +295,10 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Render / mutate the DOM now.
|
||||
* Should be used together with the ctor option `lazyRender`.
|
||||
*/
|
||||
public renderNow(): void {
|
||||
if (!this._options.lazyRender) {
|
||||
throw new Error('Please use `lazyRender` together with `renderNow`!');
|
||||
@@ -301,12 +329,12 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
|
||||
// -------------------- fade in / fade out --------------------
|
||||
|
||||
public onDragStart(): void {
|
||||
private _onDragStart(): void {
|
||||
this._isDragging = true;
|
||||
this._reveal();
|
||||
}
|
||||
|
||||
public onDragEnd(): void {
|
||||
private _onDragEnd(): void {
|
||||
this._isDragging = false;
|
||||
this._hide();
|
||||
}
|
||||
@@ -337,51 +365,41 @@ export class ScrollableElement extends Widget implements IScrollableElement {
|
||||
private _scheduleHide(): void {
|
||||
this._hideTimeout.cancelAndSet(() => this._hide(), HIDE_TIMEOUT);
|
||||
}
|
||||
|
||||
// -------------------- size & layout --------------------
|
||||
|
||||
private _createOptions(options: IScrollableElementCreationOptions): IScrollableElementOptions {
|
||||
|
||||
function ensureValue<V>(source: any, prop: string, value: V) {
|
||||
if (source.hasOwnProperty(prop)) {
|
||||
return <V>source[prop];
|
||||
}
|
||||
return value;
|
||||
}
|
||||
|
||||
let result: IScrollableElementOptions = {
|
||||
forbidTranslate3dUse: ensureValue(options, 'forbidTranslate3dUse', false),
|
||||
lazyRender: ensureValue(options, 'lazyRender', false),
|
||||
className: ensureValue(options, 'className', ''),
|
||||
useShadows: ensureValue(options, 'useShadows', true),
|
||||
handleMouseWheel: ensureValue(options, 'handleMouseWheel', true),
|
||||
flipAxes: ensureValue(options, 'flipAxes', false),
|
||||
mouseWheelScrollSensitivity: ensureValue(options, 'mouseWheelScrollSensitivity', 1),
|
||||
arrowSize: ensureValue(options, 'arrowSize', 11),
|
||||
|
||||
listenOnDomNode: ensureValue<HTMLElement>(options, 'listenOnDomNode', null),
|
||||
|
||||
horizontal: visibilityFromString(ensureValue(options, 'horizontal', 'auto')),
|
||||
horizontalScrollbarSize: ensureValue(options, 'horizontalScrollbarSize', 10),
|
||||
horizontalSliderSize: 0,
|
||||
horizontalHasArrows: ensureValue(options, 'horizontalHasArrows', false),
|
||||
|
||||
vertical: visibilityFromString(ensureValue(options, 'vertical', 'auto')),
|
||||
verticalScrollbarSize: ensureValue(options, 'verticalScrollbarSize', 10),
|
||||
verticalHasArrows: ensureValue(options, 'verticalHasArrows', false),
|
||||
verticalSliderSize: 0,
|
||||
|
||||
saveLastScrollTimeOnClassName: ensureValue(options, 'saveLastScrollTimeOnClassName', null)
|
||||
};
|
||||
|
||||
result.horizontalSliderSize = ensureValue(options, 'horizontalSliderSize', result.horizontalScrollbarSize);
|
||||
result.verticalSliderSize = ensureValue(options, 'verticalSliderSize', result.verticalScrollbarSize);
|
||||
|
||||
// Defaults are different on Macs
|
||||
if (Platform.isMacintosh) {
|
||||
result.className += ' mac';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableElementResolvedOptions {
|
||||
let result: ScrollableElementResolvedOptions = {
|
||||
forbidTranslate3dUse: (typeof opts.forbidTranslate3dUse !== 'undefined' ? opts.forbidTranslate3dUse : false),
|
||||
lazyRender: (typeof opts.lazyRender !== 'undefined' ? opts.lazyRender : false),
|
||||
className: (typeof opts.className !== 'undefined' ? opts.className : ''),
|
||||
useShadows: (typeof opts.useShadows !== 'undefined' ? opts.useShadows : true),
|
||||
handleMouseWheel: (typeof opts.handleMouseWheel !== 'undefined' ? opts.handleMouseWheel : true),
|
||||
flipAxes: (typeof opts.flipAxes !== 'undefined' ? opts.flipAxes : false),
|
||||
mouseWheelScrollSensitivity: (typeof opts.mouseWheelScrollSensitivity !== 'undefined' ? opts.mouseWheelScrollSensitivity : 1),
|
||||
arrowSize: (typeof opts.arrowSize !== 'undefined' ? opts.arrowSize : 11),
|
||||
|
||||
listenOnDomNode: (typeof opts.listenOnDomNode !== 'undefined' ? opts.listenOnDomNode : null),
|
||||
|
||||
horizontal: visibilityFromString(typeof opts.horizontal !== 'undefined' ? opts.horizontal : 'auto'),
|
||||
horizontalScrollbarSize: (typeof opts.horizontalScrollbarSize !== 'undefined' ? opts.horizontalScrollbarSize : 10),
|
||||
horizontalSliderSize: (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : 0),
|
||||
horizontalHasArrows: (typeof opts.horizontalHasArrows !== 'undefined' ? opts.horizontalHasArrows : false),
|
||||
|
||||
vertical: visibilityFromString(typeof opts.vertical !== 'undefined' ? opts.vertical : 'auto'),
|
||||
verticalScrollbarSize: (typeof opts.verticalScrollbarSize !== 'undefined' ? opts.verticalScrollbarSize : 10),
|
||||
verticalHasArrows: (typeof opts.verticalHasArrows !== 'undefined' ? opts.verticalHasArrows : false),
|
||||
verticalSliderSize: (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : 0),
|
||||
|
||||
saveLastScrollTimeOnClassName: (typeof opts.saveLastScrollTimeOnClassName !== 'undefined' ? opts.saveLastScrollTimeOnClassName : null)
|
||||
};
|
||||
|
||||
result.horizontalSliderSize = (typeof opts.horizontalSliderSize !== 'undefined' ? opts.horizontalSliderSize : result.horizontalScrollbarSize);
|
||||
result.verticalSliderSize = (typeof opts.verticalSliderSize !== 'undefined' ? opts.verticalSliderSize : result.verticalScrollbarSize);
|
||||
|
||||
// Defaults are different on Macs
|
||||
if (Platform.isMacintosh) {
|
||||
result.className += ' mac';
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -5,47 +5,76 @@
|
||||
'use strict';
|
||||
|
||||
import {IMouseEvent} from 'vs/base/browser/mouseEvent';
|
||||
import {IMouseWheelEvent, IParent} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {GlobalMouseMoveMonitor, IStandardMouseMoveEventData, standardMouseMoveMerger} from 'vs/base/browser/globalMouseMoveMonitor';
|
||||
import {Widget} from 'vs/base/browser/ui/widget';
|
||||
import {TimeoutTimer, IntervalTimer} from 'vs/base/common/async';
|
||||
|
||||
export interface IMouseWheelEventFactory {
|
||||
(): IMouseWheelEvent;
|
||||
}
|
||||
|
||||
/**
|
||||
* The arrow image size.
|
||||
*/
|
||||
export const ARROW_IMG_SIZE = 11;
|
||||
|
||||
export interface ScrollbarArrowOptions {
|
||||
onActivate: () => void;
|
||||
className: string;
|
||||
|
||||
bgWidth: number;
|
||||
bgHeight: number;
|
||||
|
||||
top?: number;
|
||||
left?: number;
|
||||
bottom?: number;
|
||||
right?: number;
|
||||
}
|
||||
|
||||
export class ScrollbarArrow extends Widget {
|
||||
|
||||
private _parent: IParent;
|
||||
private _mouseWheelEventFactory: IMouseWheelEventFactory;
|
||||
private _onActivate: () => void;
|
||||
public bgDomNode: HTMLElement;
|
||||
public domNode: HTMLElement;
|
||||
private _mousedownRepeatTimer: IntervalTimer;
|
||||
private _mousedownScheduleRepeatTimer: TimeoutTimer;
|
||||
private _mouseMoveMonitor: GlobalMouseMoveMonitor<IStandardMouseMoveEventData>;
|
||||
|
||||
constructor(className: string, top: number, left: number, bottom: number, right: number, bgWidth: number, bgHeight: number, mouseWheelEventFactory: IMouseWheelEventFactory, parent: IParent) {
|
||||
constructor(opts:ScrollbarArrowOptions) {
|
||||
super();
|
||||
this._parent = parent;
|
||||
this._mouseWheelEventFactory = mouseWheelEventFactory;
|
||||
this._onActivate = opts.onActivate;
|
||||
|
||||
this.bgDomNode = document.createElement('div');
|
||||
this.bgDomNode.className = 'arrow-background';
|
||||
this.bgDomNode.style.position = 'absolute';
|
||||
setSize(this.bgDomNode, bgWidth, bgHeight);
|
||||
setPosition(this.bgDomNode, (top !== null ? 0 : null), (left !== null ? 0 : null), (bottom !== null ? 0 : null), (right !== null ? 0 : null));
|
||||
|
||||
this.bgDomNode.style.width = opts.bgWidth + 'px';
|
||||
this.bgDomNode.style.height = opts.bgHeight + 'px';
|
||||
if (typeof opts.top !== 'undefined') {
|
||||
this.bgDomNode.style.top = '0px';
|
||||
}
|
||||
if (typeof opts.left !== 'undefined') {
|
||||
this.bgDomNode.style.left = '0px';
|
||||
}
|
||||
if (typeof opts.bottom !== 'undefined') {
|
||||
this.bgDomNode.style.bottom = '0px';
|
||||
}
|
||||
if (typeof opts.right !== 'undefined') {
|
||||
this.bgDomNode.style.right = '0px';
|
||||
}
|
||||
|
||||
this.domNode = document.createElement('div');
|
||||
this.domNode.className = className;
|
||||
this.domNode.className = opts.className;
|
||||
this.domNode.style.position = 'absolute';
|
||||
setSize(this.domNode, ARROW_IMG_SIZE, ARROW_IMG_SIZE);
|
||||
setPosition(this.domNode, top, left, bottom, right);
|
||||
this.domNode.style.width = ARROW_IMG_SIZE + 'px';
|
||||
this.domNode.style.height = ARROW_IMG_SIZE + 'px';
|
||||
if (typeof opts.top !== 'undefined') {
|
||||
this.domNode.style.top = opts.top + 'px';
|
||||
}
|
||||
if (typeof opts.left !== 'undefined') {
|
||||
this.domNode.style.left = opts.left + 'px';
|
||||
}
|
||||
if (typeof opts.bottom !== 'undefined') {
|
||||
this.domNode.style.bottom = opts.bottom + 'px';
|
||||
}
|
||||
if (typeof opts.right !== 'undefined') {
|
||||
this.domNode.style.right = opts.right + 'px';
|
||||
}
|
||||
|
||||
this._mouseMoveMonitor = this._register(new GlobalMouseMoveMonitor<IStandardMouseMoveEventData>());
|
||||
this.onmousedown(this.bgDomNode, (e) => this._arrowMouseDown(e));
|
||||
@@ -56,15 +85,11 @@ export class ScrollbarArrow extends Widget {
|
||||
}
|
||||
|
||||
private _arrowMouseDown(e: IMouseEvent): void {
|
||||
let repeater = () => {
|
||||
this._parent.onMouseWheel(this._mouseWheelEventFactory());
|
||||
};
|
||||
|
||||
let scheduleRepeater = () => {
|
||||
this._mousedownRepeatTimer.cancelAndSet(repeater, 1000 / 24);
|
||||
this._mousedownRepeatTimer.cancelAndSet(() => this._onActivate(), 1000 / 24);
|
||||
};
|
||||
|
||||
repeater();
|
||||
this._onActivate();
|
||||
this._mousedownRepeatTimer.cancel();
|
||||
this._mousedownScheduleRepeatTimer.cancelAndSet(scheduleRepeater, 200);
|
||||
|
||||
@@ -82,27 +107,3 @@ export class ScrollbarArrow extends Widget {
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
|
||||
function setPosition(domNode: HTMLElement, top: number, left: number, bottom: number, right: number) {
|
||||
if (top !== null) {
|
||||
domNode.style.top = top + 'px';
|
||||
}
|
||||
if (left !== null) {
|
||||
domNode.style.left = left + 'px';
|
||||
}
|
||||
if (bottom !== null) {
|
||||
domNode.style.bottom = bottom + 'px';
|
||||
}
|
||||
if (right !== null) {
|
||||
domNode.style.right = right + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
function setSize(domNode: HTMLElement, width: number, height: number) {
|
||||
if (width !== null) {
|
||||
domNode.style.width = width + 'px';
|
||||
}
|
||||
if (height !== null) {
|
||||
domNode.style.height = height + 'px';
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
'use strict';
|
||||
|
||||
import {Visibility} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {Disposable} from 'vs/base/common/lifecycle';
|
||||
import {TimeoutTimer} from 'vs/base/common/async';
|
||||
import {FastDomNode} from 'vs/base/browser/styleMutator';
|
||||
|
||||
export class ScrollbarVisibilityController extends Disposable {
|
||||
private _visibility: Visibility;
|
||||
private _visibleClassName: string;
|
||||
private _invisibleClassName: string;
|
||||
private _domNode: FastDomNode;
|
||||
private _shouldBeVisible: boolean;
|
||||
private _isNeeded: boolean;
|
||||
private _isVisible: boolean;
|
||||
private _revealTimer: TimeoutTimer;
|
||||
|
||||
constructor(visibility: Visibility, visibleClassName: string, invisibleClassName: string) {
|
||||
super();
|
||||
this._visibility = visibility;
|
||||
this._visibleClassName = visibleClassName;
|
||||
this._invisibleClassName = invisibleClassName;
|
||||
this._domNode = null;
|
||||
this._isVisible = false;
|
||||
this._isNeeded = false;
|
||||
this._shouldBeVisible = false;
|
||||
this._revealTimer = this._register(new TimeoutTimer());
|
||||
}
|
||||
|
||||
// ----------------- Hide / Reveal
|
||||
|
||||
private applyVisibilitySetting(shouldBeVisible: boolean): boolean {
|
||||
if (this._visibility === Visibility.Hidden) {
|
||||
return false;
|
||||
}
|
||||
if (this._visibility === Visibility.Visible) {
|
||||
return true;
|
||||
}
|
||||
return shouldBeVisible;
|
||||
}
|
||||
|
||||
public setShouldBeVisible(rawShouldBeVisible: boolean): void {
|
||||
let shouldBeVisible = this.applyVisibilitySetting(rawShouldBeVisible);
|
||||
|
||||
if (this._shouldBeVisible !== shouldBeVisible) {
|
||||
this._shouldBeVisible = shouldBeVisible;
|
||||
this.ensureVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
public setIsNeeded(isNeeded: boolean): void {
|
||||
if (this._isNeeded !== isNeeded) {
|
||||
this._isNeeded = isNeeded;
|
||||
this.ensureVisibility();
|
||||
}
|
||||
}
|
||||
|
||||
public setDomNode(domNode: FastDomNode): void {
|
||||
this._domNode = domNode;
|
||||
this._domNode.setClassName(this._invisibleClassName);
|
||||
|
||||
// Now that the flags & the dom node are in a consistent state, ensure the Hidden/Visible configuration
|
||||
this.setShouldBeVisible(false);
|
||||
}
|
||||
|
||||
public ensureVisibility(): void {
|
||||
|
||||
if (!this._isNeeded) {
|
||||
// Nothing to be rendered
|
||||
this._hide(false);
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._shouldBeVisible) {
|
||||
this._reveal();
|
||||
} else {
|
||||
this._hide(true);
|
||||
}
|
||||
}
|
||||
|
||||
private _reveal(): void {
|
||||
if (this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._isVisible = true;
|
||||
|
||||
// The CSS animation doesn't play otherwise
|
||||
this._revealTimer.setIfNotSet(() => {
|
||||
this._domNode.setClassName(this._visibleClassName);
|
||||
}, 0);
|
||||
}
|
||||
|
||||
private _hide(withFadeAway: boolean): void {
|
||||
this._revealTimer.cancel();
|
||||
if (!this._isVisible) {
|
||||
return;
|
||||
}
|
||||
this._isVisible = false;
|
||||
this._domNode.setClassName(this._invisibleClassName + (withFadeAway ? ' fade' : ''));
|
||||
}
|
||||
}
|
||||
@@ -5,44 +5,62 @@
|
||||
'use strict';
|
||||
|
||||
import * as Browser from 'vs/base/browser/browser';
|
||||
import {AbstractScrollbar, IMouseMoveEventData} from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
|
||||
import {AbstractScrollbar, ScrollbarHost, IMouseMoveEventData} from 'vs/base/browser/ui/scrollbar/abstractScrollbar';
|
||||
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 {ScrollableElementResolvedOptions, Visibility} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {DelegateScrollable} from 'vs/base/common/scrollable';
|
||||
import {ScrollbarState} from 'vs/base/browser/ui/scrollbar/scrollbarState';
|
||||
import {ARROW_IMG_SIZE} from 'vs/base/browser/ui/scrollbar/scrollbarArrow';
|
||||
|
||||
export class VerticalScrollbar extends AbstractScrollbar {
|
||||
|
||||
private _scrollable: DelegateScrollable;
|
||||
constructor(scrollable: DelegateScrollable, options: ScrollableElementResolvedOptions, host: ScrollbarHost) {
|
||||
super({
|
||||
forbidTranslate3dUse: options.forbidTranslate3dUse,
|
||||
lazyRender: options.lazyRender,
|
||||
host: host,
|
||||
scrollbarState: new ScrollbarState(
|
||||
(options.verticalHasArrows ? options.arrowSize : 0),
|
||||
(options.vertical === Visibility.Hidden ? 0 : options.verticalScrollbarSize),
|
||||
// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom
|
||||
0
|
||||
),
|
||||
visibility: options.vertical,
|
||||
extraScrollbarClassName: 'vertical',
|
||||
scrollable: scrollable
|
||||
});
|
||||
|
||||
constructor(scrollable: DelegateScrollable, parent: IParent, options: IScrollableElementOptions) {
|
||||
let s = new ScrollbarState(
|
||||
(options.verticalHasArrows ? options.arrowSize : 0),
|
||||
(options.vertical === Visibility.Hidden ? 0 : options.verticalScrollbarSize),
|
||||
// give priority to vertical scroll bar over horizontal and let it scroll all the way to the bottom
|
||||
0
|
||||
);
|
||||
super(options.forbidTranslate3dUse, options.lazyRender, parent, s, options.vertical, 'vertical');
|
||||
this._scrollable = scrollable;
|
||||
|
||||
this._createDomNode();
|
||||
if (options.verticalHasArrows) {
|
||||
let arrowDelta = (options.arrowSize - ARROW_IMG_SIZE) / 2;
|
||||
let scrollbarDelta = (options.verticalScrollbarSize - ARROW_IMG_SIZE) / 2;
|
||||
|
||||
this._createArrow('up-arrow', arrowDelta, scrollbarDelta, null, null, options.verticalScrollbarSize, options.arrowSize, () => this._createMouseWheelEvent(1));
|
||||
this._createArrow('down-arrow', null, scrollbarDelta, arrowDelta, null, options.verticalScrollbarSize, options.arrowSize, () => this._createMouseWheelEvent(-1));
|
||||
this._createArrow({
|
||||
className: 'up-arrow',
|
||||
top: arrowDelta,
|
||||
left: scrollbarDelta,
|
||||
bottom: void 0,
|
||||
right: void 0,
|
||||
bgWidth: options.verticalScrollbarSize,
|
||||
bgHeight: options.arrowSize,
|
||||
onActivate: () => this._host.onMouseWheel(new StandardMouseWheelEvent(null, 0, 1)),
|
||||
});
|
||||
|
||||
this._createArrow({
|
||||
className: 'down-arrow',
|
||||
top: void 0,
|
||||
left: scrollbarDelta,
|
||||
bottom: arrowDelta,
|
||||
right: void 0,
|
||||
bgWidth: options.verticalScrollbarSize,
|
||||
bgHeight: options.arrowSize,
|
||||
onActivate: () => this._host.onMouseWheel(new StandardMouseWheelEvent(null, 0, -1)),
|
||||
});
|
||||
}
|
||||
|
||||
this._createSlider(0, Math.floor((options.verticalScrollbarSize - options.verticalSliderSize) / 2), options.verticalSliderSize, null);
|
||||
}
|
||||
|
||||
protected _createMouseWheelEvent(sign: number) {
|
||||
return new StandardMouseWheelEvent(null, 0, sign);
|
||||
}
|
||||
|
||||
protected _updateSlider(sliderSize: number, sliderPosition: number): void {
|
||||
this.slider.setHeight(sliderSize);
|
||||
if (!this._forbidTranslate3dUse && Browser.canUseTranslate3d) {
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
|
||||
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
|
||||
import * as dom from 'vs/base/browser/dom';
|
||||
import {IOverviewRulerLayoutInfo, IScrollableElement, IScrollableElementCreationOptions} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {IOverviewRulerLayoutInfo, IScrollableElement, ScrollableElementCreationOptions} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {ScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElementImpl';
|
||||
import {EventType, IConfiguration, IConfigurationChangedEvent, IScrollEvent, IViewEventBus} from 'vs/editor/common/editorCommon';
|
||||
import {EditorScrollable} from 'vs/editor/common/viewLayout/editorScrollable';
|
||||
@@ -41,7 +41,7 @@ export class ScrollManager implements IDisposable {
|
||||
|
||||
var configScrollbarOpts = this.configuration.editor.scrollbar;
|
||||
|
||||
var scrollbarOptions:IScrollableElementCreationOptions = {
|
||||
var scrollbarOptions:ScrollableElementCreationOptions = {
|
||||
listenOnDomNode: viewDomNode,
|
||||
vertical: configScrollbarOpts.vertical,
|
||||
horizontal: configScrollbarOpts.horizontal,
|
||||
|
||||
Reference in New Issue
Block a user