提交 42ffefc4 编写于 作者: B Benjamin Pasero

grid - implement moveEditor() in title properly

上级 abfe4087
......@@ -20,7 +20,6 @@ import { IThemeService } from 'vs/platform/theme/common/themeService';
import { editorBackground, contrastBorder, focusBorder } from 'vs/platform/theme/common/colorRegistry';
import { Themable, EDITOR_GROUP_HEADER_TABS_BORDER, EDITOR_GROUP_HEADER_TABS_BACKGROUND, EDITOR_GROUP_BACKGROUND } from 'vs/workbench/common/theme';
import { INextEditorGroup, IMoveEditorOptions } from 'vs/workbench/services/editor/common/nextEditorGroupsService';
import { INextTitleAreaControl } from 'vs/workbench/browser/parts/editor2/nextTitleControl';
import { NextTabsTitleControl } from 'vs/workbench/browser/parts/editor2/nextTabsTitleControl';
import { NextEditorControl } from 'vs/workbench/browser/parts/editor2/nextEditorControl';
import { IView } from 'vs/base/browser/ui/grid/gridview';
......@@ -38,6 +37,7 @@ import { RunOnceWorker } from 'vs/base/common/async';
import { IConfigurationService, IConfigurationChangeEvent } from 'vs/platform/configuration/common/configuration';
import { getCodeEditor } from 'vs/editor/browser/services/codeEditorService';
import { EventType as TouchEventType, GestureEvent } from 'vs/base/browser/touch';
import { NextTitleControl } from 'vs/workbench/browser/parts/editor2/nextTitleControl';
export interface IGroupsAccessor {
readonly groups: NextEditorGroupView[];
......@@ -94,7 +94,7 @@ export class NextEditorGroupView extends Themable implements IView, INextEditorG
private scopedInstantiationService: IInstantiationService;
private titleContainer: HTMLElement;
private titleAreaControl: INextTitleAreaControl;
private titleAreaControl: NextTitleControl;
private progressBar: ProgressBar;
......@@ -496,7 +496,7 @@ export class NextEditorGroupView extends Themable implements IView, INextEditorG
return this.scopedInstantiationService;
}
private doCreateOrGetTitleControl(): INextTitleAreaControl {
private doCreateOrGetTitleControl(): NextTitleControl {
if (!this.titleAreaControl) {
this.titleAreaControl = this._register(this.doCreateOrGetScopedInstantiationService().createInstance(NextTabsTitleControl, this.titleContainer, this.groupsAccessor, this));
this.doLayoutTitleControl();
......@@ -548,7 +548,7 @@ export class NextEditorGroupView extends Themable implements IView, INextEditorG
// Forward to title area
if (this.titleAreaControl) {
this.titleAreaControl.moveEditor(editor, moveToIndex);
this.titleAreaControl.moveEditor(editor, currentIndex, moveToIndex);
this.titleAreaControl.pinEditor(editor);
}
}
......
......@@ -80,7 +80,7 @@ export class NextNoTabsTitleControl extends NextTitleControl {
this.ifActiveEditorChanged(() => this.redraw());
}
moveEditor(editor: IEditorInput, targetIndex: number): void {
moveEditor(editor: IEditorInput, fromIndex: number, targetIndex: number): void {
this.ifActiveEditorChanged(() => this.redraw());
}
......
......@@ -228,24 +228,51 @@ export class NextTabsTitleControl extends NextTitleControl {
this.recreate(); // TODO@grid optimize
}
moveEditor(editor: IEditorInput, targetIndex: number): void {
this.recreate(); // TODO@grid optimize
moveEditor(editor: IEditorInput, fromIndex: number, targetIndex: number): void {
// Swap the editor label
const editorLabel = this.tabLabels[fromIndex];
this.tabLabels.splice(fromIndex, 1);
this.tabLabels.splice(targetIndex, 0, editorLabel);
// As such we need to redraw each label
this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel) => {
this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel);
this.redrawEditorActive(this.groupsAccessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget);
});
// Moving an editor requires a layout to keep the active editor visible
this.layout(this.dimension);
}
pinEditor(editor: IEditorInput): void {
this.withTab(editor, (tabContainer, tabLabelWidget, tabLabel) => this.redrawLabel(tabLabel, editor, tabContainer, tabLabelWidget));
this.withTab(editor, (tabContainer, tabLabelWidget, tabLabel) => this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel));
}
setActive(isGroupActive: boolean): void {
// Activity has an impact on each tab
this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel) => {
this.redrawGroupActive(isGroupActive, editor, tabContainer, tabLabelWidget);
this.redrawEditorActive(isGroupActive, editor, tabContainer, tabLabelWidget);
});
// Activity has an impact on the toolbar, so we need to update and layout
this.updateEditorActionsToolbar();
this.layout(this.dimension);
}
updateEditorLabel(editor: IEditorInput): void {
this.redraw(true /* labels only */);
// A change to a label requires to recompute all labels
this.computeTabLabels();
// As such we need to redraw each label
this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel) => {
this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel);
});
// A change to a label requires a layout to keep the active editor visible
this.layout(this.dimension);
}
updateEditorDirty(editor: IEditorInput): void {
......@@ -269,6 +296,9 @@ export class NextTabsTitleControl extends NextTitleControl {
// Create tabs as needed
this.createTabs();
// Compute labels and protect against duplicates
this.computeTabLabels();
// Redraw tabs
this.redraw();
}
......@@ -540,82 +570,8 @@ export class NextTabsTitleControl extends NextTitleControl {
return combinedDisposable(disposables);
}
protected redraw(labelsOnly?: boolean): void {
// Compute labels and protect against duplicates
private computeTabLabels(): void {
this.tabLabels = this.getTabLabels(this.group.editors);
// For each tab
this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel) => {
// Redraw Label
this.redrawLabel(tabLabel, editor, tabContainer, tabLabelWidget);
// Redraw other Styles
if (!labelsOnly) {
// Borders
tabContainer.style.borderLeftColor = (index !== 0) ? (this.getColor(TAB_BORDER) || this.getColor(contrastBorder)) : null;
tabContainer.style.borderRightColor = (index === this.group.count - 1) ? (this.getColor(TAB_BORDER) || this.getColor(contrastBorder)) : null;
tabContainer.style.outlineColor = this.getColor(activeContrastBorder);
// Settings
const tabOptions = {} as IEditorTabOptions; // TODO@grid support tab options (this.editorGroupService.getTabOptions());
['off', 'left', 'right'].forEach(option => {
const domAction = tabOptions.tabCloseButton === option ? addClass : removeClass;
domAction(tabContainer, `close-button-${option}`);
});
['fit', 'shrink'].forEach(option => {
const domAction = tabOptions.tabSizing === option ? addClass : removeClass;
domAction(tabContainer, `sizing-${option}`);
});
if (tabOptions.showIcons && !!tabOptions.iconTheme) {
addClass(tabContainer, 'has-icon-theme');
} else {
removeClass(tabContainer, 'has-icon-theme');
}
// Active state (editor)
if (this.group.activeEditor === editor) {
addClass(tabContainer, 'active');
tabContainer.setAttribute('aria-selected', 'true');
tabContainer.style.backgroundColor = this.getColor(TAB_ACTIVE_BACKGROUND);
this.activeTab = tabContainer;
} else {
removeClass(tabContainer, 'active');
tabContainer.setAttribute('aria-selected', 'false');
tabContainer.style.backgroundColor = this.getColor(TAB_INACTIVE_BACKGROUND);
tabContainer.style.boxShadow = null;
}
// Active state (group)
this.redrawGroupActive(this.groupsAccessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget);
// Dirty State
this.redrawEditorDirty(editor, tabContainer);
}
});
// Update Editor Actions Toolbar
if (!labelsOnly) {
this.updateEditorActionsToolbar();
}
// Ensure the active tab is always revealed
this.layout(this.dimension);
}
private forEachTab(fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel) => void): void {
this.group.editors.forEach((editor, index) => {
const tabContainer = this.tabsContainer.children[index] as HTMLElement;
if (tabContainer) {
fn(editor, index, tabContainer, this.tabLabelWidgets[index], this.tabLabels[index]);
}
});
}
private getTabLabels(editors: IEditorInput[]): IEditorInputLabel[] {
......@@ -720,22 +676,87 @@ export class NextTabsTitleControl extends NextTitleControl {
}
}
private redrawLabel(label: IEditorInputLabel, editor: IEditorInput, tabContainer: HTMLElement, tabLabel: ResourceLabel): void {
const name = label.name;
const description = label.description || '';
const title = label.title || '';
protected redraw(): void {
// For each tab
this.forEachTab((editor, index, tabContainer, tabLabelWidget, tabLabel) => {
this.redrawTab(editor, index, tabContainer, tabLabelWidget, tabLabel);
});
// Update Editor Actions Toolbar
this.updateEditorActionsToolbar();
// Ensure the active tab is always revealed
this.layout(this.dimension);
}
private forEachTab(fn: (editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel) => void): void {
this.group.editors.forEach((editor, index) => {
const tabContainer = this.tabsContainer.children[index] as HTMLElement;
if (tabContainer) {
fn(editor, index, tabContainer, this.tabLabelWidgets[index], this.tabLabels[index]);
}
});
}
private redrawTab(editor: IEditorInput, index: number, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel): void {
// Label
this.redrawLabel(editor, tabContainer, tabLabelWidget, tabLabel);
// Borders
tabContainer.style.borderLeftColor = (index !== 0) ? (this.getColor(TAB_BORDER) || this.getColor(contrastBorder)) : null;
tabContainer.style.borderRightColor = (index === this.group.count - 1) ? (this.getColor(TAB_BORDER) || this.getColor(contrastBorder)) : null;
tabContainer.style.outlineColor = this.getColor(activeContrastBorder);
// Settings
const tabOptions = {} as IEditorTabOptions; // TODO@grid support tab options (this.editorGroupService.getTabOptions());
['off', 'left', 'right'].forEach(option => {
const domAction = tabOptions.tabCloseButton === option ? addClass : removeClass;
domAction(tabContainer, `close-button-${option}`);
});
['fit', 'shrink'].forEach(option => {
const domAction = tabOptions.tabSizing === option ? addClass : removeClass;
domAction(tabContainer, `sizing-${option}`);
});
if (tabOptions.showIcons && !!tabOptions.iconTheme) {
addClass(tabContainer, 'has-icon-theme');
} else {
removeClass(tabContainer, 'has-icon-theme');
}
// Active state
this.redrawEditorActive(this.groupsAccessor.activeGroup === this.group, editor, tabContainer, tabLabelWidget);
// Dirty State
this.redrawEditorDirty(editor, tabContainer);
}
private redrawLabel(editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel, tabLabel: IEditorInputLabel): void {
const name = tabLabel.name;
const description = tabLabel.description || '';
const title = tabLabel.title || '';
// Container
tabContainer.setAttribute('aria-label', `${name}, tab`);
tabContainer.title = title;
// Label
tabLabel.setLabel({ name, description, resource: toResource(editor, { supportSideBySide: true }) }, { extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) });
tabLabelWidget.setLabel({ name, description, resource: toResource(editor, { supportSideBySide: true }) }, { extraClasses: ['tab-label'], italic: !this.group.isPinned(editor) });
}
private redrawGroupActive(isGroupActive: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabel: ResourceLabel): void {
private redrawEditorActive(isGroupActive: boolean, editor: IEditorInput, tabContainer: HTMLElement, tabLabelWidget: ResourceLabel): void {
if (this.group.activeEditor === editor) {
tabLabel.element.style.color = this.getColor(isGroupActive ? TAB_ACTIVE_FOREGROUND : TAB_UNFOCUSED_ACTIVE_FOREGROUND);
this.activeTab = tabContainer;
addClass(tabContainer, 'active');
tabContainer.setAttribute('aria-selected', 'true');
tabContainer.style.backgroundColor = this.getColor(TAB_ACTIVE_BACKGROUND);
tabLabelWidget.element.style.color = this.getColor(isGroupActive ? TAB_ACTIVE_FOREGROUND : TAB_UNFOCUSED_ACTIVE_FOREGROUND);
// Use boxShadow for the active tab border because if we also have a editor group header
// color, the two colors would collide and the tab border never shows up.
......@@ -747,7 +768,12 @@ export class NextTabsTitleControl extends NextTitleControl {
tabContainer.style.boxShadow = null;
}
} else {
tabLabel.element.style.color = this.getColor(isGroupActive ? TAB_INACTIVE_FOREGROUND : TAB_UNFOCUSED_INACTIVE_FOREGROUND);
removeClass(tabContainer, 'active');
tabContainer.setAttribute('aria-selected', 'false');
tabContainer.style.backgroundColor = this.getColor(TAB_INACTIVE_BACKGROUND);
tabContainer.style.boxShadow = null;
tabLabelWidget.element.style.color = this.getColor(isGroupActive ? TAB_INACTIVE_FOREGROUND : TAB_UNFOCUSED_INACTIVE_FOREGROUND);
}
}
......
......@@ -43,20 +43,7 @@ export interface IToolbarActions {
secondary: IAction[];
}
export interface INextTitleAreaControl extends IDisposable {
openEditor(editor: IEditorInput): void;
closeEditor(editor: IEditorInput): void;
moveEditor(editor: IEditorInput, targetIndex: number): void;
setActive(isActive: boolean): void;
pinEditor(editor: IEditorInput): void;
updateEditorLabel(editor: IEditorInput): void;
updateEditorDirty(editor: IEditorInput): void;
layout(dimension: Dimension): void;
}
export abstract class NextTitleControl extends Themable implements INextTitleAreaControl {
export abstract class NextTitleControl extends Themable {
protected closeOneEditorAction: CloseOneEditorAction;
......@@ -300,7 +287,7 @@ export abstract class NextTitleControl extends Themable implements INextTitleAre
abstract closeEditor(editor: IEditorInput): void;
abstract moveEditor(editor: IEditorInput, targetIndex: number): void;
abstract moveEditor(editor: IEditorInput, fromIndex: number, targetIndex: number): void;
abstract pinEditor(editor: IEditorInput): void;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册