UNPKG

@babylonjs/gui

Version:

Babylon.js GUI module =====================

254 lines 10.7 kB
import { Measure } from "../../measure.js"; import { Container } from "../container.js"; import { ValueAndUnit } from "../../valueAndUnit.js"; import { Control } from "../control.js"; /** * Class used to hold a the container for ScrollViewer * @internal */ export class _ScrollViewerWindow extends Container { get freezeControls() { return this._freezeControls; } set freezeControls(value) { if (this._freezeControls === value) { return; } if (!value) { this._restoreMeasures(); } // trigger a full normal layout calculation to be sure all children have their measures up to date this._freezeControls = false; const textureSize = this.host.getSize(); const renderWidth = textureSize.width; const renderHeight = textureSize.height; const context = this.host.getContext(); const measure = new Measure(0, 0, renderWidth, renderHeight); this.host._numLayoutCalls = 0; this.host._rootContainer._layout(measure, context); // in freeze mode, prepare children measures accordingly if (value) { this._updateMeasures(); if (this._useBuckets()) { this._makeBuckets(); } } this._freezeControls = value; this.host.markAsDirty(); // redraw with the (new) current settings } get bucketWidth() { return this._bucketWidth; } get bucketHeight() { return this._bucketHeight; } setBucketSizes(width, height) { this._bucketWidth = width; this._bucketHeight = height; if (this._useBuckets()) { if (this._freezeControls) { this._makeBuckets(); } } else { this._buckets = {}; } } _useBuckets() { return this._bucketWidth > 0 && this._bucketHeight > 0; } _makeBuckets() { this._buckets = {}; this._bucketLen = Math.ceil(this.widthInPixels / this._bucketWidth); this._dispatchInBuckets(this._children); this._oldLeft = null; this._oldTop = null; } _dispatchInBuckets(children) { for (let i = 0; i < children.length; ++i) { const child = children[i]; const bStartX = Math.max(0, Math.floor((child._customData._origLeft - this._customData.origLeft) / this._bucketWidth)), bEndX = Math.floor((child._customData._origLeft - this._customData.origLeft + child._currentMeasure.width - 1) / this._bucketWidth), bEndY = Math.floor((child._customData._origTop - this._customData.origTop + child._currentMeasure.height - 1) / this._bucketHeight); let bStartY = Math.max(0, Math.floor((child._customData._origTop - this._customData.origTop) / this._bucketHeight)); while (bStartY <= bEndY) { for (let x = bStartX; x <= bEndX; ++x) { const bucket = bStartY * this._bucketLen + x; let lstc = this._buckets[bucket]; if (!lstc) { lstc = []; this._buckets[bucket] = lstc; } lstc.push(child); } bStartY++; } if (child instanceof Container && child._children.length > 0) { this._dispatchInBuckets(child._children); } } } // reset left and top measures for the window and all its children _updateMeasures() { const left = this.leftInPixels | 0, top = this.topInPixels | 0; this._measureForChildren.left -= left; this._measureForChildren.top -= top; this._currentMeasure.left -= left; this._currentMeasure.top -= top; this._customData.origLeftForChildren = this._measureForChildren.left; this._customData.origTopForChildren = this._measureForChildren.top; this._customData.origLeft = this._currentMeasure.left; this._customData.origTop = this._currentMeasure.top; this._updateChildrenMeasures(this._children, left, top); } _updateChildrenMeasures(children, left, top) { for (let i = 0; i < children.length; ++i) { const child = children[i]; child._currentMeasure.left -= left; child._currentMeasure.top -= top; child._customData._origLeft = child._currentMeasure.left; // save the original left and top values for each child child._customData._origTop = child._currentMeasure.top; if (child instanceof Container && child._children.length > 0) { this._updateChildrenMeasures(child._children, left, top); } } } _restoreMeasures() { const left = this.leftInPixels | 0, top = this.topInPixels | 0; this._measureForChildren.left = this._customData.origLeftForChildren + left; this._measureForChildren.top = this._customData.origTopForChildren + top; this._currentMeasure.left = this._customData.origLeft + left; this._currentMeasure.top = this._customData.origTop + top; } /** * Creates a new ScrollViewerWindow * @param name of ScrollViewerWindow */ constructor(name) { super(name); this._freezeControls = false; this._bucketWidth = 0; this._bucketHeight = 0; this._buckets = {}; } _getTypeName() { return "ScrollViewerWindow"; } /** * @internal */ _additionalProcessing(parentMeasure, context) { super._additionalProcessing(parentMeasure, context); this._parentMeasure = parentMeasure; this._measureForChildren.left = this._currentMeasure.left; this._measureForChildren.top = this._currentMeasure.top; this._measureForChildren.width = parentMeasure.width; this._measureForChildren.height = parentMeasure.height; } /** * @internal */ _layout(parentMeasure, context) { if (this._freezeControls) { this.invalidateRect(); // will trigger a redraw of the window return false; } return super._layout(parentMeasure, context); } _scrollChildren(children, left, top) { for (let i = 0; i < children.length; ++i) { const child = children[i]; child._currentMeasure.left = child._customData._origLeft + left; child._currentMeasure.top = child._customData._origTop + top; child._isClipped = false; // clipping will be handled by _draw and the call to _intersectsRect() if (child instanceof Container && child._children.length > 0) { this._scrollChildren(child._children, left, top); } } } _scrollChildrenWithBuckets(left, top, scrollLeft, scrollTop) { const bStartX = Math.max(0, Math.floor(-left / this._bucketWidth)), bEndX = Math.floor((-left + this._parentMeasure.width - 1) / this._bucketWidth), bEndY = Math.floor((-top + this._parentMeasure.height - 1) / this._bucketHeight); let bStartY = Math.max(0, Math.floor(-top / this._bucketHeight)); while (bStartY <= bEndY) { for (let x = bStartX; x <= bEndX; ++x) { const bucket = bStartY * this._bucketLen + x, lstc = this._buckets[bucket]; if (lstc) { for (let i = 0; i < lstc.length; ++i) { const child = lstc[i]; child._currentMeasure.left = child._customData._origLeft + scrollLeft; child._currentMeasure.top = child._customData._origTop + scrollTop; child._isClipped = false; // clipping will be handled by _draw and the call to _intersectsRect() } } } bStartY++; } } /** * @internal */ _draw(context, invalidatedRectangle) { if (!this._freezeControls) { super._draw(context, invalidatedRectangle); return; } this._localDraw(context); if (this.clipChildren) { this._clipForChildren(context); } const left = this.leftInPixels | 0, top = this.topInPixels | 0; if (this._useBuckets()) { if (this._oldLeft !== null && this._oldTop !== null) { this._scrollChildrenWithBuckets(this._oldLeft, this._oldTop, left, top); this._scrollChildrenWithBuckets(left, top, left, top); } else { this._scrollChildren(this._children, left, top); } } else { this._scrollChildren(this._children, left, top); } this._oldLeft = left; this._oldTop = top; for (const child of this._children) { if (!child._intersectsRect(this._parentMeasure)) { continue; } child._render(context, this._parentMeasure); } } _postMeasure() { if (this._freezeControls) { super._postMeasure(); return; } let maxWidth = this.parentClientWidth; let maxHeight = this.parentClientHeight; for (const child of this.children) { if (!child.isVisible || child.notRenderable) { continue; } if (child.horizontalAlignment === Control.HORIZONTAL_ALIGNMENT_CENTER) { child._offsetLeft(this._currentMeasure.left - child._currentMeasure.left); } if (child.verticalAlignment === Control.VERTICAL_ALIGNMENT_CENTER) { child._offsetTop(this._currentMeasure.top - child._currentMeasure.top); } maxWidth = Math.max(maxWidth, child._currentMeasure.left - this._currentMeasure.left + child._currentMeasure.width + child.paddingRightInPixels); maxHeight = Math.max(maxHeight, child._currentMeasure.top - this._currentMeasure.top + child._currentMeasure.height + child.paddingBottomInPixels); } if (this._currentMeasure.width !== maxWidth) { this._width.updateInPlace(maxWidth, ValueAndUnit.UNITMODE_PIXEL); this._currentMeasure.width = maxWidth; this._rebuildLayout = true; this._isDirty = true; } if (this._currentMeasure.height !== maxHeight) { this._height.updateInPlace(maxHeight, ValueAndUnit.UNITMODE_PIXEL); this._currentMeasure.height = maxHeight; this._rebuildLayout = true; this._isDirty = true; } super._postMeasure(); } } //# sourceMappingURL=scrollViewerWindow.js.map