layout: function (context, options) { /* Because views that extend this View class first call super() and then define their renderables, * we wait until the first engine render tick to add our renderables to the layout, when the view will have declared them all. * layout.setDataSource() will automatically pipe events from the renderables to this View. */ if (!this._initialised) { this.layout.setDataSource(this.renderables); this._renderableHelper.pipeAllRenderables(); this._renderableHelper.initializeAnimations(); this._initialised = true; this.layout.reflowLayout(); /* * When the data source is set, it will not be reflected in the context yet because the layout is already * prepared for the previous (empty) renderable data source. Therefore, it's a waste of resources * and mysterious bugs to continue. We will wait for the next rendering cycle. However, if views * are only having decorated renderables, then we don't have to do this whatsoever */ return; } /* Layout all renderables that have decorators (e.g. @someDecorator) */ this._layoutDecoratedRenderables(context, options); if (this.decorations.customLayoutFunction) { this.decorations.customLayoutFunction(context); } this._doTrueSizedSurfacesBookkeeping(); /* Legacy context.set() based layout functions */ if (this.layouts.length) { this._callLegacyLayoutFunctions(context, options); } }.bind(this)
/** * Combines all layouts defined in subclasses of the View into a single layout for the LayoutController. * @returns {void} * @private */ _createLayoutController() { let hasFlowyRenderables = this._renderableHelper.hasFlowyRenderables(); this.layout = new LayoutController({ flow: !!this.decorations.useFlow || hasFlowyRenderables, partialFlow: !this.decorations.useFlow, nativeScroll: !!this.decorations.nativeScrollable, flowOptions: this.decorations.flowOptions || { spring: { period: 200 } }, layout: function (context, options) { /* Because views that extend this View class first call super() and then define their renderables, * we wait until the first engine render tick to add our renderables to the layout, when the view will have declared them all. * layout.setDataSource() will automatically pipe events from the renderables to this View. */ if (!this._initialised) { this.layout.setDataSource(this.renderables); this._renderableHelper.pipeAllRenderables(); this._renderableHelper.initializeAnimations(); this._initialised = true; this.layout.reflowLayout(); /* * When the data source is set, it will not be reflected in the context yet because the layout is already * prepared for the previous (empty) renderable data source. Therefore, it's a waste of resources * and mysterious bugs to continue. We will wait for the next rendering cycle. However, if views * are only having decorated renderables, then we don't have to do this whatsoever */ return; } /* Layout all renderables that have decorators (e.g. @someDecorator) */ this._layoutDecoratedRenderables(context, options); if (this.decorations.customLayoutFunction) { this.decorations.customLayoutFunction(context); } this._doTrueSizedSurfacesBookkeeping(); /* Legacy context.set() based layout functions */ if (this.layouts.length) { this._callLegacyLayoutFunctions(context, options); } }.bind(this) }); this._eventInput.on('recursiveReflow', () => { this.reflowRecursively(); }); /* Add the layoutController to this View's rendering context. */ this._prepareLayoutController(); if ((this.decorations.scrollable || this.decorations.nativeScrollable) && !this._renderableHelper.getRenderableGroup('fullSize')) { this.addRenderable(new Surface(), '_fullScreenTouchArea', layout.fullSize(), layout.translate(0, 0, -10)); } }
/** * Layout all renderables that have explicit context.set() calls in this View's legacy layout array. * @returns {void} * @private */ _callLegacyLayoutFunctions(context, options) { for (let layout of this.layouts) { try { switch (typeof layout) { case 'function': layout.call(this, context, options); break; default: Utils.warn(`Unrecognized layout specification in view '${this._name()}'.`); break; } } catch (error) { Utils.warn(`Exception thrown in ${this._name()}:`); console.log(error); } } }
_initTrueSizedBookkeeping() { this.layout.on('sizeChanged', ({ oldSize, size }) => { if (size[0] !== oldSize[0] || size[1] !== oldSize[1]) { this._sizeResolver.doTrueSizedBookkeeping(); /// //TODO: Kept for legacy reasons, but remove all listeners to this function this._eventOutput.emit('newSize', size); for (let callback of this._onNewSizeCallbacks) { callback(size); } } }); /* Hack to make the layoutcontroller reevaluate sizes on resize of the parent */ this._nodes = { _trueSizedRequested: false }; /* This needs to be set in order for the LayoutNodeManager to be happy */ this.options.size = this.options.size || [true, true]; }