UNPKG

@theia/core

Version:

Theia is a cloud & desktop IDE framework implemented in TypeScript.

126 lines (111 loc) 4.73 kB
// ***************************************************************************** // Copyright (C) 2019 Red Hat, Inc. and others. // // This program and the accompanying materials are made available under the // terms of the Eclipse Public License v. 2.0 which is available at // http://www.eclipse.org/legal/epl-2.0. // // This Source Code may also be made available under the following Secondary // Licenses when the conditions for such availability set forth in the Eclipse // Public License v. 2.0 are satisfied: GNU General Public License, version 2 // with the GNU Classpath Exception which is available at // https://www.gnu.org/software/classpath/license.html. // // SPDX-License-Identifier: EPL-2.0 OR GPL-2.0-only WITH Classpath-exception-2.0 // ***************************************************************************** import { injectable, inject } from 'inversify'; import { Emitter, Event } from '../../common/event'; import { ApplicationShell } from './application-shell'; import { toArray } from '@lumino/algorithm'; import { TabBar, Widget } from '@lumino/widgets'; @injectable() export class ViewColumnService { private readonly columnValues = new Map<string, number>(); private readonly viewColumnIds = new Map<number, string[]>(); protected readonly onViewColumnChangedEmitter = new Emitter<{ id: string, viewColumn: number }>(); constructor( @inject(ApplicationShell) private readonly shell: ApplicationShell, ) { let oldColumnValues = new Map<string, number>(); const update = async () => { await new Promise<void>((resolve => setTimeout(resolve))); this.updateViewColumns(); this.viewColumnIds.forEach((ids: string[], viewColumn: number) => { ids.forEach((id: string) => { if (!oldColumnValues.has(id) || oldColumnValues.get(id) !== viewColumn) { this.onViewColumnChangedEmitter.fire({ id, viewColumn }); } }); }); oldColumnValues = new Map(this.columnValues.entries()); }; this.shell.mainPanel.widgetAdded.connect(() => update()); this.shell.mainPanel.widgetRemoved.connect(() => update()); } get onViewColumnChanged(): Event<{ id: string, viewColumn: number }> { return this.onViewColumnChangedEmitter.event; } updateViewColumns(): void { this.columnValues.clear(); this.viewColumnIds.clear(); const rows = new Map<number, Set<number>>(); const columns = new Map<number, Map<number, TabBar<Widget>>>(); for (const tabBar of toArray(this.shell.mainPanel.tabBars())) { if (!tabBar.node.style.top || !tabBar.node.style.left) { continue; } const top = parseInt(tabBar.node.style.top); const left = parseInt(tabBar.node.style.left); const row = rows.get(top) || new Set<number>(); row.add(left); rows.set(top, row); const column = columns.get(left) || new Map<number, TabBar<Widget>>(); column.set(top, tabBar); columns.set(left, column); } const firstRow = rows.get([...rows.keys()].sort()[0]); if (!firstRow) { return; } const lefts = [...firstRow.keys()].sort(); for (let i = 0; i < lefts.length; i++) { const column = columns.get(lefts[i]); if (!column) { break; } const cellIndexes = [...column.keys()].sort(); let viewColumn = Math.min(i, 2); for (let j = 0; j < cellIndexes.length; j++) { const cell = column.get(cellIndexes[j]); if (!cell) { break; } this.setViewColumn(cell, viewColumn); if (viewColumn < 7) { viewColumn += 3; } } } } protected setViewColumn(tabBar: TabBar<Widget>, viewColumn: number): void { const ids = []; for (const title of tabBar.titles) { const id = title.owner.id; ids.push(id); this.columnValues.set(id, viewColumn); } this.viewColumnIds.set(viewColumn, ids); } getViewColumnIds(viewColumn: number): string[] { return this.viewColumnIds.get(viewColumn) || []; } getViewColumn(id: string): number | undefined { return this.columnValues.get(id); } hasViewColumn(id: string): boolean { return this.columnValues.has(id); } viewColumnsSize(): number { return this.viewColumnIds.size; } }