mirror of
https://github.com/Microsoft/vscode
synced 2024-09-13 21:55:38 +00:00
custom scrollbar for tab container
This commit is contained in:
parent
a9f9451165
commit
317df5a6af
|
@ -244,6 +244,11 @@ export class ScrollableElement extends Widget {
|
|||
deltaX = e.deltaY;
|
||||
}
|
||||
|
||||
if (this._options.scrollYToX && !deltaX) {
|
||||
deltaX = e.deltaY;
|
||||
deltaY = 0;
|
||||
}
|
||||
|
||||
if (Platform.isMacintosh) {
|
||||
// Give preference to vertical scrolling
|
||||
if (deltaY && Math.abs(deltaX) < 0.2) {
|
||||
|
@ -412,6 +417,7 @@ function resolveOptions(opts: ScrollableElementCreationOptions): ScrollableEleme
|
|||
useShadows: (typeof opts.useShadows !== 'undefined' ? opts.useShadows : true),
|
||||
handleMouseWheel: (typeof opts.handleMouseWheel !== 'undefined' ? opts.handleMouseWheel : true),
|
||||
flipAxes: (typeof opts.flipAxes !== 'undefined' ? opts.flipAxes : false),
|
||||
scrollYToX: (typeof opts.scrollYToX !== 'undefined' ? opts.scrollYToX : false),
|
||||
mouseWheelScrollSensitivity: (typeof opts.mouseWheelScrollSensitivity !== 'undefined' ? opts.mouseWheelScrollSensitivity : 1),
|
||||
arrowSize: (typeof opts.arrowSize !== 'undefined' ? opts.arrowSize : 11),
|
||||
|
||||
|
|
|
@ -36,9 +36,14 @@ export interface ScrollableElementCreationOptions {
|
|||
handleMouseWheel?: boolean;
|
||||
/**
|
||||
* Flip axes. Treat vertical scrolling like horizontal and vice-versa.
|
||||
* Defaults to false;
|
||||
* Defaults to false.
|
||||
*/
|
||||
flipAxes?: boolean;
|
||||
/**
|
||||
* If enabled, will scroll horizontally when scrolling vertical.
|
||||
* Defaults to false.
|
||||
*/
|
||||
scrollYToX?: boolean;
|
||||
/**
|
||||
* A multiplier to be used on the `deltaX` and `deltaY` of mouse wheel scroll events.
|
||||
* Defaults to 1.
|
||||
|
@ -115,6 +120,7 @@ export interface ScrollableElementResolvedOptions {
|
|||
useShadows: boolean;
|
||||
handleMouseWheel: boolean;
|
||||
flipAxes: boolean;
|
||||
scrollYToX: boolean;
|
||||
mouseWheelScrollSensitivity: number;
|
||||
arrowSize: number;
|
||||
listenOnDomNode: HTMLElement;
|
||||
|
|
|
@ -5,8 +5,11 @@
|
|||
|
||||
/* Tabs Container */
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container {
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title > .monaco-scrollable-element {
|
||||
flex: 1;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container {
|
||||
display: flex;
|
||||
overflow: scroll;
|
||||
background-color: rgba(128, 128, 128, 0.2);
|
||||
|
@ -67,27 +70,27 @@
|
|||
|
||||
/* Tab Close */
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title > .tabs-container > .tab > .tab-close {
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab > .tab-close {
|
||||
opacity: 0; /* hide the close button by default */
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title.active > .tabs-container > .tab.active > .tab-close, /* always show it for active tab */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title.active > .tabs-container > .tab:hover > .tab-close, /* always show it on hover */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title.active > .tabs-container > .tab.active:hover > .tab-close, /* always show it on hover */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title > .tabs-container > .tab.dirty > .tab-close { /* always show it for dirty tabs */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title.active .tabs-container > .tab.active > .tab-close, /* always show it for active tab */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title.active .tabs-container > .tab:hover > .tab-close, /* always show it on hover */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title.active .tabs-container > .tab.active:hover > .tab-close, /* always show it on hover */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab.dirty > .tab-close { /* always show it for dirty tabs */
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title > .tabs-container > .tab.active > .tab-close, /* show dimmed for inactive group */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title > .tabs-container > .tab.active:hover > .tab-close { /* show dimmed for inactive group */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab.active > .tab-close, /* show dimmed for inactive group */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab.active:hover > .tab-close { /* show dimmed for inactive group */
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title > .tabs-container > .tab:hover > .tab-close { /* show more dimmed for inactive group and tab */
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab:hover > .tab-close { /* show more dimmed for inactive group and tab */
|
||||
opacity: 0.4;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title > .tabs-container > .tab > .tab-close .action-label {
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab > .tab-close .action-label {
|
||||
width: 20px;
|
||||
}
|
||||
|
||||
|
|
|
@ -6,7 +6,7 @@
|
|||
/* Editor Label */
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .title-label,
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title > .tabs-container > .tab .tab-label {
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab .tab-label {
|
||||
line-height: 35px;
|
||||
white-space: nowrap;
|
||||
flex: 1;
|
||||
|
@ -14,34 +14,34 @@
|
|||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title.pinned .title-label,
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title > .tabs-container > .tab.pinned .tab-label {
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab.pinned .tab-label {
|
||||
font-style: normal;
|
||||
}
|
||||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .title-label a,
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title > .tabs-container > .tab .tab-label a {
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab .tab-label a {
|
||||
text-decoration: none;
|
||||
font-size: 13px;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title .title-label a,
|
||||
.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title > .tabs-container > .tab .tab-label a {
|
||||
.vs .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab .tab-label a {
|
||||
color: rgba(51, 51, 51, 0.5);
|
||||
}
|
||||
|
||||
.vs .monaco-workbench > .part.editor > .content > .one-editor-container .title.active .title-label a,
|
||||
.vs .monaco-workbench > .part.editor > .content > .one-editor-container .title.active > .tabs-container > .tab .tab-label a {
|
||||
.vs .monaco-workbench > .part.editor > .content > .one-editor-container .title.active .tabs-container > .tab .tab-label a {
|
||||
color: #333333;
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container > .title .title-label a,
|
||||
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container > .title > .tabs-container > .tab .tab-label a {
|
||||
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container > .title .tabs-container > .tab .tab-label a {
|
||||
color: rgba(255, 255, 255, 0.5);
|
||||
}
|
||||
|
||||
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container .title.active .title-label a,
|
||||
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container .title.active > .tabs-container > .tab .tab-label a {
|
||||
.vs-dark .monaco-workbench > .part.editor > .content > .one-editor-container .title.active .tabs-container > .tab .tab-label a {
|
||||
color: white;
|
||||
}
|
||||
|
||||
|
@ -49,7 +49,7 @@
|
|||
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .title-actions .action-label,
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container > .title .group-actions .action-label,
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title > .tabs-container > .tab > .tab-close .action-label {
|
||||
.monaco-workbench > .part.editor > .content > .one-editor-container .title .tabs-container > .tab > .tab-close .action-label {
|
||||
display: block;
|
||||
height: 35px;
|
||||
width: 28px;
|
||||
|
|
|
@ -28,6 +28,8 @@ import {IInstantiationService} from 'vs/platform/instantiation/common/instantiat
|
|||
import {IKeybindingService} from 'vs/platform/keybinding/common/keybindingService';
|
||||
import {TitleControl} from 'vs/workbench/browser/parts/editor/titleControl';
|
||||
import {IDisposable, dispose} from 'vs/base/common/lifecycle';
|
||||
import {ScrollableElement} from 'vs/base/browser/ui/scrollbar/scrollableElement';
|
||||
import {ScrollbarVisibility} from 'vs/base/browser/ui/scrollbar/scrollableElementOptions';
|
||||
|
||||
export class TabsTitleControl extends TitleControl {
|
||||
|
||||
|
@ -36,6 +38,7 @@ export class TabsTitleControl extends TitleControl {
|
|||
private titleContainer: HTMLElement;
|
||||
private tabsContainer: HTMLElement;
|
||||
private activeTab: HTMLElement;
|
||||
private scrollbar: ScrollableElement;
|
||||
|
||||
private groupActionsToolbar: ToolBar;
|
||||
private tabDisposeables: IDisposable[];
|
||||
|
@ -72,7 +75,23 @@ export class TabsTitleControl extends TitleControl {
|
|||
// Tabs Container
|
||||
this.tabsContainer = document.createElement('div');
|
||||
DOM.addClass(this.tabsContainer, 'tabs-container');
|
||||
this.titleContainer.appendChild(this.tabsContainer);
|
||||
|
||||
// Custom Scrollbar
|
||||
this.scrollbar = new ScrollableElement(this.tabsContainer, {
|
||||
horizontal: ScrollbarVisibility.Auto,
|
||||
vertical: ScrollbarVisibility.Hidden,
|
||||
scrollYToX: true,
|
||||
useShadows: false,
|
||||
canUseTranslate3d: true,
|
||||
horizontalScrollbarSize: 3
|
||||
});
|
||||
this.tabsContainer.style.overflow = 'scroll'; // custom scrollbar is eager on removing this style but we want it for DND scroll feedback
|
||||
|
||||
this.scrollbar.onScroll(e => {
|
||||
this.tabsContainer.scrollLeft = e.scrollLeft;
|
||||
});
|
||||
|
||||
this.titleContainer.appendChild(this.scrollbar.getDomNode());
|
||||
|
||||
// Drag over
|
||||
this.toDispose.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.DRAG_OVER, (e: DragEvent) => {
|
||||
|
@ -113,14 +132,6 @@ export class TabsTitleControl extends TitleControl {
|
|||
}
|
||||
}));
|
||||
|
||||
// Convert mouse wheel vertical scroll to horizontal
|
||||
this.toDispose.push(DOM.addDisposableListener(this.tabsContainer, DOM.EventType.WHEEL, (e: WheelEvent) => {
|
||||
if (e.deltaY && !e.deltaX) {
|
||||
DOM.EventHelper.stop(e);
|
||||
this.tabsContainer.scrollLeft += e.deltaY;
|
||||
}
|
||||
}));
|
||||
|
||||
// Group Actions
|
||||
const groupActionsContainer = document.createElement('div');
|
||||
DOM.addClass(groupActionsContainer, 'group-actions');
|
||||
|
@ -269,24 +280,36 @@ export class TabsTitleControl extends TitleControl {
|
|||
return;
|
||||
}
|
||||
|
||||
const visibleContainerWidth = this.tabsContainer.offsetWidth;
|
||||
const totalContainerWidth = this.tabsContainer.scrollWidth;
|
||||
|
||||
// Update scrollbar
|
||||
this.scrollbar.updateState({
|
||||
width: visibleContainerWidth,
|
||||
scrollWidth: totalContainerWidth
|
||||
});
|
||||
|
||||
// Always reveal the active one
|
||||
const containerWidth = this.tabsContainer.offsetWidth;
|
||||
const containerScrollPosX = this.tabsContainer.scrollLeft;
|
||||
const activeTabPosX = this.activeTab.offsetLeft;
|
||||
const activeTabWidth = this.activeTab.offsetWidth;
|
||||
|
||||
// Tab is overflowing to the right: Scroll minimally until the element is fully visible to the right
|
||||
if (containerScrollPosX + containerWidth < activeTabPosX + activeTabWidth) {
|
||||
this.tabsContainer.scrollLeft += ((activeTabPosX + activeTabWidth) /* right corner of tab */ - (containerScrollPosX + containerWidth) /* right corner of view port */);
|
||||
if (containerScrollPosX + visibleContainerWidth < activeTabPosX + activeTabWidth) {
|
||||
this.scrollbar.updateState({
|
||||
scrollLeft: containerScrollPosX + ((activeTabPosX + activeTabWidth) /* right corner of tab */ - (containerScrollPosX + visibleContainerWidth) /* right corner of view port */)
|
||||
});
|
||||
}
|
||||
|
||||
// Tab is overlflowng to the left: Scroll it into view to the left
|
||||
else if (containerScrollPosX > activeTabPosX) {
|
||||
this.tabsContainer.scrollLeft = this.activeTab.offsetLeft;
|
||||
this.scrollbar.updateState({
|
||||
scrollLeft: this.activeTab.offsetLeft
|
||||
});
|
||||
}
|
||||
|
||||
// Update enablement of certain actions that depend on overflow
|
||||
const isOverflowing = (this.tabsContainer.scrollWidth > containerWidth);
|
||||
const isOverflowing = (totalContainerWidth > visibleContainerWidth);
|
||||
this.showEditorsOfLeftGroup.enabled = isOverflowing;
|
||||
this.showEditorsOfCenterGroup.enabled = isOverflowing;
|
||||
this.showEditorsOfRightGroup.enabled = isOverflowing;
|
||||
|
|
Loading…
Reference in a new issue