diff --git a/src/vs/base/browser/ui/splitview/panelview.ts b/src/vs/base/browser/ui/splitview/panelview.ts index 83e56ce57931c29ab97c9a53e1a2f9d6a4e26bd8..5757406a45449d17d28a7a52ffe66ccda24c0f35 100644 --- a/src/vs/base/browser/ui/splitview/panelview.ts +++ b/src/vs/base/browser/ui/splitview/panelview.ts @@ -96,7 +96,7 @@ export abstract class Panel implements IView { constructor(options: IPanelOptions = {}) { this._expanded = typeof options.expanded === 'undefined' ? true : !!options.expanded; this.ariaHeaderLabel = options.ariaHeaderLabel || ''; - this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 44; + this._minimumBodySize = typeof options.minimumBodySize === 'number' ? options.minimumBodySize : 120; this._maximumBodySize = typeof options.maximumBodySize === 'number' ? options.maximumBodySize : Number.POSITIVE_INFINITY; this.header = $('.panel-header'); } diff --git a/src/vs/base/browser/ui/splitview/splitview2.ts b/src/vs/base/browser/ui/splitview/splitview2.ts index 28beb9d066f75261fc8df5d2877a88481a37c420..3922591a095dfba610765b95fbbe710cded7499f 100644 --- a/src/vs/base/browser/ui/splitview/splitview2.ts +++ b/src/vs/base/browser/ui/splitview/splitview2.ts @@ -39,6 +39,7 @@ interface IViewItem { explicitSize: number; container: HTMLElement; disposable: IDisposable; + layout(): void; } interface ISashItem { @@ -52,16 +53,6 @@ interface ISashDragState { sizes: number[]; } -function layoutViewItem(item: IViewItem, orientation: Orientation): void { - if (orientation === Orientation.VERTICAL) { - item.container.style.height = `${item.size}px`; - } else { - item.container.style.width = `${item.size}px`; - } - - item.view.layout(item.size, orientation); -} - export class SplitView implements IDisposable { private orientation: Orientation; @@ -98,8 +89,23 @@ export class SplitView implements IDisposable { const containerDisposable = toDisposable(() => this.el.removeChild(container)); const disposable = combinedDisposable([onChangeDisposable, containerDisposable]); + const layoutContainer = this.orientation === Orientation.VERTICAL + ? size => item.container.style.height = `${item.size}px` + : size => item.container.style.width = `${item.size}px`; + + let previousSize: number | undefined = undefined; + const layout = () => { + if (item.size === previousSize) { + return; + } + + layoutContainer(item.size); + item.view.layout(item.size, this.orientation); + previousSize = item.size; + }; + const explicitSize = size; - const item: IViewItem = { view, container, explicitSize, size, disposable }; + const item: IViewItem = { view, container, explicitSize, size, layout, disposable }; this.viewItems.splice(index, 0, item); // Add sash @@ -193,8 +199,14 @@ export class SplitView implements IDisposable { } private onViewChange(item: IViewItem): void { - item.size = clamp(item.size, item.view.minimumSize, item.view.maximumSize); - this.relayout(); + const index = this.viewItems.indexOf(item); + + if (index < 0 || index >= this.viewItems.length - 1) { + return; + } + + const size = clamp(item.size, item.view.minimumSize, item.view.maximumSize); + this.resize(index, size - item.size); } resizeView(index: number, size: number): void { @@ -219,6 +231,12 @@ export class SplitView implements IDisposable { const down = downIndexes.map(i => this.viewItems[i]); const downSizes = downIndexes.map(i => sizes[i]); + delta = clamp( + delta, + -upIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0), + downIndexes.reduce((r, i) => r + (sizes[i] - this.viewItems[i].view.minimumSize), 0) + ); + for (let i = 0, deltaUp = delta; deltaUp !== 0 && i < up.length; i++) { const item = up[i]; const size = clamp(upSizes[i] + deltaUp, item.view.minimumSize, item.view.maximumSize); @@ -242,7 +260,7 @@ export class SplitView implements IDisposable { } private layoutViews(): void { - this.viewItems.forEach(item => layoutViewItem(item, this.orientation)); + this.viewItems.forEach(item => item.layout()); this.sashItems.forEach(item => item.sash.layout()); // Update sashes enablement diff --git a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css index 137f20cd4b7658669c2a81a85e442ec7af455513..c8924adc9f8622b716edbf962c74b3617b36a5e5 100644 --- a/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css +++ b/src/vs/workbench/parts/scm/electron-browser/media/scmViewlet.css @@ -145,4 +145,8 @@ .scm-viewlet .scm-editor.scroll > .monaco-inputbox > .wrapper > textarea.input { overflow-y: scroll; +} + +.scm-viewlet .split-view-view { + background: green; } \ No newline at end of file diff --git a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts index 0f7d03fe781a1ec610e166e64704de909c1b5a3d..ec75adceddde6eeb6b63595fbb32d49b5d473a72 100644 --- a/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts +++ b/src/vs/workbench/parts/scm/electron-browser/scmViewlet.ts @@ -12,7 +12,7 @@ import { chain } from 'vs/base/common/event'; import { basename } from 'vs/base/common/paths'; import { onUnexpectedError } from 'vs/base/common/errors'; import { IDisposable, dispose, combinedDisposable, empty as EmptyDisposable } from 'vs/base/common/lifecycle'; -import { Builder } from 'vs/base/browser/builder'; +import { Builder, Dimension } from 'vs/base/browser/builder'; import { PanelViewlet, ViewletPanel } from 'vs/workbench/browser/parts/views/views2'; import { append, $, toggleClass, trackFocus } from 'vs/base/browser/dom'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; @@ -68,11 +68,12 @@ class SCMMenuItemActionItem extends MenuItemActionItem { } } -interface IViewModel { +export interface IViewModel { + readonly height: number | undefined; + addRepositoryPanel(panel: RepositoryPanel, size: number, index?: number): void; removeRepositoryPanel(panel: RepositoryPanel): void; moveRepositoryPanel(from: RepositoryPanel, to: RepositoryPanel): void; - isRepositoryVisible(repository: ISCMRepository): boolean; toggleRepositoryVisibility(repository: ISCMRepository, visible: boolean); } @@ -236,9 +237,9 @@ class MainPanel extends ViewletPanel { this.list.splice(this.list.length, 0, [repository]); this.updateBodySize(); - if (this.repositories.length === 1) { - this.list.setSelection([0]); - } + // if (this.repositories.length === 1) { + this.list.setSelection(this.repositories.map((_, i) => i)); + // } } private onDidRemoveRepository(repository: ISCMRepository): void { @@ -254,16 +255,27 @@ class MainPanel extends ViewletPanel { } private onSelectionChange(e: IListEvent): void { - console.log(e.elements); + // Remove unselected panels + this.repositoryPanels + .filter(p => e.elements.every(r => p.repository !== r)) + .forEach(panel => this.viewModel.removeRepositoryPanel(panel)); - const toRemove = this.repositoryPanels.filter(p => e.elements.every(r => p.repository !== r)); - const toAdd = e.elements.filter(r => this.repositoryPanels.every(p => p.repository !== r)); + // Collect panels still selected + const repositoryPanels = this.repositoryPanels + .filter(p => e.elements.some(r => p.repository === r)); - console.log(toAdd, toRemove); + // Collect new selected panels + const newRepositoryPanels = e.elements + .filter(r => this.repositoryPanels.every(p => p.repository !== r)) + .map(r => this.instantiationService.createInstance(RepositoryPanel, r)); + // Add new selected panels + const height = typeof this.viewModel.height === 'number' ? this.viewModel.height : 1000; + const size = (height - this.minimumSize) / e.elements.length; + console.log(this.viewModel.height, height, this.minimumBodySize, e.elements.length, size); + newRepositoryPanels.forEach(panel => this.viewModel.addRepositoryPanel(panel, size)); - // this.viewModel.addRepositoryPanel(); - // this.repositoryPanels + this.repositoryPanels = [...repositoryPanels, ...newRepositoryPanels]; } private updateBodySize(): void { @@ -483,8 +495,11 @@ export class RepositoryPanel extends ViewletPanel { @IInstantiationService protected instantiationService: IInstantiationService ) { super(repository.provider.label, {}, keybindingService, contextMenuService); - this.menus = instantiationService.createInstance(SCMMenus, repository.provider); + } + + render(container: HTMLElement): void { + super.render(container); this.menus.onDidChangeTitle(this.updateActions, this, this.disposables); } @@ -703,15 +718,15 @@ class InstallAdditionalSCMProvidersAction extends Action { } } -export class SCMViewlet extends PanelViewlet { +export class SCMViewlet extends PanelViewlet implements IViewModel { private menus: SCMMenus; - private mainPanel: MainPanel; - - // private repositoryToViewDescriptor = new Map(); private disposables: IDisposable[] = []; + private _height: number | undefined = undefined; + get height(): number | undefined { return this._height; } + constructor( @ITelemetryService telemetryService: ITelemetryService, @ISCMService protected scmService: ISCMService, @@ -835,7 +850,12 @@ export class SCMViewlet extends PanelViewlet { return new SCMMenuItemActionItem(action, this.keybindingService, this.messageService); } - addRepositoryPanel(panel: RepositoryPanel, size: number, index?: number): void { + layout(dimension: Dimension): void { + super.layout(dimension); + this._height = dimension.height; + } + + addRepositoryPanel(panel: RepositoryPanel, size: number, index: number = this.length): void { this.addPanel(panel, size, index + 1); }