From 98bf44fbc831b2c64714315ebc1fbe5e6fdeb0a4 Mon Sep 17 00:00:00 2001 From: Anton Kosyakov Date: Mon, 8 Jul 2019 14:01:18 +0000 Subject: [PATCH] [core] propagate phosphor events to view container part's widget Signed-off-by: Anton Kosyakov --- packages/core/src/browser/view-container.ts | 151 ++++++++++++-------- 1 file changed, 89 insertions(+), 62 deletions(-) diff --git a/packages/core/src/browser/view-container.ts b/packages/core/src/browser/view-container.ts index edef6bd736f4a..4163f9fa11173 100644 --- a/packages/core/src/browser/view-container.ts +++ b/packages/core/src/browser/view-container.ts @@ -19,7 +19,7 @@ import { v4 } from 'uuid'; import { IIterator, toArray, find, some, every, map } from '@phosphor/algorithm'; import { Widget, EXPANSION_TOGGLE_CLASS, COLLAPSED_CLASS, MessageLoop, Message, SplitPanel, BaseWidget, - addEventListener, SplitLayout, LayoutItem + addEventListener, SplitLayout, LayoutItem, PanelLayout } from './widgets'; import { Event, Emitter } from '../common/event'; import { Deferred } from '../common/promise-util'; @@ -47,19 +47,23 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica super(); this.id = `view-container-widget-${v4()}`; this.addClass('theia-view-container'); - const layout = new ViewContainerLayout({ - renderer: SplitPanel.defaultRenderer, - orientation: this.orientation, - spacing: 2, - headerSize: ViewContainerPart.HEADER_HEIGHT, - animationDuration: 200 - }, services.splitPositionHandler); - this.panel = new SplitPanel({ layout }); + const layout = new PanelLayout(); + this.layout = layout; + this.panel = new SplitPanel({ + layout: new ViewContainerLayout({ + renderer: SplitPanel.defaultRenderer, + orientation: this.orientation, + spacing: 2, + headerSize: ViewContainerPart.HEADER_HEIGHT, + animationDuration: 200 + }, services.splitPositionHandler) + }); + layout.addWidget(this.panel); for (const { widget, options } of inputs) { this.addWidget(widget, options); } this.attached.promise.then(() => { - this.layout.setPartSizes(inputs.map(({ options }) => options ? options.weight : undefined)); + this.containerLayout.setPartSizes(inputs.map(({ options }) => options ? options.weight : undefined)); }); const { commandRegistry, menuRegistry, contextMenuRenderer } = this.services; @@ -75,7 +79,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica if (toHide) { return toHide.canHide && !toHide.isHidden; } else { - return some(this.layout.iter(), part => !part.isHidden); + return some(this.containerLayout.iter(), part => !part.isHidden); } } }); @@ -85,7 +89,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica }); this.toDispose.pushAll([ addEventListener(this.node, 'contextmenu', event => { - if (event.button === 2 && every(this.layout.iter(), part => !!part.isHidden)) { + if (event.button === 2 && every(this.containerLayout.iter(), part => !!part.isHidden)) { event.stopPropagation(); event.preventDefault(); contextMenuRenderer.render({ menuPath: this.contextMenuPath, anchor: event }); @@ -101,14 +105,14 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica if (element instanceof Element) { const closestPart = ViewContainerPart.closestPart(element); if (closestPart && closestPart.id) { - return find(this.layout.iter(), part => part.id === closestPart.id); + return find(this.containerLayout.iter(), part => part.id === closestPart.id); } } return undefined; } addWidget(widget: Widget, options?: ViewContainer.Factory.WidgetOptions): Disposable { - if (find(this.layout.iter(), ({ wrapped }) => wrapped.id === widget.id)) { + if (find(this.containerLayout.iter(), ({ wrapped }) => wrapped.id === widget.id)) { return Disposable.NULL; } const description = this.services.widgetManager.getDescription(widget); @@ -116,20 +120,20 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica const newPart = new ViewContainerPart(widget, partId, this.id, options); this.registerPart(newPart); if (options && options.order !== undefined) { - const index = this.layout.widgets.findIndex(part => part.options.order === undefined || part.options.order > options.order!); + const index = this.containerLayout.widgets.findIndex(part => part.options.order === undefined || part.options.order > options.order!); if (index >= 0) { - this.layout.insertWidget(index, newPart); + this.containerLayout.insertWidget(index, newPart); } else { - this.layout.addWidget(newPart); + this.containerLayout.addWidget(newPart); } } else { - this.layout.addWidget(newPart); + this.containerLayout.addWidget(newPart); } this.refreshMenu(newPart); this.update(); return new DisposableCollection( Disposable.create(() => this.removeWidget(widget)), - newPart.onCollapsed(() => this.layout.updateCollapsed(newPart, this.enableAnimation)), + newPart.onCollapsed(() => this.containerLayout.updateCollapsed(newPart, this.enableAnimation)), newPart.onMoveBefore(toMoveId => this.moveBefore(toMoveId, newPart.id)), newPart.onContextMenu(event => { if (event.button === 2) { @@ -143,21 +147,21 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica } removeWidget(widget: Widget): boolean { - const part = find(this.layout.iter(), ({ wrapped }) => wrapped.id === widget.id); + const part = find(this.containerLayout.iter(), ({ wrapped }) => wrapped.id === widget.id); if (!part) { return false; } this.unregisterPart(part); - this.layout.removeWidget(part); + this.containerLayout.removeWidget(part); this.update(); return true; } getTrackableWidgets(): ViewContainerPart[] { - return this.layout.widgets; + return this.containerLayout.widgets; } - get layout(): ViewContainerLayout { + get containerLayout(): ViewContainerLayout { return this.panel.layout as ViewContainerLayout; } @@ -175,11 +179,11 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica if (!this.isVisible && this.lastVisibleState) { return this.lastVisibleState; } - const parts = this.layout.widgets; - const availableSize = this.layout.getAvailableSize(); + const parts = this.containerLayout.widgets; + const availableSize = this.containerLayout.getAvailableSize(); const orientation = this.orientation; const partStates = parts.map(part => { - let size = this.layout.getPartSize(part); + let size = this.containerLayout.getPartSize(part); if (size && size > ViewContainerPart.HEADER_HEIGHT && orientation === 'vertical') { size -= ViewContainerPart.HEADER_HEIGHT; } @@ -200,19 +204,19 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica */ restoreState(state: ViewContainer.State): void { if (state.parts) { - const partStates = state.parts.filter(partState => some(this.layout.iter(), p => p.partId === partState.partId)); + const partStates = state.parts.filter(partState => some(this.containerLayout.iter(), p => p.partId === partState.partId)); // Reorder the parts according to the stored state for (let index = 0; index < partStates.length; index++) { const partState = partStates[index]; - const currentIndex = this.layout.widgets.findIndex(p => p.partId === partState.partId); + const currentIndex = this.containerLayout.widgets.findIndex(p => p.partId === partState.partId); if (currentIndex > index) { - this.layout.moveWidget(currentIndex, index); + this.containerLayout.moveWidget(currentIndex, index); } } // Restore visibility and collapsed state - const parts = this.layout.widgets; + const parts = this.containerLayout.widgets; for (let index = 0; index < parts.length; index++) { const part = parts[index]; const partState = partStates.find(s => part.partId === s.partId); @@ -229,7 +233,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica // Restore part sizes this.attached.promise.then(() => { - this.layout.setPartSizes(partStates.map(partState => partState.relativeSize)); + this.containerLayout.setPartSizes(partStates.map(partState => partState.relativeSize)); }); } } @@ -243,13 +247,13 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica const commandId = this.toggleVisibilityCommandId(toRegister); commandRegistry.registerCommand({ id: commandId }, { execute: () => { - const toHide = find(this.layout.iter(), part => part.id === toRegister.id); + const toHide = find(this.containerLayout.iter(), part => part.id === toRegister.id); if (toHide) { this.toggleVisibility(toHide); } }, isToggled: () => { - const widgetToToggle = find(this.layout.iter(), part => part.id === toRegister.id); + const widgetToToggle = find(this.containerLayout.iter(), part => part.id === toRegister.id); if (widgetToToggle) { return !widgetToToggle.isHidden; } @@ -271,7 +275,7 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica menuRegistry.registerMenuAction([...this.contextMenuPath, '1_widgets'], { commandId: commandId, label: part.wrapped.title.label, - order: this.layout.widgets.indexOf(part).toString() + order: this.containerLayout.widgets.indexOf(part).toString() }); } } @@ -305,31 +309,17 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica } protected moveBefore(toMovedId: string, moveBeforeThisId: string): void { - const parts = this.layout.widgets; + const parts = this.containerLayout.widgets; const toMoveIndex = parts.findIndex(part => part.id === toMovedId); const moveBeforeThisIndex = parts.findIndex(part => part.id === moveBeforeThisId); if (toMoveIndex >= 0 && moveBeforeThisIndex >= 0) { - this.layout.moveWidget(toMoveIndex, moveBeforeThisIndex); + this.containerLayout.moveWidget(toMoveIndex, moveBeforeThisIndex); for (let index = Math.min(toMoveIndex, moveBeforeThisIndex); index < parts.length; index++) { this.refreshMenu(parts[index]); } } } - protected onResize(msg: Widget.ResizeMessage): void { - for (const widget of [this.panel, ...this.layout.widgets]) { - MessageLoop.sendMessage(widget, Widget.ResizeMessage.UnknownSize); - } - super.onResize(msg); - } - - protected onUpdateRequest(msg: Message): void { - for (const widget of [this.panel, ...this.layout.widgets]) { - widget.update(); - } - super.onUpdateRequest(msg); - } - protected onActivateRequest(msg: Message): void { super.onActivateRequest(msg); this.panel.activate(); @@ -337,15 +327,12 @@ export class ViewContainer extends BaseWidget implements StatefulWidget, Applica protected onAfterAttach(msg: Message): void { const orientation = this.orientation; - this.layout.orientation = orientation; + this.containerLayout.orientation = orientation; if (orientation === 'horizontal') { - for (const part of this.layout.widgets) { + for (const part of this.containerLayout.widgets) { part.collapsed = false; } } - if (!this.panel.isAttached) { - Widget.attach(this.panel, this.node); - } super.onAfterAttach(msg); requestAnimationFrame(() => this.attached.resolve()); } @@ -479,7 +466,7 @@ export class ViewContainerPart extends BaseWidget { return; } this._collapsed = collapsed; - this.body.style.display = collapsed ? 'none' : 'block'; + this.wrapped.setHidden(collapsed); const toggleIcon = this.header.querySelector(`span.${EXPANSION_TOGGLE_CLASS}`); if (toggleIcon) { if (collapsed) { @@ -638,9 +625,26 @@ export class ViewContainerPart extends BaseWidget { }; } + protected onResize(msg: Widget.ResizeMessage): void { + if (this.wrapped.isAttached && !this.collapsed) { + MessageLoop.sendMessage(this.wrapped, Widget.ResizeMessage.UnknownSize); + } + super.onResize(msg); + } + + protected onUpdateRequest(msg: Message): void { + if (this.wrapped.isAttached && !this.collapsed) { + MessageLoop.sendMessage(this.wrapped, msg); + } + super.onUpdateRequest(msg); + } + protected onAfterAttach(msg: Message): void { if (!this.wrapped.isAttached) { - Widget.attach(this.wrapped, this.body); + MessageLoop.sendMessage(this.wrapped, Widget.Msg.BeforeAttach); + // tslint:disable-next-line:no-null-keyword + this.body.insertBefore(this.wrapped.node, null); + MessageLoop.sendMessage(this.wrapped, Widget.Msg.AfterAttach); } super.onAfterAttach(msg); } @@ -648,15 +652,38 @@ export class ViewContainerPart extends BaseWidget { protected onBeforeDetach(msg: Message): void { super.onBeforeDetach(msg); if (this.wrapped.isAttached) { - Widget.detach(this.wrapped); + MessageLoop.sendMessage(this.wrapped, Widget.Msg.BeforeDetach); + this.wrapped.node.parentNode!.removeChild(this.wrapped.node); + MessageLoop.sendMessage(this.wrapped, Widget.Msg.AfterDetach); } } - protected onUpdateRequest(msg: Message): void { - if (this.wrapped.isAttached) { - this.wrapped.update(); + protected onBeforeShow(msg: Message): void { + if (this.wrapped.isAttached && !this.collapsed) { + MessageLoop.sendMessage(this.wrapped, msg); + } + super.onBeforeShow(msg); + } + + protected onAfterShow(msg: Message): void { + super.onAfterShow(msg); + if (this.wrapped.isAttached && !this.collapsed) { + MessageLoop.sendMessage(this.wrapped, msg); + } + } + + protected onBeforeHide(msg: Message): void { + if (this.wrapped.isAttached && this.collapsed) { + MessageLoop.sendMessage(this.wrapped, msg); + } + super.onBeforeShow(msg); + } + + protected onAfterHide(msg: Message): void { + super.onAfterHide(msg); + if (this.wrapped.isAttached && this.collapsed) { + MessageLoop.sendMessage(this.wrapped, msg); } - super.onUpdateRequest(msg); } }